Certificates and Cloudflare TLS
The origin gets real Let’s Encrypt certificates via the DNS-01 challenge: Traefik proves control of the domain by writing a TXT record through the Cloudflare API. No inbound port 80 needed.
The Cloudflare token
Section titled “The Cloudflare token”Dashboard → My Profile → API Tokens → Create Token:
- Template Edit zone DNS (Zone · DNS · Edit); add Zone · Zone · Read.
- Zone Resources: include each zone you’ll issue certificates for.
- Client IP Address Filtering: your server’s IP, so the token only works from there.
- Copy it once. Write it on the server without it touching the screen or your shell history:
cd /opt/vps-infra/starterread -rsp 'Cloudflare token: ' T && printf '%s' "$T" > secrets/cf_dns_api_token.txt && unset T; echochmod 600 secrets/cf_dns_api_token.txtcurl -s https://api.cloudflare.com/client/v4/user/tokens/verify \ -H "Authorization: Bearer $(cat secrets/cf_dns_api_token.txt)" | grep -o '"status":"[a-z]*"'Traefik reads it as CF_DNS_API_TOKEN_FILE=/run/secrets/cf_dns_api_token.
Staging first — and why you can’t test it through Cloudflare
Section titled “Staging first — and why you can’t test it through Cloudflare”Cloudflare’s Full (strict) mode requires an origin certificate from a public CA (or Cloudflare’s Origin CA). Let’s Encrypt staging certificates are not publicly trusted, so through Cloudflare they’d show visitors a 526. Test staging on the server itself:
echo | openssl s_client -connect 127.0.0.1:443 -servername whoami.jonathandobson.com 2>/dev/null \ | openssl x509 -noout -issuer -enddate# issuer=… CN=(STAGING) …This also proved the _FILE token setting worked — something the Traefik docs
don’t cover (it comes from its ACME library).
Then production
Section titled “Then production”- Set
ACME_CA_SERVER=https://acme-v02.api.letsencrypt.org/directoryin.env. - Stop Traefik and move the staging store aside — rename, don’t delete:
docker run --rm -v traefik-acme:/data alpine:latest mv /data/acme.json /data/acme.staging.json - Start Traefik; certificates arrive in under a minute.
- Verify the chain is trusted, without
-k:curl -s -o /dev/null -w '%{ssl_verify_result}\n' --resolve <host>:443:127.0.0.1 https://<host>/—0means verified.
The starter’s .env described one wildcard certificate, but nothing actually
requested it: each hostname gets its own certificate. That’s fine — just don’t
expect a wildcard in the store.
Cloudflare SSL mode
Section titled “Cloudflare SSL mode”Set every zone to Full (strict). Cloudflare’s newer Automatic mode is safe — it scans about once a month, raises the mode gradually (starting at 1% of traffic) and never lowers it — but until it reaches Full (strict) the origin certificate isn’t verified. Setting it yourself is immediate.