Journey info · Platform: Docker Compose / Cloudflare · Time: ~30 minutes
This journey puts a Canasta wiki on Docker Compose behind Cloudflare, with Cloudflare proxying the hostname and connecting to the origin in Full (strict) mode, so traffic is encrypted and the origin certificate validated end to end. The host's HAProxy edge terminates TLS at the origin and obtains its Let's Encrypt certificate by DNS validation through a Cloudflare API token, so issuance and renewal do not depend on Cloudflare passing HTTP challenges through to the origin. The edge also recovers each visitor's address from Cloudflare's header, so its rate limits and deny lists apply to visitors rather than to Cloudflare. It complements the reference pages Help:HAProxy edge and Help:Using Canasta with Cloudflare.
The examples use the zone example.com, the wiki hostname wiki.example.com, the instance ID mywiki and the host address 192.0.2.10. Substitute your own.
Prerequisites
- A Linux host with Docker and the Canasta CLI installed (see Help:Installation), with ports 80 and 443 free, or already served by the host's edge.
- A domain whose DNS is hosted on Cloudflare (here, the zone
example.com). - Permission in the Cloudflare account to create API tokens and change the zone's DNS and SSL/TLS settings.
- For an existing instance instead of a new one: a Docker Compose instance on the host.
Phase 1: Create the Cloudflare API token
The edge uses the token to create and remove the temporary _acme-challenge TXT records that prove control of the hostname to Let's Encrypt.
- In the Cloudflare dashboard, open My Profile → API Tokens and choose Create Token.
- Start from the Edit zone DNS template, or create a custom token with these permissions:
- Zone → DNS → Edit
- Zone → Zone → Read
- Under Zone Resources, include only the specific zone
example.com. - Create the token and copy it. Cloudflare shows it once.
Then copy the zone's Zone ID from the API section of the zone's Overview page. With the zone ID set, the edge keeps this token with this instance's certificates, so other instances on the host can use different tokens.
Treat the token as a password: anyone holding it can change the zone's DNS records.
Phase 2: Point DNS at the host
In the zone's DNS → Records, add a record for the wiki hostname, proxied (orange cloud):
| Type | Name | Content | Proxy status |
|---|---|---|---|
A |
wiki |
192.0.2.10 |
Proxied |
Add an AAAA record as well if the host has an IPv6 address.
Leave the zone's SSL/TLS encryption mode alone for now. Until Let's Encrypt has issued the origin certificate (Phase 4), the edge serves a certificate from its own CA, which Full (strict) rejects.
Phase 3: Configure the instance
New instance
Create an env file, cloudflare.env, readable only by you:
TLS_MODE=acme-dns
ACME_DNS_PROVIDER=cloudflare
CLOUDFLARE_API_TOKEN=<token from Phase 1>
CLOUDFLARE_ZONE_ID=<zone ID from Phase 1>
TRUSTED_PROXIES=cloudflare
chmod 600 cloudflare.env
canasta create -i mywiki -w main -n wiki.example.com -e cloudflare.env
Every Compose instance is served by the edge, and the first one on the host starts it. The settings are copied into the instance's .env; delete cloudflare.env afterwards.
TLS_MODE=acme-dnshas the edge obtain Let's Encrypt certificates by DNS validation.CLOUDFLARE_API_TOKENandCLOUDFLARE_ZONE_IDare the credentials from Phase 1.TRUSTED_PROXIES=cloudflarehas the edge (and Caddy) take the visitor's address fromCF-Connecting-IP, on connections from Cloudflare's address ranges only.
Existing instance
For an existing instance:
canasta config set -i mywiki \
CLOUDFLARE_API_TOKEN=<token> CLOUDFLARE_ZONE_ID=<zone ID> \
TLS_MODE=acme-dns TRUSTED_PROXIES=cloudflare
The command restarts the instance, and the edge replaces its certificates with ones obtained by DNS validation. The token appears in your shell history; clear it from there afterwards.
Phase 4: Confirm the certificate, then switch to Full (strict)
Check that the edge holds a production Let's Encrypt certificate for the hostname:
canasta doctor -i mywiki
The HAProxy edge section should show:
HAProxy edge (mywiki): edge: running (...) member: yes acme.sh: running (...) wiki.example.com: Let's Encrypt production, renews ...
If the hostname instead shows "no Let's Encrypt certificate yet", see Troubleshooting before going on.
Then, in the Cloudflare dashboard, set SSL/TLS → Overview to Full (strict). Leave Always Use HTTPS on or off as you prefer: the edge redirects HTTP to HTTPS itself.
Phase 5: Lock the origin to Cloudflare
With DNS validation, nothing outside Cloudflare needs to reach the host on 80 or 443. In your provider's firewall or security group, allow inbound 80/TCP and 443/TCP only from Cloudflare's published address ranges, and 22/TCP from the addresses you administer from. Use the provider's firewall rather than ufw or firewalld: ports Docker publishes bypass host firewall rules (see Host firewall).
Phase 6: Validation
Cloudflare reaches the origin in Full (strict): from any machine,
curl -sI https://wiki.example.com/ | head -1
Expect HTTP/2 200 or a redirect to the main page, not 526 or 525.
The origin serves a publicly trusted certificate: on the host, bypassing Cloudflare,
curl -sI --resolve wiki.example.com:443:127.0.0.1 https://wiki.example.com/ | head -1
Expect a 200 or a redirect. A certificate error means the edge is still serving its own CA's certificate. canasta doctor -i mywiki also checks this, in its Origin TLS section.
The edge sees the visitor's address: load the wiki in a browser, then on the host:
docker logs --tail 20 canasta-edge
Your request's line shows your own public address, not one of Cloudflare's.
Cleanup / teardown
Delete the instance. If it was the last instance on the host, the edge stops too:
canasta delete -i mywiki -y
Then:
- In Cloudflare, delete the API token (My Profile → API Tokens), then the wiki's DNS record.
- If you changed the zone's SSL/TLS mode only for this wiki, set it back.
- Remove the firewall rules from Phase 5.
- Optionally, once no Compose instance remains on the host, remove the edge's directory, which holds its Let's Encrypt account, certificates and CA:
/etc/canasta/edgeif you runcanastaas root, otherwise~/.config/canasta/edge. A later instance creates a new one.
Production considerations
- Token scope. Restrict the token to the one zone, and add Cloudflare's client IP filtering for the token if the host's address is fixed.
- Several instances on one host can each use a different token, as long as every
acme-dnsinstance on the host setsCLOUDFLARE_ZONE_ID. The edge refuses a configuration where instances with different tokens leave it unset. - Every hostname in the zone. Each wiki, media hostname and
Caddyfile.globalsite of the instance gets its own certificate by DNS validation, so each needs to be in a zone the token can edit. - Rate limits. With
TRUSTED_PROXIES=cloudflareset, each visitor has its own allowance. TuneCANASTA_EDGE_RATE_DYNAMICandCANASTA_EDGE_RATE_DEFAULTas described in Rate limits and connection caps. - A Cloudflare Origin CA certificate is an alternative to Let's Encrypt in Full (strict): place the certificate and key in the instance's
config/certs/and setTLS_MODE=custom(see Certificates). It is trusted only by Cloudflare, so the origin can no longer be served without Cloudflare in front. - Testing. On a hostname you create and delete repeatedly, add
CANASTA_STAGING_CERTS=trueto the env file to avoid Let's Encrypt's rate limits, and use Full rather than Full (strict), since staging certificates are not publicly trusted. - Gitops. On a gitops instance,
CLOUDFLARE_API_TOKENis stored encrypted with the other secrets, andTLS_MODE,TRUSTED_PROXIESandCLOUDFLARE_ZONE_IDcan differ per host.
Troubleshooting
canasta doctorsays "no Let's Encrypt certificate yet". The start that tried printed Let's Encrypt's reason in a message beginning "Let's Encrypt did not issue a certificate for wiki.example.com". The usual causes are a token without DNS → Edit on the zone, or aCLOUDFLARE_ZONE_IDfor a different zone. Fix the setting withcanasta config set, which restarts the instance and retries.- 526 (Invalid SSL certificate). Cloudflare is in Full (strict) and the edge serves a certificate Cloudflare does not trust: its own CA's, while Let's Encrypt has not issued yet, or a staging certificate. Set Full until
canasta doctorshows a production certificate. - 525 (SSL handshake failed). Cloudflare cannot complete TLS with the origin. Check that port 443 is open to Cloudflare's ranges, and that the edge is running (
canasta doctor -i mywiki). - Redirect loop. The zone's SSL/TLS mode is Flexible, which connects to the origin over HTTP, and the edge redirects every HTTP request to HTTPS. Use Full (strict). Flexible works only with the instance served over plain HTTP; see Behind a CDN.
- "use acme-dns with different Cloudflare tokens". Another
acme-dnsinstance on the host uses a different token and one of them has noCLOUDFLARE_ZONE_ID. Set it on each. - Visitors get 429, or the edge log shows Cloudflare addresses.
TRUSTED_PROXIES=cloudflareis not set on the instance, so the edge counts every visitor arriving through one Cloudflare address together. Set it.