A minimal, self-hosted proxy for the Anthropic Claude API. Runs on any Docker host. No cloud, no signup, no SaaS.
Claude Code / your app
│
▼
gateii :8888 ← token tracking · rate limiting · monitoring
│
▼
api.anthropic.com
You're paying for Claude and have no idea what's actually happening. Either your team shares one API key with no visibility, or every user has their own and finance reviews a spreadsheet of charges no one can attribute. If you're on the Max plan and occasionally hit the wall, you have no data on where it went.
| Problem | gateii answer |
|---|---|
| No visibility into token usage | Per-user, per-model counters in a Grafana dashboard |
| Sharing one API key is risky | Per-user proxy keys pinned to their own provider + credential |
| Don't want another SaaS | Self-hosted, stateless, three Docker containers, no external deps |
| Claude Max plan (OAuth) | passthrough mode — your token forwarded as-is, no server key |
| Accidental runaway spend | Per-user daily limits, auto-block until midnight UTC |
| Cost discussions without data | Historical metrics in Prometheus, cost estimates from providers.json |
Unlike managed observability tools, gateii runs locally, stores nothing on
third-party infrastructure, and keeps your Anthropic key where you already
put it (in your .env or your OAuth session).
git clone https://github.com/bmmmm/gateii
cd gateii
cp .env.example .env
# Optional: alias the CLI so `gateii <subcommand>` works from anywhere
echo "alias gateii='$(pwd)/scripts/gateii'" >> ~/.zshrc && source ~/.zshrc
# Start the stack
gateii up
# Point Claude Code at the proxy
gateii switch local-proxy
# Optional: remind yourself when a Claude Code session is NOT routed through gateii
gateii hook install
# Open the dashboard
open http://localhost:3001The gateii hook install step registers a UserPromptSubmit hook in
~/.claude/settings.json that warns (up to 3× per session) when
ANTHROPIC_BASE_URL is not pointed at this gateii. It is opt-in on purpose —
it only makes sense once you actively route Claude Code through gateii. Remove
it with gateii hook uninstall. If you manage ~/.claude/settings.json via
dotfiles, mirror the entry there too.
Full walkthrough: Getting started.
| Page | What's in it |
|---|---|
| Getting started | Install prerequisites, first start, boot after reboot |
| CLI reference | All gateii <subcommand> options |
| Modes | passthrough vs apikey, when to use each |
| Routing | local-proxy / remote-proxy / direct, safe dev workflow, emergency rescue |
| Monitoring | What the Grafana dashboard shows, metrics exposed |
| Configuration | All .env variables, providers.json pricing |
| Plugins | console (web UI) and git-tracking |
| Local agents (omlx) | Route simple tasks (commits, summaries, …) to a local Apple-Silicon LLM |
| Providers | Adding a new upstream provider |
| Architecture | Three containers, shared dicts, why no Redis |
| Key files | Component map — which module does what |
| Testing | Suite layout, running the tests, CI parity |
| Security | Admin API hardening, secrets hygiene, network exposure |
| keys.json schema | Structured key storage (apikey mode) |
| Bootstrap handshake | Self-provisioning keys over HMAC |
| Admin API | HTTP endpoint reference |
Also: Pre-up hooks — how to run
platform-specific setup (Colima, podman, …) before docker compose up.
| Container | Image | Port | Role |
|---|---|---|---|
gateii-proxy |
openresty/openresty:alpine |
8888 | nginx + LuaJIT proxy + metrics |
gateii-prometheus |
prom/prometheus |
9090 | metrics storage |
gateii-grafana |
grafana/grafana |
3001 | dashboard |
gateii-git-tracking |
alpine (plugin) |
— | git activity metrics (optional) |
All state lives in nginx shared memory. Prometheus stores the time series — so the proxy itself is effectively stateless between restarts. See architecture.md.