Open WebUI
Self-hosted chat UI with Melious as an OpenAI connection — Docker, auto-discovered models, RAG embeddings
Open WebUI is a self-hosted, ChatGPT-shaped chat interface for teams: Docker-deployed, with user accounts, role-based access, RAG over uploaded documents, and a workspace for custom models and tools. It grew up as an Ollama front-end, but its OpenAI connection type takes any base URL, which is the door we walk through. Two environment variables on docker run and a fresh instance comes up already pointed at us, model picker populated from GET /v1/models. One thing to know before you start: Open WebUI treats everything that endpoint returns as a chat model, so a few minutes of curation saves your users a confusing error.
Setup
Run Open WebUI
docker run -d -p 3000:8080 \
-e OPENAI_API_BASE_URL=https://api.melious.ai/v1 \
-e OPENAI_API_KEY=sk-mel-<YOUR_API_KEY> \
-e ENABLE_OLLAMA_API=False \
-v open-webui:/app/backend/data \
--name open-webui ghcr.io/open-webui/open-webui:mainOpen http://localhost:3000 and create the first account — it becomes the admin. ENABLE_OLLAMA_API=False stops Open WebUI from probing for a local Ollama you don't have.
Already running docker compose? The same two variables, with MELIOUS_API_KEY=sk-mel-<YOUR_API_KEY> in the .env beside your compose file:
services:
open-webui:
environment:
- OPENAI_API_BASE_URL=https://api.melious.ai/v1
- OPENAI_API_KEY=${MELIOUS_API_KEY}Or add the connection by hand
On an instance that's already been started, those variables do nothing — they seed the config database once, on first boot, and the admin UI owns it after that.
Go to Admin Panel → Settings → Connections, click + on the OpenAI API row, and fill in:
- URL:
https://api.melious.ai/v1 - Key:
sk-mel-<YOUR_API_KEY>
The button beside the URL field — Verify Connection — calls GET /v1/models against what you typed. A Server connection verified toast means we're wired.
Pick a model
Save, and the model picker fills from GET /v1/models — everything your key can reach, no restart needed. Type glm-5.1 into the picker to start; it's our general-purpose default and handles tool calls well.
Then curate the list, because the raw one is long. Open the connection's settings, expand Advanced, and list the models you want under Model IDs. Leave it empty and you get all of them.
Curating the model list
We serve chat, embedding, image, audio, and guardrail models from one /v1/models endpoint, and nothing in the OpenAI response shape tells Open WebUI which is which. So all of them show up in the chat picker, and choosing bge-m3 for a conversation fails with The server had an error while processing your request. Sorry about that! — our error message, and not one we're proud of. Setting Model IDs is the fix; it also stops your users scrolling past seventy-odd entries to find the three they use.
A shared instance wants a short list: one general model, one for code, one cheap one for bulk work. The models hub carries the capability flags for browsing.
To build the list programmatically, filter GET /v1/models?include_meta=true on _meta.type. Today that's 48 chat, 7 embeddings, 6 image, 4 audio, and 2 guardrail.
Prefix ID, in the same Advanced section, namespaces every model from this connection — set it to melious and glm-5.1 becomes melious.glm-5.1. Open WebUI strips the prefix before the request reaches us, so nothing changes upstream, but the prefixed form is now the only one that resolves. Worth setting when you run us beside another OpenAI-compatible endpoint; worth knowing about if anything of yours refers to model IDs by name.
Documents, images, and speech
Chat isn't the only surface that talks to us, and here's the thing that catches people: Documents, Images, and Audio each keep their own URL and key, and none of them inherit your chat connection. All three ship pointed at https://api.openai.com/v1 with an empty key, so each needs the Melious base URL and your key pasted in again.
- Embeddings — Settings → Documents, Embedding Model Engine OpenAI, model
bge-m3. Worth doing even if you don't care who embeds your documents: the default engine downloadssentence-transformers/all-MiniLM-L6-v2into the container and runs it on the host CPU, which is slower and weaker on anything that isn't English. - Image generation — Settings → Images, engine OpenAI, model
flux-1-dev. Images come back into the chat at whatever Image Size you set. - Speech-to-text — Settings → Audio, STT engine OpenAI, model
whisper-large-v3.
Text-to-speech is the gap: we don't serve TTS models, so leave that engine on whatever you use today.
The task model
Titles, tags, follow-up suggestions, and retrieval queries are generated on a side channel, and by default they run on whatever model the chat is using. Point Admin Panel → Settings → Interface → External Task Model at something small instead — qwen3.5-9b is a reasonable pick — and background traffic stops being billed at chat-model rates.
Fair warning: reasoning models think before they answer here too. Asking qwen3.5-9b to count to five cost us 10 completion tokens and 279 reasoning tokens — fine in a chat, wasteful on every title you generate.
What's different
- Every model looks like a chat model. Open WebUI has no type discriminator to work with, so embedding and image models land in the picker alongside the rest.
_meta.typeonGET /v1/models?include_meta=trueis how you tell them apart; Model IDs is where you act on it. environment_impactandbilling_costreach the client untouched, and nothing renders them. Open WebUI passes our extra response fields straight through its proxy but has no UI for them. The usage dashboard aggregates the same numbers.- The Responses API toggle works. Setting API Type to Responses on the connection routes to
/v1/responses, which we implement. Chat Completions stays the default and is the better-traveled path — switch only if you need something specific to the Responses shape. - Tool calls pass through unchanged. Native function calling uses the OpenAI
tool_callsschema, so it works on any model that supports tools. Check_meta.capabilities.function_callingbefore wiring an agent to a model that can't call one, or read it off the model card at melious.ai/hub/models.
When it breaks
The server had an error while processing your request. Sorry about that!— the selected model can't serve a chat request. It's an embedding, image, audio, or guardrail model. Set Model IDs so it can't be picked.- Environment variables had no effect —
OPENAI_API_BASE_URLandOPENAI_API_KEYare read into the database on first start only. Change the connection in Admin Panel → Settings → Connections, or start over with a fresh volume. Model '<MODEL_ID>' was not found— Open WebUI caches the model list in memory. Save the connection again, or reload the page, after editing Model IDs.503with"code": "provider_error"on one model — the upstream provider behind that model is having a moment. Other models on the same key keep working; retry or switch. See Rate limits if it's every request rather than one model.
Errors and retry patterns: Errors.
LobeChat
Self-hosted chat UI pointed at Melious through its OpenAI provider — three env vars on the container and the model picker fills itself
OpenClaw
Self-hosted AI gateway that bridges chat apps (Telegram, Discord, WhatsApp) to coding agents — register Melious as a custom OpenAI-compatible provider