This bundle gives you:
- A central Prometheus + Grafana stack you can deploy as a Portainer Stack on any one node.
- A lightweight node_exporter stack to deploy on each Tailscale node you want to monitor.
- All nodes are on the same Tailscale tailnet and can reach each other over Tailscale.
- (Recommended) MagicDNS enabled on your tailnet so containers can resolve
*.ts.nethostnames. - Portainer Agent/Edge Agent installed on each node (so you can push stacks remotely).
In Portainer, on each host:
- Stacks → Add stack → Upload
stack-node-exporter.yml→ Deploy stack. - If you want node_exporter to bind only to the Tailscale IP, edit the command flag:
--web.listen-address=100.x.y.z:9100and replace100.x.y.zwith that node's Tailscale IP. (Otherwise it listens on all interfaces; access is still limited by your Tailscale ACLs.)
On the node that will host Prometheus/Grafana:
- Stacks → Add stack → Upload
docker-compose.yml(in this folder). - Also upload
prometheus.ymland theprovisioning/folder in the same stack context so relative volume paths work. - Edit
prometheus.yml: replace the exampleREPLACE_ME_NODE_A/Btargets with either MagicDNS names likemyhost.ts.net:9100or literal Tailscale IPs like100.101.102.103:9100. - Deploy. Prometheus:
http://<host>:9090and Grafana:http://<host>:3000(admin/ChangeMeNow!).
In Grafana → Dashboards → Import:
- Paste 1860 ("Node Exporter Full") and select the Prometheus datasource.
On any host:
- Run cAdvisor (host network) and add it to
prometheus.ymlunder thecadvisorjob:docker run -d --name=cadvisor --net=host --pid=host --privileged gcr.io/cadvisor/cadvisor:v0.47.2
- If containers can't resolve
*.ts.net, either switch to static Tailscale IPs inprometheus.ymlor mount/etc/resolv.conffrom the host into the Prometheus container if the host already uses MagicDNS. - Tighten access with Tailscale ACLs so only your Prometheus host can hit nodes on port 9100.
- Long‑term retention: move Prometheus data to a bigger disk or a remote TSDB (e.g., Thanos) later.
Enjoy! ✨