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.

  1. Your Nginx version must support TLS 1.3. That means nginx 1.13 or above.
  2. 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.

Update: Chrome 70 added support for the final version of TLS 1.3, but it by default is stilling using draft 28 of TLS 1.3.

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.

Rate this tutorial

[Total: 27 Average: 4.3]