No description
Find a file
pasantru 7605af70de fix Grafana dashboard provisioning: remove kubernetesDashboards feature toggle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 20:09:19 +01:00
ansible@56b357f9d2 update submodule: point ansible to remote Forgejo repo 2026-02-28 23:04:46 +01:00
grafana add mTLS for Prometheus, node_exporter, and Grafana; add README 2026-02-28 23:03:25 +01:00
scripts add mTLS for Prometheus, node_exporter, and Grafana; add README 2026-02-28 23:03:25 +01:00
.gitignore add mTLS for Prometheus, node_exporter, and Grafana; add README 2026-02-28 23:03:25 +01:00
.gitmodules update submodule: point ansible to remote Forgejo repo 2026-02-28 23:04:46 +01:00
blackbox.yml initial 2026-02-28 18:49:38 +01:00
CLAUDE.md initial 2026-02-28 18:49:38 +01:00
docker-compose.yml fix Grafana dashboard provisioning: remove kubernetesDashboards feature toggle 2026-03-09 20:09:19 +01:00
prometheus-web-config.yml add mTLS for Prometheus, node_exporter, and Grafana; add README 2026-02-28 23:03:25 +01:00
prometheus.yml add mTLS for Prometheus, node_exporter, and Grafana; add README 2026-02-28 23:03:25 +01:00
README.md add mTLS for Prometheus, node_exporter, and Grafana; add README 2026-02-28 23:03:25 +01:00

Homelab Monitoring Stack

Prometheus + Blackbox Exporter + Grafana running in Docker Compose, with mTLS on all internal connections and Ansible for node management.

Architecture

                        ┌─────────────────────────────────────┐
                        │           Docker Compose             │
                        │                                      │
  Browser ──────────────┤→ Grafana :3009  ──mTLS──→ Prometheus :9090
                        │                               │       │
                        │                          mTLS │       │ HTTP
                        │                               ↓       ↓
                        │                        Blackbox :9115  │
                        └───────────────────────────────────────┘
                                                        │
                               ┌────────────────────────┘
                               │ HTTPS probes
                               ↓
                    pasantru.es, *.homelab.pasantru.es

  Prometheus ──mTLS──→ node_exporter :9100  (nfs: 192.168.1.25)
  Prometheus ──mTLS──→ node_exporter :9100  (videoserver: 192.168.1.10)

Services

Service Image Port (host)
Prometheus prom/prometheus:v3.9.1 9090
Blackbox Exporter quay.io/prometheus/blackbox-exporter:latest
Grafana grafana/grafana:latest 3009

Prerequisites

  • Docker + Docker Compose
  • step CLI (for cert generation)
  • Ansible (for node_exporter deployment to remote nodes)

Directory Structure

.
├── docker-compose.yml                        # Service definitions
├── prometheus.yml                            # Scrape configs and targets
├── prometheus-web-config.yml                 # Prometheus TLS server + mTLS client auth config
├── blackbox.yml                              # Blackbox prober modules
├── .gitignore                                # Ignores certs/ and generated datasource YAML
├── scripts/
│   └── gen-certs.sh                          # Generates all PKI certs + Grafana datasource YAML
├── certs/                                    # (gitignored) Generated TLS certificates
│   ├── ca.crt / ca.key                       # Root CA
│   ├── prometheus-server.crt / .key          # Prometheus TLS server cert
│   ├── prometheus-client.crt / .key          # Prometheus mTLS client cert (scrapes nodes)
│   ├── grafana-client.crt / .key             # Grafana mTLS client cert (datasource)
│   ├── nfs-server.crt / .key                 # node_exporter cert for nfs
│   └── videoserver-server.crt / .key         # node_exporter cert for videoserver
├── grafana/
│   └── provisioning/
│       ├── datasources/
│       │   ├── prometheus.yml                # (gitignored) Generated with embedded certs
│       │   └── prometheus.yml.example        # Tracked template showing structure
│       ├── dashboards/
│       │   ├── dashboards.yml                # Dashboard provisioning config
│       │   ├── homelab.json                  # Blackbox probe dashboard
│       │   └── node-overview.json            # Node metrics dashboard (CPU/mem/disk/net)
│       └── alerting/
│           └── smart-alerts.yml              # SMART disk alert rules
└── ansible/
    ├── ansible.cfg
    ├── inventory/
    │   └── hosts.yml                         # nfs + videoserver hosts
    ├── playbooks/
    │   ├── site.yml                          # Full setup: common + node_exporter
    │   └── update.yml                        # Apt update/upgrade only
    └── roles/
        ├── common/                           # apt update, dist-upgrade, autoremove
        └── node_exporter/                    # Install binary + mTLS config

Setup

1. Generate certificates

Install step CLI, then from the repo root:

./scripts/gen-certs.sh

This creates all certs under certs/ (gitignored) and writes grafana/provisioning/datasources/prometheus.yml with the CA and Grafana client cert embedded directly — no volume mounts needed for Grafana.

Re-run the script any time you need to rotate certs. CA is preserved if it already exists.

2. Deploy node_exporter to nodes

ansible-playbook ansible/playbooks/site.yml

This installs node_exporter on nfs (192.168.1.25) and videoserver (192.168.1.10), deploys the host-specific server cert, and starts node_exporter with mTLS enabled.

3. Start the stack

docker compose up -d

Grafana: http://localhost:3009 — default credentials admin / admin (change on first login).

4. Reload Prometheus config (if already running)

curl -X POST http://localhost:9090/-/reload

mTLS

All internal traffic is encrypted and mutually authenticated:

Connection Client cert Server cert
Grafana → Prometheus grafana-client prometheus-server
Prometheus → node_exporter (nfs) prometheus-client nfs-server
Prometheus → node_exporter (videoserver) prometheus-client videoserver-server

All certs are signed by the local homelab-ca. TTL is 1 year — re-run gen-certs.sh before expiry.

Verify mTLS

# node_exporter responds over mTLS
curl --cacert certs/ca.crt \
     --cert certs/prometheus-client.crt \
     --key  certs/prometheus-client.key \
     https://192.168.1.25:9100/metrics | head

# Prometheus HTTPS endpoint
curl --cacert certs/ca.crt \
     --cert certs/grafana-client.crt \
     --key  certs/grafana-client.key \
     https://localhost:9090/-/healthy

Monitored Targets

Blackbox (HTTPS probe + SSL check)

Configured in prometheus.yml under the blackbox job:

Add new targets to the blackbox job's static_configs list in prometheus.yml.

Node metrics (node_exporter over mTLS)

Host IP Metrics collected
nfs 192.168.1.25 CPU, memory, disk, network
videoserver 192.168.1.10 CPU, memory, disk, network, SMART

Dashboards

Dashboard Description
Homelab Blackbox probe status and SSL expiry
Node Overview Per-node CPU, memory, disk I/O, network — filterable by job

Dashboards are auto-provisioned from grafana/provisioning/dashboards/.


Common Operations

# Start the stack
docker compose up -d

# Stop the stack
docker compose down

# Restart after config changes
docker compose restart

# Reload Prometheus config without restart
curl -X POST http://localhost:9090/-/reload

# View logs
docker compose logs -f prometheus
docker compose logs -f grafana

# Update packages on nodes (no node_exporter changes)
ansible-playbook ansible/playbooks/update.yml

# Redeploy node_exporter (e.g. after cert rotation)
ansible-playbook ansible/playbooks/site.yml

Grafana Credentials

  • URL: http://localhost:3009
  • Default: admin / admin
  • SMTP alerts via Mailgun are pre-configured in docker-compose.yml