refactor: switch nginx to Caddy with automatic Let's Encrypt
Build Admin / Build image (push) Successful in 13s
Build Admin / Build image (push) Successful in 13s
Nginx required manually managed certs on port 8443; TLS was effectively
unused. Caddy issues and renews certificates for DOMAIN on its own.
- Caddyfile replaces nginx.conf + locations.conf; upstreams are one
`import api <prefix> <host> <path-prefix>` line each
- routes wrapped in `route {}` so guards run before handle_path
- access control (IP allowlist, X-Proxy-Token) generated from env into
matchers.caddy / guard.caddy by the entrypoint, as before
- listeners: 443 (+udp, HTTP/3) and 80 for ACME on DOMAIN, plus the
unchanged plain-HTTP 8082 -> 8080 path for existing clients
- caddy_data volume added: losing it re-issues certs and burns LE limits
- scripts/migrate-host-nginx.sh backs up and retires the host nginx
- deploy.sh points at the real prod layout (/srv/elevenlabs, compose v1)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
15 files changed
+289
-466
No files matched your search
@@ -0,0 +1,70 @@
|
||||
# elevenlabs.io/Caddyfile
|
||||
# Outbound API gateway. Two listeners, one shared route set:
|
||||
# :8080 — plain HTTP (published as 8082 on the host, legacy clients)
|
||||
# {$DOMAIN} — HTTPS 443 with automatic Let's Encrypt certificates
|
||||
{
|
||||
email {$ACME_EMAIL}
|
||||
admin off
|
||||
}
|
||||
|
||||
# --- Access control (generated by docker-entrypoint.sh from env) ---
|
||||
# matchers.caddy: @denied_ip / @bad_token definitions (empty when disabled)
|
||||
# guard.caddy: matching respond directives (empty when disabled)
|
||||
|
||||
# --- Shared upstream request hygiene ---
|
||||
(scrub) {
|
||||
header_up Host {args[0]}
|
||||
header_up -X-Forwarded-For
|
||||
header_up -X-Forwarded-Proto
|
||||
header_up -X-Forwarded-Host
|
||||
header_up -X-Real-IP
|
||||
header_up -True-Client-IP
|
||||
header_up -CF-Connecting-IP
|
||||
header_up -X-Client-IP
|
||||
header_up -Forwarded
|
||||
header_up -Via
|
||||
header_up -X-Proxy-Token
|
||||
}
|
||||
|
||||
# (api) <prefix> <upstream-host> <upstream-path-prefix>
|
||||
(api) {
|
||||
handle_path /{args[0]}/* {
|
||||
rewrite * {args[2]}{uri}
|
||||
reverse_proxy https://{args[1]} {
|
||||
import scrub {args[1]}
|
||||
flush_interval -1
|
||||
transport http {
|
||||
dial_timeout 15s
|
||||
response_header_timeout 300s
|
||||
read_timeout 300s
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(routes) {
|
||||
import /etc/caddy/matchers.caddy
|
||||
|
||||
route {
|
||||
# Health check — no auth, evaluated before the guards
|
||||
respond /health `{"status":"ok","version":"2.0"}` 200
|
||||
|
||||
import /etc/caddy/guard.caddy
|
||||
|
||||
import api elevenlabs api.elevenlabs.io ""
|
||||
import api openai api.openai.com ""
|
||||
import api telegram api.telegram.org ""
|
||||
import api deepseek api.deepseek.com ""
|
||||
import api openrouter openrouter.ai /api/v1
|
||||
|
||||
respond `{"error":"unknown_upstream","hint":"use /elevenlabs/, /openai/, /telegram/, /openrouter/ or /deepseek/"}` 404
|
||||
}
|
||||
}
|
||||
|
||||
{$DOMAIN} {
|
||||
import routes
|
||||
}
|
||||
|
||||
:8080 {
|
||||
import routes
|
||||
}
|
||||
Reference in new issue
Block a user