Tawa docs

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.

ContainerNative (systemd)
Host requirementsDocker onlyRust toolchain to build, nothing to run
Image/binary sourceSame Dockerfile as localSame cargo build --release as local
Process supervisionDocker's own restart policysystemd
Fits if...You already run other containers on this boxYou'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-proxy

Binding 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
/etc/systemd/system/tawa-claude-proxy.service
[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.target
/etc/tawa-claude-proxy.env
TAWA_API_KEY=...
TAWA_PROXY_LISTEN_ADDR=127.0.0.1:8787
sudo systemctl enable --now tawa-claude-proxy
sudo journalctl -u tawa-claude-proxy -f

Put 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:

Caddyfile
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).

On this page