Self-hosted gateway that exposes the models served by the OpenCode Zen API
(https://opencode.ai/zen/go/v1) through a LiteLLM proxy, so they can be
consumed by Open WebUI (or any
OpenAI-compatible client) with a single, unified API key.
LiteLLM translates the OpenCode endpoints into the standard OpenAI API schema, adds an authentication layer (a virtual key), and persists usage/state in PostgreSQL. Open WebUI then points to LiteLLM as if it were a normal OpenAI endpoint and instantly gets the full model catalog.
This repo runs LiteLLM + PostgreSQL via Docker Compose. Open WebUI runs as your own separate instance and connects to the LiteLLM proxy — see Connecting Open WebUI.
flowchart LR
subgraph Client["🖥️ Client"]
UI["Open WebUI<br/>(github.com/open-webui/open-webui)"]
end
subgraph Docker["🐳 Docker Compose stack (this repo)"]
LL["LiteLLM Proxy<br/>:4000"]
DB[("PostgreSQL 16<br/>litellm_db")]
end
subgraph Upstream["☁️ Upstream provider"]
OC["OpenCode Zen API<br/>opencode.ai/zen/go/v1"]
end
UI -->|"OpenAI-compatible request<br/>Bearer LITELLM_MASTER_KEY"| LL
LL -->|"reads config & routes model"| OC
OC -->|"authenticated with<br/>OPENCODE_API_KEY"| LL
LL <-->|"keys, spend, state"| DB
LL -->|"streamed response"| UI
In one sentence: Open WebUI talks to LiteLLM with the master key; LiteLLM forwards each request to OpenCode using the real provider key, normalizes the response, and streams it back.
- Docker and Docker Compose
- An OpenCode Go subscription and an API key (
OPENCODE_API_KEY) — see Get an OpenCode Go subscription below - An Open WebUI instance to consume the models. Install it yourself by following the official repository — there are many installation methods and versions, so use the one that fits your setup: https://github.com/open-webui/open-webui. Once it's running, see Connecting Open WebUI.
The models exposed by this gateway come from OpenCode Go, a low-cost coding plan. Subscribe at https://opencode.ai/ (Go section).
The same subscription powers both use cases this project targets: your self-hosted chat (Open WebUI) and coding inside OpenCode/VSCode — one plan, no separate API provider needed.
Once subscribed, open your OpenCode dashboard. The Go tab shows your usage (rolling / weekly / monthly), and the API Keys tab is where you get the key:
In API Keys you can either use the default key or generate a new one.
Copy it — this is the value you put in OPENCODE_API_KEY in your .env.
git clone https://github.com/Baronco/opencode-openwebui-gateway.git
cd opencode-openwebui-gateway
cp .env.example .envEdit .env and fill in your real values:
# Your OpenCode Zen API key (the upstream provider key)
OPENCODE_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# The "virtual" master key clients use to talk to LiteLLM.
# Choose any strong secret — this is what you paste into Open WebUI.
LITELLM_MASTER_KEY=sk-my-strong-master-keydocker compose up -dThis launches two services:
| Service | Image | Port | Purpose |
|---|---|---|---|
litellm | docker.litellm.ai/berriai/litellm:main-latest | 4000 | OpenAI-compatible proxy over OpenCode |
db | postgres:16 | — | Stores keys, spend tracking and state |
Check it is up:
docker compose ps
docker compose logs -f litellmList the models LiteLLM is exposing (use your LITELLM_MASTER_KEY):
curl http://localhost:4000/v1/models \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"Send a test completion:
curl http://localhost:4000/v1/chat/completions \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"glm-5.2","messages":[{"role":"user","content":"hi"}],"max_tokens":5}'Open WebUI should not authenticate with the master key directly. Instead, you create a scoped virtual key in LiteLLM and use that. Open the LiteLLM admin panel at http://localhost:4000/ui and log in with:
- Username:
admin - Password: your
LITELLM_MASTER_KEY(the value you set in.env)
Then, following the official LiteLLM × Open WebUI tutorial:
- (Optional) Create a Team to group access.
- Go to Virtual Keys and click + Create New Key. Give it an alias
(e.g.
OWUI) and choose which models the key may use — these are exactly the models Open WebUI will see. - Copy the generated key (starts with
sk-…). This is the key you paste into Open WebUI in the next section.
Install Open WebUI by following the official repository — https://github.com/open-webui/open-webui. It offers several installation methods (Docker, pip, Kubernetes, etc.) across different versions; pick the one that suits your environment. This repo only provides the LiteLLM gateway that Open WebUI connects to.
Once Open WebUI is running, go to
Settings → Admin Settings → Connections → OpenAI API and click the +
to add a new connection:
Fill in the connection details:
| Field | Value |
|---|---|
| URL | http://host.docker.internal:4000 |
| Auth | Bearer → the virtual key you created in step 4 |
| Model IDs | leave empty to auto-import all models the key has access to |
Use the virtual key here, not
LITELLM_MASTER_KEY. The master key is only for the Admin UI / key management; the virtual key is what scopes which models this Open WebUI connection can use.
Use
http://host.docker.internal:4000when Open WebUI runs in its own container and needs to reach LiteLLM on the host. If both run in the same Docker network, use the service name instead:http://litellm:4000. If Open WebUI runs directly on the host, usehttp://localhost:4000.
After saving, the OpenCode model catalog appears in the model picker.
Reference: https://docs.litellm.ai/docs/tutorials/openweb_ui
The model catalog is defined in litellm_config.yaml.
Each entry maps a friendly model_name to the upstream OpenCode model. Current
families:
| Family | Models |
|---|---|
| MiniMax | minimax-m3, minimax-m2.7, minimax-m2.5 |
| Kimi | kimi-k2.7-code, kimi-k2.6, kimi-k2.5 |
| GLM | glm-5.2, glm-5.1, glm-5 |
| DeepSeek | deepseek-v4-pro, deepseek-v4-flash |
| Qwen | qwen3.7-plus, qwen3.6-plus, qwen3.5-plus |
| MiMo | mimo-v2.5-pro, mimo-v2.5, mimo-v2-pro, mimo-v2-omni |
| Hunyuan | hy3-preview |
📄 Full model catalog: opencode_go_models.pdf — a reference table (as of June 26, 2026) characterizing every model available on OpenCode Go. The descriptions were AI-generated as a reference, so verify against the live catalog before relying on them.
Query the upstream catalog directly from OpenCode:
curl https://opencode.ai/zen/go/v1/models \
-H "Authorization: Bearer $OPENCODE_API_KEY"Probe which models are actually reachable (returns HTTP status per model):
for model in minimax-m3 minimax-m2.7 minimax-m2.5 kimi-k2.7-code kimi-k2.6 \
kimi-k2.5 glm-5.2 glm-5.1 glm-5 deepseek-v4-pro deepseek-v4-flash \
qwen3.7-max qwen3.7-plus qwen3.6-plus qwen3.5-plus mimo-v2.5-pro mimo-v2.5 \
mimo-v2-pro mimo-v2-omni hy3-preview; do
echo -n "Testing $model... "
curl -s -o /dev/null -w "%{http_code}\n" \
https://opencode.ai/zen/go/v1/chat/completions \
-H "Authorization: Bearer $OPENCODE_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"model\":\"$model\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}],\"max_tokens\":5}"
doneTo expose a new model, add a block to litellm_config.yaml:
- model_name: <friendly-name>
litellm_params:
model: openai/<upstream-model-id>
api_base: https://opencode.ai/zen/go/v1
api_key: os.environ/OPENCODE_API_KEY
additional_drop_params: ["reasoningSummary"]Then reload the proxy:
docker compose restart litellm| Variable | Description |
|---|---|
OPENCODE_API_KEY | Upstream OpenCode Zen provider key. Used by LiteLLM to call the API. |
LITELLM_MASTER_KEY | Admin/master key for LiteLLM. Used to log into the Admin UI (/ui) and to mint virtual keys. Open WebUI should use a virtual key, not this one. |
Defines the litellm proxy (port 4000) and the db (PostgreSQL 16) service.
The DATABASE_URL and Postgres credentials are wired between the two services;
the LiteLLM config file is mounted read-only at /app/config.yaml.
Holds the model_list (model routing) and general_settings.master_key
(bound to LITELLM_MASTER_KEY). additional_drop_params: ["reasoningSummary"]
strips a non-standard field that the upstream models would otherwise reject.
docker compose up -d # start in background
docker compose ps # status
docker compose logs -f litellm# follow proxy logs
docker compose restart litellm# reload after editing litellm_config.yaml
docker compose down # stop (keeps the DB volume)
docker compose down -v # stop and DELETE the Postgres volume401 Unauthorizedfrom LiteLLM — the client key doesn't matchLITELLM_MASTER_KEY. Confirm the value in.envand that you restarted the stack after changing it.401/403from upstream —OPENCODE_API_KEYis missing or invalid.- Open WebUI can't reach LiteLLM — using
localhostfrom inside a container points to the container itself. Usehost.docker.internal:4000(or the service name on a shared network). - A model returns errors — confirm it still exists upstream with the probe loop above; the catalog changes over time.




