Skip to main content

Networking

The UI has two authenticated public paths and a separate private Tailscale ingress. API and database Services stay inside the cluster; browser workers make outbound requests to ESPN.

Find services and ports​

All application resources use default unless specified otherwise.

ServiceTypePortExposure and use
fantasy-web-uiClusterIP (pinned)80/TCPUI and same-origin /v1/* proxy; reached through the access paths above
oauth2-proxyNodePort4180/TCP; node port 30292External reverse proxy routes public UI traffic here
fantasy-core-pipelineClusterIP8000/TCPInternal API; public UI requests reach it through UI nginx
fantasy-dbHeadless5432/TCPPostgreSQL/TimescaleDB, internal only
fantasy-cacheClusterIP6379/TCPInternal cache
fantasy-brokerClusterIP5672 and 15672/TCPInternal AMQP; management HTTP also has private Tailscale ingress

Shared telemetry endpoints (Prometheus, Loki, Grafana and Tempo) and shared model services are owned by the cluster repository. There is no application API ingress directly exposing port 8000.

Internal is a routing boundary

This repository defines no NetworkPolicies. ClusterIP and headless Services do not enforce isolation between cluster workloads. Restrict node port access to the intended reverse proxy at the cluster/network boundary.

Understand each access path​

PathAuthentication boundaryOwner
Cloudflare Tunnel → UICloudflare Access policy at the edge; bypasses oauth2-proxyCluster repository and Cloudflare configuration
Reverse proxy → oauth2-proxy → UIGoogle OIDC, approved-email file and secure cookieExternal proxy/TLS in cluster repo; OAuth proxy in this repo
Tailscale ingress → UITailnet membership and access policyIngress in this repo; shared Tailscale operator
Tailscale ingress → broker managementTailnet policy plus RabbitMQ loginIngress in this repo; shared Tailscale operator

oauth2-proxy fronts both the SPA and its proxied API. Keep its redirect URI, cookie domain, OAuth provider registration and public DNS aligned. Its --reverse-proxy setting trusts forwarded protocol headers from the upstream proxy that terminates TLS.

The redirect URI, cookie domain and approved-email file come from a required Secret managed by External Secrets Operator. Provision them using private deployment values. OAuth admission uses the file allow-list alone; --email-domain would also admit every account in that domain.

The tunnel connects directly to a pinned UI ClusterIP because its host-network deployment uses node DNS, not cluster DNS. Coordinate any UI Service address change with the tunnel route. Public domain examples should use ui.example.com and draft.example.com; tailnet examples should use <private-ui>.<tailnet>.ts.net.

Trace DNS ownership​

Name classResolver/routing ownerOperator check
service.default.svc.cluster.localKubernetes cluster DNSService exists, endpoints are ready, workload DNS policy is correct
Public UI domainPublic DNS and Cloudflare tunnel or reverse-proxy routeDNS target, edge policy, TLS and backend route agree
Private ingress domainTailscale operator and tailnet DNSOperator ingress status, device membership and tailnet policy

Do not replace cluster Service names with public domains for internal traffic. Review the cluster repository for actual DNS records and ingress mappings; these docs intentionally omit deployment addresses.

Trace queue scaling​

Production polls RabbitMQ every 10 seconds, requests a worker per queued message and caps concurrent worker Jobs at three. Workers exit after 120 idle seconds; draft-day keeps at least one warm worker and sets idle exit to zero.

KEDA trigger queuesProvisioning
lineup_updates, waiver_actions, draft_targetsBroker startup definitions; dead-letter policy to dlx and matching .dlq
trade_submissions, trade_responsesBroker startup definitions and worker declarations; no added DLQ policy
trade_evaluations, trade_negotiations, llm_requestsWorker declares durable queues; a fresh scaler can report missing queues before first worker startup

KEDA reads broker credentials through a TriggerAuthentication; workers use a Secret-backed AMQP URL. Queue existence and authentication must succeed even when workers scale to zero.

Related: Stuck queue runbook, Broker rollout, Secrets.