4.7 KiB
Caddy
Docker deployment for Caddy with the Cloudflare DNS module. Run all commands from the repository root.
Appdata Location
Create appdata/ in the project root, not inside docker-compose-files/:
homelab-blueprint/
|-- appdata/
| `-- caddy/
| |-- config/
| `-- data/
|-- docker-compose-files/
`-- docker-compose.caddy.yml
The relative volume paths in the generated Compose file resolve from the project root.
Installation
-
Create
.envif it does not exist:cp -n .env.sample .env -
Set the required values in
.env:TZ=Africa/Johannesburg CADDY_TLS_EMAIL=admin@example.com CADDY_BASE_DOMAIN=home.example.com CLOUDFLARE_DNS_TOKEN=<restricted-cloudflare-api-token> CADDY_LAN_PREFIX=10.0.1 CADDY_OFFICE_PREFIX=10.0.10 CADDY_IOT_PREFIX=10.0.30 DNS_BIND_IP=10.0.10.5 CADDY_MEM_LIMIT=256m DOCKERLOGGING_MAXFILE=3 DOCKERLOGGING_MAXSIZE=10mThe Cloudflare token needs zone read and DNS edit permissions.
-
Create appdata and render the templates:
mkdir -p appdata/caddy/data appdata/caddy/config ./substitute_env.sh docker-compose-files/caddy/Caddyfile_template docker-compose-files/caddy/Caddyfile .env ./substitute_env.sh docker-compose-files/caddy/template.yaml docker-compose.caddy.yml .envEdit
Caddyfile_template, not the generatedCaddyfile.docker-compose.caddy.ymlcontains the rendered token and is ignored by Git. -
Validate and start Caddy:
docker compose -f docker-compose.caddy.yml config --quiet docker compose -f docker-compose.caddy.yml build docker compose -f docker-compose.caddy.yml run --rm caddy caddy validate --config /etc/caddy/Caddyfile docker compose -f docker-compose.caddy.yml up -d -
Verify the container:
docker compose -f docker-compose.caddy.yml ps docker compose -f docker-compose.caddy.yml logs --tail=100 caddy
Apply Configuration Changes
After changing .env or template.yaml, render the Compose file and recreate
the container:
./substitute_env.sh docker-compose-files/caddy/template.yaml docker-compose.caddy.yml .env
docker compose -f docker-compose.caddy.yml config --quiet
docker compose -f docker-compose.caddy.yml up -d --build
After changing Caddyfile_template, render, validate, and reload it:
./substitute_env.sh docker-compose-files/caddy/Caddyfile_template docker-compose-files/caddy/Caddyfile .env
docker compose -f docker-compose.caddy.yml exec caddy caddy validate --config /etc/caddy/Caddyfile
docker compose -f docker-compose.caddy.yml exec caddy caddy reload --config /etc/caddy/Caddyfile
Initial Setup
In your internal DNS server:
- Add an
Arecord namedcaddypointing to the Caddy host at10.0.15.5. - Add a wildcard
CNAMEnamed*pointing tocaddy.home.example.com.
Replace home.example.com with CADDY_BASE_DOMAIN.
Network Requirements
- Caddy uses host networking and listens on ports
80and443. - Allow Caddy to reach every upstream IP and port in
Caddyfile_template. - Allow outbound DNS and HTTPS for Cloudflare DNS-01 certificate issuance.
- Exclude the Caddy host from DNS redirection so it can query public resolvers.
- The admin API listens only on
localhost:2019.
Troubleshooting
Validate the generated Caddyfile and inspect container logs:
docker compose -f docker-compose.caddy.yml run --rm caddy caddy validate --config /etc/caddy/Caddyfile
docker compose -f docker-compose.caddy.yml logs --tail=100 caddy
If certificate issuance fails, confirm the Cloudflare token permissions and ensure Caddy's public DNS queries are not redirected to internal DNS.
Raspberry Pi OS Memory Limits
If Docker reports the following warning, Caddy still starts, but Docker ignores
CADDY_MEM_LIMIT:
Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.
Enable memory cgroups by appending these parameters to the existing single line
in /boot/firmware/cmdline.txt:
cgroup_enable=memory cgroup_memory=1
Older Raspberry Pi OS releases may use /boot/cmdline.txt. Do not add a new
line to either file. Reboot and verify:
sudo reboot
docker info | grep -i warning
docker stats --no-stream caddy
Useful Commands
# Confirm the Cloudflare module is installed
docker compose -f docker-compose.caddy.yml exec caddy caddy list-modules | grep dns.providers.cloudflare
# Rebuild after image or Dockerfile updates
docker compose -f docker-compose.caddy.yml build --pull --no-cache
docker compose -f docker-compose.caddy.yml up -d
Backup
Back up appdata/caddy/data and appdata/caddy/config. The data directory
contains certificates and ACME state.