{"id":108,"date":"2026-08-18T21:31:48","date_gmt":"2026-08-18T19:31:48","guid":{"rendered":"https:\/\/homelab.nvsd.ch\/?p=108"},"modified":"2026-08-18T21:33:44","modified_gmt":"2026-08-18T19:33:44","slug":"ia-locale-podman-ollama-open-webui-popos","status":"publish","type":"post","link":"https:\/\/homelab.nvsd.ch\/?p=108","title":{"rendered":"Construire une IA locale avec Podman, Ollama et Open WebUI sous Pop!_OS"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Je voulais int\u00e9grer une IA locale \u00e0 mon Homelab sans transformer mon poste de travail en serveur d\u00e9di\u00e9. L\u2019objectif \u00e9tait simple \u00e0 formuler : faire fonctionner <strong>Ollama<\/strong> et <strong>Open WebUI<\/strong> dans des conteneurs <strong>Podman rootless<\/strong>, conserver les donn\u00e9es sur mon disque Homelab, et exploiter ma <strong>NVIDIA GeForce GTX 1650 de 4 Go<\/strong> pour l\u2019inf\u00e9rence.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dans la pratique, cette installation m\u2019a surtout appris qu\u2019une architecture propre ne se r\u00e9sume pas \u00e0 faire d\u00e9marrer deux conteneurs. Il a fallu organiser le stockage, valider l\u2019acc\u00e8s au GPU couche par couche, r\u00e9soudre une incompatibilit\u00e9 entre Podman et NVIDIA Container Toolkit, puis simplifier la communication entre Open WebUI et Ollama.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Le r\u00e9sultat final est plus simple que certaines de mes premi\u00e8res tentatives : <strong>Pop!_OS \/ COSMIC, Podman rootless, NVIDIA CDI, Ollama, Open WebUI, un r\u00e9seau d\u00e9di\u00e9 <code>ai-net<\/code>, des donn\u00e9es persistantes sous <code>\/srv\/homelab<\/code>, et un d\u00e9marrage \u00e0 la demande depuis Podman Desktop.<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"homelab-podman-ollama-open-webui-gpu.png\" alt=\"Homelab local sous Pop!_OS avec Podman rootless, GPU NVIDIA, Ollama et Open WebUI\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Pourquoi construire mon environnement d\u2019IA locale avec Podman<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ma machine locale fonctionne sous <strong>Pop!_OS \/ COSMIC<\/strong>. Elle me sert \u00e0 la fois de poste de travail et de laboratoire : navigateur, outils de d\u00e9veloppement, conteneurs, tests, IA locale et diff\u00e9rents projets du Homelab doivent cohabiter.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Je ne voulais donc pas installer une pile d\u2019outils directement dans le syst\u00e8me ni laisser une IA monopoliser les ressources en permanence.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">J\u2019ai choisi <strong>Podman rootless<\/strong> comme moteur de conteneurs. Le principe est important : les conteneurs s\u2019ex\u00e9cutent dans le contexte de mon utilisateur, sans faire reposer toute l\u2019exploitation sur un d\u00e9mon central lanc\u00e9 avec les privil\u00e8ges root.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ce choix devait aussi s\u2019int\u00e9grer \u00e0 l\u2019organisation g\u00e9n\u00e9rale du Homelab.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Organiser le stockage avant l\u2019IA<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Avant de d\u00e9ployer Ollama ou Open WebUI, j\u2019ai s\u00e9par\u00e9 les fichiers de configuration des donn\u00e9es persistantes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mon organisation repose principalement sur :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/srv\/homelab\/\n\u251c\u2500\u2500 stacks\/\n\u251c\u2500\u2500 data\/\n\u2514\u2500\u2500 containers\/<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Les fichiers Compose sont stock\u00e9s sous :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/srv\/homelab\/stacks\/<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Les donn\u00e9es applicatives persistantes restent sous :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/srv\/homelab\/data\/<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Le stockage interne utilis\u00e9 par Podman rootless a \u00e9galement \u00e9t\u00e9 d\u00e9plac\u00e9 vers le disque Homelab. La configuration utilise un <code>graphroot<\/code> d\u00e9di\u00e9 :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;storage]\ngraphroot = \"\/srv\/homelab\/containers\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Apr\u00e8s cette modification, j\u2019ai valid\u00e9 que Podman fonctionnait bien en mode rootless avec le pilote de stockage <code>overlay<\/code>, puis j\u2019ai lanc\u00e9 un conteneur de test avant d\u2019aller plus loin.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Cette \u00e9tape peut sembler secondaire, mais elle \u00e9vite de m\u00e9langer les couches. Si un simple conteneur Alpine ne fonctionne pas, il est inutile de commencer \u00e0 diagnostiquer CUDA ou Ollama.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Deux disques mont\u00e9s automatiquement<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Le disque principal du Homelab est mont\u00e9 sur :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/srv\/homelab<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Le disque destin\u00e9 aux sauvegardes est mont\u00e9 sur :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/srv\/homelab-backup<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Je peux ainsi conserver une architecture stable ind\u00e9pendamment du cycle de vie des conteneurs. Les stacks peuvent \u00eatre recr\u00e9\u00e9es, tandis que les donn\u00e9es restent sur l\u2019h\u00f4te.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La strat\u00e9gie de sauvegarde m\u00e9rite un article distinct ; ici, l\u2019important est que le stockage ait \u00e9t\u00e9 pens\u00e9 avant les services.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Le vrai d\u00e9fi : faire fonctionner la GTX 1650 dans Podman<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ma machine dispose d\u2019une <strong>NVIDIA GeForce GTX 1650 avec 4 Go de VRAM<\/strong>. Pour une IA locale, cette quantit\u00e9 de m\u00e9moire impose naturellement des mod\u00e8les modestes, mais elle reste suffisante pour exp\u00e9rimenter avec une acc\u00e9l\u00e9ration GPU r\u00e9elle.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La premi\u00e8re validation doit toujours se faire sur l\u2019h\u00f4te.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>nvidia-smi<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Tant que cette commande ne voit pas correctement la carte graphique et le pilote NVIDIA, il ne sert \u00e0 rien d\u2019accuser Podman.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Une fois le GPU valid\u00e9 c\u00f4t\u00e9 syst\u00e8me, il reste encore plusieurs couches :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>GPU NVIDIA\n    \u2193\npilote NVIDIA\n    \u2193\nNVIDIA Container Toolkit\n    \u2193\nCDI\n    \u2193\nPodman\n    \u2193\nconteneur\n    \u2193\nOllama<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">C\u2019est pr\u00e9cis\u00e9ment cette cha\u00eene qui m\u2019a pos\u00e9 probl\u00e8me.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Podman 4.9.3 et NVIDIA Container Toolkit 1.20 : premi\u00e8re impasse<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">J\u2019avais install\u00e9 <strong>NVIDIA Container Toolkit 1.20.0<\/strong> avec <strong>Podman 4.9.3<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Le GPU \u00e9tait parfaitement visible sur l\u2019h\u00f4te, mais Podman n\u2019arrivait pas \u00e0 r\u00e9soudre correctement le p\u00e9riph\u00e9rique CDI NVIDIA. Le sympt\u00f4me se situait donc apr\u00e8s le pilote et avant l\u2019application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Le point important n\u2019\u00e9tait pas de modifier Ollama au hasard. J\u2019ai d\u2019abord r\u00e9duit le probl\u00e8me \u00e0 son niveau le plus bas : <strong>faire voir le GPU \u00e0 un conteneur ind\u00e9pendant d\u2019Ollama et d\u2019Open WebUI<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/homelab.nvsd.ch\/wp-content\/uploads\/2026\/08\/podman-nvidia-cdi-gpu-diagnostic-1024x576.png\" alt=\"Diagnostic GPU de Pop!_OS \u00e0 Ollama avec Podman 4.9.3, NVIDIA Container Toolkit 1.20 puis 1.18.2, CDI et nvidia-smi\" class=\"wp-image-111\" srcset=\"https:\/\/homelab.nvsd.ch\/wp-content\/uploads\/2026\/08\/podman-nvidia-cdi-gpu-diagnostic-1024x576.png 1024w, https:\/\/homelab.nvsd.ch\/wp-content\/uploads\/2026\/08\/podman-nvidia-cdi-gpu-diagnostic-300x169.png 300w, https:\/\/homelab.nvsd.ch\/wp-content\/uploads\/2026\/08\/podman-nvidia-cdi-gpu-diagnostic-768x432.png 768w, https:\/\/homelab.nvsd.ch\/wp-content\/uploads\/2026\/08\/podman-nvidia-cdi-gpu-diagnostic-1536x864.png 1536w, https:\/\/homelab.nvsd.ch\/wp-content\/uploads\/2026\/08\/podman-nvidia-cdi-gpu-diagnostic.png 1672w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Le diagnostic a \u00e9t\u00e9 effectu\u00e9 couche par couche : GPU h\u00f4te, Toolkit NVIDIA, CDI, conteneur de test puis Ollama.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"podman-nvidia-cdi-gpu-diagnostic.png\" alt=\"Diagnostic GPU de Pop!_OS \u00e0 Ollama : incompatibilit\u00e9 Toolkit 1.20, retour \u00e0 1.18.2, r\u00e9g\u00e9n\u00e9ration CDI et validation nvidia-smi\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Revenir \u00e0 NVIDIA Container Toolkit 1.18.2<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">La configuration qui a finalement \u00e9t\u00e9 valid\u00e9e sur cette machine utilise <strong>NVIDIA Container Toolkit 1.18.2<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Apr\u00e8s le retour \u00e0 cette version, j\u2019ai r\u00e9g\u00e9n\u00e9r\u00e9 le fichier CDI persistant :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nvidia-ctk cdi generate --output=\/etc\/cdi\/nvidia.yaml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Deux fichiers CDI ont ensuite \u00e9t\u00e9 observ\u00e9s :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/etc\/cdi\/nvidia.yaml\n\/var\/run\/cdi\/nvidia.yaml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Le fichier important pour ma configuration persistante est :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/etc\/cdi\/nvidia.yaml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">La version CDI g\u00e9n\u00e9r\u00e9e et valid\u00e9e \u00e9tait :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cdiVersion: 0.5.0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Cette correction a \u00e9t\u00e9 d\u00e9terminante. Le GPU n\u2019\u00e9tait pas le probl\u00e8me, le pilote NVIDIA non plus : c\u2019\u00e9tait bien la couche d\u2019int\u00e9gration entre Podman et NVIDIA qui devait \u00eatre corrig\u00e9e.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Valider CUDA dans un conteneur avant Ollama<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Avant d\u2019installer un mod\u00e8le, j\u2019ai test\u00e9 directement l\u2019exposition du GPU au conteneur.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La forme utilis\u00e9e par ma configuration Podman repose sur CDI :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>podman run --rm \\\n  --security-opt=label=disable \\\n  --device=nvidia.com\/gpu=all \\\n  &lt;image-cuda-nvidia&gt; \\\n  nvidia-smi<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Je conserve volontairement ici <code>&lt;image-cuda-nvidia&gt;<\/code> comme identifiant g\u00e9n\u00e9rique : l\u2019image exacte utilis\u00e9e pendant le test n\u2019est pas n\u00e9cessaire \u00e0 la compr\u00e9hension de l\u2019architecture et je pr\u00e9f\u00e8re ne pas documenter une r\u00e9f\u00e9rence que je n\u2019ai pas conserv\u00e9e avec certitude.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ce test est beaucoup plus important qu\u2019il n\u2019en a l\u2019air.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Il valide s\u00e9par\u00e9ment :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>le pilote sur l\u2019h\u00f4te ;<\/li>\n\n\n\n<li>NVIDIA Container Toolkit ;<\/li>\n\n\n\n<li>CDI ;<\/li>\n\n\n\n<li>Podman ;<\/li>\n\n\n\n<li>l\u2019acc\u00e8s r\u00e9el au GPU depuis un conteneur.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Ce n\u2019est qu\u2019apr\u00e8s cette validation que j\u2019ai int\u00e9gr\u00e9 Ollama.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">D\u00e9ployer Ollama avec acc\u00e8s GPU<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">La stack Ollama est stock\u00e9e dans :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/srv\/homelab\/stacks\/ai\/ollama<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Les mod\u00e8les et donn\u00e9es d\u2019Ollama restent sur l\u2019h\u00f4te dans :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/srv\/homelab\/data\/ollama<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Le principe du Compose final est le suivant :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>services:\n  ollama:\n    # image Ollama d\u00e9finie dans la stack\n    restart: \"no\"\n\n    ports:\n      - \"127.0.0.1:11434:11434\"\n\n    volumes:\n      - \/srv\/homelab\/data\/ollama:\/root\/.ollama\n\n    devices:\n      - nvidia.com\/gpu=all\n\n    security_opt:\n      - label=disable\n\n    networks:\n      - ai-net\n\nnetworks:\n  ai-net:\n    external: true<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Je ne reproduis pas ici une balise d\u2019image ou d\u2019autres options qui ne sont pas n\u00e9cessaires au r\u00e9cit si elles ne sont pas confirm\u00e9es dans mes notes. Les \u00e9l\u00e9ments ci-dessus sont ceux qui structurent r\u00e9ellement l\u2019installation finale : <strong>persistance, GPU CDI, r\u00e9seau d\u00e9di\u00e9 et absence de red\u00e9marrage automatique<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Premier mod\u00e8le : qwen3:1.7b<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pour cette GTX 1650 de 4 Go, j\u2019ai retenu <strong><code>qwen3:1.7b<\/code><\/strong> comme premier mod\u00e8le de travail.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">L\u2019objectif n\u2019\u00e9tait pas de faire tourner le plus gros mod\u00e8le possible, mais de disposer d\u2019un mod\u00e8le suffisamment l\u00e9ger pour valider l\u2019ensemble de la cha\u00eene locale : stockage, t\u00e9l\u00e9chargement, chargement, g\u00e9n\u00e9ration et utilisation du GPU.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Ajouter Open WebUI<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Une fois Ollama op\u00e9rationnel, j\u2019ai ajout\u00e9 <strong>Open WebUI<\/strong> pour disposer d\u2019une interface web locale.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La stack se trouve dans :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/srv\/homelab\/stacks\/ai\/open-webui<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">et ses donn\u00e9es persistantes dans :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/srv\/homelab\/data\/open-webui<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Le principe du Compose final est :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>services:\n  open-webui:\n    # image Open WebUI d\u00e9finie dans la stack\n    restart: \"no\"\n\n    ports:\n      - \"127.0.0.1:3000:8080\"\n\n    volumes:\n      - \/srv\/homelab\/data\/open-webui:\/app\/backend\/data\n\n    environment:\n      OLLAMA_BASE_URL: http:\/\/ollama:11434\n\n    networks:\n      - ai-net\n\nnetworks:\n  ai-net:\n    external: true<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Le port d\u2019Open WebUI reste li\u00e9 \u00e0 l\u2019interface locale :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>127.0.0.1:3000<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">De la m\u00eame mani\u00e8re, Ollama est expos\u00e9 localement sur :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>127.0.0.1:11434<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Pourquoi <code>host.containers.internal<\/code> n\u2019a pas \u00e9t\u00e9 ma solution finale<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Au d\u00e9but, j\u2019ai essay\u00e9 de faire joindre Ollama par Open WebUI via l\u2019h\u00f4te, avec une adresse bas\u00e9e sur :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>host.containers.internal<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Cette voie ajoutait une \u00e9tape inutile : le trafic sortait du r\u00e9seau logique des conteneurs pour repasser par l\u2019h\u00f4te avant de rejoindre un service qui se trouvait lui aussi dans Podman.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dans ma configuration, cette approche a pos\u00e9 un probl\u00e8me de connexion.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Plut\u00f4t que d\u2019ajouter des correctifs autour de cette r\u00e9solution, j\u2019ai choisi une architecture plus directe.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><code>ai-net<\/code> : faire communiquer les conteneurs directement<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">J\u2019ai cr\u00e9\u00e9 un r\u00e9seau Podman d\u00e9di\u00e9 \u00e0 la pile IA :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>podman network create ai-net<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Les deux stacks utilisent ce r\u00e9seau externe.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ollama y porte directement son nom de service, ce qui permet \u00e0 Open WebUI d\u2019utiliser :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>http:&#47;&#47;ollama:11434<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">comme URL de connexion.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Cette modification a simplifi\u00e9 toute l\u2019architecture :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Open WebUI\n     \u2502\n     \u2502 ai-net\n     \u25bc\n   Ollama\n     \u2502\n     \u25bc\nNVIDIA GPU<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Plus besoin de passer par <code>host.containers.internal<\/code> pour faire communiquer deux services qui appartiennent au m\u00eame environnement.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">C\u2019est une correction technique, mais aussi une am\u00e9lioration de conception : <strong>quand deux conteneurs doivent se parler, un r\u00e9seau d\u00e9di\u00e9 est souvent plus clair que l\u2019utilisation indirecte de l\u2019h\u00f4te<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">L\u2019architecture finale de mon IA locale<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/homelab.nvsd.ch\/wp-content\/uploads\/2026\/08\/architecture-ia-locale-podman-ollama-open-webui-1024x576.png\" alt=\"Architecture finale de l\u2019IA locale avec Pop!_OS, Podman rootless, stockage Homelab, GTX 1650 via CDI, Ollama et Open WebUI sur ai-net\" class=\"wp-image-109\" srcset=\"https:\/\/homelab.nvsd.ch\/wp-content\/uploads\/2026\/08\/architecture-ia-locale-podman-ollama-open-webui-1024x576.png 1024w, https:\/\/homelab.nvsd.ch\/wp-content\/uploads\/2026\/08\/architecture-ia-locale-podman-ollama-open-webui-300x169.png 300w, https:\/\/homelab.nvsd.ch\/wp-content\/uploads\/2026\/08\/architecture-ia-locale-podman-ollama-open-webui-768x432.png 768w, https:\/\/homelab.nvsd.ch\/wp-content\/uploads\/2026\/08\/architecture-ia-locale-podman-ollama-open-webui-1536x864.png 1536w, https:\/\/homelab.nvsd.ch\/wp-content\/uploads\/2026\/08\/architecture-ia-locale-podman-ollama-open-webui.png 1672w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Architecture finale : donn\u00e9es persistantes sur `\/srv\/homelab`, GPU NVIDIA via CDI, Ollama et Open WebUI reli\u00e9s par `ai-net`, sans d\u00e9marrage automatique.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Apr\u00e8s les essais, les erreurs et les corrections, l\u2019architecture finale est devenue relativement simple.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"architecture-ia-locale-podman-ollama-open-webui.png\" alt=\"Architecture finale de l\u2019IA locale : Pop!_OS, Podman rootless, stockage Homelab, GTX 1650 via CDI, Ollama et Open WebUI sur ai-net\"\/><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>Pop!_OS \/ COSMIC\n\u2502\n\u251c\u2500\u2500 Podman rootless\n\u2502   \u2502\n\u2502   \u251c\u2500\u2500 Ollama\n\u2502   \u2502   \u251c\u2500\u2500 \/srv\/homelab\/data\/ollama\n\u2502   \u2502   \u2514\u2500\u2500 NVIDIA GPU via CDI\n\u2502   \u2502\n\u2502   \u2514\u2500\u2500 Open WebUI\n\u2502       \u2514\u2500\u2500 \/srv\/homelab\/data\/open-webui\n\u2502\n\u251c\u2500\u2500 ai-net\n\u2502   \u251c\u2500\u2500 Ollama\n\u2502   \u2514\u2500\u2500 Open WebUI\n\u2502\n\u251c\u2500\u2500 \/srv\/homelab\n\u2502   \u251c\u2500\u2500 stacks\n\u2502   \u251c\u2500\u2500 data\n\u2502   \u2514\u2500\u2500 containers\n\u2502\n\u2514\u2500\u2500 \/srv\/homelab-backup<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Les composants remplissent chacun un r\u00f4le pr\u00e9cis :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Pop!_OS \/ COSMIC<\/strong> reste le syst\u00e8me de mon poste de travail ;<\/li>\n\n\n\n<li><strong>Podman rootless<\/strong> ex\u00e9cute les conteneurs ;<\/li>\n\n\n\n<li><strong><code>\/srv\/homelab\/stacks<\/code><\/strong> contient les d\u00e9finitions Compose ;<\/li>\n\n\n\n<li><strong><code>\/srv\/homelab\/data<\/code><\/strong> contient les donn\u00e9es persistantes ;<\/li>\n\n\n\n<li><strong><code>\/srv\/homelab\/containers<\/code><\/strong> contient le stockage rootless de Podman ;<\/li>\n\n\n\n<li><strong>CDI<\/strong> expose la GTX 1650 aux conteneurs ;<\/li>\n\n\n\n<li><strong>Ollama<\/strong> fournit le moteur d\u2019inf\u00e9rence ;<\/li>\n\n\n\n<li><strong>Open WebUI<\/strong> fournit l\u2019interface ;<\/li>\n\n\n\n<li><strong><code>ai-net<\/code><\/strong> relie directement les deux services ;<\/li>\n\n\n\n<li><strong><code>\/srv\/homelab-backup<\/code><\/strong> re\u00e7oit la strat\u00e9gie de sauvegarde du Homelab.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Un choix final important : ne rien d\u00e9marrer automatiquement<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Au d\u00e9but du projet, l\u2019id\u00e9e d\u2019un service toujours disponible pouvait sembler logique.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mais ma machine n\u2019est pas un serveur d\u00e9di\u00e9. C\u2019est aussi mon poste de travail.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Avec seulement 4 Go de VRAM sur la GTX 1650, je pr\u00e9f\u00e8re que Firefox, COSMIC et mes autres applications disposent des ressources n\u00e9cessaires lorsque je ne travaille pas avec l\u2019IA.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">J\u2019ai donc retenu :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>restart: \"no\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">pour Ollama comme pour Open WebUI.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Les conteneurs ne d\u00e9marrent pas automatiquement au boot.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Je les lance lorsque j\u2019en ai besoin depuis <strong>Podman Desktop<\/strong>, puis je peux les arr\u00eater lorsque la session d\u2019IA est termin\u00e9e.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ce choix pr\u00e9sente un avantage suppl\u00e9mentaire : toute l\u2019infrastructure reste reproductible et persistante sans imposer une consommation permanente de RAM et de VRAM.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Ce que cette installation m\u2019a appris<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Une version plus r\u00e9cente n\u2019est pas toujours la meilleure dans une configuration donn\u00e9e<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">NVIDIA Container Toolkit 1.20 \u00e9tait plus r\u00e9cent que 1.18.2, mais la combinaison r\u00e9ellement valid\u00e9e avec mon Podman 4.9.3 est celle qui utilise <strong>Toolkit 1.18.2 et un fichier CDI r\u00e9g\u00e9n\u00e9r\u00e9<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Je pr\u00e9f\u00e8re documenter l\u2019\u00e9tat qui fonctionne r\u00e9ellement plut\u00f4t que supposer qu\u2019une version plus r\u00e9cente est n\u00e9cessairement meilleure.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Tester les couches une par une change compl\u00e8tement le diagnostic<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">La progression correcte a \u00e9t\u00e9 :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>nvidia-smi sur l\u2019h\u00f4te\n        \u2193\nCDI\n        \u2193\nGPU dans un conteneur\n        \u2193\nOllama\n        \u2193\nr\u00e9seau ai-net\n        \u2193\nOpen WebUI<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Si j\u2019avais commenc\u00e9 directement par Open WebUI, j\u2019aurais pu confondre une erreur r\u00e9seau, une erreur Ollama et une erreur GPU.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En testant chaque couche ind\u00e9pendamment, le probl\u00e8me devient beaucoup plus facile \u00e0 localiser.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Le r\u00e9seau le plus simple a finalement \u00e9t\u00e9 le meilleur<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Faire passer Open WebUI par <code>host.containers.internal<\/code> ajoutait une abstraction dont je n\u2019avais pas besoin.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Le r\u00e9seau <code>ai-net<\/code> permet aux conteneurs de communiquer directement, avec :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>http:&#47;&#47;ollama:11434<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">C\u2019est plus lisible et plus proche de l\u2019architecture r\u00e9elle.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Un Homelab local doit respecter son usage r\u00e9el<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Sur un serveur d\u00e9di\u00e9, l\u2019auto-d\u00e9marrage des services est g\u00e9n\u00e9ralement naturel.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sur mon poste de travail, ce serait une mauvaise optimisation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La meilleure architecture n\u2019est donc pas seulement celle qui fonctionne techniquement. C\u2019est celle qui correspond \u00e0 la machine sur laquelle elle tourne.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Cette installation a commenc\u00e9 comme un simple objectif : faire tourner Ollama et Open WebUI avec une GTX 1650.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Elle m\u2019a finalement oblig\u00e9 \u00e0 travailler sur plusieurs niveaux du Homelab :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>le stockage ;<\/li>\n\n\n\n<li>Podman rootless ;<\/li>\n\n\n\n<li>l\u2019int\u00e9gration NVIDIA ;<\/li>\n\n\n\n<li>CDI ;<\/li>\n\n\n\n<li>le diagnostic GPU ;<\/li>\n\n\n\n<li>les volumes persistants ;<\/li>\n\n\n\n<li>le r\u00e9seau entre conteneurs ;<\/li>\n\n\n\n<li>la consommation des ressources du poste de travail.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">L\u2019environnement final n\u2019est pas spectaculaire par sa complexit\u00e9. C\u2019est pr\u00e9cis\u00e9ment ce que je recherchais.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">J\u2019ai maintenant une IA locale que je peux d\u00e9marrer \u00e0 la demande, avec ses donn\u00e9es conserv\u00e9es sous <code>\/srv\/homelab<\/code>, une communication directe entre Open WebUI et Ollama, et une acc\u00e9l\u00e9ration GPU valid\u00e9e depuis les conteneurs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La principale le\u00e7on de cette construction est devenue une r\u00e8gle g\u00e9n\u00e9rale pour mon Homelab : <strong>s\u00e9parer les couches, les tester une par une, puis simplifier l\u2019architecture d\u00e8s qu\u2019une abstraction n\u2019apporte plus rien.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Je voulais int\u00e9grer une IA locale \u00e0 mon Homelab sans transformer mon poste de travail en serveur d\u00e9di\u00e9. L\u2019objectif \u00e9tait simple \u00e0 formuler : [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":110,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[45,46],"tags":[44],"class_list":["post-108","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-homelab","category-ia-locale","tag-podman-pop_os-ollama-open-webui-nvidia-gpu-cdi-ia-locale-homelab"],"_links":{"self":[{"href":"https:\/\/homelab.nvsd.ch\/index.php?rest_route=\/wp\/v2\/posts\/108","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/homelab.nvsd.ch\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/homelab.nvsd.ch\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/homelab.nvsd.ch\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/homelab.nvsd.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=108"}],"version-history":[{"count":2,"href":"https:\/\/homelab.nvsd.ch\/index.php?rest_route=\/wp\/v2\/posts\/108\/revisions"}],"predecessor-version":[{"id":114,"href":"https:\/\/homelab.nvsd.ch\/index.php?rest_route=\/wp\/v2\/posts\/108\/revisions\/114"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/homelab.nvsd.ch\/index.php?rest_route=\/wp\/v2\/media\/110"}],"wp:attachment":[{"href":"https:\/\/homelab.nvsd.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=108"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/homelab.nvsd.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=108"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/homelab.nvsd.ch\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=108"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}