WikifitaGitHub live67e8de5
projeto · infraestrutura/fitalabs-gateway-caddy

FitaLabs Gateway — Caddy Configuration

Documentation: FitaLabs Gateway — Caddy Configuration

Baixar raw

FitaLabs Gateway — Caddy Configuration

Reverse proxy with automatic TLS (Let's Encrypt), serving 8 subdomains.

Subdomains

DomainFunctionBackend
unifita.appLanding page/var/www/index.html
claude.unifita.app1P SPA bundle/var/www/claude/ + CDN fallback
api.unifita.appAPI Gatewaygateway:4000
gateway.unifita.appAdmin UIgateway:4000/ui (redirect)
docs.unifita.appDocusaurus/var/www/docs/
get.unifita.appDMG downloads/var/www/get/
search.unifita.appSearXNGsearxng:8080
status.unifita.appUptime Kumauptime-kuma:3001

claude.unifita.app — Bundle 1P

claude.unifita.app {
    root * /var/www/claude
    encode gzip

    # API → gateway (with auth injection)
    @api {
        path /api/* /v1/* /mcp /bootstrap /account_profile /edge-api/* /accounts/* /auth/*
    }
    reverse_proxy @api gateway:4000 {
        header_up Authorization "Bearer sk-gateway-local"
        header_up anthropic-version "2023-06-01"
    }

    # SPA fallback: client-side routes → index.html
    # Only for navigation (Accept: text/html), not for JS imports
    @spa {
        not file
        not path /api/* /v1/* /mcp /bootstrap /account_profile /edge-api/* /auth/* /i18n/* /claude_code/*
        header Accept *text/html*
    }
    rewrite @spa /index.html

    file_server

    # CDN fallback: missing chunks → Anthropic CDN
    handle_errors 404 {
        rewrite * /claude-ai/v2/assets/v1{uri}
        reverse_proxy https://assets-proxy.anthropic.com
    }
}

Why auth in Caddy and not Service Worker?

  • SW has caching issues (old versions persist)
  • SW doesn't work in private/incognito until reload
  • Caddy header_up is server-side, reliable, first request already authenticated
  • Simpler debugging: docker exec caddy wget vs DevTools SW

Why SPA fallback only with Accept: text/html?

  • Browser navigation sends Accept: text/html → serves index.html ✅
  • Dynamic import (import("/logout")) does NOT send Accept: text/html → 404 ✅
  • Without this distinction, JS imports received HTML → 'text/html' is not a valid JavaScript MIME type

CDN fallback with handle_errors 404

  • Local files: served by file_server
  • Missing chunks: Caddy returns 404 → handle_errors catches → proxy to CDN
  • Browser receives chunk as if it were local
  • Frequently used chunks end up in browser cache

gateway.unifita.app — Admin UI

gateway.unifita.app {
    # Swagger/OpenAPI docs
    handle_path /swagger* {
        rewrite * /docs{path}
        reverse_proxy gateway:4000
    }
    # Root → admin UI
    redir / /ui
    reverse_proxy gateway:4000
}

api.unifita.app — API Gateway

api.unifita.app {
    reverse_proxy gateway:4000
}

No auth injection — the client (Claude Desktop/Code) sends its own x-api-key or Authorization.

TLS

All subdomains use Let's Encrypt via tls me@aleffita.dev. Caddy renews automatically.

References