Ingress
An Ingress is the standalone, shared proxy tier (nginx) that fronts apps and per-service web/SNI
routes under a domain. It is a sibling of Network — a thing other resources reference —
not a workload: it references a Compute host by name in the same scope (exactly
like service.host) and reuses that host's provisioning, firewall, cloud-init, and SSH. It carries
no provider of its own — it inherits its host's.
The ingress is one of two north-south (external-facing) tiers. Its sibling is the Gateway — the public edge external daemons HTTPS into, which routes each path to a service through the east-west mesh. Both are public nginx server blocks and can share one host (they merge into a single nginx there); the ingress fronts apps/web, the gateway fronts the daemon API.
An ingress lives in a folder under regional/ingress/<name>/ (or global/ingress/<name>/):
regional/ingress/edge/
manifest.yaml # required — the ingress spec
Schema
manifest.yaml:
name: edge # required — ingress name (unique within the scope)
container: bridge # required — grouping label
host: bridge # required — FK -> compute name (same scope); the vm nginx runs on
health_probes_port: 81 # optional — public port for service health checks (default 81)
# security: false # optional — opt this edge out of the env security tier (rate limiting)
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Ingress name. Unique within the scope. |
container | string | Yes | Grouping label (tags, like other resources). |
host | string | Yes | Name of the Compute resource (same scope) this ingress runs on. Must be a single-instance vm. A global/ prefix is rejected — a global ingress is declared in the global slice itself. At most one ingress per scope — the ingress's DNS name (ingress[.<slug>].<base>, see below) is scope-singular, which also implies one per host. |
health_probes_port | int | No | Public port nginx exposes service health checks on. Defaults to 81. Opened to the internet only when a referencing service declares its own health_probes_port. Must not be 80 or a route listen port on this host. |
security | bool | No | Set false to opt this ingress out of the env-level security tier — its servers get no rate limiting. Absent/true = the env policy applies. |
What it serves
The nginx/routing config is not declared on the ingress — it is derived at deploy from the
services that reference it. A service names an ingress via its ingress: foreign key and
contributes its routes:; the ingress nginx terminates ACME TLS (Let's Encrypt, HTTP-01) or
L4-forwards each route, proxying to the backend over loopback (co-located) or the private network
(cross-host). See Service → Ingress and routes.
A service's public FQDNs (the auto-derived <svc>.svc name and any vanity) resolve to the ingress
host's public IP, not the backend's. A cross-host backend's target ports are opened only to the
private network; only the ingress host exposes the public listen ports.
A forward route may share a listen port with tls-termination routes on the same ingress: nginx
inspects the TLS SNI without terminating (ssl_preread) and routes each known SNI to its terminator and
the single unknown SNI to the forward backend. See Service → Types.
The ingress DNS name
The scope's ingress gets a stable A record pointing at its host — ingress.<base_domain> for the
global scope, ingress.<region-slug>.<base_domain> per region — so consumers can address "the ingress
of this scope" without knowing which machine it runs on: if the ingress moves to a different host, the
name follows it on the next deploy. Because the name is scope-singular, a scope hosts at most one
ingress, and the ingress subdomain is reserved (an app or gateway may not claim it).
Health probes
When a service declares a health_probes_port, the ingress exposes a single
public health port (the ingress's health_probes_port, default 81) and reverse-proxies each probe to the
right backend, demuxed by request Host (the service's <svc>.svc FQDN). The endpoint is plain
HTTP, and the port is opened to the internet only when at least one referencing service declares its own
health_probes_port — an ingress with no health-exposing services never opens it.
# ingress
health_probes_port: 81 # public; defaults to 81 when omitted
A probe is GET http://<ingress-host>:81/healthz with Host: <svc>.svc.<env>.<slug>.<base>; a wrong or
missing Host returns 404 (each backend is matched strictly, with no catch-all). The port must not be
80 (ACME owns it), a route listen port on the host, or fall in nginx's internal ssl_preread loopback
range.
The health listener is allowlist-only: it proxies only the service's declared
health_probe_paths (exact match) and returns 404 for any other path —
the backend's health port is never exposed wholesale.
A health-declaring service gets its <svc>.svc DNS A record derived even when it has no
routes: (a health-only service), pointing at the ingress host — so probes always address it by
FQDN. A gateway-listed service without an ingress gets the same treatment on the
gateway's host instead.