Gateway TLS
The gateway speaks plain HTTP on :8787 and never terminates TLS. Put a TLS edge in front of it;
plaintext http:// breaks long streams.
Set ANYRAY_GATEWAY_PUBLIC_URL to the https:// URL users reach. Enrollment links then use
it. An http:// value (except loopback or .local) is flagged as insecure on the enrollment page.
Every recipe below also sets ANYRAY_TRUST_PROXY=true, and ends with Re-point users.
With ANYRAY_TRUST_PROXY=true, per-IP limits key on the first X-Forwarded-For entry. A second rule
is measured on this release and not enforced yet. It reads the header from the right and skips
private-network hops. On Railway, whose edge replaces the header, it keeps the first entry. Behind
Google's load balancer it skips the address the balancer appends after the client's.
GET /admin/health reports how often it would choose a different key, under
clientIpShadow. Client behavior does not change until a later release
switches to it.
Docker Compose
The public profile ships a Caddy edge that gets and renews a Let's Encrypt certificate. You
need a DNS A record to the host and ports 80/443 open.
DNS A record, e.g. gateway.example.com → the host's public IP.
ANYRAY_PUBLIC_DOMAIN=gateway.example.com # Caddy provisions a cert for this
ANYRAY_GATEWAY_PUBLIC_URL=https://gateway.example.com
ANYRAY_GATEWAY_BIND=127.0.0.1 # so :8787 isn't reachable, bypassing TLS
ANYRAY_TRUST_PROXY=true # trust X-Forwarded-* from Caddy
ANYRAY_HSTS=true # emit Strict-Transport-Security, safe once TLS fronts it
docker compose --profile public up -d
The console and /admin stay in-network.
Expose the console over HTTPS (optional)
The console (port 3000) stays in-network by default; reach it over an SSH tunnel. To let the
app.anyray.ai Billing App link admins to it, add a second DNS A record to
the same host, then:
ANYRAY_CONSOLE_DOMAIN=console.example.com # Caddy provisions a cert for this
ANYRAY_CONSOLE_PUBLIC_URL=https://console.example.com # reported home, so the Billing App links here
Re-run docker compose --profile public up -d and restart the gateway.
The console hostname serves the console and /admin, /public, and /log, behind admin auth
(ANYRAY_ADMIN_TOKEN, or console SSO). The gateway hostname keeps returning 403 for them. Use a
strong admin token.
Kubernetes
Terminate TLS at an Ingress with cert-manager (or a managed certificate). Expose only the Ingress.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: anyray-gateway
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts: [gateway.example.com]
secretName: anyray-gateway-tls
rules:
- host: gateway.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: anyray-gateway
port: { number: 8787 }
ANYRAY_GATEWAY_PUBLIC_URL=https://gateway.example.com
ANYRAY_TRUST_PROXY=true
/admin privateDo not route /admin/*, /public/*, or /log/* through the public Ingress. Use an internal Ingress
or kubectl port-forward. Caddy blocks them by default; on an Ingress, path rules do.
Managed platforms
Railway, Render, and Fly terminate TLS and give an https:// hostname. Do not expose :8787 directly.
ANYRAY_GATEWAY_PUBLIC_URL=https://your-app.up.railway.app
ANYRAY_TRUST_PROXY=true
Cloud load balancers
| Cloud | TLS edge | Lock down :8787 to |
|---|---|---|
| AWS | ALB, HTTPS:443 listener, ACM certificate, target group on :8787 | The ALB's security group |
| Google Cloud | External HTTPS LB, Google-managed certificate, backend service to the gateway | The LB's ranges |
ANYRAY_GATEWAY_PUBLIC_URL=https://gateway.example.com
ANYRAY_TRUST_PROXY=true
A certificate from your company's CA
If the edge serves a certificate signed by your company's own certificate authority, every machine must trust that root.
Push it with MDM or Group Policy.
After you re-point it, run anyray-connect doctor. Under Gateway it prints:
Certificate: trusted by this machine's certificate store (company root: Example Corp Root CA).
When an older npm install of Claude Code cannot read the OS store, Connect points it at the company
root it found there; it never trusts a root the machine does not. Every line doctor can print is
in Gateway certificate.
A publicly trusted certificate on the edge hostname avoids all of this.
Re-point users
Run anyray-connect --gateway https://gateway.example.com, or share new enrollment links. When every
tool is on https, close any direct plaintext :8787 exposure.