📍 Cluster : Observabilité Linux. Articles frères en fin d’article (journalctl, Grafana, monitoring).
Introduction
Quand on gère 1 ou 2 VPS, ssh srv1 'journalctl -u nginx --since today' reste pratique. Quand on en gère 10, 30, 100, c’est ingérable : impossible de se connecter à chaque machine pour chaque investigation. La solution moderne — alternative open source à Splunk, Datadog, Sumo Logic — est la stack Loki + Promtail + Grafana de Grafana Labs : Promtail scrape les logs sur chaque VPS, les pousse vers une instance Loki centralisée, et Grafana les requête via le langage LogQL. L’ensemble est gratuit, performant, et conçu pour les volumes modestes à moyens (jusqu’à ~10 To/jour sur une seule instance Loki).
Ce tutoriel détaille le déploiement de Promtail comme agent de collecte sur un VPS Linux : installation, configuration pour scraper journald + fichiers texte, labels, parsing structuré, envoi vers Loki distant avec authentification, intégration TLS, et monitoring de Promtail lui-même. Le déploiement et l’administration de l’instance Loki côté serveur sont couverts dans un satellite frère ; on suppose ici que vous avez déjà une URL Loki accessible et des credentials. Pour une PME ouest-africaine avec 5-15 VPS, cette stack remplace avantageusement les solutions cloud commerciales tarifées au volume (qui finissent à 200-500 €/mois), pour ~30 €/mois de VPS Hetzner CX31 dédié à Loki + Grafana.
Prérequis
- VPS Linux avec systemd (Debian 11+, Ubuntu 22.04+, Rocky/Alma 9)
- Accès sudo
- Une instance Loki accessible via HTTPS (URL + credentials Basic Auth ou tenant header)
- Une instance Grafana liée à Loki pour vérifier la collecte (optionnel mais fortement recommandé)
- Connaissance basique de YAML (Promtail se configure en YAML)
- Niveau attendu : intermédiaire
- Temps estimé : 30 à 45 minutes
Étape 1 — Installation de Promtail
Promtail est distribué en binaire statique unique (Go), sans dépendances, et également packagé pour les distributions principales. Sur Debian/Ubuntu, le paquet officiel Grafana est disponible via le dépôt Grafana ; sur Rocky/Alma via le mirror RPM. Alternative : télécharger directement le binaire depuis GitHub releases (utile sur des distros plus exotiques).
# Méthode 1 : dépôt officiel Grafana sur Debian/Ubuntu
sudo apt install -y curl gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://apt.grafana.com/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/grafana.gpg
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | \
sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install -y promtail
# Méthode 2 : binaire direct (sur toutes distros)
LATEST=$(curl -s https://api.github.com/repos/grafana/loki/releases/latest | jq -r .tag_name)
sudo curl -fsSL -o /usr/local/bin/promtail \
https://github.com/grafana/loki/releases/download/${LATEST}/promtail-linux-amd64.zip
sudo chmod +x /usr/local/bin/promtail
# Vérifier la version (3.x recommandé en 2026)
promtail --version
# Préparer le user système (si binaire direct)
sudo useradd --no-create-home --shell /usr/sbin/nologin promtail
sudo mkdir -p /var/lib/promtail
sudo chown promtail: /var/lib/promtail
La version recommandée minimale en 2026 est Promtail 3.0+ (Loki 3 series). Les versions Promtail 2.x fonctionnent encore mais perdent certaines optimisations (parsing structuré JSON, support natif de certains agents). Avec le paquet officiel Grafana, le service systemd promtail.service est créé automatiquement ; en méthode binaire direct, il faut écrire l’unit systemd soi-même (voir Étape 4).
Étape 2 — Configuration : scraper journald
Le fichier de configuration /etc/promtail/config.yml définit trois choses : le serveur HTTP Promtail (pour debug), le client Loki (où envoyer), et les « scrape configs » (sources de logs). La source la plus universelle sur Linux moderne est journald : tous les logs systemd y sont déjà concentrés, structurés, et taggés par unit/priority.
# /etc/promtail/config.yml — configuration journald + Loki
server:
http_listen_port: 9080
grpc_listen_port: 0
log_level: info
positions:
filename: /var/lib/promtail/positions.yaml
clients:
- url: https://loki.votre-entreprise.com/loki/api/v1/push
basic_auth:
username: vps-hotel-saint-louis
password_file: /etc/promtail/loki-password
tenant_id: hotel-saint-louis
backoff_config:
min_period: 500ms
max_period: 5m
max_retries: 10
batchwait: 1s
batchsize: 1048576
scrape_configs:
- job_name: journal
journal:
max_age: 12h
json: true
labels:
job: systemd-journal
host: vps-hotel-saint-louis
relabel_configs:
- source_labels: ['__journal__systemd_unit']
target_label: 'unit'
- source_labels: ['__journal__hostname']
target_label: 'hostname'
- source_labels: ['__journal_priority_keyword']
target_label: 'level'
- source_labels: ['__journal_syslog_identifier']
target_label: 'identifier'
Trois choix structurants. password_file stocke le mot de passe Loki dans un fichier permissions 0400 plutôt que dans config.yml — meilleure hygiène (un dump de config.yml dans un commit Git ne révèle pas le mot de passe). tenant_id active le multi-tenancy Loki : si l’instance Loki centralisée est partagée entre plusieurs clients, chaque client a son tenant_id et ne voit que ses logs. relabel_configs transforme les labels internes journald (préfixés __journal__) en labels Loki propres et persistants. Les labels persistants doivent rester peu nombreux (<10) et de cardinalité limitée pour ne pas exploser l'index Loki.
Étape 3 — Scraper des fichiers texte additionnels
Tous les logs ne passent pas par journald : Nginx logue par défaut dans /var/log/nginx/access.log et error.log, Apache pareil, beaucoup d’applications custom écrivent dans des fichiers texte. Promtail scrape ces fichiers via le job file_sd ou des paths statiques, avec parsing optionnel pour extraire des labels structurés depuis les lignes.
# Ajout dans /etc/promtail/config.yml — scrape_configs:
- job_name: nginx-access
static_configs:
- targets:
- localhost
labels:
job: nginx-access
host: vps-hotel-saint-louis
__path__: /var/log/nginx/access.log
pipeline_stages:
- regex:
expression: '^(?P<remote_ip>\S+) - (?P<remote_user>\S+) \[(?P<timestamp>[^\]]+)\] "(?P<method>\S+) (?P<path>\S+) [^"]+" (?P<status>\d+) (?P<bytes>\d+)'
- labels:
method:
status:
- timestamp:
source: timestamp
format: '02/Jan/2006:15:04:05 -0700'
- job_name: nginx-error
static_configs:
- targets:
- localhost
labels:
job: nginx-error
host: vps-hotel-saint-louis
__path__: /var/log/nginx/error.log
- job_name: app-custom-json
static_configs:
- targets:
- localhost
labels:
job: app-reservation
host: vps-hotel-saint-louis
__path__: /var/log/app/*.json
pipeline_stages:
- json:
expressions:
level: level
request_id: request_id
user_id: user_id
- labels:
level:
# request_id et user_id sont laissés en champs structurés (pas en labels)
# — utilisables avec | json dans LogQL, mais pas en cardinalité haute
Le pipeline_stages parse chaque ligne pour en extraire des champs structurés. Pour Nginx au format combined classique, la regex matche les composants principaux (IP, méthode, path, status, bytes). Les labels persistants (method, status) sont à choisir avec parcimonie : un label avec ~10 valeurs distinctes (méthodes HTTP, codes status grouped) est OK ; un label avec >1000 valeurs distinctes (IPs sources, paths uniques) explose l’index. Pour ces champs à haute cardinalité, ne pas les promouvoir en labels mais les laisser en contenu structuré (JSON), requêtable avec | json | request_id="abc".
Étape 4 — Service systemd et activation
Avec le paquet Grafana, le service systemd existe déjà. En méthode binaire direct, il faut le créer. Le service doit tourner avec un user dédié (promtail), pouvoir lire /var/log/ et journald, et avoir un Restart=on-failure pour redémarrer auto en cas de crash.
# /etc/systemd/system/promtail.service (si binaire direct)
[Unit]
Description=Promtail log collector
Documentation=https://grafana.com/docs/loki/latest/clients/promtail/
After=network-online.target systemd-journald.service
Wants=network-online.target
[Service]
Type=simple
User=promtail
Group=systemd-journal
ExecStart=/usr/local/bin/promtail -config.file=/etc/promtail/config.yml
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
# Hardening
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
NoNewPrivileges=true
# Pour lire /var/log/nginx/, ajouter promtail au groupe approprié
SupplementaryGroups=adm
[Install]
WantedBy=multi-user.target
# Activer
sudo systemctl daemon-reload
sudo systemctl enable --now promtail
sudo systemctl status promtail
# Vérifier les permissions journald
sudo usermod -aG systemd-journal promtail
sudo systemctl restart promtail
Les directives de hardening (PrivateTmp, ProtectSystem, ProtectHome, NoNewPrivileges) limitent la surface d’attaque si Promtail est compromis. SupplementaryGroups=adm permet la lecture des logs Nginx (les fichiers /var/log/nginx/* sont en groupe adm par défaut). Pour journald, l’appartenance au groupe systemd-journal est nécessaire (ou plus largement adm). Vérifier avec id promtail que les groupes sont bien appliqués.
Étape 5 — Validation côté Loki/Grafana
Une fois Promtail démarré, vérifier que les logs arrivent bien dans Loki côté serveur. Trois angles de vérification : l’endpoint /metrics de Promtail (compteurs de lignes envoyées), l’API Loki (labels disponibles), et l’UI Grafana avec une requête LogQL.
# 1. Compteurs Promtail locaux
curl -s http://localhost:9080/metrics | grep promtail_sent_entries_total
# promtail_sent_entries_total{host="vps-hotel-saint-louis"} 42857
# Aucune ligne envoyée ? Vérifier les erreurs
curl -s http://localhost:9080/metrics | grep promtail_dropped_entries_total
sudo journalctl -u promtail -n 50
# 2. Côté Loki : tester quels labels remontent
curl -s -u user:pass https://loki.votre-entreprise.com/loki/api/v1/labels
# Doit retourner job, host, unit, level, hostname, identifier...
curl -s -u user:pass "https://loki.votre-entreprise.com/loki/api/v1/label/host/values"
# Doit lister vos VPS
# 3. Requête LogQL via Grafana
# Explore → datasource Loki → requête :
# {host="vps-hotel-saint-louis"} # tous les logs du VPS
# {host="vps-hotel-saint-louis", unit="nginx.service"} # nginx uniquement
# {host="vps-hotel-saint-louis"} |~ "(?i)error" # erreurs (regex insensible)
# rate({host="vps-hotel-saint-louis"}[5m]) # taux de logs / 5min
Si l’endpoint /metrics de Promtail montre des envois croissants mais que Loki ne voit rien, c’est typiquement (1) une mauvaise URL Loki dans config.yml, (2) un mauvais tenant_id, (3) un blocage firewall sortant côté VPS Promtail (vérifier curl -v https://loki.votre-entreprise.com/ready), (4) une horloge VPS désynchronisée — Loki refuse les logs avec timestamps > 7 jours dans le passé ou plus de 10 minutes dans le futur. Synchroniser l’horloge avec timedatectl set-ntp true et vérifier chronyc tracking.
Étape 6 — Monitoring de Promtail lui-même
Comme tout agent de collecte, Promtail peut tomber silencieusement. Il faut donc le monitorer : ses propres métriques Prometheus (exposées sur :9080/metrics), son état systemd, et une « heartbeat » via une ligne de log régulière pour confirmer le pipeline complet de bout en bout.
# Métriques Prometheus de Promtail à scraper
# (depuis votre Prometheus, scrape config :)
scrape_configs:
- job_name: promtail
static_configs:
- targets:
- vps-hotel-saint-louis:9080
- vps-other:9080
# Métriques clés à grapher dans Grafana :
# promtail_files_active_total # nombre de fichiers actuellement scrapés
# promtail_sent_entries_total # lignes envoyées (compteur, taux à dériver)
# promtail_dropped_entries_total # lignes droppées (doit rester à 0)
# promtail_request_duration_seconds_bucket # latence vers Loki
# promtail_target_active_total # cibles actives
# Alerte Prometheus (alertmanager)
# - alert: PromtailDown
# expr: up{job="promtail"} == 0
# for: 5m
# annotations:
# summary: "Promtail down sur {{ $labels.instance }}"
#
# - alert: PromtailDroppingLogs
# expr: rate(promtail_dropped_entries_total[5m]) > 0
# for: 10m
# Heartbeat : un cron qui logue toutes les minutes une ligne reconnaissable
# /etc/cron.d/promtail-heartbeat
# * * * * * root logger -t heartbeat-promtail "alive $(date +%s)"
# Côté Grafana, alerter si la ligne heartbeat n'arrive plus depuis 5 min :
# count_over_time({identifier="heartbeat-promtail"}[5m]) == 0
L’approche heartbeat + alerte Grafana détecte les pannes invisibles aux métriques Prometheus locales : si Promtail tourne, lit ses fichiers, mais le réseau vers Loki est coupé, les compteurs locaux montent normalement mais aucun log n’arrive. La vérification end-to-end via une ligne logguée localement et lue dans Loki ferme cette boucle. Sur un parc de plusieurs VPS, c’est l’unique alerte fiable de « ma collecte fonctionne en bout-en-bout » et coûte 0 perf.
Étape 7 — Optimisation pour les gros volumes
Si votre VPS génère 10+ Go de logs/jour (web haute trafic, batch ETL, jobs CI), Promtail en config par défaut peut commencer à montrer ses limites : utilisation CPU élevée, retards d’envoi, drops sous charge. Plusieurs leviers d’optimisation : batch sizes, parallelism, sampling.
# /etc/promtail/config.yml — tuning pour gros volume
clients:
- url: ...
batchwait: 500ms # délai max avant envoi (défaut 1s) — plus court = moins de latence
batchsize: 4194304 # 4 Mo par batch (défaut 1 Mo) — plus gros = moins de requêtes
timeout: 30s # timeout de chaque envoi
# Multi-clients : envoyer aux mêmes clusters Loki avec failover
# Permet HA si on a 2 instances Loki
# Réduction du trafic via sampling (échantillonnage)
scrape_configs:
- job_name: nginx-access-sampled
pipeline_stages:
- sampling:
rate: 10 # garde 1 ligne sur 10
...
# Pour les jobs très bavards (millions de lignes/h), ajouter un drop précoce
scrape_configs:
- job_name: nginx-access
pipeline_stages:
- match:
selector: '{job="nginx-access"} |~ "GET /healthz"'
action: drop
- regex: ...
# Surveillance fine de la perf Promtail
# CPU : top -p $(pgrep promtail)
# Mémoire : ps -o rss,vsz -p $(pgrep promtail)
# File descriptors : ls /proc/$(pgrep promtail)/fd/ | wc -l
Le sampling est utile pour des logs où la valeur statistique compte plus que la complétude (ex: access logs où on veut le taux global, pas chaque requête). Le drop précoce élimine les requêtes de monitoring (healthz, ready) qui polluent sans valeur. Combiné, ces optimisations peuvent diviser par 5-10 le volume envoyé à Loki sur un site web typique, sans perte d’information actionnable.
Erreurs fréquentes
| Erreur | Cause | Solution |
|---|---|---|
| Promtail démarre mais aucun log n’arrive à Loki | Mauvaise URL Loki, mauvais tenant, ou firewall sortant bloque | Test direct : curl -v https://loki.../ready ; vérifier journalctl -u promtail pour erreurs |
| « out of order » rejected by Loki | Horloge VPS désynchronisée OU plusieurs Promtails écrivent les mêmes lignes | timedatectl set-ntp true ; ne jamais avoir deux Promtail scrapant le même fichier |
| « too many failed attempts to push to Loki » | Crédentiels invalides, ou tenant inexistant côté serveur Loki | Vérifier le couple username/password ; côté Loki, vérifier que le tenant est créé/autorisé |
| Index Loki explose (cardinalité) | Trop de labels persistants, ou label avec valeurs uniques (request_id, IP, path) | Garder ≤10 labels persistants, valeurs <100 distinct ; déplacer haute cardinalité en JSON |
| Promtail consomme 100 % CPU | Regex pipeline trop coûteuse, ou volume trop gros | Simplifier les regex, drop early, sampling, ou switcher vers Vector (plus performant) |
| « file not found » sur logs nginx | nginx n’a pas encore créé le fichier (premier accès), ou logrotate l’a déplacé | Promtail gère bien logrotate ; vérifier permissions et existence du fichier |
Adaptation au contexte ouest-africain
Trois aspects pratiques. Premièrement, l’instance Loki centrale : pour une PME ouest-africaine, héberger Loki sur un VPS Hetzner CX31 (4 vCPU, 8 Go RAM, 80 Go SSD) à ~13 €/mois suffit pour ingester 50-200 Go/mois (rétention 30 jours). Le stockage chunks Loki peut être déplacé vers Hetzner Storage Box (1 To à 4 €/mois) via S3-compatible (MinIO ou directement le Storage Box configuré en S3) pour rétention longue durée à coût marginal. L’option « tout sur le même VPS » tient jusqu’à environ 10 VPS ingérés ; au-delà, séparer Loki / Grafana sur deux VPS distincts.
Deuxièmement, latence et bandwidth : les VPS Hetzner Helsinki/Falkenstein vers d’autres VPS Hetzner ont une latence de quelques ms. Pour des VPS chez des hébergeurs locaux ouest-africains (Tunis Cloud, CIRA, etc.) qui forwardent vers un Loki en Europe, la latence monte à 150-200 ms et la bandwidth peut être limitée. Mitigation : augmenter batchsize et batchwait pour réduire le nombre de requêtes (et donc l’overhead TCP), passer en compression gzip si pas déjà actif, et accepter une latence d’observation un peu plus haute (5-30 secondes entre log généré et visible Grafana).
Troisièmement, alerter sans surcharger : pour une équipe technique de 1-2 personnes, recevoir 50 alertes par jour mène à l’ignorance. Configurer Grafana Alerting avec : (1) règles très ciblées (ex: nginx 5xx > 10/min ET non lié à un déploiement en cours), (2) routing vers WhatsApp / SMS pour les critiques (via twilio ou Africa’s Talking), email pour les warnings, (3) silences automatiques pendant les fenêtres de maintenance déclarées. Une bonne configuration alerte 1-3 fois par semaine en moyenne — ce qui se traite vraiment.
Tutoriels frères
- journalctl logs systemd : tutoriel pratique 2026 — la source des logs côté VPS
- Installer Loki sur Coolify — le serveur destinataire de Promtail
- Prometheus node-exporter sur VPS — métriques système complémentaires aux logs
- Wazuh SIEM — alternative orientée sécurité au tandem Loki/Promtail
FAQ
Promtail vs Vector vs Fluent Bit, lequel choisir ?
Promtail est natif Loki, le plus simple à configurer pour cet usage. Vector est plus performant (Rust, ~2x plus rapide) et plus polyvalent (multi-destinations : Loki, Elasticsearch, S3, ClickHouse en parallèle), mais courbe d’apprentissage plus raide. Fluent Bit est le standard CNCF, supporté largement, bon compromis. Pour 1-15 VPS et stack 100 % Grafana → Promtail. Pour parc 30+ VPS multi-destinations → Vector. Pour intégration Kubernetes/CNCF → Fluent Bit.
Comment éviter de perdre des logs si Loki est inaccessible quelques minutes ?
Promtail garde un buffer en mémoire et persiste les positions de lecture dans positions.yaml. En cas de panne Loki, Promtail accumule en mémoire (limité par batchsize) et retry exponentiellement (backoff_config). Si Loki revient sous quelques minutes, les logs sont rejouée sans perte. Pour des pannes plus longues (> 30 min), augmenter le buffer mémoire de Promtail ou prévoir un Loki HA local (deux instances avec replication). Pour les exigences réglementaires de zéro perte, ajouter un sink secondaire (S3 Storage Box avec write-once) en parallèle de Loki.
Promtail consomme combien de ressources sur un VPS ?
Très peu en config simple (journald + 2-3 fichiers, < 1 Go/jour) : 50-100 Mo de RAM, 1-3 % CPU sur un vCPU moderne. Avec parsing complexe (regex sur 10+ fichiers, pipelines lourds), on peut monter à 200-500 Mo de RAM et 10-20 % CPU. Si la consommation dérape, c'est presque toujours dû à des regex inefficaces — les profiler avec promtail -log.level=debug et simplifier.
Comment migrer depuis ELK/Datadog vers Loki ?
Phase 1 (1-2 semaines) : déployer Promtail en parallèle de l’agent existant, vérifier que les logs arrivent bien dans Loki, valider que les requêtes essentielles marchent en LogQL. Phase 2 (4-8 semaines) : migrer les dashboards et alertes une à une. Phase 3 : couper l’ancien agent. Le coût d’usage Loki/Grafana auto-hébergé est ~10-20 % d’un Datadog équivalent ; la migration est donc rentable même avec quelques semaines d’effort.
Pour aller plus loin
- Documentation officielle Promtail : grafana.com/docs/loki/latest/clients/promtail
- Référence config Promtail : grafana.com/docs/loki/latest/clients/promtail/configuration
- Documentation LogQL (langage de requête) : grafana.com/docs/loki/latest/logql
- Vector (alternative performante) : vector.dev/docs
- Tutoriel suivant suggéré : déployer Loki sur Coolify pour compléter la stack
Mots-clés secondaires : Promtail, Loki, Grafana logs, observabilité Linux, LogQL, journald scraping, log collection, Vector vs Promtail, multi-tenant Loki, hardening Promtail.