This monitoring stack was planned and staged on 192.168.11.89 (Ubuntu server with Docker 29.1.4 and Docker Compose v5.0.1). All config files are already in place at /home/claudessh/monitoring/. The stack needs to be deployed and verified.
Add claudessh to the docker group (requires sudo/root):
sudo usermod -aG docker claudessh
Then logout/login or run newgrp docker for the group change to take effect.
Verify docker access:
docker ps
/home/claudessh/monitoring/
├── docker-compose.yml # Stack definition (4 containers)
├── prometheus/prometheus.yml # Scrape targets config
├── grafana/provisioning/datasources/prometheus.yml # Auto-provision Prometheus datasource
└── README.md # Operational reference
| Container | Image | Port | Purpose |
|---|---|---|---|
| prometheus | prom/prometheus:latest | 9090 | Metrics storage, 90 day retention |
| grafana | grafana/grafana:latest | 3000 | Dashboards (default login: admin/admin) |
| starlink-exporter | ghcr.io/danopstech/starlink_exporter:latest | 9817 | Polls Starlink gRPC |
| node-exporter | prom/node-exporter:latest | 9100 | Host system metrics |
The starlink-exporter connects to the Starlink dish gRPC API via a NAT port forward:
starlink-exporter container
→ 192.168.67.1:9200 (pfSense router, TUN_WG NAT port forward)
→ 192.168.100.1:9200 (Starlink dish gRPC, no auth required)
The container needs host network access to reach 192.168.67.1. If the bridge network cannot route to 192.168.67.1, change the starlink-exporter to use network_mode: host instead of the monitoring bridge network, and remove its networks: and ports: directives.
cd /home/claudessh/monitoring
# Pull images
docker compose pull
# Start all containers
docker compose up -d
# Verify all 4 containers are running
docker compose ps
docker compose ps
# All 4 should show "Up"
curl -s http://localhost:9817/metrics | grep starlink_dish_uptime
# Should return a metric line with a numeric value
If this returns empty, the exporter cannot reach 192.168.67.1:9200. Test connectivity:
docker exec starlink-exporter sh -c "wget -q -O- http://192.168.67.1:9200 2>&1 || echo 'cannot reach dish'"
If unreachable from the container, switch starlink-exporter to network_mode: host in docker-compose.yml.
curl -s http://localhost:9090/api/v1/targets | python3 -m json.tool | grep -A2 '"health"'
# All targets should show "up"
Or open http://192.168.11.89:9090/targets in a browser - all should be green.
Open http://192.168.11.89:3000 - should show login page. Login with admin/admin.
In Grafana:
If dashboard ID 18824 does not work or is outdated, search grafana.com/dashboards for "starlink" and try the most recent one compatible with the danopstech exporter.
# Check exporter logs
docker compose logs starlink-exporter
# Test gRPC connectivity from the host
python3 -c "
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
s.connect(('192.168.67.1', 9200))
print('gRPC port OPEN')
s.close()
"
# Check prometheus config is valid
docker exec prometheus promtool check config /etc/prometheus/prometheus.yml
# Check prometheus logs
docker compose logs prometheus | tail -20
The Docker bridge network may not have a route. Fix by changing starlink-exporter in docker-compose.yml:
starlink-exporter:
image: ghcr.io/danopstech/starlink_exporter:latest
container_name: starlink-exporter
restart: unless-stopped
network_mode: host # <-- replace networks/ports with this
environment:
- STARLINK_ADDRESS=192.168.67.1:9200
Then redeploy: docker compose up -d
starlink_dish_uptime_secondsThe prometheus.yml file has commented-out stubs for:
To add a new exporter:
docker compose up -d to deploy