Certbot example: nginx

From wikinotes

Setup

This example demonstrates how to request an SSL certificate to be used on a single, explicit domain name (also works for explicit subdomains).
Before issuing a certificate, you must have purchased a domain-name, and have it's DNS records pointed at your server (See Networking DNS ).

1. Setup a http webserver (you need something online to request a certificate)

/etc/nginx.conf

# /etc/nginx/nginx.conf

http {
    server {
        listen 80;        # ipv4
        listen [::]:80;   # ipv6
        
        server_name   yourdomain.com;
        # ...your server blocks...
    }



2. request a certificate

certbot --nginx certonly \
    --domain yourdomain.com \
    --agree-tos \
    --agree-dev-preview \
    --no-eff-email

3. add a certificate to your webserver

/etc/nginx/nginx.conf

# /etc/nginx/nginx.conf

http {
    server {
        listen 80;        # ipv4
        listen [::]:80;   # ipv6
        
        listen 443 ssl http2;       # ssl ipv4
        listen [::]:443 ssl http2;  # ssl ipv6

        server_name   yourdomain.com;  # must be cert FQDN
        ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
        ssl_certificate_key  /etc/letsencrypt/live/yourdomain.com/privkey.pem;
        include /etc/letsencrypt/options-ssl-nginx.conf;

        # ...your server blocks...
    }
}

4. cron job to auto-renew cert

crontab -e

* 2,14 * * *  /usr/bin/bash -c 'sleep $[RANDOM\%60]m' && /usr/bin/certbot renew --agree-tos --agree-dev-preview --no-eff-email

saltstack recipe (simple)

If you're hosting a simple website, and do not need a wildcard certificate, issuing/renewing a certificate can be completely automated. Here is a saltstack recipe I wrote do perform this.

#!stateconf
#


# NOTE: this can't be tested on VM - A/AAAA records (DNS) must
#       be set for a CSR (Certificate-Signature-Request)

    # certbot arguments
    {% set CSR_promptparams = '--agree-tos --no-eff-email' %}
    {% set CSR_testparams = '' %}   # --test-cert
    {% set RENEW_testparams = '' %} # --dry-run

    # domains SSL certificate should validate
    {% set base_domain = 'mydomain.com' %}


include:
    - progs.webservices.certbot.nginx


./etc/letsencrypt/cli.ini (default certbot params):
    file.managed:
        - name:   /etc/letsencrypt/cli.ini
        - source: salt://hosts/webhost/files/certbot-cli.ini


    {% if not salt.file.file_exists( '/etc/letsencrypt/live/' + base_domain + '/cert.pem' )%}
.install SSL cert (A/AAAA records must be set!!):
    cmd.run:
        - name: certbot {{CSR_testparams}} --nginx certonly --domain {{base_domain}} {{CSR_promptparams}}
    {% endif %}


# NOTE: webserver must be running before SSL CSR can be issued.
#      after certificate is issued, enable SSL.
    {% if salt.file.file_exists( '/etc/letsencrypt/live/' + base_domain + '/cert.pem' )%}
./etc/nginx/nginx.conf:
    file.blockreplace:
        - name: /etc/nginx/nginx.conf
        - marker_start: '# <ssl_setup>'
        - marker_end:   '# </ssl_setup>'
        - append_if_not_found: False
        - content: |
            listen       443 ssl http2;       # ipv4
            listen       [::]:443 ssl http2;  # ipv6
            server_name  {{base_domain}};

            ssl_certificate     /etc/letsencrypt/live/{{base_domain}}/fullchain.pem;
            ssl_certificate_key /etc/letsencrypt/live/{{base_domain}}/privkey.pem;
            include /etc/letsencrypt/options-ssl-nginx.conf;
    {% endif %}


# NOTE: delay randomy <60min out of kindness for letsencrypt's servers.
.auto-renew certificate:
    cron.present:
        - identifier: renew_certbot_sslcert
        - user: root
        - name: /usr/bin/bash -c 'sleep $[RANDOM\%60]m' && /usr/bin/certbot renew {{CSR_promptparams}} {{RENEW_testparams}}
        - minute: '*'
        - hour: '2,14'
        - daymonth: '*'
        - month: '*'
        - dayweek: '*'