TLS — sing-box
Every sing-box inbound and outbound embeds a tls: { ... } block via InboundTLSOptionsContainer / OutboundTLSOptionsContainer. The same block carries REALITY, ECH, and uTLS sub-blocks as nested options — they're not separate top-level features.
Inbound tls
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
enabled | bool | false | true | false | Master switch. When false, the rest of the block is ignored. |
server_name | string | (inferred from SNI) | <hostname> | Expected server name for ACME provisioning. Required if acme is set. |
insecure | bool | false | true | false | Skip TLS verification. Test only. |
alpn | badoption.Listable[string] | [] | <ALPN string> | ALPN list offered to clients. |
min_version | string | 1.2 | 1.0 | 1.1 | 1.2 | 1.3 | Minimum acceptable TLS version. |
max_version | string | 1.3 | 1.0 | 1.1 | 1.2 | 1.3 | Maximum acceptable TLS version. |
cipher_suites | badoption.Listable[string] | (library default) | <cipher> | Override the cipher suite list (TLS 1.2 only). |
curve_preferences | badoption.Listable[CurvePreference] | (library default) | P256 | P384 | P521 | X25519 | X25519MLKEM768 | Key-exchange curve preference list. |
certificate | badoption.Listable[string] | [] | <PEM block> | Inline server certificate PEM. List form supports the full chain. |
certificate_path | string | (unset) | <PEM file path> | Path to server certificate. |
client_authentication | ClientAuthType | no | no | request | require-any | verify-if-given | require-and-verify | Mutual-TLS client-auth policy. Maps to crypto/tls's ClientAuthType values. |
client_certificate | badoption.Listable[string] | [] | <PEM block> | Trusted client-certificate roots (mTLS). |
client_certificate_path | badoption.Listable[string] | [] | <PEM file path> | Path-form trusted client roots. |
client_certificate_public_key_sha256 | badoption.Listable[[]byte] | [] | <SHA-256 bytes> | Pin the client cert by public-key SHA-256. Useful when issuing throw-away client certs. |
key | badoption.Listable[string] | [] | <PEM block> | Inline server private key. |
key_path | string | (unset) | <file path> | Path to server private key. |
kernel_tx | bool | false | true | false | Linux KTLS — offload TLS encryption to the kernel for outgoing traffic. Requires kernel TLS support and the right crypto modules. |
kernel_rx | bool | false | true | false | Linux KTLS for incoming traffic. |
handshake_timeout | badoption.Duration | 15s | <duration> | TLS handshake timeout (Go duration). |
certificate_provider | *CertificateProviderOptions | (unset) | <provider tag> | CertificateProviderOptions | Certificate managed by a certificate provider: the tag of an entry in top-level certificate_providers, or an inline provider object with a type (acme, tailscale, cloudflare-origin-ca). When set, certificate / key are not read. Mutually exclusive with acme; not available with reality. |
acme | *InboundACMEOptions | (deprecated) | InboundACMEOptions | Deprecated: inline ACME. Use certificate_provider with type: acme — the fields move over unchanged. Mutually exclusive with certificate_provider. |
ech | *InboundECHOptions | (unset) | InboundECHOptions | Encrypted Client Hello configuration. |
reality | *InboundRealityOptions | (unset) | InboundRealityOptions | REALITY server configuration. Mutually exclusive with normal TLS — REALITY replaces the TLS handshake. |
Source: option/tls.go:13-40 · pinned at v1.14.2 (af6e64c)
Outbound tls
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
enabled | bool | false | true | false | Master switch. |
engine | string | go | go | apple | windows | TLS implementation for the handshake. apple uses Network.framework (Apple builds with CGO); windows uses Schannel via SSPI (Windows build 17763+, TLS 1.3 only on Windows 11 / Server 2022+). Non-go engines accept only server_name, insecure, alpn, min_version, max_version, certificate(_path), certificate_public_key_sha256 and handshake_timeout; any other TLS option is rejected at startup. |
disable_sni | bool | false | true | false | Omit the SNI extension entirely from the ClientHello. |
server_name | string | (server address) | <hostname> | SNI sent to the server, and the name verified against the leaf certificate. |
insecure | bool | false | true | false | Skip server-certificate verification. |
alpn | badoption.Listable[string] | [] | <ALPN string> | ALPN list offered to the server. |
min_version | string | 1.2 | 1.0 | 1.1 | 1.2 | 1.3 | Minimum acceptable TLS version. |
max_version | string | 1.3 | 1.0 | 1.1 | 1.2 | 1.3 | Maximum acceptable TLS version. |
cipher_suites | badoption.Listable[string] | (library default) | <cipher> | Override cipher suite list. |
curve_preferences | badoption.Listable[CurvePreference] | (library default) | <see inbound> | Key-exchange curve preference. |
certificate | badoption.Listable[string] | [] | <PEM block> | Trusted CA certificates appended to the system root store. Use with insecure: false for self-signed servers. |
certificate_path | string | (unset) | <file path> | Path-form trusted CAs. |
certificate_public_key_sha256 | badoption.Listable[[]byte] | [] | <SHA-256 bytes> | Pin the server certificate by public-key SHA-256. |
client_certificate | badoption.Listable[string] | [] | <PEM block> | Client certificate (mTLS). |
client_certificate_path | string | (unset) | <file path> | Path-form client certificate. |
client_key | badoption.Listable[string] | [] | <PEM block> | Client private key. |
client_key_path | string | (unset) | <file path> | Path-form client private key. |
fragment | bool | false | true | false | TCP-level handshake fragmentation. Splits the ClientHello across packets to evade SNI-based DPI. |
fragment_fallback_delay | badoption.Duration | 500ms | <duration> | If the fragmented handshake doesn't complete by this deadline, retry without fragmentation. |
record_fragment | bool | false | true | false | TLS-record-layer fragmentation (more aggressive than fragment — splits inside the TLS record stream, not just TCP packets). |
spoof | string | (unset) | <hostname> | Send a forged copy of the ClientHello carrying this SNI before the real one, to fool SNI-filtering middleboxes that allow specific hostnames. Must differ from server_name. Linux, macOS and Windows only; needs raw-socket privileges (CAP_NET_RAW + CAP_NET_ADMIN on Linux, root on macOS, Administrator on Windows; not on Windows ARM64). |
spoof_method | string | wrong-sequence | wrong-sequence | wrong-checksum | wrong-ack | wrong-md5 | wrong-timestamp | How the real server is made to drop the forged segment: out-of-window sequence number (default), bad checksum, out-of-window ACK, TCP-MD5 option, or backdated timestamp (wrong-timestamp is not supported on macOS). |
kernel_tx | bool | false | true | false | Linux KTLS for outgoing traffic. |
kernel_rx | bool | false | true | false | Linux KTLS for incoming traffic. |
handshake_timeout | badoption.Duration | 15s | <duration> | TLS handshake timeout (Go duration). |
ech | *OutboundECHOptions | (unset) | OutboundECHOptions | ECH configuration. When unset, ECH is not used (unless auto-discovered via HTTPS records). |
utls | *OutboundUTLSOptions | (unset) | OutboundUTLSOptions | uTLS client-hello mimicry. |
reality | *OutboundRealityOptions | (unset) | OutboundRealityOptions | REALITY client configuration. Mutually exclusive with normal TLS. |
Source: option/tls.go:107-136 · pinned at v1.14.2 (af6e64c)
utls
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
enabled | bool | false | true | false | Turn uTLS on. |
fingerprint | string | chrome | chrome | firefox | safari | ios | android | edge | 360 | qq | random | randomized | Browser fingerprint to mimic. Drives the entire ClientHello (cipher suites, extensions, signatures). |
Source: option/tls.go:247-250 · pinned at v1.14.2 (af6e64c)
Certificate providers
A server's certificate can come from a certificate provider instead of files or the inline acme block. Define providers in the top-level certificate_providers array (each with type and tag) and reference one by tag from tls.certificate_provider, or put a provider object inline there. Types: acme (needs the with_acme build tag), tailscale (reuses a Tailscale endpoint; MagicDNS and HTTPS must be enabled in the tailnet) and cloudflare-origin-ca. Full option reference: Certificate providers. The acme provider:
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
domain | badoption.Listable[string] | (required) | <domain> | … | Domains to request certificates for. Required. |
data_directory | string | (certmagic default) | <dir path> | Where ACME state and certificates are stored. Default: $XDG_DATA_HOME/certmagic or $HOME/.local/share/certmagic. |
email | string | (unset) | <e-mail> | Account e-mail used to create or select the ACME account. |
provider | string | letsencrypt | letsencrypt | zerossl | <https:// directory URL> | ACME CA. With zerossl, EAB credentials are requested automatically when email is set and external_account is empty. |
account_key | string | (unset) | <PEM key> | PEM private key of an existing ACME account. |
dns01_challenge | *ACMEProviderDNS01ChallengeOptions | (unset) | ACMEProviderDNS01ChallengeOptions | DNS-01 challenge settings (provider: alidns, cloudflare, acmedns, plus ttl, propagation_delay, propagation_timeout, resolvers, override_domain). When set, the other challenge types are disabled. |
key_type | ACMEKeyType | (certmagic default) | ed25519 | p256 | p384 | rsa2048 | rsa4096 | Key type for newly issued certificates. |
profile | string | (unset) | <ACME profile> | ACME profile for issuance. With Let's Encrypt, shortlived is chosen automatically when any domain is an IP address. |
http_client | *HTTPClientOptions | (default client) | <http_clients tag> | HTTPClientOptions | HTTP 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)
Examples
Inbound with an inline ACME certificate provider:
{
"inbounds": [{
"type": "vless",
"listen_port": 443,
"users": [{ "uuid": "..." }],
"tls": {
"enabled": true,
"server_name": "example.com",
"alpn": ["h2", "http/1.1"],
"certificate_provider": {
"type": "acme",
"domain": ["example.com"],
"email": "admin@example.com"
}
}
}]
}Outbound with uTLS chrome fingerprint and TCP-fragment SNI hiding:
{
"outbounds": [{
"type": "vless",
"server": "example.com",
"server_port": 443,
"uuid": "...",
"tls": {
"enabled": true,
"server_name": "example.com",
"utls": { "enabled": true, "fingerprint": "chrome" },
"fragment": true,
"fragment_fallback_delay": "500ms"
}
}]
}Mutual TLS — server requires client certificates:
{
"inbounds": [{
"type": "http",
"listen_port": 8443,
"tls": {
"enabled": true,
"certificate_path": "/etc/ssl/cert.pem",
"key_path": "/etc/ssl/key.pem",
"client_authentication": "require-and-verify",
"client_certificate_path": ["/etc/ssl/clients-ca.pem"]
}
}]
}Notes
- The five
client_authenticationvalues map directly to Go'scrypto/tls.ClientAuthType:no— no client cert (default).request— ask for one, accept without it.require-any— require but don't validate.verify-if-given— validate if provided.require-and-verify— strict mTLS.
fragmentandrecord_fragmentare two different layers:fragmentsplits the TCP packets carrying the TLS handshake.record_fragmentsplits the TLS records themselves (Handshakerecords sent in multiple smaller pieces). Usefragmentfirst; only enablerecord_fragmentif SNI-based DPI still classifies the connection.
kernel_tx/kernel_rxenable Linux KTLS for AES-GCM and CHACHA20-POLY1305. The kernel must have thetlsmodule loaded and the right crypto modules registered.- Inline
tls.acmeis deprecated. Move its fields unchanged into acertificate_provideroftype: acme(inline, as in the example, or shared viacertificate_providers+ tag).certificate_providerandacmecannot be combined, and REALITY accepts neither. engine: apple/windowshand the handshake to the OS TLS stack. They reject uTLS, REALITY, ECH, fragmentation, KTLS, client certificates,cipher_suites,curve_preferences,disable_sniandspoofat startup.spoof(withspoof_method) is also available per connection as thetls_spoof/tls_spoof_methodroute rule action options.- REALITY (the
realitysub-block) replaces the TLS handshake entirely — see REALITY — sing-box. - ECH (the
echsub-block) plugs into the same handshake — see ECH — sing-box.
Cross-core notes
- Xray-core uses
streamSettings.tlsSettingsrather than an embeddedtlsblock. Field names are camelCase (serverName,cipherSuites). uTLS fingerprint is a top-level field, not a sub-block. See TLS — Xray-core. - mihomo has no consolidated TLS block — each proxy adapter carries TLS fields inline (
tls,sni,alpn,skip-cert-verify, …). See TLS — mihomo.
Source: option/tls.go:13-250 · v1.14.2 (af6e64c)
