# Codex Proxy RS pins one release tag and speaks only the Responses API

> A Rust gateway that puts several Codex accounts behind one client key, installed as a version-pinned Compose stack. The protocol choice, the empty account-group default, and the installer's refusal to upgrade on a second run are the three things to understand before you deploy it.

**zyycn/codex-proxy-rs** — 基于 Rust 的自托管 Codex 多账号透明代理网关

- Repository: https://github.com/zyycn/codex-proxy-rs
- Stars: 712 · Forks: 144
- Language: Rust
- License: Apache-2.0
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/zyycn-codex-proxy-rs

## The gateway serves Responses and nothing else

The protocol warning sits above the install command, before any configuration step. Codex Proxy RS serves the Responses API and does not serve `/v1/chat/completions`, so the note asks you to confirm your client speaks Responses before anything else. For anything that does, two fields carry the whole integration. The base URL is `http://127.0.0.1:8080/v1` on the server itself, and the API key is a client key created in the admin console, not the admin login. The model catalog for that key is the first request worth making, because the list returned is scoped to the accounts the key can reach. That gives two answers in one call: whether the Responses endpoint is answering at all, and whether the account groups behind the key resolved the way you intended. A tool that only speaks chat completions has no route through this gateway, and editing the base URL will not change that.

## One command downloads release files, not a checkout

Installation is a single shell command, and it fetches deploy files belonging to one formal release rather than cloning the tree:

```bash
curl -fsSL https://raw.githubusercontent.com/zyycn/codex-proxy-rs/main/deploy/install.sh -o install.sh && bash install.sh
```

By default it installs into `codex-proxy-rs/` under the current directory, generates a password, sets directory permissions and starts the service, bringing up PostgreSQL and Redis next to a version-pinned release image. `INSTALL_DIR` moves the target, `CPR_RELEASE_TAG` names the tag, and both are read from the environment at the moment you run `bash install.sh`. The command is stated for Linux amd64 and arm64 and expects Docker Engine, the Docker Compose Plugin, curl and OpenSSL to be present, plus a user who can reach Docker and set directory permissions through `sudo` or root. A warning above that path tells anyone with an existing deployment to read the image upgrade and source build notes in `deploy/README.md` first, and not to overwrite the current config. That warning matters because the same command behaves differently once a directory already holds one.

## A second installer run upgrades nothing

Running the installer twice is the quiet failure in this flow. When it finds `deploy/config.yaml` in the target directory, the script keeps the existing configuration and deploy files, ignores any `ADMIN_PASSWORD` passed to it, and does not perform a version upgrade. The same command that built a stack will therefore do nothing on the next run, and the only signal is a requested password quietly discarded. Upgrading follows the notes in `deploy/README.md` instead of a re-run. The top-level tree explains why the split exists: `.gitmodules`, `AGENTS.md`, `.agents/`, `modules/` and `release/` sit beside `backend/`, `frontend/`, `deploy/` and `docs/`, and the install path touches none of them because it pulls release artifacts rather than a source checkout. Building from source is a separate, documented route with its own requirements.

## The admin password may not contain a dollar sign

The password rules are narrower than the surrounding text explains. `ADMIN_PASSWORD` must be at least 12 characters, must not contain a dollar sign, and must not be one of the common weak passwords; leave it unset and the script generates one, then prints the access address and password when it finishes, with an instruction to save the password. Why the dollar sign is refused is not stated anywhere in the README, which is an awkward gap for operators whose generated secrets come from a shell-heavy vault. That password only ever lands in the local admin console at `http://127.0.0.1:8080` under the identity `admin@cpr.local`. If the printout scrolls past, this page does not describe how to recover it, and the manual install flow in `deploy/README.md` is where the answer would have to come from.

## An empty group selection grants every account

Key scoping inverts the intuition an access-control screen usually teaches. You add an account and finish its authorization or import, build account groups as needed, then create a client key and choose which groups it may use. Selecting no group at all means the key can use every account. An empty selection is the broadest grant in the system rather than the narrowest, so a key created before its groups exist ends up wider than its owner intended, and nothing in the flow forces a choice. After creation, the key's own usage panel holds the client configuration to copy, already filtered to the accounts behind it. Treat that group picker as the security boundary it is, and check the model list for the key before handing it to a client, since that list is the fastest evidence of what the key can actually reach.

## One port serves admins and key holders

Two audiences share a single address, and the switch happens at login. Administrators open `http://127.0.0.1:8080` as `admin@cpr.local` and manage accounts, groups, proxies and usage statistics. A client key holder opens the same address, switches identity on the login page, sees only their own usage and quota, and copies a Codex configuration or imports CCSwitch from the key settings screen. A key holder is therefore not confined to a headless API surface: they land in a console built for operators, with their view narrowed after authentication instead of by a separate endpoint. That makes the exposure decision all or nothing. The default address answers on the server itself only, and every other device needs the HTTPS reverse proxy documented under public access in `deploy/README.md`, at which point a client key becomes a network credential.

## The public preview runs simulated accounts on a published build

A hosted preview removes the deployment question, and it is worth reading closely before drawing conclusions from it. The address is `https://codex-proxy-rs.ainz.cc`, the identity is administrator, the account is `admin@cpr.local`, and the shared password sits in the README login table in plain sight. That environment runs a published version, and every account, proxy and usage record in it is simulated, regenerated each day at `00:00` Beijing time. It makes no real model calls, and the page asks you not to import real accounts, keys or other sensitive material into it. So the console layout, the group picker and the usage screens can all be judged from that instance, while nothing about real latency, quota behavior or account rotation can be. Browsing it answers whether the management surface fits your workflow before you bind a port.

## Patch tags land daily while the install stays pinned

Versions move quickly and the install path is deliberately static, which is the tension worth planning around. Three releases appeared in three days: v3.18.2 on 2026-09-29, v3.18.3 on 2026-09-30 and v3.19.0 on 2026-10-01, with the most recent push dated 2026-10-02. Compose brings up a version-pinned release image and the installer pulls deploy files from that same tag, so a running stack never drifts on its own. `CPR_RELEASE_TAG` is the lever for choosing a different tag at install time, and the upgrade notes govern everything after that. A minor bump inside a single day is reason enough to read the release notes before pointing clients at a new base URL, and to record the tag you deployed, since the installer will not lift it for you. Container images are published to the project package registry as well.

## Conclusion

Codex Proxy RS fits a Linux host running Docker Compose where several Codex accounts need to sit behind one client key and every client already speaks the Responses protocol. It does not fit a stack where any tool still calls `/v1/chat/completions`, nor a setup that wants the console reachable from another machine without putting your own TLS terminator in front. Before installing, confirm your client speaks Responses, choose the install directory once because a second run will not upgrade anything, pick account groups deliberately since an empty selection grants every account, and read the upgrade notes in `deploy/README.md` instead of re-running the installer when a new tag appears.

## FAQ

### Does Codex Proxy RS support the chat completions API?

No. It serves the Responses API only, and the README states plainly that `/v1/chat/completions` is not supported. Clients must speak the Responses protocol before they can talk to the gateway at all.

### What does a Codex Proxy RS client key return from the model list?

The catalog visible to that key, scoped to the accounts behind it. Requesting `http://127.0.0.1:8080/v1/models` with the client key is the quickest way to see which accounts the key resolved to.

### What happens when I run the Codex Proxy RS installer twice in the same directory?

The second run detects `deploy/config.yaml`, keeps the existing configuration and deploy files, ignores any `ADMIN_PASSWORD` passed in, and performs no version upgrade. Upgrading is a separate documented step in `deploy/README.md`.

### Can I reach the Codex Proxy RS console from another machine?

Not by default. The `http://127.0.0.1:8080` address answers on the server itself, so other devices need the HTTPS reverse proxy documented under public access in `deploy/README.md`, and remote clients then use the server HTTPS address as their base URL.

### What does a Codex Proxy RS client key reach when no account group is selected?

Every account. Selecting no group means the key is permitted to use all accounts, which makes an empty selection the widest grant the console offers rather than a neutral default.

## Sources

- [Issues](https://github.com/zyycn/codex-proxy-rs/issues)
- [License: Apache-2.0](https://github.com/zyycn/codex-proxy-rs/blob/main/LICENSE)
- [README](https://github.com/zyycn/codex-proxy-rs/blob/main/README.md)
- [Releases](https://github.com/zyycn/codex-proxy-rs/releases)
- [zyycn/codex-proxy-rs on GitHub](https://github.com/zyycn/codex-proxy-rs)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/zyycn-codex-proxy-rs
