Home Lab Monitoring with Prometheus, Loki, Alloy and Grafana

Set up a lightweight observability stack using Prometheus, Loki, and Alloy for metrics and log collection, all visualised in Grafana. This home lab guide focuses on simplicity, minimal config, and quick deployment with Docker Compose—helping you monitor containerised applications effortlessly.

Home Lab Monitoring with Prometheus, Loki, Alloy and Grafana
Photo by Nadine E / Unsplash

Introduction

Observability is crucial in any modern infrastructure, whether you're managing cloud-native applications or running services in a home lab. With the right tools, you can monitor metrics and aggregate logs to diagnose issues.

In this guide, we’ll set up Prometheus for metrics collection, Loki for log aggregation, and Alloy as a unified data pipeline. We’ll also use Grafana to query and visualise everything. By the end, you'll have a fully functional observability stack for your containerised applications.

This guide is part of my home lab series, where I document my journey in building a lightweight testing environment to experiment and learn without unnecessary complexity. If you’re new to my project, I recommend starting with my first article, where I lay out the foundation of my setup.

Jimmie Rissanen
Exploring software, learning, and personal growth.

Inspiration & References

The configuration presented in this guide is inspired by various open-source projects. In particular:

These resources helped form my own setup, and I highly recommend checking them out for alternative approaches or deeper insights.


Table of Contents


Goals and Limitations

Goals

For this project, the objective is to:

✅ Collect logs and metrics from my running containers.
✅ Keep the setup minimal and lightweight.
✅ Use configurations that require low maintenance.

Limitations

To keep things simple, the following constraints apply:

No persistence – Data is lost on container restart.
No authentication – Services are accessible without credentials.
Only container metrics – No application-level instrumentation.
All containers are included – No selective labelling or filtering.

This is not a production-ready setup but rather a starting point to learn how these tools work together. The focus is on how to set them up, not why to use them in production.

Initialise the Project

Checkout my home lab repo to follow along of create your own!

Below is a simple diagram illustrating how the observability stack components interact. Alloy collects both logs and metrics from the running containers and sends them to Loki and Prometheus. Grafana then queries these data sources for visualisation.
A simple architecture diagram showing how Alloy collects logs and metrics from running containers and forwards them to Loki and Prometheus. Grafana connects to both data sources to visualise the data.
Architectural overview

To begin, create a new directory to hold all observability-related configurations:

mkdir observability && cd observability
touch docker-compose.yaml

Project Initialisation

This will keep all configuration files organised in a single location.

Prometheus

Prometheus is responsible for collecting and storing metrics from running containers. Add the following configuration to your docker-compose.yaml:

services:
  prometheus:
    container_name: prometheus
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    command:
      - --config.file=/etc/prometheus/prometheus.yml

Prometheus Configuration in Docker Compose

Explanation

  • container_name: Names the container prometheus for easy identification.
  • image: Pulls the latest version of Prometheus.
  • ports: Maps port 9090 from the container to the host, making the Prometheus UI accessible.
  • command: Specifies the path to the Prometheus configuration file.

Since we're not mounting a configuration file, Prometheus will start with its default settings. We do how ever need to specify where the config file is located.

Loki

Loki is a log aggregation system that efficiently stores and queries logs. Add this to docker-compose.yaml:

  loki:
    container_name: loki
    image: grafana/loki:latest
    ports:
      - "3100:3100"

Loki Configuration in Docker Compose

Explanation

  • container_name: Names the container loki.
  • image: Uses the latest Loki version.
  • ports: Maps Loki’s 3100 port for external access.

Loki will be used as the destination for logs collected from all running containers.

Alloy

Alloy serves as the telemetry pipeline, collecting and forwarding logs and metrics to Loki and Prometheus. Add the following configuration:

  alloy:
    container_name: alloy
    image: grafana/alloy:latest
    volumes:
      - ./alloy:/etc/alloy/
      - /var/run/docker.sock:/var/run/docker.sock
    command:
      - run
      - /etc/alloy/config.alloy
      - --server.http.listen-addr=0.0.0.0:12345

Alloy Configuration in Docker Compose

Explanation

  • contaner_name: Names the container alloy.
  • image: Uses the latest Alloy image.
  • volumes:
    • Mounts ./alloy to /etc/alloy/, where the config file will be stored.
    • Mounts the Docker socket, allowing Alloy to discover running containers.
  • command:
    • run starts Alloy.
    • /etc/alloy/config.alloy specifies the configuration file.
    • --server.http.listen-addr=0.0.0.0:12345 makes the Alloy HTTP server accessible.
  • ports: I chose to omit ports but if you would like to view the alloy ui you can provide a config for that under ports. 12345:12345 is normally used for accessing Alloy.

Configuring Alloy

Alloy uses a plain text configuration format, defined in a config.alloy file. This file determines what data to collect and where to send it.

Start by creating the configuration file:

mkdir alloy && touch alloy/config.alloy

Creating Alloy Configuration File

For this guide, Alloy will be configured to collect logs and container metrics. Alloy provides different components for data collection. Here, we’ll use:

  • discovery.docker – To detect running Docker containers.
  • discovery.relabel – To modify and add labels to collected data.
  • loki.source.docker & loki.write – To send logs to Loki.
  • prometheus.exporter.cadvisor & prometheus.remote_write – To collect and send metrics to Prometheus.

Collecting Logs

To collect logs from all running Docker containers, Alloy needs to identify them. The discovery.docker component accomplishes this by pointing to the Docker socket on the host machine:

discovery.docker "linux" {
  host = "unix:///var/run/docker.sock"
}

Alloy Docker Discovery

By default, Alloy assigns metadata to discovered containers, but we can enhance this using discovery.relabel. This step adds a custom label called service_name, which extracts the container name from the __meta_docker_container_name label.

discovery.relabel "logs_integrations_docker" {
  targets = []

  rule {
    source_labels = ["__meta_docker_container_name"]
    regex = "^/?(.*)$"
    target_label = "service_name"
  }
}

Alloy Relabelling for Logs

This ensures logs are tagged with a human-readable service_name, making it easier to filter and analyse data later.

Forwarding Logs to Loki

Now that Alloy can discover and tag logs, we need to forward them to Loki.

  • loki.source.docker collects logs from running containers.
  • loki.write sends the logs to the Loki service.
loki.source.docker "docker_logs" {
  host          = "unix:///var/run/docker.sock"
  targets       = discovery.docker.linux.targets
  labels        = {"platform" = "docker"}
  relabel_rules = discovery.relabel.logs_integrations_docker.rules
  forward_to    = [loki.write.loki.receiver]
}

loki.write "loki" {
  endpoint {
    url = "http://loki:3100/loki/api/v1/push"
  }
}

Alloy Configuration for Loki

Since all services in this setup share a Docker network, we can refer to Loki by its container name (loki) instead of an IP address.

Collecting Metrics

For container performance monitoring, we use prometheus.exporter.cadvisor, which collects metrics like CPU usage, memory consumption, and network activity from all running containers.

prometheus.exporter.cadvisor "docker_metrics" {
  docker_host       = "unix:///var/run/docker.sock"
  storage_duration  = "5m"
}

Alloy Configuration for Prometheus Metrics Collection

This configuration connects to the Docker daemon and retains metric data for 5 minutes before discarding old values.

Scraping and Forwarding Metrics to Prometheus

Next, we configure Prometheus to scrape the metrics collected by cadvisor and forward them to our Prometheus instance:

prometheus.scrape "scraper" {
  targets         = prometheus.exporter.cadvisor.docker_metrics.targets
  forward_to      = [prometheus.remote_write.prometheus.receiver]
  scrape_interval = "10s"
}

prometheus.remote_write "prometheus" {
  endpoint {
    url = "http://prometheus:9090/api/v1/write"
  }
}

Alloy Scraping and Forwarding Metrics to Prometheus

  • prometheus.scrape collects container metrics every 10 seconds.
  • prometheus.remote_write ensures these metrics are sent to Prometheus.

Setting Up Grafana

Grafana provides a visualisation layer for logs and metrics. Add this to docker-compose.yaml:

  grafana:
    container_name: grafana
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_LOG_LEVEL=debug
    volumes:
      - ./grafana/provisioning/datasources:/etc/grafana/provisioning/datasources

Grafana Configuration in Docker Compose

Explanation

  • container_name: Names the container grafana.
  • image: Uses the latest grafana image.
  • ports: Maps Grafana’s web interface to port 3000.
  • environment: Sets log level to debug.
  • volumes: Auto-configures data sources on startup.

Configuring Grafana

Create the provisioning config file at this path:

mkdir -p grafana/provisioning/datasources && touch grafana/provisioning/datasources/datasource.yaml

Creating Grafana Data Source Configuration File

apiVersion: 1

datasources:
  - name: Loki
    type: loki
    access: proxy
    url: http://loki:3100
    basicAuth: false

  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    basicAuth: false

Configuring Data Sources in Grafana

Running the Applications

Start everything with:

docker compose up -d

Starting the Observability Stack

Access Grafana at http://localhost:3000 (login: admin/admin).

Once the observability stack is up and running, you can open Grafana in your browser and visualise the data sources. Below is an example of container metrics and logs from my deployment.

Screenshot of Grafana displaying container metrics collected from Prometheus, including CPU and memory usage over time.
Metrics in Grafana
Screenshot of Grafana's Loki query interface displaying logs collected from running Docker containers using Alloy.
Logs in Grafana

Conclusion

With this setup, you now have a fully functional observability stack for your home lab, capable of collecting logs and metrics from your containers. By integrating Prometheus, Loki, Alloy, and Grafana, you've created a streamlined system that enables monitoring, visualisation, and troubleshooting—all with minimal configuration.

While this guide is tailored for a lightweight home lab setup, it provides a foundation for observability in more advanced environments. If you plan to extend this for production use, consider adding persistence, authentication, and more refined configurations to tailor the setup to your needs.

With everything running, you can now visualise your containerised applications. Happy monitoring! 🚀