A portable, Docker-based AI stack combining LiteLLM (model gateway), OpenWebUI (chat frontend), and Codex (agent CLI), backed by OpenRouter, Fireworks, and OpenAI.
| Layer | Tool | Purpose |
|---|---|---|
| Frontend | OpenWebUI | Web-based chat UI |
| Gateway | LiteLLM | Routes models across providers, logs spend |
| Agent CLI | Codex | Terminal-based coding assistant |
| Agent CLI | Claude Code | Terminal-based coding assistant |
| Inference | OpenRouter / Fireworks / OpenAI | Model providers |
| Storage | Postgres | Chat history and LiteLLM database |
graph LR
User["🧑 User"] -->|browser| OpenWebUI
User -->|terminal| Codex
User -->|terminal| ClaudeCode["Claude Code"]
OpenWebUI -->|OpenAI-compatible API| LiteLLM
Codex -->|OpenAI-compatible API| LiteLLM
ClaudeCode -->|Anthropic-compatible API| LiteLLM
LiteLLM -->|routes to| OpenAI["OpenAI"]
LiteLLM -->|routes to| Fireworks["Fireworks"]
LiteLLM -->|routes to| OpenRouter["OpenRouter"]
LiteLLM -->|stores chat history| Postgres["Postgres"]
One-liner:
curl -fsSL https://raw.githubusercontent.com/asaini/openmodelstack/main/install.sh | bashOr clone and run locally:
git clone https://github.com/asaini/openmodelstack.git
cd openmodelstack
./install.shThe installer will:
- Check for Docker
- Create
.envfrom.env.exampleand prompt for API keys - Generate random internal secrets (Postgres, LiteLLM master key, WebUI secret)
- Copy the Codex and Claude Code configs to
~/.codex/config.tomland~/.claude/settings.json(each skips if one already exists) - Start all services via Docker Compose
After it finishes, open http://localhost:3000 for the chat UI.
- OpenWebUI →
http://localhost:3000 - LiteLLM API →
http://localhost:4000/v1(OpenAI-compatible) - LiteLLM Admin UI →
http://localhost:4000/ui
- LiteLLM model routing:
config/litellm/config.yaml - Codex model provider:
config/codex/config.toml - Claude Code model provider:
config/claude/settings.json - Secrets and API keys:
.env(not committed to git)
The installer copies a minimal config.toml to ~/.codex/config.toml that points Codex at your local LiteLLM proxy. You'll need:
export LITELLM_API_KEY="<your LITELLM_MASTER_KEY from .env>"Add that to your shell profile. If you already have a Codex config, the installer won't overwrite it — merge the [model_providers.litellm] section manually.
Launch Codex with its configured default model:
codexOr select any model exposed by LiteLLM without changing your default:
codex -m z-ai/glm-5.3-flashThe value passed to -m must match the model_name in config/litellm/config.yaml. Models are added there; config/codex/config.toml only defines the provider connection and your default model.
The installer copies a sample settings.json to ~/.claude/settings.json that points Claude Code at your local LiteLLM gateway. The sample sets:
ANTHROPIC_BASE_URL→http://localhost:4000(LiteLLM serves the Anthropic-compatible/v1/messagesendpoint)ANTHROPIC_AUTH_TOKEN→ a placeholder for yourLITELLM_MASTER_KEYfrom.env— replace it after install:
export ANTHROPIC_AUTH_TOKEN="<your LITELLM_MASTER_KEY from .env>"ANTHROPIC_MODEL/ANTHROPIC_SMALL_FAST_MODEL→ model names matchingmodel_nameentries inconfig/litellm/config.yaml(defaults:gpt-5.6-lunaandglm-5p3-flash).
If you already have a Claude Code config, the installer won't overwrite it — merge the env section from config/claude/settings.json manually. To change models, update the names in that file; no gateway change is needed since LiteLLM serves any routed model.
docker compose down # stop services
docker compose up -d # restart
docker compose logs -f # follow logs