Example certbot docker-compose.yml
for use with Traefik's provider.http
with inline TLS certificates. It will create LetsEncrypt certificates for all Hosts, Traefik will just see them as regular TLS certificate files in dynamic configuration. THIS IS NOT PRODUCTION READY.
version: '3.9'
certbot:
image: certbot/certbot
entrypoint: ["/bin/sh", "-c"]
command:
- |
apk add curl pcre-tools jq
WEBROOT=/webroot
echo WEBROOT $$WEBROOT
mkdir -p $$WEBROOT/.well-known/acme-challenge
echo START WEBSERVER
python -m http.server 80 --directory $$WEBROOT &
/bin/sleep 2
while true; do
echo FETCH DOMAINS
DOMAINS=$$( \
curl --silent --max-time 5 http://user:pass@traefik_traefik:8080/api/http/routers | \
pcregrep -o '(?<=Host\(`).*?(?=`\))' | sort | uniq \
)
echo FETCH DONE
for NAME in $$DOMAINS; do
echo DOMAIN $$NAME
FILE=/.well-known/acme-challenge/traefik-certbot-$$EPOCHREALTIME
touch $$WEBROOT$$FILE
curl --silent --max-time 5 http://$$NAME$$FILE >> /dev/null
ERR=$$?
rm $$WEBROOT$$FILE
if [ $$ERR -eq 0 ]; then
echo DOMAIN CHALLENGE OK, RUN CERTBOT
certbot certonly \
--webroot -w $$WEBROOT \
--non-interactive \
--agree-tos \
--no-eff-email \
--keep-until-expiring \
-m email@example.com \
--quiet \
--cert-name $$NAME \
-d $$NAME
if [ $$? -eq 0 ]; then
echo CERTBOT OK $$NAME
else
echo CERTBOT FAILED $$NAME
fi
else
echo DOMAIN CHALLENGE FAILED http://$$NAME$$FILE
fi
done
echo TRAEFIK TLS FILE GENERATION
FILE=$$WEBROOT/traefik-certbot.yml
printf "tls:\n options:\n default:\n minVersion: VersionTLS12\n certificates:\n" > $$FILE
for NAME in $$(find /etc/letsencrypt/live/ -maxdepth 1 -mindepth 1 -type d -print) ; do
echo TRAEFIK TLS FILE ADD $$NAME
printf " # CERT FILE $$NAME\n" >> $$FILE
printf " - certFile: |-\n" >> $$FILE
sed -e 's/^/ /' $$NAME/fullchain.pem >> $$FILE
printf " keyFile: |-\n" >> $$FILE
sed -e 's/^/ /' $$NAME/privkey.pem >> $$FILE
done
#echo TREAFIK TLS FILE CONTENT
#cat $$WEBROOT/traefik-certbot.yml
echo SLEEP
/bin/sleep 15
done
hostname: '{{.Node.Hostname}}'
networks:
- proxy
volumes:
- traefik-certificates:/etc/letsencrypt
deploy:
replicas: 1 # only single instance
placement:
constraints:
- node.role==manager # for service discovery
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.certbot.entrypoints=web'
- 'traefik.http.routers.certbot.rule=PathPrefix(`/.well-known/acme-challenge`)'
- 'traefik.http.routers.certbot.priority=1024'
- 'traefik.http.services.certbot.loadbalancer.server.port=80'
Pieces of the Traefik static configuration:
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
swarmMode: true
exposedByDefault: false
network: proxy
# for dashboard
file:
filename: /traefik-dynamic.yml
watch: true
# for LetsEncrypt certificates from certbot
http:
endpoint: "http://traefik_certbot/traefik-certbot.yml"
pollInterval: 15s
pollTimeout: 5s
entryPoints:
web:
address: :80
http:
redirections:
entryPoint:
to: websecure
scheme: https
priority: 1000 # needed for certbot to be able to overrule
websecure:
...
It's probably better to use a shared folder across all Traefik nodes and write the dynamic config file into the folder and use Traefik with watching provider.file
instead. Then you could just copy and reference the certificates instead of inlining them. Be aware that the host folder needs to exist when running with Docker Swarm.