The Let's Encrypt is a certificate authority that offers free and automated SSL/TLS certificates for your website(s). It issues certificates trusted by most browsers. In this article will show how to setup and automate the renewal of Let's Encrypt SSL/TLS certificates with Nginx.
It is assumed that Nginx is already installed in your system. But if it is not please follow the steps in this article. The following procedures are tested on Linode server running Centos 7 64-bit Linux distribution.
The following steps are not updated. Please follow the updated steps in this article.
-
Download the Let's Encrypt client:
yum install -y git git clone https://github.com/certbot/certbot /opt/letsencrypt
Note: to update the Let's Encrypt client execute:
cd /opt/letsencrypt git pull
-
Let's Encrypt client validates ownership of your domain by creating a temporary file (a token) in
[webroot-path]/.well-known/acme-challenge/
. We will use/var/www/letsencrypt
as our [webroot-path]. Let's create it and set permission:mkdir -p /var/www/letsencrypt chown apache. /var/www/letsencrypt
Note: 'apache' is a user set in nginx.conf. If this is not the case in your setup, please change it to user set in your nginx.conf file.
-
The Let's Encrypt client sends an HTTP request to validate the temporary file created in
/var/www/letsencrypt/.well-known/acme-challenge/
which serves as verification that your domain's DNS record resolves to the server running it. Skip this step if you came from and followed this article. To allow the HTTP request to access the temporary file, add the following nginx script snippet:location /.well-known/acme-challenge { root /var/www/letsencrypt; }
... in your virtual servers. Example, applying it in 'yourwebsite.com' and 'yourotherwebsite.com' virtual servers nginx script:
... server { listen XXX.XXX.XXX.XXX:80; ## IPv4 listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:80; ## IPv6 server_name yourwebsite.com www.yourwebsite.com; ... location /.well-known/acme-challenge { root /var/www/letsencrypt; } ... } ... server { listen XXX.XXX.XXX.XXX:80; ## IPv4 listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:80; ## IPv6 server_name yourotherwebsite.com www.yourotherwebsite.com; ... location /.well-known/acme-challenge { root /var/www/letsencrypt; } ... } ...
Note: The
XXX.XXX.XXX.XXX
is your server's IPv4 address andXXXX:XXXX::XXXX:XXXX:XXXX:XXXX
is your server's IPv6 address.Restart Nginx:
systemctl restart nginx
-
Create Let's Encrypt configuration file
/etc/nginx/letsencrypt/domain.conf
and add the following to it:# Domains (100 maximum) domains = yourwebsite.com,www.yourwebsite.com,yourotherwebsite.com,www.yourotherwebsite.com # Key size 2048 or 4096 rsa-key-size = 2048 # The current closed beta (as of 2015-Nov-07) is using this server server = https://acme-v01.api.letsencrypt.org/directory # This email will receive renewal reminders email = [email protected] # Configure it to make non-interactively to be able to run as a cronjob text = True agree-tos = True renew-by-default = True # Authenticate by placing a file in the webroot (under .well-known/acme-challenge/) # and then letting LE fetch it authenticator = nginx webroot-path = /var/www/letsencrypt/
As of this writing, Let's Encrypt does not support wildcard certificates yet. Include all the domains and their sub-domains in 'domains' parameter inside your Let's Encrypt configuration file. Take note that Let's Encrypt can only holds a maximum of 100 domains/sub-domains per certificate. If you have more than 100 domains/sub-domains, you will need to split or create new Let's Encrypt configuration file the another set of 100 domains/sub-domains.
Use 2048 bits for 'rsa-key-size' if performance is your priority and use 4096 if more security strength is needed. Plus 2048 bits uses less CPU during encryption and authentication; and less CPU means less battery drain than 4096 bits.
-
We can now request the certificate by executing:
/opt/letsencrypt/letsencrypt-auto --config /etc/nginx/letsencrypt/domain.conf certonly
If successful, we should see message something like this at the end:
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/yourwebsite.com/fullchain.pem. Your cert will expire on 2017-03-08. To obtain a new or tweaked version of this certificate in the future, simply run letsencrypt-auto again. To non-interactively renew *all* of your certificates, run "letsencrypt-auto renew"
Note: the path name
/etc/letsencrypt/live/yourwebsite.com
generated by the Let's Encrypt client is based on the first domain name listed in 'domains' parameter inside your Let's Encrypt configuration file/etc/nginx/letsencrypt/domain.conf
. In our case, it is 'yourwebsite.com' and the certificate files generated inside/etc/letsencrypt/live/yourwebsite.com
are already for 'yourwebsite.com', 'www.yourwebsite.com', 'yourotherwebsite.com' and 'www.yourotherwebsite.com' domains. -
Integrate the Let's Encrypt generated certificate with Nginx. Skip this step if you came from and followed this article. Open your
/etc/nginx/nginx.conf
and add the following nginx script snippet inside the 'http' context:## Timeout for keep-alive connections. ## Server will close connections after this time. keepalive_timeout 75 75; ## Use a SSL/TLS cache for SSL session resume. This needs to be ## here (in this context, for session resumption to work. See this ## thread on the Nginx mailing list: ## http://nginx.org/pipermail/nginx/2010-November/023736.html. ## 1MB store about 4000 sessions: ## In this case, it store about 80000 sessions in 1 day ssl_session_cache shared:SSL:20m; ssl_session_timeout 1d; ## The server dictates the choice of cipher suites. ssl_prefer_server_ciphers on; ## Use only Perfect Forward Secrecy Ciphers. ## No SSLv3 support (SSLv3 POODLE Vulnerability) ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ## Old Mozilla SSL Configuration ## https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.10.2&openssl=1.0.1e&hsts=no&profile=old ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305: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:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP'; ## Pregenerated Diffie-Hellman parameters 2048. ssl_dhparam key/dh_param.pem; ## Curve to use for ECDH. ssl_ecdh_curve prime256v1; ## Enable OCSP stapling. A better way to revocate server certificates. ssl_stapling on; ## Enable verification of OCSP stapling responses by the server. ssl_stapling_verify on; ## Server certificate and key (using Let's Encrypt free SSL certificate). ssl_certificate /etc/letsencrypt/live/yourwebsite.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourwebsite.com/privkey.pem; ## Verify chain of trust of OCSP response using Root CA and Intermediate certs ssl_trusted_certificate /etc/letsencrypt/live/yourwebsite.com/chain.pem; ## Use Google's DNS resolver 8.8.8.8 8.8.4.4;
Generate DH parameters file with 2048 bit long safe prime:
openssl dhparam 2048 -out /etc/nginx/key/dh_param.pem
Restart Nginx:
systemctl reload nginx
-
The Let's Encrypt certificate is only valid for three months. Automating the renewal of the certificate is possible with Let's Encrypt client using cronjob. Let's create a bash script that cronjob will execute to renew the Let's Encrypt certificate(s). Create
/etc/nginx/letsencrypt/renew.sh
file and add the following to it:#!/bin/sh for conf in $(ls /etc/nginx/letsencrypt/*.conf); do /opt/letsencrypt/letsencrypt-auto --config "$conf" certonly done systemctl reload nginx
-
Execute
crontab -e
and append this line to run the script every two months:0 0 1 */2 * /bin/sh /etc/nginx/letsencrypt/renew.sh
-
Test your website's SSL rating at https://www.ssllabs.com/ssltest.
Comments
Let's Encrypt only works on…
/etc/letsencrypt/live/mydjroom.com/
is empty.
/opt/letsencrypt/letsencrypt-auto --config /etc/nginx/letsencrypt/domain.conf certonly
name
I see, thank you! Could you please change my domain name in my comment to example.com?
thank you
ssl record too long
when loading a https page, I get:
An error occurred during a connection to mydjroom.com. SSL received a record that exceeded the maximum permissible length. Error code: SSL_ERROR_RX_RECORD_TOO_LONG
Is the protocol not changing to https?
fixed
In sites-enabled .conf I changed the listen to "listen 443 ssl;" instead of listen " listen 0.0.0.0:443;" . Now it works.
But why do I need to put these lines in my sites-enabled? Aren't they already loaded via nginx.conf?
This is my sites-enabled\example.com.conf:
server {
listen 0.0.0.0:80;
listen 443 ssl;
server_name example.com;
location / {
root /home/ericson/public_html/example.com;
index index.html index.htm;
try_files $uri $uri/ =404;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
proxy_set_header X-Forwarded-Proto https;
}
Is it all correctly done?
Your website's domain(s)…
server
context which tells that your nginx is(are) handling your website(s). In your sites-enabled
folder is where your active site(s) configuration files located. Actually, you can have have all your nginx configuration files' content written in one file nginx.conf
and remove the rest of configuration files and folders. But we don't do that. We separate the configuration into multiple files for the sake of best practice (code readability, organization, etc.) and call these files in our main nginx.conf
.
The lines:
listen 0.0.0.0:80;
listen 443 ssl;
Ideally, you should only define one port and listen
directive for each server
context. If you prefer your website as SSL version, create two server
context and redirect the non-SSL to SSL server
context.
No such file or directory
did all the steps, but I get this error:
nginx: [emerg] BIO_new_file("/etc/letsencrypt/live/example.com/fullchain.pem") failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/etc/letsencrypt/live/example.com/fullchain.pem','r') error:2006D080:BIO routines:BIO_new_file:no such file) nginx: configuration file /etc/nginx/nginx.conf test failed