Last updated: 2026-05-15
NATS TLS Configuration
NATS is written in Go and uses Go's TLS stack, so cipher suite names follow Go's naming convention rather than OpenSSL's. The nats-server.conf format is NATS's own configuration language (similar to nginx config blocks).
NATS has three independent TLS surfaces: client connections, cluster peer connections, and leaf node connections. Each gets its own tls block.
Client TLS
Add a tls block at the top level of nats-server.conf:
tls {
cert_file: "/etc/nats/ssl/server.crt"
key_file: "/etc/nats/ssl/server.key"
ca_file: "/etc/nats/ssl/ca.crt"
verify: true
min_version: "1.2"
cipher_suites: [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
]
curve_preferences: [
"X25519",
"CurveP256",
"CurveP384"
]
}
Key settings:
verify: true: requires clients to present a certificate signed byca_file. Default isfalse.min_version: accepts"1.2"or"1.3".cipher_suites: applies to TLS 1.2 only. Go's TLS stack always enables TLS 1.3 when available and its ciphers are not configurable.curve_preferences: ECDH curves for key exchange.
If any client supports TLS 1.3, Go will negotiate it regardless of
cipher_suites. Setmin_version: "1.3"to enforce TLS 1.3 exclusively, only viable if all clients support it.See RFC 8446 ยง4.3.2 for the TLS Certificate Request specification, and Wikipedia: Mutual authentication for a general overview.
Cluster TLS
For peer-to-peer connections within a NATS cluster, add a tls block inside the cluster block:
cluster {
name: my-cluster
port: 6222
tls {
cert_file: "/etc/nats/ssl/server.crt"
key_file: "/etc/nats/ssl/server.key"
ca_file: "/etc/nats/ssl/ca.crt"
verify: true
min_version: "1.2"
}
routes: [
nats-route://nats1.internal:6222
nats-route://nats2.internal:6222
nats-route://nats3.internal:6222
]
}
With verify: true in the cluster block, each node must present a valid certificate, preventing unauthorized nodes from joining as cluster members.
Leaf Node TLS
For leaf nodes (extending a cluster across network or security boundaries):
leafnodes {
port: 7422
tls {
cert_file: "/etc/nats/ssl/server.crt"
key_file: "/etc/nats/ssl/server.key"
ca_file: "/etc/nats/ssl/ca.crt"
verify: true
min_version: "1.2"
}
}
Client Connections
nats CLI
nats --server tls://nats.example.com:4222 \
--tlscert /etc/nats/ssl/client.crt \
--tlskey /etc/nats/ssl/client.key \
--tlsca /etc/nats/ssl/ca.crt \
sub "my.subject"
Use the tls:// scheme in the server URL to require TLS. The nats:// scheme with TLS options will also negotiate TLS, but tls:// makes the requirement explicit.
Security Notes
NATS uses Go's crypto/tls package, which has a different vulnerability history than OpenSSL:
- POODLE (CVE-2014-3566, 2014): SSL 3.0 has never been supported in Go's TLS implementation.
- BEAST (CVE-2011-3389, 2011): Mitigated by recommending TLS 1.2 as the minimum; AEAD-only ciphers eliminate the CBC padding oracle.
- CRIME (CVE-2012-4929, 2012): TLS compression is not supported in Go's
crypto/tls. - Lucky13 (2013): AEAD-only cipher list eliminates CBC padding timing side-channels entirely.
- FREAK (CVE-2015-0204, 2015): EXPORT-grade ciphers have never been supported in Go's
crypto/tls. - LOGJAM (CVE-2015-4000, 2015): DHE key exchange is not offered by default in Go; only ECDHE is used.
- Sweet32 (CVE-2016-2183, 2016): 3DES was removed from Go's default cipher list in Go 1.14 (February 2020) and is excluded from the recommended configuration.
- ROBOT (CVE-2017-13099, 2017): Static RSA key exchange is not offered in Go's
crypto/tls; only ECDHE is used. - Downgrade attacks: TLS_FALLBACK_SCSV is supported in Go's TLS implementation.
The following are not addressable through TLS configuration alone:
- Heartbleed (CVE-2014-0160, 2014): Not applicable. Go's
crypto/tlsis an independent TLS implementation and was never affected by Heartbleed. - BREACH (CVE-2013-3587, 2013): Not applicable. BREACH targets HTTP-level response compression; the NATS messaging protocol does not involve HTTP.
- DROWN (CVE-2016-0800, 2016): Not applicable. Go's
crypto/tlsdoes not support SSLv2.
Verification
Test the TLS handshake:
openssl s_client -connect nats.example.com:4222 -CAfile /etc/nats/ssl/ca.crt
After a successful handshake, NATS sends an INFO banner with server metadata. If TLS is required and a client connects without it, the server sends an error and closes the connection immediately.
Enable debug logging in nats-server.conf to trace TLS negotiation:
debug: true
trace: true