Tools: Caddy Has a Free API You've Never Heard Of (2026)
What Makes Caddy Special?
The Hidden API: Dynamic Configuration
PKI API — Certificate Management
Caddyfile — The Simple API
Quick Start
Why DevOps Choose Caddy Caddy is a web server with automatic HTTPS. Unlike Nginx, it handles TLS certificates automatically and has a powerful REST API for dynamic configuration — no restarts needed. Caddy exposes a full REST API for live configuration: A DevOps engineer shared: "We replaced our Nginx + certbot + cron setup (5 config files, a renewal script, and monthly cert failures) with a 12-line Caddyfile. Zero cert issues in 2 years. The admin API lets us add backends dynamically during blue-green deploys." Need infrastructure automation? Email [email protected] or check my tools. Nginx or Caddy? What's your web server of choice? Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse
# Get current config
-weight: 500;">curl localhost:2019/config/ | jq . # Add a new site dynamically — no -weight: 500;">restart!
-weight: 500;">curl -X POST localhost:2019/config/apps/http/servers/srv0/routes \ -H 'Content-Type: application/json' \ -d '{ "match": [{"host": ["api.example.com"]}], "handle": [{ "handler": "reverse_proxy", "upstreams": [{"dial": "localhost:3000"}] }] }' # Update upstream without downtime
-weight: 500;">curl -X PATCH localhost:2019/config/apps/http/servers/srv0/routes/0/handle/0/upstreams \ -H 'Content-Type: application/json' \ -d '[{"dial": "localhost:3001"}, {"dial": "localhost:3002"}]' # Delete a route
-weight: 500;">curl -X DELETE localhost:2019/config/apps/http/servers/srv0/routes/0
# Get current config
-weight: 500;">curl localhost:2019/config/ | jq . # Add a new site dynamically — no -weight: 500;">restart!
-weight: 500;">curl -X POST localhost:2019/config/apps/http/servers/srv0/routes \ -H 'Content-Type: application/json' \ -d '{ "match": [{"host": ["api.example.com"]}], "handle": [{ "handler": "reverse_proxy", "upstreams": [{"dial": "localhost:3000"}] }] }' # Update upstream without downtime
-weight: 500;">curl -X PATCH localhost:2019/config/apps/http/servers/srv0/routes/0/handle/0/upstreams \ -H 'Content-Type: application/json' \ -d '[{"dial": "localhost:3001"}, {"dial": "localhost:3002"}]' # Delete a route
-weight: 500;">curl -X DELETE localhost:2019/config/apps/http/servers/srv0/routes/0
# Get current config
-weight: 500;">curl localhost:2019/config/ | jq . # Add a new site dynamically — no -weight: 500;">restart!
-weight: 500;">curl -X POST localhost:2019/config/apps/http/servers/srv0/routes \ -H 'Content-Type: application/json' \ -d '{ "match": [{"host": ["api.example.com"]}], "handle": [{ "handler": "reverse_proxy", "upstreams": [{"dial": "localhost:3000"}] }] }' # Update upstream without downtime
-weight: 500;">curl -X PATCH localhost:2019/config/apps/http/servers/srv0/routes/0/handle/0/upstreams \ -H 'Content-Type: application/json' \ -d '[{"dial": "localhost:3001"}, {"dial": "localhost:3002"}]' # Delete a route
-weight: 500;">curl -X DELETE localhost:2019/config/apps/http/servers/srv0/routes/0
# Issue certificates on demand
-weight: 500;">curl -X POST localhost:2019/pki/ca/local/certificates \ -H 'Content-Type: application/json' \ -d '{"subject": {"common_name": "internal.dev"}}' # List managed certificates
-weight: 500;">curl localhost:2019/pki/ca/local/certificates | jq .
# Issue certificates on demand
-weight: 500;">curl -X POST localhost:2019/pki/ca/local/certificates \ -H 'Content-Type: application/json' \ -d '{"subject": {"common_name": "internal.dev"}}' # List managed certificates
-weight: 500;">curl localhost:2019/pki/ca/local/certificates | jq .
# Issue certificates on demand
-weight: 500;">curl -X POST localhost:2019/pki/ca/local/certificates \ -H 'Content-Type: application/json' \ -d '{"subject": {"common_name": "internal.dev"}}' # List managed certificates
-weight: 500;">curl localhost:2019/pki/ca/local/certificates | jq .
# Caddyfile — entire config in ~10 lines
api.example.com { reverse_proxy localhost:3000 encode gzip log { output file /var/log/caddy/api.log }
} app.example.com { root * /var/www/app file_server try_files {path} /index.html
} *.example.com { tls { dns cloudflare {env.CF_TOKEN} } respond "Wildcard works!"
}
# Caddyfile — entire config in ~10 lines
api.example.com { reverse_proxy localhost:3000 encode gzip log { output file /var/log/caddy/api.log }
} app.example.com { root * /var/www/app file_server try_files {path} /index.html
} *.example.com { tls { dns cloudflare {env.CF_TOKEN} } respond "Wildcard works!"
}
# Caddyfile — entire config in ~10 lines
api.example.com { reverse_proxy localhost:3000 encode gzip log { output file /var/log/caddy/api.log }
} app.example.com { root * /var/www/app file_server try_files {path} /index.html
} *.example.com { tls { dns cloudflare {env.CF_TOKEN} } respond "Wildcard works!"
}
-weight: 500;">brew -weight: 500;">install caddy
caddy reverse-proxy --from :443 --to :3000
# That's it — HTTPS is automatic
-weight: 500;">brew -weight: 500;">install caddy
caddy reverse-proxy --from :443 --to :3000
# That's it — HTTPS is automatic
-weight: 500;">brew -weight: 500;">install caddy
caddy reverse-proxy --from :443 --to :3000
# That's it — HTTPS is automatic - Automatic HTTPS — Let's Encrypt certificates out of the box
- REST API — modify configuration without restarts
- Caddyfile — human-readable config format
- Zero-downtime config — hot-reload via API
- Single binary — no dependencies