How To Secure Nginx with Let’s Encrypt on CentOS 7
Let’s Encrypt is a new certificate authority (CA) that provides free X.509 certificates for Transport Layer Security encryption (TLS) through an automated process. This automated process is designed to banish most of required steps. The present day complex process of manual creation, validation, signing, installation and renewal of certificates for websites is fully automated only on Apache web servers. However, it can also be used to obtain a free SSL certificate, which can be installed manually, regardless of web server software.
This tutorial will guide you through the process of using Let’s Encrypt to obtain a free SSL certificate and using it with Nginx on CentOS7. This will also cover how to automatically renew your SSL certificate.
Prerequisites
Before following this tutorial, please ensure the below requirements:
- A CentOS7 server with a non-root user who has sudo
- Ownership or control of the domain name that you wish to use the certificate with.
- Be sure to create an A Record that points your domain to the public IP address of your server. This is required because of how Let’s Encrypt validates that you own the domain it is issuing a certificate for. For example, if you want to obtain a certificate for com, that domain must resolve to your server for the validation process to work. Our setup will use abc.com and www.abc.com as the domain names, so both DNS records are required.
Step 1: Install Let’s Encrypt Client
To begin using Let’s Encrypt install the letsencrypt software on your server. This will be the first step to obtain your SSL certificate. The best available way to install Let’s encrypt is to simple clone it from the official GitHub repository.
Install git and bc
Let’s install Git now, so we can clone the Let’s Encrypt repository.
Install the git and bc packages with yum:
sudo yum -y install git bc
With git and bc installed, we can easily download letsencrypt by cloning the repository from GitHub.
Clone Let’s Encrypt
We can now clone the Let’s Encrypt repository in /opt with this command:
sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
You should now have a copy of the letsencrypt repository in the /opt/letsencrypt directory.
Step 2 — Obtain a Certificate
Let’s Encrypt offers a range of ways to obtain SSL certificates, through various plugins. Most of the plugins (except Apache) only help you to obtain a certificate which has to be manually configured to be used on your server. Plugins that only obtain certificates, and don’t install them, are referred to as “authenticators” because they are used to authenticate whether a server should be issued a certificate.
This tutorial will guide you through the use of Webroot plugin.
How to Use the Webroot Plugin?
This plugin works by placing a unique file in the /.well-known directory within your document root, which will be opened (through your web server) by the Let’s Encrypt service for validation. Depending on your configuration, you may need to explicitly allow access to the /.well-known directory.
If you haven’t installed Nginx yet, first install the epel-release repository:
sudo yum -y install epel-release
Then install Nginx with this command:
sudo yum -y install nginx
We will then make a little change to our default Nginx server block to ensure that the directory is accessible to Let’s Encrypt for validation. The default Nginx configuration file allows us to easily add directives to the port 80 server block by adding files in the/etc/nginx/default.d directory. If you’re using the default configuration, create a new file called filename.conf and open it for editing with this command:
sudo vi /etc/nginx/default.d/filename.conf
Then paste in these lines:
/etc/nginx/default.d/filename.conf
location ~ /.well-known
{
allow all;
}
Save and exit.
Start Nginx with this command:
sudo systemctl restart nginx
You will need to look up what your document root is set to if you aren’t using the default server block. You can find the document root directive in your default Nginx server block. This is the value that Let’s Encrypt requires, as webroot-path, when using the Webroot plugin. The default root is /usr/share/nginx/html.
Since you know your webroot-path, you 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.abc.com and www.abc.com), be sure to include all of them. Also, make sure that you replace the highlighted parts with the appropriate webroot path and domain name(s):
cd /opt/letsencrypt
./letsencrypt-auto certonly -a webroot --webroot-path=/usr/share/nginx/html -d abc.com -d www.abc.com
Note: The Let’s Encrypt software requires super user privileges, so you will be required to enter your password if you haven’t used sudo recently.
After initialization, you will be prompted for some information. These prompts may vary depending on if you have used Let’s Encrypt before.
At the prompt, enter an email address that will be used for notices and lost key recovery:
Then you must agree to the Let’s Encrypt Subscribe Agreement. Select Agree:
If everything was successful, you should see an output message that looks something like this:
Output:
IMPORTANT NOTES:
– If you lose your account credentials, you can recover through
e-mails sent to
– Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/abc.com/fullchain.pem
Your cert will expire on 2016-04-20. To obtain a new version of the
certificate in the future, simply run Let’s Encrypt again.
– Your account credentials have been saved in your Let’s Encrypt
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 Let’s
Encrypt so making regular backups of this folder is ideal.
– If like Let’s Encrypt, please consider supporting our work by:
Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Make sure you note the path and expiration date of your certificate, which was highlighted in the example output.
Firewall Note: If you receive an error like Failed to connect to host for DVSNI challenge, your server’s firewall may need to be configured to allow TCP traffic on port 80 and 443.
Note: If your domain is routing through a DNS service like CloudFlare, you will need to temporarily disable it until you have obtained the certificate.
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
You must know the location of the certificate files that were just created. The files themselves are placed in a subdirectory in /etc/letsencrypt/archive. Let’s encrypt offers a feature that creates symbolic links to the most recent certificate files in the/etc/letsencrypt/live/your_domain_name directory. Since, 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.
You can check that the files exist by running this command (substituting in your domain name):
sudo ls -l /etc/letsencrypt/live/your_domain_name
The output should be the four previously created certificate files. By this, you configure your web server to use fullchain.pem as the certificate file, and privkey.prm as the certificate key file.
Generate Strong Diffie-Hellman Group
In order to increase security, generate a strong Diffie-Hellman group. To generate a 2048-bit group, use command:
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
This might take a few minutes but after completion you will have a strong DH group at
/etc/ssl/certs/dhparam.pem.
Step 3: Configure TLS/SSL on Web Server (Nginx)
The next step calls for editing the Nginx configuration to use the Let’s Encrypt Certificate files. Here we will create a new server block that uses SSL/TLS and listens on port 443. Then we will configure the default (HTTP on port 80) server block to redirect to the HTTPS-enabled server block.
By default, additional server block configuration can be placed in /etc/nginx/conf.d. Create a new file called ssl.conf and open it for editing with this command:
sudo vi /etc/nginx/conf.d/ssl.conf
Then paste this configuration in. Be sure to change every instance of abc.com, all four, with your own domain name:
/etc/nginx/conf.d/ssl.conf
server {
listen 443 ssl;
server_name abc.com www.abc.com;
ssl_certificate /etc/letsencrypt/live/abc.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/abc.com/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ciphers ‘ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA’;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security max-age=15768000;
location ~ /.well-known {
allow all;
}
# The rest of your server block
root /usr/share/nginx/html;
index index.html index.htm;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
# Uncomment to enable naxsi on this location
# include /etc/nginx/naxsi.rules
}
}
Save and exit…
The above configuration configures Nginx to use SSL, and makes it use the SSL certificate we obtained in the earlier steps. The SSL options specified here ensure that only the most secure protocols and ciphers will be used. This example serves the default Nginx page only. You can modify it as per your requirement.
Now, we’ll configure Nginx to redirect HTTP requests on port 80 to HTTPS on port 443.
The default Nginx configuration file allows us to easily add directives to the port 80 server block by adding files in the /etc/nginx/default.d directory. Create a new file called ssl-redirect.conf and open it for editing with this command:
sudo vi /etc/nginx/default.d/ssl-redirect.conf
Then paste in this line:
/etc/nginx/default.d/ssl-redirect.conf
return 301 https://$host$request_uri;
Save and exit. This configures the HTTP on port 80 (default) server block to redirect incoming requests to HTTPS.
Now reload Nginx:
sudo systemctl reload nginx
You will also want to enable Nginx, so it starts when your server boots:
sudo systemctl enable nginx
The Let’s Encrypt TLS/SSL certificate is now active. To authenticate the working of your TLS/SSL certificate, you must test your domain via HTTPS in a web browser.
You can use the Qualys SSL Labs Report to see how your server configuration scores
In a browser :
https://www.ssllabs.com/ssltest/analyze.html?d=abc.com
This SSL setup should report an A+ rating.
Step 4: Set Up Auto Renewal
Let’s Encrypt certificate has a life of 90 days. In order to allow a margin of error it is recommended that you renew them every 60 days. Presently, automatic renewal is not an available feature of the client, but you can manually renew your certificates by running Let’s Encrypt client with the renew option.
Initiate the renewal process for all domains by using this command:
/opt/letsencrypt/letsencrypt-auto renew
Since our certificate was recently installed the command will only check for the expiration date. A message informing that the certificate is not due to renewal date will be on the screen. The output should look similar to this:
Output:
Checking for new version…
Requesting root privileges to run letsencrypt…
/root/.local/share/letsencrypt/bin/letsencrypt renew
Processing /etc/letsencrypt/renewal/abc.com.conf
The following certs are not due for renewal yet:
/etc/letsencrypt/live/abc.com/fullchain.pem (skipped)
No renewals were attempted.
Notice that if you created a bundled certificate with multiple domains, only the base domain name will be shown in the output, but the renewal should be valid for all domains included in this certificate.
A way to automate this process as well is to create a cron job. The software utility Cron is a time-based job scheduler in Unix-like computer operating systems. People who set up and maintain software environments use cron to schedule jobs (commands or shell scripts) to run periodically at fixed times, dates, or intervals. This cron job will periodically execute an automatic renewal command. The command first checks for the expiration date and only executes for renewal if the certificate is less than 30 days from expiration. Therefore it is safe to create a cron job that runs every week or even every day, for instance.
Let’s edit the crontab to create a new job that will run the renewal command every week. To edit the crontab for the root user, run:
sudo crontab -e
Add the following lines:
crontab entry
30 2 * * 1 /opt/letsencrypt/letsencrypt-auto renew >> /var/log/le-renew.log
35 2 * * 1 /usr/bin/systemctl reload nginx
Save and exit.
The above commands creates a new cron job that will execute the letsencrypt-auto renew command every Monday at 2:30 am, and reload Nginx at 2:35am (so the renewed certificate will be used). The output produced by the command will be piped to a log file located at /var/log/le-renewal.log.
Your installation is complete…
Updating the Let’s Encrypt Client.
You can update your local copy whenever new updates are available. Just run a git pull from inside the Let’s Encrypt directory:
cd /opt/letsencrypt
sudo git pull
This will download all recent changes to the repository ns update your client.