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.

Deploy gateway TLS

Put the gateway behind TLS; plaintext http:// breaks long streams.

The gateway never terminates TLS itself — it speaks plain HTTP on :8787 and is designed to sit behind a TLS edge (a reverse proxy, an Ingress, a load balancer, or your platform's router). How you terminate TLS depends on where you run it, but the rule is the same everywhere:

The one invariant

Set ANYRAY_GATEWAY_PUBLIC_URL to the https:// URL your users reach the gateway at. The gateway reports it to your console, so enrollment links resolve to the secure URL automatically. An http:// value (to anything but localhost) is flagged as insecure on the setup page.

Pick your deployment

Docker Compose

The stack ships a Caddy TLS edge behind the public profile — it provisions and renews a Let's Encrypt certificate automatically. You need a domain (or subdomain) with a DNS A record pointing at the host, and ports 80/443 open.

1
Point a domain at the host

Create a DNS A record, e.g. gateway.example.com → your host's public IP.

2
Configure the edge

In .env:

.env
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
3
Start with the public profile
docker compose --profile public up -d

Caddy comes up on :80/:443, gets the certificate, and proxies to the gateway. The console and /admin stay in-network only.

4
Re-point users

Re-run anyray-connect --gateway https://gateway.example.com, or share fresh enrollment links — once the gateway reports its https ANYRAY_GATEWAY_PUBLIC_URL, new links resolve to the secure URL automatically. Once every tool is on https, close off any direct plaintext :8787 exposure.

Exposing the console over HTTPS (optional)

By default the console (compose port 3000) speaks plain HTTP and stays in-network — reach it over an SSH tunnel. If you want the app.anyray.ai Billing app to link your admins straight to it, give the console its own public hostname so the bundled Caddy edge terminates TLS for it too:

1
Point a second domain at the host

Create another DNS A record, e.g. console.example.com → the same host IP.

2
Add the console vars
.env
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 so it re-reports the URL). Leave both unset to keep the console in-network only.

This exposes the admin surface to the internet

The console hostname serves the admin console and the /admin, /public, and /log endpoints — gated by admin auth (ANYRAY_ADMIN_TOKEN, or console SSO if enabled; the gateway hostname keeps 403-ing them). Use a strong admin token, and prefer an SSH tunnel if you don't need the Billing app hand-off.

Kubernetes

Terminate TLS at an Ingress with cert-manager (or your cluster's managed certificate). The gateway runs as a normal Service on :8787; the Ingress is the only thing exposed.

1
Apply the Ingress
gateway-ingress.yaml
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 }
2
Set the gateway env

Set on the gateway Deployment:

ANYRAY_GATEWAY_PUBLIC_URL=https://gateway.example.com
ANYRAY_TRUST_PROXY=true
3
Re-point users

Re-run anyray-connect --gateway https://gateway.example.com, or share fresh enrollment links — once the gateway reports its https ANYRAY_GATEWAY_PUBLIC_URL, new links resolve to the secure URL automatically. Once every tool is on https, close off any direct plaintext :8787 exposure.

Keep /admin private

Don't expose /admin/*, /public/*, or /log/* through the public Ingress — keep the console and admin API in-network (a separate internal Ingress or kubectl port-forward). The bundled Caddy edge blocks them by default; on an Ingress you enforce it with path rules.

Managed platforms

Managed platforms terminate TLS for you and give the service a public https:// hostname. There's nothing to provision — just don't expose :8787 directly, and set:

ANYRAY_GATEWAY_PUBLIC_URL=https://your-app.up.railway.app
ANYRAY_TRUST_PROXY=true

Then re-point users at the new URL: re-run anyray-connect --gateway <https-url> or share fresh enrollment links, and once every tool is on https, close off any direct plaintext :8787 exposure.

Cloud load balancers

Terminate TLS at the load balancer with a managed certificate, targeting the gateway on :8787.

Front the gateway with an Application Load Balancer: an HTTPS:443 listener with an ACM certificate, forwarding to a target group on the gateway's :8787. Lock the gateway's security group so :8787 only accepts traffic from the ALB.

ANYRAY_GATEWAY_PUBLIC_URL=https://gateway.example.com
ANYRAY_TRUST_PROXY=true

Then re-point users at the new URL: re-run anyray-connect --gateway https://gateway.example.com or share fresh enrollment links, and once every tool is on https, close off any direct plaintext :8787 exposure.