DEV Community

Nils Eriksson
Nils Eriksson

Posted on

TLS Configuration in 2026: What "Secure" Actually Means Now

TLS Configuration in 2026: What "Secure" Actually Means Now

Meta: Having SSL/TLS is not a security posture. The green padlock tells users nothing useful. This article covers what "secure" actually means in 2026: why TLS 1.0 and 1.1 are dead, what TLS 1.3 actually improved, certificate management, cipher suites, HSTS, NIS2 context, and practical nginx/Apache configs.

Keyword: TLS configuration 2026, TLS 1.3 best practices, SSL TLS setup, NIS2 cryptographic requirements


A client showed me their SSL certificate last week. Green padlock. Certificate valid. Expiry date: 2027.

I checked the TLS version their server was advertising: TLS 1.0.

I told them they had a liability, not a security measure.

They looked confused. "But the lock is green," they said.

Yeah. And that's the problem with how most people think about SSL/TLS.

The Green Padlock Is Not Security

Let me be direct: having HTTPS is not a security posture. It's a basic requirement. Like having a front door. A locked front door keeps out opportunistic thieves, but it doesn't stop an intruder who knows the lock is broken.

The green padlock tells users: "The connection to this server is encrypted." That's true. It doesn't tell them:

  • Whether the encryption is any good
  • Whether the server is who it claims to be
  • Whether the site has other vulnerabilities
  • Whether the cipher suites are modern or ancient

A visitor sees the lock and feels safe. That feeling is mostly marketing.

Your job is to make the lock actually mean something.

TLS 1.0 and 1.1 Are Dead. Stop Running Them.

TLS 1.0 was ratified in 1999. That's 27 years ago. In cryptography terms, it's ancient.

TLS 1.1 came out in 2006. Still ancient.

Both have known attacks. Both are weak. And yet—I still see them in production.

Why they're bad:

  • TLS 1.0 and 1.1 use MD5 and SHA1 for message authentication, both of which are cryptographically broken.
  • They don't protect against various padding attacks.
  • They require cipher suites that modern attackers can break in reasonable time.
  • Every major browser has deprecated them or is actively phasing them out.

Why people still run them:

Usually legacy. An old device (POS terminal, printer, sensor) only speaks TLS 1.0. So they support it. The device works. Problem solved—until an attacker uses the device as an entry point.

What to do:

Disable TLS 1.0 and 1.1. I don't care if you lose 0.01% of traffic from devices that can't upgrade. That 0.01% is a security liability.

If you have a device that only speaks TLS 1.0, you have two options:

  1. Upgrade the device.
  2. Isolate it on its own connection, not the public internet.

There is no third option where it's acceptable to support TLS 1.0 in 2026.

TLS 1.2: The Status Quo

TLS 1.2 has been around since 2008. It's solid. Still widely used. Still secure if configured correctly.

The keyword is if configured correctly. Because TLS 1.2 is flexible, and flexibility means there are wrong ways to use it.

What can go wrong:

  • Using CBC ciphers without AEAD (authenticated encryption with associated data).
  • Supporting cipher suites that use DES, RC4, or other broken ciphers.
  • Not enforcing perfect forward secrecy (PFS).

The good news: if you're enforcing TLS 1.2 or TLS 1.3 and using modern cipher suites, you're fine. You're not using TLS 1.2 for the coolness factor. You're using it because some people on old systems need it.

TLS 1.3: What Actually Changed

TLS 1.3 shipped in 2018. It's been eight years. Most browsers support it. Most servers support it. If you're not using it, you should be asking why.

What TLS 1.3 improved:

  1. Reduced handshake: TLS 1.2 takes two round trips to establish encryption. TLS 1.3 does it in one. This matters for latency, especially on high-latency connections.

  2. Removed broken ciphers: TLS 1.3 only supports AEAD cipher suites. No more negotiation over broken algorithms. No cipher suite downgrade attacks.

  3. Perfect Forward Secrecy by default: In TLS 1.3, every session gets a unique key. Even if someone steals your private key tomorrow, they can't decrypt past sessions. This should have been default all along.

  4. 0-RTT (kind of): You can send data in the initial handshake. This is great for latency. It's also dangerous if misused, but it's there.

  5. Removed renegotiation: TLS 1.2 allowed mid-connection renegotiation, which opened attack vectors. Gone in TLS 1.3.

The practical benefit: TLS 1.3 is faster, more secure, and harder to misconfigure. If you can support it, you should.

Certificates: The Other Half of the Equation

A certificate proves that you own the domain. That's it. It doesn't prove your server is secure. It doesn't prove you're not exfiltrating data. It just proves: yes, this domain belongs to me.

Types of certificates:

  1. Domain Validated (DV): Cheap, easy. The CA checks that you can receive email or modify DNS for the domain. That's all the verification they do. This is fine for most sites. It's what Let's Encrypt issues.

  2. Organization Validated (OV): More expensive. The CA verifies that your organization exists. Browsers display "organization" info. This doesn't make you more secure. Most people don't see it.

  3. Extended Validation (EV): Most expensive. The CA does extensive verification. Browsers used to show a green bar with your company name. That's mostly gone now because users didn't care. Don't bother.

Wildcard certificates: One certificate for multiple subdomains. *.example.com covers api.example.com, cdn.example.com, etc. Be careful with these—if one subdomain is compromised, the attacker has a valid certificate for all of them.

Practical recommendation: Use DV certificates from Let's Encrypt. Free, automated renewal, plenty of entropy. Wildcard if you have lots of subdomains.

Cipher Suites: The Meat of the Config

A cipher suite is the combination of algorithms that TLS uses. In TLS 1.2, you can choose from dozens. In TLS 1.3, the choice is much more limited (in a good way).

For TLS 1.3, use this:

TLS_AES_256_GCM_SHA384
TLS_AES_128_GCM_SHA256
TLS_CHACHA20_POLY1305_SHA256
Enter fullscreen mode Exit fullscreen mode

That's it. All three are solid. All three support perfect forward secrecy. Modern browsers support all three.

For TLS 1.2, if you have to:

ECDHE-ECDSA-AES256-GCM-SHA384
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-ECDSA-CHACHA20-POLY1305
ECDHE-RSA-CHACHA20-POLY1305
Enter fullscreen mode Exit fullscreen mode

See the ECDHE? That's elliptic curve Diffie-Hellman Ephemeral. The ephemeral part means the key is used once and discarded. That's perfect forward secrecy.

Anything without ECDHE (DHE instead, or no PFS at all) is weaker. Don't use it.

HSTS: Permanent Redirect

HSTS (Strict-Transport-Security) tells the browser: "Always use HTTPS for this domain. No exceptions. Even if the user types HTTP, force HTTPS."

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Enter fullscreen mode Exit fullscreen mode

What this does:

  • max-age=31536000 — Remember this for one year (in seconds).
  • includeSubDomains — Apply to all subdomains.
  • preload — Include me in the HSTS preload list (a hardcoded list in browsers).

Why it matters:

Without HSTS, an attacker can intercept the initial HTTP request, before the browser gets redirected to HTTPS. HSTS kills that attack—the browser refuses to connect via HTTP at all.

The warning:

Preload is optional but permanent. Once you're in the list, you can't get out quickly. If you enable HSTS with preload and then decide you need to serve some subdomains over HTTP (for legacy stuff), you're stuck. Browsers won't let you.

Only add preload if you're 100% sure you want HTTPS everywhere, forever.

Also: includeSubDomains is risky if you have any subdomain that doesn't support HTTPS. mail.example.com still on HTTP? HSTS will break it.

I've seen companies destroy services by enabling HSTS incorrectly. Get your HTTPS infrastructure solid first. Then enable HSTS.

Certificates: Expiry and Monitoring

Certificates expire. You need to notice before they do.

Why this matters:

When a certificate expires, the browser shows a warning. The user thinks the site is compromised (or just broken). Traffic drops. Users go somewhere else. You miss the outage because nobody tells you.

How to prevent it:

  1. Automated renewal: Let's Encrypt + certbot automatically renews certificates before expiry. Set it and forget it.

  2. Monitoring: Use a service that checks your certificate expiry and alerts you. There are free options (e.g., checking cert transparency logs, using curl to extract certificate dates).

  3. Certificate Transparency: Your certificates are logged in CT logs (by law, in most jurisdictions). You can check what certificates exist for your domain. Unexpected certificate? That's a sign of account compromise.

NIS2 Context

The NIS2 directive (Network and Information Security Directive 2) came into effect for critical infrastructure in late 2024. For most SMBs, it's not directly applicable yet. But it's worth understanding the direction.

NIS2 requires "encryption of data in transit" for critical systems. It doesn't prescribe TLS. But TLS is the de-facto standard. NIS2 expects:

  • Encryption of data in transit (TLS).
  • Encryption of data at rest (separate topic, but included).
  • Regular security assessments.
  • Incident reporting.

For your purposes: if you're encrypting data in transit with TLS 1.2+ using strong ciphers, you're compliant. If you're running TLS 1.0 or weak ciphers, you're not.

The directive is general enough that it doesn't prescribe specifics. Your security posture matters more than the certificate.

Practical: Nginx Config

Here's a reasonable nginx configuration for 2026:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;

    # Certificates (from Let's Encrypt)
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # TLS protocol: 1.2 and 1.3 only
    ssl_protocols TLSv1.2 TLSv1.3;

    # Cipher suites: strong ciphers first
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
    ssl_prefer_server_ciphers on;

    # Perfect Forward Secrecy
    ssl_dhparam /etc/ssl/dhparam.pem;
    ssl_ecdh_curve secp384r1;

    # Session settings
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;

    # HSTS (be careful with this)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # Other security headers
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Your app config here
    location / {
        proxy_pass http://backend;
    }
}

# Redirect HTTP to HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}
Enter fullscreen mode Exit fullscreen mode

Generate dhparam once:

openssl dhparam -out /etc/ssl/dhparam.pem 2048
Enter fullscreen mode Exit fullscreen mode

Practical: Apache Config

For Apache, use this in your VirtualHost or .htaccess:

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

    # TLS protocols
    SSLProtocol TLSv1.2 TLSv1.3

    # Cipher suites
    SSLCipherSuite 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'
    SSLHonorCipherOrder On

    # DH parameters
    SSLOpenSSLConfCmd DHParameters "/etc/ssl/dhparam.pem"

    # Session
    SSLSessionCache "shmcb:logs/ssl_scache(512000)"
    SSLSessionCacheTimeout 300

    # HSTS
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

    # Other headers
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "DENY"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"

    # Your config here
</VirtualHost>

# Redirect HTTP to HTTPS
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    Redirect permanent / https://example.com/
</VirtualHost>
Enter fullscreen mode Exit fullscreen mode

Testing: Verify You Did It Right

Quick command line test:

openssl s_client -connect example.com:443 -tls1_3
Enter fullscreen mode Exit fullscreen mode

Look for:

  • Protocol: TLSv1.3 (or TLSv1.2 if 1.3 isn't available)
  • Cipher suite information (should show AES-GCM or ChaCha20-Poly1305)
  • Certificate info (expiry date, subject)

Web-based test:

Go to SSL Labs by Qualys (https://www.ssllabs.com/ssltest/). Enter your domain. It'll scan your server and grade it. A grade is a rough measure. A's are good. C's and below means you've got problems.

Browser devtools:

Open your site in a browser, hit F12, go to Security tab. It'll show certificate info and any TLS warnings.

The Common Mistakes

  1. Mixing HTTP and HTTPS: You have HTTPS on the main page but load CSS, JavaScript, or images over HTTP. Browsers block this (mixed content). Enable HSTS and keep everything HTTPS.

  2. Not renewing certificates: The certificate expires, users see a warning, you lose traffic. Automate renewal.

  3. Using self-signed certificates in production: They don't prove anything. Use Let's Encrypt.

  4. Setting HSTS too aggressively: If you enable HSTS with preload and then need to rollback, you're stuck for months. Start with max-age=3600 (one hour), test it, then increase.

  5. Supporting too many legacy ciphers: I've seen configs that support RC4 and DES "just in case." They don't need to. Disable them.

The Checklist

Before you deploy:

  • [ ] TLS 1.2 and 1.3 only. No 1.0, 1.1, or SSL.
  • [ ] Strong cipher suites with ECDHE or DHE (PFS).
  • [ ] Certificate from a trusted CA (Let's Encrypt is fine).
  • [ ] Certificate valid for your domain (no warnings).
  • [ ] HSTS enabled (but test with short max-age first).
  • [ ] Automated renewal (certbot for Let's Encrypt).
  • [ ] Test with SSL Labs (aim for A or A+).
  • [ ] HTTP redirects to HTTPS.
  • [ ] No mixed content warnings.

That's security in 2026. Not complicated. Just discipline.


Nils Eriksson is a Stockholm-based security consultant. He writes about web security, bad practices, and the occasional existential crisis caused by production deployments.

Top comments (0)