How to Self-Host Promtail with Docker Compose

What Is Promtail?

Promtail is Grafana’s log collection agent designed to ship logs to Loki. It discovers log files, attaches labels, and pushes entries to Loki’s API. Think of it as the “Prometheus of logs” — it tails files and streams them to your central log store. Promtail entered LTS in early 2026; Grafana recommends Grafana Alloy for new deployments, but Promtail remains widely used and fully functional.

Updated March 2026: Verified with latest Docker images and configurations.

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • A running Loki instance (Loki setup guide)
  • 512 MB of free RAM
  • Basic understanding of your log file locations

Docker Compose Configuration

This deploys Promtail alongside Loki and Grafana as a complete logging stack. If you already have Loki running, use only the promtail service.

Create a docker-compose.yml file:

services:
  loki:
    image: grafana/loki:3.6.7
    container_name: loki
    ports:
      - "3100:3100"
    volumes:
      - loki_data:/loki
    command: -config.file=/etc/loki/local-config.yaml
    restart: unless-stopped

  promtail:
    image: grafana/promtail:3.6.7
    container_name: promtail
    volumes:
      - ./promtail-config.yml:/etc/promtail/config.yml:ro
      - /var/log:/var/log:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - promtail_positions:/tmp
    command: -config.file=/etc/promtail/config.yml
    depends_on:
      - loki
    restart: unless-stopped

  grafana:
    image: grafana/grafana:12.4.1
    container_name: grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=changeme  # CHANGE THIS
    restart: unless-stopped

volumes:
  loki_data:
  promtail_positions:
  grafana_data:

Create a promtail-config.yml file alongside:

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

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

scrape_configs:
  # System logs
  - job_name: system
    static_configs:
      - targets:
          - localhost
        labels:
          job: syslog
          __path__: /var/log/syslog

  # Auth logs
  - job_name: auth
    static_configs:
      - targets:
          - localhost
        labels:
          job: auth
          __path__: /var/log/auth.log

  # Docker container logs
  - job_name: docker
    static_configs:
      - targets:
          - localhost
        labels:
          job: docker
          __path__: /var/lib/docker/containers/*/*-json.log
    pipeline_stages:
      - json:
          expressions:
            log: log
            stream: stream
            time: time
      - labels:
          stream:
      - timestamp:
          source: time
          format: RFC3339Nano
      - output:
          source: log

Start the stack:

docker compose up -d

Initial Setup

  1. Verify Promtail is running and connected to Loki:
docker compose logs promtail

You should see lines like Starting Promtail and Sending batch — no connection errors.

  1. Open Grafana at http://your-server:3000 (default login: admin / changeme).

  2. Add Loki as a data source:

    • Go to Connections → Data Sources → Add data source
    • Select Loki
    • Set URL to http://loki:3100
    • Click Save & Test
  3. Go to Explore, select the Loki data source, and query {job="syslog"} to see system logs flowing in.

Configuration

Scrape Config Structure

Each scrape_config defines a log source with three key parts:

ComponentPurpose
job_nameLabel for this log source
static_configsFile paths and labels to attach
pipeline_stagesOptional log parsing and transformation

Adding Custom Log Sources

To collect logs from a specific application (e.g., Nginx):

scrape_configs:
  - job_name: nginx
    static_configs:
      - targets:
          - localhost
        labels:
          job: nginx
          type: access
          __path__: /var/log/nginx/access.log
      - targets:
          - localhost
        labels:
          job: nginx
          type: error
          __path__: /var/log/nginx/error.log

Mount the log directory in your Docker Compose:

promtail:
  volumes:
    - /var/log/nginx:/var/log/nginx:ro

Pipeline Stages

Pipeline stages parse and transform log lines before sending to Loki:

pipeline_stages:
  # Parse JSON logs
  - json:
      expressions:
        level: level
        message: msg
        timestamp: ts

  # Add extracted values as labels
  - labels:
      level:

  # Parse timestamps
  - timestamp:
      source: timestamp
      format: "2006-01-02T15:04:05.000Z"

  # Set the output line
  - output:
      source: message

Multi-Tenant Configuration

Route logs to different Loki tenants:

clients:
  - url: http://loki:3100/loki/api/v1/push
    tenant_id: infrastructure

  - url: http://loki:3100/loki/api/v1/push
    tenant_id: applications

Advanced Configuration (Optional)

Journal Scraping (systemd)

Collect logs from systemd journal instead of files:

scrape_configs:
  - job_name: journal
    journal:
      max_age: 12h
      labels:
        job: systemd-journal
    relabel_configs:
      - source_labels: ['__journal__systemd_unit']
        target_label: 'unit'

Requires mounting the journal directory:

volumes:
  - /var/log/journal:/var/log/journal:ro
  - /run/log/journal:/run/log/journal:ro
  - /etc/machine-id:/etc/machine-id:ro

Regex Parsing for Unstructured Logs

Extract fields from plain text logs:

pipeline_stages:
  - regex:
      expression: '^(?P<ip>\S+) \S+ \S+ \[(?P<timestamp>[^\]]+)\] "(?P<method>\S+) (?P<path>\S+) \S+" (?P<status>\d+) (?P<size>\d+)'
  - labels:
      method:
      status:
  - timestamp:
      source: timestamp
      format: "02/Jan/2006:15:04:05 -0700"

Drop Noisy Logs

Filter out unwanted log lines to reduce storage:

pipeline_stages:
  - drop:
      expression: "healthcheck"
      drop_counter_reason: "healthcheck_noise"
  - drop:
      expression: "GET /favicon.ico"
      drop_counter_reason: "favicon_noise"

Reverse Proxy

Promtail’s HTTP API (port 9080) is typically internal-only. If you need to expose it:

location /promtail/ {
    proxy_pass http://localhost:9080/;
    proxy_set_header Host $host;
}

For reverse proxy setup details, see Reverse Proxy Setup.

Backup

Back up the positions file to preserve read offsets:

docker compose exec promtail cat /tmp/positions.yaml > promtail-positions-backup.yaml

The positions file tracks where Promtail left off in each log file. If lost, Promtail re-reads from the beginning of active files. For your full backup strategy, see Backup Strategy.

Troubleshooting

Promtail Not Sending Logs to Loki

Symptom: No data appears in Grafana when querying Loki. Fix: Check Promtail logs for connection errors:

docker compose logs promtail | grep -i error

Verify Loki is reachable from the Promtail container:

docker compose exec promtail wget -qO- http://loki:3100/ready

Permission Denied on Log Files

Symptom: permission denied errors for /var/log/ files. Fix: Run Promtail as root or add the container user to the appropriate groups. In Docker Compose, add:

promtail:
  user: root

Duplicate Log Entries After Restart

Symptom: Same log lines appear multiple times in Loki. Fix: Ensure the positions volume is persistent. If promtail_positions is lost, Promtail re-reads all files from the start. Check:

docker volume inspect promtail_positions

High Memory Usage

Symptom: Promtail consuming excessive RAM. Fix: Reduce the number of active targets or add rate limiting:

limits_config:
  readline_rate_enabled: true
  readline_rate: 100
  readline_burst: 1000

Docker Container Logs Not Appearing

Symptom: Docker logs not visible despite /var/lib/docker/containers being mounted. Fix: Verify Docker’s log driver is json-file (the default). Other drivers like journald require different scraping:

docker info | grep "Logging Driver"

Resource Requirements

  • RAM: 50-100 MB idle, 200-500 MB under heavy log volume
  • CPU: Low — Promtail is I/O-bound, not CPU-bound
  • Disk: Minimal — positions file is a few KB. Logs are stored in Loki, not Promtail.

Verdict

Promtail is the simplest path to getting logs into Loki. If you already run Loki and Grafana, Promtail is the natural collector — zero configuration friction, native label support, and pipeline stages handle most parsing needs. For new deployments, evaluate Grafana Alloy as the next-generation replacement — it handles logs, metrics, and traces in a single agent. For existing setups, Promtail works reliably and will receive LTS patches.

Frequently Asked Questions

Is Promtail being replaced by Grafana Alloy?

Yes. Grafana has announced that Promtail is in maintenance mode and recommends Grafana Alloy for new deployments. Alloy handles logs, metrics, and traces in a single agent. Existing Promtail setups will continue receiving security patches but no new features. If starting fresh, consider Alloy. If Promtail is already working, there’s no urgent need to migrate.

Can Promtail collect logs from Docker containers?

Yes. Mount /var/lib/docker/containers and /var/run/docker.sock into the Promtail container, then configure a Docker scrape target. Promtail reads container logs and adds labels for container name, image, and compose service. Docker must use the default json-file logging driver.

Does Promtail work without Loki?

No. Promtail is specifically designed to ship logs to Loki. It cannot send logs to Elasticsearch, Graylog, or other log backends. If you need a flexible log shipper that works with multiple backends, use Fluentd, Fluent Bit, or Vector instead.

How does Promtail handle log parsing?

Promtail uses pipeline stages for log processing. You can parse JSON, regex-match log lines, extract labels, add timestamps, drop unwanted lines, and transform values — all in the configuration file. Pipeline stages process logs before sending them to Loki, so you can structure and filter data at the source.

Can Promtail collect system logs (journald, syslog)?

Yes. Promtail supports journald and syslog as log sources alongside file-based scraping. For journald, configure a journal scrape config. For syslog, Promtail can listen on a UDP/TCP port as a syslog receiver. Mount /var/log/journal for journald access.

How much disk space does Promtail use?

Promtail uses virtually no disk space — it reads log files and streams them to Loki without storing copies. The only persistent data is a small positions file (a few KB) that tracks read offsets so Promtail can resume after restart. All log storage is in Loki, not Promtail.

Comments