Héberger un modèle Hermes sur un VPS avec Ollama

Un modèle 8B quantifié tient dans 6 Go de RAM et répond à quelques jetons par seconde sans GPU. Voici le montage honnête, avec les chiffres avant les commandes.

Serveur chargeant un modèle de langage et produisant des jetons

Héberger soi-même un modèle de langage ouvert répond à trois besoins concrets : garder les données sur sa propre machine, avoir un coût fixe plutôt qu'à l'usage, et ne dépendre d'aucun fournisseur pour la disponibilité. Les modèles Hermes de Nous Research se prêtent bien à l'exercice, ce sont des affinages de modèles ouverts, orientés suivi d'instructions et appel d'outils, distribués en poids libres.

Commençons par le point que la plupart des tutoriels passent sous silence : ce que vous pouvez réellement attendre d'un VPS sans GPU.

1. Dimensionner avant d'installer

Deux contraintes décident de tout : la RAM doit contenir les poids du modèle, et le débit dépend de la bande passante mémoire, pas de la fréquence du processeur. Un ordre de grandeur pour une quantification Q4_K_M, la plus courante :

  • 3B, environ 2 Go de poids, 4 Go de RAM utile. Confortable, mais limité en raisonnement.
  • 8B, environ 4,7 Go de poids, 6 à 8 Go de RAM utile. C'est le point d'équilibre sur un VPS.
  • 14B, environ 9 Go de poids, 12 Go de RAM utile. Nettement plus lent en CPU.
  • 70B et au-delà, hors de portée sans GPU. Ne perdez pas votre temps.

Côté débit, comptez quelques jetons par seconde pour un 8B sur 4 vCPU, de l'ordre d'une réponse en trente secondes à une minute. C'est parfaitement utilisable pour du traitement en arrière-plan, de la classification, de l'extraction ou un assistant interne peu sollicité. Ce n'est pas utilisable pour une interface de discussion grand public. Si vous avez besoin de vitesse et de capacité de raisonnement, une API distante reste plus économique ; l'auto-hébergement se justifie par la confidentialité et la prévisibilité du coût.

Le contexte coûte de la mémoire, en plus des poids. Le cache d'attention grandit avec la longueur de conversation : sur un 8B, tablez sur 1 à 2 Go supplémentaires pour 8 000 jetons de contexte. Dimensionnez la VM sur poids + cache + système, pas sur les poids seuls.

2. Installer Ollama

Ollama enveloppe llama.cpp d'une API HTTP et d'un gestionnaire de modèles. C'est le chemin le plus court entre un VPS nu et un modèle qui répond.

bash
curl -fsSL https://ollama.com/install.sh | sh
systemctl status ollama --no-pager

L'installateur crée un service systemd et un utilisateur dédié. Par défaut, le démon n'écoute que sur 127.0.0.1:11434, c'est exactement ce qu'il faut : l'API d'Ollama n'a aucune authentification, elle ne doit jamais être exposée directement.

3. Récupérer un modèle Hermes

Le catalogue Ollama expose la génération Hermes 3 sous le nom hermes3, en plusieurs tailles :

bash
ollama pull hermes3:8b
ollama list
ollama run hermes3:8b "Résume en trois points ce qu'est un VPS KVM."

Pour une génération plus récente ou une quantification précise, Ollama sait tirer directement un GGUF depuis Hugging Face, utile pour les modèles publiés par Nous Research avant leur arrivée au catalogue :

bash
# syntaxe : hf.co/<organisation>/<dépôt>:<quantification>
ollama pull hf.co/NousResearch/Hermes-4-14B-GGUF:Q4_K_M

Vérifiez le nom exact du dépôt et les quantifications disponibles sur la page du modèle avant de lancer le téléchargement : les noms de fichiers varient d'une publication à l'autre, et un pull qui échoue après plusieurs gigaoctets est agaçant.

4. Régler le démon

Trois variables d'environnement changent réellement quelque chose. Elles se posent dans une surcharge systemd, pas dans le fichier d'unité fourni par le paquet.

bash
sudo systemctl edit ollama.service
systemd
[Service]
Environment="OLLAMA_HOST=127.0.0.1:11434"
Environment="OLLAMA_KEEP_ALIVE=30m"
Environment="OLLAMA_NUM_PARALLEL=1"
Environment="OLLAMA_MODELS=/var/lib/ollama/models"
bash
sudo systemctl daemon-reload
sudo systemctl restart ollama
  • OLLAMA_KEEP_ALIVE, durée pendant laquelle le modèle reste en mémoire après une requête. Le défaut est court : chaque appel espacé paie alors le rechargement complet des poids depuis le disque. Sur un service peu sollicité mais qui doit répondre vite, allongez-le ; sur une VM à mémoire serrée, raccourcissez-le.
  • OLLAMA_NUM_PARALLEL, nombre de requêtes traitées en parallèle. En CPU, au-delà de 1, vous ne gagnez rien : les requêtes se partagent les mêmes cœurs et chacune ralentit d'autant.
  • OLLAMA_MODELS, emplacement des poids. Les modèles pèsent lourd ; pointez vers le volume qui a la place.

5. Utiliser l'API

Ollama expose une API native et une API compatible OpenAI, ce qui permet de brancher la plupart des bibliothèques existantes sans les modifier.

bash
# API native
curl -s http://127.0.0.1:11434/api/chat -d '{
  "model": "hermes3:8b",
  "stream": false,
  "messages": [{"role": "user", "content": "Bonjour"}]
}' | jq -r '.message.content'

# API compatible OpenAI, au même endroit
curl -s http://127.0.0.1:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model": "hermes3:8b", "messages": [{"role": "user", "content": "Bonjour"}]}' \
  | jq -r '.choices[0].message.content'

Mesurez le débit réel avant de bâtir quoi que ce soit dessus. La réponse de l'API native contient les compteurs qui comptent :

bash
curl -s http://127.0.0.1:11434/api/chat -d '{
  "model": "hermes3:8b", "stream": false,
  "messages": [{"role": "user", "content": "Écris un paragraphe sur le routage IPv6."}]
}' | jq '{
  jetons: .eval_count,
  duree_s: (.eval_duration / 1000000000),
  jetons_par_s: (.eval_count / (.eval_duration / 1000000000))
}'

eval_count compte les jetons produits et eval_duration le temps passé à les produire, en nanosecondes. Le rapport des deux est votre débit réel, celui à confronter à vos attentes avant d'aller plus loin.

6. Exposer le service, correctement

L'API d'Ollama n'a ni authentification, ni limitation de débit, ni quota. Publier le port 11434 sur Internet revient à offrir votre CPU au premier scanner venu. Le bon montage est un proxy Nginx qui termine le TLS et impose un jeton.

bash
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/ollama.htpasswd agent
nginx
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name llm.exemple.com;

    auth_basic           "llm";
    auth_basic_user_file /etc/nginx/ollama.htpasswd;

    location / {
        proxy_pass http://127.0.0.1:11434;
        proxy_buffering off;          # indispensable pour la réponse en flux
        proxy_read_timeout 600s;      # une génération longue dépasse le défaut
    }
}

Les deux lignes qui comptent sont les deux dernières. Sans proxy_buffering off, Nginx accumule toute la réponse avant de la transmettre et la génération en flux ne sert plus à rien ; sans un proxy_read_timeout allongé, une réponse longue est coupée en plein milieu par le délai d'attente de 60 secondes par défaut.

Ajoutez le certificat avec Certbot, ouvrez le port 443 dans UFW, et laissez 11434 fermé de l'extérieur. Un contrôle depuis une autre machine confirme le montage :

bash
nmap -Pn -p 11434,443 llm.exemple.com

7. Quand cela vaut le coup, et quand non

Après quelques semaines d'exploitation, la question se pose en termes simples. L'auto-hébergement gagne quand les données ne doivent pas sortir, quand le volume est régulier et prévisible, ou quand la tâche est simple, classification, extraction, reformulation, résumé court. Il perd quand vous avez besoin de la capacité de raisonnement des grands modèles, quand le trafic est en pics, ou quand le temps de réponse est visible par un utilisateur.

Rien n'oblige à choisir : router les tâches simples vers votre Hermes local et les tâches difficiles vers une API distante est un montage courant, et le premier absorbe souvent l'essentiel du volume.

Checklist

  • RAM dimensionnée sur poids + cache d'attention + système.
  • Débit réel mesuré avec eval_count et eval_duration avant de bâtir dessus.
  • Démon lié à 127.0.0.1, jamais exposé directement.
  • OLLAMA_KEEP_ALIVE ajusté à la fréquence d'appel réelle.
  • Proxy Nginx avec TLS, authentification, mise en tampon désactivée et délai allongé.
  • Port 11434 vérifié fermé depuis l'extérieur.
  • Snapshot pris une fois le modèle téléchargé, cela évite de le retélécharger.