Visualizing Nginx Access Logs with Loki and Grafana
This guide explains how to collect Nginx access logs, convert them to JSON, store them in Loki using Promtail, and visualize the data with Grafana dashboards, including installation of required modules, Docker deployment, and world‑map panel configuration.
A client needed a way to view website access statistics without using Google or Baidu analytics, so the solution chosen was the Loki stack (Nginx + Promtail + Loki + Grafana) for a lightweight site.
Install Nginx as usual, then download and extract the binary releases of Promtail and Loki, configuring Promtail with a server: http_listen_port: 9080 grpc_listen_port: 0 positions: filename: /tmp/positions.yaml clients: - url: http://localhost:3100/loki/api/v1/push scrape_configs: - job_name: nginx pipeline_stages: - replace: expression: '(?:[0-9]{1,3}\.){3}([0-9]{1,3})' replace: '***' static_configs: - targets: - localhost labels: job: nginx_access_log host: expatsxxxxs agent: promtail __path__: /var/log/nginx/expatshxxxxs.access.log to push logs to Loki.
Modify Nginx to output logs in JSON format by adding the following log_format json_analytics escape=json '{"msec": "$msec", "connection": "$connection", "connection_requests": "$connection_requests", "pid": "$pid", "request_id": "$request_id", "request_length": "$request_length", "remote_addr": "$remote_addr", "remote_user": "$remote_user", "remote_port": "$remote_port", "time_local": "$time_local", "time_iso8601": "$time_iso8601", "request": "$request", "request_uri": "$request_uri", "args": "$args", "status": "$status", "body_bytes_sent": "$body_bytes_sent", "bytes_sent": "$bytes_sent", "http_referer": "$http_referer", "http_user_agent": "$http_user_agent", "http_x_forwarded_for": "$http_x_forwarded_for", "http_host": "$http_host", "server_name": "$server_name", "request_time": "$request_time", "upstream": "$upstream_addr", "upstream_connect_time": "$upstream_connect_time", "upstream_header_time": "$upstream_header_time", "upstream_response_time": "$upstream_response_time", "upstream_response_length": "$upstream_response_length", "upstream_cache_status": "$upstream_cache_status", "ssl_protocol": "$ssl_protocol", "ssl_cipher": "$ssl_cipher", "scheme": "$scheme", "request_method": "$request_method", "server_protocol": "$server_protocol", "pipe": "$pipe", "gzip_ratio": "$gzip_ratio", "http_cf_ray": "$http_cf_ray", "geoip_country_code": "$geoip_country_code" }'; in the Nginx configuration.
Install the GeoIP module by running yum -y install GeoIP GeoIP-data GeoIP-devel , then recompile Nginx with --with-http_geoip_module , and reload it using kill -USR2 to apply the new log format.
Deploy Grafana via Docker with docker run -d -p 3000:3000 grafana/grafana , log in using the default admin credentials, add Loki as a data source, and import a pre‑built dashboard by ID.
Since the world‑map panel is missing, install it using grafana-cli plugins install grafana-worldmap-panel and restart Grafana; the map will then display, though external map tiles may need a reverse‑proxy workaround.
After these steps, the client can view detailed, searchable Nginx access logs in Grafana, demonstrating that Loki + Grafana provides an effective monitoring solution for small‑scale websites.
Architect's Tech Stack
Java backend, microservices, distributed systems, containerized programming, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.