How to setup HTTP2 on CentOs 7.3 with NGINX

#helpful #text #written #digitalocean #letsencrypt #centos #nginx #http2

For a few years now I have been a fan of CentOS for my servers, its light weight and simple to use. Lately I have been experimenting with HTTP/2 and trying to have my server serve my pages as quickly and modernly as possible which I have written about in other articles.

CentOS 7.3 how ever doesn't come with all which is needed to serve your page over HTTP/2 out of the box. So have have made this article as a collection of links and tutorials to have it working on CentOS.

This was done on a clean installation of CentOs 7.3 on a DigitalOcean Droplet.

Start by updating your installation with:
yum update

OpenSSL

NGINX needs OpenSSL 1.0.2 to function however CentOS 7.3 comes with 1.0.1e pre-installed. CentOS 7.4 which should be released around August/September 2017 comes with 1.0.2 installed. So if you have 7.4 you can skip this step.

Start by installing the Development tools.
yum groupinstall "Development Tools"

First check your OpenSSL version.

openssl version

OpenSSL 1.0.1e-fips 11 Feb 2013
You can also check the available version in the vendors directory too.

yum info openssl

To download the latest version of OpenSSL, do as follows:

cd /usr/local/src
wget https://www.openssl.org/source/openssl-1.0.2-latest.tar.gz
tar -zxf openssl-1.0.2-latest.tar.gz

To manually compile OpenSSL and install/upgrade OpenSSL, do as follows:

cd openssl-1.0.2k
./config
make
make test
make install

If the old version is still displayed or installed before, please make a copy of openssl bin file :

mv /usr/bin/openssl /root/
ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl

Now verify the OpenSSL version.

openssl version

OpenSSL 1.0.2k 26 Jan 2017

NGINX

For installing nginx 1.13 install the following REPO. This usually includes OpenSSL as well, but I prefer to install it myself.
https://brouken.com/brouken-centos-7-repo/

yum -y install yum-utils
yum-config-manager --add-repo https://brouken.com/brouken.repo

Additional highly recommended configuration (if you’re using EPEL!):
yum-config-manager --save --setopt=epel.exclude=nginx*;

Then just install NGINX like this:
yum install nginx

To check that NGINX installed correctly:
nginx -v

Which should output something like:

nginx version: nginx/1.13.2

Optional, change SSH port

When ever I create a new droplet on digitalocean, after just a month or so using I start having a lot unsuccessful logins on my server, probably being one or multiple hacking robots trying to access my server. A simple solution to make it slightly more safe for yourself I prefer to change the SSH port to something else random.

As a root user edit the ssh config file:
vi /etc/ssh/sshd_config

Find the line with
# Port 22

Remove the # and change 22 to the port you want to use instead. Like 222 or 333 or whatever else you prefer. Just make sure you remember it.

Then restart the SSH service
service sshd restart

Get some SSL certificates

HTTP/2 needs https to work. So you'll need to get some valid certificates to get it working. Check out Let's encrypt to get some.

When you have the certs you could create a dhparam's file for extra security like this:

cd /etc/ssl/certs (use your path provided by letsencrypt)
openssl dhparam -out dhparam.pem 4096

Setup NGINX

Enabling nginx with http2 and https

Start by creating a config file for your domain.
vi /etc/nginx/conf.d/example.com.conf

Paste the following and change example.com for your domain and change the paths for the certificates to the ones provided by lets encrypt.

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name example.com;

    ssl_certificate        /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key    /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_dhparam            /etc/letsencrypt/live/example.com/dhparam.pem;
    ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";

    add_header Strict-Transport-Security max-age=31536000;
    add_header X-Frame-Options SAMEORIGIN;

    location / {
        limit_req zone=one burst=20 nodelay;
        proxy_pass http://localhost:2368; <- make this line point to where your web site is running.
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_buffering off;
    }
}

server {
    listen         80;
    listen    [::]:80;
    server_name    example.com;
    return         301 https://$server_name$request_uri;
}

Then lastly to speedup the loading of your page you can add GZIPPING to your NGINX settings.

vi /etc/nginx/nginx.conf

After gzip, add:

gzip  on;

    ##
    # SSL settings
    ##
    ssl_session_cache    shared:SSL:10m;
    ssl_session_timeout  10m;
    # Forward secrecy settings
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";

Conclusion

This is pretty much it. My server is running a ghost blog which runs on port 2368 so as seen in the nginx setup its pointing to the blog. You should now be able to test your page and see it is now being served over HTTP/2 and with https enabled.

To test the security of your page you can use this url and change to your domain: https://www.ssllabs.com/ssltest/analyze.html?d=example.com