In this article, we will show you how to obtain free SSL certificate and secure your web server with it. Also, we will show how to renew your certificates automatically. Prerequisites:
- Debian 9 - a sudo non-root user
- Nginx We will use Let’s Encrypt for our purpose. Let’s Encrypt is a free, automated, and open certificate authority brought to you by the non-profit Internet Security Research Group.
Step 1. Install certbot (the client of Let’s Encrypt)
Let’s use following command:
1
sudo apt-get install python-certbot-nginx -t stretch-backports
Step 2: Obtain an SSL Certificate
To obtain an SSL certificate for your website we can use Webrootplugin:
The Webroot plugin works by placing a special file in the /.well-known
directory within your document root. This file would be opened (through your web server) by the Let’s Encrypt service for validation. You may need to explicitly allow access to the /.well-known
directory.
Open your nginx configuration:
1
sudo nano /etc/nginx/sites-available/default
And add the following code to SSL block:
1
2
3
location ~ /.well-known {
allow all;
}
Also, we can change our root
directory path. Let’s change it to /var/www/html/reheda
Save and close it.
And we should create our new root directory inside the /var/www/html
1
sudo mkdir /var/www/html/reheda
Create simple index.html
file inside root directory to be able to check it:
1
echo "<html><head><meta charset='UTF-8'><title>Document</title></head><body>Hello world</body></html>" | sudo tee --append /var/www/html/reheda/index.html
Check your Nginx config file for syntax errors with:
1
sudo nginx -t
If no errors are found, restart Nginx:
1
sudo systemctl restart nginx
Now that we know our webroot-path, we can use the Webroot plugin to request an SSL certificate with these commands. Here, we are also specifying our domain names with the -d option. If you want a single cert to work with multiple domain names (e.g. example.com and www.example.com), be sure to include all of them.
1
certbot certonly -a webroot --webroot-path=/var/www/html/reheda -d reheda.pro -d www.reheda.pro -d vpn.reheda.pro -d jenkins.reheda.pro -d blog.reheda.pro -d costs.reheda.pro -d api.costs.reheda.pro
After certbot initializes, you will be prompted to enter your email and agree to the Let’s Encrypt terms of service. Afterwards, the challenge will run. If everything was successful, you should see something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/example.com/fullchain.pem. Your cert
will expire on 2017-09-05. 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"
- If you lose your account credentials, you can recover through
e-mails sent to sammy@example.com.
- 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.
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
After obtaining the cert, you will have the following PEM-encoded files:
- cert.pem: Domain’s certificate
- chain.pem: The Let’s Encrypt chain certificate
- fullchain.pem: cert.pem and chain.pem combined
- privkey.pem: 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. Because the links will always point to the most recent certificate files, this is the path that you should use to refer to your certificate files.
Make sure that the received certificate is exactly what we need with the necessary domains:
1
cat /etc/letsencrypt/live/*/cert.pem | openssl x509 -text | grep -o 'DNS:[^,]*' | cut -f2 -d:
Generate Strong Diffie-Hellman Group
To further increase security, you should also generate a strong Diffie-Hellman group:
1
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
Step 3: Configure TLS/SSL on Nginx
We will make a few changes to our configuration: -create a configuration snippet containing our SSL key and certificate file locations. -create a configuration snippet containing strong SSL settings that can be used with any certificates in the future. -adjust the Nginx server blocks to handle SSL requests and use the two snippets above.
This method of configuring will allow us to keep clean server blocks and reusable modules.
Create a Configuration Snippet Pointing to the SSL Key and Certificate
Let’s create a new Nginx configuration snippet:
1
sudo nano /etc/nginx/snippets/ssl-reheda.pro.conf
We should point to our certificates:
1
2
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
Save and close the file.
Create a Configuration Snippet with Strong Encryption Settings
Next, we should create another snippet for SSL settings. This will help keep our server secure.
The parameters we will set could be reused in future Nginx configurations, so we will give the file a generic name:
1
sudo nano /etc/nginx/snippets/ssl-params.conf
We will add our preferred DNS resolver for upstream requests. We will use Google’s for this guide. We will also go ahead and set the ssl_dhparam setting to point to the Diffie-Hellman file we generated earlier.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 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;
Save and close it.
Set the Nginx Configuration up to Use SSL
Let’s back up our current server block file:
1
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak
Open config file:
1
sudo nano /etc/nginx/sites-available/default
We will disable HTTP access and allow only HTTPS. Split your server block into two. We should listen to 80 (http) port and redirect to 443 (https) port.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Default server
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name reheda.pro www.reheda.pro;
return 301 https://www.reheda.pro$request_uri;
}
server {
# SSL configuration
listen 127.0.0.1:443 ssl default_server;
listen [::]:443 ssl default_server;
include snippets/ssl-reheda.pro.conf;
include snippets/ssl-params.conf;
. . .
Save and close when finished.
Step 4: Enable the adjustment in the Nginx
Check nginx syntax:
1
sudo nginx -t
And restart if previous step is ok:
1
sudo systemctl restart nginx
Step 5: Set up SSL auto renewal
Let’s Encrypt certificates are valid for 90 days, but it’s recommended that you renew the certificates every 60 days to allow a margin of error.
To trigger the renewal process for all installed domains:
1
sudo certbot renew
Since the renewal first checks for the expiration date and only executes the renewal if the certificate is less than 30 days away from expiration, it is safe to create a cron job that runs every week or even every day:
1
sudo crontab -e
Add the following line:
1
17 */12 * * * /usr/bin/certbot renew --noninteractive --renew-hook "/bin/systemctl reload nginx" >> /var/log/le-renew.log
We should change 17 in the current line to random number between 0 and 59.
1
crontab -l | sed s/^17/$((RANDOM % 60))/ | crontab
So Certbot will try to renew certificates every 12 hours in the random minute of the hour.
Save and exit
The output produced by the command will be piped to a log file located at /var/log/le-renew.log
.