Skip to content

Instantly share code, notes, and snippets.

@Peregrinox
Last active March 1, 2018 09:34
Show Gist options
  • Save Peregrinox/8df12a205957a99f841bb36840fad5bd to your computer and use it in GitHub Desktop.
Save Peregrinox/8df12a205957a99f841bb36840fad5bd to your computer and use it in GitHub Desktop.
enable https on nginx server

Secure nginx with letsncrypt

Add the backports repository to your server by typing:

$ echo 'deb http://ftp.debian.org/debian stretch-backports main' | sudo tee /etc/apt/sources.list.d/backports.list
$ sudo apt-get update

Install the certbot package by targeting the backports repository: (this failed with dependency errors if python is set to 3.4 version, so I previously set alternatives to 2.7)

$ sudo apt-get install certbot -t stretch-backports

Step 1. Use the Webroot plugin to obtain an SSL certificate.

The Webroot plugin works by placing a special file in the /.well-known directory within your document root, which can be opened (through your web server) by the Let's Encrypt service for validation. So, with nginx installed, explicitly allow access to the /.well-known directory:

$ sudo nano /etc/nginx/sites-available/default

Inside the server block, add this location block:

 location ~ /.well-known {
    allow all;
 }

Check your configuration for syntax errors:

sudo nginx -t

restart Nginx

sudo systemctl restart nginx

Be secure that your nginx server is visible from port 80 (and 443 for ssh) of your router public address and that your domains are resolving well with DNS (proper 'A' records are set in your DNS provider)

upnpc -e "nginx server" -a `ip route get 8.8.8.8 | awk '{print $NF; exit}'` 80 80 TCP
upnpc -e "ssh nginx server" -a `ip route get 8.8.8.8 | awk '{print $NF; exit}'` 443 443 TCP

Now we can use the Webroot plugin to request an SSL certificate, here we are specifying all of our domain names with the -d option.

$ sudo certbot certonly -a webroot --webroot-path=/var/www/html -d example.com -d www.example.com

You will be prompted to enter your email and agree to the Let's Encrypt terms of service. You will want to note the path and expiration date of your certificate.

you'll get some lines as

...
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Using the webroot path /var/www/html for all unmatched domains.
Generating key (2048 bits): /etc/letsencrypt/keys/0000_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0000_csr-certbot.pem

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
  /etc/letsencrypt/live/yourdomain.com/fullchain.pem. Your cert will
  expire on 2018-04-24. To obtain a new or tweaked version of this
  certificate in the future, simply run certbot again. To
  non-interactively renew *all* of your certificates, run "certbot
  renew"
- Your account credentials have been saved in your Certbot
  configuration directory at /etc/letsencrypt. You should make a
  secure backup of this folder now. This configuration directory will
  also contain certificates and private keys obtained by Certbot so
  making regular backups of this folder is ideal.
  ...

Certificate Files

After obtaining the cert, you will have the following PEM-encoded files:

  • cert.pem: Your domain's certificate
  • chain.pem: The Let's Encrypt chain certificate
  • fullchain.pem: cert.pem and chain.pem combined
  • privkey.pem: Your certificate's private key

The files themselves are placed in a subdirectory in /etc/letsencrypt/archive. However, Let's Encrypt creates symbolic links to the most recent certificate files in the /etc/letsencrypt/live/your_domain_name directory. This is the path that you should use to refer to your certificate files:

$ sudo ls -l /etc/letsencrypt/live/your_domain_name

Generate Strong Diffie-Hellman Group

To further increase security:

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

This may take a few minutes but when it's done you will have a strong DH group at /etc/ssl/certs/dhparam.pem.

Step 2. Configure TLS/SSL on Web Server (Nginx)

Now that you have an SSL certificate, you need to configure your Nginx web server to use it. Keeping clean server blocks and put common configuration segments into reusable modules.

Create a nginx Configuration Snippet Pointing to the SSL Key and Certificate

$ sudo nano /etc/nginx/snippets/ssl-example.com.conf

set the ssl_certificate directive to our certificate file and the ssl_certificate_key to the associated key with:

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

Create a Configuration Snippet with Strong Encryption Settings

It can be reused in future Nginx configurations, so we will give the file a generic name:

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

and paste next text:

# from https://cipherli.st/
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Disable preloading HSTS for now.  You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

Adjust the Nginx Configuration to Use SSL

$ sudo nano /etc/nginx/sites-available/default

change your current config:

server {
 listen 80 default_server;
 listen [::]:80 default_server;
 
 # SSL configuration
 # listen 443 ssl default_server;
 # listen [::]:443 ssl default_server;
 ...

to:

server {
 listen 80 default_server;
 listen [::]:80 default_server;
 listen 443 ssl default_server;
 listen [::]:443 ssl default_server;
 
 server_name example.com www.example.com;
 include snippets/ssl-example.com.conf;
 include snippets/ssl-params.conf;
 ...

Setup Auto renewal

To trigger the renewal process for all installed domains, you should run this command:

sudo certbot renew

the renewal first checks for the expiration date and only executes the renewal if the certificate is less than 30 days away from expiration, so, it is safe to create a cron job that runs every week or even every day.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment