Rolter sends requests to URLs an operator writes. An admin surface that accepts an arbitrary one would turn the gateway into a way to reach whatever its network position can reach, and the prize on a cloud host is instance metadata at 169.254.169.254. The egress policy refuses those destinations.
Configuration#
Self-hosted and air-gapped upstreams live on loopback and private networks, so only the link-local range is denied by default.
What it covers#
Every URL below is checked when it is saved, and again before each request. A stored row is not a standing permission to egress: a policy tightened later applies to rows saved earlier.
| URL | Saved through | A denied value is |
|---|---|---|
Provider api_base, egress proxy | provider API, config file | a 400; in a snapshot, row dropped |
Provider status_page_url, kv_events.endpoint, lmcache.endpoint | config file | refused at load; row dropped |
| MCP server URL and MCP OAuth URLs | MCP API, config file | a 400 |
| Alert channel and connector endpoints | alerting and connector APIs | a 400 |
| SSO issuer, and the endpoints its discovery document names | SSO provider API | a 400; at login, the login fails |
Guardrail webhook url ([guardrail_webhook] and Guardrails, Providers) | guardrail provider API, config file | a 400; in a snapshot, kept and reported |
PII sanitizer url, restore_url and restore_stream_url | config file | refused at load; kept and reported in a snapshot |
Plugin endpoint | plugin API | a 400; in a snapshot, kept and reported |
A denied provider URL in a snapshot drops that provider rather than refusing the snapshot, so one bad row cannot stop every gateway from receiving its configuration. A denied guardrail webhook, sanitizer or plugin URL is never dropped or switched off, because that would turn a fail-closed control into a fail-open one. It stays in the configuration and every call to it is refused, so its failure mode decides: fail closed rejects the request, fail open lets it through. Every such problem is listed by GET /api/v1/config/problems; check that list after tightening the policy.
Hostnames and redirects#
A saved URL is classified by its IP literal in every spelling a client would dial it by (2852039166, 0xa9fea9fe, 169.254.169.254.). A hostname cannot be classified without DNS, so the connection itself is checked: the addresses the name resolves to are filtered immediately before connecting, which also catches a name that later rebinds to a denied address. A name that resolves to several addresses keeps the permitted ones.
None of the clients above follows a redirect, because a 3xx is how an endpoint that passed the check hands the request to one that would not have.
The kv_events subscription speaks ZeroMQ rather than HTTP. Its endpoint is
checked, and a hostname is resolved and filtered, before each connect, but
the transport resolves the name again itself, so a rebind in between is not
caught.