Files
ouranos/docs/openwebui.md
Robert Helewka b4d60f2f38 docs: rewrite README with structured overview and quick start guide
Replaces the minimal project description with a comprehensive README
including a component overview table, quick start instructions, common
Ansible operations, and links to detailed documentation. Aligns with
Red Panda Approval™ standards.
2026-03-03 12:49:06 +00:00

11 KiB

Open WebUI

Open WebUI is an extensible, self-hosted AI interface that provides a web-based chat experience for interacting with LLMs. This document covers deployment, Casdoor SSO integration, and configuration.

Architecture

Components

Component Location Purpose
Open WebUI Native on Oberon AI chat interface
PostgreSQL Portia Database with pgvector extension
Casdoor Titania SSO identity provider
HAProxy Ariel TLS termination, routing

Network Diagram

┌────────────────────────────────────────────────────────────────────┐
│  External Access                                                    │
│  https://openwebui.ouranos.helu.ca                                │
└───────────────────────────────┬────────────────────────────────────┘
                                │
                                ▼
┌────────────────────────────────────────────────────────────────────┐
│  ariel.incus (HAProxy)                                             │
│  TLS termination → proxy to oberon.incus:25588                     │
└───────────────────────────────┬────────────────────────────────────┘
                                │
                                ▼
┌────────────────────────────────────────────────────────────────────┐
│  oberon.incus                                                       │
│                                                                     │
│  ┌────────────────────────────────────────────────────────────────┐ │
│  │  Open WebUI (systemd)                                          │ │
│  │  - Python 3.12 virtual environment                             │ │
│  │  - Port 25588                                                  │ │
│  │  - OAuth/OIDC via Casdoor                                      │ │
│  └────────────────────────────────────────────────────────────────┘ │
│           │                              │                          │
│           │ PostgreSQL                   │ OIDC                     │
│           ▼                              ▼                          │
│  portia.incus:5432              titania.incus:22081                 │
│  (openwebui database)           (Casdoor SSO)                       │
└────────────────────────────────────────────────────────────────────┘

Network Ports

Port Service Access
25588 Open WebUI HTTP Via HAProxy
5432 PostgreSQL Internal (Portia)
22081 Casdoor Internal (Titania)

Casdoor SSO Integration

Open WebUI uses native OAuth/OIDC to authenticate against Casdoor. Local signup is disabled—all users must authenticate through Casdoor.

How It Works

  1. User visits https://openwebui.ouranos.helu.ca
  2. Open WebUI redirects to Casdoor login page
  3. User authenticates with Casdoor credentials
  4. Casdoor redirects back with authorization code
  5. Open WebUI exchanges code for tokens and creates/updates user session
  6. User email from Casdoor becomes their Open WebUI identity

Configuration

OAuth settings are defined in host variables and rendered into the environment file:

Host Variables (inventory/host_vars/oberon.incus.yml):

# OAuth/OIDC Configuration (Casdoor SSO)
openwebui_oauth_client_id: "{{ vault_openwebui_oauth_client_id }}"
openwebui_oauth_client_secret: "{{ vault_openwebui_oauth_client_secret }}"
openwebui_oauth_provider_name: "Casdoor"
openwebui_oauth_provider_url: "https://id.ouranos.helu.ca/.well-known/openid-configuration"

# Disable local authentication
openwebui_enable_signup: false
openwebui_enable_email_login: false

Environment Variables (rendered from openwebui.env.j2):

ENABLE_SIGNUP=false
ENABLE_EMAIL_LOGIN=false
ENABLE_OAUTH_SIGNUP=true
OAUTH_CLIENT_ID=<client-id>
OAUTH_CLIENT_SECRET=<client-secret>
OAUTH_PROVIDER_NAME=Casdoor
OPENID_PROVIDER_URL=https://id.ouranos.helu.ca/.well-known/openid-configuration

Casdoor Application

The app-openwebui application is defined in ansible/casdoor/init_data.json.j2:

Setting Value
Name app-openwebui
Display Name Open WebUI
Redirect URI https://openwebui.ouranos.helu.ca/oauth/oidc/callback
Grant Types authorization_code, refresh_token
Token Format JWT
Token Expiry 168 hours (7 days)

Prerequisites

1. PostgreSQL Database

The openwebui database must exist on Portia with the pgvector extension:

ansible-playbook postgresql/deploy.yml

2. Casdoor SSO

Casdoor must be deployed and the app-openwebui application configured:

ansible-playbook casdoor/deploy.yml

3. Vault Secrets

Add to ansible/inventory/group_vars/all/vault.yml:

# OpenWebUI
vault_openwebui_secret_key: "<random-secret>"
vault_openwebui_db_password: "<database-password>"
vault_openwebui_oauth_client_id: "<from-casdoor>"
vault_openwebui_oauth_client_secret: "<from-casdoor>"

# API Keys (optional)
vault_openwebui_openai_api_key: "<openai-key>"
vault_openwebui_anthropic_api_key: "<anthropic-key>"
vault_openwebui_groq_api_key: "<groq-key>"
vault_openwebui_mistral_api_key: "<mistral-key>"

Generate secrets:

# Secret key
openssl rand -hex 32

# Database password
openssl rand -base64 24

Deployment

Fresh Installation

cd ansible

# 1. Ensure PostgreSQL is deployed
ansible-playbook postgresql/deploy.yml

# 2. Deploy Casdoor (if not already deployed)
ansible-playbook casdoor/deploy.yml

# 3. Get OAuth credentials from Casdoor admin UI
#    - Navigate to https://id.ouranos.helu.ca
#    - Go to Applications → app-openwebui
#    - Copy Client ID and Client Secret
#    - Update vault.yml with these values

# 4. Deploy Open WebUI
ansible-playbook openwebui/deploy.yml

Verify Deployment

# Check service status
ssh oberon.incus "sudo systemctl status openwebui"

# View logs
ssh oberon.incus "sudo journalctl -u openwebui -f"

# Test health endpoint
curl -s http://oberon.incus:25588/health

# Test via HAProxy
curl -s https://openwebui.ouranos.helu.ca/health

Redeployment

To redeploy Open WebUI (preserves database):

ansible-playbook openwebui/deploy.yml

Configuration Reference

Host Variables

Located in ansible/inventory/host_vars/oberon.incus.yml:

# Service account
openwebui_user: openwebui
openwebui_group: openwebui
openwebui_directory: /srv/openwebui
openwebui_port: 25588
openwebui_host: puck.incus

# Database
openwebui_db_host: portia.incus
openwebui_db_port: 5432
openwebui_db_name: openwebui
openwebui_db_user: openwebui
openwebui_db_password: "{{ vault_openwebui_db_password }}"

# Authentication (SSO only)
openwebui_enable_signup: false
openwebui_enable_email_login: false

# OAuth/OIDC (Casdoor)
openwebui_oauth_client_id: "{{ vault_openwebui_oauth_client_id }}"
openwebui_oauth_client_secret: "{{ vault_openwebui_oauth_client_secret }}"
openwebui_oauth_provider_name: "Casdoor"
openwebui_oauth_provider_url: "https://id.ouranos.helu.ca/.well-known/openid-configuration"

# API Keys
openwebui_openai_api_key: "{{ vault_openwebui_openai_api_key }}"
openwebui_anthropic_api_key: "{{ vault_openwebui_anthropic_api_key }}"
openwebui_groq_api_key: "{{ vault_openwebui_groq_api_key }}"
openwebui_mistral_api_key: "{{ vault_openwebui_mistral_api_key }}"

Data Persistence

Open WebUI data locations:

/srv/openwebui/
├── .venv/                    # Python virtual environment
├── .env                      # Environment configuration
└── data/                     # User uploads, cache

Database (on Portia):

PostgreSQL: openwebui database with pgvector extension

User Management

First-Time Setup

After deployment, the first user to authenticate via Casdoor becomes an admin. Subsequent users get standard user roles.

Promoting Users to Admin

  1. Log in as an existing admin
  2. Navigate to Admin Panel → Users
  3. Select the user and change their role to Admin

Existing Users Migration

If users were created before SSO was enabled:

  • Users with matching email addresses will be linked automatically
  • Users without matching emails must be recreated through Casdoor

Troubleshooting

Service Issues

# Check service status
ssh oberon.incus "sudo systemctl status openwebui"

# View logs
ssh oberon.incus "sudo journalctl -u openwebui -n 100"

# Restart service
ssh oberon.incus "sudo systemctl restart openwebui"

OAuth/OIDC Issues

# Verify Casdoor is accessible
curl -s https://id.ouranos.helu.ca/.well-known/openid-configuration | jq

# Check redirect URI matches
# Must be: https://openwebui.ouranos.helu.ca/oauth/oidc/callback

# Verify client credentials in environment
ssh oberon.incus "sudo grep OAUTH /srv/openwebui/.env"

Database Issues

# Test database connection
ssh oberon.incus "PGPASSWORD=<password> psql -h portia.incus -U openwebui -d openwebui -c '\dt'"

# Check pgvector extension
ssh portia.incus "sudo -u postgres psql -d openwebui -c '\dx'"

Common Errors

Error Cause Solution
"Invalid redirect_uri" Mismatch between Casdoor config and Open WebUI Verify redirect URI in Casdoor matches exactly
"Invalid client credentials" Wrong client ID/secret Update vault with correct values from Casdoor
"OIDC discovery failed" Casdoor unreachable Check Casdoor is running on Titania
"Database connection failed" PostgreSQL unreachable Verify PostgreSQL on Portia, check network

Security Considerations

  1. SSO-only authentication - Local signup disabled, all users authenticate through Casdoor
  2. API keys in vault - All API keys stored encrypted in Ansible vault
  3. Database credentials - Stored in vault, rendered to environment file with restrictive permissions (0600)
  4. Session security - JWT tokens with 7-day expiry, managed by Casdoor