{ email admin@filps.com acme_ca https://acme-v02.api.letsencrypt.org/directory } aiops.filps.com { # AI Software Factory — direct backend API surface. # All API routes live here: /api/v1/* (incl. /api/v1/docs + /api/v1/health), # /internal/*, /saml/*, /sso/*, /scim/v2/*. Used by webhook deliveries, # API-key clients, IdP SCIM/ACS and programmatic access — NOT browser- # facing (the browser uses notion.filps.com only, see below). reverse_proxy 127.0.0.1:4000 { header_up Host {host} header_up X-Real-IP {remote_host} # Stream SSE (e.g. /api/v1/ai/... streaming, automation logs). flush_interval -1 } } play.filps.com { @engine path /v1/* /actuator/* reverse_proxy @engine localhost:8080 reverse_proxy localhost:8089 } flydubai.filps.com { reverse_proxy localhost:5173 } play-api.filps.com { reverse_proxy localhost:8080 } intra.filps.com { reverse_proxy 127.0.0.1:18083 { header_up Host {host} header_up X-Real-IP {remote_host} } } notion.filps.com { # ── AI Software Factory — THE app origin ──────────────────────────── # Single-origin topology: the browser talks ONLY to this host (UI + API # + WebSocket + S3 presigned URLs), so the host-scoped httpOnly # `factory_refresh` cookie (no Domain= attr) satisfies the web # middleware's session gate without cross-host cookie sharing. # Every reverse_proxy preserves Host ({host}) so SigV4-signed S3 # requests keep a valid signed host through the proxy. # `handle` blocks are mutually exclusive; they are ordered most- # specific first. # S3 (local shim :9000) — the two bucket prefixes, no path rewrite. # S3_ENDPOINT=https://notion.filps.com (path-style); presigned GET/PUT # URLs + the browser's direct upload XHR are same-origin. The matchers # deliberately omit the trailing slash (`/factory-files*`) so the bare # bucket root (ListObjects / bootstrap's anonymous-access check) also # reaches the shim instead of falling through to the web app. handle /factory-files* { reverse_proxy 127.0.0.1:9000 { header_up Host {host} header_up X-Real-IP {remote_host} } } handle /factory-thumbs* { reverse_proxy 127.0.0.1:9000 { header_up Host {host} header_up X-Real-IP {remote_host} } } # Realtime gateway (WebSocket upgrade at /realtime + SSE). handle /realtime* { reverse_proxy 127.0.0.1:4001 { header_up Host {host} header_up X-Real-IP {remote_host} } } # SAML SSO: /saml/start/:orgSlug, /saml/metadata/:orgSlug, POST /saml/acs. handle /saml/* { reverse_proxy 127.0.0.1:4000 { header_up Host {host} header_up X-Real-IP {remote_host} flush_interval -1 } } # OIDC SSO: /sso/oidc/:orgId/authorize|callback, /sso/start/:orgSlug. handle /sso/* { reverse_proxy 127.0.0.1:4000 { header_up Host {host} header_up X-Real-IP {remote_host} flush_interval -1 } } # Backend API: everything under /api/v1 (incl. /api/v1/docs and # /api/v1/health). (The web app's own /api/v1/health liveness route is # shadowed publicly — container probes hit :3000 directly.) handle /api/v1/* { reverse_proxy 127.0.0.1:4000 { header_up Host {host} header_up X-Real-IP {remote_host} # Stream SSE (AI streaming, long-running exports). flush_interval -1 } } # Everything else → Next.js web app. handle { reverse_proxy 127.0.0.1:3000 { header_up Host {host} header_up X-Real-IP {remote_host} } } } countdown.filps.com { root * /data/coding/flx-website file_server } flxpop.com, www.flxpop.com { root * /data/coding/flx-website file_server } dockhand.filps.com { log { output file /var/log/caddy/dockhand.access.log format json } @allowed remote_ip 13.206.168.181 handle @allowed { reverse_proxy localhost:3000 { header_up X-Real-IP {remote_host} header_up Host {host} } } respond "Forbidden" 403 }