867180f4bf
Configura il gateway Caddy per il deploy su cerbero-mcp.tielogic.xyz: - Build custom Caddy con plugin mholt/caddy-ratelimit (Dockerfile + build via xcaddy). - TLS automatico via Let's Encrypt (richiede DNS A record + porte 80/443 raggiungibili), HSTS preload, header di sicurezza. - Rate limit per IP (60 req/min sui read, 10 req/min sui write, sliding window). - Allowlist IP sui write endpoint (place_*, cancel_*, set_*, close_*, transfer_*, amend_*, switch_*): IP non in WRITE_ALLOWLIST → 403. - Default WRITE_ALLOWLIST copre loopback + Docker bridge: bot sulla stessa macchina (host o container) funziona senza configurazione, IP pubblici esterni vanno aggiunti esplicitamente. - Smoke test e README aggiornati per il nuovo URL gateway. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
80 lines
1.8 KiB
Caddyfile
80 lines
1.8 KiB
Caddyfile
{
|
|
admin off
|
|
email {$ACME_EMAIL:adrianodalpastro@tielogic.com}
|
|
|
|
# Plugin mholt/caddy-ratelimit
|
|
order rate_limit before basicauth
|
|
}
|
|
|
|
cerbero-mcp.tielogic.xyz {
|
|
log {
|
|
output stdout
|
|
format json
|
|
}
|
|
|
|
# ───── Security headers ─────
|
|
header {
|
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
|
X-Content-Type-Options "nosniff"
|
|
X-Frame-Options "DENY"
|
|
Referrer-Policy "no-referrer"
|
|
-Server
|
|
}
|
|
|
|
# ───── IP allowlist su endpoint write ─────
|
|
# WRITE_ALLOWLIST: CIDR space-separated (es. "1.2.3.4/32 5.6.7.0/24").
|
|
# Default 127.0.0.1/32 — fail-closed se non configurato.
|
|
@writes_blocked {
|
|
path_regexp ^/mcp-[a-z]+/tools/(place_|cancel_|set_|close_|transfer_|amend_|switch_)
|
|
not remote_ip {$WRITE_ALLOWLIST:127.0.0.1/32 ::1/128 172.16.0.0/12}
|
|
}
|
|
respond @writes_blocked "forbidden: source ip not in allowlist" 403
|
|
|
|
# ───── Rate limit ─────
|
|
# Reads: 60 req/min/IP, writes: 10 req/min/IP (sliding window).
|
|
rate_limit {
|
|
zone reads {
|
|
match {
|
|
not path_regexp ^/mcp-[a-z]+/tools/(place_|cancel_|set_|close_|transfer_|amend_|switch_)
|
|
}
|
|
key {remote_ip}
|
|
events 60
|
|
window 1m
|
|
}
|
|
zone writes {
|
|
match {
|
|
path_regexp ^/mcp-[a-z]+/tools/(place_|cancel_|set_|close_|transfer_|amend_|switch_)
|
|
}
|
|
key {remote_ip}
|
|
events 10
|
|
window 1m
|
|
}
|
|
}
|
|
|
|
# ───── Reverse proxy ─────
|
|
handle_path /mcp-deribit/* {
|
|
reverse_proxy mcp-deribit:9011
|
|
}
|
|
handle_path /mcp-bybit/* {
|
|
reverse_proxy mcp-bybit:9019
|
|
}
|
|
handle_path /mcp-hyperliquid/* {
|
|
reverse_proxy mcp-hyperliquid:9012
|
|
}
|
|
handle_path /mcp-alpaca/* {
|
|
reverse_proxy mcp-alpaca:9020
|
|
}
|
|
handle_path /mcp-macro/* {
|
|
reverse_proxy mcp-macro:9013
|
|
}
|
|
handle_path /mcp-sentiment/* {
|
|
reverse_proxy mcp-sentiment:9014
|
|
}
|
|
|
|
# Landing page statica
|
|
handle {
|
|
root * /srv
|
|
file_server
|
|
}
|
|
}
|