Skip to main content
Unlisted page
This page is unlisted. Search engines will not index it, and only users having a direct link can access it.

Restricted-egress reference

Detail behind Behind a forward proxy.

How the proxy variables are read​

RuleDetail
SpellingLowercase (https_proxy) wins over uppercase. An empty value counts as unset
Which proxyhttps:// calls use HTTPS_PROXY, or HTTP_PROXY when only that one is set. http:// calls use HTTP_PROXY only
Valuehttp://host:port or https://host:port. A value with no scheme is read as http://. Basic credentials go in the URL (http://user:password@proxy.example.com:3128) and never reach a log line or /admin/health
Bad valueThe gateway stops at boot with a message that names the variable, never its value
NO_PROXYComma or space separated, case-insensitive. example.com, .example.com, and *.example.com each match the host and every subdomain. host:port matches that port only. * sends nothing through the proxy. CIDR ranges are not matched; private addresses are direct anyway
Always directLoopback, private, link-local, and CGNAT addresses; cloud metadata hosts; the suffixes .local, .localdomain, .internal, .intranet, .lan, .home, .corp, .test, .invalid, .onion, .localhost; any name with no dot. The optimizer is always direct, whatever its address. The database never uses the proxy

SSRF checks behind a proxy​

The SSRF policy still runs before a destination someone names goes to the proxy. The gateway resolves the name and refuses a private, loopback, or metadata answer, with the same exemptions as a direct connection. It cannot pin that answer, because the proxy resolves the name again. That is why the proxy must deny internal destinations itself, and why a configured upstream on a private address belongs in NO_PROXY: the proxy would refuse it.

When the server's own DNS has no answer for the name:

DestinationResult
Provider APIs, the Billing App, github.comSent to the proxy
A provider Base URL or routing upstream you configuredSent to the proxy
An MCP server configured in the console, or a URL an admin tests from itSent to the proxy
An alert webhookSent to the proxy
Organization MCP sign-in through WorkOS AuthKit (the issuer the Billing App names, and only that host)Sent to the proxy
An MCP sign-in endpoint discovered from a server's metadataRefused
A caller-supplied custom host (x-anyray-custom-host, x-anyray-config)Refused, unless it is in TRUSTED_CUSTOM_HOSTS or is the built-in ChatGPT seat host (chatgpt.com)

Cloud metadata is refused on every path.

TLS-inspecting proxies​

Mount the proxy's root CA and point NODE_EXTRA_CA_CERTS at it.

docker-compose.override.yml (Docker Compose)
services:
gateway:
environment:
NODE_EXTRA_CA_CERTS: /etc/anyray/proxy-ca.pem
volumes:
- ./proxy-ca.pem:/etc/anyray/proxy-ca.pem:ro

On Helm, create the secret first:

kubectl create secret generic proxy-ca -n anyray --from-file=ca.pem=proxy-ca.pem
Never disable certificate verification instead

NODE_TLS_REJECT_UNAUTHORIZED=0 turns off verification for every connection the gateway makes.