---
title: "Self-host Open WebUI"
description: "Run Open WebUI on exe.dev: a private ChatGPT for you or your team, with models from exe.dev's LLM gateway, exe.dev login, and chats on your VM."
url: https://exe-staging.dev/deploy/open-webui
category: "AI apps"
updated: 2026-10-17
---

# Self-host Open WebUI

A private ChatGPT for you and your team. No API keys.

- **Software:** Open WebUI (https://openwebui.com)
- **Source:** https://github.com/open-webui/open-webui
- **License:** Open WebUI License (BSD-3-Clause with a branding clause)
- **Time:** 10 minutes
- **Example VM name:** `my-open-webui` (yours will differ; on the VM, `hostname` prints it)
- **Machine-readable:** https://exe-staging.dev/deploy/open-webui/manifest.json

## What you get

- Open WebUI at your VM's private URL, signed in with exe.dev, with you as admin.
- Dozens of models from exe.dev's LLM gateway. No API keys to paste.
- An account made automatically for each teammate you share the VM with.
- Chat with documents, DuckDuckGo web search, and voice input, ready to use.
- Starts again after a reboot; nightly backups, with one restored and checked.

Running on the VM:

- **Open WebUI 0.12**: The official Docker image, in Docker Compose, port 8000, data in `~/open-webui/data`
- **exe.dev LLM gateway**: GPT, GLM, Kimi, Grok, and more, without API keys
- **exe.dev login**: Signs everyone in to Open WebUI; no second password

How it is reached:

- https://my-open-webui.exe.xyz/ (private): Your chats, signed in with your exe.dev account
- https://my-open-webui.exe.xyz/ (shared): Teammates you share the VM with, each with their own account

## Deploy with Shelley

Open https://exe-staging.dev/new?prompt=Set%20up%20Open%20WebUI%20on%20this%20VM%20by%20following%20the%20exe.dev%20recipe%20at%20https%3A%2F%2Fexe-staging.dev%2Fdeploy%2Fopen-webui.md%20from%20top%20to%20bottom.%0A%0AThe%20recipe%27s%20example%20VM%20name%20is%20my-open-webui.%20This%20VM%27s%20name%20is%20the%20output%20of%20%60hostname%60%3A%20use%20it%20wherever%20the%20recipe%20writes%20my-open-webui.%20Skip%20the%20step%20that%20creates%20the%20VM%3B%20you%20are%20on%20it.%0A%0AYou%20are%20done%20when%20all%20of%20these%20are%20true.%20Check%20each%20one%20yourself%3A%0A-%20Open%20WebUI%20at%20your%20VM%27s%20private%20URL%2C%20signed%20in%20with%20exe.dev%2C%20with%20you%20as%20admin.%0A-%20Dozens%20of%20models%20from%20exe.dev%27s%20LLM%20gateway.%20No%20API%20keys%20to%20paste.%0A-%20An%20account%20made%20automatically%20for%20each%20teammate%20you%20share%20the%20VM%20with.%0A-%20Chat%20with%20documents%2C%20DuckDuckGo%20web%20search%2C%20and%20voice%20input%2C%20ready%20to%20use.%0A-%20Starts%20again%20after%20a%20reboot%3B%20nightly%20backups%2C%20with%20one%20restored%20and%20checked.%0A%0ARead%20the%20whole%20recipe%2C%20including%20the%20closed%20details.%20For%20initial%20setup%2C%0Afollow%20%22Install%20by%20hand%22%20first%2C%20skipping%20VM%20creation%20and%20SSH%3A%20Docker%2C%0Athe%20Compose%20stack%2C%20the%20owner%27s%20admin%20account%2C%20the%20chat%20check%2C%20the%0Adocuments%2Fsearch%2Fvoice%20check%2C%20the%20backup%20timer%2C%20and%20the%20backup%20check.%0AThose%20checks%20are%20enough%3B%20don%27t%20install%20extra%20tools%20to%20test%20further.%0AThe%20walkthrough%20at%20the%20top%20is%20for%20the%20owner%20afterwards.%20Do%20not%20run%0ARestore%2C%20Update%2C%20or%20%22Run%20a%20small%20model%20on%20the%20VM%22.%0AWork%20as%20exedev%20in%20~%2Fopen-webui.%20Never%20overwrite%20an%20existing%20.env.%0AMake%20the%20VM%27s%20owner%20the%20admin%2C%20using%20the%20email%20from%20the%20reflection%0Aintegration%3B%20if%20it%20prints%20nothing%2C%20ask%20the%20user%20for%20their%20exe.dev%20email.%0AThe%20VM%20is%20private%20until%20it%27s%20shared%2C%20so%20start%20Open%20WebUI%20as%20written%3B%0Athere%27s%20no%20need%20to%20hide%20port%208000%20first.%20Don%27t%20share%20the%20VM%20or%20make%20it%0Apublic.%20Keep%20test%20chats%20to%20a%20word%20or%20two.%0AVerify%20docker.service%20is%20enabled%20and%20the%20container%20uses%20unless-stopped%3B%0Ado%20not%20reboot.%0A%0AFinish%20with%20the%20URLs%20I%20should%20open%20and%20these%20commands%2C%20which%20only%20I%20can%20run%2C%20from%20my%20own%20computer%20%28with%20this%20VM%27s%20name%20in%20them%29%3A%0A%20%20ssh%20exe.dev%20share%20add%20my-open-webui%20teammate%40example.com%0A to create a VM whose agent, Shelley, follows this recipe. From a terminal:

```sh
curl -fsSL https://exe-staging.dev/deploy/open-webui/prompt.txt | ssh exe.dev new --prompt=/dev/stdin
```

Then, on your own computer:

```sh
ssh exe.dev share add my-open-webui teammate@example.com
```

Or follow the steps below by hand.

Open WebUI is the friendly chat app you might know from ChatGPT: a model
picker, chat history, file uploads, and voice input. Here it runs on your own
exe.dev VM, with models from exe.dev's [LLM gateway](/docs/integrations-llm)
and no API keys anywhere. Your exe.dev login is the sign-in, so there's no
extra password to forget.

Share the VM with your team and each teammate gets their own account and
chat history. Everything lives on the VM's disk, backed up every night.

## Start chatting

Open the URL Shelley gives you. It'll look like
`https://my-open-webui.exe.xyz/`. Sign in to exe.dev if you're asked, and
Open WebUI signs you in automatically. You're its admin.

Pick a model at the top of the chat, or keep the default, and say hello.
The model menu has a search box, and the list includes GPT models plus GLM,
Kimi, DeepSeek, and Grok. A small model writes chat titles and suggested
follow-ups.

Admin settings live under your name, bottom left: **Settings → Admin**.

## Bring your team

On your computer, share the VM with a teammate:

```bash
ssh exe.dev share add my-open-webui teammate@example.com
```

They get an email invitation. Once they've signed in to exe.dev, they open
the same URL and land in their own Open WebUI account, with access to all the
models. Their chats are separate from yours, but as an admin you can read
them; tell your team. `ssh exe.dev share add my-open-webui team` shares
with everyone in your exe.dev team.

People you haven't shared with see exe.dev's login screen and never reach
Open WebUI. `ssh exe.dev share remove my-open-webui teammate@example.com`
locks someone out again. Their account and chats stay until you delete them
in **Settings → Admin → Users**, which is also where you make someone admin.

> [!WARNING]
> Admins can install Functions and Tools, which run Python on your VM.
> Only make someone admin if you'd give them a shell. Everyone's chats
> count against your LLM allocation, so don't make the VM public with
> `share set-public`: anyone signed in to exe.dev would get an account.

## Documents, web search, and voice

- **Documents:** click **+** in the message box to attach a PDF, Word file,
  or text file, then ask about it. Collections you reuse go in
  **Workspace → Knowledge**; type `#` in a chat to pull one in.
- **Web search:** click the integrations button next to **+** and turn on
  **Web Search**. It uses DuckDuckGo, with no key. If DuckDuckGo starts
  refusing requests, choose another engine in **Settings → Admin → Web Search**.
- **Voice:** the microphone button transcribes speech through the gateway.

## Keep your chats

Backups run nightly into `~/open-webui-backups`. Each one includes your chats,
accounts, settings, and uploaded files. Keep a copy **off the VM**. On your
computer:

```bash
scp -r my-open-webui.exe.xyz:open-webui-backups .
```

Keep these files private. To restore one, or to update Open WebUI, see the
sections below, or ask Shelley to help. Something stuck? On the VM, try
`cd ~/open-webui && docker compose logs --tail=100`.

## The nuts and bolts

Happy clicking Deploy? You can stop here. These are the same setup steps
Shelley follows, plus the maintenance commands for later.

<details id="create-the-vm" data-manual-setup class="dp-details">
<summary>Install by hand</summary>

### Create a VM

On your computer (pick another name if `my-open-webui` is taken):

```bash
ssh exe.dev new --name=my-open-webui
ssh my-open-webui.exe.xyz
```

All remaining installation commands run **on the VM**, as `exedev`.
Commands use `hostname`, so your VM can have any name.

### Get Docker ready

Open WebUI recommends Docker for servers; its image bundles everything,
including document readers and a small local model for searching
documents. Enable Docker at boot, or exe.dev's on-demand Docker won't
restart Open WebUI after a reboot. Install `jq` if needed:

```bash
sudo systemctl enable --now docker.service
systemctl is-enabled docker.service
command -v jq >/dev/null || sudo apt-get install -y jq
```

The check should print `enabled`.

### Choose the models

The gateway lists its models at `https://llm.int.exe.xyz/models.json`.
Open WebUI talks to it with OpenAI's Responses API; Anthropic-only models
and very expensive `-pro` models are left out. This writes `.env` **once**,
with a secret key for Open WebUI's sessions, the model list, a default
model, and a small model for chat titles:

```bash
mkdir -p ~/open-webui/data
cd ~/open-webui
if [ ! -e .env ]; then
  catalog=$(curl -fsS https://llm.int.exe.xyz/models.json)
  models=$(jq -c '[.models[] | select((.apis // []) | index("openai_responses"))
    | .id | sub("^openai/"; "") | select(test("-pro$") | not)]' <<<"$catalog")
  default_model=$(jq -r '.preferred_model // "gpt-5.5" | sub("^openai/"; "")' <<<"$catalog")
  task_model=$(jq -r 'map(select(test("^gpt-[0-9.]+-(mini|nano)$")))[0] // "gpt-5.4-mini"' <<<"$models")
  touch .env && chmod 600 .env
  cat >> .env <<EOF
# Open WebUI copies these into its database on the FIRST start only.
# After that, change them in Settings -> Admin.
WEBUI_URL=https://$(hostname).exe.xyz
WEBUI_SECRET_KEY=$(openssl rand -hex 32)
DEFAULT_MODELS=$default_model
TASK_MODEL_EXTERNAL=$task_model
OPENAI_API_CONFIGS='{"0":{"enable":true,"api_type":"responses","model_ids":$models}}'
EOF
fi
grep -E '^(DEFAULT_MODELS|TASK_MODEL_EXTERNAL)=' .env
sed -n "s/^OPENAI_API_CONFIGS='\(.*\)'$/\1/p" .env | jq '."0".model_ids | length'
```

Expect the default model, the title model, and a count of a few dozen models.

### Start Open WebUI

The Compose file signs people in with the email exe.dev's proxy sends in
the `X-ExeDev-Email` header (see [Login with exe](/docs/login-with-exe)),
and turns off Open WebUI's own sign-up form. New people start as ordinary
users who can use every model. The gateway needs no key, so Open WebUI
gets a placeholder.

```bash
cat > ~/open-webui/compose.yaml <<'EOF'
# Open WebUI behind exe.dev's HTTPS proxy, with models from the LLM gateway.
# Secrets and first-start settings come from .env in this directory.
name: open-webui

services:
  open-webui:
    # 0.12 follows the newest 0.12.x patch release.
    image: ghcr.io/open-webui/open-webui:0.12
    restart: unless-stopped
    ports:
      - "8000:8080"
    env_file: .env
    extra_hosts:
      # Lets Open WebUI reach an optional Ollama on the VM.
      - "host.docker.internal:host-gateway"
    environment:
      # exe.dev login is the sign-in. Port 8000 is only reachable
      # through exe.dev's proxy, which sets this header.
      WEBUI_AUTH_TRUSTED_EMAIL_HEADER: X-ExeDev-Email
      ENABLE_LOGIN_FORM: "false"
      DEFAULT_USER_ROLE: user
      BYPASS_MODEL_ACCESS_CONTROL: "true"
      # Models from exe.dev's LLM gateway; it needs no real key.
      OPENAI_API_BASE_URL: https://llm.int.exe.xyz/v1
      OPENAI_API_KEY: exe-llm-gateway
      ENABLE_OLLAMA_API: "false"
      # Web search without an API key.
      ENABLE_WEB_SEARCH: "true"
      WEB_SEARCH_ENGINE: duckduckgo
      # Voice input, transcribed by the gateway.
      AUDIO_STT_ENGINE: openai
      AUDIO_STT_OPENAI_API_BASE_URL: https://llm.int.exe.xyz/v1
      AUDIO_STT_OPENAI_API_KEY: exe-llm-gateway
      AUDIO_STT_MODEL: gpt-transcribe
    volumes:
      - ./data:/app/backend/data
EOF
```

Start it and wait for `{"status":true}`. The first start downloads a
large image (about 6 GB on disk) and the small model for documents, so give
it a few minutes. If it takes more than ten, stop the loop with Ctrl-C and
[check the logs](#troubleshooting).

```bash
cd ~/open-webui
docker compose up -d
until curl -fs http://localhost:8000/health; do sleep 5; done; echo
docker compose ps
```

The container should be `Up` and, after a minute, `healthy`.

### Make yourself the admin

The first account Open WebUI creates becomes its admin. The VM is private
until you share it, so nobody else can get there first, but create your
account now, before you share it. Find your exe.dev email:

```bash
owner=$(curl -fsS https://reflection.int.exe.xyz/email | jq -r '.email // empty')
echo "$owner"
```

If that prints nothing, set it yourself: `owner=you@example.com`, using the
email you sign in to exe.dev with. Then sign in the way exe.dev's proxy
will:

```bash
curl -fsS -X POST http://localhost:8000/api/v1/auths/signin \
  -H 'Content-Type: application/json' -H "X-ExeDev-Email: $owner" \
  -d '{"email":"","password":""}' | jq '{email, role}'
```

Expect your email and `"role": "admin"`.

### Check a chat

Ask the title model for one word, through Open WebUI and the gateway:

```bash
cd ~/open-webui
owner=${owner:-$(curl -fsS https://reflection.int.exe.xyz/email | jq -r '.email // empty')}
token=$(curl -fsS -X POST http://localhost:8000/api/v1/auths/signin \
  -H 'Content-Type: application/json' -H "X-ExeDev-Email: $owner" \
  -d '{"email":"","password":""}' | jq -r .token)
curl -fsS http://localhost:8000/api/models -H "Authorization: Bearer $token" | jq '.data | length'
model=$(sed -n 's/^TASK_MODEL_EXTERNAL=//p' .env)
curl -fsS http://localhost:8000/api/chat/completions \
  -H "Authorization: Bearer $token" -H 'Content-Type: application/json' \
  -d "{\"model\":\"$model\",\"stream\":false,\"messages\":[{\"role\":\"user\",\"content\":\"Reply with one word: pong\"}]}" \
  | jq -r '.choices[0].message.content'
```

Expect the number of models and `pong`. Without exe.dev's header, nobody
gets in. This should print `400`:

```bash
curl -s -o /dev/null -w '%{http_code}\n' -X POST http://localhost:8000/api/v1/auths/signin \
  -H 'Content-Type: application/json' -d '{"email":"","password":""}'
```

### Check documents, web search, and voice

Upload a one-line document and ask about it, run a web search, and send a
second of silence to voice transcription. Each goes through Open WebUI as
you, and the test file is deleted at the end:

```bash
cd ~/open-webui
owner=${owner:-$(curl -fsS https://reflection.int.exe.xyz/email | jq -r '.email // empty')}
auth="Authorization: Bearer $(curl -fsS -X POST http://localhost:8000/api/v1/auths/signin \
  -H 'Content-Type: application/json' -H "X-ExeDev-Email: $owner" \
  -d '{"email":"","password":""}' | jq -r .token)"
model=$(sed -n 's/^TASK_MODEL_EXTERNAL=//p' .env)
echo 'The project codename is BLUE PELICAN.' > /tmp/codename.txt
file=$(curl -fsS -X POST 'http://localhost:8000/api/v1/files/?process=true' \
  -H "$auth" -F file=@/tmp/codename.txt | jq -r .id)
until curl -fsS "http://localhost:8000/api/v1/files/$file/process/status" -H "$auth" \
  | jq -e '.status != "pending"' >/dev/null; do sleep 2; done
curl -fsS http://localhost:8000/api/chat/completions \
  -H "$auth" -H 'Content-Type: application/json' \
  -d "{\"model\":\"$model\",\"stream\":false,\"files\":[{\"type\":\"file\",\"id\":\"$file\"}],
       \"messages\":[{\"role\":\"user\",\"content\":\"What is the codename? Two words.\"}]}" \
  | jq -r '.choices[0].message.content'
curl -fsS -X POST http://localhost:8000/api/v1/retrieval/process/web/search \
  -H "$auth" -H 'Content-Type: application/json' -d '{"queries":["exe.dev"]}' \
  | jq '.items | length'
python3 -c 'import wave; w = wave.open("/tmp/silence.wav", "wb"); w.setnchannels(1)
w.setsampwidth(2); w.setframerate(16000); w.writeframes(bytes(32000)); w.close()'
curl -fsS -X POST http://localhost:8000/api/v1/audio/transcriptions \
  -H "$auth" -F 'file=@/tmp/silence.wav;type=audio/wav' | jq -c '{text}'
curl -fsS -X DELETE "http://localhost:8000/api/v1/files/$file" -H "$auth"; echo
rm /tmp/codename.txt /tmp/silence.wav
```

Expect `BLUE PELICAN` (perhaps with a `[1]` citation), a number of search
results, `{"text":""}` for the silence, and a deleted-file message. If the
search fails, DuckDuckGo is limiting requests from the VM's address; try
again later. Everything else still works.

### Set up nightly backups

The backup stops Open WebUI for a few seconds, so the database and the
document index are copied in a consistent state. It runs as root because
the container writes `data` as root, and skips `data/cache`, which Open
WebUI downloads again.

```bash
cat > ~/open-webui/backup.sh <<'EOF'
#!/usr/bin/env bash
# Back up Open WebUI: data (chats, accounts, settings, uploads, document
# index), .env (the secret key), and the Compose file. Run with sudo.
set -euo pipefail
umask 077
cd "$(dirname "$(readlink -f "$0")")"
owner=$(stat -c %U:%G .)
dest="$(dirname "$PWD")/open-webui-backups"
mkdir -p "$dest"
out="$dest/open-webui-$(date -u +%Y%m%d-%H%M%S).tar.gz"

# A short stop keeps the SQLite database and document index consistent.
docker compose stop open-webui
trap 'docker compose start open-webui' EXIT
tar -czf "$out.part" --exclude=data/cache .env compose.yaml backup.sh data
docker compose start open-webui
trap - EXIT
mv "$out.part" "$out"
chown -R "$owner" "$dest"

# Keep the 14 newest backups.
ls -1t "$dest"/open-webui-*.tar.gz | tail -n +15 | xargs -r rm --
echo "$out"
EOF
chmod +x ~/open-webui/backup.sh
```

Schedule it for 03:30 UTC (or so), then take a first backup:

```bash
sudo tee /etc/systemd/system/open-webui-backup.service >/dev/null <<EOF
[Unit]
Description=Back up Open WebUI to ~/open-webui-backups
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
ExecStart=$HOME/open-webui/backup.sh
EOF
sudo tee /etc/systemd/system/open-webui-backup.timer >/dev/null <<'EOF'
[Unit]
Description=Back up Open WebUI every night

[Timer]
OnCalendar=*-*-* 03:30:00
RandomizedDelaySec=30m
Persistent=true

[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now open-webui-backup.timer
sudo systemctl start open-webui-backup.service
systemctl list-timers open-webui-backup.timer
ls -lh ~/open-webui-backups
until curl -fs http://localhost:8000/health; do sleep 5; done; echo
```

Check that the timer has a next run, the directory has a tarball, and Open
WebUI is back. For failures: `journalctl -u open-webui-backup.service`.

### Test a backup

Unpack the newest backup into a **scratch directory** and check its
database, without touching the running copy:

```bash
latest=$(ls -1t ~/open-webui-backups/open-webui-*.tar.gz | head -n 1)
mkdir /tmp/open-webui-restore-test
sudo tar -xzf "$latest" -C /tmp/open-webui-restore-test
cd /tmp/open-webui-restore-test
sudo ls -A . data
docker compose -p open-webui-restore-test run --rm --no-deps -T open-webui python3 -c '
import sqlite3
db = sqlite3.connect("/app/backend/data/webui.db")
print(db.execute("pragma integrity_check").fetchone()[0])
for table in ("user", "chat"):
    print(table, db.execute(f"select count(*) from {table}").fetchone()[0])
'
```

Expect `.env`, `compose.yaml`, and `data` with `webui.db`, then `ok` and
the number of accounts and chats. Remove only the scratch copy:

```bash
cd /tmp/open-webui-restore-test && docker compose -p open-webui-restore-test down
cd ~ && sudo rm -rf /tmp/open-webui-restore-test
```

Installation done. Leave sharing to the owner; continue with
[Start chatting](#start-chatting).

</details>

<details id="back-up-and-restore" class="dp-details">
<summary>Back up and restore</summary>

On the VM, `sudo ~/open-webui/backup.sh` makes an extra backup and prints
its path. Copy backups off the VM as shown in
[Keep your chats](#keep-your-chats).

### Restore

On a new VM, get Docker ready as in [Install](#get-docker-ready). Create
`~/open-webui-backups` there, then copy your backup over from your computer:

```bash
scp open-webui-20261017-033012.tar.gz my-open-webui.exe.xyz:open-webui-backups/
```

Use your backup's actual filename in this and the commands below. All
remaining commands run **on the VM**. If Open WebUI already runs there,
stop it and keep its directory aside first:

```bash
cd ~/open-webui && docker compose down
sudo mv ~/open-webui ~/open-webui.before-restore
```

Unpack the backup and start it:

```bash
mkdir ~/open-webui
sudo tar -xzf ~/open-webui-backups/open-webui-20261017-033012.tar.gz -C ~/open-webui
cd ~/open-webui
docker compose up -d
until curl -fs http://localhost:8000/health; do sleep 5; done; echo
```

Open the site and check your chats are there. Sign in with the same exe.dev
account to stay admin. On a new VM, recreate the backup timer from
[Install](#set-up-nightly-backups), and if its name changed, update
**WebUI URL** in **Settings → Admin → General**. Keep
`~/open-webui.before-restore` until you're happy everything is back.

</details>

<details id="update" class="dp-details">
<summary>Update Open WebUI</summary>

The `0.12` image tag follows the newest 0.12.x release. On the VM, back up,
then pull and restart:

```bash
cd ~/open-webui
sudo ./backup.sh
docker compose pull
docker compose up -d
until curl -fs http://localhost:8000/health; do sleep 5; done; echo
curl -fsS http://localhost:8000/api/version; echo
docker image prune -f
```

Check the version, then reload the site with Ctrl+Shift+R (Cmd+Shift+R on a
Mac) so your browser picks up the new pages. The last command frees the old
image's disk space.

For a new minor version, such as 0.13, read the
[release notes](https://github.com/open-webui/open-webui/releases) first,
then change the `image:` tag in `compose.yaml` and run the same commands.
To roll back, [restore the backup](#restore): changing the tag alone won't
undo database migrations.

New models on the gateway don't show up by themselves. Add their IDs in
**Settings → Admin → Connections**, with the gear next to
`https://llm.int.exe.xyz/v1`.

</details>

<details id="local-models" class="dp-details">
<summary>Run a small model on the VM (optional)</summary>

[Ollama](https://ollama.com) runs open models on the VM's own CPU, so a
chat never leaves the VM. On the default VM (2 vCPUs, 8 GB), we measured
these speeds, in tokens (word pieces) per second:

- `gemma3:1b`: about 28. Fine for quick, simple jobs.
- `llama3.2:3b`: about 19. A bit smarter, still quick.
- 7-8B models: about 7, and they crowd Open WebUI out of memory.

They are much weaker than the gateway's models, and slow to read long
documents. For 7-8B models, give the VM more room first, on your computer:
`ssh exe.dev resize my-open-webui --cpu=4 --memory=16GB`.

On the VM, install Ollama (about 2 GB) and let Open WebUI's container reach
it. exe.dev's proxy only forwards ports 3000-9999, so port 11434 stays
off the internet.

```bash
curl -fsSL https://ollama.com/install.sh | sh
sudo mkdir -p /etc/systemd/system/ollama.service.d
printf '[Service]\nEnvironment=OLLAMA_HOST=0.0.0.0:11434\n' \
  | sudo tee /etc/systemd/system/ollama.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart ollama
ollama pull gemma3:1b
cd ~/open-webui
docker compose exec open-webui curl -fsS http://host.docker.internal:11434/api/version; echo
```

Expect a version number. Then, in Open WebUI, go to
**Settings → Admin → Connections** and switch on **Ollama API**. Its address is
already `http://host.docker.internal:11434`. `gemma3:1b` appears in the model
menu. Add models with `ollama pull`, or from the download icon next to the
Ollama connection.

</details>

<details id="troubleshooting" class="dp-details">
<summary>Something not working?</summary>

On the VM:

```bash
cd ~/open-webui
docker compose ps
docker compose logs --tail=100 open-webui
```

- **502 right after starting or updating:** Open WebUI takes up to a
  minute to start. Wait for `curl -fsS http://localhost:8000/health`.
- **An error mentioning `/v1/chat/completions`:** the gateway connection was
  switched to Chat Completions. In **Settings → Admin → Connections**, open the
  gear and set **API Type** back to **Responses**.
- **I changed `.env` and nothing happened:** most settings are read only on
  the first start, then kept in Open WebUI's database. Change them in
  **Settings → Admin** instead.
- **A teammate sees no models:** check the gateway connection is switched on
  in **Settings → Admin → Connections**, and that the model isn't hidden in
  **Settings → Admin → Models**.
- **Web search fails or finds nothing:** DuckDuckGo limits automated searches
  at times. Pick another engine in **Settings → Admin → Web Search**; most
  need an API key.
- **Down after a reboot:** run `sudo systemctl enable --now docker.service`.
- **Disk full:** each image is about 6 GB. Check `df -h /` and run
  `docker image prune -f`.

</details>

## Frequently asked questions

### How much does it cost?

Open WebUI is free. You pay for your [VM plan](https://exe.dev/pricing), and chats use your exe.dev [LLM allocation](/docs/integrations-llm), including your teammates' chats. Voice transcription with `gpt-transcribe` is free.

### Which models can I use? Is Claude there?

Everything the gateway serves through OpenAI's API: GPT models plus GLM, Kimi, DeepSeek, Grok, and others. Claude isn't, because the gateway offers it only through Anthropic's Messages API, which Open WebUI doesn't speak to custom servers. Shelley and Claude Code can use it.

### Can I use my own API key or ChatGPT subscription?

Yes, without touching Open WebUI. Point your [LLM integration](/docs/integrations-llm) at your own provider key or ChatGPT account, and the same address serves your models.

### Who can read my chats?

Each person's chats are their own, but Open WebUI admins can open anyone's chats, and the VM's owner can read its disk. Prompts and replies go to the model provider through exe.dev's gateway. Run a [small local model](#local-models) to keep a chat entirely on the VM.

### Does it work with Ollama?

Yes. Small 1-3B models run fast enough on the default VM's CPU; bigger ones want a bigger VM. See [Run a small model on the VM](#local-models).

### Is it free for my company?

Yes, Open WebUI's license allows commercial use. It adds one rule: don't remove the Open WebUI name and logo, unless your instance has 50 or fewer users in any 30 days or you have an enterprise license.


## Related

- [Self-host Hermes Agent](https://exe-staging.dev/deploy/hermes-agent.md): An agent that remembers you, on a computer that never sleeps.
- [Host OpenClaw](https://exe-staging.dev/deploy/openclaw.md): An AI sidekick with its own computer. Your laptop can take a nap.
- [Self-host n8n](https://exe-staging.dev/deploy/n8n.md): Connect your apps. Let the boring bits run themselves.
- [Run Claude Code on a remote server](https://exe-staging.dev/deploy/claude-code.md): A computer for Claude. A breather for your laptop.
- [VS Code in your browser, with code-server](https://exe-staging.dev/deploy/code-server.md): Your editor in a tab. Your projects right where you left them.
- [Self-host Uptime Kuma](https://exe-staging.dev/deploy/uptime-kuma.md): A little lookout for your websites. Green bars encouraged.
