Who can reach my app?
An shc install sets two independent dials — access (open by default, --gated) and exposure (lan by default, --public). They do not stack into a ladder: every one of the four cells below is legal. The request path never changes; only the place a request dies moves. Drag an origin along its wire toward the app — it stops where this posture stops it.
simulated
Mirrors internal/modules/app/inject_traefik.go, internal/modules/app/dns_target.go, internal/modules/app/commands/install.go and forward-auth/cmd/forward-auth/main.go. No live cluster; packet timing is illustrative.
The honest part: exposure is not a firewall — SHC installs no iptables or nftables rule for it. What --public changes is the managed-DNS target and the cert posture. exposure=internet points the record at the Traefik node's public_address and fails closed (X200980DNSDEF, record deferred) rather than ever publishing an RFC1918 address; other exposures keep the LAN fallback — the Traefik node's internal address, else all swarm nodes / the advertise address. That is why the off-network request dies at the name layer above, and why the faint any caller path still arrives: anyone who already has a route to the node and sends the right Host header reaches the router regardless of exposure.
Two axes, not a ladder: --gated and --open are mutually exclusive (MarkFlagsMutuallyExclusive("gated","open")) and open is the default; --public is independent of both, which is why all four cells above are legal. --public raises exposure only — it never skips the SSO gate. The ungated warning (ShouldWarnUngated → X200950APPUGW) fires on access=open plus self_auth: false and does not read exposure at all, so a LAN-only open app warns too.
Ingress exists only when --host is passed — with no --host there is no Traefik router at all. Docs: docs.