How To Enable TLS 1.3 in Nginx on Ubuntu 18.04 and 16.04
HTTPS just got faster and safer thanks to the release of TLS 1.3 by IETF (RFC 8446) in August 2018. TLS 1.3 is now the latest version of the TLS protocol. This tutorial will be showing you how to enable TLS 1.3 in Nginx web server on Ubuntu 18.04 and Ubuntu 16.04.
Update: There’s an easier way to enable TLS 1.3. See this article: How to easily enable TLS 1.3 in Nginx on Ubuntu 18.10, 18.04, 16.04, 14.04
TLS 1.3: Improved Performance and Security
Performance-wise, TLS 1.2 needs two round trips to establish HTTPS connection. With TLS 1.3, only one round trip is required. TLS 1.3 also supports zero round trip mode (0-RTT session resumption), allowing clients who have previously connected to your website to send HTTP request on the first message to the server. This makes a big difference for users on mobile networks or at far distant locations.
In terms of security, TLS 1.3 removed support for old cipher suites, which is responsible for exploits like ROBOT attack. As such server admins can no longer add old cipher suites in TLS 1.3 to appease users of old web browsers. This, of course, is an oversimplified explanation. CloudFlare has a good detailed explanation of TLS 1.3.
Enable TLS 1.3 in Nginx on Ubuntu 18.04, Ubuntu 16.04
There are two requirements when it comes to enable TLS 1.3 with Nginx.
- Your Nginx version must support TLS 1.3. That means nginx 1.13 or above.
- Nginx needs to either be built with OpenSSL 1.1.1+, or runs with OpenSSL 1.1.1+.
The second requirement may sound confusing, so let me give you two examples.
- Ubuntu 18.04 ships with OpenSSL 1.1.0. Replacing the system OpenSSL library isn’t a good idea, but you can download OpenSSL 1.1.1 source code and compile Nginx with OpenSSL 1.1.1 source code to enable TLS 1.3.
- Arch Linux currently ships with OpenSSL 1.1.1, but the Nginx package in Arch repository is actually built with OpenSSL 1.1.0. In this case, Nginx isn’t built with OpenSSL 1.1.1, but it runs with OpenSSL 1.1.1.
Now let’s see how to compile Nginx with OpenSSL 1.1.1 on Ubuntu 18.04 and Ubuntu 16.04.
1. Adding the Official Nginx Repository
Instead of downloading the source tarball and compiling it with make
, I’m going to add the official Nginx repository to my Ubuntu server and then create a deb package from source code. In this way, I don’t need to manually add a long list of configuration parameter to the configure
command. Also there will be a handy systemd service file within the deb package.
First fetch the Nginx GPG key and import it to Ubuntu.
wget http://nginx.org/keys/nginx_signing.key sudo apt-key add nginx_signing.key
Then create a source list file for Nginx repo.
sudo nano /etc/apt/sources.list.d/nginx.list
Add the following two lines into the file. The deb-src
line allows us to download Nginx source packages with apt source
command. Bonic
is the codename for Ubuntu 18.04. If you are using Ubuntu 16.04, replace it with xenial
. (Note: This repository doesn’t support 32 bit OS.)
deb [arch=amd64] http://nginx.org/packages/mainline/ubuntu/ bionic nginx deb-src http://nginx.org/packages/mainline/ubuntu/ bionic nginx
To save a file in Nano text editor, press Ctrl+O
, then press Enter to confirm. To exit, press Ctrl+X
. Then update local package index.
sudo apt update
Now the Nginx official repository is added to Ubuntu server.
2. Download Nginx and OpenSSL Source Code
We will make a nginx
directory under /usr/local/src/
to store the Nginx sources and then cd
into that directory.
sudo mkdir /usr/local/src/nginx cd /usr/local/src/nginx/
Download Nginx source package with the command below:
sudo apt install dpkg-dev sudo apt source nginx
Check out the downloaded files.
ls
Output:
nginx-1.15.3 nginx_1.15.3-1~bionic.dsc nginx_1.15.3-1~bionic.debian.tar.xz nginx_1.15.3.orig.tar.gz
Then clone the OpenSSL github repository.
cd /usr/local/src sudo apt install git sudo git clone https://github.com/openssl/openssl.git cd openssl
Next, list all branches and switch to the 1.1.1 stable branch.
git branch -a sudo git checkout OpenSSL_1_1_1-stable
3. Edit Nginx Compile Rules
Edit Nginx compile rules file.
sudo nano /usr/local/src/nginx/nginx-1.15.3/debian/rules
Find config.status.nginx: config.env.nginx
section. Add the following text at the end of CFLAGS line. Note that the following text isn’t a line by itself.
--with-openssl=/usr/local/src/openssl
Save and close the file.
4. Compile Nginx
Make sure you are in the Nginx source directory.
cd /usr/local/src/nginx/nginx-1.15.3/
Install dependencies to build our Nginx deb package.
sudo apt build-dep nginx
Now use the following command to build the deb package.
sudo dpkg-buildpackage -b
If you see the following error,
missing initializer for field 'md_ctrl' of 'EVP_MD {aka const struct evp_md_st}
Then edit the auto/cc/gcc
file.
sudo nano /usr/local/src/nginx/nginx-1.15.3/auto/cc/gcc
Comment out the following line. The -Werror
flag makes GCC treat warnings as errors.
CFLAGS="$CFLAGS -Werror"
Then rerun the build command. Once the build is complete, there will be a Nginx deb package in /usr/local/src/nginx/
directory. If you have installed Nginx before, it’s time to remove the old version and then install the new version.
sudo apt remove nginx nginx-common nginx-full
cd /usr/local/src/nginx/
sudo dpkg -i nginx_1.15.3-1~bionic_amd64.deb
Now let’s start Nginx.
sudo systemctl start nginx
If you see the following error message.
Failed to start nginx.service: Unit nginx.service is masked.
Then unmask nginx and issue the start command again.
sudo systemctl unmask nginx
Note that the Nginx process might run as user nginx
or www-data
. This can be changed by editing the first line in /etc/nginx/nginx.conf
file. Just make sure Nginx run as the same user with PHP-FPM.
Now check the config arguments of Nginx.
sudo nginx -V
As you can see, we have the latest version of Nginx built with OpenSSL 1.1.1.
5. Enable TLS 1.3 in Nginx Server Block
Now I assume that you have already enabled HTTPS for your Nginx server block. The syntax to enable TLS 1.3 is fairly easy. Open your Nginx server block file in /etc/nginx/conf.d/
directory or /etc/nginx/sites-enabled/
directory. Find the following line.
ssl_protocols TLSv1.2;
Add TLSv1.3
to the list of protocols.
ssl_protocols TLSv1.2 TLSv1.3;
Then add the following 3 cipher suites to your existing cipher suites.
TLS-CHACHA20-POLY1305-SHA256 TLS-AES-256-GCM-SHA384 TLS-AES-128-GCM-SHA256
like so:
ssl_ciphers 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256: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:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
Save and close the file. Then test Nginx configuration and reload.
sudo nginx -t sudo systemctl reload nginx
It’s unlikely that Ubuntu 18.04 would switch to OpenSSL 1.1.1, so if you upgrade Nginx with sudo apt upgrade
command, TLS 1.3 will be gone. It’s a good idea to hold Nginx from being upgraded by apt
with this command:
sudo apt-mark hold nginx
Update: As of Nginx 1.15.4, you can enable 0-RTT with OpenSSL by adding the following directive in the ssl server context. The default value is set to off
. In the previous version 1.15.3, it can only be used with BoringSSL.
ssl_early_data on
Enable TLS 1.3 in Google Chrome
Currently, Firefox 62 and Chrome 69 only support draft 28 of TLS 1.3. OpenSSL 1.1.1 supports the final version of TLS 1.3. Implementations based on draft version and the final RFC version do not interoperate with each other.
To test our Nginx server now, we need to install the beta version of Google Chrome and enable the final version of TLS 1.3. Once you have Chrome beta installed, Enter chrome://flags/#tls13-variant
in the address bar and switch from default
to Enabled (Final)
. Then relaunch Google Chrome for the change to take effect.
Now visit your TLS 1.3 enabled website in Google Chrome beta and press Ctrl+Shift+I
to open the developer tools page. Go to Security
tab. You can see the version of TLS in use.
Firefox is said to ship the final version of TLS 1.3 in Firefox 63, scheduled for October 2018. In Chrome 70, the final version of TLS 1.3 will be enabled for outgoing connections.
Enable TLS 1.3 with CloudFlare
If you are using CloudFlare CDN (Content Delivery Network), then your website is already using TLS1.3. In CloudFlare dashboard, select the crypto
tab and you will see the option to enable/disable TLS 1.3. You can also enable 0-RTT. CloudFlare supports both the draft 28 version and the final version.
That’s it! I hope this tutorial helped you enable TLS 1.3 in Nginx on Ubuntu 18.04 and Ubuntu 16.04. Take care.
I compiled correctly and made the right configurations. I used Letsencrypt to generate the keys, yet I still end up with TLSv1.2 as the the highest supported protocol.
As explained in this article, the current stable version of Firefox and Chrome by default support the draft 28 of TLS 1.3. You can change Chrome settings to make it support the final version of TLS 1.3. In Firefox I have’t found such setting.
I have a site in Cloudflare with enabled TLSv1.3 and this same browser shows that it utilizes TLSv1.3. This site shows TLSv.1.3 as well.
Doing SSL tests as well shows TLSv1.2 is used.
Are you sure your ciphers are correct, shouldn’t they include 13:
TLS13-AES-
Sorry, I forgot to tell you that you need to use Google Chrome beta and change the TLS 1.3 version. Chrome stable doesn’t include setting to switch to TLS 1.3 final version.
Both
and
are OK with Nginx.
It’s not about Chromes draft settings, both Beta and standard use the same 23 and 28, there is no final version in Beta.
I tried to access the site I have on Cloudflare and it shows TLSv1.3 both on draft 23 and 28.
Chrome Beta on Mac doesn’t incorporate the Final draft, Windows does. I will test it on my Windows machine.
But how come this site runs v1.3 even though I’m using standard Chrome (draft 28)? Is it compiled with an older version of OpenSSL?
Because this site is on CloudFlare, which supports both draft 28 and final version.
If I already have nginx installed through a Linux package and sites running on it, should I remove the package after I have compiled nginx or prior? Or there is not difference and it won’t break my sites if I don’t purge the conf files.
You can uninstall the previous Nginx package at any time before installing the new one. Your sites will be down for a few moment.
Don’t purge your existing server block configuration files.
I also try this tutorial, my Nginx show built with OpenSSL 1.1.1a-dev, regenerate my site Keys, installed Chrome 70…but no TLS 1.3. Can’t understand whats happening.
Wow, i tested with Dev version and i get YES to TLS 1.3, if you want to test: https://dev.ssllabs.com/ssltest/
Thanks! YMMV but it looks like one does not even have to change cipher suites config after TLS1.3 is enabled – openssl enables them by default – see: https://wiki.openssl.org/index.php/TLS1.3#Ciphersuites
I recompiled nginx with openssl 1.1.1 and everything started working after I enabled TLS1.3 protocol.
i faced problem after doing this step
Comment out the following line. The -Werror flag makes GCC treat warnings as errors.
CFLAGS=”$CFLAGS -Werror”
the problem was clearsign failed: no secret key
could you help me in solving the error
Please post the nearby message as well.
dpkg-source — after-build nginx 1.15.6
dpkg-buildpackage: binary-only upload(no source code included)
signfile nginx_1.15.6-1~bionic_amd64.changes
gpg: key ‘/home/sumaia/.gnupg/pubring.kbx’ created
gpg: skipped “konstantin pavlov “: No secret key
gpg: dpkg-sign.a_V4GIGK/nginx_1.15.6-1~bionic_amd64.changes: clearsign failed: No secret key
This is normal. It just means the generated files can’t be signed because you don’t have a private key on this system. You can proceed to install the package.
i faced another problem when i run
sudo dpkg -i nginx_1.15.3-1~bionic_amd64.deb
it said me that:
dpkg: error processing archive nginx_1.15.3-1~bionic_amd64.deb (–install):
cannot access archive: No such file or directory
Errors were encounterd while processing:
nginx_1.15.3-1~bionic_amd64.deb
can you help me
Your Nginx version is now 1.15.6. Please replace 1.15.3 with 1.15.6.
thank you very much for your article it helped me to pass in TLS 1.3 and also to compile nginx with open ssl 1.1.1
Everything working as expected following guide for Ubuntu 16.04, thanks 🙂
Great tutorial!
In case that someone encounters this error during build:
You must modify this file:
Look for this line:
And change it to add this flag
Many thanks for “missing initializer for field ‘md_ctrl’ of ‘EVP_MD {aka const struct evp_md_st}”