Skip to content

Certificate providers — sing-box ​

Certificate providers obtain and renew TLS server certificates for inbounds. Declare them in the top-level certificate_providers array and reference one from an inbound tls block through certificate_provider — by tag, or inline as an object with its own type. Three types exist: acme (Let's Encrypt, ZeroSSL or any ACME CA), cloudflare-origin-ca (certificates from Cloudflare's Origin CA) and tailscale (the node's tailnet certificate via a Tailscale endpoint). They replace the inline tls.acme block, which is deprecated.

Envelope ​

Each certificate_providers[] entry has type and tag, plus the fields of its type at the same level:

FieldTypeDefaultAllowed valuesDescription
typestring(required)acme | cloudflare-origin-ca | tailscaleProvider type; selects which of the field sets below applies. An unknown type fails at startup.
tagstring(unset)<string>Name that inbound tls.certificate_provider fields reference. Not used by inline providers.

Source: option/certificate_provider.go:18-22 · pinned at v1.14.2 (af6e64c)

An inbound uses a provider with tls.certificate_provider: a string is the tag of a certificate_providers entry, an object is an inline provider with its own type. See TLS for how this interacts with certificate / key, the inline acme block and REALITY.

acme ​

FieldTypeDefaultAllowed valuesDescription
domainbadoption.Listable[string](required)<domain> | <IP address>Names to obtain certificates for. IP addresses are accepted (see profile).
data_directorystring$XDG_DATA_HOME/certmagic<dir path>Where ACME account data and certificates are stored. Falls back to $HOME/.local/share/certmagic.
default_server_namestring(unset)<hostname>Server name used to pick a certificate when the ClientHello carries no SNI.
emailstring(unset)<e-mail>E-mail used to create or select the ACME account.
providerstringletsencryptletsencrypt | zerossl | <https:// directory URL>ACME CA. For zerossl, one of external_account, email or account_key is required; with email and no external_account, EAB credentials are requested automatically.
account_keystring(unset)<PEM key>PEM private key of an existing ACME account to reuse.
disable_http_challengeboolfalsetrue | falseDisable the HTTP-01 challenge.
disable_tls_alpn_challengeboolfalsetrue | falseDisable the TLS-ALPN-01 challenge.
alternative_http_portuint1680<port>Port for the HTTP-01 challenge listener instead of 80; port 80 must still reach it.
alternative_tls_portuint16443<port>Port for the TLS-ALPN-01 challenge listener instead of 443; the system must forward 443 to it.
external_account*ACMEExternalAccountOptions(unset){ key_id, mac_key }External Account Binding: the key identifier and MAC key the CA issued out of band.
dns01_challenge*ACMEProviderDNS01ChallengeOptions(unset)ACMEProviderDNS01ChallengeOptionsUse the DNS-01 challenge (see below). When set, the other challenge types are disabled.
key_typeACMEKeyType(library default)ed25519 | p256 | p384 | rsa2048 | rsa4096Private-key type for newly issued certificates.
profilestring(unset)<ACME profile>ACME profile to request. With Let's Encrypt, shortlived is chosen automatically when any domain is an IP address.
http_client*HTTPClientOptions(default client)<http_clients tag> | HTTPClientOptionsHTTP client for all ACME requests: an inline object or the tag of an http_clients entry.

Source: option/acme.go:15-31 · pinned at v1.14.2 (af6e64c)

DNS-01 challenge ​

dns01_challenge takes a provider plus that provider's credentials, and these tuning fields:

FieldTypeDefaultAllowed valuesDescription
ttlbadoption.Duration(provider default)<duration>TTL of the temporary _acme-challenge TXT record.
propagation_delaybadoption.Duration0s<duration>Wait this long after creating the record before checking propagation.
propagation_timeoutbadoption.Duration(library default)<duration> | -1Give up waiting for propagation after this long; -1 disables propagation checks.
resolversbadoption.Listable[string](system)<resolver> | …DNS resolvers used for the propagation checks.
override_domainstring(unset)<domain>Write the challenge record under this domain instead — for an _acme-challenge name delegated to another zone.

Source: option/acme.go:41-47 · pinned at v1.14.2 (af6e64c)

providerCredential fields
alidnsaccess_key_id, access_key_secret, region_id, security_token (STS temporary credentials)
cloudflareapi_token, zone_token (optional token with Zone:Read, so api_token can be scoped to a single zone)
acmednsusername, password, subdomain, server_url (an ACME-DNS server)

cloudflare-origin-ca ​

FieldTypeDefaultAllowed valuesDescription
domainbadoption.Listable[string](required)<domain> | *.<domain>Hostnames, wildcards included, to put in the certificate.
data_directorystring$XDG_DATA_HOME/certmagic<dir path>Root directory for the issued certificate, private key and metadata. Same default as the ACME provider.
api_tokenstring(unset)<token>Cloudflare API token with the Zone / SSL and Certificates / Edit permission. Exactly one of api_token and origin_ca_key is required.
origin_ca_keystring(unset)<key>Cloudflare Origin CA Key, the alternative credential. Mutually exclusive with api_token.
request_typeCloudflareOriginCARequestTypeorigin-rsaorigin-rsa | origin-eccKey type to request: RSA or ECDSA P-256.
requested_validityCloudflareOriginCARequestValidity54757 | 30 | 90 | 365 | 730 | 1095 | 5475Certificate validity in days (5475 = 15 years).
http_client*HTTPClientOptions(default client)<http_clients tag> | HTTPClientOptionsHTTP client for the Cloudflare API requests: an inline object or the tag of an http_clients entry.

Source: option/origin_ca.go:12-20 · pinned at v1.14.2 (af6e64c)

tailscale ​

FieldTypeDefaultAllowed valuesDescription
endpointstring(required)<endpoint tag>Tag of the Tailscale endpoint whose node certificate (its *.ts.net name) is served. MagicDNS and HTTPS must be enabled in the Tailscale admin console.

Source: option/tailscale.go:78-80 · pinned at v1.14.2 (af6e64c)

Examples ​

A shared ACME provider using the Cloudflare DNS-01 challenge, referenced by tag:

json
{
  "certificate_providers": [
    {
      "type": "acme",
      "tag": "le",
      "domain": ["example.com"],
      "email": "admin@example.com",
      "dns01_challenge": {
        "provider": "cloudflare",
        "api_token": "<cloudflare-api-token>"
      }
    }
  ],
  "inbounds": [
    {
      "type": "trojan",
      "tag": "trojan-in",
      "listen": "::",
      "listen_port": 443,
      "users": [{ "name": "user", "password": "<password>" }],
      "tls": {
        "enabled": true,
        "certificate_provider": "le"
      }
    }
  ]
}

The tailnet certificate of a Tailscale endpoint; an inbound then sets "certificate_provider": "ts-cert":

json
{
  "endpoints": [
    { "type": "tailscale", "tag": "ts-ep", "auth_key": "tskey-auth-xxxxxxxxxxxx" }
  ],
  "certificate_providers": [
    { "type": "tailscale", "tag": "ts-cert", "endpoint": "ts-ep" }
  ]
}

Migrating from inline tls.acme ​

Move the tls.acme fields unchanged into tls.certificate_provider with "type": "acme" added (or into a certificate_providers entry referenced by tag):

json
// before (deprecated)
"tls": { "enabled": true, "acme": { "domain": ["example.com"], "email": "admin@example.com" } }

// after
"tls": { "enabled": true, "certificate_provider": { "type": "acme", "domain": ["example.com"], "email": "admin@example.com" } }

Notes ​

  • Build tags: acme needs with_acme and tailscale needs with_tailscale; without them the type exists but fails at startup. cloudflare-origin-ca is always compiled in.
  • A tagged provider can be referenced by several inbounds.
  • Cloudflare Origin CA certificates are trusted only by Cloudflare's own edge. Use them on origin servers behind Cloudflare's proxy, not for clients that connect directly. The provider renews them automatically before they expire.
  • The tailscale provider fails at startup if endpoint is empty, unknown, or not a Tailscale endpoint.
  • The ACME fields match the deprecated inline tls.acme block, plus account_key, key_type, profile and http_client.

Cross-core notes ​

  • Xray-core has no built-in ACME or certificate providers: server certificates come from files or inline PEM in tlsSettings.certificates. See TLS — Xray-core.
  • mihomo has none either: listeners take a certificate and private key directly. See TLS overview — mihomo.

Source: option/certificate_provider.go:18-69 · v1.14.2 (af6e64c)

Core Tutorial by Argsment