Installer Ollama avec Podman rootless sur un VPS
Déployez Ollama avec Podman rootless sur un VPS : utilisateur dédié, lingering, Quadlet après reboot, labels SELinux et port 11434 fermé.
Exécuter Ollama dans Podman rootless sur un VPS
Pour exécuter Ollama dans Podman rootless sur un serveur, cinq conditions doivent être réunies, contrairement à un guide destiné aux postes de travail. Un utilisateur non privilégié dédié possède le conteneur. Le lingering est activé pour cet utilisateur afin que le conteneur continue de fonctionner après votre déconnexion. Un fichier Quadlet confie le conteneur à systemd afin qu’il redémarre après un reboot. Le répertoire des modèles porte un label SELinux sur les distributions qui l’imposent. L’API écoute uniquement sur loopback, et vous y accédez par un tunnel SSH (secure shell).
Ollama est un serveur pour les grands modèles de langage (LLM). Il stocke les poids des modèles sur le disque, les charge en mémoire et répond aux requêtes HTTP sur le port 11434. Il ne possède ni authentification, ni clé d’API, ni comptes utilisateur : le réseau est donc le seul contrôle d’accès disponible. Podman exécute les conteneurs sans daemon et sans root. Ainsi, tout élément qui s’échappe du conteneur s’exécute d’abord avec les privilèges d’un utilisateur non privilégié. Si vous souhaitez commencer par comparer les runtimes, consultez les différences entre Podman et Docker sur un VPS. Si vous préférez éviter complètement les conteneurs, installer Ollama directement sur un VPS est une solution plus courte.
SSD Nodes fournit Fedora parmi ses images, et Fedora inclut par défaut Podman et SELinux (security-enhanced Linux). Toutes les commandes ci-dessous fonctionnent sur les distributions équipées de Podman 5 ou version ultérieure.
Pourquoi la version pour ordinateur portable doit être adaptée sur un serveur
Fedora Magazine a publié un guide clair sur cette pile le 5 août 2026 : Exécuter Ollama localement avec Podman sous Fedora Linux, par Yazan Monshed. C’est une bonne introduction aux outils. Mais ce guide vise aussi un ordinateur portable, et quatre de ses choix se comportent différemment sur une machine dotée d’une adresse IP publique.
- Le conteneur est démarré avec un simple
podman run -d. Un conteneur démarré manuellement ne redémarre pas après un reboot, car rien n’a été configuré pour le démarrer. - Le guide utilise le tag évolutif
ollama/ollama. Sur un ordinateur portable, vous remarquez le jour où le comportement change. Sur un serveur, le premier signe est souvent un script qui cesse de fonctionner pendant la nuit. - La publication utilise
-p 11434:11434, qui lie le service à toutes les interfaces. Derrière un routeur domestique, le service est inaccessible depuis Internet. Sur un VPS, cela expose une API d’inférence publique sans mot de passe. - Le conteneur s’exécute avec votre propre utilisateur de connexion. Sur un serveur, le compte propriétaire du conteneur ne doit rien posséder d’autre. Ainsi, une sortie du conteneur aboutit dans un répertoire personnel vide.
Aucun de ces choix n’est incorrect pour la machine visée par le guide. Il s’agit simplement de décisions à réexaminer lorsque le serveur est accessible depuis partout et que personne ne se trouve devant lui.
Créer l’utilisateur non privilégié et vérifier subuid
Rootless Podman mappe les identifiants utilisateur internes du conteneur (UID) vers un bloc d’identifiants inutilisés sur l’hôte. Ce bloc est déclaré dans /etc/subuid et /etc/subgid. Sans ce bloc, les conteneurs rootless ne peuvent pas démarrer.
sudo dnf install -y podman # or: sudo apt install -y podman
sudo useradd --create-home --shell /bin/bash --comment "Ollama container owner" ollama
sudo passwd --lock ollama
grep ollama /etc/subuid /etc/subgidLa commande grep doit afficher deux lignes, une provenant de chaque fichier. Chaque ligne doit indiquer une plage de 65536 identifiants :
/etc/subuid:ollama:100000:65536
/etc/subgid:ollama:100000:65536Votre nombre de départ sera différent, ce qui est normal. Si grep n’affiche rien, useradd n’a pas attribué de plage. La première commande podman exécutée avec cet utilisateur échoue alors ainsi :
Error: cannot find UID/GID for user ollama: no subuid ranges found for user "ollama" in /etc/subuidAttribuez une plage qui n’est utilisée par aucun autre utilisateur, puis indiquez à Podman que son ancien mapping est obsolète :
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 ollama
sudo -iu ollama podman system migrateVerrouiller le mot de passe empêche toute connexion directe avec ollama. Pour accéder à ce compte, utilisez votre utilisateur administrateur avec sudo -iu ollama.
Activez le lingering pour que le service survive à la déconnexion
L’instance systemd d’un utilisateur démarre normalement à la connexion et s’arrête à la déconnexion, et /run/user/<uid> est supprimé en même temps. Tous les conteneurs rootless appartenant à cet utilisateur s’arrêtent au même moment. Le lingering maintient l’instance utilisateur en fonctionnement sans session associée.
sudo loginctl enable-linger ollama
loginctl show-user ollama --property=LingerLa commande doit afficher Linger=yes. Activez le lingering avant de créer l’unité, car le répertoire requis par celle-ci, /run/user/<uid>, n’existe qu’une fois le lingering activé.
Il reste une étape que personne n’anticipe. sudo -iu ollama vous donne un shell, mais pas de session bus. systemctl --user échoue donc immédiatement :
Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not definedsystemd recherche le user bus à l’emplacement $XDG_RUNTIME_DIR/bus, mais sudo -i ne définit pas cette variable. Définissez-la manuellement dans chaque shell d’administration depuis lequel vous gérez ce service :
sudo -iu ollama
export XDG_RUNTIME_DIR=/run/user/$(id -u)
systemctl --user statusOù les blobs des modèles sont stockés et quelle capacité disque prévoir
Ollama écrit les poids dans /root/.ollama/models à l’intérieur du conteneur. Montez un répertoire du dossier personnel de l’utilisateur sur ce chemin : les fichiers seront alors stockés à un emplacement dont vous pouvez mesurer l’utilisation, /home/ollama/ollama-data/models. Les blobs sont placés dans models/blobs sous forme de fichiers adressés par contenu, et models/manifests contient le petit index qui les référence. Si vous utilisez plutôt un volume nommé, comme dans l’article de Fedora Magazine, la même arborescence se trouve sous /home/ollama/.local/share/containers/storage/volumes/<volume>/_data. Dans les deux cas, ollama pull et ollama run écrivent les poids dans la même arborescence. Ce qui distingue les deux commandes est uniquement le fait qu’une session de chat s’ouvre une fois le téléchargement terminé.
Dimensionnez le disque avant de télécharger quoi que ce soit. Les tailles de téléchargement publiées donnent la capacité minimale à prévoir.
The data behind this chart
[
{
"label": "gemma3:4b",
"download_gb": 3.3
},
{
"label": "mistral:7b",
"download_gb": 4.4
},
{
"label": "qwen3:8b",
"download_gb": 5.2
},
{
"label": "gemma3:12b",
"download_gb": 8.1
},
{
"label": "qwen3:14b",
"download_gb": 9.3
},
{
"label": "gemma3:27b",
"download_gb": 17
},
{
"label": "qwen3:30b",
"download_gb": 19
}
]Les 7 lignes correspondent toutes à des chiffres publiés sur ollama.com/library, et non à des tailles mesurées sur un disque. Le tag le plus petit, gemma3:4b, nécessite le téléchargement de 3.3 Go. Le plus grand, qwen3:30b, nécessite le téléchargement de 19 Go. L’image du conteneur s’ajoute à cela dans le stockage propre à Podman. Vérifiez donc les deux valeurs avec podman system df et df -h /home. Un modèle a également besoin d’une quantité de RAM correspondant approximativement à sa taille sur disque lorsqu’il est chargé, ainsi que d’espace pour la fenêtre de contexte. Un modèle de 19 Go ne fonctionnera donc pas sur un VPS doté de 16 Go de RAM.
Épinglez le tag de l’image et utilisez le nom complet du registre
sudo -iu ollama
export XDG_RUNTIME_DIR=/run/user/$(id -u)
mkdir -p ~/ollama-data ~/.config/containers/systemd
podman pull docker.io/ollama/ollama:0.32.9Utilisez un tag de version publiée, 0.32.9 en août 2026, et non latest. Un tag épinglé garantit qu’un redémarrage à 04:00 utilise le même binaire que celui que vous avez testé. Tout changement de comportement provient donc d’une modification que vous avez effectuée. Docker Hub publie également les tags -rc et -rocm pour les mêmes versions. Choisissez le tag simple, sauf si vous disposez d’un GPU AMD.
Indiquez également l’hôte du registre. Sur Fedora, un nom court utilisé dans une unité systemd ne peut pas afficher de demande de confirmation, car aucun terminal n’est disponible. L’unité échoue alors avec :
Error: short-name "ollama/ollama" did not resolve to an alias and no unqualified-search registries are definedEffectuer d’abord le pull manuellement est facultatif, mais utile. Le téléchargement de plusieurs gigaoctets n’est ainsi pas inclus dans le délai d’expiration du démarrage de l’unité.
L’unité Quadlet qui survit à un redémarrage
Quadlet est le générateur systemd de Podman. Vous écrivez un fichier .container, systemd le transforme en service au démarrage, et podman generate systemd n’est plus nécessaire. Enregistrez-le sous /home/ollama/.config/containers/systemd/ollama.container, avec l’utilisateur ollama comme propriétaire.
[Unit]
Description=Ollama API (rootless)
After=network-online.target
Wants=network-online.target
[Container]
Image=docker.io/ollama/ollama:0.32.9
ContainerName=ollama
PublishPort=127.0.0.1:11434:11434
Volume=/home/ollama/ollama-data:/root/.ollama:Z
Environment=OLLAMA_KEEP_ALIVE=30m
Environment=OLLAMA_MAX_LOADED_MODELS=1
[Service]
Restart=always
TimeoutStartSec=900
[Install]
WantedBy=default.targetLe nom du fichier définit le nom du service, donc ollama.container devient ollama.service.
systemctl --user daemon-reload
systemctl --user start ollama.service
systemctl --user status ollama.servicestatus doit afficher active (running). N’exécutez pas systemctl --user enable ollama.service. L’unité n’existe pas sous forme de fichier sur le disque, donc systemd refuse :
Failed to enable unit: Unit file /run/user/1001/systemd/generator/ollama.service is transient or generated.La section [Install] s’en charge déjà. Quadlet crée lui-même le lien de démarrage automatique pendant daemon-reload, ce qui explique pourquoi cette commande est obligatoire. TimeoutStartSec=900 couvre un premier démarrage qui doit encore télécharger l’image, car le délai par défaut de 90 secondes ne suffit pas pour un téléchargement de deux gigaoctets et systemd arrête alors le démarrage en le marquant comme échoué. OLLAMA_KEEP_ALIVE=30m conserve un modèle en mémoire entre les requêtes au lieu de le décharger après cinq minutes ; les compromis sont expliqués dans conserver un modèle Ollama en mémoire. Si certains termes systemd utilisés ici vous sont inconnus, fonctionnement des services et des timers systemd sur un VPS présente les unités elles-mêmes.
Pourquoi le répertoire des modèles renvoie « permission denied » avec SELinux
Sur Fedora, RHEL, Rocky et AlmaLinux, SELinux est activé en mode enforcing par défaut. Un processus de conteneur s’exécute dans le domaine container_t, tandis qu’un répertoire situé dans le home d’un utilisateur porte l’étiquette user_home_t. La policy ne permet pas à l’un d’accéder à l’autre. Ollama ne peut donc pas créer son arborescence de modèles et le conteneur s’arrête. Sur ces systèmes, getenforce affiche Enforcing, et le refus est enregistré :
sudo ausearch -m avc -ts recentVous verrez une ligne qui indique le domaine et l’étiquette de la cible :
avc: denied { write } for pid=1842 comm="ollama" name="models" dev="vda1" ino=131077 scontext=system_u:system_r:container_t:s0:c214,c827 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=dir permlisted=0Le :Z à la fin de la ligne Volume= est la correction. Il réétiquette le répertoire hôte avec container_file_t et lui attribue une catégorie MCS (multi-category security) privée que seul ce conteneur porte. La forme en minuscules, :z, utilise à la place une étiquette partagée. C’est ce qu’il faut utiliser lorsque deux conteneurs lisent le même répertoire.
Attention à :Z, car cette commande est destructive et silencieuse. Le réétiquetage est récursif. Si vous lui indiquez /home/ollama, tous les fichiers de ce répertoire home sont réétiquetés, ce qui empêche l’utilisateur concerné d’accéder à ses clés SSH. Donnez toujours à :Z un sous-répertoire dédié qui ne contient rien d’autre. Les volumes nommés n’en ont pas besoin, car Podman les étiquette correctement lors de leur création. Pour une vue d’ensemble, Principes de base de SELinux pour un serveur explique les contextes et les booleans. Ubuntu et Debian utilisent AppArmor à la place. Dans ce cas, :Z ne fait rien, et sa présence dans l’unité ne pose aucun problème.
Fermez le port 11434 et accédez à l’API via SSH
PublishPort=127.0.0.1:11434:11434 lie le côté hôte à loopback. Vérifiez-le :
ss -ltnp | grep 11434
curl http://127.0.0.1:11434La sortie de ss doit afficher 127.0.0.1:11434. 0.0.0.0:11434 ou *:11434 signifie que le port est ouvert sur Internet, et curl doit répondre avec Ollama is running.
Soyez précis sur le côté auquel vous liez le service. L’adresse indiquée dans PublishPort est l’adresse de l’hôte. Dans le conteneur, Ollama doit continuer à écouter sur toutes les interfaces, comme le prévoit l’image par défaut. Définir Environment=OLLAMA_HOST=127.0.0.1 lie Ollama au loopback du conteneur. Podman redirige alors le trafic publié vers l’adresse réseau du conteneur, et chaque requête est refusée, y compris depuis l’hôte.
Un port 11434 ouvert vous expose à deux risques. Ollama n’a aucune authentification. Toute personne qui atteint le port peut donc lister vos modèles via /api/tags, lancer des inférences en utilisant votre CPU et votre quota de bande passante via /api/generate, télécharger de nouveaux modèles sur votre disque et supprimer ceux que vous possédez. Ensuite, des requêtes HTTP non chiffrées vers un port distant transmettent les prompts et les réponses en clair. Chaque machine située sur le chemin peut donc les lire. Ces deux problèmes disparaissent si le port ne sort jamais de la machine.
Depuis votre poste de travail, redirigez le port via SSH :
ssh -N -L 11434:127.0.0.1:11434 you@vps.example.comDésormais, http://127.0.0.1:11434 sur votre ordinateur portable correspond à l’instance Ollama du serveur, à l’intérieur du chiffrement de la session SSH. Si Ollama fonctionne déjà sur votre ordinateur portable, la liaison locale échoue avec bind [127.0.0.1]:11434: Address already in use. Utilisez -L 11435:127.0.0.1:11434 et configurez votre client pour utiliser le port 11435.
Lorsqu’un client web en a besoin, placez plutôt un reverse proxy protégé par mot de passe devant Ollama. Un bloc de site Caddy tient en quatre lignes, et caddy hash-password affiche le hash bcrypt attendu :
ollama.example.com {
basic_auth {
you $2a$14$replace_with_the_generated_hash
}
reverse_proxy 127.0.0.1:11434
}Caddy obtient lui-même un certificat TLS (transport layer security), ce qui chiffre le trafic. Testez d’abord votre client : de nombreux outils qui communiquent avec Ollama ne disposent d’aucun champ pour un en-tête Authorization et échouent avec une authentification basic qui renvoie seulement 401 Unauthorized. Le tunnel SSH ne présente pas ce problème, raison pour laquelle il est recommandé par défaut ici.
Téléchargez un modèle et vérifiez l’ensemble du chemin
podman exec -it ollama ollama pull gemma3:4b
curl -s http://127.0.0.1:11434/api/tags
curl -s http://127.0.0.1:11434/api/generate -d '{"model":"gemma3:4b","prompt":"Reply with the single word: ready","stream":false}'
du -sh ~/ollama-data/models/api/tags renvoie une liste JSON de gemma3:4b. /api/generate renvoie un objet JSON contenant un champ response, après une pause pendant le chargement des poids depuis le disque. du doit indiquer un nombre proche de la taille de téléchargement publiée. Vérifiez ensuite la partie qui constitue l’objectif de ce guide :
sudo reboot
# reconnect, then:
sudo -iu ollama
export XDG_RUNTIME_DIR=/run/user/$(id -u)
systemctl --user is-active ollama.serviceactive signifie que la persistance fonctionne : la section [Install] et daemon-reload ont toutes deux rempli leur rôle. inactive signifie qu’un des trois éléments est manquant.
Modes de défaillance et messages affichés
Le conteneur a disparu après un redémarrage. Vérifiez d’abord loginctl show-user ollama --property=Linger, car sans Linger=yes, l’instance systemd de l’utilisateur ne démarre jamais au boot. Si le lingering est activé, la section [Install] manque dans le fichier .container, ou vous avez modifié le fichier sans exécuter systemctl --user daemon-reload.
Error: statfs /home/ollama/ollama-data: no such file or directory. La source du bind mount doit exister avant le démarrage du conteneur. Podman ne crée pas les répertoires de l’hôte à votre place. Exécutez mkdir -p ~/ollama-data avec l’utilisateur ollama.
Le démarrage échoue après 90 secondes. journalctl --user -u ollama.service affiche Start operation timed out. Terminating., car le téléchargement de l’image était toujours en cours. Téléchargez l’image manuellement ou conservez TimeoutStartSec=900.
Le conteneur démarre puis s’arrête. podman logs ollama et sudo ausearch -m avc -ts recent indiquent ensemble si le problème vient du label SELinux. Un AVC mentionnant container_t et user_home_t signifie que :Z manque.
Les requêtes sont refusées depuis l’hôte. curl: (7) Failed to connect to 127.0.0.1 port 11434: Connection refused avec le service active signifie généralement que OLLAMA_HOST a été défini sur une adresse loopback dans le conteneur. Supprimez cette ligne.
La génération est très lente ou le conteneur est tué. Sans GPU, l’inférence s’exécute sur le CPU et un modèle volumineux est naturellement lent. Si un conteneur s’arrête au milieu d’une requête et que signal: killed apparaît dans les journaux, il s’agit du killer out-of-memory du noyau. Choisissez donc un tag plus petit dans le tableau ci-dessus.
Mise à jour d’une image épinglée
L’épinglage signifie que les mises à jour sont déclenchées par vous, et non qu’elles se produisent automatiquement. Modifiez Image= dans ollama.container, puis rechargez la configuration et redémarrez :
systemctl --user daemon-reload
systemctl --user restart ollama.service
podman exec ollama ollama --versionLes modèles résident dans le bind mount. Ils restent donc inchangés lors du remplacement de l’image. AutoUpdate=registry dans la section [Container] est destiné aux personnes qui utilisent un moving tag. Cette option n’est pas utile avec un fixed version tag, car le contenu de ce tag ne change jamais. Sauvegardez /home/ollama/ollama-data/models/manifests et le fichier .container, mais ignorez les blobs : ils sont volumineux et ollama pull les télécharge de nouveau sur une nouvelle machine.
FAQ
Pourquoi mon conteneur Podman rootless s’arrête-t-il lorsque je me déconnecte ?
L’instance systemd d’un utilisateur et son répertoire /run/user/<uid> sont supprimés lorsque sa dernière session se termine. Tous ses conteneurs rootless sont alors arrêtés. Exécutez sudo loginctl enable-linger ollama et vérifiez que loginctl show-user ollama --property=Linger affiche Linger=yes. Activez le lingering avant de créer l’unité Quadlet, car le répertoire d’exécution dont l’unité a besoin n’existe qu’une fois le lingering activé.
Les labels SELinux sont-ils nécessaires sur le répertoire des modèles Ollama ?
Sur Fedora, RHEL, Rocky et AlmaLinux, oui, si vous montez un répertoire de l’hôte dans le conteneur. Le conteneur s’exécute dans le domaine container_t, tandis qu’un répertoire situé dans un dossier personnel porte le label user_home_t. L’écriture est donc refusée et Ollama s’arrête. Ajoutez :Z à la ligne Volume= et utilisez-lui un sous-répertoire dédié, car le relabelling est récursif. Cibler :Z sur tout un dossier personnel empêcherait cet utilisateur d’accéder à ses clés SSH. Les volumes nommés reçoivent les bons labels avec Podman et ne nécessitent rien de plus.
De quel espace disque un modèle Ollama a-t-il besoin ?
Commencez par la taille de téléchargement publiée sur ollama.com/library. Elle va de 3.3 GB pour gemma3:4b à 19 GB pour qwen3:30b. Ajoutez ensuite la taille de l’image Podman et gardez une marge, car un deuxième modèle ne remplace pas le premier sur le disque. Vérifiez df -h /home avant le téléchargement et du -sh ~/ollama-data/models après. Prévoyez la mémoire RAM de la même manière : lorsqu’il est chargé, un modèle nécessite environ la taille de son fichier en mémoire, à laquelle il faut ajouter la taille de la fenêtre de contexte.
Est-il prudent d’exposer le port 11434 sur un VPS ?
Non. Ollama ne fournit aucune authentification. Toute personne pouvant atteindre ce port peut lister vos modèles, les supprimer, en télécharger de nouveaux sur votre disque et exécuter des inférences en utilisant votre CPU et votre quota de bande passante. Le HTTP non chiffré sur Internet transmet également chaque prompt et chaque réponse en clair. Liez le côté hôte à 127.0.0.1 avec PublishPort=127.0.0.1:11434:11434, vérifiez avec ss -ltnp | grep 11434, puis utilisez un tunnel SSH ou un reverse proxy qui exige un mot de passe.