Chat local ouvert sur le web

Depuis qu’Ollama tourne sur mon serveur, l’étape suivante était inévitable : lui coller une vraie interface de chat et lui donner accès à internet. Pas pour un vrai concurrent capable remplacer un ChatGPT ou un Perplexity, mais pour la beauté du geste. D’avoir un outil souverain, sans tracker, sans abonnement, qui tourne 24/7 sur mon serveur. Le duo gagnant pour ça en complément d’Ollama déjà en place, c’est Open WebUI pour l’interface, et SearXNG pour la recherche web. Tout ça intégré dans mon Docker Compose derrière Traefik, évidemment.

Le principe

Open WebUI, c’est l’interface qui parle à Ollama. Elle ressemble à ChatGPT, supporte plusieurs modèles, gère l’authentification, l’historique des conversations, les fichiers, les RAG locaux… et depuis quelques versions, elle intègre nativement une connexion à un moteur de recherche web via son système de Web Search. C’est là qu’entre SearXNG : un méta-moteur open source auto-hébergeable qui agrège Google, Bing, DuckDuckGo et consorts sans jamais identifier l’utilisateur. Quand le modèle a besoin d’une info récente, Open WebUI interroge SearXNG, récupère les résultats, les injecte dans le contexte, et le LLM synthétise. C’est propre et totalement transparent.

Le docker-compose

Voici les trois blocs à ajouter ou intégrer dans le docker-compose.yml existant. J’assume qu’Ollama est déjà en place, si ce n’est pas le cas, le bloc est inclus pour référence.

services:

  ollama:
    container_name: ollama
    image: ollama/ollama:latest
    restart: unless-stopped
    volumes:
      - ollama_data:/root/.ollama
    ports:
      - "11434:11434"
    environment:
      - OLLAMA_HOST=0.0.0.0
      - OLLAMA_NUM_THREADS=2
    deploy:
      resources:
        limits:
          memory: 4G
          cpus: '4'
    labels:
      - "traefik.enable=false"

  open-webui:
    container_name: open-webui
    image: ghcr.io/open-webui/open-webui:main
    restart: unless-stopped
    depends_on:
      - ollama
    volumes:
      - open_webui_data:/app/backend/data
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
      - WEBUI_SECRET_KEY=changeme
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.openwebui.rule=Host(`chat.domaine`)"
      - "traefik.http.services.openwebui.loadbalancer.server.port=8080"

  searxng:
    container_name: searxng
    image: searxng/searxng:latest
    restart: unless-stopped
    volumes:
      - ./searxng:/etc/searxng:rw
    environment:
      - SEARXNG_BASE_URL=https://search.domaine
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.searxng.rule=Host(`search.domaine`)"
      - "traefik.http.services.searxng.loadbalancer.server.port=8080"

volumes:
  ollama_data:
  open_webui_data:

Une remarque sur SearXNG : il a besoin d’un fichier de configuration au démarrage, sans quoi il refuse de se lancer. Il faut créer le répertoire ./searxng/ à la racine du projet, avec un settings.yml minimal dedans. La façon la plus rapide de l’obtenir depuis le serveur host :

mkdir searxng
docker run --rm searxng/searxng cat /etc/searxng/settings.yml > searxng/settings.yml

Ensuite, deux lignes à vérifier dans ce fichier pour autoriser et formater les requêtes JSON qu’Open WebUI va envoyer :

search:
  formats:
    - html
    - json

Sans le format json, Open WebUI ne recevra rien d’exploitable et la recherche web restera inopérante. C’est le genre de détail sur lequel on peut passer des heures à déboguer.

Brancher la recherche web dans Open WebUI

Une fois les services up (docker compose up -d), on ouvre l’interface sur le sous-domaine configuré. Première connexion : création d’un compte admin local, rien de spécial. Ensuite, direction Paramètres → Admin → Web Search.

  • Activer Enable Web Search
  • Choisir SearXNG comme moteur
  • Renseigner l’URL interne : http://searxng:8080 (résolution Docker, pas le sous-domaine externe)
  • Sauvegarder

De retour dans une conversation, une petite icône de globe apparaît dans la barre de saisie. En l’activant, le modèle ira chercher sur le web avant de répondre. Il cite ses sources dans la réponse, ce qui permet de vérifier ce qu’il a réellement ingéré.

Choisir le bon modèle

Open WebUI propose un téléchargement direct depuis Ollama Library. Depuis l’interface admin, il suffit de taper le nom du modèle voulu. Pour un serveur sans GPU dédié, comme dans mon cas, gemma3:4b ou qwen2.5:7b offrent un bon compromis vitesse/qualité sur CPU. Si la machine à 16 Go de RAM disponibles, mistral:7b reste une valeur sûre quoique le tout récent gemma4:e4b semble prometteur.  Pour la recherche web en particulier, un modèle avec une bonne fenêtre de contexte fait la différence : il doit digérer plusieurs résultats de recherche en plus de la question. L’installation en commande se fait avec l’habituelle :

ollama pull qwen2.5:7b

Ou directement depuis l’interface Open WebUI → Paramètres → Modèles → Télécharger un modèle.

Ce que ça donne vraiment

La recherche web fonctionne bien sur des questions d’actualité ou des faits datés. Le modèle récupère 3 à 5 résultats, les synthétise et répond avec les liens sources. C’est honnêtement proche de ce que fait Perplexity, à la latence en plus, sur CPU, chaque échange prend quelques secondes de plus qu’avec un service cloud. Rien de rédhibitoire pour un usage personnel.

Ce que j’apprécie par-dessus tout, l’argument de fond, plus que la gratuité, c’est que SearXNG ne transmet aucun identifiant aux moteurs qu’il interroge. Les requêtes que le modèle génère pour chercher sur le web ne sont pas associées à un compte. On ne peut empêcher qu’elles soient loggées chez Google, ou utilisées pour entraîner un autre modèle.

La prochaine étape logique : brancher une base documentaire locale (RAG) pour que le modèle puisse répondre sur nos documents plutôt que sur le web. Open WebUI supporte ça nativement aussi. La suite serait également d’avoir un asisstant sys-admin dans le terminal. Mais ça, c’est pour un prochain article.

By tech