Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions services/openweb-ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# openweb-ui stack

This folder defines a Docker Compose stack that runs:

- **tailscale** as the network boundary and HTTPS entrypoint
- **ollama** for local model serving
- **open-webui** for the UI connected to Ollama

## Files

- `docker-compose.yml`: stack definition for all services and Tailscale serve config.
- `stack.env.example`: example environment variables (safe placeholders).

## How the compose setup works

### `configs.ts-serve`
Embeds Tailscale Serve JSON as an inline Docker config:

- Enables HTTPS on TCP 443.
- Publishes `${TS_CERT_DOMAIN}:443`.
- Proxies `/` traffic to `http://127.0.0.1:8080` inside the shared network namespace.
- Explicitly disables Funnel for that domain.

`$${TS_CERT_DOMAIN}` uses double-dollar escaping so Compose passes `${TS_CERT_DOMAIN}` literally into the config payload.

### `tailscale` service
- Uses `tailscale/tailscale:latest`.
- Authenticates with `TS_AUTHKEY`.
- Stores state at `/var/lib/tailscale` (mapped to `/mnt/appdata/tailscale/${SERVICE}/state`).
- Loads serve config from `/config/serve.json` via Compose `configs`.
- Requires `/dev/net/tun` and `NET_ADMIN` capability.
- Exposes host ports:
- `3000 -> 8080`
- `11434 -> 11434`
- Healthcheck probes `http://127.0.0.1:41234/healthz`.

### `ollama` service
- Uses `ollama/ollama:latest`.
- Shares network namespace with Tailscale via `network_mode: service:tailscale`.
- Starts only after Tailscale is healthy.
- Loads variables from `stack.env`.
- Mounts model storage at `/mnt/ai_models/ollama`.
- Requests GPU access with `gpus: all`.

### `open-webui` service
- Uses `ghcr.io/open-webui/open-webui:main`.
- Shares Tailscale network namespace.
- Depends on `ollama`.
- Uses `stack.env` and points to Ollama at `http://127.0.0.1:11434`.
- Stores WebUI data in `/mnt/appdata/open-webui`.

## Usage

1. Copy the env template and fill in real secrets:

```bash
cp stack.env.example stack.env
```

2. Edit `stack.env` with your actual values.

3. Start the stack:

```bash
docker compose up -d
```

4. Check status:

```bash
docker compose ps
```

## Notes

- Keep `stack.env` out of git (contains secrets).
- Ensure the host supports GPU passthrough and has `/dev/net/tun` available.
- `WEBUI_AUTH`, admin email, and admin password are set through environment variables in `stack.env`.
89 changes: 89 additions & 0 deletions services/openweb-ui/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
configs:
ts-serve:
content: |
{
"TCP": {
"443": {
"HTTPS": true
}
},
"Web": {
"$${TS_CERT_DOMAIN}:443": {
"Handlers": {
"/": {
"Proxy": "http://127.0.0.1:8080"
}
}
}
},
"AllowFunnel": {
"$${TS_CERT_DOMAIN}:443": false
}
}

services:
tailscale:
image: tailscale/tailscale:latest
container_name: tailscale-${SERVICE}
hostname: ${SERVICE}
environment:
- TS_AUTHKEY=${TS_AUTHKEY}
- TS_STATE_DIR=/var/lib/tailscale
- TS_SERVE_CONFIG=/config/serve.json
- TS_USERSPACE=false
- TS_ENABLE_HEALTH_CHECK=true
- TS_LOCAL_ADDR_PORT=127.0.0.1:41234
- TS_AUTH_ONCE=true
- TS_ACCEPT_DNS=true
configs:
- source: ts-serve
target: /config/serve.json
volumes:
- /mnt/appdata/tailscale/${SERVICE}/state:/var/lib/tailscale
devices:
- /dev/net/tun:/dev/net/tun
cap_add:
- net_admin
ports:
- "3000:8080"
- "11434:11434"
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:41234/healthz"]
interval: 1m
timeout: 10s
retries: 3
start_period: 10s
restart: always

ollama:
image: ollama/ollama:latest
container_name: ollama-${SERVICE}
network_mode: service:tailscale
depends_on:
tailscale:
condition: service_healthy
env_file:
- stack.env
environment:
- TZ=${TZ}
- OLLAMA_HOST=0.0.0.0:11434
volumes:
- /mnt/ai_models/ollama:/root/.ollama
gpus: all
restart: unless-stopped

open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-webui-${SERVICE}
network_mode: service:tailscale
depends_on:
- ollama
env_file:
- stack.env
environment:
- TZ=${TZ}
- OLLAMA_BASE_URL=http://127.0.0.1:11434
- WEBUI_AUTH=${WEBUI_AUTH}
volumes:
- /mnt/appdata/open-webui:/app/backend/data
restart: unless-stopped
9 changes: 9 additions & 0 deletions services/openweb-ui/stack.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
SERVICE=ai
TS_AUTHKEY=tskey-auth-REPLACE_ME
TS_CERT_DOMAIN=ai.example.ts.net
TZ=Europe/London
OLLAMA_HOST=0.0.0.0:11434
OLLAMA_BASE_URL=http://ollama:11434
WEBUI_AUTH=True
WEBUI_ADMIN_EMAIL=admin@example.com
WEBUI_ADMIN_PASSWORD=REPLACE_WITH_STRONG_PASSWORD