Configure NGINX log analysis with Loki and Grafana for centralized monitoring

Intermediate 45 min Apr 19, 2026 120 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up Loki log aggregation with Promtail agent to collect NGINX logs and create Grafana dashboards for comprehensive web server monitoring and analysis.

Prerequisites

  • NGINX web server installed and running
  • Root or sudo access
  • At least 2GB RAM available
  • Basic knowledge of systemd services

What this solves

NGINX generates access and error logs that contain valuable insights about your web server performance, traffic patterns, and potential issues. By default, these logs are stored locally and require manual analysis. This tutorial sets up Loki for centralized log storage with Promtail as the log shipping agent, then creates Grafana dashboards to visualize NGINX metrics, errors, and traffic patterns in real-time.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you have the latest software versions.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Configure NGINX structured logging

Modify NGINX configuration to use structured JSON logging format. This makes log parsing more reliable and provides better data extraction for Loki.

http {
    log_format json_logs escape=json
    '{
        "timestamp":"$time_iso8601",
        "remote_addr":"$remote_addr",
        "remote_user":"$remote_user",
        "request":"$request",
        "status":"$status",
        "body_bytes_sent":"$body_bytes_sent",
        "request_time":"$request_time",
        "http_referrer":"$http_referer",
        "http_user_agent":"$http_user_agent",
        "http_x_forwarded_for":"$http_x_forwarded_for",
        "upstream_addr":"$upstream_addr",
        "upstream_response_time":"$upstream_response_time"
    }';
    
    access_log /var/log/nginx/access.log json_logs;
    error_log /var/log/nginx/error.log warn;
}

Test and reload NGINX configuration

Verify the configuration syntax is correct before applying changes.

sudo nginx -t
sudo systemctl reload nginx

Install Loki

Download and install Loki binary for log aggregation and storage.

cd /tmp
wget https://github.com/grafana/loki/releases/download/v2.9.4/loki-linux-amd64.zip
unzip loki-linux-amd64.zip
sudo mv loki-linux-amd64 /usr/local/bin/loki
sudo chmod +x /usr/local/bin/loki

Create Loki configuration

Create the configuration directory and main Loki configuration file with retention policies and storage settings.

sudo mkdir -p /etc/loki /var/lib/loki
auth_enabled: false

server:
  http_listen_port: 3100
  grpc_listen_port: 9096

common:
  path_prefix: /var/lib/loki
  storage:
    filesystem:
      chunks_directory: /var/lib/loki/chunks
      rules_directory: /var/lib/loki/rules
  replication_factor: 1
  ring:
    instance_addr: 127.0.0.1
    kvstore:
      store: inmemory

query_range:
  results_cache:
    cache:
      embedded_cache:
        enabled: true
        max_size_mb: 100

schema_config:
  configs:
    - from: 2020-10-24
      store: boltdb-shipper
      object_store: filesystem
      schema: v11
      index:
        prefix: index_
        period: 24h

ruler:
  alertmanager_url: http://localhost:9093

limits_config:
  reject_old_samples: true
  reject_old_samples_max_age: 168h
  ingestion_rate_mb: 16
  ingestion_burst_size_mb: 32

chunk_store_config:
  max_look_back_period: 0s

table_manager:
  retention_deletes_enabled: true
  retention_period: 168h

Create Loki systemd service

Set up Loki as a system service with proper user permissions and automatic startup.

sudo useradd --system --no-create-home --shell /bin/false loki
sudo chown -R loki:loki /var/lib/loki /etc/loki
[Unit]
Description=Loki log aggregation system
After=network-online.target

[Service]
Type=simple
User=loki
Group=loki
ExecStart=/usr/local/bin/loki -config.file=/etc/loki/loki.yml
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Start and enable Loki service

Start Loki and configure it to start automatically on system boot.

sudo systemctl daemon-reload
sudo systemctl enable --now loki
sudo systemctl status loki

Install Promtail log agent

Download and install Promtail to collect and ship NGINX logs to Loki.

cd /tmp
wget https://github.com/grafana/loki/releases/download/v2.9.4/promtail-linux-amd64.zip
unzip promtail-linux-amd64.zip
sudo mv promtail-linux-amd64 /usr/local/bin/promtail
sudo chmod +x /usr/local/bin/promtail

Configure Promtail for NGINX logs

Create Promtail configuration to collect NGINX access and error logs with proper parsing and labeling.

sudo mkdir -p /etc/promtail
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /var/lib/promtail/positions.yaml

clients:
  - url: http://localhost:3100/loki/api/v1/push

scrape_configs:
  - job_name: nginx-access
    static_configs:
      - targets:
          - localhost
        labels:
          job: nginx-access
          __path__: /var/log/nginx/access.log
    pipeline_stages:
      - json:
          expressions:
            timestamp: timestamp
            remote_addr: remote_addr
            request: request
            status: status
            body_bytes_sent: body_bytes_sent
            request_time: request_time
            http_user_agent: http_user_agent
            upstream_response_time: upstream_response_time
      - labels:
          remote_addr:
          status:
      - timestamp:
          source: timestamp
          format: RFC3339

  - job_name: nginx-error
    static_configs:
      - targets:
          - localhost
        labels:
          job: nginx-error
          __path__: /var/log/nginx/error.log
    pipeline_stages:
      - regex:
          expression: '^(?P\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[(?P\w+)\] (?P.*)'
      - labels:
          level:
      - timestamp:
          source: timestamp
          format: '2006/01/02 15:04:05'

Create Promtail systemd service

Set up Promtail as a system service with appropriate permissions to read NGINX logs.

sudo useradd --system --no-create-home --shell /bin/false promtail
sudo mkdir -p /var/lib/promtail
sudo chown -R promtail:promtail /var/lib/promtail /etc/promtail
sudo usermod -aG adm promtail
[Unit]
Description=Promtail log collector
After=network-online.target

[Service]
Type=simple
User=promtail
Group=promtail
ExecStart=/usr/local/bin/promtail -config.file=/etc/promtail/promtail.yml
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Start and enable Promtail service

Start Promtail service and verify it can read NGINX log files successfully.

sudo systemctl daemon-reload
sudo systemctl enable --now promtail
sudo systemctl status promtail

Install Grafana

Install Grafana for creating dashboards and visualizing NGINX log data from Loki.

wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install -y grafana
sudo dnf install -y https://dl.grafana.com/oss/release/grafana-10.2.3-1.x86_64.rpm

Start and enable Grafana

Enable Grafana service and start it on system boot.

sudo systemctl enable --now grafana-server
sudo systemctl status grafana-server

Configure firewall rules

Open firewall ports for Grafana web interface and Loki API if accessing from remote hosts.

sudo ufw allow 3000/tcp comment "Grafana"
sudo ufw allow 3100/tcp comment "Loki API"
sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --permanent --add-port=3100/tcp
sudo firewall-cmd --reload

Add Loki data source to Grafana

Access Grafana at http://your-server-ip:3000 (admin/admin). Navigate to Configuration > Data Sources and add Loki as a data source with URL http://localhost:3100.

curl -X POST http://admin:admin@localhost:3000/api/datasources \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Loki",
    "type": "loki",
    "url": "http://localhost:3100",
    "access": "proxy",
    "isDefault": true
  }'

Create NGINX monitoring dashboard

Import or create a dashboard with panels for request rates, status codes, response times, and error logs.

{
  "dashboard": {
    "title": "NGINX Log Analysis",
    "panels": [
      {
        "title": "Request Rate",
        "type": "stat",
        "targets": [
          {
            "expr": "rate({job=\"nginx-access\"}[5m])",
            "refId": "A"
          }
        ]
      },
      {
        "title": "Status Codes",
        "type": "piechart",
        "targets": [
          {
            "expr": "sum by (status) (rate({job=\"nginx-access\"}[5m]))",
            "refId": "A"
          }
        ]
      },
      {
        "title": "Top IPs",
        "type": "table",
        "targets": [
          {
            "expr": "topk(10, sum by (remote_addr) (rate({job=\"nginx-access\"}[5m])))",
            "refId": "A"
          }
        ]
      },
      {
        "title": "Error Logs",
        "type": "logs",
        "targets": [
          {
            "expr": "{job=\"nginx-error\"}",
            "refId": "A"
          }
        ]
      }
    ],
    "time": {
      "from": "now-1h",
      "to": "now"
    },
    "refresh": "30s"
  }
}
curl -X POST http://admin:admin@localhost:3000/api/dashboards/db \
  -H "Content-Type: application/json" \
  -d @/tmp/nginx-dashboard.json

Verify your setup

Test that logs are flowing from NGINX through Promtail to Loki and can be queried in Grafana.

# Generate some NGINX traffic
curl http://localhost/
curl http://localhost/nonexistent

Check Loki API for logs

curl -G -s "http://localhost:3100/loki/api/v1/query" --data-urlencode 'query={job="nginx-access"}' | jq

Check Promtail status

sudo systemctl status promtail journalctl -u promtail -f

Verify Grafana data source

curl http://admin:admin@localhost:3000/api/datasources

Configure log retention and alerting

Set up log retention policies

Configure automatic cleanup of old logs to prevent disk space issues.

# Add to limits_config section
retention_period: 720h  # 30 days
per_stream_rate_limit: 3MB
per_stream_rate_limit_burst: 15MB
sudo systemctl restart loki

Create log-based alerts

Set up Grafana alerts for high error rates and suspicious traffic patterns.

# Alert for high 5xx error rate
query: sum(rate({job="nginx-access",status=~"5.."}[5m]))
condition: IS ABOVE 0.1
frequency: 1m
for: 2m

Common issues

SymptomCauseFix
Promtail can't read logsPermission deniedsudo usermod -aG adm promtail && sudo systemctl restart promtail
No logs in GrafanaLoki data source misconfiguredVerify URL is http://localhost:3100 in data source settings
JSON parsing errorsNGINX log format mismatchCheck /var/log/nginx/access.log format matches promtail config
Loki disk fullNo retention policyConfigure retention in /etc/loki/loki.yml and restart
High memory usageToo many active streamsReduce cardinality by limiting labels in promtail config

Next steps

Running this in production?

Want this handled for you? Setting up log monitoring once is straightforward. Keeping it patched, monitored, backed up and tuned across environments is the harder part. See how we run infrastructure like this for European SaaS and e-commerce teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed devops services for businesses that depend on uptime. From initial setup to ongoing operations.