# Set up CLIProxyAPI for Claude Code and Codex

From Harry Smaje's guide: https://smaje.net/blog/cliproxyapi-raspberry-pi-tailscale

Give this file to Claude Code or Codex on the machine you code on. Read the
guide's account rules first. Anthropic and OpenAI haven't approved running
subscriptions through a proxy, and either could suspend or ban an account
that does. You follow this at your own risk.

---

## Instructions for the agent

Set up CLIProxyAPI so Claude Code and Codex on this machine send their
requests through it. CLIProxyAPI holds the user's own subscription logins and
spreads Claude Code conversations across their Claude accounts.

### Before you start

Ask the user which setup they want, unless they've already said:

- **Raspberry Pi:** the hub runs on a Raspberry Pi (or another always-on
  64-bit Linux machine) at their home, reached over SSH and Tailscale. Ask
  for the SSH target, such as `you@your-pi.local`, if they haven't given one.
- **This Mac:** the hub runs on this Mac with Homebrew and is only used here.

Ask how many Claude accounts they'll sign in, and confirm they have only one
ChatGPT account for Codex.

### Rules

- Never print the access key, the management key or login tokens in your
  replies, commands or logs. Pass them through files or pipes.
- Stop and explain if the release checksum fails or the network check below
  shows anything other than a home broadband provider.
- Pause whenever the user has to approve something in a browser: Claude and
  ChatGPT sign-ins, Tailscale sign-in, Tailscale HTTPS certificates and key
  expiry. Tell them exactly what to open and which account to use.
- Back up any file before editing it (`cp file file.bak`) and keep the user's
  existing settings.
- Only use personal accounts, and only for Claude Code and Codex sessions.
- Don't change anything this file doesn't ask for.

### 1. Check the network

On the hub machine, run `curl -s https://ipinfo.io/org`. It should name the
user's home broadband provider. If it shows a hosting company or a VPN,
stop. If the user's router sends some sites through a VPN, ask them to
confirm Anthropic and OpenAI aren't among them.

### 2. Install

**Raspberry Pi**, on the Pi over SSH. Check `uname -m` prints `aarch64`. Use
the latest version from https://github.com/router-for-me/CLIProxyAPI/releases
as `V`:

```sh
(
set -eu
V=8.0.51
cd "$(mktemp -d)"
B=https://github.com/router-for-me/CLIProxyAPI/releases/download/v$V
curl -fsSLO "$B/CLIProxyAPI_${V}_linux_aarch64.tar.gz"
curl -fsSLO "$B/checksums.txt"
grep "CLIProxyAPI_${V}_linux_aarch64.tar.gz$" checksums.txt | sha256sum -c -
tar -xzf "CLIProxyAPI_${V}_linux_aarch64.tar.gz"
mkdir -p ~/cliproxyapi
install -m 755 cli-proxy-api ~/cliproxyapi/
cp config.example.yaml ~/cliproxyapi/
install -m 600 config.example.yaml ~/cliproxyapi/config.yaml
install -d -m 700 ~/.cli-proxy-api
)
```

The config file is `~/cliproxyapi/config.yaml`.

**This Mac:**

```sh
brew install cliproxyapi
chmod 600 "$(brew --prefix)/etc/cliproxyapi.conf"
install -d -m 700 ~/.cli-proxy-api
```

The config file is `$(brew --prefix)/etc/cliproxyapi.conf`.

### 3. Configure

On the hub machine, generate an access key (`openssl rand -hex 32`) and a
management key (`openssl rand -hex 24`). Write both to
`~/cliproxyapi-keys.txt` with mode 600 and tell the user to move them to
their password manager and then delete the file. The hub replaces the
management key in the config with a hash when it first starts, so this is
the user's only copy.

Change these settings in the config file and leave the rest as shipped:

```yaml
server:
  host: "127.0.0.1"
  port: 8317
  trusted-proxies: ["127.0.0.1", "::1"]   # Raspberry Pi only

management:
  allow-remote: true                      # false on This Mac
  secret-key: "<management key>"
  disable-auto-update-panel: true

access:
  api-keys:
    - "<access key>"

routing:
  session-affinity: true
  session-affinity-rebind-on: "quota"

requests:
  proxy-url: "direct"

observability:
  usage:
    usage-statistics-enabled: true
```

### 4. Keep it running

**Raspberry Pi:** create `~/.config/systemd/user/cliproxyapi.service`:

```ini
[Unit]
Description=CLIProxyAPI
After=network-online.target
Wants=network-online.target

[Service]
WorkingDirectory=%h/cliproxyapi
ExecStart=%h/cliproxyapi/cli-proxy-api -config %h/cliproxyapi/config.yaml
Restart=always
RestartSec=5
CPUQuota=150%
Nice=5
NoNewPrivileges=yes
UMask=0077

[Install]
WantedBy=default.target
```

Then:

```sh
sudo loginctl enable-linger "$USER"
systemctl --user daemon-reload
systemctl --user enable --now cliproxyapi
journalctl --user -u cliproxyapi -n 20 --no-pager
```

**This Mac:** `brew services start cliproxyapi`.

### 5. Sign in

Run `umask 077` in the shell that runs each login. Sign in one account at a
time. Before each Claude login, ask the user to make sure the browser that
will approve it is signed in to claude.ai as the right account.

**Raspberry Pi:** the Claude login redirects the browser to
`localhost:54545`, which has to reach the Pi. On this machine, start
`ssh -N -L 54545:127.0.0.1:54545 <ssh target>` in the background. Then on the
Pi run `cd ~/cliproxyapi && ./cli-proxy-api -config config.yaml -claude-login -no-browser`,
give the user the URL it prints and wait for them to approve. Ignore the
`ssh` command it suggests. Repeat for each Claude account, then stop the
tunnel. For Codex, run
`./cli-proxy-api -config config.yaml -codex-device-login -no-browser` and give
the user the code. If ChatGPT says device-code login is off, they can turn it
on in their account's security settings.

**This Mac:** run `cliproxyapi -claude-login` for each Claude account, then
`cliproxyapi -codex-device-login`.

Afterwards, run `chmod 600 ~/.cli-proxy-api/*.json` on the hub machine.
Remind the user the login files are their accounts: keep them out of
unencrypted backups.

### 6. Publish it to the tailnet (Raspberry Pi only)

Install Tailscale on the Pi if it isn't there
(`curl -fsSL https://tailscale.com/install.sh | sh`), then
`sudo tailscale up` and have the user sign in with the same Tailscale
account as this machine. Then:

```sh
sudo tailscale serve --bg --https=8317 http://127.0.0.1:8317
```

If Tailscale asks for HTTPS certificates to be turned on, give the user the
link. Work out the hub's address, `https://<pi>.<tailnet>.ts.net:8317`, from
`tailscale status`. Ask the user to turn off key expiry for the Pi in the
Tailscale admin console. Confirm this machine is on the same tailnet.

### 7. Point Claude Code and Codex at the hub

On this machine (not the Pi), check `claude --version` is 2.1.242 or later.
The hub's address is `https://<pi>.<tailnet>.ts.net:8317` for the Raspberry
Pi setup and `http://127.0.0.1:8317` for This Mac.

Merge this into `~/.claude/settings.json`, keeping existing settings.
`promptCacheTtl` goes at the top level, not inside `env`:

```json
{
  "env": {
    "ANTHROPIC_BASE_URL": "<hub address>",
    "ANTHROPIC_AUTH_TOKEN": "<access key>"
  },
  "promptCacheTtl": "1h"
}
```

Add this to `~/.codex/config.toml`, with `model_provider` above any
`[table]` in the file:

```toml
model_provider = "cliproxy"

[model_providers.cliproxy]
name = "CLIProxyAPI"
base_url = "<hub address>/v1"
wire_api = "responses"
requires_openai_auth = false
supports_websockets = true
experimental_bearer_token = "<access key>"
```

Leave the user's direct Claude Code and Codex logins in place, for when the
hub is down.

### 8. Check it works

With `H` set to the hub's address and the access key read from the keys file
without printing it:

1. `GET $H/v1/models` with `Authorization: Bearer <access key>` returns 200.
2. The cache works. Run
   `claude -p "Reply with just ok" --output-format json > first.json` and
   check `.usage.cache_creation` has tokens under `ephemeral_1h_input_tokens`
   and none under `ephemeral_5m_input_tokens`. Then resume it with
   `claude -p --resume "$(jq -r .session_id first.json)" "Reply with just ok again" --output-format json`
   and check `.usage.cache_read_input_tokens` is large.
3. `codex exec --skip-git-repo-check "Reply with just ok"` replies.
4. Tell the user to open `$H/management.html`, enter the management key and
   check each account shows the requests.

### 9. Report

Tell the user what you installed and changed, which files you backed up,
the results of each check, and where the keys file is. Remind them to move
the keys to their password manager and delete the file, and that to bypass
the hub they can remove `ANTHROPIC_BASE_URL` and `ANTHROPIC_AUTH_TOKEN` from
Claude Code's settings and the `model_provider` line from Codex's config.
