How to enable post-quantum TLS

For most stacks it is one configuration line — the hard part is knowing which one.

The prerequisites

Hybrid post-quantum key exchange needs two things: TLS 1.3 (there is no post-quantum TLS 1.2), and a TLS library that knows the ML-KEM groups. In the OpenSSL world that means OpenSSL 3.5 or newer — the current long-term-support release, which ships ML-KEM natively and even offers X25519MLKEM768 by default. If your distribution still ships an older OpenSSL, upgrading the library (or terminating TLS somewhere newer) is the whole job; no certificate changes are involved.

Behind a CDN? You may already be done

The general rule: post-quantum key exchange is a property of whatever terminates TLS. Fix it there, and remember internal legs (CDN → origin, service → service) are separate conversations with their own HNDL exposure.

Self-hosted stacks

nginx (with OpenSSL 3.5+): set the group list, hybrid first, classical fallbacks after:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1;

Apache httpd (with OpenSSL 3.5+):

SSLOpenSSLConfCmd Groups X25519MLKEM768:X25519:prime256v1

HAProxy:

ssl-default-bind-curves X25519MLKEM768:X25519:P-256

Caddy / Go servers: nothing to do — Go's TLS stack has enabled X25519MLKEM768 by default since Go 1.24, so recent builds negotiate it automatically.

Node.js: builds against OpenSSL 3.5 accept the same group list via --tls-groups or the ecdhCurve option.

Keep classical groups in the list. Clients that don't offer ML-KEM (older browsers, embedded devices, many API clients) must still be able to fall back to X25519 or P-256 — the hybrid group protects the clients that ask for it without breaking the ones that can't.

Verifying it worked

The quickest check is the post-quantum TLS test — it pins a separate handshake to each ML-KEM group and shows exactly which ones your server accepts. From a machine with OpenSSL 3.5+, you can do the same by hand:

openssl s_client -connect example.com:443 -groups X25519MLKEM768 -brief

A successful connection means the server negotiated the hybrid group (the pinned offer leaves it nothing else to choose); a handshake failure means it doesn't support it. In Chrome, DevTools → Security shows the key exchange as "X25519MLKEM768" on protected sites.

What you do not need to change


Made a change? Re-run the post-quantum TLS test to confirm, and check the rest of your protocol hygiene with the TLS version scanner.

Related guides