AI-generated content

A good monitoring setup is the difference between “the network is down” and “I noticed packet loss on eth0 at 2:14 AM and already sent a fix.”

Architecture

[Devices] → [Exporters] → [Prometheus] → [Grafana]
                    ↓
                 [Alertmanager] → [Notifications]
Component Purpose
Prometheus Time-series database, scraping, alerting
Grafana Visualization, dashboards, alerting
Alertmanager Deduplication, routing, notifications
Exporters System/network metrics collection

Components to Monitor

Servers

  • node_exporter: CPU, memory, disk, network, temperatures
  • cAdvisor: Container metrics (memory, CPU, filesystem)
  • blackbox_exporter: HTTP/TCP/ICMP probing

Network

  • snmp_exporter: Router/switch metrics via SNMP
  • nfdump_exporter: NetFlow data for traffic analysis
  • Suricata: IDS/IPS metrics

Services

  • Prometheus itself: Scrape health
  • Application exporters: Custom app metrics
  • Uptime Kuma: Simple uptime monitoring

Quick Start

Docker Compose Setup

version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=30d'
      - '--storage.tsdb.path=/prometheus'
    ports:
      - "9090:9090"
    restart: unless-stopped

  grafana:
    image: grafana/grafana:latest
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/dashboards:/etc/grafana/provisioning/dashboards
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=your-strong-password
    ports:
      - "3000:3000"
    depends_on:
      - prometheus
    restart: unless-stopped

  alertmanager:
    image: prom/alertmanager:latest
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
    ports:
      - "9093:9093"
    restart: unless-stopped

volumes:
  prometheus-data:
  grafana-data:

Prometheus Configuration

global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - "alert.rules"

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node'
    static_configs:
      - targets: ['node_exporter:9100']

  - job_name: 'blackbox'
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets:
        - https://example.com
        - https://github.com
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: blackbox_exporter:9115

  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']

Essential Dashboards

1. System Overview (node_exporter)

  • CPU utilization by core
  • Memory pressure
  • Disk I/O and space
  • Network throughput
  • System load averages

2. Network Traffic

  • Bandwidth per interface
  • Top talkers (with nfdump)
  • Error rates
  • Packet drops
  • Connection tracking

3. Service Health

  • Uptime per service
  • Response times
  • Error rates
  • Certificate expiry
  • DNS resolution times

4. Security

  • Failed SSH attempts (fail2ban metrics)
  • Port scan detection
  • Firewall rule hits
  • File integrity changes

Alert Rules

groups:
  - name: infrastructure
    rules:
      - alert: HighCPU
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 90
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High CPU on {{ $labels.instance }}"
          description: "{{ $labels.instance }} CPU usage > 90% for 5 minutes"

      - alert: DiskSpaceLow
        expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 < 10
        for: 10m
        labels:
          severity: critical
        annotations:
          summary: "Low disk space on {{ $labels.instance }}"

      - alert: ServiceDown
        expr: up == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Service {{ $labels.job }} is down"

  - name: network
    rules:
      - alert: HighNetworkErrors
        expr: rate(node_network_receive_errs_total[5m]) + rate(node_network_transmit_errs_total[5m]) > 10
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Network errors on {{ $labels.instance }}"

Notification Channels

Email (SMTP)

# alertmanager.yml
route:
  receiver: 'email'
  group_by: ['alertname']
  group_wait: 30s
  group_interval: 5m

receivers:
  - name: 'email'
    email_configs:
      - to: '[email protected]'
        from: '[email protected]'
        smarthost: 'smtp.example.com:587'

Telegram Bot

  - name: 'telegram'
    telegram_configs:
      - bot_token: 'YOUR_BOT_TOKEN'
        chat_id: YOUR_CHAT_ID
        message_format: 'html'

Discord Webhook

  - name: 'discord'
    discord_configs:
      - webhook_url: 'https://discord.com/api/webhooks/...'
        send_resolved: true

Advanced: NetFlow Analysis

For deeper network visibility, collect NetFlow/sFlow data:

# Install nfdump
sudo apt install nfdump

# Configure your router to send NetFlow to your server
# Then export to Prometheus
nfcapd -p /var/nfdump -l -T -L 4h

Maintenance

Task Frequency
Check Prometheus health Daily
Verify alerts firing Weekly
Review disk usage Weekly
Update dashboards As needed
Rotate Grafana passwords Monthly
Review alert noise Weekly

Budget

Component Cost
All software Free (open source)
Raspberry Pi 4 (2GB) $50
USB drive (32GB) $10
Total ~$60

The Raspberry Pi can comfortably handle Prometheus + Grafana + a handful of exporters for a home network.


This post was generated with AI assistance. Review and customize it to match your experience.