Ingress & Domains
Forginate uses up to three hostnames, all driven by values — nothing is hardcoded.
| Hostname | Values key | Purpose |
|---|---|---|
forginate.example.com | global.domain | SPA, API, WebSockets, OAuth callbacks, webhooks |
*.apps.forginate.example.com | global.appsWildcard | Tenant hosted apps (one subdomain per project) |
share.forginate.example.com | apiGateway.shareHost | Public customer-facing document review portal |
Prerequisites
- An ingress controller whose class name you put in
global.ingressClass. - cert-manager with a
ClusterIssuernamed inglobal.certIssuer. - The wildcard certificate requires a DNS-01 solver (HTTP-01 cannot issue wildcards) — configure your DNS provider's API credentials on the issuer.
- DNS records pointing at your ingress:
A/CNAMEfor the app domain and share host, and a wildcard record*.apps.forginate.example.com.
The main Ingress
The chart renders one Ingress (named dev-forginate in the template) routing global.domain → the api-gateway Service on port 80 (container port 8080):
metadata:
annotations:
cert-manager.io/cluster-issuer: <global.certIssuer>
spec:
ingressClassName: <global.ingressClass>
rules:
- host: <global.domain>
http:
paths:
- path: /
pathType: Prefix
backend: { service: { name: api-gateway, port: { number: 80 } } }
tls:
- hosts: [<global.domain>]
secretName: dev-forginate-tlsEverything rides this one host: the SPA bundle, /api/*, WebSocket upgrades (including /agent/ws for customer deploy agents), /webhooks/github, /webhooks/stripe, and OAuth callbacks.
WebSockets and long-lived streams
The api-gateway serves WebSockets (run event streams, deploy-agent sockets) and the chat-editor path proxies Server-Sent Events. Make sure your ingress controller and any fronting proxy/CDN allow WebSocket upgrade on this host and don't buffer or idle-kill long-lived connections. Deploy agents on customer clusters connect outbound to wss://<global.domain>/agent/ws — no inbound access to their clusters is needed, but your edge must let those sockets stay open.
The internal listener is never exposed
The gateway has a second listener on port 8081 (api-gateway-internal Service, ClusterIP). It serves /internal/* routes authenticated by per-run agent tokens and the shared internal service token. Factory-runner pods reach it at api-gateway-internal.<namespace>.svc.cluster.local:8081.
Never create an Ingress for api-gateway-internal. The chart deliberately doesn't.
Tenant-apps wildcard certificate
The chart renders a cert-manager Certificate named apps-wildcard covering *.<global.appsWildcard> and <global.appsWildcard>, stored in the apps-wildcard-tls secret:
spec:
secretName: apps-wildcard-tls
issuerRef: { name: <global.certIssuer>, kind: ClusterIssuer }
dnsNames:
- "*.apps.forginate.example.com"
- "apps.forginate.example.com"Environment gate in the template
As shipped, apps-wildcard-cert.yaml only renders when global.environment == "dev" — the template guards on both .Values.global.appsWildcard being set and the environment equaling dev. If you run with environment: prod and want hosted tenant apps, create the equivalent Certificate yourself (or patch the template) — this is a known sharp edge.
Per-project ingresses for hosted apps are created dynamically at deploy time and terminate TLS with apps-wildcard-tls.
The share host
SHARE_HOST / SHARE_PUBLIC_BASE_URL (from apiGateway.shareHost) define a second public hostname used for customer-facing document review links (/s/<token>). When a request arrives with the share Host header, the gateway's host-gate restricts it to only the share surface (/s/*, /share/*, /api/share/*, /api/health) — the share host can never reach the control plane, even if your edge auth differs per host.
Point the share hostname at the same ingress/Service as the main domain (add a second Ingress rule or a copy of the Ingress with the share host). If you don't need the share portal, an empty SHARE_HOST disables the gate (single-host installs).
Cookies and base URLs
PUBLIC_BASE_URL=https://<global.domain>— used to build the GitHub OAuth callback (/auth/github/callback), GitHub App callbacks, and webhook URLs. Your GitHub OAuth app must be registered against exactly this origin.COOKIE_DOMAIN=<global.domain>,COOKIE_SECURE=true— session cookies only work over HTTPS on the configured domain. There is no chart knob to disable secure cookies; terminate TLS properly rather than fighting this.
Edge protection (optional)
If you put an authenticating proxy or zero-trust layer in front of the app domain, you must exempt:
/webhooks/github— GitHub's webhook IPs (published athttps://api.github.com/meta, keyhooks) must reach the gateway unauthenticated; signatures are verified by HMAC./webhooks/stripe— same story for Stripe's webhook IPs, if billing is enabled./agent/ws— customer deploy agents authenticate with their enrollment key/agent token, not your SSO.- The entire share host — it is customer-facing by design.