# Installing on an Ubuntu desktop Start to finish. About an hour, most of it unattended. **Steps 1–4 are the whole tool server**; 5 and 6 are optional extras, and 6 is the big one. Assumes Ubuntu 24.04 or newer with Docker installed, and that you can `sudo`. --- Already running Ollama and Open WebUI? Skip to step 3. ## 1. Ollama and a model Read the header of `docs/deployment/ollama.compose.yml` first: the memory limit and the port binding are the two things most likely to need changing for your machine. Then: ```sh docker compose -f docs/deployment/ollama.compose.yml up -d docker exec ollama ollama pull qwen3.8:latest ``` Any model with tool-calling support works; `qwen3.8` is what this was tuned against. ## 2. Open WebUI Edit `docs/deployment/open-webui.compose.yml` and set `WEBUI_SECRET_KEY` to your own value (`openssl rand -hex 32`). The OIDC block at the bottom is optional — delete it to use the built-in login form. Then: ```sh docker compose -f docs/deployment/open-webui.compose.yml up -d ``` Open , create the first account — it becomes the admin — and **check you can chat before going any further.** If that does not work, nothing downstream will, and the tool server will get the blame. > The compose file pins its project name to `openwebui`, so its network is > `openwebui_default` — which is the name the tool server joins in the next step. If you > already run Open WebUI under some other name, put that network in > `OWUITOOLS_OWUI_NETWORK` instead of renaming anything. ## 3. The tool server ```sh cp configs/owuitools.env.example configs/owuitools.env sed -i "s|^OWUITOOLS_AUTH_TOKEN=.*|OWUITOOLS_AUTH_TOKEN=$(openssl rand -hex 32)|" \ configs/owuitools.env ``` Set `OWUITOOLS_CONTACT` to a real address while you are in there — Wikipedia refuses requests without one. Then generate a secret for SearXNG, which ships with a placeholder: ```sh sed -i "s|^ secret_key: .*| secret_key: \"$(openssl rand -hex 32)\"|" \ configs/services/searxng.settings.yml docker compose up -d --build ``` Give it a minute, then: ```sh ./tests/try-tool.sh # is it up? ./tests/smoke.sh # every tool, through the real path ``` > Nothing here publishes a port to the host — the app container has no default route and > the gateway is only on Open WebUI's docker network. So `curl http://localhost:8000` does > **not** reach the tool server, and may reach something else entirely that answers and > looks healthy. `try-tool.sh` calls it from inside the container instead. `smoke.sh` exercises every tool through the real path. Some cases need the internet and can fail on a slow link; a couple of failures out of 175 is not alarming, twenty is. ## 4. Point Open WebUI at it Two things, both by hand, and the second matters more than the first. **The connection.** *Admin Panel → Settings → **Integrations*** — not your personal settings, or only you will have the tools. | Field | Value | |---|---| | Type | OpenAPI | | URL | `http://owuitools-gw:8000` (or the host's address if not on the same docker network) | | Auth | Bearer, and the token you generated | Save. It fetches the spec; you should see 22 tools. **The model.** *Workspace → Models → your model → Edit*: - paste [`../configs/assistant/system-prompt.md`](../configs/assistant/system-prompt.md) into **System Prompt** - turn the tool connection **on** - **Function Calling: Default**, not Legacy - set `num_ctx` to match what Ollama loaded See [advanced-params.md](advanced-params.md) for the rest and the reasoning. **Try it:** *"what's the current version of ripgrep?"* should call `lookup_package` rather than recalling a number. ### After any change to the tool list ```sh docker compose restart api ``` …then **re-save the connection in Open WebUI**. It caches the spec from when you saved. ## 5. The filters — optional Five small plugins, pasted into Open WebUI. None are required. `inline_tool_images` is the one to install if you plot anything; `vm_agent_progress` is required to *watch* a VM session rather than stare at a spinner. See [filters.md](filters.md). ## 6. The VM sub-agent — optional, and the big one See [setup/vm-agent.md](setup/vm-agent.md). In outline: ```sh sudo ./vm/host/install.sh # users, units, nftables, polkit sudo ./vm/images/import.sh ubuntu # ~9.6 GB, checksum-verified, frozen on arrival ``` That downloads a finished base image. To build one instead — about 25 unattended minutes, and the right choice if you want to change what is in it: ```sh sudo ./vm/images/fetch.sh ubuntu # ~6 GB, verified against Canonical's checksums sudo ./vm/images/ubuntu/build.sh ``` Then open **Tool Server VM Maintenance** from your applications menu and check the Ubuntu row says *frozen*. You will also want [setup/gitea.md](setup/gitea.md) if sessions should publish what they build, and the three timeouts in [advanced-params.md](advanced-params.md) raised, or a long session is cut off with the work already done. --- ## If something is wrong | Symptom | Cause | |---|---| | No tools in the model | Connection added to personal settings instead of Admin → Integrations | | Tools listed but never called | Function Calling set to Legacy; or the system prompt was not pasted | | A tool you switched on is missing | `docker compose restart api`, then re-save the connection | | `wikipedia_lookup` returns 403 | `OWUITOOLS_CONTACT` is unset | | Searches return nothing | SearXNG's engines are blocking your IP — see [setup/searxng.md](setup/searxng.md) | | `vm_agent` fails at ~5 minutes | `AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER` unset; it defaults to 300, not to unlimited | | Everything up, nothing reachable | You recreated `netguard` without recreating `api` — see [configuration.md](configuration.md#servicesthe-supporting-containers) |