Agent Installation
The agent is a lightweight service to deploy on each server running a Caddy instance.
How reload works
When a vhost is updated, the agent writes the .caddyfile to SITES_DIR then reloads Caddy using one of two methods:
- Docker socket (preferred): if
/var/run/docker.sockis accessible, the agent runsdocker exec <caddy-container> caddy reload --config <CADDY_CONFIG_PATH>—CADDY_CONFIG_PATHhere is the path inside the Caddy container. - Caddy API fallback: if the socket is not available, the agent POSTs the Caddyfile content to
CADDY_API_URL/load—CADDY_CONFIG_PATHis then read by the agent itself (must be accessible via a volume mount).
Caddy running in Docker
The agent mounts the Docker socket to reload Caddy via docker exec. The sites directory is shared between both containers via a volume.
services:
cadmin-agent:
image: cletus/cadmin-agent:latest
restart: unless-stopped
environment:
AGENT_TOKEN: ${AGENT_TOKEN}
CADDY_API_URL: http://caddy:2019
CADDY_LOG_FILE: /var/log/caddy/access.log
SITES_DIR: /caddy/sites # path inside agent container
CADDY_CONFIG_PATH: /etc/caddy/Caddyfile # path inside Caddy container
ports:
- '3002:3002'
volumes:
- /var/log/caddy:/var/log/caddy:ro
- /opt/caddy/sites:/caddy/sites # host path → agent path
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- caddy
caddy:
image: caddy:2-alpine
volumes:
- /opt/caddy/sites:/etc/caddy/sites # same host path → Caddy path
- /var/log/caddy:/var/log/caddy
networks:
- caddy
networks:
caddy:
external: trueTIP
The host directory (/opt/caddy/sites) is mounted into both containers under different paths. The agent writes files there, and CADDY_CONFIG_PATH is the path Caddy itself sees inside its own container.
Caddy running as a binary (systemd)
Without Docker, the agent uses the Caddy API fallback. The sites directory and Caddyfile must be readable/writable by the agent process.
services:
cadmin-agent:
image: cletus/cadmin-agent:latest
restart: unless-stopped
environment:
AGENT_TOKEN: ${AGENT_TOKEN}
CADDY_API_URL: http://localhost:2019
CADDY_LOG_FILE: /var/log/caddy/access.log
SITES_DIR: /etc/caddy/sites # same as on the host (volume 1:1)
CADDY_CONFIG_PATH: /etc/caddy/Caddyfile # same as on the host (volume 1:1)
ports:
- '3002:3002'
volumes:
- /var/log/caddy:/var/log/caddy:ro
- /etc/caddy/sites:/etc/caddy/sites # host path = container path
- /etc/caddy/Caddyfile:/etc/caddy/Caddyfile
network_mode: host # reach localhost:2019WARNING
network_mode: host is required so the agent can reach the Caddy API on localhost:2019. The Docker socket is not needed in this mode.
Environment Variables
| Variable | Description | Default |
|---|---|---|
AGENT_TOKEN | Bearer token for authentication (required) | — |
CADDY_API_URL | Caddy admin API URL | http://caddy:2019 |
CADDY_LOG_FILE | Path to Caddy access logs (inside container) | /var/log/caddy/access.log |
SITES_DIR | Directory for per-site .caddyfile files (inside agent container) | /etc/caddy/sites |
CADDY_CONFIG_PATH | Path to the main Caddyfile — inside Caddy container when using Docker socket, inside agent container otherwise | /etc/caddy/Caddyfile |
Security
The agent exposes an HTTP port that allows reloading the Caddy configuration. Access must be restricted:
Recommendations
- Firewall: only allow the hub's IP on the agent port (default
3002) - Token: use a long, unique token for each agent
- Network: if possible, place the agent on a private network (VPN, internal network)
Verification
curl http://localhost:3002/healthExpected response:
{ "status": "ok" }The /health endpoint is the only one accessible without authentication.
