Instantly share code, notes, and snippets.

Embed
What would you like to do?
One-line certificate generation/renews with Letsencrypt and nginx

Prerequisites : the letsencrypt CLI tool

This method allows your to generate and renew your Lets Encrypt certificates with 1 command. This is easily automatable to renew each 60 days, as advised.

You need nginx to answer on port 80 on all the domains you want a certificate for. Then you need to serve the challenge used by letsencrypt on /.well-known/acme-challenge. Then we invoke the letsencrypt command, telling the tool to write the challenge files in the directory we used as a root in the nginx configuration.

I redirect all HTTP requests on HTTPS, so my nginx config looks like :

server {
  listen              80;
  listen              [::]:80;
  server_name         example.net example.org;
  location '/.well-known/acme-challenge' {
  default_type "text/plain";
    root        /tmp/letsencrypt-auto;
  }

  location / {
    return              301 https://$server_name$request_uri;
  }
}

This approatch allows me do no longer needing to do any nginx config change if I add a new domain and use server_name *;, I create a new certificate with the needed hostname, and add the new vhost for this domain listening on 443 only using the newly generated certificate.

Then, to generate your initial certificate for those domains :

$ export DOMAINS="-d example.net -d example.org"
$ export DIR=/tmp/letsencrypt-auto
$ mkdir -p $DIR && letsencrypt certonly --server https://acme-v01.api.letsencrypt.org/directory -a webroot --webroot-path=$DIR --agree-dev-preview $DOMAINS
$ service nginx reload

The command will output the path to the signed certificate, and you can add it to your nginx configuration as usual. The private key is located in the same directory than the generated fullchain.pem

A Lets Encrypt cert is valid for 90 days, it is recommended to renew every 60 days. Automation is needed here to avoid any expired certificate ! To renew your certificate (in a cron job for example), call the same command with a --renew arg :

$ export DOMAINS="-d example.net -d example.org"
$ export DIR=/tmp/letsencrypt-auto
$ mkdir -p $DIR && letsencrypt --renew certonly --server https://acme-v01.api.letsencrypt.org/directory -a webroot --webroot-path=$DIR --agree-dev-preview $DOMAINS
$ service nginx reload

You can also get a duplicate certificate by using the same command again, with a --duplicate arg.

@ethanmick

This comment has been minimized.

ethanmick commented Dec 3, 2015

Love this!

Perhaps an update though? I got:

Use of --agree-dev-preview is deprecated.

So it looks like with the public beta, this has changed. Thanks!

@jlowgren

This comment has been minimized.

jlowgren commented Dec 5, 2015

To my knowledge, --agree-dev-preview has been replaced with --agree-tos.

@Ajnasz

This comment has been minimized.

Ajnasz commented Dec 14, 2015

It's so cool! Thank you!

I created a tool to list those certificates which about to expire, so you can renew only those which are going to expire soon:
https://github.com/Ajnasz/letsencrypt-expiring-certs

@rdlu

This comment has been minimized.

rdlu commented Dec 15, 2015

@Ajnasz: nice tool, but it does support SNI, or multiple certs over nginx?

For this you need to run one command per certificate ("per main domain"). A single command will generate only one certificate for all domains.

@Ajnasz

This comment has been minimized.

Ajnasz commented Dec 20, 2015

@rdlu Thanks for the reply. I updated the program, also attached a shell script for easier setup, if you wish.

@linwiz

This comment has been minimized.

linwiz commented Dec 26, 2015

@Ajnasz forgive my ignorance, but the readme for letsencrypt-expiring-certs doesn't tell me anything about how to compile the source code. Can you provide me with more information please?

@Ajnasz

This comment has been minimized.

Ajnasz commented Dec 27, 2015

@linwiz I added some documentation about compilation.

@gmemstr

This comment has been minimized.

gmemstr commented Jan 3, 2016

I'm a bit confused - I followed the steps, but I can't seem to connect. https:// doesn't work and when I curl http:// it gives me the 301 status. My site is served from /home/gabriel/public_html, so I'm thinking maybe it's my root directory I need to change?

@rafaelalcalde

This comment has been minimized.

rafaelalcalde commented Feb 24, 2016

How can I do the letsencrypt setup properly in nginx if the domain which I 've to install the certificate it is only an alias of the principal? It does not works adding the lines on "default" config for nginx

@jult

This comment has been minimized.

jult commented Mar 9, 2016

Opened a can of worms for my config. Little sad that the intended simplicity of letsencrypt ends up taking up more time than when I would simply use startssl..

@rturk

This comment has been minimized.

rturk commented Jun 9, 2016

I'm surprised that Letsencrypt don't try HTTPS first and only as second option HTTP.

@BillyParadise

This comment has been minimized.

BillyParadise commented Aug 2, 2016

Some things have changed

  • letsencrypt is now letsencrypt-auto
  • --agree-dev-preview is deprecated

Renewal also needs to be updated

./letsencrypt-auto renew --server https://acme-v01.api.letsencrypt.org/directory -a webroot --webroot-path=$DIR

@marcmmx

This comment has been minimized.

marcmmx commented Aug 12, 2016

For me this package works:

export DOMAINS="-d example.net -d example.org"
export DIR=/tmp/letsencrypt-auto
mkdir -p $DIR && ./letsencrypt-auto certonly --server https://acme-v01.api.letsencrypt.org/directory -a webroot --webroot-path=$DIR --agree-tos $DOMAINS
service nginx reload

@Lewiscowles1986

This comment has been minimized.

Lewiscowles1986 commented Dec 2, 2016

❤️ this. Been messing with DNS challenge, but aside from spamming my DNS with records I now have to clear it was nothing but a PITA.

Is anyone using this with nginx as a FLB? I'm thinking of installing letsencrypt to terminate SSL at the FLB and transfer via private network but I'm sure that is less secure than it should be and I'd love to see any reference material anyone has to share.

@917huB

This comment has been minimized.

917huB commented May 3, 2017

thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment