Set up SSL/TLS with Let's Encrypt

[//letsencrypt.org Let's Encrypt] is a [//en.wikipedia.org/wiki/Certificate_authority Certificate Authority] (CA) accepted by popular browsers that provides free certificates to support encrypting websites without drawing browser warnings. It is also supported by a convenient automation tool through the [//certbot.eff.org/ Certbot] project. Let's Encrypt certificates support [//en.wikipedia.org/wiki/Server_Name_Indication Server Name Indication] (SNI), an extension of TLS that allows accepting more than one certificate from one IP address.

This article explains how to configure SSL/TLS with Let's Encrypt on a LEMP web server configured as per the prior articles in this series. Note that the general procedure and configurations may be used with other Certificate Authorities.

Nearly every step in this article requires root level access:

username@servername:~$ sudo -i

Install letsencrypt
The  package contains all of the tools necessary to create and manage all of the necessary certificates. Note that if Python is not currently installed, then its various packages will be installed as they are required.

root@servername:~# add-apt-repository ppa:certbot/certbot root@servername:~# aptitude update root@servername:~# aptitude install python-certbot-nginx

When a certificate is created, it will be valid for example.com and one subdomain. To verify ownership of a domain, a temporary file will be written to a public directory, and then erased. To support this, make one small edit to the  file:

root@servername:~# nano /etc/nginx/global-configs/http_server.conf

Add as the very top line:

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

root@servername:~# service nginx restart

Create the directory:

root@servername:~# mkdir /var/www/example.com/public/.well-known root@servername:~# chown www-data /var/www/example.com/public/.well-known root@servername:~# chmod 775 /var/www/example.com/public/.well-known

Create the certificates:

root@servername:~# letsencrypt certonly --rsa-key-size 4096 --webroot -w /var/www/example.com/public/ -d example.com -d www.example.com -w /var/www/example.net/public/ -d example.net -d www.example.net

The additional domain of example.net is added to demonstrate using the command on multiple domains. Note that the configuration file name and certificate issuance domain will be assigned based on the first domain stated in the above command.

nginx.conf
Edit :

root@servername:~# nano /etc/nginx/nginx.conf

Add at the bottom of the  block:

ssl_session_cache shared:SSL:10m;

The  will set up a shared cache for SSL sessions across all virtual hosts between all worker processes.

dhparam.pem
The default OpenSSL Diffe-Helman Ephemeral (DHE) parameter is 1024 bits, which is weaker than the key strength of the server's private key, thus clients using DHE will connect with a weaker encryption than non-DHE clients. Generate a strong DHE parameter. Note that this will take some time to complete and will use approximately 100% of one thread (1.00 load) for the duration of the task.

root@servername:~# openssl dhparam -out /etc/ssl/private/dhparam.pem 4096 && chmod 600 /etc/ssl/private/dhparam.pem

HTTPS server common configuration file
Create the HTTPS server file, which includes the common settings for SSL/TLS in an HTTPS server block:

root@servername:~# nano /etc/nginx/global-configs/https_server.conf

Add to the file:

location ~ /\.well-known { allow all; } location ~ /\. { access_log off; log_not_found off; deny all; } location ~ ~$ { access_log off; log_not_found off; deny all; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { allow all; log_not_found off; access_log off; } ssl_protocols TLSv1.2; ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-CCM:DHE-RSA-AES256-CCM8; ssl_prefer_server_ciphers on; ssl_ecdh_curve secp384r1; ssl_dhparam /etc/ssl/private/dhparam.pem; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on; resolver  valid=300s; resolver_timeout 5s; add_header Strict-Transport-Security "max-age=63072000;includeSubDomains"; add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff;
 * 1) TLSv1 and TLSv1.1 may be added when desired to support older devices.
 * 2) TLSv1.3 can be added, but note it requires a 128-bit cipher
 * 3) See https://tools.ietf.org/html/rfc8446#section-9.1 for more details

SSL/TLS protocols and ciphers
The  are configured to leave out all variants of the SSL protocol and include only TLS. This is to protect against the [//en.wikipedia.org/wiki/POODLE POODLE attack]. The server should still be able to support the vast majority of devices, and given that it is already operating on SNI, most devices that don't support SNI also don't support any of the TLS protocols.

The  used are the strongest ciphers available and will yield a score of 100% on the Qualys SSL Labs SSL Report testing. The  directive instructs   not to use any cipher suites that offer no authentication.

Enabling  instructs the server to prefer server ciphers over client ciphers.

Setting the  instructs the server to use a stronger curve for ECDHE ciphers from the default curve of.

The  directive tells the server the location of the file to obtain DH parameters for DHE ciphers.

OCSP Stapling
Most clients will verify the validity of a server's certificate through either a [//en.wikipedia.org/wiki/Revocation_list Certificate Revocation List (CRL)] or [//en.wikipedia.org/wiki/Online_Certificate_Status_Protocol Online Certificate Status Protocol (OCSP)]. OCSP is typically preferred because the size of the CRLs is quite huge and pinging a server for a single record is a much faster method.

OCSP stapling is configured through several directives.

ssl_stapling
directive enables stapling of OCSP respones

enables verification of the responses by the server;

resolver
The  configures name servers used to resolve names of upstream servers into addresses. This can be either a domain or an IP address (both IPv6 or IPv4) and can be configured to accept only IPv4. Here are some examples:

Cloudflare IPv4 & IPv6: resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111]:535 [2606:4700:4700::1001]:5353 valid=300s;

OpenDNS IPv4: resolver 208.67.222.222 208.67.220.220 valid=300s;

OpenDNS IPv6: resolver [2620:0:ccc::2]:5353 [2620:0:ccd::2]:5353 valid=300s;

OpenDNS with both IPv4 and IPv6: resolver 208.67.222.222 208.67.220.220 [2620:0:ccc::2]:5353 [2620:0:ccd::2]:5353 valid=300s;

Google Public DNS: resolver 8.8.8.8 8.8.4.4 [2001:4860:4860::8888]:5353 [2001:4860:4860::8844]:5353 valid=300s;

A local network gateway using only IPv4: resolver 192.168.1.1 ipv6=off valid=300s;

The  sets a timeout for   name resolution.

ssl_trusted_certificate
OCSP stapling requires that the entire certificate chain be available. This is configured in the  file with the   directive.

Verification
To verify OSCP stapling is working properly, use either the Qualys SSL Labs SSL Server Test and look in the test results for OCSP stapling Yes or run the following command:

root@servername:~# openssl s_client -connect example.com:443 -tls1 -tlsextdebug -status

Note that this command may not work for servers behind firewalls.

The output of a test failure will include the line:

OCSP response: no response sent

The output of a successful test will include:

OCSP response: ====================================== OCSP Response Data: OCSP Response Status: successful (0x0) ...

HTTP headers
Several directives setting the [//en.wikipedia.org/wiki/List_of_HTTP_header_fields HTTP headers] can be used to enhance security.

HSTS
[//en.wikipedia.org/wiki/HTTP_Strict_Transport_Security HTTP Strict Transport Security] (HSTS) protects against downgrade attacks by telling a browser that after it has established a secure connection, it should only communicate using HTTPS.

Clickjacking prevention
This setting can prevent [//en.wikipedia.org/wiki/Clickjacking clickjacking] by setting controls on how a server may be viewed in a frame or an iframe. The example configuration of  will allow the site to be viewed in frames of the same origin server, which is a common feature in various popular PHP tools, including WordPress. Optionally, the  option could be used to prevent framing from any server. Note that there is an option for, but this is not well support by all popular browsers.

[//en.wikipedia.org/wiki/Content_Security_Policy Content Security Policy] (CSP) is being adopted and will replace  with its   option, but this is not yet widely supported.

X-Content-Type-Options
Adding the  prevents MIME-sniffing and is most important on sites that host user-uploaded content.

Add HTTPS server block to sites-available file
Open the sites-available file and add the HTTPS server block.

root@servername:~# nano /etc/nginx/sites-available/example.com

Add below the HTTP server block: server { listen 443 ssl; listen [::]:443 ssl; root /var/www/example.com/public; access_log /var/www/example.com/logs/access.log; error_log /var/www/example.com/logs/error.log; server_name www.example.com; include global-configs/https_server.conf; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem; location / { try_files $uri $uri/ =404; } }
 * 1) HTTPS server

Test then restart nginx.

root@servername:~# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful root@servername:~# service nginx reload

Navigating to  https://example.com  (or  https://subdomain.example.com ) should load  in a secure session.

Note that if the the local device's ISP has not yet updated to the new DNS records for the server, entering the IP address of the server should bring up the page, but with the browser's certificate warnings. Proceeding through these warnings should allow the user to view the certificate and verify its settings are correct. Presumably, once the DNS records have updated, the certificates should function normally.

Configure automated renewals
Let's Encrypt certificates expire after only 90 days. Fortunately, one of the most useful and convenient tools available through certbot is the automation of certificate renewal, which can be done through a simple cron job.

root@servername:~# crontab -e

Add the following at the bottom:

30 2 * * 1 /usr/bin/letsencrypt renew >> /var/log/le-renew.log 40 2 * * 1 /bin/systemctl reload nginx

This will run the renew script every Monday at 02:30, save an output to a log file, and then reload nginx at 02:40 so that the new certificate is used.

Install ntp
The ntp package maintains the system clock instead of having only the default method for time synchronization,, which runs only once, when Ubuntu starts up. It is important for the clock to be synchronized because, theoretically, if a server goes a long time without being restarted, or a motherboard battery failure causes system clock malfunctions, it may end up having issues with the certificate authority.

root@servername:~# aptitude install ntp

Add CAA records
The [//en.wikipedia.org/wiki/DNS_Certification_Authority_Authorization DNS Certification Authority Authorization] (CAA) record adds an additional layer of security by declaring which CAs are permitted to issue certificates for a domain and should be added when the DNS server supports it.

Based on the configurations in this article, CAA records should include at least two entries per domain, and at least two entries per subdomain:

example.com       issue        letsencrypt.org example.com       issuewild    ;

www.example.com   issue        letsencrypt.org www.example.com   issuewild    ;

Further configuration assistance is available from SSLMate's CAA Record Helper.

Common configurations
The HTTPS server block is just as configurable as the HTTP server block, but some configurations are commonly desired by adminstrators.

Require location to load in HTTPS
To require a file or directory to load only in HTTPS, perform the following.

root@servername:~# nano /etc/nginx/sites-available/example.com

In the HTTP server block, add the following:

location ^~ /path/to/directory/or/file { return 301 https://$server_name$request_uri; }

Require subdomain or site to load in HTTPS
To require a subdomain or site to load only HTTPS, perform the following:

root@servername:~# nano /etc/nginx/sites-available/example.com

Add the following server block:

server { listen 80; listen [::]:80; server_name example.com www.example.com; access_log off; error_log /var/www/example.com/logs/error.log; return 301 https://subdomain.example.com$request_uri; }

Testing
The [//www.ssllabs.com/ssltest/index.html Qualys Labs SSL Server Test] is regularly updated based on new vulnerabilities and changes in the SSL/TLS standard. Periodically testing a server there is useful for making sure the server is configured correctly and securely.



Next step
Install PHP, that oh-so-popular server-side scripting language.