Ollama qui tourne en ligne de commande, c’est bien pour tester. Mais quand tu veux utiliser un LLM local au quotidien – garder l’historique d’une conversation, basculer entre modèles, partager l’accès à d’autres utilisateurs sur ton réseau – l’API curl a ses limites. Open WebUI règle ça avec une interface qui ressemble suffisamment à ChatGPT pour être intuitive immédiatement.
Prérequis
Cet article est la suite directe du précédent. Il faut qu’Ollama tourne sur une VM Ubuntu 24.04 dans Proxmox VE 8.3, avec l’API exposée sur le réseau local (port 11434). Si tu pars de zéro, lis d’abord l’article sur l’installation d’Ollama.
Ma VM Ollama est sur le VLAN Serveurs (30), adresse IP 10.10.30.42. C’est cette adresse que Open WebUI va utiliser pour se connecter à Ollama.
Choix d’architecture : VM ou LXC séparé
J’aurais pu installer Open WebUI directement sur la même VM qu’Ollama, via Docker. J’ai préféré créer un LXC séparé, le LXC 105 sur heighliner. Deux raisons. D’abord, séparer les responsabilités : la VM Ollama gère l’inférence et la RAM qui va avec, le LXC Open WebUI gère uniquement le frontend et la base de données de conversations. Ensuite, si je veux remplacer Open WebUI par autre chose, je détruis le LXC sans toucher à Ollama.
Le LXC 105 est un LXC Debian 12 non-privilégié avec Docker installé dedans (ce qui nécessite quelques ajustements sur Proxmox – je couvre ça brièvement plus bas). Allocation : 2 vCPU, 4 GB RAM, 20 GB disque. Open WebUI est léger côté CPU : il ne fait pas d’inférence, il délègue tout à Ollama.
Docker dans un LXC Proxmox
Pour faire tourner Docker dans un LXC Proxmox non-privilégié, il faut activer le keyctl et désactiver l’AppArmor dans la configuration du LXC. Dans /etc/pve/lxc/105.conf sur heighliner :
features: keyctl=1,nesting=1
lxc.apparmor.profile: unconfined
`lxc.apparmor.profile: unconfined` désactive la couche d’isolation AppArmor sur ce LXC. C’est acceptable sur un réseau homelab interne, mais ne fais pas ça pour des LXC exposés sur Internet ou qui font tourner des services critiques.
Après avoir appliqué ces changements et redémarré le LXC, l’installation de Docker se fait normalement via le script officiel Docker.
Installation d’Open WebUI
Dans le LXC 105, j’utilise Docker Compose. Voici le docker-compose.yml minimal pour Open WebUI :
services:
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-webui
restart: unless-stopped
ports:
- "3000:8080"
volumes:
- /opt/open-webui/data:/app/backend/data
environment:
- OLLAMA_BASE_URL=http://10.10.30.42:11434
- WEBUI_SECRET_KEY=change_this_to_a_random_string
mkdir -p /opt/open-webui/data
cd /opt/open-webui
docker compose up -d
Génère une clé secrète aléatoire avec `openssl rand -hex 32` et mets-la dans `WEBUI_SECRET_KEY`. Cette clé signe les sessions utilisateurs – si elle change, tous les utilisateurs sont déconnectés.
Au premier démarrage, Open WebUI télécharge son image (~1.5 GB), initialise la base de données SQLite dans /opt/open-webui/data/, et est accessible sur http://10.10.30.105:3000 (ou ton IP de LXC).
La version que j’utilise : Open WebUI 0.3.x (l’image main se met à jour fréquemment – épingle une version spécifique comme ghcr.io/open-webui/open-webui:v0.3.35 si tu veux de la stabilité).
Premier démarrage : créer l’admin et sécuriser l’accès
À la première connexion depuis un navigateur, Open WebUI te propose de créer un compte administrateur. Ce compte a accès à tous les paramètres, la gestion des utilisateurs et les modèles disponibles. Crée-le immédiatement.
L’étape critique ensuite : désactiver l’inscription publique. Par défaut, n’importe qui qui peut atteindre ton instance Open WebUI peut créer un compte. Sur un réseau homelab fermé c’est peu dangereux, mais si tu exposes Open WebUI via ton reverse proxy (Traefik dans mon cas), c’est un problème réel.
Dans l’interface admin, va dans Admin Panel > Settings > General et désactive « Enable New Sign Ups ». Désactive aussi « Enable Community Sharing » si tu n’en as pas besoin.
Admin Panel → Settings → General
☐ Enable New Sign Ups ← désactiver
☐ Enable Community Sharing ← désactiver
Pour créer des comptes supplémentaires après avoir désactivé l’inscription publique, tu passes par Admin Panel > Users > Add User. Tu contrôles qui a accès.
Exposer via Traefik
J’expose Open WebUI sur chat.arewel.com via Traefik v3 qui tourne sur le VLAN Serveurs. Les labels dans le docker-compose.yml :
labels:
- "traefik.enable=true"
- "traefik.http.routers.openwebui.rule=Host(`chat.arewel.com`)"
- "traefik.http.routers.openwebui.entrypoints=websecure"
- "traefik.http.routers.openwebui.tls.certresolver=letsencrypt"
- "traefik.http.services.openwebui.loadbalancer.server.port=8080"
Traefik gère le certificat Let’s Encrypt automatiquement. L’accès externe est possible depuis https://chat.arewel.com avec authentification via les comptes Open WebUI.
Connexion Authentik via OAuth2
J’ai Authentik comme IdP sur le homelab pour centraliser l’authentification. Open WebUI supporte OAuth2/OIDC nativement. Dans Authentik, j’ai créé une application OAuth2 avec comme redirect URI https://chat.arewel.com/oauth/oidc/callback.
Dans Open WebUI, Admin Panel > Settings > Auth > OAuth, on configure :
Client ID: [l'ID de l'application Authentik]
Client Secret: [le secret généré par Authentik]
OpenID Connect URL: https://authentik.arewel.com/application/o/open-webui/.well-known/openid-configuration
OAuth Provider Name: Authentik
Avec ça, le bouton « Login with Authentik » apparaît sur l’écran de connexion. Les utilisateurs qui ont un compte Authentik peuvent se connecter sans créer de compte Open WebUI séparé – utile si d’autres membres du foyer utilisent le homelab.
Dans Authentik, définis qui a accès à l’application Open WebUI via les policies. Sinon tous tes utilisateurs Authentik peuvent se connecter, y compris ceux qui n’ont pas besoin d’un LLM local.
Fonctionnalités qui servent vraiment
L’historique de conversations est la première chose qui change l’usage. Avec l’API curl, chaque requête est isolée. Dans Open WebUI, les conversations sont sauvegardées et accessibles depuis le panneau latéral, classées par date. Je retrouve une conversation de la semaine dernière sur un script bash en deux secondes.
Les system prompts (appelés « Models » dans l’UI) permettent de créer des personnages avec un prompt système prédéfini. J’en ai créé un « SRE Assistant » avec un prompt qui demande au modèle de répondre en français, de favoriser les commandes exactes sur les explications générales, et de préciser quand il n’est pas sûr de quelque chose. Ce personnage est sélectionnable dans toutes mes conversations.
La gestion des modèles depuis l’interface admin est pratique : tu peux télécharger de nouveaux modèles Ollama depuis l’UI d’Open WebUI sans passer par la ligne de commande de la VM Ollama. L’opération s’exécute sur la VM Ollama via l’API, mais elle est déclenchée depuis Open WebUI.
Le RAG : utile dans certains cas, décevant dans d’autres
Open WebUI intègre une fonctionnalité RAG (Retrieval-Augmented Generation) : tu peux uploader des documents (PDF, texte, HTML) et les modèles peuvent y puiser des informations pour répondre à tes questions. En théorie, c’est très utile – un LLM local qui répond sur ta documentation interne, sans que cette documentation quitte ton réseau.
En pratique, les résultats sont décevants sur les modèles 7-9B. J’ai uploadé la documentation d’une API interne (une cinquantaine de pages de PDF exporté depuis Confluence). Sur des questions précises sur des endpoints spécifiques, Phi-4 Mini et Llama 3.1 8B donnent des réponses qui mélangent le contenu du document avec leurs connaissances d’entraînement. Les hallucinations ne disparaissent pas, elles changent juste de source.
Le RAG fonctionne mieux avec du contexte court et structuré. Un fichier de configuration YAML bien formaté, un README court, un script commenté – là, les modèles s’en sortent mieux. Un PDF de 50 pages avec des sections imbriquées, des tableaux, du contenu mixte : les résultats sont peu fiables.
Ce n’est pas un défaut d’Open WebUI – c’est une limite des modèles eux-mêmes à cette taille. Les modèles 70B auraient de meilleurs résultats sur ce type de tâche, mais on a vu dans l’article précédent que 70B n’est pas réaliste sur notre config CPU.
Ce qui a coincé
Le premier problème : Open WebUI ne se connectait pas à Ollama au démarrage et affichait « Ollama connection error » dans l’interface. La cause était triviale – j’avais oublié que le firewall Ubuntu sur la VM Ollama bloquait les connexions depuis l’IP du LXC. Un ufw allow from 10.10.30.105 to any port 11434 sur la VM Ollama a réglé ça.
Le deuxième problème : après avoir activé OAuth2 Authentik, les utilisateurs qui se connectaient via OAuth2 recevaient le rôle « pending » par défaut, ce qui les empêche d’utiliser les modèles. Dans Admin Panel > Settings > Auth, il faut changer le « Default User Role » à « user » (pas « pending »). Sinon tu dois approuver manuellement chaque nouvel utilisateur OAuth2.
La mise à jour de l’image Open WebUI main a cassé une fois les conversations existantes – une migration de schéma SQLite s’est mal passée. Depuis, j’épingle une version spécifique dans le docker-compose.yml et je fais les mises à jour en lisant les release notes sur le GitHub d’Open WebUI d’abord.
Coût et honnêteté sur la qualité
Coût total de la stack : 0€ de licences ou d’APIs. Le coût électrique d’une session d’usage d’Ollama sur le MS-01 est négligeable – Shelly EM mesure environ 25-30 W en charge CPU pour l’inférence, contre 15 W idle. Une heure d’usage intensif coûte quelques centimes.
Sur la qualité : pour du scripting bash, de la reformulation de paragraphes, de la complétion de configurations, la stack Ollama + Open WebUI est utilisable et je m’en sers régulièrement. Pour de la génération de contenu complexe, du debugging d’architecture, de l’analyse de logs non structurés, Claude reste significativement meilleur. Ce n’est pas une raison de ne pas faire tourner Ollama – c’est juste la réalité des capacités actuelles des modèles locaux à 7-9B paramètres.
La valeur principale reste la confidentialité. Quand j’analyse un fichier de configuration avec des adresses IP internes ou des noms d’hôtes privés, ça reste sur heighliner. C’est suffisant pour justifier la stack.