Caddy with Cloudflare DNS-01 and CrowdSec bouncer plugins, built with xcaddy
9.6K
Caddy reverse proxy and web server, custom-built with xcaddy to bundle the Cloudflare DNS-01 plugin and the CrowdSec HTTP bouncer.
Caddy is a modern, automatic-HTTPS reverse proxy and web server. This image rebuilds it from upstream's official builder with two extra plugins so you can:
All of Caddy's standard features work as documented.
Built from the official builder. The binary matches upstream Caddy exactly; plugins are compiled in with xcaddy, the upstream-prescribed mechanism.
Distroless runtime. The final stage is gcr.io/distroless/static: no shell, no package manager, no OS packages to patch or scan. There is no shell to docker exec into, and docker exec can only run the shipped binaries (caddy, /probe); debugging is otherwise via logs, metrics, and the admin API.
Upstream contract preserved. The default Caddyfile, welcome page, MIME map and state directories are copied from the upstream runtime image, so upstream changes to them keep flowing in with ordinary image updates. The XDG_* env that makes /data the certificate store is declared by hand, because COPY moves files and not image ENV metadata.
Multi-arch, built natively. amd64 and arm64 each compile on matching hardware, with no emulation.
Config reload without a restart. Send the running process SIGUSR1
(docker kill -s USR1 caddy) and Caddy reloads from the --config file and
--adapter this image's CMD already records. For a deploy script that needs a
rejected Caddyfile on the caller's own exit status, use
docker exec caddy caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile.
Either way a rejected Caddyfile leaves the previous config running.
Watch mode available, off by default. Upstream documents --watch as a
local-development feature, so the shipped command is upstream's. To opt in, override
the command on your compose service:
command: ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile", "--watch"]
Know what that turns on: one save that fails to ADAPT stops the watcher for the
lifetime of the container, and later valid edits are then ignored with no healthcheck
and no metric reporting it; the watcher logger emits unable to load latest config
once, carrying the adapter error, at the moment it dies. Recovery is a container
restart; an explicit reload applies the current file but does not revive the watcher.
Validate before saving with
docker exec caddy caddy validate --adapter caddyfile --config /etc/caddy/Caddyfile.
Separately, a single-file bind mount pins an inode, so an editor that saves by rename
leaves the container reading the old bytes; save in place, or mount the directory
(./caddy:/etc/caddy). That defeats every reload path, not only the watcher.
docker pull cplieger/docker-caddy:latest
Also published to ghcr.io/cplieger/docker-caddy with identical images and tags. Release versions are tagged vX.Y.Z alongside latest.
# Example compose for docker-caddy. See the README for all configuration options and hardening.
services:
caddy:
image: ghcr.io/cplieger/docker-caddy:latest
container_name: caddy
restart: unless-stopped
environment:
# Set these in a gitignored .env file; never commit live tokens.
CLOUDFLARE_API_TOKEN: "${CLOUDFLARE_API_TOKEN:-}" # used by the DNS-01 plugin
CROWDSEC_BOUNCER_KEY: "${CROWDSEC_BOUNCER_KEY:-}" # used by the CrowdSec bouncer
ports:
- "80:80"
- "443:443"
- "443:443/udp" # HTTP/3
volumes:
- "./caddy:/etc/caddy:ro" # put Caddyfile.example or Caddyfile.plugins.example at ./caddy/Caddyfile; both lock the admin API to loopback
- "./data:/data" # persist issued certs + ACME state
Apache-2.0. See LICENSE. The image carries the license text of every bundled component under /usr/share/licenses/.
The image packages Caddy (Apache-2.0, source at https://github.com/caddyserver/caddy), built with xcaddy from the official caddy:2.11-builder image the Dockerfile pins by digest, together with the caddy-dns/cloudflare and caddy-crowdsec-bouncer plugins (both Apache-2.0) at the versions the Dockerfile's --with flags name. The build applies no patches. One linked module, hslatman/ipstore, publishes no license file and carries the Apache-2.0 header in every source file; the packager supplies its license text under licenses/ in this repository, and it ships in the image beside the others.
Content type
Image
Digest
sha256:b7529c68d…
Size
23 MB
Last updated
about 4 hours ago
docker pull cplieger/docker-caddy