HTTP gateway
An http listener lets roxy stand in for an origin. Clients send ordinary
requests to a name that resolves to roxy, and rules decide where each one
goes and what to add. The example here is an LLM gateway: clients hold
placeholder keys, and roxy adds the real ones on the way out.
The pattern
*.gw.example.com points at a load balancer, which terminates TLS and
forwards plain HTTP to roxy. One rule per subdomain redirects the request
to its provider over HTTPS and sets the real key. Anything no rule
matches is denied.
version: 1
listeners:
- name: gateway
mode: http
bind: 0.0.0.0:8080
forwarded_for: { trusted_hops: 1 } # one load balancer in front
secrets:
anthropic: { env: ANTHROPIC_API_KEY }
openai: { env: OPENAI_API_KEY }
aws_akid: { env: AWS_ACCESS_KEY_ID }
aws_sk: { env: AWS_SECRET_ACCESS_KEY }
rules:
- id: anthropic
when: listener.name == "gateway" and host == "anthropic.gw.example.com" and path starts_with "/v1/"
then:
- redirect: { host: api.anthropic.com, port: 443, scheme: https, rewrite_host: true }
- set_header: { x-api-key: "${secret:anthropic}" }
- allow
- id: openai
when: listener.name == "gateway" and host == "openai.gw.example.com" and path starts_with "/v1/"
then:
- redirect: { host: api.openai.com, port: 443, scheme: https, rewrite_host: true }
- set_header: { authorization: "Bearer ${secret:openai}" }
- allow
- id: bedrock
when: listener.name == "gateway" and host == "bedrock.gw.example.com" and path starts_with "/model/"
then:
- redirect: { host: bedrock-runtime.eu-west-2.amazonaws.com, port: 443, scheme: https, rewrite_host: true }
- sign:
aws_sigv4:
service: bedrock
region: eu-west-2
access_key_id: "${secret:aws_akid}"
secret_access_key: "${secret:aws_sk}"
- allowrewrite_host: true sends the provider's name in Host, which the
provider expects (redirect).
Bedrock needs a signature rather than a key. sign signs the request as
forwarded, after the redirect
(signing AWS requests).
Authenticating clients
The listener does no authentication: rules see only listener.name and
client.ip. Authenticate clients at the load balancer, or with an addon
that checks a credential and tags the exchange with the user, as the
quickstart's auth check does
(what just happened). A per-user quota
is another addon.
What to know
- This is not containment. The listener serves whoever reaches it, and clients may have other routes out (threat model).
- Say how many proxies are in front. Set
forwarded_for.trusted_hopsto the number of proxies between clients and roxy, soclient.ipis the real client rather than the load balancer (HTTP). Only the load balancer may be able to reach the listener: a client that connects directly can choose its ownclient.ip. - Leave the per-client connection cap alone. It counts the load balancer, not the client, so lowering it caps the whole gateway (limits).
- TLS stays at the load balancer. roxy does not terminate TLS on an
httplistener, so keep the hop from the load balancer to roxy on a network you trust. - In-cluster upstreams have private addresses, which roxy refuses by
default. A rule that forwards to one needs
then: { allow: { private_ok: true } }(address floor). - Do not use quarantine. A quarantine shuts the whole process, so one client's bad requests would lock out every other client.