This tutorial provides the steps to configure Nginx Web Server to allow only TLS 1.2 or TLS 1.3 or both to increase the security of the web applications served by it. This is required since there are several known vulnerabilities including POODLE for SSL or TLS versions older than TLS 1.2. We must either enable TLS 1.2 only or TLS 1.3 only or both depending on the Web Server and OpenSSL versions. This tutorial provides all the steps for Ubuntu 20.04 LTS. The steps should be similar on other versions of Ubuntu and Linux systems.
Prerequisites
This tutorial assumes that Nginx is already installed on the system. You may follow How To Install And Configure Nginx on Ubuntu 20.04 LTS. It also assumes that the minimum version of OpenSSL is 1.0.1.
TLSv1.2 - The minimum version of the Nginx Web Server must be - Nginx 1.9.1 and OpenSSL version must be OpenSSL 1.0.1
TLSv1.3 - The minimum version of the Nginx Web Server must be - Nginx 1.13.0 and OpenSSL version must be OpenSSL 1.1.1
Notes: The current version of Nginx on Ubuntu 18.04 LTS repositories is 1.14.0 and Ubuntu 20.04 LTS repositories is 1.17.10. We can always install Nginx using it's official PPA as explained at How To Install And Configure Nginx on Ubuntu 18.04 LTS and How To Install And Configure Nginx on Ubuntu 20.04 LTS. We can install the most recent version of Nginx i.e. Nginx 1.19.0 on Ubuntu 18.04 LTS and Ubuntu 20.04 LTS using official PPA.
We can check the Nginx and OpenSSL versions as shown below.
# Nginx Version
nginx -v
# Output
nginx version: nginx/1.17.10 (Ubuntu)
# OpenSSL Version
openssl version
# Output
OpenSSL 1.1.1f 31 Mar 2020
Update SSL Protocol
This section provides the steps to update the SSL Protocol and SSL Cipher Suite on the Nginx Web Server to enable SSL 1.2 or SSL 1.3 or both and also update the Cipher Suite to enable higher versions. The steps in this section enable these protocols for all the virtual hosts. Now update the Nginx configurations as shown below.
# Update SSL Configuration
sudo nano /etc/nginx/nginx.conf
# Updates
-----
ssl_protocols TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on;
-----
# Save and exit the editor -> Ctrl + o -> Enter -> Ctrl + x
The above configuration changes allow only TLS 1.2 by configuring the ssl_protocols to TLSv1.2. This ensures that all the secure communication between the web server and client takes place using the TLS 1.2 SSL protocol.
Similarly, we can allow only TLS 1.3 as shown below.
# Update SSL Configuration
sudo nano /etc/nginx/nginx.conf
# Updates
-----
ssl_protocols TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on;
-----
We can also allow both TLS 1.2 and TLS 1.3 as shown below.
# Update SSL Configuration
sudo nano /etc/nginx/nginx.conf
# Updates
-----
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on;
-----
This is all about enabling TLS 1.2 or TLS 1.3 or both on the Nginx Web Server. We can further tighten the security by specifying the SSL Cipher Suites as shown below.
# Update SSL Configuration
sudo nano /etc/nginx/nginx.conf
# Updates
-----
# Refer - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
ssl_ciphers ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS:!AESCCM;
-----
Also, restart Nginx Web Server after updating the SSL configuration.
# Test Nginx Configurations
sudo nginx -t
# Output
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# Restart Nginx Web Server
sudo systemctl restart nginx
# OR
sudo service nginx restart
This ensures that the Nginx Web Server is only using strong encryption algorithms. You must also redirect the HTTP requests to HTTPS to use the protocols TLS 1.2 and TLS 1.3. You can follow Configure Virtual Host Or Server Block On Nginx, How To Install Let's Encrypt For Nginx On Ubuntu, and Redirect HTTP to HTTPS on Nginx to enable HTTPS only.
Update Server Block
Instead of enabling the TLS 1.2 or TLS 1.3 or both for all the virtual hosts as shown in the previous section, we can also enable these protocols for the selective virtual hosts by updating the server block as shown below.
# Virtual Host - HTTPS - Example -Let's Encrypt
sudo nano /etc/nginx/sites-available/example.com
# Content
server {
listen 80;
server_name example.com www.example.com;
# Redirect to https
return 301 https://$host$request_uri;
}
server {
#listen 80;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
listen 443 ssl;
ssl_protocols TLSv1.2;
ssl_certificate /etc/letsencrypt/live/example.com/cert.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}
# Save and exit the editor - Press Ctrl + o -> Press Enter -> Ctrl + x
Similar to the previous section, we can also update the virtual host to enable either TLS 1.2 only or TLS 1.3 only or both. Also, reload Nginx Web Server after updating the virtual host.
# Reload Nginx Web Server
sudo systemctl reload nginx
# OR
sudo service nginx reload
Test Nginx
We can also test Nginx for the TLS protocols supported by it as shown below.
# Test Nginx for TLS 1
curl -I -v --tlsv1 --tls-max 1.0 https://www.example.com/
# Test Nginx for TLS 1.1
curl -I -v --tlsv1.1 --tls-max 1.1 https://www.example.com/
# Test Nginx for TLS 1.2
curl -I -v --tlsv1.2 --tls-max 1.2 https://www.example.com/
# Test Nginx for TLS 1.3
curl -I -v --tlsv1.3 --tls-max 1.3 https://www.example.com/
The test should pass in case the TLS version is enabled else it should fail. You may also get the error - "SSL certificate problem: unable to get local issuer certificate" in case you are using the SSL certificate from Let's Encrypt. The complete error logs are shown below.
# Test Nginx for TLS 1.2
curl -I -v --tlsv1.2 --tls-max 1.2 https://www.example.com/
# Output
* Trying 34.151.201.52:443...
* TCP_NODELAY set
* Connected to www.example.com (34.151.201.52:443) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS alert, unknown CA (560):
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
We have to use fullchain.pem file instead of cert.pem to resolve this issue.
# Virtual Host - HTTPS - Example -Let's Encrypt
sudo nano /etc/nginx/sites-available/example.com
# Update
-----
listen 443 ssl;
ssl_protocols TLSv1.2;
#ssl_certificate /etc/letsencrypt/live/example.com/cert.pem;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}
# Save and exit the editor - Press Ctrl + o -> Press Enter -> Ctrl + x
# Reload Nginx Web Server
sudo systemctl reload nginx
Now try again to test TLS 1.2 as shown below.
# Test Nginx for TLS 1.2
curl -I -v --tlsv1.2 --tls-max 1.2 https://www.example.com/
# Output
* Trying 34.151.201.52:443...
* TCP_NODELAY set
* Connected to www.example.com (34.151.201.52) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: CN=example.com
* start date: Jul 4 02:11:26 2020 GMT
* expire date: Oct 2 02:11:26 2020 GMT
* subjectAltName: host "www.example.com" matched cert's "www.example.com"
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.
> HEAD / HTTP/1.1
> Host: www.example.com
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: nginx/1.17.10 (Ubuntu)
Server: nginx/1.17.10 (Ubuntu)
< Date: Sun, 05 Jul 2020 04:19:14 GMT
Date: Sun, 05 Jul 2020 04:19:14 GMT
< Content-Type: text/html
Content-Type: text/html
< Content-Length: 185
Content-Length: 185
< Last-Modified: Sat, 04 Jul 2020 02:13:38 GMT
Last-Modified: Sat, 04 Jul 2020 02:13:38 GMT
< Connection: keep-alive
Connection: keep-alive
< ETag: "5effe5d2-b9"
ETag: "5effe5d2-b9"
< Accept-Ranges: bytes
Accept-Ranges: bytes
<
* Connection #0 to host www.example.com left intact
Summary
This tutorial provided the steps to configure the Nginx Web Server to allow only TLS 1.2 or TLS 1.3 or both depending on the version of the Nginx Web Server.