How to enable TLS 1.3 on Nginx

How to enable TLS 1.3 on Nginx

TLS 1.3 is the new TLS version that will power a faster and more secure web for the next few years.

The final release of TLS .13 has been out since august 2018. The final draft is supported by OpenSSL in its 1.1.1 version.

LibreSSL does not support TLS 1.3 as of today, since they want to do a clean implementation.

Nginx supports TLS 1.3 since version 1.13.0 (released in April 2017), when built against OpenSSL 1.1.1. Before the stable OpenSSL release, it has been possible to build Nginx with OpenSSL 1.1.1 pre-releases, containing TLS 1.3 drafts. It is important to note that drafts of RFC 8446 can be incompatible.

Now that OpenSSL 1.1.1 has a stable release, we can enjoy TLS 1.3 on Nginx!

First, make sur your Nginx version is >= 1.13.0, and built against OpenSSL 1.1.1 or more. For most distributions, it may be a bit early.

FYI, OpenSSL 1.1.1 comes with:

For Debian and Ubuntu, I made a script to compile Nginx with a bunch of modules, in which you can choose your OpenSSL/LibreSSL version.

During my tests, I used the latest stable version, compiled and running on Debian 9:

root@server:~# nginx -V
nginx version: nginx/1.14.0
built by gcc 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)
built with OpenSSL 1.1.1 11 Sep 2018
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --user=nginx --group=nginx --with-cc-opt=-Wno-deprecated-declarations --without-http_ssi_module --without-http_scgi_module --without-http_uwsgi_module --without-http_geo_module --without-http_split_clients_module --without-http_memcached_module --without-http_empty_gif_module --without-http_browser_module --with-threads --with-file-aio --with-http_ssl_module --with-http_v2_module --with-http_mp4_module --with-http_auth_request_module --with-http_slice_module --with-http_stub_status_module --with-http_realip_module --with-openssl=/usr/local/src/nginx/modules/openssl-1.1.1

If your version of Nginx supports TLS 1.3, it is really simple to enable:

ssl_protocols TLSv1.2 TLSv1.3;

Contrary to previous versions, TLS 1.3 has it own ciphers. We need no add them, otherwise no TLS 1.3 handshake will succeed.

The ciphers are the 3 following:

  • TLS13-CHACHA20-POLY1305-SHA256
  • TLS13-AES-256-GCM-SHA384
  • TLS13-AES-128-GCM-SHA256

OR:

  • TLS-CHACHA20-POLY1305-SHA256
  • TLS-AES-256-GCM-SHA384
  • TLS-AES-128-GCM-SHA256

These are the exact same (TLS vs TLS13) as of today. I prefer to use TLS13 since it's more explicit. As you can see, non-PFS and non-AEAD ciphers have been dropped, so no more DHE or AES CBC.

Here is the cipher suite I recommend:

ssl_ciphers TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:EECDH+CHACHA20:EECDH+AESGCM:EECDH+AES;

It enables TLS 1.3 ciphers as well as, for TLS 1.2, AES CBC/GCM 128/256 bits, CHACHA20, ECDSA/RSA and EECDH.

You should be able to reload/restart your Nginx server, and if everything went well, you now have TLS 1.3 support!

You can head to SSL Labs, which should tell you:

This server supports TLS 1.3 (RFC 8446).

As of the web browsers, most of them have been supporting the multiple drafts published over the last year and a half. We're using the final draft here, which is only supported since Chrome 70 and Firefox 62. It is in development for other browsers.

X25519 FTW!

You can check the status of TLS 1.3 support on Can I use.

Stanislas
Author
Stanislas
I like building things with code and computers

Comments

15Atom feed
Markdown supported
  1. normcore

    Hi, I have installed my nginx using their official Docker image (latest), do you think TLS 1.3 will work? I do not know how their image is built but I do use chacha20 and x25519 with tls 1.2.

    1. StanislasAuthor

      The Debian image is based on Stretch, and the Alpine image is based on Alpine 3.8, both of them have OpenSSL 1.0.2, so no, for now.

    2. Zvonimir

      I found the nginx:stable-alpine is updated to alpine 3.9, and have openssl 1.1.1a, but I haven't test it yet.

  2. Anonymous

    Hi, thanks for the guide. I've been trying to implement TLS1.3 as well, but didn't really get it to work. I installed nginx using your autoinstall script with OpenSSL 1.1.1, but activating TLS1.3 and updating the ciphers did nothing... Maybe the OpenSSL install on the system itself also needs to be up to date? Maybe you've got another idea ^_^ (https://pastebin.com/a32EnDp4)

    1. StanislasAuthor

      That should work! The issue is probably somewhere else in your configuration... Is this the correct vhost? Did you restart Nginx? How did you test TLS 1.3?

    2. Anonymous

      K, thanks for looking over my config! I reloaded & restarted nginx, definitely tested it on several correct vhosts. But my FF 63 and Chromium 70 both load with TLS1.2, and SSL Labs says so as well. Been googling for a while also, but no clue...

  3. Yuri

    Hi, I have read the article and have a question: you sort the ciphers: ssl_ciphers TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:..... but SSL Labs return the next list ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256.... Does nginx have the bug with server-preferred order?

    1. StanislasAuthor

      Make sure you have ssl_prefer_server_ciphers set to on in your configuration.

    2. StanislasAuthor

      Ah, sorry! Indeed, this is weird... I'll do some testing to see if this is an issue with SSL Labs or Nginx.

  4. Dario Zadro

    Hi, great article! Any idea how to get nginx re-built to work with TLS 1.3? I'm guessing the "built with openssl 1.1.0" line is the issue.

    Here's what I get from nginx -V

    nginx version: nginx/1.15.12 built by gcc 6.3.0 20170516 (Debian 6.3.0-18+deb9u1) built with OpenSSL 1.1.0j 20 Nov 2018 (running with OpenSSL 1.1.1b 26 Feb 2019)

    I'm actually on Debian 9 and not sure why it says 6.3

    Any insight would be much appreciated.

  5. enoch85

    No matter which chipers I set, I don't get it to show TLS1.3 supported on SSL Labs. Tried several guides, not just this.

    Running Nginx 1.16.1 (PPA:nginx/stable) + openssl 1.1.1.

    Gah!

  6. John

    I ran ssllabs test on your suggested cipher config (19-02-2020) and got a few weak algos:

    TLS 1.2 (suites in server-preferred order)TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030) ECDH secp256r1 (eq. 3072 bits RSA) FS256

    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f) ECDH secp256r1 (eq. 3072 bits RSA) FS128 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028) ECDH secp256r1 (eq. 3072 bits RSA) FS
    WEAK256TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014) ECDH secp256r1 (eq. 3072 bits RSA) FS
    WEAK256TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027) ECDH secp256r1 (eq. 3072 bits RSA) FS
    WEAK128TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013) ECDH secp256r1 (eq. 3072 bits RSA) FS
    WEAK128