Let’s Encrypt & Certbot
Let’s Encrypt is a free, automated, and open Certificate Authority. And Certbot is the shell client to deploy Let’s Encrypt certificates. Some providers manage the certificates for you but in our case we will directly use Certbot.
Installation
Just follow the instruction on Certbot website.
With debian 9 (stretch), we simply do:
$ apt-get install certbot
Or with debian 8 (jessie):
$ apt-get install certbot -t jessie-backports
HTTP Nginx configuration
Before starting to generate our first certificates with Let’s Encrypt, we first need to have Nginx responding to our domain(s). With this example we have our server listening to myapp.com
and www.myapp.com
domain and subdomain in HTTP with /home/deploy/myapp/current/public
folder as root.
server {
listen 80;
server_name myapp.com www.myapp.com;
root /home/deploy/myapp/current/public;
}
And we also need to create the directory if it’s not already existing.
$ mkdir -p /home/deploy/myapp/current/public
Certificates generation
Now to generate certificates we simply execute the following command. You only need to apply it once (or more if you want to add subdomains to the same certificate or change some configuration). By default Certbot comes with a cron which renews certificates by itself.
$ certbot certonly --webroot \
--webroot-path /home/deploy/myapp/current/public \
--keep-until-expiring \
--email email@domain.tld \
--agree-tos \
--non-interactive \
-d domain.tld \
-d www.domain.tld \
--rsa-key-size 4096 \
--post-hook "/bin/systemctl reload nginx.service"
[--expand]
If you already generate certificates and you want to add one or more new domains, you have to use the --expand
option.
Options explanation
Option | Description |
---|---|
--webroot |
Obtain certs by placing files in a webroot directory. |
--webroot-path |
public_html / webroot path. This can be specified multiple times to handle different domains; each domain will have the webroot path that precede it. |
--keep-until-expiring |
If the requested cert matches an existing cert, always keep the existing one until it is due for renewal (for the ‘run’ subcommand this means reinstall the existing cert). (default: Ask) |
--email |
Email used for registration and recovery contact. (default: Ask) |
--agree-tos |
Agree to the ACME Subscriber Agreement (default: Ask) |
--non-interactive |
Run without ever asking for user input. This may require additional command line flags; the client will try to explain which ones are required if it finds one missing (default: False) |
--domain|-d |
Domain names to apply. For multiple domains you can use multiple -d flags or enter a comma separated list of domains as a parameter. |
--rsa-key-size |
Size of the RSA key. (default: 2048) |
--post-hook |
Command to be run in a shell after attempting to obtain/renew certificates. We use it to reload nginx configuration because nginx need to have the new generated certificates. |
--expand |
Tell Certbot to expand the certificate with new domaines if the certificate already exists. |
HTTPS Nginx configuration
Now we have to configure our HTTP server. In our case we use Nginx.
We first have to generate a dhparam.pem
:
$ openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096
While you’re at it, you can improve the security of Nginx configuration by hiding Server
header. To do so, create the following file:
# /etc/nginx/conf.d/security.conf
server_tokens off;
add_header "Server" "anon.";
proxy_pass_header "Server";
Then we create a snippet that contains the generic ssl configuration:
# /etc/nginx/snippets/ssl.conf
add_header Strict-Transport-Security 'max-age=31536000';
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
ssl_prefer_server_ciphers on;
ssl_ciphers 'kEECDH+ECDSA+AES128 kEECDH+ECDSA+AES256 kEECDH+AES128 kEECDH+AES256 +SHA !aNULL !eNULL !LOW !MD5 !EXP !DSS !PSK !SRP !kECDH !CAMELLIA !RC4 !SEED';
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
keepalive_timeout 70;
ssl_stapling on;
ssl_stapling_verify on;
resolver_timeout 10;
And to finish we have to update the configuration for our website. Here’s an example with a Rails application:
# /etc/nginx/sites-enabled/myapp.conf
upstream app {
server unix:///home/deploy/myapp/current/tmp/sockets/puma.sock fail_timeout=0;
}
# http to https redirection
server {
listen 80;
server_name myapp.com www.myapp.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name myapp.com www.myapp.com;
root /home/deploy/myapp/current/public;
# ssl configuration
ssl_certificate /etc/letsencrypt/live/myapp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myapp.com/privkey.pem;
include /etc/nginx/snippets/ssl.conf;
try_files $uri/index.html $uri @app;
# proxy to unix socket
location @app {
proxy_pass http://app;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_redirect off;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# assets
location ~ ^/assets/ {
gzip_static on;
expires 1y;
add_header Cache-Control public;
add_header ETag "";
}
}
And don’t forget to reload your nginx configuration by running systemctl reload nginx.service
. It’s recommended to use reload
instead of restart
to avoid stopping nginx server. So if you make a mistake in the configuration you are still serving your applications ;)
What about certificates expiration?
One nice thing by installing Certbot with the package manager is that it installs a cron with a renew script (/etc/cron.d/certbot
). It renews certificates which are expiring within 30 days.
Because we generate our certificates with --keep-until-expiring
and --post-hook "/bin/systemctl reload nginx.service"
, Certbot will generate the new certificates and reload nginx configuration just after.
So let the magic operate, you have nothing more to do!
Conclusion
And there you have it, a fresh configuration to run your application in https!
Edit 2017-07-29: Added “HTTP Nginx configuration” missing section.