์ฌ๋ฌ ChatGPT ๊ณ์ ์ ๋ฌถ์ด์ ์ฌ์ฉ๋์ ๊ด๋ฆฌํ๊ณ , Codex CLI๋ OpenAI ํธํ ํด๋ผ์ด์ธํธ์์ ๊ณตํต ์๋ํฌ์ธํธ๋ก ๋ถ์ ์ ์๊ฒ ํด์ฃผ๋ ํ๋ก์์ ๋๋ค. ๋์๋ณด๋์์ ๊ณ์ , API ํค, ์ฌ์ฉ๋, ์ต๊ทผ ์์ฒญ์ ํ ๊ณณ์์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
์ด ํฌํฌ codex-lb-cinamon์ codex-lb๋ฅผ ๊ธฐ๋ฐ์ผ๋ก, OpenAI Platform API key๋ฅผ ๋ณด์กฐ upstream์ผ๋ก ๋ฑ๋กํด ChatGPT ๊ณ์ ๋ค์ ์ฌ์ฉ๋์ด ๋ชจ๋ ์์ง๋์์ ๋ fallback์ผ๋ก ์ฌ์ฉํ ์ ์๋๋ก ์์ ํ ๋ฒ์ ์
๋๋ค. ์ฆ ๊ธฐ๋ณธ ๊ฒฝ๋ก๋ ๊ณ์ ChatGPT ๊ณ์ ํ์ ์ฌ์ฉํ๊ณ , ํ์ํ ๋๋ง Platform API๋ก ์ฐํํ๋ ๊ฐ์ธ/์ฌ๋ด ์ด์์ฉ ํฌํฌ๋ฅผ ๋ชฉํ๋ก ํฉ๋๋ค.
openai_platform์ ์ฌ์ ํ fallback ์ ์ฉ์ ๋๋ค. ์ต์ 1๊ฐ์ ํ์ฑchatgpt_web๊ณ์ ์ด ์์ด์ผ ๋ฑ๋ก๊ณผ ๋ผ์ฐํ ์ด ๊ฐ๋ฅํฉ๋๋ค.- ์ผ๋ฐ fallback์ ๋ชจ๋ ํธํ ChatGPT ๊ณ์ ์ด drain ๊ธฐ์ค์ ๋์์ ๋๋ง ํ์ฑํ๋ฉ๋๋ค.
- ๊ธฐ๋ณธ ๊ธฐ์ค:
primary remaining <= 10%,secondary remaining <= 5%
- ๊ธฐ๋ณธ ๊ธฐ์ค:
CODEX_LB_PLATFORM_FALLBACK_FORCE_ENABLED=true๋ฅผ ์ฃผ๋ฉด usage drain ์ฌ๋ถ์ ๋ฌด๊ดํ๊ฒ fallback ํ์ ์ ๊ฐ์ ํ ์ ์์ต๋๋ค.backend_codex_http๋ฅผ ์ผ๋ฉด HTTPGET /backend-api/codex/models์ HTTPPOST /backend-api/codex/responses๊ฐ Platform fallback ํ๋ณด๊ฐ ๋ฉ๋๋ค.- HTTP
POST /backend-api/codex/responses์์session_id,x-codex-session-id,x-codex-conversation-id,x-codex-turn-state๊ฐ์ Codex ์ธ์ ํค๋๋ fallback์ ๋ง์ง ์์ต๋๋ค. - ํ์ง๋ง payload์
conversation๋๋previous_response_id๋ ์ฌ์ ํ Platform์์ ์ง์ํ์ง ์์ผ๋ฏ๋ก fallback ๋์์ด ์๋๋๋ค. - websocket
/backend-api/codex/responses,/v1/chat/completions, compact ๊ฒฝ๋ก๋ phase 1์์ Platform fallback์ ์ง์ํ์ง ์์ต๋๋ค.
- ์ฌ๋ฌ ChatGPT ๊ณ์ ์ ํ ํ๋ก ๋ฌถ์ด์ ๋ก๋๋ฐธ๋ฐ์ฑ
- ๊ณ์ ๋ณ ์ฌ์ฉ๋, ํ ํฐ, ๋น์ฉ, ์ต๊ทผ ์ถ์ด ํ์ธ
- ๋์๋ณด๋์์ API ํค ๋ฐ๊ธ ๋ฐ ํค๋ณ ์ ํ ์ค์
- Codex CLI, OpenCode, OpenClaw, OpenAI SDK์ ์ฐ๋
- ์ ์คํธ๋ฆผ ๋ชจ๋ธ ๋ชฉ๋ก ์๋ ๋๊ธฐํ
- ๋์๋ณด๋ ๋น๋ฐ๋ฒํธ ๋ฐ ์ ํํ TOTP ์ธ์ฆ
PyPI๋ก ์ค์น:
macOS / Linux:
python3.13 -m venv .venv
source .venv/bin/activate
pip install codex-lb-cinamon
codex-lb-cinamon start
# ๋์ ์ํ ํ์ธ
codex-lb-cinamon status
# ์ข
๋ฃ ์
codex-lb-cinamon shutdownWindows PowerShell:
py -3.13 -m venv .venv
.venv\Scripts\Activate.ps1
pip install codex-lb-cinamon
codex-lb-cinamon start
# ๋์ ์ํ ํ์ธ
codex-lb-cinamon status
# ์ข
๋ฃ ์
codex-lb-cinamon shutdownํฌ๊ทธ๋ผ์ด๋๋ก ๋ช ์ ์คํ:
codex-lb-cinamon servemacOS ๋ฉ๋ด๋ฐ ์ฑ ์คํ:
# ๋ฉ๋ด๋ฐ ์ฑ์์ ์๋ฒ ์์/์ข
๋ฃ๊น์ง ํจ๊ป ์ ์ด
codex-lb-cinamon menubar --manage-server --start-on-launch๊ฐ๋ฐ ์ฒดํฌ์์์์ ์คํํ๋ค๋ฉด ๊ฐ์ ๋ช
๋ น ์์ uv run์ ๋ถ์ด๋ฉด ๋ฉ๋๋ค.
uv run codex-lb-cinamon menubar --manage-server --start-on-launchํฐ๋ฏธ๋ ์์ด ์ํด๋ฆญ์ผ๋ก ์คํํ๋ ค๋ฉด Finder์์ repo ๋ฃจํธ ํด๋๋ฅผ ์ด๊ณ CodexLBCinamonMenubar.app ์์ด์ฝ์ ๋๋ธํด๋ฆญํฉ๋๋ค.
/Users/jacob/Workspace/codex-lb-cinamon/CodexLBCinamonMenubar.app
์์ฃผ ์ด๋ค๋ฉด ์ด .app ์์ด์ฝ์ Dock์ ๋์ด๋ค ๋๊ณ Dock์์ ํด๋ฆญํ๋ฉด ๋ฉ๋๋ค. ์ด ๋ฐ์ฒ๋ repo ๋ฃจํธ์ ๋ ๊ฐ๋ฐ ์ฒดํฌ์์์ฉ ์ฑ ๋ฒ๋ค์ด๋ฉฐ, ๋ด๋ถ์ ์ผ๋ก .venv/bin/python -m app.cli menubar --manage-server --start-on-launch๋ฅผ ๋ฐฑ๊ทธ๋ผ์ด๋๋ก ์คํํฉ๋๋ค.
menubar --manage-server๋ macOS ์๋จ ๋ฉ๋ด๋ฐ์์ ์๋ฒ ์์/์ข
๋ฃ, ์ํ ์๋ก๊ณ ์นจ, ๋์๋ณด๋ ์ด๊ธฐ, ๋ก๊ทธ ์ด๊ธฐ, codex-provider sync ์คํ์ ์ ์ดํฉ๋๋ค. --start-on-launch๋ฅผ ํจ๊ป ์ฃผ๋ฉด ๋ฉ๋ด๋ฐ ์ฑ ์์ ์ ์ถ์ ๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์๋ฒ๊ฐ ์์ ๋ ์๋์ผ๋ก ์๋ฒ๋ฅผ ์์ํฉ๋๋ค.
Sync Providers ๋ฉ๋ด๋ codex-provider ์คํ ํ์ผ์ด ํ์ํฉ๋๋ค. LaunchAgent๋ Dock ์คํ์ shell PATH๋ฅผ ๊ทธ๋๋ก ์์ํ์ง ์์ ์ ์์ผ๋ฏ๋ก, ์๋ ๊ฐ์ง๊ฐ ์คํจํ๋ ํ๊ฒฝ์์๋ CODEX_PROVIDER_BIN์ ์ ๋๊ฒฝ๋ก๋ฅผ ์ง์ ํ์ธ์.
export CODEX_PROVIDER_BIN=/opt/homebrew/bin/codex-provider์ด ๋ช
๋ น์ ๋ฉ๋ด๋ฐ ์ฑ ์์ฒด๋ฅผ ํฐ๋ฏธ๋ foreground ํ๋ก์ธ์ค๋ก ์คํํฉ๋๋ค. ๋ฐ๋ผ์ ํฐ๋ฏธ๋์ ๋ซ์ผ๋ฉด ๋ฉ๋ด๋ฐ ์ฑ๋ ํจ๊ป ์ข
๋ฃ๋ฉ๋๋ค. --manage-server์ --start-on-launch๋ ์ถ์ ๋ API ์๋ฒ๋ฅผ ๋ฐฑ๊ทธ๋ผ์ด๋๋ก ์์ํ๊ณ ๊ด๋ฆฌํ๋ ์ต์
์ด๋ฉฐ, ๋ฉ๋ด๋ฐ ์ฑ ํ๋ก์ธ์ค๋ฅผ macOS ๋ก๊ทธ์ธ ํญ๋ชฉ์ด๋ LaunchAgent๋ก ๋ฑ๋กํ์ง๋ ์์ต๋๋ค.
ํฐ๋ฏธ๋๊ณผ ๋ถ๋ฆฌํด์ ์คํํ๋ ค๋ฉด nohup์ผ๋ก detached ์คํํ ์ ์์ต๋๋ค.
mkdir -p ~/.codex-lb
nohup uv run codex-lb-cinamon menubar --manage-server --start-on-launch \
> ~/.codex-lb/menubar.log 2>&1 &
disown์ผ์์ ์ผ๋ก ๊ณ์ ์ฌ์ฉํ ๋๋ macOS LaunchAgent ๋ฑ๋ก์ ๊ถ์ฅํฉ๋๋ค. ๋จผ์ ํ์ฌ checkout์ ์ ์ญ ๋๊ตฌ๋ก ์ค์นํฉ๋๋ค.
uv tool install --reinstall .uv๊ฐ /Users/jacob/.local/bin์ด PATH์ ์๋ค๊ณ ์๋ดํ๋ฉด, LaunchAgent์ ProgramArguments์๋ /Users/jacob/.local/bin/codex-lb-cinamon์ฒ๋ผ ์ ๋๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํฉ๋๋ค. ํฐ๋ฏธ๋์์ codex-lb-cinamon๋ง ์
๋ ฅํด ์ต์ ์ค์น๋ณธ์ ์ฐ๋ ค๋ฉด ~/.local/bin์ shell PATH ์์ชฝ์ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
๊ทธ๋ค์ ~/Library/LaunchAgents/com.cinev.codex-lb-cinamon.menubar.plist์ ์๋์ฒ๋ผ ๋ฑ๋กํ๋ฉด ๋ก๊ทธ์ธ ์ ๋ฉ๋ด๋ฐ ์ฑ์ด ์๋์ผ๋ก ์คํ๋๊ณ , ๋ฉ๋ด๋ฐ ์ฑ์ด ์๋ฒ๋ฅผ ํจ๊ป ๊ด๋ฆฌํฉ๋๋ค.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.cinev.codex-lb-cinamon.menubar</string>
<key>ProgramArguments</key>
<array>
<string>/Users/jacob/.local/bin/codex-lb-cinamon</string>
<string>menubar</string>
<string>--manage-server</string>
<string>--start-on-launch</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>EnvironmentVariables</key>
<dict>
<key>CODEX_PROVIDER_BIN</key>
<string>/opt/homebrew/bin/codex-provider</string>
</dict>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>StandardOutPath</key>
<string>/Users/jacob/.codex-lb/menubar.launchd.out.log</string>
<key>StandardErrorPath</key>
<string>/Users/jacob/.codex-lb/menubar.launchd.err.log</string>
</dict>
</plist>๋ฑ๋ก ํ ์ฆ์ ์์ํ๋ ค๋ฉด ํ์ฌ macOS ์ฌ์ฉ์ UID๋ฅผ ํ์ธํ ๋ค bootstrap/kickstart๋ฅผ ์คํํฉ๋๋ค.
id -u
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.cinev.codex-lb-cinamon.menubar.plist
launchctl kickstart -k gui/$(id -u)/com.cinev.codex-lb-cinamon.menubarํด์ ํ๋ ค๋ฉด ์๋ ๋ช ๋ น์ ์ฌ์ฉํฉ๋๋ค.
launchctl bootout gui/$(id -u)/com.cinev.codex-lb-cinamon.menubar์ด๋ฏธ ์คํ ์ค์ธ ์๋ฒ๋ง ์ฝ๊ณ ์ถ๋ค๋ฉด ๊ธฐ์กด์ฒ๋ผ base URL์ ์ง์ ํด ์ํ ์ฑ์ผ๋ก๋ง ์คํํ ์ ์์ต๋๋ค.
codex-lb-cinamon menubar --base-url http://127.0.0.1:2455๊ธฐ๋ณธ PID ํ์ผ๊ณผ ๋ก๊ทธ ํ์ผ์ ์๋ ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํฉ๋๋ค.
macOS / Linux: ~/.codex-lb/server.pid
macOS / Linux: ~/.codex-lb/server.log
Windows: %USERPROFILE%\.codex-lb\server.pid
Windows: %USERPROFILE%\.codex-lb\server.log
์ํ๋ฉด start์๋ --pid-file, --log-file, --host, --port๋ฅผ ํจ๊ป ์ค ์ ์๊ณ , serve์๋ --host, --port, --ssl-certfile, --ssl-keyfile๋ฅผ ํจ๊ป ์ค ์ ์์ต๋๋ค. menubar --manage-server๋ ๊ฐ์ ์๋ฒ bind/TLS ์ต์
๊ณผ --pid-file, --log-file, --startup-timeout์ ์ง์ํฉ๋๋ค.
์๊ฒฉ์์ ์ฒ์ ๋์๋ณด๋ ๋น๋ฐ๋ฒํธ๋ฅผ ์ค์ ํ ๋๋ bootstrap token์ด ํ์ํฉ๋๋ค.
์๋ ์์ฑ(๊ธฐ๋ณธ):
docker logs codex-lb-cinamon
# ============================================
# Dashboard bootstrap token (first-run):
# <token>
# ============================================๋น๋ฐ๋ฒํธ๊ฐ ์์ง ์๊ณ CODEX_LB_DASHBOARD_BOOTSTRAP_TOKEN ์ ์ง์ ํ์ง ์์๋ค๋ฉด ์๋ฒ๊ฐ 1ํ์ฉ bootstrap token์ ์์ฑํด ๋ก๊ทธ์ ๋จ๊น๋๋ค. ์ฌ๋ฌ replica๊ฐ ๊ฐ์ ์ํธํ ํค๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ์์ ๋ค์๋ ๊ฐ์ ํ ํฐ์ ๋ณต๊ตฌํด ๋ค์ ๋ก๊ทธ๋ก ํ์ธํ ์ ์์ต๋๋ค.
์๋ ์ง์ :
docker run -d --name codex-lb-cinamon \
-e CODEX_LB_DASHBOARD_BOOTSTRAP_TOKEN=your-secret-token \
-p 2455:2455 -p 1455:1455 \
-v codex-lb-cinamon-data:/var/lib/codex-lb \
ghcr.io/cinev/codex-lb-cinamon:latestlocalhost ๋ host-OS bypass ๋ก ๋ถ๋ฅ๋๋ ์์ฒญ์ bootstrap token ์์ด๋ ์ด๊ธฐ ์ค์ ์ ์งํํ ์ ์์ต๋๋ค.
DB ๋ง์ด๊ทธ๋ ์ด์ ์ ์๋์ผ๋ก ์คํํด์ผ ํ๋ฉด:
codex-lb-cinamon-db upgrade head๋ธ๋ผ์ฐ์ ์์ http://localhost:2455 ๋ก ์ ์ํ ๋ค ๊ณ์ ์ ์ถ๊ฐํ๋ฉด ๋ฐ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ปจํ ์ด๋ ์คํ:
docker volume create codex-lb-cinamon-data
docker run -d --name codex-lb-cinamon \
-p 2455:2455 -p 1455:1455 \
-v codex-lb-cinamon-data:/var/lib/codex-lb \
-e CODEX_LB_HTTP_RESPONSES_SESSION_BRIDGE_INSTANCE_ID=codex-lb-cinamon-local \
-e CODEX_LB_INSECURE_ALLOW_REMOTE_NO_AUTH=true \
-e CODEX_LB_INSECURE_ALLOW_REMOTE_NO_AUTH_HOST_CIDRS=172.17.0.0/16 \
ghcr.io/cinev/codex-lb-cinamon:latest๋๋ ๋ก์ปฌ ์คํ:
uvx codex-lb-cinamon๋ช
๋ น์ serve์ ๋์ผํ๊ฒ foreground ์๋ฒ๋ฅผ ๋ฐ๋ก ๋์ฐ๋ฉฐ, ํ์ํ๋ฉด ์ถ๊ฐ ์ธ์๋ฅผ ๊ทธ๋๋ก ๋๊ธธ ์ ์์ต๋๋ค.
์ปจํ ์ด๋๋ก ์คํํ ๋๋ ์๋ ์ค์ ์ ํจ๊ป ์ฃผ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
CODEX_LB_HTTP_RESPONSES_SESSION_BRIDGE_INSTANCE_ID=codex-lb-cinamon-local- ์ปจํ ์ด๋ ์ฌ์์ ์ bridge instance id๊ฐ ํ๋ค๋ฆฌ์ง ์๊ฒ ํด์ ์ธ์ ๋ธ๋ฆฌ์ง ์์ ์ฑ์ ๋์ ๋๋ค.
CODEX_LB_INSECURE_ALLOW_REMOTE_NO_AUTH=true- ๋ก์ปฌ ๋คํธ์ํฌ๋ ์ฌ๋ด ๊ฐ์ธ์ฉ์ฒ๋ผ ์ ํ๋ ํ๊ฒฝ์์ ๋ก๊ทธ์ธ, bootstrap, proxy API key ์ธ์ฆ ์์ด ๋ฐ๋ก ๋ถ์ ์ ์๊ฒ ํฉ๋๋ค.
- ํ ์คํธ/๋ด๋ถ ์ฌ์ฉ ์ ์ฉ์ด๋ฉฐ, ์ธ๋ถ์ ๋ ธ์ถ๋๋ ํ๊ฒฝ์๋ ๊ถ์ฅํ์ง ์์ต๋๋ค.
Docker๋ฅผ ์ด๋ค๋ฉด ์๋ CIDR ์ค์ ๋ ํจ๊ป ์ฃผ๋ ํธ์ด ์์ ํฉ๋๋ค.
CODEX_LB_INSECURE_ALLOW_REMOTE_NO_AUTH_HOST_CIDRS=172.17.0.0/16- Docker bridge ํ๊ฒฝ์์ ํธ์คํธ OS์์ ๋ค์ด์ค๋ ์์ฒญ๋ง ๋ฌด์ธ์ฆ์ผ๋ก ํ์ฉํ๋ ค๋ฉด ํจ๊ป ์ฃผ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
- Docker ๊ธฐ๋ณธ bridge ๋์ญ ์์์ ๋๋ค. ๋คํธ์ํฌ ์ค์ ์ด ๋ค๋ฅด๋ฉด ์ค์ bridge CIDR์ ๋ง๊ฒ ๋ฐ๊ฟ์ผ ํฉ๋๋ค.
Podman์ ์ด๋ค๋ฉด ์ CIDR ๊ฐ์ ๊ทธ๋๋ก ์ฐ์ง ๋ง๊ณ , ํ๊ฒฝ์ ๋ง๋ bridge ๋์ญ์ ๋ฃ๊ฑฐ๋ ์๋ ๊ฐ์ง์ ๋งก๊ธฐ์ธ์. ์๋ฅผ ๋ค์ด rootless Podman์ 10.88.0.0/16 ๊ณ์ด์ธ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
Podman์ rootless๋ก ์ฐ๊ธฐ ์ฝ๊ณ ๋น๊ต์ ๊ฐ๋ฒผ์ด ์ปจํ ์ด๋ ๋ฐํ์์ด๋ผ, Docker๊ฐ ๋ฌด๊ฒ๋ค๊ณ ๋๊ปด์ง๋ฉด ํ ๋ฒ ์จ๋ณผ ๋งํฉ๋๋ค.
- ๋์๋ณด๋์ ์ ์ํฉ๋๋ค.
- ChatGPT ๊ณ์ ๊ณผ Platform API Key๋ฅผ ์ถ๊ฐํฉ๋๋ค.
- ํด๋ผ์ด์ธํธ์์
codex-lb-cinamon์๋ํฌ์ธํธ๋ฅผ ์ฌ์ฉํ๋๋ก ์ค์ ํฉ๋๋ค.
๋์๋ณด๋์์ Platform ํค๋ฅผ ๋ฃ์ ๋๋ Accounts ํ์ด์ง์์ Add OpenAI Platform API key๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
์ ๋ ฅ ํญ๋ชฉ:
Label: ๋์๋ณด๋์์ ๊ตฌ๋ถํ ์ด๋ฆAPI key: OpenAI Platform API ํคOrganization,Project: ์ฐ๋ ๊ฒฝ์ฐ๋ง ์ ๋ ฅ, ๋น์๋ฌ๋ ๋จ
์ค์:
- Platform API key๋ ๋จ๋ ์ผ๋ก ์ธ ์ ์์ต๋๋ค. ๋จผ์ ํ์ฑ ChatGPT ๊ณ์ ์ด ์ต์ 1๊ฐ ์์ด์ผ ๋ฑ๋ก๋ฉ๋๋ค.
Eligible routes๋ฅผ ํ๋๋ ์ฒดํฌํ์ง ์์ผ๋ฉด ๋ฑ๋ก์ ๋์ด๋ ์ค์ ๋ผ์ฐํ ์๋ ์ฐ์ด์ง ์์ต๋๋ค.
Codex app์ด๋ Codex CLI์ ๋ถ์ผ ๊ฑฐ๋ฉด Eligible routes์ ์ฒดํฌ๋ฐ์ค 3๊ฐ๋ฅผ ์ ๋ถ ์ฒดํฌํ์ธ์.
Fallback HTTP /v1/modelsFallback stateless HTTP /v1/responsesFallback HTTP /backend-api/codex
๊ฐ์ฅ ๋จ์ํ ๊ธฐ์ค์ผ๋ก ๋ณด๋ฉด:
- Codex app / Codex CLI ์ฌ์ฉ: ์ 3๊ฐ ์ ๋ถ ์ฒดํฌ
- ์ผ๋ฐ OpenAI ํธํ
/v1ํด๋ผ์ด์ธํธ๋ง ์ฌ์ฉ: ๋ณดํต/v1/models,/v1/responses์ชฝ๋ง ์ฒดํฌํ๋ฉด ๋จ
OpenAI ํธํ ํด๋ผ์ด์ธํธ๋ ๋ชจ๋ codex-lb-cinamon์ upstream์ฒ๋ผ ์ฌ์ฉํ ์ ์์ต๋๋ค. API ํค ์ธ์ฆ์ ์ผ ๊ฒฝ์ฐ ๋์๋ณด๋์์ ๋ฐ๊ธํ ํค๋ฅผ Bearer ํ ํฐ์ผ๋ก ๋ฃ์ด์ผ ํฉ๋๋ค.
| ํด๋ผ์ด์ธํธ | ์๋ํฌ์ธํธ | ์ค์ ์์น |
|---|---|---|
| Codex CLI | http://127.0.0.1:2455/backend-api/codex |
~/.codex/config.toml |
| OpenCode | http://127.0.0.1:2455/v1 |
~/.config/opencode/opencode.json |
| OpenClaw | http://127.0.0.1:2455/v1 |
~/.openclaw/openclaw.json |
| OpenAI Python SDK | http://127.0.0.1:2455/v1 |
์ฝ๋์์ ์ค์ |
Codex CLI / IDE ํ์ฅ
~/.codex/config.toml:
๊ฐ์ฅ ์ฝ๊ฒ ๋งํ๋ฉด:
model_provider = "codex-lb-cinamon"๋ ํ์ผ ๋งจ ์์ ๋ฃ์ต๋๋ค.[model_providers.codex-lb-cinamon]๋ธ๋ก์ ํ์ผ ๋งจ ์๋์ ๋ฃ์ต๋๋ค.
- ๋จผ์ ์๋ 1์ค์ ํ์ผ ๋งจ ์์ ๋ฃ์ต๋๋ค.
[ ... ]๋ก ์์ํ๋ ๋ค๋ฅธ ์น์ ์์ ๋ฃ์ผ๋ฉด ์ ๋ฉ๋๋ค.model์ด๋model_reasoning_effort๋ ์ฌ๊ธฐ์ ๊ฑด๋๋ฆด ํ์ ์์ต๋๋ค.- ์ด๋ฏธ
model_provider๊ฐ ์๋ค๋ฉด ๊ทธ ๊ฐ๋งcodex-lb-cinamon์ผ๋ก ๋ฐ๊พธ๋ฉด ๋ฉ๋๋ค.
model_provider = "codex-lb-cinamon"- ๊ทธ๋ค์ ์๋ ๊ณต๊ธ์ ์ ์ ๋ธ๋ก์ ํ์ผ ๋งจ ์๋์ ๊ทธ๋๋ก ๋ถ์ฌ ๋ฃ์ต๋๋ค.
- ์ด ๋ธ๋ก์ ๋ค๋ฅธ
[ ... ]์น์ ๋ค ์๋์ ๋ฐ๋ก ๋ค์ด๊ฐ๋ฉด ๋ฉ๋๋ค.
- ์ด ๋ธ๋ก์ ๋ค๋ฅธ
[model_providers.codex-lb-cinamon]
name = "OpenAI"
base_url = "http://127.0.0.1:2455/backend-api/codex"
wire_api = "responses"์ฆ, ์ต์ข ํ์ผ ๋ชจ์์ ์๋์ฒ๋ผ ๋ฉ๋๋ค.
model_provider = "codex-lb-cinamon"
[model_providers.codex-lb-cinamon]
name = "OpenAI"
base_url = "http://127.0.0.1:2455/backend-api/codex"
wire_api = "responses"codex-lb-cinamon์ API ํค ์ธ์ฆ์ ์ผ ๊ฒฝ์ฐ์๋ ์๋์ฒ๋ผ ์ถ๊ฐํฉ๋๋ค.
model_provider = "codex-lb-cinamon"
[model_providers.codex-lb-cinamon]
name = "OpenAI"
base_url = "http://127.0.0.1:2455/backend-api/codex"
wire_api = "responses"
env_key = "CODEX_LB_API_KEY"
supports_websockets = true
requires_openai_auth = trueexport CODEX_LB_API_KEY="sk-clb-..."
codex์ ๋ฆฌํ๋ฉด:
model_provider = "codex-lb-cinamon": ์ต์์ ์ค์ [model_providers.codex-lb-cinamon]: ๊ณต๊ธ์ ์์ธ ์ ์ ๋ธ๋ก- ๋ ์ด๋ฆ
codex-lb-cinamon์ ๋ฐ๋์ ์๋ก ๊ฐ์์ผ ํฉ๋๋ค. model/model_reasoning_effort๋ ๊ธฐ์กด Codex ์ค์ ์ ๊ทธ๋๋ก ์จ๋ ๋ฉ๋๋ค.
์ถ๊ฐ ๋ฉ๋ชจ:
CODEX_LB_UPSTREAM_STREAM_TRANSPORT=websocket๋ฅผ ์ฃผ๋ฉด ์ ์คํธ๋ฆผ ์คํธ๋ฆฌ๋ฐ์ WebSocket ์ฐ์ ์ผ๋ก ๊ฐ์ ํ ์ ์์ต๋๋ค.- ๊ธฐ๋ณธ๊ฐ์ธ
auto๋ Codex ์ ์ฉ ํค๋๋ ๋ชจ๋ธ์ ๋ง์ถฐ ์ ์ ํ transport๋ฅผ ๊ณ ๋ฆ ๋๋ค. - Codex ์์ฒด์ ์คํ์ WebSocket ํ๋๊ทธ๋ ๊ณ์
wire_api = "responses"์ ํจ๊ป ์ฌ์ฉํ๋ ์ ์ ์ ๋๋ค.
OpenCode
Before starting, please ensure that all existing OpenAI credentials is cleared in ~/.local/share/opencode/auth.json
You can clean the config by using this one-liner
jq 'del(.openai)' ~/.local/share/opencode/auth.json > auth.json.tmp && mv auth.json.tmp ~/.local/share/opencode/auth.json
~/.config/opencode/opencode.json:
export CODEX_LB_API_KEY="sk-clb-..."
opencodeOpenClaw
~/.openclaw/openclaw.json:
{
"agents": {
"defaults": {
"model": { "primary": "codex-lb-cinamon/gpt-5.4" },
"models": {
"codex-lb-cinamon/gpt-5.4": { "params": { "cacheRetention": "short" } },
"codex-lb-cinamon/gpt-5.4-mini": { "params": { "cacheRetention": "short" } },
"codex-lb-cinamon/gpt-5.3-codex": { "params": { "cacheRetention": "short" } }
}
}
},
"models": {
"mode": "merge",
"providers": {
"codex-lb-cinamon": {
"baseUrl": "http://127.0.0.1:2455/v1",
"apiKey": "${CODEX_LB_API_KEY}",
"api": "openai-responses",
"models": [
{
"id": "gpt-5.4",
"name": "gpt-5.4 (codex-lb-cinamon)",
"contextWindow": 1050000,
"contextTokens": 272000,
"maxTokens": 4096,
"input": ["text"],
"reasoning": false
},
{
"id": "gpt-5.4-mini",
"name": "gpt-5.4-mini (codex-lb-cinamon)",
"contextWindow": 400000,
"contextTokens": 272000,
"maxTokens": 4096,
"input": ["text"],
"reasoning": false
}
]
}
}
}
}CODEX_LB_API_KEY ํ๊ฒฝ ๋ณ์๋ฅผ ์ฐ๊ฑฐ๋ ${CODEX_LB_API_KEY} ์๋ฆฌ์ ๋์๋ณด๋์์ ๋ฐ๊ธํ ํค๋ฅผ ๋ฃ์ผ๋ฉด ๋ฉ๋๋ค. API ํค ์ธ์ฆ์ด ๊บผ์ ธ ์์ด๋ ๋น๋ก์ปฌ ์์ฒญ์ proxy ์ธ์ฆ์ด ์ค๋น๋๊ธฐ ์ ๊น์ง ๊ฑฐ์ ๋ ์ ์์ต๋๋ค.
OpenAI Python SDK
from openai import OpenAI
client = OpenAI(
base_url="http://127.0.0.1:2455/v1",
api_key="sk-clb-...", # ๋์๋ณด๋์์ ๋ฐ๊ธํ ํค. ์ธ์ฆ์ด ๊บผ์ ธ ์์ผ๋ฉด ์๋ฌด non-empty ๋ฌธ์์ด๋ ๊ฐ๋ฅ
)
response = client.chat.completions.create(
model="gpt-5.3-codex",
messages=[{"role": "user", "content": "์๋
ํ์ธ์"}],
)
print(response.choices[0].message.content)API ํค ์ธ์ฆ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๊บผ์ ธ ์์ต๋๋ค. ์ด ์ํ์์๋ ๋ณดํธ๋ ํ๋ก์ ๋ผ์ฐํธ์ ๋ํด ๋ก์ปฌ ์์ฒญ๋ง ํค ์์ด ํต๊ณผํ๊ณ , ๋น๋ก์ปฌ ์์ฒญ์ proxy ์ธ์ฆ์ด ์ค๋น๋ ๋๊น์ง ๊ฑฐ์ ๋ฉ๋๋ค. Docker, VM, ์๊ฒฉ ๋คํธ์ํฌ์ฒ๋ผ ์๋น์ค๊ฐ ๋น๋ก์ปฌ๋ก ์ธ์ํ๋ ํ๊ฒฝ์์ ๋ถ๋ ํด๋ผ์ด์ธํธ๋ ๋ณดํต ๋์๋ณด๋์ Settings -> API Key Auth ์์ ์ด ๊ธฐ๋ฅ์ ์ผ๊ณ ํค๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
ํ์ฑํ ํ์๋ ๋ชจ๋ ํด๋ผ์ด์ธํธ ์์ฒญ์ด ๋ค์ ํ์์ ๋ฐ๋ผ์ผ ํฉ๋๋ค.
Authorization: Bearer sk-clb-...
์ ์ฉ ๋ผ์ฐํธ:
/v1/*/backend-api/codex/*/backend-api/transcribe
/api/codex/usage ๋ ๋ณ๋ caller-identity ๊ฒฝ๋ก๋ผ ๋์๋ณด๋ ์ธ์
๋ง์ผ๋ก๋ ์ ๊ทผํ ์ ์์ต๋๋ค.
API ํค๋ Dashboard -> API Keys -> Create ์์ ๋ฐ๊ธํ๋ฉฐ, ์ ์ฒด ํค ๊ฐ์ ์์ฑ ์ ํ ๋ฒ๋ง ํ์๋ฉ๋๋ค.
์ง์ ํญ๋ชฉ:
- ๋ง๋ฃ์ผ
- ํ์ฉ ๋ชจ๋ธ ์ ํ
- ๊ฐ์ ๋ชจ๋ธ
- ํ ํฐ / ๋น์ฉ / ๊ธฐ๊ฐ ๊ธฐ๋ฐ ์ ํ
- ํ๊ฒฝ ๋ณ์๋
CODEX_LB_์ ๋์ด๋ฅผ ์ฌ์ฉํฉ๋๋ค. - ์์๋
.env.example์ ์์ต๋๋ค. - ๋์๋ณด๋ ์ธ์ฆ ์ค์ ์ UI์์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
- ๊ธฐ๋ณธ DB๋ SQLite์ด๋ฉฐ,
CODEX_LB_DATABASE_URL์ ์ฃผ๋ฉด PostgreSQL๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
codex-lb-cinamon ์ ๋ค์ 3๊ฐ์ง ๋์๋ณด๋ ์ธ์ฆ ๋ชจ๋๋ฅผ ์ง์ํฉ๋๋ค.
CODEX_LB_DASHBOARD_AUTH_MODE=standard- ๊ธฐ๋ณธ ๋ด์ฅ ๋น๋ฐ๋ฒํธ ์ธ์ฆ๊ณผ ์ ํํ TOTP๋ฅผ ์ฌ์ฉํฉ๋๋ค.
CODEX_LB_DASHBOARD_AUTH_MODE=trusted_header- ๋ฆฌ๋ฒ์ค ํ๋ก์๊ฐ ์ฃผ์ ํ ์ธ์ฆ ํค๋๋ฅผ ์ ๋ขฐํฉ๋๋ค.
CODEX_LB_FIREWALL_TRUST_PROXY_HEADERS=true,CODEX_LB_FIREWALL_TRUSTED_PROXY_CIDRS,CODEX_LB_DASHBOARD_AUTH_PROXY_HEADER์ค์ ์ด ํจ๊ป ํ์ํฉ๋๋ค.- ๋ด์ฅ ๋น๋ฐ๋ฒํธ/TOTP๋ fallback ์ผ๋ก ๊ณ์ ๋ ์ ์์ต๋๋ค.
CODEX_LB_DASHBOARD_AUTH_MODE=disabled- ์ฑ ๋ ๋ฒจ ๋์๋ณด๋ ์ธ์ฆ์ ์์ ํ ์ฐํํฉ๋๋ค.
- ์ธ๋ถ ์ธ์ฆ์ด๋ ๋คํธ์ํฌ ์ ํ์ด ์๋ ํ๊ฒฝ์์๋ง ์ฐ๋ ๊ฒ์ด ์์ ํฉ๋๋ค.
trusted_header ์์:
CODEX_LB_FIREWALL_TRUST_PROXY_HEADERS=true
CODEX_LB_FIREWALL_TRUSTED_PROXY_CIDRS=172.18.0.0/16
CODEX_LB_DASHBOARD_AUTH_PROXY_HEADER=Remote-User์ ๋ขฐ ํค๋๊ฐ ์๊ณ fallback ๋น๋ฐ๋ฒํธ๋ ์ค์ ๋์ง ์์๋ค๋ฉด ๋์๋ณด๋๋ fail-closed ๋ก ๋์ํฉ๋๋ค.
| ์คํ ๋ฐฉ์ | ๊ฒฝ๋ก |
|---|---|
๋ก์ปฌ / uvx codex-lb-cinamon |
~/.codex-lb/ |
| ์ปจํ ์ด๋ | /var/lib/codex-lb/ |
์ด ๋๋ ํฐ๋ฆฌ๋ฅผ ๋ฐฑ์ ํ๋ฉด ๊ณ์ , ์ค์ , ํค, ๋ก๊ทธ๋ฅผ ๋ณด์กดํ ์ ์์ต๋๋ค.
์ด ํฌํฌ๋ ์ปจํ ์ด๋ ๋ฐฐํฌ๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ฌธ์๋ฅผ ์ ์งํฉ๋๋ค. Kubernetes/Helm ๊ด๋ จ ์ ์ฐจ๋ ์ด README์์ ๋ค๋ฃจ์ง ์์ต๋๋ค.
์ด๋ฏธ์ง ์ฃผ์:
ghcr.io/cinev/codex-lb-cinamon
# ๋ฐฑ์๋ + ํ๋ก ํธ ๊ฐ๋ฐ ์๋ฒ
uv sync
cd frontend && bun install && cd ..
uv run fastapi run app/main.py --reload
cd frontend && bun run dev์ปจํ ์ด๋ ๊ธฐ๋ฐ ๊ฐ๋ฐ:
docker compose watch๊ธฐ๋ณธ ํฌํธ:
- ๋ฐฑ์๋:
2455 - ํ๋ก ํธ ๊ฐ๋ฐ ์๋ฒ:
5173
{ "$schema": "https://opencode.ai/config.json", "provider": { "openai": { "options": { "baseURL": "http://127.0.0.1:2455/v1", "apiKey": "{env:CODEX_LB_API_KEY}" }, "models": { "gpt-5.4": { "name": "GPT-5.4", "reasoning": true, "options": { "reasoningEffort": "high", "reasoningSummary": "detailed" }, "limit": { "context": 1050000, "output": 128000 } }, "gpt-5.3-codex": { "name": "GPT-5.3 Codex", "reasoning": true, "options": { "reasoningEffort": "high", "reasoningSummary": "detailed" }, "limit": { "context": 272000, "output": 65536 } } } } }, "model": "openai/gpt-5.3-codex" }