VPS deployment
Run tawa-claude-proxy on a server for a team or CI runners, instead of one developer's laptop.
The Docker page covers running the proxy next to Claude Code on your own machine. That's the right setup for one developer. It stops being the right setup once you want it to keep running when your laptop is closed, or want every developer/CI runner on a team going through the same relay instead of each running their own.
There's no pre-built docker-compose.yml, Terraform, or one-command deploy
script for tawa-cli-proxy yet — unlike tawa-gateway, which has a
checked-in deploy/stage0 folder for exactly this. Everything below is
the same pattern applied by hand. Building a matching deploy/ folder for
this proxy is a reasonable next step, not done yet.
Two ways to run it on a server
Both work; pick based on what you'd rather operate.
| Container | Native (systemd) | |
|---|---|---|
| Host requirements | Docker only | Rust toolchain to build, nothing to run |
| Image/binary source | Same Dockerfile as local | Same cargo build --release as local |
| Process supervision | Docker's own restart policy | systemd |
| Fits if... | You already run other containers on this box | You'd rather avoid a container runtime entirely |
Option A: container
Same image as Docker, built and run directly on the VPS:
docker build -t tawa-claude-proxy .
docker run -d \
--name tawa-claude-proxy \
--restart unless-stopped \
-p 127.0.0.1:8787:8787 \
-e TAWA_API_KEY=<your Tawa API key> \
tawa-claude-proxyBinding to 127.0.0.1 here too, even on a server — the reverse proxy in
front (below) is what actually terminates external connections.
Option B: native binary under systemd
cargo build --release --locked -p tawa-cli-proxy-claude-code
sudo cp target/release/tawa-claude-proxy /usr/local/bin/tawa-claude-proxy[Unit]
Description=tawa-claude-proxy
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/tawa-claude-proxy
EnvironmentFile=/etc/tawa-claude-proxy.env
Restart=on-failure
DynamicUser=yes
[Install]
WantedBy=multi-user.targetTAWA_API_KEY=...
TAWA_PROXY_LISTEN_ADDR=127.0.0.1:8787sudo systemctl enable --now tawa-claude-proxy
sudo journalctl -u tawa-claude-proxy -fPut TLS in front of it
Whichever option you pick, the proxy itself only speaks plain HTTP. Once
ANTHROPIC_BASE_URL points at something other than localhost, every
request through it — including the real ANTHROPIC_API_KEY Claude Code
sends in the x-api-key header — crosses whatever network sits between the
developer's machine and this server. Don't point ANTHROPIC_BASE_URL at a
plain http:// address on the open internet.
Terminate TLS with a reverse proxy in front instead of exposing :8787
directly — the same shape as the Caddy setup already used for
tawa-gateway's own VPS deployment:
proxy.yourdomain.com {
reverse_proxy 127.0.0.1:8787
}Then point Claude Code at the HTTPS address instead of the container port:
export ANTHROPIC_BASE_URL=https://proxy.yourdomain.com
export ANTHROPIC_API_KEY=<your real Anthropic key>This server can spend your Anthropic key
Anyone who can reach this endpoint can route Anthropic-billed traffic
through whatever ANTHROPIC_API_KEY a client sends it — the proxy relays
that header verbatim and never checks who's presenting it. Restrict access
at the network layer (firewall rule, VPN, IP allowlist, or auth at the
reverse proxy) the same way you'd restrict access to any internal service
that can spend money on your behalf. This is unrelated to Tawa's own
scanning — it's true of any Claude Code gateway, corporate or otherwise.
Next
See Configuration for the full environment variable reference, and note the streaming responses this proxy relays can run for minutes on a long agentic turn — size any load balancer/reverse-proxy idle-timeout in front of it accordingly (Claude Code's own client-side idle watchdog is 300s).