Analyser des logs Nginx avec Elasticsearch et Kibana
21 Feb 2026
Introduction
Même si écrire des articles et des tutoriels sur ce blog est un hobby et qu’aucun gain n’y est recherché, j’aime bien comprendre quels articles sont les plus lus et lesquels passent inaperçus. Ça me permet de consacrer plus de temps à peaufiner les sujets qui intéressent le plus.
C’est là qu’on met un pied dans la fourmillière de l’analytics web. Il existe de nombreux outils auto-hébergés. Cela peut aller d’une simple feuille de calcul où l’on trace ses propres graphiques, à des plateformes complètes comme Matomo ou Umami.
En ce qui me concerne, je voulais trouver une solution qui respecte la vie privée des visiteurs, c’est à dire :
- Pas de JavaScript traquant les données dans le navigateur
- Se baser exclusivement sur les logs du serveur pour analyser le trafic (Nginx dans mon cas)
Avec ces contraintes, j’ai choisi la stack ELK (nommée d’après ses composants : Elasticsearch / Logstash / Kibana) pour deux raisons :
- C’est un outil puissant qui vaut le coup d’être appris dans mon domaine (même si je n’ai pas l’intention d’en devenir un expert).
- Je l’utilise déjà pour analyser d’autres données temporelles. Par “données temporelles” je parle ici de données qui sont capturées à des intervalles de temps réguliers ou irréguliers. Comme des logs, des transactions financières, etc.
Je tiens à préciser que je ne recommanderais pas cette configuration en production. Il existe de meilleurs outils pour cet usage. Pour une solution plus light, je vous suggère de vous renseigner sur Loki et Grafana !
Et je me connais : dans six ans j’aurai tout oublié de ce setup, donc ce tutoriel me servira aussi de documentation personnelle 🙂
C’est parti.
Installer Nginx + ELK
Pour simplifier au maximum, on va tout faire tourner dans des conteneurs Docker. Commençons par créer quelques fichiers dans le dossier de votre choix. Dans cet exemple je crée un dossier elk-tuto.
mkdir elk-tuto
cd elk-tuto
touch docker-compose.yml
touch kibana.yml
touch elasticsearch.yml
mkdir html
cd html
touch article1.html
touch article2.html
docker-compose.yml
volumes:
elasticsearch_data:
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.19.9
environment:
ES_JAVA_OPTS: "-Xmx256m -Xms256m"
discovery.type: single-node
volumes:
- elasticsearch_data:/usr/share/elasticsearch/data
- ./elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
kibana:
image: docker.elastic.co/kibana/kibana:8.19.9
volumes:
- ./kibana.yml:/usr/share/kibana/config/kibana.yml:ro
ports:
- "5601:5601"
nginx:
image: nginx:1.29.5-alpine-slim
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
elasticsearch.yml
---
cluster.name: "docker-cluster"
network.host: 0.0.0.0
xpack.license.self_generated.type: basic
xpack.ml.enabled: false
xpack.security.enabled: false
kibana.yml
---
server.name: kibana
server.host: "0.0.0.0"
elasticsearch.hosts: [ "http://elasticsearch:9200" ]
article1.html
<!DOCTYPE html>
<html>
<head>
<title>Article 1</title>
</head>
<body>
<h1>Article 1 - what's the weather today</h1>
</body>
</html>
article2.html
<!DOCTYPE html>
<html>
<head>
<title>Article 2</title>
</head>
<body>
<h1>Article 2 - something cool</h1>
</body>
</html>
Ce que nous avons :
- Un conteneur Elasticsearch qui stockera les données parsées depuis les logs Nginx.
- Un conteneur Kibana pour visualiser ces données.
- Un conteneur Nginx avec 2 pages, prêtes à générer des logs que nous enverrons bientôt à Elasticsearch.
Executez docker compose up -d depuis le répertoire elk-tuto, et après quelques minutes vous devriez pouvoir ouvrir Kibana à l’adresse http://localhost:5601. Si vous voyez « Configure Elastic to get started », attendez encore quelques secondes jusqu’à voir « Welcome home ».
Filebeat entre en scène
Il manque un élément pour que tout cela devienne vraiment utile. Comment envoyer nos logs nginx vers ELK ? C’est là que Filebeat est pratique.
La documentation docker de Filebeat est disponible via ce lien.
Commençons par mettre à jour le fichier docker-compose.yml et créer la configuration filebeat. On expliquera deux ou trois trucs juste après.
docker-compose.yml
...
services:
...
filebeat:
image: docker.elastic.co/beats/filebeat:8.19.9
user: root
# On surcharge la commande pour définir --strict.perms=false car
# nous sommes en développement et on ne veut pas se soucier des permissions.
# En production, il faudra mettre les bons droits à la place.
command: filebeat -e --strict.perms=false
volumes:
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
filebeat.yml
filebeat.config:
modules:
path: '${path.config}/modules.d/*.yml'
reload.enabled: false
filebeat.autodiscover:
providers:
- type: docker
templates:
- condition:
contains:
# Si vous utilisez une image nginx personnalisée, pensez à mettre à jour cette ligne.
# Exemple : registry.gitlab.com/user/mon-site/mon-nginx
docker.container.image: nginx
config:
- module: nginx
access:
enabled: true
input:
type: container
stream: stdout
paths:
# Par défaut docker stocke ses données dans /var/lib/docker.
# Si vous avez configuré un autre dossier,
# adaptez ce chemin et le suivant.
- '/var/lib/docker/containers/${data.docker.container.id}/*.log'
error:
enabled: true
input:
type: container
stream: stderr
paths:
- '/var/lib/docker/containers/${data.docker.container.id}/*.log'
output.elasticsearch:
hosts: 'elasticsearch:9200'
pipeline: geoip-info
N’executez pas encore docker compose up -d car nous devons d’abord créer le “processor geoip”.
Vous noterez que nous avons monté le dossier /var/lib/docker/containers directement dans le conteneur filebeat. C’est là que les logs nginx sont présents en dehors du conteneur.
Avant d’aller plus loin, vérifions que ces logs sont bien accessibles avec la commande tail suivante :
nginx_container_id=$(docker ps -q --no-trunc --filter "name=nginx-1") && sudo tail -f /var/lib/docker/containers/$nginx_container_id/$nginx_container_id-json.log
Puis ouvrez http:localhost:8080/article1.html pour s’assurer que de nouveaux logs s’affichent comme prévu.
Ajouter le processor geoip
Je suis sûr que vous voudrez visualiser dans Kibana d’où viennent vos visiteurs. Pour cela, on peut utiliser Filebeat avec le GeoIP Processor d’Elasticsearch pour enrichir les adresses IP avec des informations géographiques (documentation).
On peut créer la pipeline directement depuis la console Kibana à l’adresse http://localhost:5601/app/dev_tools#/console/shell.
PUT _ingest/pipeline/geoip-info
{
"description": "Add geoip info",
"processors": [
{
"geoip": {
"field": "source.ip",
"target_field": "source.geo",
"ignore_missing": true
}
}
]
}

Cliquez sur la petite flèche. Si vous voyez "acknowledged": true dans le panneau de droite, c’est tout bon.
Visualiser les logs dans Kibana
Tout est prêt, il est temps de relancer docker compose up -d pour démarrer Filebeat et envoyer quelques logs vers elasticsearch.
Avant d’ouvrir Kibana, ouvrez et rafraîchissez plusieurs fois http://localhost:8080/article1.html et http://localhost:8080/article2.html afin de générer des logs.
Ensuite, ouvrez la page Index Management de Kibana, puis l’onglet Data Streams. Vous devriez voir filebeat-8.19.9 créé à partir des logs de notre conteneur Nginx.
Passons ensuite à la page Data Views et cliquez sur le bouton Create data view.

Remplissez les champs et cliquez sur “Save data view to Kibana”

Enfin, ouvrez la page Discover. Vous devriez voir les données de logs, bien parsées dans différents champs prêts à être utilisés pour créer des graphiques.
En local, on ne peut pas faire grand-chose de plus. Mais avec ce setup sur un serveur distant, vous aurez des données de qualité, incluant les IP réelles.
Tous les fichiers sont disponibles directement sur GitHub ici.
Si ce tutoriel vous a été utile, mettez une étoile au repo pour dire merci ! ⭐