Use Docker to run the latest versions of Let's Encrypt certbot and the AWS CLI on Debian Stable / Ubuntu LTS
Tags: docker, certbot, aws
Published: 2020-11-29 21:04:20

*My posts are usually notes and reference materials for myself, which I publish here with the hope that others might find them useful.*


Like everyone else, I use Let's Encrypt certbot to obtain TLS certs for my domains.

This post is about using `certbot`, but I also use AWS Route 53 to host my domains, which is nice for [automating certificate renewal with the `certbot-dns-route53` plugin](https://certbot-dns-route53.readthedocs.io/en/stable/). So this post is also about using the AWS CLI, to enable use of that plugin. [Other plugins are available](https://certbot.eff.org/docs/using.html#dns-plugins).

Running the Stable/LTS distributions of Debian/Ubuntu is the only sane approach for a production server. However, the version of `certbot` in Debian 10 (Buster) is stuck at `0.31`, while the latest version (as of 11/2020) is `1.9`; likewise, `aws-cli` is stuck at `1.16` while the latest version is `2.1`. 

Docker containers to the rescue!

[Instructions for installing Docker on Debian.](https://docs.docker.com/engine/install/debian/)

[AWS documentation on using the official AWS CLI Docker image.](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-docker.html)

[Certbot instructions "Running with Docker"](https://certbot.eff.org/docs/install.html#running-with-docker)

# Cliffs Notes

**These instructions assume running as root.**

0: Make sure Docker is working by following the official instructions (linked above) to add the official `apt` repository, install the Docker software, and run `hello-world`.

1: Configure AWS credentials using the AWS CLI Docker image:
   
   ```bash
docker run --rm -it -v "/root/.aws:/root/.aws" amazon/aws-cli configure
   ```

2: Verify AWS credentials are working and have nominal access to Route 53:
   
   ```bash
docker run --rm -it -v "/root/.aws:/root/.aws" amazon/aws-cli route53 list-hosted-zones
   ```

3: Request a Let's Encrypt wildcard certificate using `certbot/dns-route53` Docker image, forwarding AWS credentials:
   
   ```bash
docker run -it --rm --name certbot -v "/usr/bin:/usr/bin" -v "/root/.aws:/root/.aws" -v "/etc/letsencrypt:/etc/letsencrypt" -v "/var/lib/letsencrypt:/var/lib/letsencrypt" certbot/dns-route53 certonly --dns-route53 --domain "example.com" --domain "*.example.com"
   ```

4: Create systemd timer to automate certificate renewal, then `daemon-reload`, `enable`, and `start` the timer.

`/etc/systemd/system/certbot.service`:

(For the docker command, remove `--it` for non-interactive execution by `systemd`, and pass `/usr/bin` to the container to allow execution of `systemctl` by `--deploy-hook`)

```
[Unit]
Description=Let's Encrypt certificate renewal

[Service]
Type=oneshot
ExecStart=docker run --rm --name certbot -v "/usr/bin:/usr/bin" -v "/root/.aws:/root/.aws" -v "/etc/letsencrypt:/etc/letsencrypt" -v "/var/lib/letsencrypt:/var/lib/letsencrypt" certbot/dns-route53 renew --dns-route53 --quiet --agree-tos --deploy-hook "systemctl reload nginx"
```

`/etc/systemd/system/certbot.timer`:

```
[Unit]
Description=Monthly renewal of Let's Encrypt certificates

[Timer]
OnCalendar=monthly
RandomizedDelaySec=12 hours
Persistent=true

[Install]
WantedBy=timers.target
```