How to Monitor Proxmox with Grafana and Prometheus: A Beginner-Friendly Guide That Actually Helps
Learn how to monitor Proxmox with Prometheus and Grafana using a beginner-friendly setup with the Proxmox exporter, real commands, and troubleshooting steps.
Author
David Okonkwo
FTC disclosure: This article contains affiliate links. If you purchase through these links, we may earn a commission at no additional cost to you.
Key Takeaways
- Proxmox monitoring gets much easier when you split the stack into four parts: Proxmox API, exporter, Prometheus, and Grafana.
- The clean beginner path is to run Grafana, Prometheus, and the Proxmox exporter in Docker, then scrape your Proxmox node through a read-only API token.
- The
PVEAuditorrole is enough for metrics collection in most homelab setups. You do not need to give your monitoring stack broad admin access. - If Grafana shows no data, the problem is usually one of three things: the API token, the Prometheus scrape target, or the wrong datasource on the imported dashboard.
- Historical metrics matter because the Proxmox web UI is good at showing what is happening right now, but not always why the host was struggling six hours ago.
If you have ever watched a Proxmox node feel slow, then opened the web UI only to find everything looking vaguely normal, this guide is for you. That is one of the most frustrating homelab problems because the failure is real, but the evidence has already wandered off.
The good news is that Proxmox monitoring does not need to turn into a full observability side quest. We are going to build a small stack with Prometheus and Grafana that gives you real history for CPU, memory, disk, storage, and guest activity without making the setup feel like enterprise punishment.
Why this matters before you touch anything
The Proxmox dashboard is useful, but it is mostly a live window. That works for obvious failures. It is much less helpful when your backup window overlaps with storage IO spikes, a noisy VM starts chewing CPU at 3 a.m., or a node quietly runs hot for days before you notice.
This is where Prometheus and Grafana help. Think of Proxmox as the machine room, the exporter as the translator, Prometheus as the notebook, and Grafana as the control panel on the wall. Once those four pieces are talking to each other, you stop guessing.
If you are still building the rest of your Proxmox environment, my guides on Proxmox networking, Proxmox templates, and Proxmox cluster setup are a good next layer after this one.
What we are building
We will use:
- A read-only Proxmox monitoring user and API token
prometheus-pve-exporterto collect metrics from the Proxmox API- Prometheus to scrape and store those metrics
- Grafana to visualize everything with a Proxmox dashboard
This guide assumes you already have:
- a working Proxmox node or cluster
- Docker and Docker Compose on a Linux box or VM
- network access from that box to your Proxmox host on port
8006
You can run the monitoring stack on a dedicated VM, on a small Docker host, or on an existing observability box. For beginners, I prefer a separate VM because it keeps the moving parts easy to reason about.
What you will need
A few practical gear picks if you are building or expanding your setup:
- A low-power mini PC for running a dedicated monitoring VM or Docker host: Fanless N100 mini PC with 2.5GbE
- A UPS so Prometheus does not lose its short-term database every time your power flickers: APC Back-UPS 1500VA
- Fast storage for VM disks and local metrics retention: Samsung 990 EVO 2TB NVMe SSD
Do not overthink the hardware. Monitoring is one of those jobs that sounds fancy but is usually light. You are not training models here. You are collecting numbers and drawing graphs.
Step 1 - Create a read-only Proxmox monitoring user
Why this matters
This is the first place beginners often make an avoidable security mistake. It is tempting to point monitoring at your existing Proxmox admin account because it is already there. Please do not do that.
Monitoring should have read-only access. If the monitoring box gets compromised, you want the blast radius to be boring.
Create the user and token
SSH into one Proxmox node as root and create a dedicated user:
pveum user add prometheus@pve --comment "Prometheus metrics collector"
pveum aclmod / -user prometheus@pve -role PVEAuditor
pveum user token add prometheus@pve monitoring -privsep 0
That last command prints the token value once. Save it immediately in your password manager or a local secrets file that is not committed anywhere.
Your final credential set will look like this:
- User:
prometheus@pve - Token name:
monitoring - Token value:
your-long-token-value
Verify the idea, not just the command
The goal here is simple:
- the user has the
PVEAuditorrole - the permission path is
/ - the token exists and can read cluster information
If you are newer to Proxmox permissions, this is the same principle I recommend in my SSH hardening guide: give services only the access they need, then stop.
Step 2 - Create the monitoring stack files
Why this matters
Before you run containers, it helps to make the stack layout predictable. Otherwise, a week from now you will be staring at a folder called monitoring-final-v2-actual and wondering what past-you was trying to prove.
Create a working directory on your Docker host:
mkdir -p ~/proxmox-monitoring/prometheus
mkdir -p ~/proxmox-monitoring/grafana/provisioning/datasources
mkdir -p ~/proxmox-monitoring/pve
cd ~/proxmox-monitoring
Now create this docker-compose.yml file:
services:
pve-exporter:
image: prompve/prometheus-pve-exporter:latest
container_name: pve-exporter
restart: unless-stopped
ports:
- "127.0.0.1:9221:9221"
volumes:
- ./pve/pve.yml:/etc/prometheus/pve.yml:ro
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: unless-stopped
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus
- --web.enable-lifecycle
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
depends_on:
- pve-exporter
grafana:
image: grafana/grafana-oss:latest
container_name: grafana
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning/datasources:/etc/grafana/provisioning/datasources:ro
depends_on:
- prometheus
volumes:
prometheus_data:
grafana_data:
A couple of notes:
- I bind the exporter to
127.0.0.1:9221so it is not exposed to the whole LAN by default. - Prometheus and Grafana can be exposed to your LAN, but I still recommend putting them behind a reverse proxy later if you want remote access. If you need that piece, my Nginx Proxy Manager guide walks through the basics.
Step 3 - Configure the Proxmox exporter
Why this matters
The exporter is the translator between Prometheus and Proxmox. Prometheus cannot scrape the Proxmox API directly in the format Grafana expects for these dashboards. The exporter handles that translation for you.
Create ~/proxmox-monitoring/pve/pve.yml:
default:
user: prometheus@pve
token_name: monitoring
token_value: YOUR_LONG_TOKEN_VALUE
verify_ssl: false
Replace YOUR_LONG_TOKEN_VALUE with the actual token value from Step 1.
What could go wrong
If your Proxmox node uses a self-signed certificate, verify_ssl: false is usually the quickest beginner path. Long term, I prefer trusted certificates, but there is no point pretending every homelab starts there.
If you already use valid certificates, set this instead:
verify_ssl: true
Step 4 - Configure Prometheus scraping
Why this matters
Prometheus needs to know where metrics live, how often to collect them, and how to label them. This is where a lot of "Grafana shows nothing" problems actually start.
Create ~/proxmox-monitoring/prometheus/prometheus.yml:
global:
scrape_interval: 30s
evaluation_interval: 30s
scrape_configs:
- job_name: prometheus
static_configs:
- targets:
- localhost:9090
- job_name: pve
static_configs:
- targets:
- 192.168.1.10
metrics_path: /pve
params:
module: [default]
cluster: ['1']
node: ['1']
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: pve-exporter:9221
Replace 192.168.1.10 with the IP or hostname of your Proxmox node.
If you have a cluster, list each Proxmox node under targets:
- targets:
- 192.168.1.10
- 192.168.1.11
- 192.168.1.12
This configuration follows the exporter project pattern where Prometheus sends the Proxmox node as the target parameter and the exporter does the API call on its behalf.
Step 5 - Provision the Grafana datasource
Why this matters
You can add the datasource by hand in the UI. I still prefer provisioning it in a file because it makes rebuilds painless. If you redeploy the stack later, Grafana comes back with the datasource ready instead of making you click through the same screens again.
Create ~/proxmox-monitoring/grafana/provisioning/datasources/prometheus.yml:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: true
Step 6 - Start the stack
Why this matters
Now we move from configuration to proof. The point is not just to start containers. The point is to confirm each layer works before you pile the next layer on top.
Launch the stack:
cd ~/proxmox-monitoring
docker compose up -d
Check container status:
docker compose ps
Then follow the logs if something looks off:
docker compose logs -f pve-exporter
docker compose logs -f prometheus
docker compose logs -f grafana
Verify the exporter first
From the Docker host, test the exporter endpoint:
curl -s http://127.0.0.1:9221/metrics | head
You should see exporter self-metrics. Then test the Proxmox-backed endpoint through Prometheus later, but this quick check confirms the container is alive.
Verify Prometheus targets
Open Prometheus at http://YOUR-DOCKER-HOST:9090/targets.
You want to see the pve target as UP. If it is DOWN, do not move to Grafana yet. Fix the scrape first.
This step saves time because Grafana is just a mirror here. If Prometheus has nothing, Grafana will faithfully visualize nothing (which is a very honest failure mode, to be fair).
Step 7 - Import the Proxmox Grafana dashboard
Why this matters
Grafana without a dashboard is just a very polished blank page. The easiest starting point is the public Proxmox dashboard with ID 10347 from Grafana Labs.
Open Grafana at http://YOUR-DOCKER-HOST:3000.
Default login:
- Username:
admin - Password:
admin
Grafana will ask you to change the password on first login.
Then import dashboard ID 10347:
- Go to Dashboards
- Click New -> Import
- Enter
10347 - Choose the
Prometheusdatasource - Finish the import
That dashboard is a good beginner starting point because it covers:
- node CPU and memory
- storage allocation and usage
- guest CPU, memory, disk IO, and network IO
- historical trends that the Proxmox UI does not keep front and center
Step 8 - Check that the graphs mean something
Why this matters
A dashboard full of moving lines feels impressive, but the real question is whether it helps you catch useful problems. I like to do a quick sanity test right after setup.
Try one or two controlled changes:
# On a busy VM or container host
apt update
# Or generate a little disk activity on a test VM
fio --name=randread --rw=randread --bs=4k --size=256M --runtime=60 --time_based
Then watch whether:
- CPU changes on the correct node
- IO appears where you expect
- guest graphs line up with your test workload
If the graphs move in the wrong place, you probably have a target or instance-label mismatch.
Common mistakes
1. Using an admin account instead of a monitoring account
You do not need full admin rights for metrics. Use PVEAuditor and keep it boring.
2. Importing the dashboard before Prometheus targets are up
This wastes time. Always verify http://YOUR-HOST:9090/targets first.
3. Forgetting to replace the Proxmox target IP in prometheus.yml
I have seen people copy a config, stand up the stack, and then wonder why Grafana is still blank. It turns out they were scraping somebody else's example IP. Computers are ruthless about details.
4. Leaving the exporter open on all interfaces
Bind it to 127.0.0.1 unless you have a good reason not to. Metrics endpoints should not be casually exposed.
5. Blaming Grafana for a Prometheus problem
If Prometheus does not scrape the exporter successfully, Grafana cannot rescue the situation. Check the stack in this order:
- Proxmox token and permissions
- exporter container logs
- Prometheus target status
- Grafana datasource
- imported dashboard settings
Troubleshooting checklist
If the dashboard shows no data, walk through these checks in order:
# Is the exporter container running?
docker compose ps
# Does the exporter respond locally?
curl -s http://127.0.0.1:9221/metrics | head
# Can Prometheus see the config you expect?
docker compose exec prometheus cat /etc/prometheus/prometheus.yml
# Reload Prometheus after config changes if needed
curl -X POST http://localhost:9090/-/reload
Then confirm in the UI:
- Prometheus -> Status -> Targets ->
pveis UP - Grafana -> Connections -> Data sources ->
Prometheusis healthy - Imported dashboard is using the same datasource you configured
If you want a broader monitoring foundation after this, my article on homelab monitoring with Prometheus and Grafana expands the stack beyond Proxmox specifically. And if you are building Docker-based services next, these Docker Compose best practices will save you some future cleanup.
FAQ
Do I need to run Grafana and Prometheus on the Proxmox host itself?
No. In most homelabs, I prefer a separate VM or Docker host. It keeps the monitoring stack isolated and makes maintenance easier.
Can I use a password instead of an API token?
Yes, but I do not recommend it if token auth is available. Tokens are cleaner, easier to rotate, and generally a better habit.
Should I monitor every Proxmox node separately?
Yes. If you have multiple nodes, add each node as a target in Prometheus so you get complete node-level visibility.
What if my Proxmox node uses a self-signed certificate?
Use verify_ssl: false in pve.yml as the short-term fix. Long term, trusted certificates are the better answer.
Is this enough for alerting too?
It is enough to get started with visibility. Once the data is flowing, you can add Prometheus alert rules or an Alertmanager stack later.
What to learn next
Once you have Proxmox metrics working, the next useful improvements are:
- add node exporter on important Linux VMs for OS-level metrics
- monitor your backup jobs and storage pool health
- put Grafana behind HTTPS and SSO
- build a few simple alerts for disk exhaustion, host memory pressure, and guest downtime
For official references, keep these handy:
- prometheus-pve-exporter GitHub project
- Grafana dashboard 10347 for Proxmox via Prometheus
- Prometheus configuration documentation
If you came into this feeling overwhelmed by the terminology, that is normal. The trick is to stop treating monitoring like one giant product and start treating it like a small chain of jobs. Proxmox exposes data. The exporter translates it. Prometheus stores it. Grafana shows it. Once that clicks, the setup becomes much easier to manage.
And once you have historical graphs for your cluster, a whole category of weird homelab problems stops feeling mysterious. Which is nice, because the homelab will always invent new ways to be weird.
