How to enable TLS 1.3 in Nginx with OpenSSL Centos 7

Tags: security, linux, webdev, devops
Published: 2020-05-25 05:22:46


Here, we are going to enable TLS 1.3 on our production CentOS 7 server.

OpenSSL is a robust, commercial-grade, and full-featured toolkit for the Transport Layer Security (TLS) and Secure Sockets Layer (SSL) protocols. OpenSSL is a software library for applications that secure communications over computer networks against eavesdropping or need to identify the party at the other end. It is licensed under an Apache-style license, which means that you are free to get and use it for commercial and non-commercial purposes subject to some simple license conditions. For a list of vulnerabilities, and the releases in which they were found and fixes, see the OpenSSL [Vulnerabilities](https://www.openssl.org/news/vulnerabilities.html) page.

![](https://cdn-images-1.medium.com/max/2800/0*gt0ivtektI66R9fu.png)

<code>TLS 1.3</code> is the newest and most secure version of the TLS protocol. It has improved latency over older versions and several new features. It is currently supported in both Chrome (starting with release 66) and Firefox (starting with release 60) and in development for Safari and Edge browsers.

If you download the Nginx from the centos 7 repo you will get Nginx built with <code>**OpenSSL 1.0.2k-fips**</code>. But If you want to enable TLS 1.3 then you must fulfill the few requirements. To enable <code>TLS 1.3</code> on any distributions please look at the below-required details.

**Requirements:**

* Apache version <code>2.4.37</code> or <code>greater</code>.

* Nginx version <code>1.13.0</code> or <code>greater</code>.

* OpenSSL version <code>1.1.1</code> or <code>greater</code>.

* A valid domain name with correctly configured DNS records.

* A valid TLS certificate.

As we are planning to deploy TLS 1.3 on our production CentOS7 server, we already have a valid domain name, valid TLS certificate, and Nginx version 1.16.1 which is greater than the minimum version required for TLS 1.3. But the current Nginx version is built with <code>**OpenSSL 1.0.2k-fips**</code> so first we need to install OpenSSL version 1.1.1 through the compile process and again recompile our Nginx with a new OpenSSL version.

As we can see below the OpenSSL version is <code>OpenSSL 1.0.2k-fps 26 Jan 2017</code> and Nginx <code>**1.16.1**</code>


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mp6mgt4di5nvlgnwu4hd.png)

    yum install gcc gcc-c++ pcre-devel zlib-devel make unzip gd-devel perl-ExtUtils-Embed libxslt-devel openssl-devel perl-Test-Simple
    yum groupinstall 'Development Tools'


**Install OpenSSL**

    cd /usr/src
    wget [https://www.openssl.org/source/old/1.1.1/openssl-1.1.1f.tar.gz](https://www.openssl.org/source/old/1.1.1/openssl-1.1.1f.tar.gz)
    tar xvf openssl-1.1.1f.tar.gz
    mv openssl-1.1.1f openssl
    cd openssl
    ./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl --libdir=/lib64 shared zlib-dynamic
    make -j4
    make test
    make install

We downloaded the latest version of OpenSSL which is <code>**openssl-1.1.1f**</code> at the time of writing this post. After that decompress the file, rename the folder name and navigate to the OpenSSL folder. <code>--prefix</code> and <code>--openssldir</code> control the configuration of installed components. The behavior and interactions of <code>--prefix</code> and <code>--openssldir</code> are slightly different between <code>OpenSSL 1.0.2 </code> and below and OpenSSL 1.1.0 and above. Also set --prefix and --openssldir to the same location. shared will force creating shared libraries and Zlib means that compression will be performed by using zlib library. It is worth running the <code>make test</code> to see if there are any unexpected errors. If there are any, you need to fix them before installing the library.

Now rename the existing OpenSSL binary and add a new symlink.

    mv /usr/bin/openssl /usr/bin/openssl-backup
    ln -s /usr/local/openssl/bin/openssl /usr/bin/openssl

Here, <code>ldd</code> showing dependencies of the binary OpenSSL.

![](https://cdn-images-1.medium.com/max/2048/0*W5NPDJodC6neb6m4.png)

Your newly installed OpenSSL should show <code>TLSv1.3</code> like below.

    openssl ciphers -v | awk '{print $2}' | sort | uniq

![](https://cdn-images-1.medium.com/max/2048/0*nABES9WSieZBKoGK.png)

We have completed the OpenSSL installation part. Now we have to recompile Nginx again to built from the newly installed OpenSSL.

**Recompile Nginx**

Download the installed Nginx version source code from the web. In my case Nginx version 1.16.1 is installed on my production server so I will download the same version and start compiling.

    cd /usr/src
    wget [http://nginx.org/download/nginx-1.16.1.tar.gz](http://nginx.org/download/nginx-1.16.1.tar.gz)
    tar xvf nginx-1.16.1.tar.gz
    cd nginx-1.16.1

{% gist https://gist.github.com/bidhanahdib/72181014d8c301d9ab392782d57237f2 %}

    make -j4
    make install

As we can see now that Nginx has been built with newly installed OpenSSL. <code>**built with OpenSSL 1.1.1f 31 Mar 2020**</code>

    nginx -V

    nginx version: nginx/1.16.1
    built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
    built with OpenSSL 1.1.1f 31 Mar 2020
    TLS SNI support enabled

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/53joqj88uhxlkkd2bqxa.png)

Update your Nginx configuration to enable <code>TLS 1.3</code>. Add below lines on your Nginx vhost configuration’s server block.

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    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';

check the configuration and restart Nginx.
    
    nginx -t
    service nginx restart

Now you can verify your web application from your browser or from the command line to check whether it uses TLS 1.3 or not.

In Google Chrome browser, go to the website [https://link.bdn.com.np](https://link.bdn.com.np)
<code>Right Click</code> >> <code>Inspect</code> >> <code>Security Tab</code>

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/q52wxrmardd7po55vlgz.png)




You can also check from your command line. If you have installed OpenSSL version 1.1.1 on your end device then your connection to the server will be through TLS 1.3 on first priority.

    openssl s_client -connect link.bdn.com.np:443 -tls1_3

You will see the output below.

    New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
    Server public key is 2048 bit
    Post-Handshake New Session Ticket arrived:
    SSL-Session:
    Protocol : TLSv1.3
    Cipher : TLS_AES_256_GCM_SHA384

That’s it. We have enabled the TLS 1.3 on our Nginx server and it’s running as expected. Somehow if your application breaks down due to the new OpenSSL version then you might also need to recompile your PHP with the new headers.