Proxmox VEXXII · Operating as a Business ServiceBusiness of the platform
On-call, escalation and handover
What you'll learn
- Size a rota honestly for a small team and name what breaks below the minimum
- Define page-worthy conditions for a Proxmox cluster, and demote everything else
- Build an escalation path that has been tested rather than documented
- Write a handover that records temporary cluster state, which is what actually gets lost
Prerequisites
Verified against Proxmox VE 9.2.4 · Proxmox Backup Server 4.2.5 · Ceph Squid / Tentacle · Debian 13 (Trixie) · Linux kernel 7.0 (PVE 9.2 default) · 2026-08-12
Most Proxmox estates are run by between two and six people. That is too few for a comfortable rota and more than enough to run the platform well, and the tension between those two facts is what this lesson is about.
The parts that go wrong are predictable: a rota that quietly requires somebody to be available every other week forever, a pager that fires for things nobody can act on at 03:00, an escalation path that has never been dialled, and a handover that says “quiet night” while leaving four temporary settings in place that nobody else knows about.
Rota arithmetic
Start with the honest numbers, because the conversation about resourcing goes much better with them than without.
| Team size | Rotation | What it actually means |
|---|---|---|
| 1 | 1-in-1 | Not a rota. One person is permanently on call, including during illness and holiday |
| 2 | 1-in-2 | Every other week, indefinitely. Sustainable for a few months, then one of them leaves |
| 3 | 1-in-3 | The realistic minimum for primary-only cover. Collapses to 1-in-2 whenever anyone is away |
| 4 | 1-in-4 | Workable primary rota with room for holiday |
| 6 | 1-in-6 primary, 1-in-6 secondary | Comfortable, with a genuine secondary tier |
What earns a page
The single largest determinant of whether a rota is survivable is the number of pages per shift. Everything else is secondary.
The test for whether something should page is not “is it important”. It is: is there an action a human can usefully take right now, and does waiting until morning make it materially worse? Two yeses is a page. Anything else is a ticket.
| Condition | Page | Reasoning |
|---|---|---|
| A Tier-0 service is unreachable from outside | Yes | Users are affected now |
| Cluster has lost quorum | Yes | Nothing can be changed and HA cannot act |
Ceph OSD_FULL or PG_AVAILABILITY | Yes | Writes are blocked or blocking |
Ceph OSD_BACKFILLFULL | Yes | The cluster can no longer heal itself |
| Second OSD down in the same failure domain | Yes | The next one is data loss |
| PBS datastore above 90% | Yes | Prune and GC need space, and they are about to fail |
| A node fenced and HA recovered the guests | Yes, informational | The event resolved itself; somebody must still know a node is down |
| Backup job failed for a Tier-0 guest | Yes | The restore window is closing |
| Single OSD down, cluster healing normally | No — ticket | Ceph is handling it; a human adds nothing at 03:00 |
Ceph OSD_NEARFULL | No — ticket with a deadline | Days of runway |
| A node reboot completed as scheduled | No | It was expected |
PG_NOT_DEEP_SCRUBBED | No — ticket | Weeks of runway |
| Backup job failed for a Tier-3 guest | No — morning report | Nothing degrades overnight |
| CPU above 80% on a node | No | Not actionable and usually not a problem |
| Any warning-level notification | No | This is how pagers become noise |
Escalation that has been tested
An escalation path is a list of people and a rule for when to move down it. The list is easy. The two things that make it work are harder.
Every entry has a tested contact method. Not “he’s in the directory”. A number that was dialled during a drill, by someone who was not the person who wrote the document.
Each step has a trigger, not a feeling. “Escalate if you are stuck” is not a trigger, because the people most likely to need escalation are the least likely to judge that they are stuck.
| Step | Trigger | Who |
|---|---|---|
| Primary responds | Page fires | On-call engineer |
| Secondary | Primary has not acknowledged within 10 minutes, or primary asks | Second engineer on the rota |
| Engineering lead | 30 minutes with no path to resolution, or a decision is needed that costs money or data | Named individual |
| Vendor support | The problem is in Proxmox itself, or a supported hardware component | Proxmox support portal, hardware vendor |
| Business communication | Any incident lasting more than 30 minutes on a Tier-0 service | Named business contact |
The handover, and the part everybody omits
A handover is usually written as a summary of what happened. That is the least useful part, because what happened is in the ticket system.
What is not recorded anywhere else is temporary state: the settings somebody changed to get through an incident and intends to change back. Proxmox and Ceph are generous with these, and neither will remind you.
set -euo pipefail
echo '=== Ceph flags (expect none set outside a maintenance window)'
ceph osd stat 2>/dev/null || echo 'not a Ceph cluster'
ceph health detail 2>/dev/null | head -20 || true
echo '--- muted health checks, with their expiry'
ceph health mute ls 2>/dev/null || true
echo
echo '=== HA: services not in the started state, and nodes in maintenance'
ha-manager config
ha-manager status
echo
echo '=== Quorum: expected votes should match the node count'
pvecm status | grep -E 'Expected votes|Total votes|Quorate'
echo
echo '=== Backup jobs: any disabled?'
pvesh get /cluster/backup --output-format yaml | grep -E 'id:|enabled:|comment:'
echo
echo '=== Notification matchers: any disabled?'
pvesh get /cluster/notifications/matchers --output-format yaml
echo
echo '=== Replication jobs: any disabled or failing?'
pvesr listA handover that is worth reading
Five sections. Short is fine; complete is not optional.
1. Temporary state. The output of the sweep above, plus a line per item: what, why, who owns it, when it must be cleared. If this section is empty, say “none” explicitly — a blank section is ambiguous and an explicit “none” is a statement.
2. Open incidents. Each with its current state, what has been tried, and what the next step is. “Investigating” is not a state; “waiting for the vendor to respond to case 12345, expected tomorrow” is.
3. Changes in the last 24 hours. Anything that touched the platform, including changes made by other teams. Most incidents follow a change, and the incoming shift needs the list to correlate against.
4. Scheduled work in the coming shift. Backups, a firmware rollout, a storage migration, somebody else’s DNS change. Anything that will generate noise, so that expected noise is not investigated as an incident.
5. Fragile items. The things you would not touch tonight. “Node pve-04 has a marginal PSU, replacement Thursday.” “The Windows file server takes 12 minutes to boot, so do not assume a failed start.”
Making the rota survivable
Four practices that cost little and matter more than anything else in this lesson:
- Shadow before solo. A new engineer takes a shift alongside an experienced one before taking one alone. Two shadowed shifts is usually enough and it is the cheapest way to find out that the runbook assumes knowledge nobody wrote down.
- Compensate it. Payment, time in lieu, or both, and stated in advance. Unpaid on-call is a resignation on a delay.
- Protect the day after. Somebody paged at 03:00 does not start at 09:00. Making this a written rule rather than a favour is what stops it eroding.
- Review pages monthly, not incidents. Incidents get reviewed already. The page list — every page, whether it was actionable, whether it should have been a ticket — is what actually reduces the load, and thirty minutes a month on it is the highest-leverage meeting the team has.
Common mistakes
- Claiming 24/7 cover a three-person team cannot staff.
- Paging on warnings, which trains people to ignore the pager.
- An escalation path that has never been dialled.
- No credentials for vendor support in the on-call pack.
- Handover as a narrative of the shift rather than a register of state.
- Leaving
noout, a health mute, a maintenance flag or a disabled backup job with no owner and no expiry. - Assuming shared context makes the handover unnecessary.
- Reviewing incidents but never reviewing pages.
Key takeaways
- Below four people you have a rota, not guaranteed cover; say which one you are offering.
- A page requires an action a human can take now, where waiting makes it worse. Everything else is a ticket.
- Track pages per shift and actionable rate; deleting a useless alert is reliability work.
- Escalation steps need triggers and tested contact methods, and your Proxmox support tier has a response time that determines where it fits.
- The handover section that matters is temporary state: Ceph flags, HA maintenance and disabled states, muted checks, disabled backup jobs and matchers, lowered expected votes.
- Every temporary state gets an owner and an expiry when it is set, not when
it is remembered.
ceph health mutewith a duration is the only one that expires by itself.
Knowledge check
Knowledge check · 5 questions
Q1. A single OSD fails overnight on a healthy size=3 Ceph cluster and recovery begins automatically. Should this page the on-call engineer?
Q2. Which of these belong in the temporary-state section of a shift handover? Select all that apply.
Q3. On a Proxmox Basic subscription, vendor support is a viable step in the escalation path during an active outage.
Q4. A team reviews its pages and finds that only 45% resulted in the responder taking any action that changed the outcome. What is the right response?
Q5. Why is ceph health mute with a duration argument better practice than the other temporary states in this lesson?
Passing score: 75%. Answers are checked in this browser.