// Engineering Log

HTTP, HTTPS and TLS: Part 5 — TLS Versions, Cipher Suites, SNI, ALPN, ECH and mTLS

Published on 2026-10-05

// Fast route

This article belongs to the topic Security and protection.

Under the phrase “TLS type” people usually mean different things: protocol version (1.2 or 1.3), cipher suite, certificate type (DV, OV, EV) or a scheme where the client also presents a certificate (mTLS). In this part — all four, plus ClientHello extensions that determine which site and which protocol the client will get: SNI, ALPN and ECH.

Protocol versions

VersionYearStatus
SSL 2.01995prohibited (RFC 6176)
SSL 3.01996prohibited (RFC 7568), POODLE attack
TLS 1.01999deprecated (RFC 8996, 2021)
TLS 1.12006deprecated (RFC 8996, 2021)
TLS 1.22008supported, requires correct configuration
TLS 1.32018current, recommended

Browsers disabled TLS 1.0 and 1.1 in 2020. On servers today you enable TLS 1.2 and 1.3. You can leave only 1.3 enabled if your clients do not include old hardware and software: Android versions before 10, Java 8 without updates, old versions of .NET, and embedded clients in cash registers and terminals support only 1.2.

Cipher suite

A cipher suite is a combination of algorithms agreed by the client and server. In TLS 1.2 the name describes everything at once:

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
     │     │        │           └ hash for key derivation
     │     │        └ data cipher and mode (AEAD)
     │     └ certificate signature algorithm
     └ key exchange

In TLS 1.3 the key exchange and signature are moved to separate extensions, and the cipher suite describes only the cipher and hash. There are only five of them, and all are secure:

  • TLS_AES_128_GCM_SHA256;
  • TLS_AES_256_GCM_SHA384;
  • TLS_CHACHA20_POLY1305_SHA256 — faster than AES on processors without AES hardware acceleration, for example on some ARM chips;
  • TLS_AES_128_CCM_SHA256 and TLS_AES_128_CCM_8_SHA256 — for embedded devices, not used on the web.

For TLS 1.2 you should keep only suites with ECDHE key exchange (forward secrecy) and AEAD ciphers — GCM or ChaCha20-Poly1305. Disable:

  • RSA key exchange (TLS_RSA_WITH_...) — no forward secrecy;
  • CBC-mode ciphers — source of attacks like Lucky13;
  • RC4, 3DES, NULL, EXPORT, anonymous suites.

Key exchange and post-quantum cryptography. The groups for key exchange are x25519, secp256r1, secp384r1. Since late 2024 Chrome, and then Firefox and Safari, by default offer a hybrid group X25519MLKEM768: classic X25519 together with the post-quantum ML-KEM algorithm. The idea is to protect against a “record-now, decrypt-later” scenario where traffic is stored in hopes of a future quantum computer. OpenSSL supports it since version 3.5 (2025). The ClientHello key with this group is over 1 KB and doesn’t fit into a single TCP packet — some old firewalls and load balancers break on that.

Ready configuration for Nginx

Don’t pick ciphers manually. Mozilla maintains a configuration generator (ssl-config.mozilla.org) with three profiles: modern (TLS 1.3 only), intermediate (TLS 1.2 and 1.3, recommended for most sites) and old (for compatibility with very old clients). The intermediate profile for Nginx looks roughly like this:

nginx
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;

ssl_ciphers applies only to TLS 1.2: TLS 1.3 cipher suites in OpenSSL are configured separately, and the defaults are fine. ssl_prefer_server_ciphers off gives the choice to the client — all the remaining suites are secure, and the client knows better whether it has hardware AES.

You can check the result with the SSL Labs service (ssllabs.com/ssltest) or locally with the testssl.sh utility, which works for internal addresses as well.

SNI

SNI (Server Name Indication, RFC 6066) is a ClientHello extension in which the client writes the site name in plaintext. Without it, a server hosting multiple sites on one IP doesn’t know which certificate to present: the handshake happens before the Host header arrives.

Important to know:

  • in Nginx the certificate is selected by server_name according to SNI; if SNI is missing or the name is unknown, it responds with the default_server for that listen — and the client receives someone else’s certificate;

  • to avoid exposing other sites’ certificates on an IP request, create an empty default server that aborts the handshake:

    nginx
    server {
        listen 443 ssl default_server;
        ssl_reject_handshake on;   # Nginx 1.19.4+
    }
  • SNI is the main signal used by DPI equipment to determine which site traffic is going to and to block it;

  • IP addresses are not sent in SNI: when accessing https://192.0.2.10/ the field is empty.

ALPN

ALPN (Application-Layer Protocol Negotiation, RFC 7301) is an extension in which the client lists protocols and the server selects one: h2, http/1.1, h3 for QUIC. This is how HTTP/2 is negotiated without extra round trips. ALPN is also used by other protocols over TLS: acme-tls/1 for Let’s Encrypt domain validation via TLS-ALPN-01, dot for DNS-over-TLS.

ECH

SNI and ALPN go in ClientHello in plaintext. The ECH extension (Encrypted Client Hello, RFC 9849, March 2026) encrypts them with a key that the server publishes in a DNS HTTPS record — an observer sees only the provider’s common name. How ECH works, where it is deployed and why connections with it are blocked in Russia are explained in the article “What is ECH”.

Types of certificates: DV, OV, EV

The only difference is what the CA checked before issuance — encryption is the same for all.

  • DV (Domain Validation) — only domain control is verified: a file on the site (HTTP-01) or a DNS record (DNS-01). Issued automatically in minutes. Let’s Encrypt, ZeroSSL, Google Trust Services issue only DV — and that’s sufficient for any website.
  • OV (Organization Validation) — the organization is additionally verified. The company name is visible in the certificate details, but browsers do not highlight it.
  • EV (Extended Validation) — extended verification. Browsers used to show the company name in green in the address bar; since 2019 they no longer do. EV no longer gives additional benefits to users.

Separately for name coverage: single-domain, multi-domain (several names in SAN) and wildcard (*.example.ru). Let’s Encrypt issues wildcard only via DNS-01 validation.

Russian certificates. Since 2022 the Ministry of Digital Development issues certificates for Russian sites from its own certificate authority (Russian Trusted Root CA). That root is not in the stores of Chrome, Firefox and Safari; it is supported by Yandex Browser and Atom; in other browsers and in the OS the root must be installed manually. Separately, TLS using Russian GOST algorithms exists — it is used in government systems and requires certified cryptographic modules on both sides.

mTLS: client certificate

In ordinary HTTPS only the server presents a certificate. In mutual authentication (mutual TLS, mTLS) the server requests a certificate from the client as well and allows only those whose certificate is signed by a trusted CA. It is used for access to admin panels, communication between microservices, receiving webhooks, and partner APIs.

Configuration in Nginx:

nginx
server {
    listen 443 ssl;
    server_name admin.example.ru;

    ssl_certificate     /etc/letsencrypt/live/admin.example.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/admin.example.ru/privkey.pem;

    ssl_client_certificate /etc/nginx/client-ca.crt;  # CA that issues client certificates
    ssl_verify_client on;                             # optional — allow without certificate
    ssl_verify_depth 2;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header X-Client-DN $ssl_client_s_dn;
    }
}

Create your own CA and a client certificate:

bash
# CA
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \
  -keyout client-ca.key -out client-ca.crt -days 3650 -subj "/CN=Example Client CA"

# client key and CSR
openssl req -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \
  -keyout ivanov.key -out ivanov.csr -subj "/CN=ivanov"

# sign the CSR
openssl x509 -req -in ivanov.csr -CA client-ca.crt -CAkey client-ca.key \
  -CAcreateserial -out ivanov.crt -days 365

Check:

bash
curl https://admin.example.ru/                                   # 400 No required SSL certificate was sent
curl --cert ivanov.crt --key ivanov.key https://admin.example.ru/ # 200

For a browser the certificate is packaged into PKCS#12: openssl pkcs12 -export -in ivanov.crt -inkey ivanov.key -out ivanov.p12 — and imported into the system.

The client CA does not need to be public; on the contrary: if you specify a public CA in ssl_client_certificate, anyone who buys a certificate from it will pass. For revoking client certificates — ssl_crl. If there is a CDN or load balancer in front of Nginx that terminates TLS itself, configure mTLS on it.

Common mistakes

  • TLS 1.0 and 1.1 are left enabled “for compatibility” — security scanners and PCI DSS flag this as a vulnerability.
  • A long list of ciphers in the config copied ten years ago that includes CBC and RSA key exchange — use Mozilla’s generator.
  • No empty default_server with ssl_reject_handshake — scanners requesting the IP address get a certificate covering all your domains.
  • A wildcard certificate is copied to dozens of servers — compromise of one reveals all subdomains. Better to use separate certificates via ACME.
  • mTLS with ssl_verify_client optional without checking $ssl_client_verify in the application — a client without a certificate will pass.

// Similar task

If you are dealing with something similar

This article belongs to one of the main working topics. You can keep reading on the topic, go to the homepage to understand what I do, or open the service pages directly.

Article topic

Security and protection

SSL, hardening, access control, service protection, and secure configurations.

Typical tasks behind this topic

  • Set up SSL, certificates, and secure connections
  • Restrict access and close unnecessary entry points
  • Harden server and service configuration

// Next step

If you need help with this topic, not just another article, it is better to go straight to the service page. The homepage and topic collection stay available as secondary routes.

Open services

// Reviews

Related reviews

apande

apande

Configuring Nginx and OpenCart

2024-09-07 · ★ 5/5

A very powerful buyer
kireevk

kireevk

Diagnosing Nginx Proxy Manager in a Docker container and resolving the issue

2024-03-15 · ★ 5/5

Settled-in customer

// Contact

Need help?

Get in touch with me and I'll help solve the problem

I reply within one business day (03:00-13:00 GMT)

Или оставьте заявку здесь:

Confirm that you are not a bot.

Write and get a quick reply