Route Fly proxy through Caddy on indri for direct WireGuard peering
All checks were successful
Deploy Fly.io Proxy / deploy (push) Successful in 1m59s

Tailscale Ingress pods in k8s can't establish direct WireGuard
connections (stuck behind pod-network NAT → DERP relay → 20s latency).
Indri's host-level Tailscale CAN peer directly with Fly.

Change all nginx upstreams to route through Caddy on indri instead of
per-service Tailscale Ingress endpoints. Tag indri as flyio-target in
the Tailscale ACL so the Fly proxy can reach it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erich Blume 2026-04-18 09:40:20 -07:00
commit 12b2786ca2
3 changed files with 30 additions and 34 deletions

View file

@ -54,24 +54,17 @@ http {
websocket upgrade;
}
# --- Upstream pools with keepalive ---
# DNS is resolved once at config load via MagicDNS. If Tailscale Ingress
# pods get new IPs (restart, reschedule), run `mise run fly-reload` to
# re-resolve. A Grafana alert fires when upstreams are unreachable.
# --- Upstream ---
# DNS resolved via Tailscale MagicDNS at config load.
resolver 100.100.100.100 valid=30s;
resolver_timeout 5s;
upstream forge_backend {
server forge.tail8d86e.ts.net:443;
keepalive 8;
}
upstream docs_backend {
server docs.tail8d86e.ts.net:443;
keepalive 4;
}
upstream cv_backend {
server cv.tail8d86e.ts.net:443;
keepalive 4;
# All services route through Caddy on indri. Indri's host-level Tailscale
# can establish direct WireGuard peering, avoiding the DERP relay
# bottleneck that k8s-hosted Tailscale Ingress pods cannot escape.
upstream indri_backend {
server indri.tail8d86e.ts.net:443;
keepalive 16;
}
# --- docs.eblu.me (static site) ---
@ -90,11 +83,11 @@ http {
internal;
}
location / {
proxy_pass https://docs_backend$request_uri;
proxy_pass https://indri_backend$request_uri;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_ssl_name docs.tail8d86e.ts.net;
proxy_set_header Host docs.tail8d86e.ts.net;
proxy_ssl_name docs.ops.eblu.me;
proxy_set_header Host docs.ops.eblu.me;
proxy_intercept_errors on;
proxy_http_version 1.1;
@ -134,11 +127,11 @@ http {
}
location / {
proxy_pass https://cv_backend$request_uri;
proxy_pass https://indri_backend$request_uri;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_ssl_name cv.tail8d86e.ts.net;
proxy_set_header Host cv.tail8d86e.ts.net;
proxy_ssl_name cv.ops.eblu.me;
proxy_set_header Host cv.ops.eblu.me;
proxy_intercept_errors on;
proxy_http_version 1.1;
@ -209,13 +202,13 @@ http {
location ~ ^/user/(login|sign_up|forgot_password) {
limit_req zone=forge_auth burst=5 nodelay;
proxy_pass https://forge_backend$request_uri;
proxy_pass https://indri_backend$request_uri;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_ssl_name forge.tail8d86e.ts.net;
proxy_ssl_name forge.ops.eblu.me;
proxy_intercept_errors on;
proxy_set_header Host $host;
proxy_set_header Host forge.ops.eblu.me;
proxy_set_header X-Real-IP $http_fly_client_ip;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
@ -228,10 +221,10 @@ http {
# Cache release artifact downloads immutable files keyed by tag+filename.
# Avoids hammering Forgejo when crawlers or users re-download the same asset.
location ~ ^/[^/]+/[^/]+/releases/download/ {
proxy_pass https://forge_backend$request_uri;
proxy_pass https://indri_backend$request_uri;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_ssl_name forge.tail8d86e.ts.net;
proxy_ssl_name forge.ops.eblu.me;
proxy_http_version 1.1;
proxy_set_header Connection $connection_upgrade;
@ -240,7 +233,7 @@ http {
proxy_cache_valid 200 7d;
proxy_cache_key $host$uri;
proxy_set_header Host $host;
proxy_set_header Host forge.ops.eblu.me;
proxy_set_header X-Real-IP $http_fly_client_ip;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
@ -251,10 +244,10 @@ http {
# Selectively cache static assets only
location ~* \.(css|js|png|jpg|svg|woff2?)$ {
proxy_pass https://forge_backend$request_uri;
proxy_pass https://indri_backend$request_uri;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_ssl_name forge.tail8d86e.ts.net;
proxy_ssl_name forge.ops.eblu.me;
proxy_http_version 1.1;
proxy_set_header Connection $connection_upgrade;
@ -268,15 +261,15 @@ http {
}
location / {
proxy_pass https://forge_backend$request_uri;
proxy_pass https://indri_backend$request_uri;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_ssl_name forge.tail8d86e.ts.net;
proxy_ssl_name forge.ops.eblu.me;
proxy_intercept_errors on;
# NO proxy_cache dynamic content with sessions
proxy_set_header Host $host;
proxy_set_header Host forge.ops.eblu.me;
proxy_set_header X-Real-IP $http_fly_client_ip;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;