Ollama sans mot de passe : sécuriser le port 11434
Ollama n’a aucune authentification par défaut : toute machine atteignant le port 11434 peut exécuter vos modèles ou en télécharger. Voici les 3 correctifs.
L’API Ollama n’a pas de mot de passe
L’API Ollama n’utilise aucune authentification. Le serveur que vous exécutez ne vérifie ni utilisateur, ni mot de passe, ni clé, et ne contient aucune allowlist. Toute machine capable d’ouvrir une connexion TCP vers le port 11434 peut lister vos modèles, les exécuter, en télécharger de nouveaux et supprimer ceux que vous possédez.
La documentation officielle l’indique clairement : « Aucune authentification n’est requise pour accéder localement à l’API Ollama via http://localhost:11434. » Le terme localement constitue à lui seul tout le modèle de sécurité. Ollama est lié par défaut à 127.0.0.1. Sur un laptop, l’interface loopback contrôle donc l’accès. Si vous déplacez ce listener vers une adresse publique, ce contrôle d’accès disparaît, car rien ne le remplace.
C’est pourquoi ce point est important sur un VPS (virtual private server). La configuration par défaut est sûre. La première modification effectuée par la plupart des utilisateurs consiste à ouvrir le listener pour qu’une seconde machine puisse utiliser le modèle. C’est précisément la modification qui supprime toutes les protections en une seule fois.
Ce qu’expose le port 11434 ouvert
Tous les endpoints. Il n’existe ni mode en lecture seule ni port d’administration distinct. Voici les requêtes réelles, dirigées vers l’adresse du serveur au lieu de localhost :
# List every model on the box
curl http://SERVER_IP:11434/api/tags
# See what is loaded into memory right now
curl http://SERVER_IP:11434/api/ps
# Run a prompt on your hardware
curl http://SERVER_IP:11434/api/generate -d '{"model":"llama3.2","prompt":"Why is the sky blue?"}'
# Write several gigabytes to your disk
curl http://SERVER_IP:11434/api/pull -d '{"model":"llama3.2"}'
# Remove a model
curl -X DELETE http://SERVER_IP:11434/api/delete -d '{"model":"llama3.2"}'Pour l’administrateur, quatre problèmes se posent :
- Votre CPU ou votre GPU exécute des inférences pour quelqu’un d’autre. Avec une offre qui applique une limite d’utilisation équitable du CPU, une charge soutenue consomme votre quota pour le compte d’un tiers. Maîtriser les coûts des workloads d’IA sur un VPS devient beaucoup plus difficile dès que vous n’êtes plus le seul appelant.
/api/pullécrit sur votre disque. Chaque modèle occupe de deux à quarante gigaoctets. Une boucle de téléchargements remplit le volume, et un disque plein interrompt tous les autres services de la machine, pas seulement Ollama.- Les requêtes arrivent dans votre processus et sont consignées. Avec le niveau de journalisation par défaut, Ollama enregistre uniquement les métadonnées : endpoint, statut, latence et adresse du client, mais pas le texte du prompt. Cela constitue tout de même une trace de l’utilisateur de votre machine et de son usage, stockée dans votre journal, sans que vous ayez choisi de la collecter.
/api/deletesupprime des modèles. Pour les récupérer, vous devez les télécharger de nouveau en utilisant votre propre bande passante.
Aucun exploit n’est nécessaire. L’API documentée se comporte exactement comme prévu.
La clé Ed25519 ne contrôle pas l’accès
Recherchez « Ollama API key » et vous trouverez deux éléments différents. Aucun des deux n’est le mot de passe de votre serveur. Les distinguer élimine la plupart des confusions.
Le premier est la paire de clés d’identité. Ollama génère une paire de clés Ed25519 lors de sa première exécution. Sous Linux, le script d’installation crée un utilisateur système nommé ollama, avec son répertoire personnel dans /usr/share/ollama. La paire se trouve donc ici :
/usr/share/ollama/.ollama/id_ed25519
/usr/share/ollama/.ollama/id_ed25519.pubCette clé sert à authentifier la machine auprès d’un service externe. ollama signin enregistre la partie publique auprès de votre compte ollama.com. Elle vous autorise à envoyer un modèle vers le registre ou à récupérer un modèle privé. Elle prouve l’identité de votre machine auprès d’ollama.com. Elle ne demande aucune authentification aux clients qui se connectent à votre machine. Sa suppression, sa rotation ou son absence ne change rien aux clients autorisés à appeler votre API.
Le second est OLLAMA_API_KEY. Cette variable contient une clé que vous créez dans https://ollama.com/settings/keys. Votre client l’envoie comme Authorization: Bearer $OLLAMA_API_KEY lorsqu’il appelle l’API hébergée à l’adresse https://ollama.com/api. Il s’agit d’un identifiant d’authentification pour leur service, que vous utilisez en tant que client. Votre propre ollama serve ne la lit jamais. Définir OLLAMA_API_KEY sur votre VPS ne protège pas votre VPS par mot de passe.
Il n’existe donc aucun paramètre à activer. Les trois protections ci-dessous fonctionnent de la même manière : rendez le port inaccessible et placez devant lui un composant qui effectue bien un contrôle.
Vérifiez les services actuellement en écoute sur votre serveur
sudo ss -tlnp | grep 11434Le résultat sûr utilise l’adresse loopback :
LISTEN 0 4096 127.0.0.1:11434 0.0.0.0:* users:(("ollama",pid=812,fd=3))Le résultat exposé utilise toutes les interfaces :
LISTEN 0 4096 0.0.0.0:11434 0.0.0.0:* users:(("ollama",pid=812,fd=3))0.0.0.0 désigne toutes les adresses IPv4 de la machine, y compris l’adresse publique. *:11434 et [::]:11434 désignent la même chose avec IPv6.
Vérifiez maintenant depuis l’extérieur. Exécutez cette commande sur votre ordinateur portable, pas sur le serveur :
curl -m 5 http://YOUR_SERVER_IP:11434/api/versioncurl: (28) Connection timed out after 5001 milliseconds est le résultat attendu, tout comme curl: (7) Failed to connect ... Connection refused. Un objet JSON contenant un champ version signifie que toute personne qui envoie une requête peut accéder à l’API. Tester avec curl directement sur le serveur ne prouve rien, car le loopback répond toujours.
L’exposition survient généralement de deux façons. La première est une modification volontaire, parce qu’un autre ordinateur devait accéder au modèle :
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"Cette seule ligne suffit à exposer le service. La seconde méthode utilise Docker et ne nécessite aucune modification manuelle. Elle est décrite dans la section suivante.
Défense 1 : le garder sur localhost et créer un tunnel
Commencez par cette solution. Elle ne nécessite aucun nouveau logiciel et ne crée aucun identifiant susceptible de fuiter. Le port n’existe jamais sur une interface publique, donc un scan ne peut pas le trouver.
Définissez explicitement l’adresse d’écoute au lieu de vous appuyer sur la valeur par défaut :
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_HOST=127.0.0.1:11434"Cette commande écrit /etc/systemd/system/ollama.service.d/override.conf. Appliquez la modification et vérifiez :
sudo systemctl daemon-reload
sudo systemctl restart ollama
sudo ss -tlnp | grep 11434ss doit maintenant afficher 127.0.0.1:11434. S’il affiche toujours 0.0.0.0, un second fichier drop-in prend le dessus. Exécutez systemctl cat ollama.service pour lister l’unité et tous les fichiers drop-in avec leur chemin, puis supprimez celui qui est obsolète.
Pour utiliser le modèle depuis votre ordinateur portable, transférez le port via SSH :
ssh -N -L 11434:127.0.0.1:11434 you@your-server-L 11434:127.0.0.1:11434 ouvre le port 11434 sur votre ordinateur portable et envoie tout ce qui y arrive vers 127.0.0.1:11434 tel qu’il est vu depuis le serveur. -N indique à SSH de ne pas exécuter de commande distante, afin que le processus maintienne simplement le tunnel ouvert. Pendant son exécution, cette commande fonctionne sur votre ordinateur portable :
curl -s http://localhost:11434/api/tagsVous rencontrerez deux problèmes. bind [127.0.0.1]:11434: Address already in use signifie qu’Ollama fonctionne déjà sur ce port sur votre ordinateur portable. Choisissez donc un autre port local avec -L 11500:127.0.0.1:11434 et configurez votre client pour utiliser le port 11500. Une réponse vide via un tunnel qui s’est correctement établi signifie que SSH fonctionne, mais qu’Ollama n’écoute pas côté serveur. Vérifiez donc ss sur le serveur avant de modifier la commande SSH.
Pour plusieurs machines clientes, un réseau privé est préférable à un tunnel par personne. Connectez les machines à WireGuard ou Tailscale, puis liez Ollama à l’adresse de ce réseau au lieu de 0.0.0.0 :
[Service]
Environment="OLLAMA_HOST=10.8.0.1:11434"Le port n’existe alors que sur une interface dont l’accès nécessite une clé. Cette solution résiste également à une erreur de pare-feu, car une règle qui autoriserait accidentellement tout le monde ne peut toujours pas exposer un service d’écoute absent de l’interface publique.
Défense 2 : un reverse proxy qui vérifie un bearer token
Lorsqu’un élément sur Internet doit appeler le modèle, gardez Ollama sur loopback et placez un proxy devant. Le proxy termine TLS (transport layer security) et rejette les requêtes qui ne contiennent pas le bon en-tête. Ollama accepte toujours les connexions uniquement depuis 127.0.0.1, le proxy est donc le seul point d’accès.
Générez d’abord un vrai token. N’en inventez pas un manuellement :
openssl rand -base64 36Un site nginx qui le vérifie :
map $http_authorization $ollama_ok {
default 0;
"Bearer PASTE_YOUR_GENERATED_TOKEN_HERE" 1;
}
server {
listen 443 ssl;
server_name llm.example.com;
ssl_certificate /etc/letsencrypt/live/llm.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/llm.example.com/privkey.pem;
location = /api/pull { return 403; }
location = /api/delete { return 403; }
location = /api/push { return 403; }
location / {
if ($ollama_ok = 0) { return 401; }
proxy_pass http://127.0.0.1:11434;
proxy_set_header Host 127.0.0.1:11434;
proxy_buffering off;
proxy_read_timeout 600s;
}
}Cinq lignes jouent ici un rôle réel. Chacune empêche une erreur que vous rencontreriez autrement.
if dans un bloc location est généralement une mauvaise idée avec nginx. Toutefois, un corps de requête d’exactement return fait partie des deux formes dont le comportement est prévisible. Cette utilisation est donc sûre.
location = /api/pull est une correspondance exacte. nginx lui donne la priorité sur le préfixe location /. Ces trois endpoints sont donc refusés avant même la vérification du token. Un token valide autorise alors l’inférence, mais pas le remplissage du disque.
proxy_set_header Host 127.0.0.1:11434; est important, car Ollama examine les en-têtes entrants Host et Origin. Transmettre directement le nom d’hôte public du proxy peut produire un 403 Forbidden provenant d’Ollama plutôt que de nginx, ce qui complique le diagnostic. OLLAMA_ORIGINS est l’autre paramètre important pour un client navigateur qui doit autoriser une origine précise.
proxy_buffering off; est important, car Ollama diffuse sa réponse token par token. Lorsque le buffering est activé, nginx conserve le flux et le transmet en une seule fois à la fin. Votre client semble donc bloqué pendant toute la génération.
proxy_read_timeout 600s; est important, car nginx utilise par défaut un délai de 60 secondes. Une génération longue sur CPU dépasse facilement ce délai. Le client reçoit alors 504 Gateway Time-out, et /var/log/nginx/error.log enregistre upstream timed out (110: Connection timed out) while reading response header from upstream. La requête fonctionnait toujours. nginx l’a abandonnée.
Rechargez la configuration et testez les deux chemins :
sudo nginx -t && sudo systemctl reload nginx
curl -s -o /dev/null -w '%{http_code}\n' https://llm.example.com/api/tags
curl -s -H "Authorization: Bearer YOUR_TOKEN" https://llm.example.com/api/tagsLa première commande doit afficher 401. La seconde doit afficher la liste de vos modèles. Si la première renvoie également la liste des modèles, le bloc map se trouve dans la mauvaise portée. Il doit être placé au niveau http, dans un fichier sous /etc/nginx/conf.d/ ou au-dessus du bloc server, jamais à l’intérieur de server.
Caddy fournit le même service avec une authentification de base en quatre lignes. Cette solution convient mieux à un client navigateur qu’un bearer token :
llm.example.com {
basic_auth {
apiuser PASTE_BCRYPT_HASH_HERE
}
reverse_proxy 127.0.0.1:11434
}Exécutez caddy hash-password pour produire le hash bcrypt attendu. Attention à un changement de nom : la directive s’appelait basicauth avant Caddy v2.8 et s’appelle désormais basic_auth. Une configuration copiée depuis un ancien guide refuse donc de se charger, et Caddy indique le nom de la directive qu’il ne reconnaît pas.
Quel que soit le proxy choisi, il s’agit d’un secret partagé par tous les clients. Tous les clients qui le détiennent disposent des mêmes accès. Pour le révoquer, vous devez modifier la configuration et mettre à jour tous les appelants au même moment.
Défense 3 : une gateway qui attribue des clés par client
Dès que plusieurs personnes ou applications appellent le modèle, un token partagé atteint rapidement ses limites. Vous ne pouvez pas déterminer quel client est à l’origine de la charge, ni en désactiver un sans les désactiver tous. Une gateway se place là où se trouvait le proxy, utilise la même API compatible avec OpenAI, attribue une clé distincte à chaque client et enregistre l’utilisation associée à chaque clé. Une gateway LiteLLM auto-hébergée est généralement la solution retenue. Elle ajoute des budgets par clé et des journaux de requêtes au contrôle d’accès.
La règle de la défense 1 reste inchangée. Ollama écoute sur 127.0.0.1, la gateway est le seul processus qui communique avec lui et elle est le seul service à exposer un port public. Une gateway installée sur une machine dont le port 11434 reste ouvert à Internet ne sert à rien, car les clients peuvent simplement la contourner.
Le piège du firewall : un port de conteneur publié contourne UFW
C’est ainsi que des instances exposées se retrouvent sur des serveurs dont les propriétaires ont correctement configuré le firewall.
UFW (uncomplicated firewall) écrit ses règles dans la chaîne INPUT de la table filter du kernel, et INPUT traite les paquets destinés à l’hôte lui-même. L’option -p de Docker écrit une règle de destination NAT (network address translation) dans la chaîne PREROUTING de la table nat, que le kernel évalue avant de déterminer la destination du paquet. Au moment où la décision de routage intervient, la destination a déjà été réécrite vers l’adresse du conteneur. Le paquet est donc forwardé au lieu d’être livré localement, et il traverse FORWARD au lieu de INPUT. Les règles INPUT d’UFW ne sont jamais consultées. Le paquet contourne donc le firewall au lieu de le traverser.
C’est pourquoi cette séquence laisse le port 11434 ouvert sur Internet :
sudo ufw default deny incoming
sudo ufw enable
docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollamaet sudo ufw status indique toujours que le firewall est actif avec une politique par défaut deny. Les deux résultats sont corrects en même temps. C’est précisément pour cette raison que l’on se fie au mauvais résultat. Vous pouvez afficher la règle responsable :
sudo iptables -t nat -L DOCKER -nLa correction consiste à ajouter une adresse dans l’option de publication :
docker rm -f ollama
docker run -d -v ollama:/root/.ollama -p 127.0.0.1:11434:11434 --name ollama ollama/ollama-p 11434:11434 est l’abréviation de -p 0.0.0.0:11434:11434. Indiquer 127.0.0.1 lie le côté hôte du mapping à loopback. Votre tunnel SSH et votre reverse proxy peuvent donc toujours y accéder, mais pas Internet. Recréer le conteneur est sans risque ici, car les modèles résident dans le volume nommé ollama, et non dans le conteneur.
Vérifiez que les deux résultats concordent :
docker port ollama
sudo ss -tlnp | grep 11434docker port ollama doit afficher 11434/tcp -> 127.0.0.1:11434. S’il affiche 0.0.0.0:11434, le service est toujours exposé. Une fois ce mécanisme compris, il s’applique à chaque conteneur que vous publierez : pourquoi les ports publiés par Docker contournent UFW présente la chaîne DOCKER-USER et les règles qui persistent après un redémarrage de Docker. Si vous êtes encore en train de construire la policy du host, les règles UFW nécessaires sur un nouveau VPS présente la base sur laquelle cette configuration s’appuie.
Sous quel compte le processus s’exécute
Le script d’installation Linux crée un compte dédié et exécute le service avec ce compte :
useradd -r -s /bin/false -U -m -d /usr/share/ollama ollamaL’unité située dans /etc/systemd/system/ollama.service définit ensuite User=ollama et Group=ollama. Ne modifiez pas ces paramètres. Un démarrage rapide avec ollama serve exécuté manuellement dans un terminal s’effectue avec le compte de la session ouverte. Si ce compte est root, une API non authentifiée écrit alors des fichiers avec les privilèges de root. Vérifiez le compte utilisé :
ps -o user= -C ollamaLa réponse doit être ollama. Toute autre réponse indique qu’un processus démarré manuellement s’exécute en parallèle de l’unité ou à sa place. Le même raisonnement s’applique à chaque daemon ajouté par la suite, et exécuter les services avec des comptes disposant du minimum de privilèges permet de le faire correctement.
Vérifier que le endpoint de l’API Ollama est sécurisé
Quel que soit votre choix, un seul test permet de trancher. Il doit être exécuté depuis une autre machine :
curl -m 5 http://YOUR_SERVER_IP:11434/api/version
curl -m 5 http://YOUR_SERVER_IP:11434/api/tagsLes deux requêtes doivent expirer ou être refusées. Si vous avez mis en place un proxy, les deux mêmes chemins sur le hostname du proxy doivent renvoyer 401 sans identifiants, et du JSON réel avec des identifiants.
Consultez ensuite une fois l’access log. Il indique si quelqu’un a trouvé le port pendant qu’il était ouvert :
journalctl -u ollama --since "-30 days" | grep GIN | grep -v 127.0.0.1Ollama écrit une ligne par requête et inclut l’adresse du client :
[GIN] 2026/08/12 - 14:01:10 | 200 | 103.965898ms | 127.0.0.1 | POST "/api/generate"Chaque ligne doit afficher 127.0.0.1 une fois qu’Ollama est lié à loopback, car c’est la seule adresse depuis laquelle une connexion peut arriver. Une adresse publique dans cette colonne indique une requête externe, et l’horodatage indique quand elle a eu lieu. L’absence totale de sortie pour cette commande est le résultat recherché. Si l’exécution de modèles vous est nouvelle, exécuter Ollama sur un VPS couvre l’installation, le dimensionnement du modèle et les limites de mémoire qui déterminent ce qui pourra réellement être chargé.
FAQ
Ollama dispose-t-il d’une clé API ou d’un mot de passe ?
Non. Le serveur que vous exécutez n’utilise aucune forme d’authentification, et la documentation officielle indique qu’aucune authentification n’est nécessaire pour accéder à l’API. Les deux éléments appelés « clé API Ollama » servent à autre chose. La paire Ed25519 dans /usr/share/ollama/.ollama/ authentifie votre machine auprès de ollama.com pour vous permettre de pousser des modèles et d’en récupérer des privés. OLLAMA_API_KEY est un identifiant d’authentification que votre client envoie à l’API hébergée sur https://ollama.com/api. Votre propre ollama serve ne lit aucun de ces deux éléments. Le contrôle d’accès doit donc être assuré par le réseau ou par un proxy placé en amont.
OLLAMA_HOST=0.0.0.0 est-il sûr si j’ai un pare-feu ?
Seulement si rien d’autre n’écrit de règles de pare-feu sur cette machine. 0.0.0.0 signifie que le listener est réellement présent sur l’interface publique et que vous comptez uniquement sur le pare-feu pour empêcher son accès. Cette confiance disparaît dès que Docker publie un port, car la règle DNAT ajoutée par Docker dans la table nat est évaluée avant que le paquet n’atteigne la chaîne INPUT, où se trouve UFW. Le paquet est donc transmis et UFW ne le voit jamais. Lier le service à 127.0.0.1 ou à l’adresse d’un tunnel privé retire le listener de l’interface publique. Une erreur de configuration du pare-feu n’a alors plus rien à exposer.
Comment vérifier si mon port Ollama est ouvert sur Internet ?
Exécutez sudo ss -tlnp | grep 11434 sur le serveur, puis curl -m 5 http://YOUR_SERVER_IP:11434/api/version depuis une autre machine. Si ss affiche 127.0.0.1:11434 et que curl expire depuis la machine distante, c’est le résultat attendu. Si ss affiche 0.0.0.0:11434 ou *:11434 et que curl renvoie du JSON depuis la machine distante, l’API complète est accessible. Ne testez jamais avec curl directement sur le serveur, car loopback répond quelle que soit l’adresse d’écoute utilisée.
Puis-je simplement remplacer le port 11434 par un port aléatoire ?
Non, et la raison mérite d’être précisée. Un autre port ne ralentit qu’un scan limité à un seul port. Les scanners parcourent toute la plage de ports, et une requête vers /api/tags identifie le service, quel que soit le port utilisé. Changer de port casse également les valeurs par défaut de tous les clients et rend votre configuration plus difficile à comprendre par la suite. Utilisez plutôt loopback, ce qui retire le listener au lieu de le déplacer.
Quelqu’un a accédé à mon Ollama ouvert. Que dois-je vérifier ?
Liez-le à 127.0.0.1 et redémarrez d’abord le service, afin de stopper l’exposition avant de commencer l’analyse. Exécutez ensuite journalctl -u ollama --since "-30 days" | grep GIN | grep -v 127.0.0.1 pour voir quelles adresses externes ont appelé quels endpoints et à quel moment. Comparez ollama list aux modèles que vous vouliez posséder, car /api/pull n’utilise aucune authentification et un modèle que vous n’avez pas récupéré représente à la fois une consommation d’espace disque et un élément de preuve. Vérifiez l’espace libre avec df -h. Ollama n’enregistre pas le texte des prompts avec le niveau de journalisation par défaut. Vous savez donc qui a effectué une requête et pour quel modèle, mais pas ce qui a été généré.