Post
1Password is interfering with code blocks. Disable it for this site to fix code block formatting. Learn How

Building Enterprise-Style UniFi Observability with Unpoller, Prometheus, and Grafana

Building Enterprise-Style UniFi Observability with Unpoller, Prometheus, and Grafana

If you run a UniFi network in a homelab or small environment, there’s a point where basic status pages stop being enough. You want to understand how your network behaves over time - what normal looks like, what’s changing, and how those changes correlate with real issues.

This post walks through building an enterprise-style observability stack for UniFi using Unpoller, Prometheus, and Grafana, in a way that’s repeatable, approachable, and easy to run in a homelab.

The goal is not just better charts, but better understanding - and hands-on experience with tooling that’s widely used in production environments.

Watch the video


What We’re Building

At a high level, we’re collecting metrics from UniFi devices and making them available for long-term analysis and visualization.

Data flow: UniFi Devices → Unpoller → Prometheus → Grafana

  • UniFi devices expose metrics via the UniFi Network API
  • Unpoller collects those metrics and exposes them in Prometheus format
  • Prometheus scrapes and stores metrics over time
  • Grafana visualizes the data using dashboards

This pattern - exporter, time-series storage, visualization - is extremely common in enterprise environments, and it scales down very nicely to a homelab.


Why Observability Matters

Point-in-time status is useful, but it only tells you what’s happening right now. Observability gives you:

  • Historical trends
  • Baselines for what “normal” looks like
  • Better troubleshooting context
  • Capacity planning insight

Instead of guessing, you can correlate behavior over hours, days, or weeks.


Docker Compose Stack

Everything is deployed using a single Docker Compose stack with all services preconfigured and wired together.

🔗 Complete configuration and files available on GitHub

Services Included

  • Prometheus – metrics storage
  • Grafana – visualization
  • Unpoller – UniFi metrics collector
  • Dozzle (optional) – lightweight container log viewer

Docker Compose File

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
services:
  prometheus:
    image: prom/prometheus:latest
    restart: unless-stopped
    container_name: prometheus
    user: "${UID:-1000}:${GID:-1000}"
    env_file:
      - ./prometheus/.env
    ports:
      - '9090:9090'
    volumes:
      - ./prometheus/config:/etc/prometheus
      - ./prometheus/data:/prometheus

  grafana:
    image: grafana/grafana:latest
    restart: unless-stopped
    container_name: grafana
    user: "${UID:-1000}:${GID:-1000}"
    env_file:
      - ./grafana/.env
    ports:
      - '3000:3000'
    volumes:
      - ./grafana/data:/var/lib/grafana
      - ./grafana/provisioning/datasources:/etc/grafana/provisioning/datasources
      - ./grafana/provisioning/dashboards:/etc/grafana/provisioning/dashboards
    depends_on:
      - prometheus

  unpoller:
    image: ghcr.io/unpoller/unpoller:latest
    restart: unless-stopped
    container_name: unpoller
    env_file:
      - ./unpoller/.env
    ports:
      - '9130:9130'

  dozzle:
    image: amir20/dozzle:latest
    restart: unless-stopped
    container_name: dozzle
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./dozzle/data:/data
    env_file:
      - ./dozzle/.env
    ports:
      - '8080:8080'

All containers run as the same UID/GID as the host user, allowing Docker to create bind-mounted directories automatically in most homelab setups.

Unpoller Configuration

Unpoller is configured via environment variables. You do not need to tune every option to get started.

Note: All pre-configured .env files for every service are included in the GitHub repository. You only need to update the UniFi controller details and credentials.

Complete Unpoller Configuration

Here’s the complete unpoller/.env file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
UP_INFLUXDB_DISABLE=true
UP_POLLER_DEBUG=false
UP_UNIFI_DYNAMIC=false
UP_PROMETHEUS_HTTP_LISTEN=0.0.0.0:9130
UP_PROMETHEUS_NAMESPACE=unpoller
UP_UNIFI_CONTROLLER_0_VERIFY_SSL=false
UP_UNIFI_CONTROLLER_0_SAVE_ALARMS=true
UP_UNIFI_CONTROLLER_0_SAVE_ANOMALIES=true
UP_UNIFI_CONTROLLER_0_SAVE_EVENTS=true
UP_UNIFI_CONTROLLER_0_SAVE_IDS=true
UP_UNIFI_CONTROLLER_0_SAVE_SITES=true
UP_UNIFI_CONTROLLER_0_VERIFY_SSL=false
UP_UNIFI_CONTROLLER_0_SAVE_DPI=false

UP_UNIFI_CONTROLLER_0_URL=https://192.168.10.1 # change to your Unifi Controller URL
UP_UNIFI_CONTROLLER_0_USER=unpoller # change to your Unifi Controller username
UP_UNIFI_CONTROLLER_0_PASS=password123 # change to your Unifi Controller password
UP_UNIFI_CONTROLLER_0_SITE=default # this is usually 'default', change if needed
TZ=America/Chicago # change to your timezone

The required settings you must update are:

  • UP_UNIFI_CONTROLLER_0_URL - Your UniFi controller address
  • UP_UNIFI_CONTROLLER_0_USER - UniFi username
  • UP_UNIFI_CONTROLLER_0_PASS - UniFi password
  • UP_UNIFI_CONTROLLER_0_SITE - Usually “default”

UniFi User Requirement

Unpoller authenticates to UniFi using a standard UniFi account.

  • Create a dedicated local UniFi account that has read-only access to your Network controller
  • Read-only permissions are sufficient
  • Use these credentials in the Unpoller .env file

If authentication fails, this is the first thing to double-check.

Prometheus Metrics Endpoint

The Prometheus metrics endpoint is configured in the complete .env file above and exposes metrics at /metrics that Prometheus will scrape.

Prometheus Scrape Configuration

Prometheus needs to be told where Unpoller is running.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
global:
  scrape_interval: 15s
  evaluation_interval: 15s

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

  - job_name: 'unpoller'
    static_configs:
      - targets: ['unpoller:9130']
    scrape_interval: 30s
    scrape_timeout: 10s

The key line is:

1
targets: ['unpoller:9130']

This uses the Docker Compose service name, so no IP management is required.

If dashboards are empty, this is one of the first places to check.

Starting the Stack

With everything configured, bring the stack up:

1
docker compose up -d

Access

Grafana default login: admin/admin123 (change in grafana/.env)

Grafana Provisioning

Grafana is fully provisioned using files on disk.

  • Datasources are defined via provisioning
  • Dashboards are loaded automatically on startup
  • No manual imports required

Note: All Grafana datasources and dashboards are included in the GitHub repository under the grafana/ directory.

This approach is repeatable, versionable, and aligns with how Grafana is typically managed in production.

Dashboards and What They Enable

The stack includes pre-configured Grafana dashboards for comprehensive UniFi network monitoring:

  • Access Points - Client counts, radio utilization, 2.4/5/6 GHz visibility
  • Switches - Port utilization, throughput, and performance metrics
  • Gateway - WAN performance, throughput, and edge behavior
  • Clients - Connection history, device behavior, and usage patterns
  • DPI - Deep packet inspection and traffic insights (requires gateway support)
  • Sites - Multi-site overview and comparison
  • PDU - Power distribution unit metrics (hardware-dependent)

Access Points

The Access Points dashboard is usually the best place to start:

  • Client counts over time
  • Radio utilization
  • 2.4, 5, and 6 GHz visibility

This makes it much easier to understand load distribution, interference, and capacity issues.

Clients, Switches, and Gateways

Additional dashboards:

  • Client connection history and behavior
  • Switch throughput and port utilization
  • Gateway performance and WAN behavior

The real value comes from being able to correlate changes over time rather than relying on snapshots.

Bonus Dashboards

Several additional dashboards are included but not required for day-one value:

  • Gateway - throughput, latency, edge behavior
  • PDU - power usage and device state (hardware-dependent)
  • DPI - traffic insights (depends on gateway support and configuration)

For example, the DPI dashboard will populate automatically if DPI is enabled and supported by your gateway. Not every UniFi deployment will expose every metric - that’s expected.

Troubleshooting

If you run into issues, here are the most common solutions:

  • Check logs: docker compose logs [service-name] or use Dozzle at http://localhost:8080
  • Verify UniFi controller accessibility from Docker network
  • Ensure a local UniFi account has been created with read-only/view-only network controller access
  • For 429 errors, increase scrape interval in prometheus/config/prometheus.yml
  • If dashboards are empty, check the Prometheus scrape configuration

Summary

With this setup in place, you now have:

  • Long-term visibility into your UniFi network
  • Repeatable, file-based configuration
  • Enterprise-style tooling running at homelab scale
  • A solid foundation for alerts, customization, and deeper analysis

This approach removes much of the guesswork from monitoring and gives you both better insight and valuable hands-on experience.

Join the conversation


🤝 Support the channel and help keep this site ad-free

🛍️ Check out all merch: https://shop.technotim.live/

⚙️ See all the hardware I recommend at https://l.technotim.live/gear

This post is licensed under CC BY 4.0 by the author.