Skip to main content

Grafana Loki: centralized log collection from your servers

Cloud & DevOps · 29.09.2026

When a project runs on three to five VDS instances, finding a specific line in the logs turns into visiting each server over SSH one by one. Grafana Loki collects logs from all servers in one place and lets you search them through the same Grafana interface already used for metrics. Let's cover installing Loki, the Promtail agent, and typical LogQL queries.

Why centralized logging matters and how Loki differs from ELK

Elasticsearch indexes the full text of every log line, so an ELK cluster needs a lot of memory and disk even at moderate volumes. Loki works differently: it indexes only labels — server name, service name, log level — and stores the text itself compressed in blocks. Searching by labels is nearly instant, full-text search inside the matched blocks is a bit slower, but the infrastructure for Loki needs far fewer resources than Elasticsearch.

For a fleet of several VDS instances with ordinary load, that's a reasonable trade-off: no need for a separate three-node cluster just for logs.

Installing Loki on a VDS with Docker Compose

A minimal stack — Loki for storage, Promtail for collection, Grafana for viewing — comes up with one file:

services:
  loki:
    image: grafana/loki:3.1.0
    ports:
      - "3100:3100"
    volumes:
      - ./loki-data:/loki
    command: -config.file=/etc/loki/local-config.yaml

  grafana:
    image: grafana/grafana:11.1.0
    ports:
      - "3000:3000"
    volumes:
      - ./grafana-data:/var/lib/grafana

After docker compose up -d, Loki accepts data on port 3100, and Grafana is available on port 3000 for setting up dashboards and queries.

Promtail: collecting logs from servers and shipping to Loki

Promtail is installed on every server that needs its logs collected, reads files from /var/log and docker containers, adds labels, and ships batches to Loki. The agent config:

server:
  http_listen_port: 9080

clients:
  - url: http://loki.internal:3100/loki/api/v1/push

scrape_configs:
  - job_name: nginx
    static_configs:
      - targets: ["localhost"]
        labels:
          job: nginx
          host: web-01
          __path__: /var/log/nginx/*.log

The host label here is critical: without it, in a shared log stream from five servers there's no way to tell where a specific line came from.

Setting up labels for fast search

In Loki, it's important not to turn frequently changing values into labels — for example, a request ID or a timestamp inside the line. Every unique label value creates a separate stream, and thousands of unique values turn Loki into something like Elasticsearch in terms of index load.

  • Labels should hold stable values: server name, service name, environment (prod/staging)
  • A request ID, email, or IP address is searched with a full-text query inside an already selected stream, not through a label
  • Keep the number of unique label combinations within a few hundred per installation

Connecting Loki as a data source in Grafana

In Grafana, the data source is added under Connections → Data sources → Loki, with the URL set to http://loki:3100 on a shared Docker network. Once saved, logs are searched from the Explore tab, the same interface already used for Prometheus graphs.

LogQL queries: examples

LogQL combines picking a stream by labels in curly braces with a text filter after the pipe character:

{host="web-01", job="nginx"} |= "500"
{job="nginx"} | json | status >= 500
sum(rate({job="nginx"} |= "500" [5m])) by (host)

The first query looks for the string "500" in nginx logs on a specific server, the second parses a JSON log and filters on the numeric status field, and the third counts the rate of 500 errors per minute for each server — useful for alerts and dashboards.

Storage and log rotation

By default Loki stores logs locally on disk with no time limit, so retention is configured separately with the retention_period parameter in the config, otherwise the server's disk fills up sooner or later. For a long-term log archive, fresh blocks can be shipped off to S3-compatible storage — see the article comparing S3 providers for details.

The Loki plus Promtail plus Grafana stack makes sense to deploy next to an already configured Uptime Kuma monitoring setup: availability metrics and error logs complement each other when investigating an incident. If there are many servers joined into a Docker Swarm, Promtail is deployed as a global service on every node of the cluster.

Summary: Loki launch checklist

Centralized logs save hours of searching during incidents, provided the stack is set up correctly from the start rather than thrown together after the first outage.

  • Loki for storage, Promtail on every server, Grafana for queries
  • The host label is mandatory on every log source
  • Labels hold only stable values, everything else stays in the log text
  • The retention parameter is set explicitly, not left at the default
← Back to Knowledge Base Ask Support