Skip to content

Instantly share code, notes, and snippets.

@peterwwillis
Last active March 8, 2021 02:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peterwwillis/454de911fdb3ee93584e5fef279fe164 to your computer and use it in GitHub Desktop.
Save peterwwillis/454de911fdb3ee93584e5fef279fe164 to your computer and use it in GitHub Desktop.
Let's Encrypt cheat sheet

Install Certbot

Debian 8

Debian 8 (Jessie) End Of Life was June 17, 2018, its LTS support ended on June 30, 2020, and its Extended LTS ends on June 30, 2022. The backports have been moved to "archive", so extra steps are necessary to install backport packages.

echo "deb [check-valid-until=no] http://archive.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/jessie-backports.list
apt-get -o Acquire::Check-Valid-Until=false update
apt-get -o Acquire::Check-Valid-Until=false -t jessie-backports install -y certbot

Supported Linux distros

Certbot (apparently) only works on officially supported Linux distributions (of which Debian 8 is not one).

wget -O /usr/local/bin/certbot-auto https://dl.eff.org/certbot-auto
chmod a+x /usr/local/bin/certbot-auto
ln -sf /usr/local/bin/certbot-auto /usr/local/bin/certbot
certbot

Docker

If all else fails, you can always run certbot with Docker.

docker run --rm certbot/certbot

Install a certificate with certbot

Install a cert behind a proxy (like CloudFlare)

certbot certonly \
  --webroot \
  --webroot-path /var/www/html/ \
  --renew-by-default \
  --email email@host.tld \
  --text \
  --agree-tos \
  -d example.tld \
  -d www.example.tld

Install a cert behind a proxy using Docker certbot

Use this simple bash wrapper to run certbot via Docker.

  1. Make sure Nginx is running with the following config files.
# file: /etc/nginx/letsencrypt-acme-challenge.conf
location ^~ /.well-known/acme-challenge/ {
    # Set correct content type. According to this:
    # https://community.letsencrypt.org/t/using-the-webroot-domain-verification-method/1445/29
    # Current specification requires "text/plain" or no content header at all.
    # It seems that "text/plain" is a safe option.
    default_type "text/plain";
    
    # This directory must be the same as in /etc/letsencrypt/cli.ini
    # as "webroot-path" parameter. Also don't forget to set "authenticator" parameter
    # there to "webroot".
    # Do NOT use alias, use root! Target directory is located here:
    # /var/www/common/letsencrypt/.well-known/acme-challenge/
    root         /var/www/letsencrypt;
}

# Hide /acme-challenge subdirectory and return 404 on all requests.
# It is somewhat more secure than letting Nginx return 403.
# Ending slash is important!
location = /.well-known/acme-challenge/ {
    return 404;
}
# file: /etc/nginx/sites-enabled/default
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    include /etc/nginx/letsencrypt-acme-challenge.conf;
    root /var/www/html;
    # Add index.php to the list if you are using PHP
    index index.html index.htm index.nginx-debian.html;
    server_name _;
    location / {
            # First attempt to serve request as file, then
            # as directory, then fall back to displaying a 404.
            try_files $uri $uri/ =404;
    }
}

Make sure to change the 2 lines noted below with your e-mail & domains.

#!/bin/bash
# file: /usr/local/bin/docker-certbot.sh
set -eu

# NOTE: CHANGE THESE 2 LINES!
CERTBOT_EMAIL="myemail@example.com"
declare -a CERTBOT_DOMAINS=(example.com www.example.com)

_run_certbot_docker () {
    docker run \
        --rm \
        -it \
        -v "/etc/letsencrypt:/etc/letsencrypt" \
        -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
        -v "/var/www/letsencrypt:/var/www/letsencrypt" \
        certbot/certbot "$@"
}
_run_certbot_docker_certonly () {
    declare -a ARGS=()
    for d in "${CERTBOT_DOMAINS[@]}" ; do ARGS+=("-d" "$d") ; done
    _run_certbot_docker certonly \
        --webroot \
        --webroot-path /var/www/letsencrypt \
        --renew-by-default \
        --email "$CERTBOT_EMAIL" \
        --text \
        --agree-tos \
        "${ARGS[@]}"
}
_run_certbot_docker_renew () {
    _run_certbot_docker renew
}

_usage () {
    cat <<EOUSAGE
Usage: $0 CMD

Commands:
    certonly
    renew
EOUSAGE
    exit 1
}

[ $# -lt 1 ] && _usage
case "$1" in
    renew)        _run_certbot_docker_renew ;;
    certonly)     _run_certbot_docker_certonly ;;
    *)            _usage ;;
esac
  1. Make sure nginx is running (nginx -t && service nginx restart) and that you can reach the web server at the domains above (ex. "http://example.com/"). They don't have to return any content, but they have to respond to HTTP requests.

  2. Create the certificates. Make sure nginx is running using the configuration found above.

# /usr/local/bin/docker-certbot.sh certonly
  1. Install a new nginx site configuration with your new certs.
# file: /etc/nginx/sites-enabled/default.tls
server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    ssl_certificate /etc/letsencrypt/live/EXAMPLE.COM/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/EXAMPLE.COM/privkey.pem;
    
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
    ssl_session_tickets off;

    # Run: curl -s https://ssl-config.mozilla.org/ffdhe2048.txt > /etc/nginx/dhparam
    ssl_dhparam /etc/nginx/dhparam;

    # intermediate configuration
    #ssl_protocols TLSv1.2 TLSv1.3;
    #ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    #ssl_prefer_server_ciphers off;

    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    #add_header Strict-Transport-Security "max-age=63072000" always;

    # OCSP stapling
    #ssl_stapling on;
    #ssl_stapling_verify on;

    # Verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/EXAMPLE.COM/fullchain.pem;

    # replace with the IP address of your resolver
    #resolver 127.0.0.1;
}
  1. Download the dhparam file and restart nginx:
curl -s https://ssl-config.mozilla.org/ffdhe2048.txt > /etc/nginx/dhparam
nginx -t && service nginx restart
  1. Install a cron job to automatically renew the certs via Docker.
( crontab -l ; echo "" ; cat << EOCRON ) | crontab
# Renew Let's Encrypt certs
0 * * * * /etc/nginx/docker-certbot.sh renew --quiet

# Reload Nginx to pick up new certs
# (Alternative command: systemctl reload nginx)
0 */6 * * * service nginx reload
EOCRON
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment