Pourquoi centraliser vos logs sur un VPS plutôt que de rester en SSH
Quand une erreur touche plusieurs services simultanément — un timeout côté application, un 502 côté nginx, une exception dans un worker — aucun outil SSH ne permet de corréler ces événements sans les lire un par un. docker compose logs -f app puis docker compose logs -f nginx puis docker compose logs -f worker : c'est le diagnostic en série, sur un seul serveur. Sur deux VPS, la durée double. Sur trois, elle triple.
Loki est un système d'agrégation de logs open source développé par Grafana Labs et référencé au catalogue CNCF. Contrairement à Elasticsearch, qui indexe l'intégralité du contenu de chaque ligne, Loki n'indexe que les labels — des métadonnées légères comme le nom du conteneur, le nom du service ou l'environnement. Les logs eux-mêmes sont compressés et stockés tels quels. Ce choix de conception a une conséquence directe : Loki tourne confortablement sur un VPS 2 Go de RAM, là où une stack ELK de base réclame au moins 8 à 16 Go pour rester stable. Pour un développeur ou un sysadmin qui gère plusieurs applications auto-hébergées sans budget APM enterprise, c'est la différence entre une solution faisable et une solution irréaliste.
Ce que cette stack apporte concrètement
- Recherche unifiée sur tous les conteneurs — une seule requête LogQL couvre l'ensemble des services sur tous vos VPS, sans SSH ni
grepdistribué. - Corrélation temporelle — Grafana affiche Loki (logs) et Prometheus (métriques) sur le même axe de temps : vous voyez l'erreur 502 et le pic CPU qui l'a précédée en une seule vue.
- Aucun quota d'ingestion — vous stockez autant de logs que votre disque le permet, sans abonnement ni limite mensuelle imposée par un tiers.
- Empreinte mémoire contenue — Loki consomme nettement moins de RAM qu'Elasticsearch à volume de logs équivalent, grâce à l'indexation par labels uniquement.
- Rétention configurable — définissez la durée de conservation par label (
chunk_retain_period,retention_period) selon vos contraintes de disque et de conformité. - Intégration native Grafana — Loki est une source de données de première classe dans Grafana : pas de plugin tiers, pas d'API intermédiaire.
- Alertes sur le contenu des logs — Grafana peut déclencher une alerte quand une expression régulière matche dans un flux Loki, sans passer par un service externe.
- Données hébergées sur votre infrastructure — les logs restent sur votre VPS, sans transiter par un service cloud.
Prérequis avant de déployer
La stack Loki + Promtail + Grafana est légère, mais elle a ses propres exigences. Voici ce qu'il vous faut avant de commencer.
Ressources VPS recommandées : 2 vCPU et 2 Go de RAM constituent le minimum raisonnable pour un usage mono-serveur avec quelques dizaines de conteneurs actifs. Si vous collectez les logs de plusieurs VPS ou d'un grand nombre de services, visez 4 Go de RAM. Loki ne garde pas les logs en mémoire : il les compresse et les écrit sur disque, ce qui maintient l'empreinte mémoire stable dans le temps. Prévoyez 20 à 50 Go de stockage SSD selon votre volume de logs et votre durée de rétention.
Logiciels requis : Docker et Docker Compose v2 installés sur le VPS, un sous-domaine dédié (logs.votre-domaine.com) pointant sur l'IP du VPS, et les ports 3100 (Loki) et 3000 (Grafana) accessibles en interne. Le port 3100 ne doit pas être exposé publiquement — Loki n'a pas de couche d'authentification native, seul Grafana est exposé via reverse proxy.
Déploiement étape par étape
Créer la structure de répertoires
Connectez-vous à votre VPS et créez un répertoire dédié : mkdir -p /opt/loki-stack/{loki,promtail} && cd /opt/loki-stack. Ce dossier accueillera les fichiers de configuration de Loki et de Promtail ainsi que le docker-compose.yml.
Écrire la configuration Loki
Créez /opt/loki-stack/loki/loki-config.yaml avec le contenu suivant :
auth_enabled: false — désactive l'authentification multi-tenant, suffisant pour un usage mono-VPS.
server: { http_listen_port: 3100 }
ingester: { lifecycler: { address: 127.0.0.1, ring: { kvstore: { store: inmemory }, replication_factor: 1 } }, chunk_idle_period: 5m, chunk_retain_period: 30s }
schema_config: { configs: [ { from: 2020-10-24, store: boltdb-shipper, object_store: filesystem, schema: v11, index: { prefix: index_, period: 24h } } ] }
storage_config: { boltdb_shipper: { active_index_directory: /loki/boltdb-shipper-active, cache_location: /loki/boltdb-shipper-cache, shared_store: filesystem }, filesystem: { directory: /loki/chunks } }
limits_config: { retention_period: 720h }
Écrire la configuration Promtail
Créez /opt/loki-stack/promtail/promtail-config.yaml. Promtail est l'agent qui collecte les logs des conteneurs Docker et les pousse vers Loki :
server: { http_listen_port: 9080, grpc_listen_port: 0 }
positions: { filename: /tmp/positions.yaml }
clients: [ { url: http://loki:3100/loki/api/v1/push } ]
scrape_configs: [ { job_name: docker, docker_sd_configs: [ { host: unix:///var/run/docker.sock, refresh_interval: 5s } ], relabel_configs: [ { source_labels: ['__meta_docker_container_name'], regex: '/(.*)', target_label: container }, { source_labels: ['__meta_docker_container_log_stream'], target_label: stream } ] } ]
Cette configuration utilise la découverte automatique Docker (docker_sd_configs), qui détecte chaque conteneur démarré sans intervention manuelle.
Écrire le fichier docker-compose.yml
Créez /opt/loki-stack/docker-compose.yml :
version: '3.8'
services:
loki: image: grafana/loki:3.0.0 ports: ['127.0.0.1:3100:3100'] volumes: [loki-data:/loki, ./loki/loki-config.yaml:/etc/loki/local-config.yaml] command: -config.file=/etc/loki/local-config.yaml restart: unless-stopped
promtail: image: grafana/promtail:3.0.0 volumes: [/var/run/docker.sock:/var/run/docker.sock:ro, ./promtail/promtail-config.yaml:/etc/promtail/config.yml, /var/log:/var/log:ro] command: -config.file=/etc/promtail/config.yml restart: unless-stopped depends_on: [loki]
grafana: image: grafana/grafana:latest ports: ['127.0.0.1:3000:3000'] volumes: [grafana-data:/var/lib/grafana] environment: [GF_SECURITY_ADMIN_PASSWORD=changez-moi] restart: unless-stopped depends_on: [loki]
volumes: loki-data: grafana-data:
Notez que Loki (3100) et Grafana (3000) sont liés sur 127.0.0.1 uniquement — ils ne sont pas directement accessibles depuis l'extérieur.
Démarrer la stack
Depuis /opt/loki-stack, lancez : docker compose up -d. Attendez 20 à 30 secondes puis vérifiez que les trois conteneurs sont en cours d'exécution : docker compose ps. Vérifiez ensuite les logs de Loki pour confirmer qu'il a démarré sans erreur : docker compose logs -f loki. Vous devez voir une ligne msg="Loki started" dans la sortie.
Configurer le reverse proxy pour Grafana
Exposez Grafana via nginx avec un sous-domaine et un certificat TLS. Créez /etc/nginx/sites-available/grafana.conf :
server { listen 443 ssl; server_name logs.votre-domaine.com; ssl_certificate /etc/letsencrypt/live/logs.votre-domaine.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/logs.votre-domaine.com/privkey.pem; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
Obtenez le certificat avec : certbot certonly --nginx -d logs.votre-domaine.com, puis activez le site : ln -s /etc/nginx/sites-available/grafana.conf /etc/nginx/sites-enabled/ && nginx -t && systemctl reload nginx.
Ajouter Loki comme source de données dans Grafana
Ouvrez https://logs.votre-domaine.com dans votre navigateur. Connectez-vous avec l'identifiant admin et le mot de passe que vous avez défini dans GF_SECURITY_ADMIN_PASSWORD. Allez dans Connections → Data sources → Add data source, choisissez Loki, et renseignez l'URL : http://loki:3100. Cliquez Save & test — vous devez voir le message Data source connected and labels found.
Interroger vos premiers logs
Dans Grafana, ouvrez l'onglet Explore, sélectionnez la source Loki. Utilisez le Log Browser pour choisir un label container et filtrer par nom de conteneur. Par exemple, pour voir tous les logs du conteneur nginx : {container="nginx"}. Pour filtrer sur une chaîne : {container="nginx"} |= "error". Pour compter les erreurs par conteneur sur la dernière heure : sum by (container) (count_over_time({container=~".+"} |= "error" [1h])).
Collecter les logs d'un second VPS
Pour centraliser les logs d'un second VPS dans la même instance Loki, déployez uniquement Promtail sur ce VPS secondaire. Dans sa configuration, remplacez l'URL cliente par l'adresse interne de votre premier VPS : url: http://<IP-du-VPS-Loki>:3100/loki/api/v1/push. Ouvrez le port 3100 uniquement entre les deux VPS (firewall ou réseau privé), jamais publiquement. Ajoutez un label statique pour distinguer les logs par serveur : static_configs: [ { labels: { host: vps2 } } ].
Configuration post-install : rétention, sauvegarde et alertes
Une fois la stack démarrée, trois ajustements sont importants avant de considérer le déploiement comme complet.
Rétention. La valeur retention_period: 720h dans loki-config.yaml correspond à 30 jours. Ajustez ce paramètre selon votre disque disponible (docker system df pour connaître l'occupation des volumes). Loki applique la rétention en arrière-plan sans impact notable sur les performances.
Sauvegarde. Le volume loki-data contient les index BoltDB et les chunks compressés — c'est le seul élément à sauvegarder. Un snapshot quotidien du volume Docker (docker run --rm -v loki-data:/data -v /backup:/backup alpine tar czf /backup/loki-$(date +%F).tar.gz /data) suffit pour un usage standard. Ne sauvegardez pas Grafana sans son volume grafana-data (il contient vos dashboards et alertes).
Alertes sur le contenu des logs. Dans Grafana, créez une alerte de type Grafana managed alert sur une requête Loki : par exemple, déclencher une notification quand le nombre de lignes contenant FATAL dépasse 0 sur les 5 dernières minutes. Configurez un canal de notification (e-mail, Slack, webhook) dans Alerting → Contact points avant de créer la règle.
Loki n'expose aucun mécanisme d'authentification natif sur le port 3100. Si vous devez exposer l'API Loki à un réseau non maîtrisé (pour des Promtail distants, par exemple), placez un reverse proxy nginx avec authentification par certificat client ou basic auth en amont. Ne laissez jamais le port 3100 ouvert sur 0.0.0.0 sur un VPS en production. Côté Grafana, activez l'authentification forte : GF_AUTH_ANONYMOUS_ENABLED=false et GF_USERS_ALLOW_SIGN_UP=false dans les variables d'environnement du conteneur.
Dépannage : erreurs courantes et leur résolution
Voici les problèmes les plus fréquents lors du déploiement de la stack Loki + Promtail + Grafana.
Erreurs fréquentes
msg="error creating ingester" err="context deadline exceeded"au démarrage de Loki — le conteneur Loki n'a pas accès en écriture au volume monté. Vérifiez les permissions du répertoire correspondant au volume Docker (docker inspect loki-datapour trouver le chemin réel) et assurez-vous que l'utilisateur du conteneur (UID 10001 pour les images Grafana récentes) peut écrire dedans :chown -R 10001:10001 /chemin/vers/le/volume.Data source connected and labels foundabsent dans Grafana, remplacé parconnection refused— Grafana ne peut pas atteindre Loki. Vérifiez que l'URL renseignée dans la source de données est bienhttp://loki:3100(nom du service Docker, paslocalhost) et que les deux conteneurs sont dans le même réseau Docker (docker inspect loki-grafana-stack_default).- Promtail ne collecte aucun log,
docker compose logs -f promtailmontrecomponent=discovery.docker msg="refreshing targets"en boucle sans progression — Promtail n'a pas accès au socket Docker. Vérifiez que le volume/var/run/docker.sock:/var/run/docker.sock:roest bien déclaré dans le service Promtail et que le socket existe sur l'hôte :ls -la /var/run/docker.sock. err="entry out of order for stream"dans les logs Loki — des logs arrivent avec des horodatages dans le désordre (un conteneur redémarré qui renvoie d'anciens logs, par exemple). Ajoutezmax_stream_label_count: 0danslimits_configetunordered_writes: truedansingesterdeloki-config.yamlpour accepter les entrées hors séquence.- Grafana affiche
no datasur une requête LogQL pourtant valide — vérifiez d'abord la plage de temps sélectionnée en haut à droite (le piège le plus courant : plage définie surlast 5 minutesalors que Promtail n'a pas encore collecté de logs récents). Vérifiez ensuite que le label utilisé dans votre requête existe bien :{container="nginx"}échoue si le conteneur s'appellenginx-1— utilisez le Log Browser pour explorer les labels disponibles.
Un tableau de bord pour corréler logs et métriques
L'intérêt principal de Loki dans un environnement Grafana existant est la corrélation avec les métriques Prometheus. Si vous disposez déjà d'une source Prometheus (voir l'article sur le monitoring VPS avec Grafana et Prometheus), vous pouvez créer un dashboard mixte : une rangée de panels métriques (CPU, mémoire, taux de requêtes HTTP) en haut, et un panel de logs Loki filtré sur le même service en bas. Quand un pic CPU apparaît à 14h37, vous voyez immédiatement quels logs ont été émis à cet instant précis, sans changer d'outil ni relancer une commande SSH. Ce type de corrélation est le cas d'usage qui justifie de déployer les deux stacks plutôt que l'une ou l'autre : Prometheus pour « ce qui se mesure », Loki pour « ce qui se raconte ».
Loki vs ELK vs logs en SSH — quelle approche pour quel cas
| Critère | SSH + docker logs | Stack ELK (Elastic) | Loki + Grafana |
|---|---|---|---|
| RAM requise | Aucune (pas de service) | 8–16 Go minimum par nœud | 2–4 Go pour un VPS standard |
| Indexation | Aucune | Indexation full-text (Elasticsearch) | Indexation par labels uniquement |
| Recherche multi-serveurs | Impossible sans script | Oui, nativement | Oui, via Promtail multi-hôtes |
| Corrélation avec métriques | Manuelle | Avec Kibana + APM (complexe) | Native dans Grafana |
| Coût logiciel | Nul | Licence Basic gratuite, fonctionnalités limitées | Entièrement open source, sans quota |
Ce que vous venez de mettre en orbite
Vous disposez maintenant d'une stack d'agrégation de logs fonctionnelle : Loki stocke et indexe par labels, Promtail collecte automatiquement les flux de tous vos conteneurs Docker, et Grafana offre une interface de recherche et d'alerte. La stack tourne entièrement sur votre VPS, sans service tiers, sans quota d'ingestion et sans coût logiciel additionnel. Les prochaines étapes naturelles : connecter cette stack à votre monitoring Prometheus existant pour la corrélation métriques/logs, activer le traçage distribué avec Tempo si vos applications émettent des traces OpenTelemetry, et explorer les alertes Grafana sur le contenu des logs pour être notifié avant que vos utilisateurs ne signalent un problème.