# CLIProxyAPI + Codex einrichten: Docker, OAuth und Reverse Proxy

> Canonical: https://vxi.me/de/posts/cliproxyapi-codex-docker-proxy/
> Locale: de-de
> Published: 2026-03-30
> Updated: 2026-10-14
> Markdown: https://vxi.me/de/posts/cliproxyapi-codex-docker-proxy.md

**Begleit-Repository**: die One-Command-Deploy-Variante dieses Guides – Docker-Deployment, Key-Erzeugung und Config-Rendering in einem Befehl, dazu ein Generator für die Client-Konfiguration und ein Nginx-Beispiel:

<a class="gh-repo-pill" href="https://github.com/kuangyongjie/cliproxyapi-codex-deploy" target="_blank" rel="noopener"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg><span>kuangyongjie/cliproxyapi-codex-deploy</span></a>

```bash
git clone https://github.com/kuangyongjie/cliproxyapi-codex-deploy.git
cd cliproxyapi-codex-deploy
./scripts/setup.sh
```

CLIProxyAPI kann Codex hinter einen eigenen OpenAI-kompatiblen Endpunkt setzen. Der praktische Weg sieht so aus: CLIProxyAPI mit Docker starten, Codex-OAuth auf dem Proxy abschließen, einen stabilen `/v1`-Endpunkt bereitstellen und anschließend den lokalen Codex-Client mit aktivierter Responses API auf diesen Endpunkt zeigen lassen.

## Schnelleinrichtung

1. CLIProxyAPI mit Docker oder Docker Compose deployen.
2. Das Auth-Verzeichnis des Proxys persistent einbinden, damit der OAuth-Status Neustarts überlebt.
3. Den Codex-OAuth-Login auf dem Proxy ausführen.
4. Den Proxy über HTTPS veröffentlichen und dabei den Pfad `/v1/` unverändert lassen.
5. Codex mit einem benutzerdefinierten `base_url` auf den Proxy zeigen lassen.
6. `wire_api = "responses"` setzen und einen nachgelagerten Proxy-Key verwenden.

Der Rest dieses Guides erklärt, warum die einzelnen Schritte wichtig sind, wie die Authentifizierungsschichten zusammenspielen und welche Fehler einen ansonsten gesunden Aufbau am häufigsten aus dem Tritt bringen.

Wenn Codex bereits Teil des täglichen Workflows ist, taucht früher oder später eine naheliegende Frage auf: Bleibt man beim offiziellen direkten Login, oder setzt man Codex hinter eine eigene Proxy-Schicht und macht ihn damit zu einem Baustein einer größeren, selbst kontrollierten Umgebung?

Für einen Rechner und einen Benutzer ist der direkte Login weiterhin die einfachste Lösung. Das sollte man nicht künstlich komplizierter darstellen. Installieren, anmelden, weiterarbeiten. Weniger bewegliche Teile, weniger Dienste und weniger Stellen, an denen man debuggen muss.

Sobald der Workflow darüber hinauswächst, verändert sich die Frage. Vielleicht sollen mehrere Rechner denselben Endpunkt nutzen. Vielleicht sollen Codex, Claude Code und Gemini CLI hinter einer gemeinsamen Routing-Schicht liegen. Vielleicht sollen OAuth-Status und Zugriffsregeln serverseitig verwaltet werden, statt auf jedem Client erneut eingerichtet zu werden. Genau an diesem Punkt hört [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) auf, wie ein Nischen-Proxy zu wirken, und wird zu brauchbarer Infrastruktur.

Der Grund, warum ich diesen Ansatz ernst genommen habe, war nicht der Wunsch nach einem „schickeren Setup“. Es war die Erkenntnis, dass direkter Login auf einem Rechner hervorragend funktioniert, aber zerfasert, sobald Codex neben einem VPS, mehreren selbst gehosteten Tools und internen Skripten laufen soll. Der Login-Status hängt an einem Client, jede weitere Anwendung möchte eine eigene Endpunkt-Konfiguration und der nächste Consumer bedeutet wieder eine neue Einrichtungsrunde. Die eigentliche Frage wurde deshalb: Wie sieht die Kette aus, wenn Codex hinter CLIProxyAPI auf einem Linux-Server in Docker läuft, dort über OpenAI OAuth authentifiziert wird und anschließend wieder mit der lokalen Codex-App verbunden wird – und an welchen Stellen geht sie typischerweise kaputt?

## Warum Codex hinter einen Proxy setzen?

Meine Antwort ist im Kern einfach: Für unmittelbare Bequemlichkeit gewinnt der direkte Login. Wenn Codex dagegen Teil einer wiederverwendbaren und kontrollierbaren AI-Tooling-Schicht werden soll, lohnt sich der Proxy-Ansatz. Der Nutzen besteht nicht darin, dass die Architektur „fortgeschrittener“ aussieht. Entscheidend ist, dass Authentifizierungsstatus, Routing, Endpunkt-Kontrolle und spätere Erweiterungen nicht mehr an eine einzelne Client-Installation gebunden sind.

Ist diese Proxy-Schicht einmal vorhanden, reicht der Nutzen meist weit über Codex hinaus. Im Ergebnis bekommt man einen wiederverwendbaren OpenAI-kompatiblen Einstiegspunkt, den auch andere selbst gehostete Tools verwenden können. Kann ein Projekt auf ein eigenes `base_url` zeigen, lässt es sich mit hoher Wahrscheinlichkeit hinter dasselbe Gateway hängen. Codex kann der erste Consumer sein, bleibt aber selten der einzige. Ein selbst gehostetes Frontend, ein Agent-Panel, ein interner Skript-Dienst oder eine andere OpenAI-kompatible Anwendung kann denselben Endpunkt wiederverwenden, statt jeweils einen eigenen Upstream-Login-Status zu tragen.

Leicht zu übersehen ist, was dabei tatsächlich gemeinsam genutzt wird. Es geht nicht darum, dass ein Upstream-Secret immer weiter kopiert wird. Im Gegenteil: OAuth- und Token-Status bleiben zentral in der Proxy-Schicht. Nachgelagerte Tools benötigen nur die Proxy-URL und einen vom Proxy ausgegebenen Key. Das klingt nach einer kleinen Konfigurationsänderung, ist operativ aber ein völlig anderes Modell als Login und Secrets in jeder App oder jedem Container neu einzurichten. Beim nächsten OpenAI-kompatiblen Tool lautet die Frage nicht mehr „Wie logge ich auch dieses Tool ein?“, sondern „Welchen Proxy-Key soll es verwenden und soll es denselben Endpunkt teilen?“

Für einen unabhängigen Entwickler ist das relevant, weil sich dadurch auch das Secret-Management verändert. Nicht mehr jede Maschine und jede App muss Upstream-Authentifizierung kennen. Der sensible OAuth-Status bleibt zentral im Proxy. Clients und selbst gehostete Projekte brauchen nur einen Proxy-Key und einen stabilen Endpunkt. Ein neues Projekt hinzuzufügen bedeutet damit „neuen Downstream-Key ausgeben und auf das Gateway zeigen“, nicht „die komplette Upstream-Authentifizierung noch einmal aufbauen“.

Es gibt außerdem einen sehr praktischen Mittelweg. Wer heute nur wenige interne Tools betreibt, kann zunächst mehrere davon einen Proxy-API-Key teilen lassen, um schnell online zu kommen. Sobald saubereres Logging, Limits pro Projekt oder die Möglichkeit wichtig wird, einen Consumer unabhängig von allen anderen zu sperren, trennt man die Keys auf. Die Proxy-Schicht hilft also sowohl dann, wenn zunächst Geschwindigkeit zählt, als auch später bei einer disziplinierteren Architektur.

## Die Kette in drei Teile zerlegen

Am meisten geholfen hat mir, den gesamten Aufbau in drei Teile zu trennen. Erstens läuft der `CLIProxyAPI`-Dienst auf dem Server. Zweitens muss der Codex-OAuth-Status tatsächlich im eingebundenen Auth-Verzeichnis dieses Dienstes gespeichert werden. Drittens gibt es die lokale Codex-Client-Konfiguration, vor allem `~/.codex/config.toml` und `~/.codex/auth.json`. Bleiben diese drei Ebenen gedanklich getrennt, ist das Setup gut beherrschbar. Werden sie vermischt, wirkt das Ganze schnell mysteriöser, als es ist.

Die Projektdokumentation deckt die wesentlichen Bausteine bereits ab: Codex über OAuth, Deployment mit Docker und Docker Compose sowie das Muster für die lokale Client-Konfiguration. Entscheidend ist zu verstehen, welche Datei zu welcher Ebene gehört. `config.yaml` gehört zum Proxy-Dienst. Das gemountete Verzeichnis `auth/` enthält den gespeicherten Login-Status des Proxys. Die Dateien unter `~/.codex/` gehören zur lokalen Codex-App.

## Serverseite: Docker-Deployment und OAuth-Login

Wenn ich das heute von Grund auf einrichten würde, hielte ich das Serververzeichnis bewusst sehr klein:

```text
/opt/cliproxyapi/
├── docker-compose.yml
├── config.yaml
└── auth/
```

Dieses `auth/`-Verzeichnis ist wichtiger, als es zunächst wirkt. CLIProxyAPI verwendet standardmäßig `~/.cli-proxy-api` als Auth-Verzeichnis. Mit Docker sollte genau dieser Pfad aus dem Container heraus gemountet werden, damit OAuth-Status Neustarts und Container-Neubauten überlebt. Viele Fälle von „gestern lief es, nach dem Neustart nicht mehr“ sind letztlich nur fehlende Persistenz an dieser Stelle.

Für den ersten Durchlauf würde ich auch `config.yaml` möglichst klein halten. Die offizielle `config.example.yaml` ist umfangreich, für einen Codex-Proxy sind zu Beginn aber nur wenige Teile wichtig:

```yaml
host: ""
port: 8317
auth-dir: "~/.cli-proxy-api"

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

remote-management:
  allow-remote: false
  secret-key: ""
```

Zwei Dinge werden hier leicht falsch gelesen. Der Bereich `api-keys` enthält **nicht** die OpenAI-Upstream-Zugangsdaten. Das sind die Zugangsschlüssel, mit denen nachgelagerte Clients den Proxy aufrufen. Genau diese Trennung ist eine der stärksten Eigenschaften des Designs: Unterschiedliche Clients oder Projekte können unterschiedliche Downstream-Keys bekommen. Codex nutzt einen, eine andere selbst gehostete App einen anderen. Muss ein Key rotiert oder gesperrt werden, passiert das an der Proxy-Schicht, ohne den Upstream-Login überall neu anzufassen. Und solange es keinen guten Grund gibt, die Management-Ebene nach außen zu öffnen, würde ich `remote-management.allow-remote` deaktiviert lassen. Die konservative Voreinstellung passt hier sehr gut.

Für Docker Compose würde ich die Konfiguration ebenfalls schlicht und explizit halten:

```yaml
services:
  cli-proxy-api:
    image: eceasy/cli-proxy-api:latest
    container_name: cli-proxy-api
    restart: unless-stopped
    ports:
      - "127.0.0.1:8317:8317"
      - "127.0.0.1:1455:1455"
    volumes:
      - ./config.yaml:/CLIProxyAPI/config.yaml
      - ./auth:/root/.cli-proxy-api
```

Beide Ports sind bewusst an Loopback gebunden. Der API-Port muss nur vom Nginx auf demselben Host erreichbar sein – der Client-Abschnitt weiter unten proxyt ohnehin auf `http://127.0.0.1:8317` – und der OAuth-Callback-Listener hat eine dokumentierte Vorgeschichte, bei offener Publikation alle Interfaces zu binden (Upstream-Issue #3463). Diese beiden Ports standardmäßig ins öffentliche Netz zu stellen, würde eine temporäre Login-Fläche in eine permanente verwandeln; behandle öffentliche Publikation also nicht als sichere Voreinstellung. Wenn deine Netzwerktopologie wirklich breiteren Zugriff braucht, definiere das als explizite Ausnahme mit eigenen Einschränkungen, nicht als Ausgangspunkt.

Noch ein Hinweis zum Image-Tag: `:latest` ist ein bewegliches Tag. Die v8-Feldzuordnung in diesem Guide wurde am 2026-10-14 gegen den Main-Branch des Upstream-Repositories geprüft – nicht durch Ausführen dieses Images. Prüfe vor dem Deployment, ob der Tag, den du pullst, noch zu diesem Layout passt, oder pinne einen Digest, den du selbst verifiziert hast.

Der zusätzliche Port `1455` ist nicht zufällig dabei. Laut offizieller Provider-Dokumentation verwendet Codex OAuth einen lokalen Callback auf Port `1455`. Oft konzentriert man sich nur auf den API-Port `8317`, obwohl der OAuth-Teil eigene Anforderungen hat. Der Dienst kann gesund laufen, während der Login trotzdem scheitert, weil dieser Callback-Pfad nie berücksichtigt wurde.

Ist der Container gestartet, lautet der dokumentierte Codex-Login-Befehl:

```bash
docker compose exec cli-proxy-api /CLIProxyAPI/CLIProxyAPI -no-browser --codex-login
```

Das Flag `-no-browser` ist auf einem entfernten Linux-Server besonders praktisch, weil es die URL ausgibt, statt innerhalb des Containers einen Browser starten zu wollen. Genau hier lohnt es sich, gedanklich präzise zu bleiben: In diesem Schritt wird **nicht** der lokale Codex-Client angemeldet. Stattdessen wird Codex für den Proxy-Dienst authentifiziert, damit der Proxy später Codex-kompatible Requests beantworten kann.

Eine Sache an diesem Callback geht auf einem entfernten Rechner leicht schief. Der Browser läuft auf deinem lokalen Laptop, also löst `http://localhost:1455/auth/callback` zu deinem Laptop auf – nicht zum VPS – egal, wie die Container-Ports gemappt sind. Für ein Remote-Linux/VPS-Setup schließt erst diese Reihenfolge die Schleife:

1. Auf deinem **lokalen** Rechner (nicht dem Server) zuerst den Tunnel öffnen:
   ```bash
   ssh -N -L 1455:127.0.0.1:1455 <user>@<vps>
   ```
2. Den Login-Befehl aus diesem Guide ausführen. Die CLI gibt die OAuth-URL aus – mit `-no-browser` druckt sie diese SSH-Tunnel-Anleitung sogar selbst.
3. Diese URL im lokalen Browser öffnen und die Anmeldung abschließen. Der Callback an `localhost:1455` läuft jetzt durch den Tunnel zurück zum Container.

Ohne Tunnel bleibt die CLI bei „Waiting for Codex authentication callback...“ stehen und bietet nach etwa 15 Sekunden `Paste the Codex callback URL (or press Enter to keep waiting):` an. Dann einfach die vollständige Callback-URL aus der Adressleiste des Browsers einfügen – das ist der CLI-eigene manuelle Weg, kein Workaround.

Wenn dieser Schritt nicht wirklich abgeschlossen wird, helfen die folgenden Schritte nicht weiter. Beim ersten Durchlauf würde ich deshalb zwei Dinge genau beobachten: die Ausgabe von `docker compose logs -f` und das gemountete `auth/`-Verzeichnis. Wenn der OAuth-Flow angeblich erfolgreich war, aber dort nichts Brauchbares landet, existiert noch kein belastbarer Proxy-Status.

## config.yaml-Feldreferenz (v8)

Das minimale `config.yaml` weiter oben in diesem Guide nutzt die älteren Top-Level-Schreibweisen (`host`, `port`, `auth-dir`, `api-keys`, `remote-management`). Sie laden weiterhin problemlos, aber das Upstream-Projekt ist zu einem `v8`-Layout (`config-version: 8`) gewechselt, in dem jede Einstellung unter einem benannten Abschnitt lebt. Wer Beispiele aus der aktuellen `config.example.yaml` des Upstream-Repositories kopiert, sieht das neue Layout – hier also eine Feld-für-Feld-Zuordnung für die Einstellungen, die ein Codex-Proxy-Setup tatsächlich berührt. Jeder Feldname unten ist gegen die `config.example.yaml` des Upstream auf dem Main-Branch verifiziert (geprüft am 2026-10-14). Plus-Forks können abweichen; prüfe deren gepinntes Image/deren Version und `config.example.yaml`, bevor du dieses Layout für sie voraussetzt.

| Feld (v8) | Alte Schreibweise | Bedeutung |
|---|---|---|
| `config-version: 8` | — | Deklariert das v8-Layout. Sind beide Schreibweisen eines Felds vorhanden, gewinnt der v8-Wert. |
| `server.host` | `host` | Interface, an das gebunden wird. Ein leerer String bindet alle Interfaces. |
| `server.port` | `port` | Der API-Port, den Clients aufrufen. `8317` in diesem Guide. |
| `oauth.auth-dir` | `auth-dir` | Wo der Codex-OAuth-Status gespeichert wird. Muss zum `auth/`-Mount passen, sonst gehen Logins beim Neustart verloren. |
| `access.api-keys` | `api-keys` | Downstream-Keys für deine Clients. Das sind *keine* Upstream-OpenAI-Zugangsdaten. |
| `management.allow-remote` | `remote-management.allow-remote` | Auf `false` lassen, solange es keinen echten Grund gibt, die Management-API freizugeben. |
| `management.secret-key` | `remote-management.secret-key` | Key für die Management-API. Leer lassen deaktiviert die Management-API komplett. |
| `client.codex.optimize-multi-agent-v2` | — | Optional. Optimiert Codex-Desktop- und codex-tui-Requests für Multi-Agent-Setups. Standard `false`. |

Eine minimale v8-Konfiguration für das Setup in diesem Guide sieht so aus:

```yaml
config-version: 8

server:
  host: ""
  port: 8317

oauth:
  auth-dir: "~/.cli-proxy-api"

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

management:
  allow-remote: false
  secret-key: ""
```

Zwei Details sind es wert, eigens genannt zu werden. Erstens: `access.api-keys` ist dieselbe Liste wie das alte `api-keys` – Keys, die du an Downstream-Clients vergibst, niemals Upstream-Secrets. Zweitens löst `oauth.auth-dir` im Container standardmäßig zu `/root/.cli-proxy-api` auf – genau deshalb mountet die Compose-Datei `./auth` dorthin. Änderst du eine Seite ohne die andere, kommt der „gestern lief es, nach dem Neustart ist der Login weg“-Fehler aus dem vorherigen Abschnitt direkt zurück.

## Docker Compose: der eigenständige Weg

Das Begleit-Repository oben in diesem Guide automatisiert alles Folgende in einem Skript. Wer lieber jede Datei selbst besitzt und genau sehen will, was läuft, bekommt hier dasselbe Setup als eigenständiges Compose-Projekt – ganz ohne Hilfsskripte.

Dasselbe kleine Verzeichnis behalten:

```text
/opt/cliproxyapi/
├── docker-compose.yml
├── config.yaml
└── auth/
```

Die Compose-Datei ist dieselbe wie im Server-Abschnitt oben – dieselben `127.0.0.1`-gebundenen Ports, dieselben Mounts, aus der eigenen `docker-compose.yml` des Upstream-Repositories zusammengestellt und auf das zugeschnitten, was dieser Guide braucht. Ich wiederhole sie hier nicht, weil es genau eine Datei geben sollte, die korrekt gehalten wird; kopiere sie von oben. Der `./auth`-Mount muss weiterhin dort landen, wohin `oauth.auth-dir` zeigt, sonst geht der OAuth-Status bei jedem Container-Neubau verloren.

Hochfahren und den Start beobachten:

```bash
docker compose config
docker compose up -d
docker compose logs -f
```

Der erste Befehl ist eine gute Gewohnheit: `docker compose config` rendert die effektive Datei, ohne etwas zu starten – ein kostenloser statischer Check, der Einrückungsfehler und falsche Mount-Pfade abfängt, bevor sie zu Laufzeit-Rätseln werden.

Dann den Codex-Login genau wie im vorherigen Abschnitt ausführen:

```bash
docker compose exec cli-proxy-api /CLIProxyAPI/CLIProxyAPI -no-browser --codex-login
```

Eine ehrliche Einschränkung: Jedes Feld der Compose-Datei oben ist gegen die `docker-compose.yml` des Upstream-Repositories und die bereits in diesem Guide gezeigte Konfiguration verifiziert, aber ich habe genau diese Datei für dieses Update nicht auf einer echten Maschine ausgeführt. Wenn deine Umgebung abweicht – rootless Docker, ein nicht standardmäßiges Datenverzeichnis – sind die Volume-Pfade das Erste, was du prüfen solltest.

## Clientseite: Codex-Client und Nginx konfigurieren

Danach kommt der Teil, der anfangs etwas kontraintuitiv wirkt. Selbst wenn der Proxy Codex-OAuth erfolgreich abgeschlossen hat, muss die lokale Codex-App weiterhin neu konfiguriert werden. Laut offizieller CLIProxyAPI-Seite für den Codex-Client bedeutet das, `~/.codex/config.toml` und `~/.codex/auth.json` anzupassen.

Hilfreich ist das Modell von zwei getrennten Key-Ebenen. Upstream hält der Proxy den echten OAuth-Status und das Token-Material, mit dem er im Namen des Codex-Zugangs arbeiten kann. Downstream braucht jeder Client oder jede App lediglich die Berechtigung, den eigenen Proxy aufzurufen. Genau diese Trennung macht das Setup interessant, sobald mehr als ein Tool beteiligt ist: Upstream einmal authentifizieren, danach Downstream-Zugriff kontrolliert verteilen.

Für einen entfernten Server hinter einer eigenen Domain würde ich `config.toml` als den Ort betrachten, an dem Codex von „direkt zu OpenAI“ auf „meinen Proxy-Provider verwenden“ umgestellt wird:

```toml
model_provider = "cliproxyapi"
model = "gpt-5-codex"
model_reasoning_effort = "high"

[model_providers.cliproxyapi]
name = "cliproxyapi"
base_url = "https://codex-proxy.example.com/v1"
wire_api = "responses"
```

Zwei Fehler sieht man hier immer wieder. Erstens bleibt `base_url` auf einem localhost-Beispiel stehen, obwohl der Proxy tatsächlich auf einem entfernten Server läuft. Zweitens fehlt `wire_api = "responses"`. Die CLIProxyAPI-Dokumentation verwendet für Codex ausdrücklich das Wire-Format `responses`. Lässt man diese Zeile weg, entstehen leicht seltsame Client-Fehler, die deutlich schwerer wirken, als ihre Ursache ist.

Danach folgt `auth.json`, das die offizielle Dokumentation bewusst minimal hält:

```json
{
  "OPENAI_API_KEY": "<proxy-api-key>"
}
```

Bei `<proxy-api-key>` sollte man kurz überlegen – aber nur darüber, **welcher** Key dort hingehört, nicht darüber, ob er relevant ist. Er muss zu den Keys aus der `api-keys`-Liste in `config.yaml` gehören: also der Downstream-Proxy-Key aus Schritt 6 der Schnelleinrichtung. CLIProxyAPI behandelt diese Keys als Client-Zugangsdaten. Genau diesen Key präsentiert der lokale Codex-Client beim Gespräch mit dem Proxy. Er ist weiterhin **kein** echter OpenAI-Upstream-Key; das Routing steckt in `config.toml`, vor allem im Provider-Block und im Proxy-`base_url`.

Soll der Dienst zusätzlich hinter Nginx liegen und HTTPS bekommen, ist das eigentliche Proxying unkompliziert. Beim Pfad `/v1/` würde ich bewusst keine unnötige Magie einbauen. Pfad erhalten, keine überflüssigen Rewrite-Regeln:

```nginx
server {
  listen 443 ssl http2;
  server_name codex-proxy.example.com;

  location /v1/ {
    proxy_pass http://127.0.0.1:8317/v1/;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}
```

Sobald dieser Endpunkt stabil ist, geht sein Nutzen weit über die Codex-Desktop-App hinaus. Viele selbst gehostete Tools benötigen lediglich eine OpenAI-kompatible Base-URL und eine API-Key-artige Zugangsinformation. Ab diesem Punkt ist die Architektur nicht mehr „ein spezieller Proxy für Codex“, sondern eher „mein einheitliches AI-Gateway“. Typische Umgebungsvariablen solcher Projekte sehen so aus:

```bash
OPENAI_BASE_URL=https://codex-proxy.example.com/v1
OPENAI_API_KEY=<proxy-api-key-for-this-project>
```

Hier zahlt sich die Architektur wirklich aus. Der schwere Teil – Upstream-OAuth, Account-Status, Provider-Routing und mögliche Multi-Account-Regeln – bleibt in CLIProxyAPI. Jedes Downstream-Projekt braucht nur einen stabilen Endpunkt und seinen eigenen Proxy-Key. Wenn später der Upstream wechselt, weitere Accounts hinzukommen, sich die Routing-Strategie ändert oder Traffic zwischen Tools verschoben werden soll, geschieht das an einer Stelle statt in jedem Client und jeder App.

Das wird besonders nützlich, wenn bereits unterschiedliche Tools betrieben werden. Vielleicht übernimmt Codex den Coding-Workflow, ein selbst gehostetes Chat-Frontend das tägliche Prompting und ein kleiner interner Skript- oder Agent-Dienst die Automation. Ohne gemeinsames Gateway entwickelt jede dieser Anwendungen schnell ihre eigene Secret-Geschichte. Mit einem Proxy in der Mitte bleibt der langlebige Upstream-Status an einer Stelle, während die Downstream-Seite deutlich einfacher wird: Welches Projekt bekommt welchen Proxy-Key und welchen Endpunkt soll es aufrufen? Genau dann fühlt sich die Lösung nicht mehr wie ein „spezieller Codex-Trick“ an, sondern wie normale Infrastruktur.

## Die häufigsten Fehlerquellen

In der Praxis liegen die häufigsten Fehler meist gar nicht bei Docker. Typisch sind stattdessen:

- der Proxy-Container läuft, aber das gemountete `auth/`-Verzeichnis hat nie wirklich Codex-OAuth-Status erhalten
- die lokale Client-Konfiguration wurde geändert, `base_url` zeigt aber noch auf localhost
- der Domain-Proxy existiert, doch `/v1/` fehlt oder wurde umgeschrieben
- `wire_api = "responses"` wurde weggelassen
- jemand nimmt an, `auth.json` benötige ein echtes OpenAI-Upstream-Secret und verteilt dadurch wieder Zugangsdaten, die dort gar nicht nötig sind

Genau darin liegt auch der klarste Unterschied zum direkten Login. Direkter Login ist einfacher, weil Authentifizierung und Client-Verhalten an einer Stelle bleiben. CLIProxyAPI teilt das System dagegen in Dienstlaufzeit, gespeicherten OAuth-Status, Reverse Proxying und Client-Konfiguration. Das bedeutet am Anfang mehr Einrichtung, ergibt aber eine wesentlich wiederverwendbarere Form, sobald Codex Teil einer größeren Umgebung werden soll statt nur eine einzelne lokale App zu sein.

Lohnt sich das? Für mich ist die sauberste Antwort: Direkter Login ist besser, wenn das Ziel lautet „Ich möchte Codex jetzt auf diesem Rechner verwenden.“ CLIProxyAPI ist besser, wenn das Ziel lautet „Codex soll Teil meiner eigenen kontrollierten AI-Tooling-Schicht werden.“ Das eine reduziert Reibung. Das andere schafft Raum für Standardisierung, Wiederverwendung und spätere Erweiterung. Und dieser Trade-off wird deutlich attraktiver, sobald mehr als ein Consumer dieselbe Upstream-Fähigkeit nutzen soll. Teilen einige selbst gehostete Tools denselben AI-Backend-Zugang, fühlt sich zentrale Authentifizierung mit Downstream-Keys meist wesentlich sauberer an als verstreute Secrets und Login-Zustände in jedem einzelnen Projekt.

Wer den zweiten Weg geht, sollte `config.yaml` und `auth/` außerdem wie echten Zustand behandeln und nicht wie wegwerfbare Setup-Dateien. Beim Recovery tut selten das erneute Pullen eines Images weh. Problematisch sind die kleinen Auth- und Config-Bausteine, von denen man dachte, sie ließen sich jederzeit problemlos rekonstruieren.

Wenn du bereits einen größeren Codex-Workflow aufbaust, ist [Was sich im neuen Codex geändert hat und warum es sich mehr wie eine Entwicklungsumgebung anfühlt](/de/posts/what-changed-in-the-new-codex/) eine passende Ergänzung. Und wenn dieser Proxy länger auf einem VPS laufen soll, passt [Docker-Volumes zu GitHub sichern: kostengünstiges Disaster Recovery für 1Panel](/de/posts/docker-volume-backup-github-sync/) ebenfalls gut dazu – denn Auth- und Config-Zustand wirkt nur so lange theoretisch, bis man ihn schnell wiederherstellen muss.
