Skip to content

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 by ca_file. Default is false.
  • 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. Set min_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/tls is 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/tls does 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

Related Guides

View all Message Brokers guides →

Configured TLS? Now Monitor It.

Generator Labs alerts you before certificates expire, get revoked, or fail chain validation — across HTTPS, SMTPS, IMAPS, LDAPS, and more.

Certificate Monitoring →