Node Exporter + pve-exporter for Proxmox Metrics
Install prometheus-node-exporter on every Proxmox node and prometheus-pve-exporter with a read-only API token — the two endpoints Prometheus needs for full host and cluster metrics.
Distrosproxmox, debian
Shell
bashUpdated
Script
# ── Run on each Proxmox node. Placeholder: <TOKEN-SECRET> is printed
# ── by the pveum command in step 2 — copy it into pve.yml.
# ── Full stack walkthrough: /blog/node-exporter-grafana-proxmox/
# 1. Host metrics — Debian's packaged node exporter (port 9100)
apt update && apt install -y prometheus-node-exporter
systemctl enable --now prometheus-node-exporter
# 2. Read-only API user + token for the PVE exporter
pveum user add pve-exporter@pve --comment "Prometheus PVE exporter"
pveum acl modify / --users pve-exporter@pve --roles PVEAuditor
pveum user token add pve-exporter@pve monitoring --privsep 0
# ^ COPY the printed token secret now — it is shown only once
# 3. Install prometheus-pve-exporter (isolated via pipx)
apt install -y pipx
PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install prometheus-pve-exporter
# 4. Exporter config — paste the token secret from step 2
mkdir -p /etc/prometheus
cat > /etc/prometheus/pve.yml <<'EOF'
default:
user: pve-exporter@pve
token_name: monitoring
token_value: <TOKEN-SECRET>
verify_ssl: false
EOF
chmod 600 /etc/prometheus/pve.yml
# 5. Run it as a service (port 9221)
cat > /etc/systemd/system/pve-exporter.service <<'EOF'
[Unit]
Description=Prometheus Proxmox VE exporter
After=network.target
[Service]
ExecStart=/usr/local/bin/pve_exporter --config.file /etc/prometheus/pve.yml
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now pve-exporter
# 6. Smoke test both endpoints
curl -s localhost:9100/metrics | head -3
curl -s "localhost:9221/pve?target=localhost" | head -3
Prerequisites
- Proxmox VE 8.x/9.x node(s), root shell
- A Prometheus server to scrape the endpoints (the full stack guide)
Prometheus scrape config
Add both jobs on your Prometheus server — substitute your node addresses
(10.0.0.x are placeholders):
- job_name: node
static_configs:
- targets: ['10.0.0.11:9100', '10.0.0.12:9100']
- job_name: pve
static_configs:
- targets: ['10.0.0.11']
metrics_path: /pve
params:
module: [default]
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 10.0.0.11:9221
Notes
PVEAuditoris read-only — the exporter can see everything and change nothing--privsep 0gives the token the user’s full (audit-only) permissions- One pve-exporter per cluster is enough (it reads cluster-wide state); node-exporter goes on every node
- Dashboards and the reasoning behind each piece: the companion guide