diff --git a/fly/nginx.conf b/fly/nginx.conf index 5723722..ceafbdd 100644 --- a/fly/nginx.conf +++ b/fly/nginx.conf @@ -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; diff --git a/pulumi/tailscale/__main__.py b/pulumi/tailscale/__main__.py index 2bbecfd..2f5262b 100644 --- a/pulumi/tailscale/__main__.py +++ b/pulumi/tailscale/__main__.py @@ -50,6 +50,7 @@ indri_tags = tailscale.DeviceTags( "tag:loki", "tag:registry", # Zot container registry "tag:k8s-api", # Kubernetes API server (minikube) + "tag:flyio-target", # Fly proxy routes through Caddy on indri ], ) diff --git a/pulumi/tailscale/policy.hujson b/pulumi/tailscale/policy.hujson index e6ddb85..84f1f17 100644 --- a/pulumi/tailscale/policy.hujson +++ b/pulumi/tailscale/policy.hujson @@ -193,11 +193,13 @@ "src": "tag:ci-gateway", "accept": ["tag:registry:443"], }, - // Fly.io proxy can only reach flyio-target tagged endpoints, nothing else + // Fly.io proxy can only reach flyio-target tagged endpoints, nothing else. + // indri has tag:flyio-target (Caddy) so tag:homelab:443 is reachable on + // indri specifically but not other homelab devices. { "src": "tag:flyio-proxy", "accept": ["tag:flyio-target:443"], - "deny": ["tag:k8s:443", "tag:homelab:443", "tag:homelab:22", "tag:nas:445", "tag:registry:443"], + "deny": ["tag:k8s:443", "tag:homelab:22", "tag:nas:445", "tag:registry:443"], }, ], }