Skip to content

Caddy — Reference

  • Website: https://caddyserver.com
  • Docs: https://caddyserver.com/docs
  • API docs: https://caddyserver.com/docs/api
  • Caddyfile directives: https://caddyserver.com/docs/caddyfile/directives
  • reverse_proxy directive: https://caddyserver.com/docs/caddyfile/directives/reverse_proxy
  • GitHub: https://github.com/caddyserver/caddy

Admin API

Caddy exposes an admin API on localhost:2019 (LXC 105 only — not exposed externally). All requests are unauthenticated since the API is localhost-only.

Get current config (JSON)

ssh [email protected] "curl -s localhost:2019/config/" | python3 -m json.tool

Get specific config section

# List all server routes
ssh [email protected] "curl -s localhost:2019/config/apps/http/servers/"

Load a new config

ssh [email protected] "curl -s -X POST localhost:2019/load \
  -H 'Content-Type: text/caddyfile' \
  --data-binary @/etc/caddy/Caddyfile"

Check reverse proxy upstream health

ssh [email protected] "curl -s localhost:2019/reverse_proxy/upstreams" | python3 -c \
  "import json,sys; [print(f'{u[\"address\"]} healthy={u[\"healthy\"]} requests={u[\"num_requests\"]}') for u in json.load(sys.stdin)]"

Stop Caddy gracefully

ssh [email protected] "curl -s -X POST localhost:2019/stop"

CLI

Run from LXC 105 (ssh [email protected]).

# Reload config (zero-downtime)
caddy reload --config /etc/caddy/Caddyfile

# Validate config without applying
caddy validate --config /etc/caddy/Caddyfile

# Format Caddyfile (standardize indentation)
caddy fmt --overwrite /etc/caddy/Caddyfile

# Convert Caddyfile to JSON (useful for API debugging)
caddy adapt --config /etc/caddy/Caddyfile --pretty

# List loaded modules
caddy list-modules

# Version
caddy version

Caddyfile — Common Patterns

Basic reverse proxy

service.eva-00.network {
    reverse_proxy 192.168.1.xxx:PORT
}

With WebSocket support (automatic — no extra config needed)

Caddy automatically proxies WebSocket connections.

With custom headers

service.eva-00.network {
    reverse_proxy 192.168.1.xxx:PORT {
        header_up X-Custom-Header "value"
    }
}

Multiple upstreams (load balancing)

service.eva-00.network {
    reverse_proxy 192.168.1.10:8080 192.168.1.11:8080 {
        lb_policy round_robin
    }
}

What the API/CLI Cannot Do

Gap Workaround
Admin API only accessible from localhost (LXC 105) SSH into LXC 105 first, then curl
No built-in dashboard or status page Check upstream health via /reverse_proxy/upstreams API or Loki logs
Cannot add routes dynamically via API without full JSON config Use caddy reload with Caddyfile — the IaC workflow handles this
No Prometheus metrics endpoint in this deployment Monitor via Loki log queries; Caddy does support metrics via a module but it's not enabled
TLS cert issues are silent until a request fails Check {job="caddy", unit="caddy.service"} \| json \| msg=~".*tls.*" in Loki
Cannot revoke/force-renew a cert via API Delete cert files in /var/lib/caddy/.local/share/caddy/certificates/ and reload