Skip to content

Instantly share code, notes, and snippets.

@teocci
Last active July 1, 2019 14:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save teocci/67e935ff981f7927be93c90e1cb8b2d9 to your computer and use it in GitHub Desktop.
Save teocci/67e935ff981f7927be93c90e1cb8b2d9 to your computer and use it in GitHub Desktop.
Nginx SSL configuration

How to enable SSL on NGINX

Secure Sockets Layer (SSL) has become a necessity for web servers. Why? Because security has been forced into the spotlight, and every company now faces the fact that their web servers must serve up content securely.

To that end, you need to make use of SSL. If you happen to work with NGINX, you're in luck, as the process is quite possible (though slightly complicated).

I want to walk you through the steps of enabling SSL on a Ubuntu Server 18.04, running NGINX. I will demonstrate this with a self-signed certificate, but a certificate from an official Certificate Authority (CA) is a much better choice. In fact, you should use the self-signed certificate only as a means for testing purposes.

What you need

To accomplish this, you'll need NGINX running on Ubuntu Server 18.04, with a self-signed certificate at the ready. I'll assume you already have Ubuntu and NGINX up and running. We'll walk through the process of creating the self-signed certificate.

Self-signed certificate

The first step is to generate your self-signed certificate. To do this, log into your server and issue the following command:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt

You will be asked a few questions (such as country name, state, locality, etc.). The most important answer is the Common Name. For this question, answer with the server's IP Address.

Once the command completes, the necessary files will be added to the /etc/ssl directory and are ready to use.

Configure NGINX

Now we need to configure NGINX to use SSL. First, create a new configuration snippet file with the command:

sudo nano /etc/nginx/snippets/self-signed.conf

In that new file, add the following contents:

ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;

Save and close that file.

Next, create a second configuration snippet that points to our newly-generated SSL key and certificate. To do this, issue the command:

sudo nano /etc/nginx/snippets/ssl-params.conf

In that new file, add the following contents:

ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
ssl_session_timeout  10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off; # Requires nginx >= 1.5.9
# ssl_stapling on; # Requires nginx >= 1.3.7
# ssl_stapling_verify on; # Requires nginx => 1.3.7
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

Because we are using a self-signed certificate, we disable SSL stapling (a method for quickly and safely determining whether or not an SSL certificate is valid). If you're not using a self-signed certificate, remove the # symbols before the two lines. You can also change the resolver line to reflect your preferred DNS servers. Save and close that file.

We also need to generate the dhparam.pem file with the command:

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

The above command will take some time.

The next step is to configure NGINX to be aware that we're going to be using SSL. Let's assume you have a server block for example.com in sites-available. Open that server block with the command:

sudo nano /etc/nginx/sites-available/example.com

In that file, edit it to reflect the following:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

    server_name example.com www.example.com;

    root /var/www/example.com/html;
    index index.html index.htm index.nginx-debian.html;

}

Below that add a new server block (to perform an HTTPS redirect) like so:

server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;

    return 302 https://$server_name$request_uri;
}

Finally, we need to link from sites-available to sites-enabled with the command:

ln -s /etc/nginx/sites-available/www.example.com /etc/nginx/sites-enabled/

Check the profiles

Using ufw, we can check our new SSL-enabled profiles with the command:

sudo ufw app list

This should clearly show NGINX HTTPS is enabled.

Credits

ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
# version 2019 May 28
# Improve HTTPS performance with session resumption
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
ssl_buffer_size 4k;
# Enable server-side protection against BEAST attacks
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
# Tolerant -- compatibility with WinXP and pre android 5 is bad, but still supports wide range of clients:
# Firefox 1, Chrome 1, IE 7, Opera 5 and Safari 1!
ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS;
# Alternative
# ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384";
# RFC-7919 recommended: https://wiki.mozilla.org/Security/Server_Side_TLS#ffdhe4096
# generated using:# openssl dhparam -dsaparam -out /etc/ssl/dh4096.pem 4096
ssl_dhparam /etc/ssl/dh4096.pem;
ssl_ecdh_curve secp384r1;
# ssl_ecdh_curve secp521r1:secp384r1;
# Enable OCSP stapling
# Reference: http://blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox
ssl_stapling on;
ssl_stapling_verify on;
# I use dnsmasq for faster lookups, highly recommend it!
resolver 127.0.0.1 [::1];
resolver_timeout 6s;
# if you don't have ipv6 on your network, like with many cable-ISPs:
# resolver 127.0.0.1 valid=300s ipv6=off;
# Cloudflare DNS server
#resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001] valid=300s;
#resolver_timeout 5s;
# Aditional Security Headers
# HTTP Strict Transport Security: Tell browsers to require https:// without first checking http:// for a redirect.
# Reference: https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security
# Warning: Set this only after all else is correct, all browsers will remember this setting..
#
# max-age: length of requirement in seconds (31536000 = 1 year)
# includeSubdomains: force TLS for *ALL* subdomains (remove if different servers host subdomains of the same domainname!)
# preload: indicates you want browsers to ship with HSTS preloaded for your domain.
#
# Submit your domain for preloading in browsers at: https://hstspreload.appspot.com
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
add_header Strict-Transport-Security "max-age=31536000; preload" always;
# See https://securityheaders.io/ for referer-options:
add_header Referrer-Policy no-referrer-when-downgrade;
# Content Security Policy (CSP)
# https://www.owasp.org/index.php/Content_Security_Policy
add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data:;";
# Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
add_header X-Frame-Options deny always;
# http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
# Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
add_header X-Content-Type-Options nosniff always;
# https://wiki.mozilla.org/Security/Features/XSS_Filter
# http://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx
# Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
add_header X-Xss-Protection "1; mode=block" always;
server {
listen 80;
server_name www.test-domain.com test-domain.com;
# redirects both www and non-www to https
return 301 https://test-domain.com$request_uri;
}
server {
listen 443 ssl;
server_name www.test-domain.com;
# redirects www to non-www. wasn't work for me without this server block
return 301 $scheme://test-domain.com$request_uri;
}
server {
## SSL settings
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name test-domain.com;
include snippets/ssl-domain.com.conf;
include snippets/ssl-params.conf;
# other vhost configuration
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment