ObservabilityLVIII · Proxmox ObservabilityProxmoxObs
Proxmox APIs and Metrics
What you'll learn
- Describe the Proxmox REST API surface (/api2/json) and what each endpoint group returns for monitoring
- Configure a least-privilege API user, issue an API token, and propagate the secret to an exporter without leaking it
- Distinguish ticket, token, and user authentication and choose the right model for a long-lived monitoring integration
- Identify the API rate-limit and concurrency constraints and explain their impact on a scraping exporter
- Diagnose the most common API authentication failure modes from observable symptoms
Prerequisites
Verified against Prometheus 2.55.x · Alertmanager 0.28.x · node_exporter 1.8.x · blackbox_exporter 0.26.x · Grafana 11.x · Loki 3.x · Tempo current · OpenTelemetry Collector 0.110.x · Grafana Alloy current · Docker Engine 28.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-13
A Grafana panel reads “VM 104 CPU at 99%” but the VM is not slow. The metric is from the host that runs the VM, not the VM itself; the host’s pvestatd counter has drifted after a memory balloon event. The engineer clicks through to the same answer three different ways and gets three different numbers. That ambiguity is what the Proxmox REST API exists to remove - one authoritative surface for cluster, node, VM, storage, and backup state - and what observability for Proxmox requires you to master.
This lesson establishes the API. It covers the REST surface
(/api2/json), the pvesh CLI that wraps it, the three credential models
(ticket, token, user) and which one a monitoring integration should
choose, the rate limits you only discover at 03:00, and the failure modes
that take a metrics pipeline offline silently.
What it is
The Proxmox VE API is a JSON-over-HTTPS interface served by pveproxy
(the per-node HTTP frontend) and pvedaemon (the per-node privileged
daemon). The URL prefix is /api2/json, and the authoritative endpoint
catalog lives in the pvesh CLI and in the API viewer at
pve.proxmox.com. Every Proxmox GUI action calls the same API; the GUI is
a thin client that calls it.
Three surfaces matter for monitoring:
/api2/json/cluster/resources- aggregated cluster-wide resources. The endpoint every cluster-level exporter consumes./api2/json/nodes- per-node status, including CPU, memory, storage, and the corosync membership state./api2/json/access/usersand/access/domains- identity and authentication surface; the API is where tokens live.
The APIs are documented per-form. A path that is not in the catalog returns HTTP 501.
Why a sysadmin cares
Without the API, Proxmox observability reduces to SSH-per-node plus
pvestatd scraping. That approach makes cluster-wide questions hard:
total VMs across a 12-node cluster, the storage used per datastore, the
backup health across all VMs. The API is the canonical answer to “what
does the cluster look like right now”, and a metrics exporter is just a
polling loop over it.
The security and operational price of using it badly is high. A token issued with the wrong role gives the exporter permission to migrate VMs or delete containers. A token left unrevoked after a decommissioned exporter remains a valid credential until expiry. A scraper that exceeds the rate-limit starts returning HTTP 595 responses, the metrics pipeline shows gaps, and the on-call engineer has no panel to look at during the incident.
How it works
The mental model has four moving parts: the API protocol, the authentication model, the rate-limit, and the per-node proxy.
HTTP client pveproxy
(exporter, pvesh, (per-node TLS
curl, Proxmox GUI) + auth + ACL)
| |
| HTTPS POST /api2/json/... |
+--------------------------------------->|
| |
| ticket OR token |
| in Authorization header |
| |
| +-- pvedaemon (privileged,
| | talks to kernel, qemu,
| | LVM, ZFS, Ceph)
| |
| 200 OK (JSON) |
+<---------------------------------------+
|
poll loop (15s scrape typically)
pveproxy is a Perl daemon that terminates TLS, validates the
credential, applies the ACL, and forwards to pvedaemon over a local
Unix socket. pvedaemon does the privileged work (snapshot, migrate,
start VM). Both daemons run per node; the cluster API
/api2/json/cluster/... is satisfied by the proxy on whichever node the
request lands at, which reads the shared cluster filesystem (pmxcfs)
for cluster-wide state.
Under the hood
The rate limit is undocumented but real. Proxmox applies a per-source-IP
cap on the API daemon; sustained high call rates return HTTP 595 with
the message “rate limit exceeded”. The cap is generous for human use (a
GUI user issues a few calls per minute) and sharp for an exporter that
polls every node, every VM, every storage, every task, every 15
seconds. A naive exporter that requests
/cluster/resources?full=1 on every scrape will trip the cap inside a
busy cluster.
How to configure it
Create a dedicated user and token for the monitoring exporter. Use
pveum (the user-manager CLI) so the change is auditable in
/etc/pve/user.cfg.
# SEVERITY: CONFIGURATION (writes user.cfg; no service restart)
# Realms assume the default pam authentication.
pveum useradd monitoring-pve@pam --comment 'Prometheus exporter'
Grant the user a role that matches what the exporter calls. The default
PVEAuditor role is the minimum that exposes the read paths the
exporter needs.
# SEVERITY: CONFIGURATION
pveum aclmod / --user monitoring-pve@pam --role PVEAuditor
Issue an API token. Tokens do not need a password; the secret is displayed once at creation.
# SEVERITY: CONFIGURATION
# Output line: "│ full token id: monitoring-pve@pam!prometheus"
# Output line: "│ value: 1a2b3c4d-..."
# Capture the value; it cannot be retrieved later.
pveum tokenadd monitoring-pve@pam prometheus \
--comment 'pve-exporter token'
Propagate the token to the exporter using whatever secrets manager the rest of your stack uses. Never commit the secret to git.
Validate from the exporter host before pointing the scraper at it:
# SEVERITY: READ-ONLY
curl -sk -H "Authorization: PVEAPIToken=monitoring-pve@pam!prometheus=$TOKEN" \
https://pve.example.lan:8006/api2/json/cluster/resources | jq '.data[0]'
Expected output is a JSON object with fields type, id, node,
status, cpu, mem, maxmem, disk, maxdisk, uptime. The
presence of these fields proves the token is valid, the role is
sufficient, and the cluster is reachable from the exporter host.
How to validate it
Beyond the curl above, the export-side validation is the same as for every Proxmox API integration:
# SEVERITY: READ-ONLY
# Confirm the user still exists and the role is unchanged.
pveum userlist
pveum acllist --user monitoring-pve@pam
# SEVERITY: READ-ONLY
# Time the call. Healthy pveproxy + pvedaemon respond in < 50 ms for
# cluster/resources on a 12-node cluster. Sustained calls over 200 ms
# indicate pveproxy is contending for the per-process accept queue.
time curl -sk -H "Authorization: PVEAPIToken=..." \
https://pve.example.lan:8006/api2/json/cluster/resources
# SEVERITY: READ-ONLY
# Verify each node answers. A partial cluster response (one node
# missing) indicates a corosync split, not an API failure.
for N in pve-01 pve-02 pve-03; do
curl -sk -o /dev/null -w "%{http_code} %{time_total}s $N\n" \
-H "Authorization: PVEAPIToken=..." \
"https://$N.example.lan:8006/api2/json/nodes/$N/status"
done
# SEVERITY: READ-ONLY
# Confirm pvestatd is publishing values on every node. The agent
# populates the RRD files that back many of the metrics the exporter
# reports; without it, per-VM metrics read zero.
systemctl status pvestatd
ls -l /var/lib/rrdcached/db/ | head
How it can fail
Five failure modes appear repeatedly in production:
- Token deleted from the GUI. A colleague removed the token while cleaning up credentials. Symptom: HTTP 401 from every API call; exporter logs fill with auth errors; every cluster-level metric series disappears at the same timestamp.
- Role downgraded.
pveum aclmod / --role PVENoAccess(a common mis-type) silences the exporter silently. Symptom: HTTP 200 responses with empty arrays; dashboards show “no data” but no errors. - Token secret leaked into a config file. The exporter’s YAML is world-readable or committed to a public mirror. Symptom: nothing visible until the metrics show clusters you never owned; the token must be revoked and rotated.
- Rate-limit hit. The exporter polls too aggressively for a busy cluster. Symptom: HTTP 595 responses from pveproxy; random gaps in metric series; the exporter retries and compounds the load.
- pveproxy stuck. A long-running TLS connection in CLOSE_WAIT
state exhausts the accept queue. Symptom: every new request hangs;
established connections still return data; restart of
pveproxyclears the queue.
How to troubleshoot it
The order is: token, role, network, rate-limit, daemons.
- Token.
pveum userlistshows the user;pveum tokenlist monitoring-pve@pamshows attached tokens. If the token is gone, recreate it. - Role.
pveum acllist --user monitoring-pve@pamshows the ACL. The expected rule is/(ACL) PVEAuditor. If empty or wrong, runpveum aclmod / --user ... --role PVEAuditor. - Network. From the exporter host,
openssl s_client -connect pve:8006confirms TLS.tcpdump -i any host pve and port 8006on the exporter host shows whether packets leave. - Rate-limit.
journalctl -u pveproxy -n 200for the “rate limit exceeded” string. If present, raise the scrape interval or reduce the modules the exporter pulls. - Daemons.
systemctl status pveproxy pvedaemonon every node. A daemon crash is visible injournalctl -u pvedaemon -n 200. Restart withsystemctl restart pveproxy; pvedaemon restart affects VM operation, not just metrics.
Security implications
Three rules apply:
- Token scope equals exporter scope. The token’s role must match
what the exporter reads.
PVEAuditoris sufficient for every pve-exporter metric;PVEAdminis not. Issuance is cheap viapveum, and the audit log records who created the role. - Treat the secret as a credential. Rotate on personnel change, on suspect compromise, and at the cadence your compliance regime requires. The pve-exporter reads the secret from the environment; no file should be world-readable.
- Restrict the API surface.
pveproxylistens on the internal network by default. A reverse proxy that faces the public internet must terminate TLS, validate the source IP, and apply WAF rules that reject credential-stuffing patterns.
Performance implications
The Proxmox API is not a database; it is a request-response daemon that
serialises work through pvedaemon. Two constraints matter:
- Concurrency limit per node. pvedaemon is single-threaded per
node; a slow API call blocks the daemon. Long-running endpoints
(
/nodes/{node}/vzdump,/cluster/backup/{id}) compete with read calls. - Scrape interval cost. A pve-exporter scrape that pulls
/cluster/resources?full=1,/nodes,/storage, and per-VM/status/currentis 1 + N + M + V*x API calls. For twelve nodes, four storage pools, and 200 VMs, that is hundreds of calls per scrape. At a 15-second interval this is the difference between stable and saturated.
Mitigations:
- Use
?full=0for the metrics exporter;full=1adds guest network and disk details the exporter does not need. - Raise the scrape interval to 30s or 60s for the cluster exporter; cluster state changes on a human time-scale.
- Disable exporter modules per cluster if a dashboard does not consume them.
Production guidance
- Treat the token like a database password. Vault, sealed secrets, or a least-readable file. Rotate quarterly.
- Use
pveum useraddandpveum aclmod. The GUI looks the same but the audit trail is weaker. - Run a single exporter per cluster, not per node. The API returns cluster-wide data.
- Alert on exporter
up == 0, not on the rate of HTTP 5xx. The scrape failure is the symptom; the upstream exporter being down is the cause. - For very large clusters, prefer
prometheus-pve-exporterwith module filtering, and split the cluster into groups of nodes scraped by independent exporters.
Verification
You should now be able to answer:
- What are the three credential models Proxmox exposes, and which should a monitoring integration use?
- What is the relationship between
pveproxy,pvedaemon, and the/api2/jsonURL prefix? - What is the rate-limit symptom, and what exporter behaviour produces it?
- What is the right user-role combination for a metrics-only exporter?
Quiz
Knowledge check · 8 questions
Q1. Which URL prefix does the Proxmox VE API expose?
Q2. Which credential model is the right choice for a long-lived monitoring exporter?
Q3. PVEAuditor is the minimum role that satisfies a read-only pve-exporter token.
Q4. Which failure modes present as either 401 Unauthorized or empty arrays with HTTP 200 from the exporter?
Q5. Name the per-node daemon that terminates HTTPS and applies ACL for the Proxmox API.
Q6. Which HTTP status code does pveproxy return when the per-source rate-limit is exceeded?
Q7. Treating the API token secret like a database password requires rotation on personnel change.
Q8. Right first step when the exporter starts returning empty arrays with HTTP 200?
Passing score: 75%. Answers are checked in this browser.