PYLONMON

Proxmox monitoring: get an SMS when a VM stops

A Proxmox host will happily report 4% CPU, 30% memory and eleven days of uptime while one of its VMs has been powered off since Tuesday. The host isn’t lying — it is genuinely fine. It simply has no idea that the thing you actually cared about is gone. Here is how to close that gap in about five minutes, and how to make the alert reach you when you are nowhere near a screen.

The blind spot on every hypervisor

Proxmox knows its own state perfectly. Open the web UI and every guest, every storage pool and every node is right there. The catch is the one every dashboard has: it waits for you to come and look.

On a hypervisor that blind spot is worse than usual, because the obvious thing to monitor — the host — is the least likely thing to break. A VM that hit an out-of-memory condition and never came back. A container that quietly failed to start after a reboot. A ZFS pool creeping to 96%. None of those move the host’s CPU or memory at all, so host-level monitoring reports a healthy green straight through every one of them.

What you actually want to be told:

Why the usual answers do not fit a homelab

Proxmox can send email on certain events, but it is built around backup jobs and replication rather than “this VM is not running any more”, and it needs a working mail relay on the host. Plenty of home connections cannot send mail at all.

The other direction is a full monitoring stack: Prometheus, the PVE exporter, Alertmanager, Grafana. That genuinely works, and if you enjoy running it, run it. But it is four services, a database and a scrape target that has to stay reachable — a lot of machinery, and machinery that lives inside the same house that just lost power.

There is a smaller shape. One agent on the Proxmox host reads the cluster’s own inventory and pushes the numbers out over ordinary HTTPS. Nothing listens. Nothing is exposed. It works behind NAT and CGNAT, and because the watching happens off-site, it still works when the whole rack goes dark — which is precisely the moment a monitor living on that rack stops being able to tell you anything at all.

Step 1 — install the agent on the Proxmox host

Proxmox VE is Debian underneath, so this is the ordinary Linux install. SSH in as root:

root@pve1: ~
curl -fsSL https://pylonmon.com/beacon.sh | sh

It asks for an API key. Create an ingest-scoped one in the portal under Settings → Status page & API. An ingest key can push readings and nothing else — it cannot read your monitors or touch your account — so it is a safe thing to leave sitting on a box.

Install it on the host itself, not inside a VM. A guest cannot see its siblings.

Step 2 — two lines of config

Open /etc/pylon-beacon.conf and add a section:

/etc/pylon-beacon.conf
[proxmox]
enabled = true

Then systemctl restart pylon-beacon. That is the whole integration.

There is no API token to create, store or rotate. The agent already runs as root on the host, so it uses pvesh — the CLI Proxmox installs and authenticates for you, speaking the same API the web UI does. It behaves identically on a standalone host and on a cluster; a single node simply reports itself as a one-node cluster.

What starts arriving

Within one interval the node’s monitor carries the hypervisor’s inventory alongside its own vitals:

MetricWhat it tells you
pve_guests_stoppedevery non-template guest that is not running — the one most people alert on
pve_qemu_running · _stopped · _totalvirtual machines
pve_lxc_running · _stopped · _totalLXC containers
pve_storage_pctthe fullest storage, not an average
pve_nodes_online · _totalcluster members
pve_quorate1 with quorum, 0 without (clusters only)

Two deliberate details, because each is the difference between a monitor you keep and one you mute after a week.

Templates are never counted as stopped. A template’s status is “stopped” permanently — that is what a template is. Counting them would page you on day one for a machine doing precisely its job.

pve_storage_pct is the fullest pool, on purpose. Average a 96% pool together with three empty ones and you get a comfortable-looking number that hides the pool about to break your backups.

Step 3 — the rule that pages you

Open the node’s monitor and find Vital thresholds. The metric dropdown fills itself from what the node actually sent, so the pve_ metrics are already in the list — there is nothing to type:

Monitor → pve1 → Vital thresholds
pve_guests_stopped
>
0
if it lasts 5 min
pve_storage_pct
>
85
if it lasts 15 min

The sustained column is what keeps this liveable — a guest you reboot on purpose is back inside five minutes and never pages.

That last setting matters more than it looks. Without it, every deliberate reboot, every qm shutdown while you are working, every migration pages you — and a monitor that cries wolf during normal work gets muted, which is the same as not having one. “If it lasts 5 min” means a guest you stopped yourself stays silent, and a guest that died does not.

Vital thresholds are on every plan, including free. Alerting on your own numbers is the agent’s entire job, not a paywall.

Step 4 — Discord now, a text if nobody looks

Getting the alert is half of it. The other half is that a Discord message at 2 AM is a message nobody reads until 8. That is what the escalation ladder is for: alert cheaply first, and escalate only if the problem is still there.

Monitor → pve1 → Escalation ladder
#homelabdiscordfirst alert, immediately
if still down after 15 minemailnotify: ops@
if still down after 30 minsmskeep paging every 30 min until it recovers

Read that as a sentence: tell the Discord channel straight away; if it is still broken a quarter of an hour later, send email; if it is still broken after half an hour, wake me up. A VM you restarted yourself never reaches step one. A VM that actually died reaches step two, and your phone buzzes.

You can also attach a step note to a rung — a runbook link, or just “check the ZFS pool before restarting” — so the 3 AM version of you receives an instruction rather than a puzzle.

What the alert actually says

Because the agent sends the names of the stopped guests along with the count, the page tells you what to go and start:

SMS — 02:14
PylonMon: pve1 vital breach
pve_guests_stopped = 2 (limit > 0)

vm/102 db-01 on pve1
ct/201 mail on pve1

“2 guests stopped” is a puzzle you solve by opening a laptop. db-01 and mail is something you can act on from the bedside table.

What this costs, honestly

Everything up to step 3 works on the free plan. The ladder in step 4 does not, and it is worth being straight about why:

FreePro — $4/mo
Monitors2075
Alert channels110
SMS per month010
Vital thresholdsyesyes
Escalation ladderyesyes

The ladder itself is free on every plan. But a ladder with one rung is not a ladder, and the free plan gives you one alert channel — so “Discord, then email, then SMS” is arithmetically impossible on it. Text messages also cost real money per message, which is why they come with an allowance rather than being unlimited.

So the honest line is this: if you want to know your homelab is healthy, free covers it completely and always will. If you want to be woken up when it is not, that is the $4 tier. The same line applies whether you run one Proxmox host or six.

Want per-VM detail? Keep the paging here

Worth saying plainly, so nobody installs this expecting something else. The [proxmox] section reports the cluster in aggregate: how many guests are running, how many are not, and which ones are down. It is not a per-VM inventory — no monitor per guest, no per-VM CPU curve, no backup-job history.

If you want that depth, you do not have to choose. Run Prometheus for the graphs and the per-VM rules, and then point Prometheus straight at PylonMon for the alerting — PylonMon implements the Alertmanager v2 API, so Prometheus posts alerts to it natively. You keep the dashboards, and you delete Alertmanager.

The whole integration is one block in prometheus.yml:

prometheus.yml
alerting:
  alertmanagers:
    - scheme: https
      authorization:
        type: Bearer
        credentials_file: /etc/prometheus/pylonmon.key
      static_configs:
        - targets: ["pylonmon.com"]

Prometheus appends /api/v2/alerts itself. No Alertmanager container, no routing tree, no silences file.

Every firing rule then arrives as a monitor here and inherits everything this post already set up: the escalation ladder, the step notes, the SMS rung. Your ProxmoxVMDown rule with a per-guest label pages exactly like pve_guests_stopped does — same ladder, same phone.

The Prometheus section of the docs covers all three modes (we pull a metric, you push one, or you send us alerts), and there is a complete worked example — docker-compose, prometheus.yml and a rules.yml you can copy — in the examples/prometheus-to-pylonmon directory of the repo. Alert ingest is a paid feature: 25 alert streams on Pro, 200 on Team.

So the honest division of labour: Prometheus is very good at remembering what happened, and this is built to answer the question a dashboard structurally cannot — is anything wrong right now, and is it wrong enough to wake someone up.

Five minutes, start to finish

  1. Install the agent on the Proxmox host — one command.
  2. Add the [proxmox] section, set enabled = true, restart it.
  3. Add a rule: pve_guests_stopped above 0, sustained 5 minutes.
  4. Add a second: pve_storage_pct above 85, sustained 15 minutes.
  5. Build the ladder: Discord now, email at 15 minutes, SMS at 30.

Nothing listens on your network. Nothing is exposed. And the thing doing the watching is somewhere else entirely — so when the rack loses power at 2 AM, the silence itself is the alert.

Monitor your Proxmox host — free →   or read the pylon-beacon overview and the Prometheus integration docs.