nginx as a reverse proxy with letsencrypt SSL
05 Dec 2015Let’s Encrypt has just entered public beta, and so, is now generally available for the public to use. Whilst in public beta, there are a few access restrictions (5 certificates per domain per week).
Whilst official support for nginx is still in development, it is still possible to use nginx with automatically renewing certificates from Let’s Encrypt (including automatic verification!). Here’s how I’ve achieved it, all credit to ‘renchap’ on the letsencrypt community forums for the original guide.
1. Configuring nginx
The nginx configuration is quite straightforward. We simply tell nginx to server on port 80 for all domains, a path named /.well-known/acme-challenge. Let’s Encrypt uses this path to perform automatic verification of domain name ownership. We tell nginx to serve from the /tmp/letsencrypt-auto directory, which we will configure letsencrypt to use when generating a certificate.
1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 80;
listen [::]:80;
server_name ~(.*)$;
location '/.well-known/acme-challenge' {
default_type "text/plain";
root /tmp/letsencrypt-auto;
}
location / {
return 302 https://$host$request_uri;
}
}
I place this snippet in the http block directly in my nginx.conf. This will match any domains that are not already configured to listen on port 80, (hence the server_name being set to ~(.*)$).
We also set up a 302 redirect to the HTTPS site - this enforces SSL on a domain by default (although it’s still possible to override this for individual domains).
2. Request a certificate
So after following the letsencrypt installation guide, we need to request our first certificate. With nginx set up and running from the above step, we run the following command:
letsencrypt-auto certonly --server https://acme-v01.api.letsencrypt.org/directory -a webroot --webroot-path=/tmp/letsencrypt-auto -d example.org -d www.example.orgThis will generate a single certificate the is for both example.org and www.example.org. Please note that the DNS record for both example.org and www.example.org must resolve to your nginx instance you’ve just configured. This is because letsencrypt will make a request to your server for a file that is generated by the letsencrypt client in order to verify you control the domain name.
Once this process is succesful, a folder containing your certificate and private key (as well as certificate chain) will be generated. As of the time of writings, letsencrypt stores this folder at /etc/letsencrypt/live/.
3. Set up autorenewal
letsencrypt certificates expire after 90 days, and so it’s recommended you renew your certificates every 60 days to be safe. To do this, we’ll configure cron to run a renewal command every 2 months. This can be done with the following line in your crontab:
0 0 */2 * * /letsencrypt/letsencrypt-auto --renew certonly --server https://acme-v01.api.letsencrypt.org/directory -a webroot --webroot-path=/tmp/letsencrypt-auto -d example.org -d www.example.org && service nginx reloadThis is the same as the command we ran in the previous step, with the addition of the --renew flag. We also reload nginx after renewing so that it begins using the new certificate immediately.
4. Configure nginx to use your certificate
So now that we have our new certificate, and we have cron configure to automatically renew them every 2 months, it’s time to configure nginx to actually use this new certificate.
This step should be trivial for anyone that’s configure nginx to use SSL before. Simply create a new file in your /etc/nginx/sites-enabled folder, containing something similar to the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
upstream backend {
server server1;
}
server {
listen 443;
server_name example.org www.example.org;
ssl on;
ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;
location / {
proxy_pass http://backend;
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
}
}
Conclusion
Whilst not the easiest setup procedure, this is a nice and quick way to get up and running with letsencrypt before they add official support for nginx to the letsencrypt client. If you’ve noticed any issues as you follow this guide, please let me know!