trillium proxy
A reverse and forward proxy with upstream load-balancing, an in-memory response cache, compression, WebSocket passthrough, rate limiting, HTTPS, and HTTP/3.
trillium proxy [UPSTREAM]...
Proxy all traffic to a single upstream:
trillium proxy http://localhost:4000
Upstream URLs accept http://, https://, or a bare host:port (which
defaults to http://). The upstream list also reads from the UPSTREAM
environment variable.
Load balancing
Pass several upstreams to spread traffic across them. The default strategy is round-robin:
trillium proxy http://app-1:4000 http://app-2:4000
trillium proxy http://app-1:4000 http://app-2:4000 --strategy connection-counting
| Strategy | Behavior |
|---|---|
round-robin | (default) cycle through the upstreams in order |
connection-counting | send each request to the upstream with the fewest open connections |
random | pick an upstream at random per request |
forward | classic forward proxy — pass no upstreams (see below) |
-s / --strategy also reads the STRATEGY environment variable.
Forward-proxy mode
With --strategy forward and no upstreams, trillium proxy acts as a classic
forward proxy: it forwards absolute-form requests and tunnels HTTPS via
CONNECT.
trillium proxy --strategy forward
curl -x http://localhost:8080 https://example.com # use it as a proxy
Passing upstreams together with --strategy forward is an error, as is
omitting upstreams for any other strategy.
Caching
The proxy ships with an in-memory response cache that honors standard caching
headers (Cache-Control, ETag, …). It is on by default — appropriate for
a proxy fronting cacheable content. (The gateway
equivalent is opt-in, because a gateway shouldn't silently cache dynamic
upstreams.)
# 1 GiB cache, evict entries idle for 5 minutes
trillium proxy http://localhost:4000 \
--cache-capacity 1GiB --cache-time-to-idle 5m
| Flag | Default | Notes |
|---|---|---|
--no-cache | disable caching entirely | |
--cache-capacity | 256MiB | maximum total in-memory cache size (e.g. 256MiB, 1GB) |
--cache-max-body | 16MiB | largest cacheable body; bigger responses stream uncached |
--cache-time-to-idle | evict entries not read within this duration (e.g. 5m) | |
--cache-time-to-live | evict entries this long after they are stored (e.g. 1h) |
The cache flags conflict with --no-cache.
Listening, HTTPS, and HTTP/3
The proxy listens like serve: -o / --host (env HOST, default
localhost) and -p / --port (env PORT, default 8080). Provide a
certificate and key to terminate TLS — and, with the default h3 feature,
HTTP/3 over QUIC on the same port:
trillium proxy http://localhost:4000 --cert ./cert.pem --key ./key.pem
# or via the environment:
CERT=./cert.pem KEY=./key.pem trillium proxy http://localhost:4000
| Flag | Env | Notes |
|---|---|---|
--cert | CERT | listener certificate (PEM); requires --key |
--key | KEY | listener private key (PEM); requires --cert |
--tls | TLS | acceptor backend: rustls (default), native, openssl |
Connecting to HTTPS upstreams
When an upstream is https://, the proxy needs a client TLS backend
(separate from the listener's --tls acceptor):
trillium proxy https://api.internal --client-tls rustls
trillium proxy https://localhost:4000 -k # self-signed dev cert
| Flag | Notes |
|---|---|
-c, --client-tls | client backend for https:// upstreams: rustls/native/openssl |
-k, --insecure | skip upstream certificate verification (rustls only) — dangerous |
--insecure disables authentication of the upstream entirely; use it only
against hosts you control.
Compression, WebSockets, and 404s
- Responses are compressed (gzip / brotli / zstd) based on the client's
Accept-Encoding. Disable with--no-compress. - WebSocket upgrades are passed through to the upstream transparently.
- Upstream
404 Not Foundresponses are forwarded to the client as-is. (This is the opposite ofserve --forward, where a 404 falls back to local files.) - Proxied responses carry a
Via: trillium-proxyheader.
Rate limiting
The same controls as serve: --rate-limit RATE caps
requests per client network, --rate-limit-burst permits short spikes.
Off unless --rate-limit is given.
trillium proxy http://localhost:4000 --rate-limit 1000/min
Full flag reference
trillium proxy [OPTIONS] [UPSTREAM]...
Arguments:
[UPSTREAM]... Upstream URLs [env: UPSTREAM=]
Options:
-s, --strategy <STRATEGY> [env: STRATEGY=] [default: round-robin]
-o, --host <HOST> [env: HOST=] [default: localhost]
-p, --port <PORT> [env: PORT=] [default: 8080]
--cert <CERT> [env: CERT=]
--key <KEY> [env: KEY=]
--tls <TLS> [env: TLS=] [default: rustls]
-c, --client-tls <CLIENT_TLS> [default: rustls]
-k, --insecure
--no-compress
--rate-limit <RATE>
--rate-limit-burst <BURST> (requires --rate-limit)
-v, --verbose...
-q, --quiet...
-h, --help
Cache:
--no-cache
--cache-capacity <CACHE_CAPACITY> [default: 256MiB]
--cache-max-body <CACHE_MAX_BODY> [default: 16MiB]
--cache-time-to-idle <CACHE_TIME_TO_IDLE>
--cache-time-to-live <CACHE_TIME_TO_LIVE>
For a config-driven proxy that can mix in static files, redirects, header
rewriting, and virtual hosts across several listeners, see
gateway.