stack.basicstack.de/apps/openwebui/openwebui.yaml
CTO b2ee3ffa67 feat(openwebui): deploy Open WebUI v0.11.3 with Pocket ID OIDC (DEV-567)
Adds the Open WebUI stack at openwebui.basicstack.de:

- Namespace `openwebui`, ArgoCD Application with auto-sync + selfHeal
- Own Postgres 16 + pgvector (`pgvector/pgvector:pg16`, 20Gi encrypted PVC,
  fsn1-pinned); VECTOR_DB=pgvector, extension auto-created
- Own Redis 7 (2Gi encrypted PVC, fsn1-pinned) used both as cache and as
  websocket manager (db=1)
- Hetzner Object Storage bucket `openwebui-basicstack` (hel1, path-style)
  for file uploads; shared project S3 credentials
- Traefik ingress + Let's Encrypt TLS
- Pocket ID client `Open WebUI` (PKCE on) restricted to groups
  `openwebui_admins` and `openwebui_users`; `andreas.leinen@basicstack.de`
  is member of both and gets admin via OAUTH_ADMIN_ROLES
- Password login disabled (`ENABLE_LOGIN_FORM=false`, `ENABLE_SIGNUP=false`)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-12 14:06:56 +00:00

279 lines
7.2 KiB
YAML

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: openwebui-data
namespace: openwebui
spec:
accessModes:
- ReadWriteOnce
storageClassName: hcloud-volumes-encrypted
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: openwebui
namespace: openwebui
labels:
app: openwebui
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: openwebui
template:
metadata:
labels:
app: openwebui
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: csi.hetzner.cloud/location
operator: In
values:
- fsn1
initContainers:
- name: wait-for-postgres
image: postgres:16-alpine
command:
- sh
- -c
- |
until pg_isready -h openwebui-postgres -p 5432 -U "$POSTGRES_USER"; do
echo "Waiting for openwebui-postgres..."; sleep 2;
done
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: openwebui-postgres-credentials
key: POSTGRES_USER
- name: wait-for-redis
image: redis:7-alpine
command:
- sh
- -c
- |
until redis-cli -h openwebui-redis -p 6379 ping | grep -q PONG; do
echo "Waiting for openwebui-redis..."; sleep 2;
done
containers:
- name: openwebui
image: ghcr.io/open-webui/open-webui:v0.11.3
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
env:
# Core
- name: PORT
value: "8080"
- name: WEBUI_URL
value: "https://openwebui.basicstack.de"
- name: WEBUI_SECRET_KEY
valueFrom:
secretKeyRef:
name: openwebui-app-secrets
key: WEBUI_SECRET_KEY
- name: ENV
value: "prod"
- name: WEBUI_AUTH
value: "true"
- name: ENABLE_SIGNUP
value: "false"
- name: ENABLE_LOGIN_FORM
value: "false"
# Database (Postgres)
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: openwebui-app-secrets
key: DATABASE_URL
# Vector DB (pgvector)
- name: VECTOR_DB
value: "pgvector"
- name: PGVECTOR_DB_URL
valueFrom:
secretKeyRef:
name: openwebui-app-secrets
key: PGVECTOR_DB_URL
- name: PGVECTOR_CREATE_EXTENSION
value: "true"
# Redis (main + websocket manager)
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: openwebui-app-secrets
key: REDIS_URL
- name: ENABLE_WEBSOCKET_SUPPORT
value: "true"
- name: WEBSOCKET_MANAGER
value: "redis"
- name: WEBSOCKET_REDIS_URL
valueFrom:
secretKeyRef:
name: openwebui-app-secrets
key: WEBSOCKET_REDIS_URL
# Object Storage (Hetzner S3-compatible)
- name: STORAGE_PROVIDER
value: "s3"
- name: S3_BUCKET_NAME
valueFrom:
secretKeyRef:
name: openwebui-s3
key: bucket
- name: S3_REGION_NAME
valueFrom:
secretKeyRef:
name: openwebui-s3
key: region
- name: S3_ENDPOINT_URL
valueFrom:
secretKeyRef:
name: openwebui-s3
key: endpoint
- name: S3_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: openwebui-s3
key: access-key
- name: S3_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: openwebui-s3
key: secret-key
- name: S3_ADDRESSING_STYLE
value: "path"
- name: S3_USE_ACCELERATE_ENDPOINT
value: "false"
# OIDC (Pocket ID)
- name: ENABLE_OAUTH_SIGNUP
value: "true"
- name: OAUTH_MERGE_ACCOUNTS_BY_EMAIL
value: "true"
- name: OAUTH_UPDATE_PICTURE_ON_LOGIN
value: "true"
- name: DEFAULT_USER_ROLE
value: "user"
- name: OAUTH_PROVIDER_NAME
value: "Pocket ID"
- name: OPENID_PROVIDER_URL
value: "https://auth.basicstack.de/.well-known/openid-configuration"
- name: OAUTH_SCOPES
value: "openid email profile groups"
- name: OAUTH_CLIENT_ID
valueFrom:
secretKeyRef:
name: openwebui-oidc
key: client-id
- name: OAUTH_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: openwebui-oidc
key: client-secret
- name: ENABLE_OAUTH_ROLE_MANAGEMENT
value: "true"
- name: ENABLE_OAUTH_GROUP_MANAGEMENT
value: "true"
- name: ENABLE_OAUTH_GROUP_CREATION
value: "true"
- name: OAUTH_ROLES_CLAIM
value: "groups"
- name: OAUTH_ALLOWED_ROLES
value: "openwebui_users,openwebui_admins"
- name: OAUTH_ADMIN_ROLES
value: "openwebui_admins"
- name: OAUTH_GROUPS_CLAIM
value: "groups"
# Runtime
- name: UVICORN_WORKERS
value: "1"
volumeMounts:
- name: openwebui-data
mountPath: /app/backend/data
resources:
requests:
cpu: 250m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
startupProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 60
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 5
readinessProbe:
httpGet:
path: /health/db
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
volumes:
- name: openwebui-data
persistentVolumeClaim:
claimName: openwebui-data
---
apiVersion: v1
kind: Service
metadata:
name: openwebui
namespace: openwebui
labels:
app: openwebui
spec:
type: ClusterIP
selector:
app: openwebui
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: openwebui
namespace: openwebui
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
traefik.ingress.kubernetes.io/router.entrypoints: websecure
spec:
ingressClassName: traefik
tls:
- hosts:
- openwebui.basicstack.de
secretName: openwebui-tls
rules:
- host: openwebui.basicstack.de
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: openwebui
port:
number: 80