In this guide, you'll learn how to use SSL to secure your Nginx, this way, you can ensure your websites are encrypted and available over HTTPS.
By default, Nginx configuration listens for traffic on port 80 in Ubuntu, and not port 443 (HTTPS).
There are two ways you can go about installing SSL, you can either go with a self-signed certificate that most browsers won't trust by default and the other way is to install certificates signed by a certificate authority, which is the recommended method.
We would be using a self-signed certificate as an illustration in this guide, they are not recommended for a production environment, so, if you are planning to secure Nginx on a production server, you can go with this article: Securing Nginx Server Using (Let's Encrypt) [Ubuntu]
Create a directory that would house the certificates. Create a certs directory under /etc/nginx/
Change your working directory into /etc/nginx/ and run the following command
sudo mkdir certs
To avoid an error when issuing a self-signed certificate in Ubuntu, you might need to create a .rnd in your user directory, make sure this is owned by the user of the home directory, it is used by OpenSSL to store some amount (256 bytes) of seed data.
Create the .rnd file:
touch ~/.rnd
Now, request for the certificate and key pair with the following command:
Note: You can also change the name of the key and cert file to match the name of your website. In my case, I am using website.com
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/certs/website.key -out /etc/nginx/certs/website.crt
You would be asked a series of questions, this is would be incorporated in your certificate request, here is the questions, and answer of mine:
Note: Your common name should be your server IP address
Country Name (2 letter code) [AU]:NG
State or Province Name (full name) [Some-State]:Lagos
Locality Name (eg, city) []:Ikeja
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Devsrealm
Organizational Unit Name (eg, section) []:IT
Common Name (e.g. server FQDN or YOUR name) []:192.168.43.150
Email Address []:faruq@devsrealm.com
The next step is configuring Ngnix to use SSL, to do this, we would create two new configuration files, this is to make the process easy.
Create a self-signed.conf:
sudo nano /etc/nginx/certs/self-signed.conf
In that new file, add the location that the pair certificates is installed:
ssl_certificate /etc/nginx/certs/website.crt; ssl_certificate_key /etc/nginx/certs/website.key;
Save and Close using Ctrl + X and Enter.
The next step is to create another configuration snippet, these provide Strong SSL Security for all modern browsers, plus you get an A+ on the SSL Labs Test. In short, they set a strong Forward Secrecy enabled ciphersuite, they disable SSLv2 and SSLv3, add HTTP Strict Transport Security and X-Frame-Deny headers and enable OCSP Stapling.
If you need more ciphers, visit cipherlist.eu
Create a new file:
sudo nano /etc/nginx/snippets/ssl-params.conf
In that new file, add the following:
ssl_protocols TLSv1.3;# Requires nginx >= 1.13.0 else use TLSv1.2
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/dhparam.pem; # openssl dhparam -out /etc/nginx/dhparam.pem 4096
ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
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 Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
I have commented out stapling, this is a method for quickly and safely determining whether or not an SSL certificate is valid, this is not needed in a self-signed certificate, uncomment it if you are not using self-signed.
The next step is to configure Nginx to use SSL. I'll assume you already have a config for website.com
Open it:
sudo nano /etc/nginx/sites-available/website.com
First, we change the first two lines to listen on port 443 with SSL instead of standard port
80:
listen 443 ssl;
listen [::]:443 ssl;
Next, update the server block to reflect the following:
server {
listen 443 ssl;
listen [::]:443 ssl;
include certs/self-signed.conf;
include snippets/ssl-params.conf;
ssl_session_timeout 5m;
server_name website.com www.website.com;
root /var/www/website.com/html;
index index.html index.htm index.nginx-debian.html;
The last step is to redirect all HTTP version of our site to HTTPS version automatically. To do that add a new server block (to perform an HTTPS redirect) like so:
server {
listen 80;
listen [::]:80;
server_name website.com www.website.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.website.com /etc/nginx/sites-enabled/
Using ufw, we can check our new SSL-enabled profiles with the command:
sudo ufw app list
Restart NGINX with with the command:
sudo systemctl restart nginx
Now try visiting your server IP address with https, e.g https://192.168.43.150/
You would see a warning "certificate is not trusted because it is self-signed" bypass it by clicking allow.
You can configure chrome to trust the certificate by issuing:
certutil -d sql:$HOME/.pki/nssdb -A -t "P,," -n "localhost" -i localhost.crt