How to Enable TLS 1.3 in Nginx on Debian 9

Published on: Fri, Aug 16, 2019 at 11:00 am EST
Linux Guides Security Web Servers

Introduction

TLS 1.3 is a version of the Transport Layer Security (TLS) protocol published in 2018 as a proposed standard in RFC 8446. It offers security and performance improvements over its predecessors.

This guide explains how to enable TLS 1.3 using the Nginx web server on Debian 9.

Requirements

  • Nginx version 1.13.0 or greater.
  • OpenSSL version 1.1.1 or greater.
  • Vultr Cloud Compute (VC2) instance running Debian 9 x64 (stretch).
  • A valid domain name and properly configured A/AAAA/CNAME DNS records for your domain.
  • A valid TLS certificate. We will get one from Let's Encrypt.

Before you begin

Check the Debian version.

lsb_release -ds
# Debian GNU/Linux 9.9 (stretch)

Ensure that your system is up to date.

apt update && apt upgrade -y

Install the necessary packages.

apt install -y git unzip curl sudo socat build-essential

Create a new non-root user account with sudo access and switch to it.

adduser johndoe --gecos "John Doe"
usermod -aG sudo johndoe
su - johndoe

NOTE: Replace johndoe with your username.

Set up the timezone.

sudo dpkg-reconfigure tzdata

Install the Acme.sh client and obtain a TLS certificate from Let's Encrypt

Download and install Acme.sh.

sudo mkdir /etc/letsencrypt
sudo git clone https://github.com/Neilpang/acme.sh.git
cd acme.sh 
sudo ./acme.sh --install --home /etc/letsencrypt --accountemail your_email@example.com
cd ~
source ~/.bashrc

Check the version.

/etc/letsencrypt/acme.sh --version
# v2.8.2

Obtain RSA and ECDSA certificates for your domain.

# RSA 2048
sudo /etc/letsencrypt/acme.sh --issue --standalone --home /etc/letsencrypt -d example.com --ocsp-must-staple --keylength 2048
# ECDSA
sudo /etc/letsencrypt/acme.sh --issue --standalone --home /etc/letsencrypt -d example.com --ocsp-must-staple --keylength ec-256

NOTE: Replace example.com with your domain name.

After running the previous commands, your certificates and keys are accessible in the following locations:

  • RSA: /etc/letsencrypt/example.com
  • ECC/ECDSA: /etc/letsencrypt/example.com_ecc

Build Nginx from Source

Nginx added support for TLS 1.3 in version 1.13.0. On most Linux distributions, including Debian 9, Nginx is built with the older OpenSSL version, which does not support TLS 1.3. Consequently, we need our own custom Nginx build linked to the OpenSSL 1.1.1 release, which includes support for TLS 1.3.

Download the latest mainline version of the Nginx source code and extract it.

wget https://nginx.org/download/nginx-1.17.0.tar.gz && tar zxvf nginx-1.17.0.tar.gz

Download the OpenSSL 1.1.1c source code and extract it.

# OpenSSL version 1.1.1c
wget https://www.openssl.org/source/openssl-1.1.1c.tar.gz && tar xzvf openssl-1.1.1c.tar.gz

Delete all .tar.gz files, as they are not needed anymore.

rm -rf *.tar.gz

Enter the Nginx source directory.

cd ~/nginx-1.17.0

Configure, compile, and install Nginx. For simplicity's sake, we will compile only essential modules that are required for TLS 1.3 to work. If you need a full Nginx build, you can read this Vultr guide about Nginx compilation.

./configure --prefix=/etc/nginx \
            --sbin-path=/usr/sbin/nginx \
            --modules-path=/usr/lib/nginx/modules \
            --conf-path=/etc/nginx/nginx.conf \
            --error-log-path=/var/log/nginx/error.log \
            --pid-path=/var/run/nginx.pid \
            --lock-path=/var/run/nginx.lock \
            --user=nginx \
            --group=nginx \
            --build=Debian \
            --builddir=nginx-1.17.0 \
            --http-log-path=/var/log/nginx/access.log \
            --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 \
            --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
            --http-scgi-temp-path=/var/cache/nginx/scgi_temp \
            --with-compat \
            --with-http_ssl_module \
            --with-http_v2_module \
            --with-openssl=../openssl-1.1.1c \
            --with-openssl-opt=no-nextprotoneg \
            --without-http_rewrite_module \
            --without-http_gzip_module

make
sudo make install

Create an Nginx system group and user.

sudo adduser --system --home /nonexistent --shell /bin/false --no-create-home --disabled-login --disabled-password --gecos "nginx user" --group nginx

Symlink /usr/lib/nginx/modules to /etc/nginx/modules. The latter is a standard place for Nginx modules.

sudo ln -s /usr/lib/nginx/modules /etc/nginx/modules

Create Nginx cache directories and set the proper permissions.

sudo mkdir -p /var/cache/nginx/client_temp /var/cache/nginx/fastcgi_temp /var/cache/nginx/proxy_temp /var/cache/nginx/scgi_temp /var/cache/nginx/uwsgi_temp
sudo chmod 700 /var/cache/nginx/*
sudo chown nginx:root /var/cache/nginx/*

Check the Nginx version.

sudo nginx -V

# nginx version: nginx/1.17.0 (Debian)
# built by gcc 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)
# built with OpenSSL 1.1.1c  28 May 2019
# TLS SNI support enabled
# configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx . . .
# . . .

Create an Nginx systemd unit file.

sudo vim /etc/systemd/system/nginx.service

Populate the file with the following configuration.

[Unit]
Description=nginx - high performance web server
Documentation=https://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

Start and enable Nginx.

sudo systemctl start nginx.service
sudo systemctl enable nginx.service

Create conf.d, sites-available and sites-enabled directories in /etc/nginx.

sudo mkdir /etc/nginx/{conf.d,sites-available,sites-enabled}

Run sudo vim /etc/nginx/nginx.conf and add the following two directives to the end of the file, just before the closing }.

    . . .
    . . .
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*.conf;
}

Save the file and exit with :+W+Q.

Configure Nginx for TLS 1.3

Now that we have successfully built Nginx, we are ready to configure it to start using TLS 1.3 on our server.

Run sudo vim /etc/nginx/conf.d/example.com.conf and populate the file with the following configuration.

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;

  # RSA
  ssl_certificate /etc/letsencrypt/example.com/fullchain.cer;
  ssl_certificate_key /etc/letsencrypt/example.com/example.com.key;
  # ECDSA
  ssl_certificate /etc/letsencrypt/example.com_ecc/fullchain.cer;
  ssl_certificate_key /etc/letsencrypt/example.com_ecc/example.com.key;

  ssl_protocols TLSv1.2 TLSv1.3;
  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:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
  ssl_prefer_server_ciphers on;
}

Save the file and exit with :+W+Q.

Notice the new TLSv1.3 parameter of the ssl_protocols directive. This parameter is necessary to enable TLS 1.3.

Check the configuration.

sudo nginx -t

Reload Nginx.

sudo systemctl reload nginx.service

To verify TLS 1.3, you can use browser dev tools or SSL Labs service. The screenshots below show Chrome's security tab that indicates that TLS 1.3 is working.

Congratulations! You have successfully enabled TLS 1.3 on your Debian 9 server.

Want to contribute ?

You could earn up to $300 by adding new articles