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 [email protected]
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.
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.