docs: Provision a cert with the ACME DNS-01 challenge via Certbot + Cloudflare (#2968)

* docs: Certbot cloudflare
Add docs for implement certbot-dns-cloudflare to generate certificate for mail server

* Apply suggestions from code review

* fix: certbot-cloudflare docs

Fix the docker-compose command according to the advice

* feat: DNS-Cloudflare certificate renew
Add docs for implementing renewing certificate with crontab

* Apply suggestions from code review

Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
This commit is contained in:
Y.C.Huang 2023-01-07 06:58:50 +08:00 committed by GitHub
parent 1024e0ccf2
commit 88715974eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -158,6 +158,143 @@ Certbot provisions certificates to `/etc/letsencrypt`. Add a volume to store the
Certbot does support [alternative certificate providers via the `--server`][certbot::custom-ca] option. In most cases you'll want to use the default _Let's Encrypt_.
#### Example using `certbot-dns-cloudflare` with Docker { data-toc-label='certbot-dns-cloudflare with Docker' }
If you are unable get a certificate via the `HTTP-01` (port 80) or `TLS-ALPN-01` (port 443) [challenge types](https://letsencrypt.org/docs/challenge-types/), the `DNS-01` challenge can be useful (_this challenge can additionally issue wildcard certificates_). This guide shows how to use the `DNS-01` challenge with Cloudflare as your DNS provider.
Obtain a Cloudflare API token:
1. Login into your Cloudflare dashboard.
2. Navigate to the [API Tokens page](https://dash.cloudflare.com/profile/api-tokens).
3. Click "Create Token", and choose the `Edit zone DNS` template (_Certbot [requires the `ZONE:DNS:Edit` permission](https://certbot-dns-cloudflare.readthedocs.io/en/stable/#credentials)_).
!!! warning "Only include the necessary Zone resource configuration"
Be sure to configure "Zone Resources" section on this page to `Include -> Specific zone -> <your zone here>`.
This restricts the API token to only this zone (domain) which is an important security measure.
4. Store the _API token_ you received in a file `cloudflare.ini` with content:
```dosini
dns_cloudflare_api_token = YOUR_CLOUDFLARE_TOKEN_HERE
```
- As this is sensitive data, you should restrict access to it with `chmod 600` and `chown 0:0`.
- Store the file in a folder if you like, such as `docker-data/certbot/secrets/`.
5. Your `docker-compose.yml` should include the following:
```yaml
services:
mailserver:
environments:
# Set SSL certificate type.
- SSL_TYPE=letsencrypt
volumes:
# Mount the cert folder generated by Certbot into mail-server:
- ./docker-data/certbot/certs/:/etc/letsencrypt/:ro
certbot-cloudflare:
image: certbot/dns-cloudflare:latest
command: certonly --dns-cloudflare --dns-cloudflare-credentials /run/secrets/cloudflare-api-token -d mail.example.com
volumes:
- ./docker-data/certbot/certs/:/etc/letsencrypt/
- ./docker-data/certbot/logs/:/var/log/letsencrypt/
secrets:
- cloudflare-api-token
# Docs: https://docs.docker.com/engine/swarm/secrets/#use-secrets-in-compose
# WARNING: In compose configs without swarm, the long syntax options have no effect,
# Ensure that you properly `chmod 600` and `chown 0:0` the file on disk. Effectively treated as a bind mount.
secrets:
cloudflare-api-token:
file: ./docker-data/certbot/secrets/cloudflare.ini
```
Alternative using the `docker run` command (`secrets` feature is not available):
```sh
docker run \
--volume "${PWD}/docker-data/certbot/certs/:/etc/letsencrypt/" \
--volume "${PWD}/docker-data/certbot/logs/:/var/log/letsencrypt/" \
--volume "${PWD}/docker-data/certbot/secrets/:/tmp/secrets/certbot/"
certbot/dns-cloudflare \
certonly --dns-cloudflare --dns-cloudflare-credentials /tmp/secrets/certbot/cloudflare.ini -d mail.example.com
```
6. Run the service to provision a certificate:
```sh
docker-compose run certbot-cloudflare
```
7. You should see the following log output:
```log
Saving debug log to /var/log/letsencrypt/letsencrypt. log | Requesting a certificate for mail.example.com
Waiting 10 seconds for DNS changes to propagate
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/mail.example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/mail.example.com/privkey.pem
This certificate expires on YYYY-MM-DD.
These files will be updated when the certificate renews.
NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal structions.
```
After completing the steps above, your certificate should be ready to use.
??? tip "Renewing a certificate (Optional)"
We've only demonstrated how to provision a certificate, but it will expire in 90 days and need to be renewed before then.
In the following example, add a new service (`certbot-cloudflare-renew`) into `docker-compose.yml` that will handle certificate renewals:
```yml
services:
certbot-cloudflare-renew:
image: certbot/dns-cloudflare:latest
command: renew --dns-cloudflare --dns-cloudflare-credentials /run/secrets/cloudflare-api-token
volumes:
- ./docker-data/certbot/certs/:/etc/letsencrtypt/
- ./docker-data/certbot/logs/:/var/log/letsencrypt/
secrets:
- cloudflare-api-token
```
You can manually run this service to renew the cert within 90 days:
```sh
docker-compose run certbot-cloudflare-renew
```
You should see the following output
(The following log was generated with `--dry-run` options)
```log
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/mail.example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Account registered.
Simulating renewal of an existing certificate for mail.example.com
Waiting 10 seconds for DNS changes to propagate
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/mail.example.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```
It is recommended to automate this renewal via a task scheduler like a _systemd timer_ or in `crontab`
(`crontab` example: Checks every day if the certificate should be renewed)
```sh
0 0 * * * docker-compose -f PATH_TO_YOUR_DOCKER_COMPOSE_YML up certbot-cloudflare-renew
```
#### Example using `nginx-proxy` and `acme-companion` with Docker { data-toc-label='nginx-proxy with Docker' }
If you are running a web server already, port 80 will be in use which Certbot requires. You could use the [Certbot `--webroot`][certbot::webroot] feature, but it is more common to leverage a _reverse proxy_ that manages the provisioning and renewal of certificates for your services automatically.