--- # Loki + Alloy + Grafana log aggregation stack # Place this file in a directory e.g. ~/docker/loki-stack/ # Run with: docker compose up -d networks: logging: driver: bridge volumes: loki-data: grafana-data: services: # ── Loki: log storage and query engine ────────────────────────────────────── loki: image: grafana/loki:3.4.2 container_name: loki restart: unless-stopped networks: - logging ports: - "3100:3100" # Loki HTTP API (Alloy pushes here; Grafana queries here) volumes: - loki-data:/loki - ./config/loki.yml:/etc/loki/loki.yml:ro command: -config.file=/etc/loki/loki.yml healthcheck: test: ["CMD-SHELL", "wget -q --spider http://localhost:3100/ready || exit 1"] interval: 30s timeout: 5s retries: 5 # ── Alloy: log collector / syslog receiver ─────────────────────────────────── alloy: image: grafana/alloy:v1.7.5 container_name: alloy restart: unless-stopped networks: - logging ports: - "514:514/udp" # Syslog UDP (for MikroTik and other network devices) - "514:514/tcp" # Syslog TCP - "12345:12345" # Alloy UI (optional, useful for debugging) volumes: - ./config/alloy.alloy:/etc/alloy/config.alloy:ro - /var/lib/docker/containers:/var/lib/docker/containers:ro # Docker log access - /var/run/docker.sock:/var/run/docker.sock:ro # Docker metadata command: run /etc/alloy/config.alloy --server.http.listen-addr=0.0.0.0:12345 depends_on: loki: condition: service_healthy # ── Grafana: log query UI ──────────────────────────────────────────────────── grafana: image: grafana/grafana:11.5.2 container_name: grafana restart: unless-stopped networks: - logging ports: - "3098:3000" volumes: - grafana-data:/var/lib/grafana - ./config/grafana-datasources.yml:/etc/grafana/provisioning/datasources/loki.yml:ro environment: - GF_AUTH_ANONYMOUS_ENABLED=true # Remove if you want login - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin # Remove if you want login - GF_SECURITY_ADMIN_PASSWORD=changeme # Change this depends_on: loki: condition: service_healthy