Let’s Encrypt with lego and nginx

1. Prepare the server

server {
    listen 80;
    server_name example.com;
    server_name www.example.com;

    # Other directives

    location /.well-known/acme-challenge {
        proxy_pass http://127.0.0.1:81;
        proxy_set_header Host $host;
    }
}

2. Order the certificate

sudo bash
cd /www/letsencrypt
lego --email="mail@gmail.com" --domains="example.com" --domains="www.example.com" --http=:81 run

When supplying multiple domains to the –domains switch, lego creates a SAN (Subject Alternate Names) certificate which results in only one certificate but this certificate is valid for all domains you entered. The first domain in your list is added as the “CommonName” of the certificate and all other domains are added as “DNSNames” to the SAN extension inside of your certificate.

There are ways to run as a different user than “root”. See lego documentation.

3. Update the server

server {
    listen 80;
    server_name example.com www.example.com;

    location / {
        return 301 https://example.com$request_uri;
    }

    location /.well-known/acme-challenge {
        proxy_pass http://127.0.0.1:81;
        proxy_set_header Host $host;
    }
}

server {
    listen 443 ssl;
    server_name example.com www.example.com;

    ssl_certificate /www/letsencrypt/.lego/certificates/example.com.crt;
    ssl_certificate_key /www/letsencrypt/.lego/certificates/example.com.key;

    # Other directives
}
service nginx reload

4. Renew every 90 days

sudo bash
cd /www/letsencrypt
lego --email="mail@gmail.com" --domains="example.com" --domains="www.example.com" --http=:81 --tls=:444 -x "tls-sni-01" renew
service nginx reload

The “tls-sni-01” challenge is excluded because it would require port 443 to be forwarded unmodified to lego. If multiple domains are hosted on the same IP address, this is very complicated. Instead, we rely on the HTTP challenge.