My homelab now runs on two NUCs with a UNAS Pro for storage. One NUC handles compute (Proxmox VE), the other runs Proxmox Backup Server. The backup node doesn't need to run 24/7 as it only does one job per day. So I built an automation that wakes it up, runs the backup, and shuts it down.

Some links in this post are affiliate links. I may earn a small commission at no extra cost to you.

Table of Contents

Why Home Assistant?

When I started looking into automating the scheduled backup tasks and automatic startup and shutdown, cron jobs and shell scripts came to mind. I would have a cron job on the PVE to send the magic WoL packet and perform the backup after a minute or two. The PBS could have a script to automatically shut down after a set amount of time. Or I'd issue the shutdown REST command from the PVE. That would mean I'd have to inject the secret token somewhere, figure out where to store it securely, and hope the timing works out. As you can see this gets messy quickly. I'm also fairly certain I wouldn't be able to remember where I put those scripts a year from now.

A solution to this is Infrastructure as Code, where you document and version any configuration to the hosts within your homelab, but I'm not quite there yet.

The next best thing for me was sitting right there, at the heart of my homelab in the form of Home Assistant. It has basic secret management, a great ecosystem and already great support for automations.

The flow

This is how it works:

Home Assistant sends a Wake-on-LAN magic packet to PBS and waits for it to come online via a ping sensor. It then tells PVE to start a backup via the REST API. When the backup finishes, PVE sends a webhook back to Home Assistant, which then shuts down PBS. The whole cycle takes under 10 minutes.

PBS setup

You'll need the MAC address of your PBS machine for Wake-on-LAN. Find it with ip link show or in your routers interface.

BIOS settings

Two things to check:

  • Wake on LAN from S4/S5: Power On - Normal Boot

  • ErP Ready: Disabled

ErP is an EU energy regulation that minimizes standby power, but it also cuts power to the NIC when the system is off, which breaks Wake-on-LAN. Mine was already disabled, but worth checking if WoL isn't working for you.

API token

Configuration → Access Control → API Tokens:

  • User: root@pam

  • Token ID: hass

  • Privilege Separation: OFF

The token needs two separate permissions:

  • Path / → Role Admin (for shutdown)

  • Datastore your-datastore → Role DatastoreAdmin (for backup operations)

If you only add one, you'll get a 401 error that doesn't tell you which permission is missing. I spent some time on this because I assumed the Admin role on / would cover everything.

One other thing that took me about an hour to figure out: PBS and PVE use different token formats for some reason:

  • PVE: PVEAPIToken=root@pam!hass=secret (equals sign)

  • PBS: PBSAPIToken=root@pam!hass:secret (colon)

The error messages don't make this obvious.

PVE setup

API token

Datacenter → Permissions → API Tokens → Add:

  • User: root@pam

  • Token ID: hass

  • Privilege Separation: OFF

Add PBS as storage

Datacenter → Storage → Add → Proxmox Backup Server:

  • ID: pbs

  • Server: <PBS_IP>

  • Datastore: your-datastore

  • Username: root@pam!hass

  • Password: your PBS token secret

Webhook notification

For Home Assistant to know when the backup is done, PVE needs to send a webhook.

Datacenter → Notifications → Notification Targets → Add:

  • Name: hass-backup

  • URL: http://<HASS_IP>:8123/api/webhook/pbs_backup_complete

  • Method: POST

  • Body: {}

Datacenter → Notifications → Notification Matchers → Add:

  • Name: backup-complete

  • Match field: exact:type=vzdump

  • Targets: hass-backup

Finally, set your backup job's notification mode to notification-system.

The matcher syntax comes from the Proxmox documentation. I expected to have to fiddle with it but it worked on the first attempt.

Home Assistant config

Ping sensor

Add the Ping integration via the UI: Settings → Devices & Services → Add Integration → Ping. Enter the PBS IP address. This creates a binary sensor that tracks whether PBS is online.

secrets.yaml

pve_api_token: "PVEAPIToken=root@pam!hass=YOUR_TOKEN"
pbs_api_token: "PBSAPIToken=root@pam!hass:YOUR_TOKEN"

For some reason, the token format is different between the PVE and PBS. It took me about an hour to realize that the separators are different: = for PVE, : for PBS.

configuration.yaml

wake_on_lan:

rest_command:
  pve_start_backup:
    url: "https://<PVE_IP>:8006/api2/json/nodes/pve/vzdump"
    method: POST
    headers:
      Authorization: !secret pve_api_token
    content_type: "application/x-www-form-urlencoded"
    payload: "storage=pbs&mode=snapshot&compress=zstd&all=1"
    verify_ssl: false

  pbs_shutdown:
    url: "https://<PBS_IP>:8007/api2/json/nodes/localhost/status"
    method: POST
    headers:
      Authorization: !secret pbs_api_token
    content_type: "application/x-www-form-urlencoded"
    payload: "command=shutdown"
    verify_ssl: false

The verify_ssl: false is needed because both PVE and PBS use self-signed certificates by default. You could add their certs to Home Assistant's trust store if you prefer.

automations.yaml

- id: pbs_backup_cycle
  alias: PBS Backup Cycle
  trigger:
    - platform: time
      at: "03:00:00"
  action:
    - service: wake_on_lan.send_magic_packet
      data:
        mac: "<PBS_MAC>"

    - wait_for_trigger:
        - platform: state
          entity_id: binary_sensor.pbs_online
          to: "on"
      timeout: "00:05:00"
      continue_on_timeout: false

    - delay: "00:00:30"

    - service: rest_command.pve_start_backup

    - wait_for_trigger:
        - platform: webhook
          webhook_id: pbs_backup_complete
          local_only: true
      timeout: "02:00:00"
      continue_on_timeout: true

    - service: rest_command.pbs_shutdown

The timeouts are set so that if PBS doesn't wake within 5 minutes, the automation stops entirely. If the backup doesn't finish within 2 hours, PBS shuts down anyway to prevent the node from running indefinitely.

Troubleshooting

If you're getting 401 errors on PBS calls, check the token format—colon, not equals sign. For "permission denied" on shutdown specifically, you're probably missing the Admin permission on path /. The datastore permission alone isn't enough.

506 errors usually mean the content type is wrong. Home Assistant defaults to application/octet-stream, but the Proxmox API expects application/x-www-form-urlencoded.

If PBS won't wake at all, check that ErP is disabled in BIOS and that WoL is enabled for S4/S5 states. You can test from another machine with wakeonlan <mac>. Some managed switches block broadcast packets by default.

Is this overkill?

Maybe 😅

A scheduled backup job in PVE that dumps straight to the UNAS would have been simpler. My reasoning at this point is that this approach lets me have all automations in one place and the PBS gives you deduplication which should save storage space over time, though I haven't measured the actual savings yet.

I wanted a dedicated backup node, not virtualized within the machine that I'm trying to back up. For me, this approach works, I didn't have to SSH into any machine, and I don't have to think about it anymore.

Hardware

The compute node is a NUC 14 Pro with a Core Ultra 125H, which handles AV1 transcoding in Jellyfin. I got it as an Amazon Warehouse deal. The backup node is a NUC 15 Pro with an Intel Core 3 100U, bought second hand via Marktplaats. Both are barebone kits, so RAM and storage came separately, and the NVMe moved across from my old Ridge server.

Component

Price (approx.)

NUC 14 Pro barebone (Core Ultra 125H), compute node

€412

NUC 15 Pro barebone (Core 3 100U), backup node

€330

RAM + SSD, both second hand

€430

NVMe, reused from the Ridge

€0

Total

€1172

Both boards came out of their cases and went into a MyElectronics 1U Rack Mount Pro shelf, which holds two of them in a single rack unit. A Mijia precision screwdriver set made short work of taking them apart.

As for the UNAS Pro, I'm not fully convinced yet. It fit my rack and I already had UniFi equipment, so it made sense at the time. But the software still needs to mature. I've had NFS freezes that required a reboot to resolve. I switched to an SMB mount and it has been stable since. It works, but the software isn't as polished as Synology or other solutions at this point.

I also made a mistake with the drives: I started with WD Red Plus 12TB (7200 RPM), which turned out to be way too loud with the rack sitting next to my desk. Thankfully, Informatique was super customer friendly and let me swap them for WD Red Plus 8TB (5640 RPM) and return the difference.

Drive

Idle

Seek

WD Red Plus 12TB (7200 RPM)

~28-30 dB

~32-34 dB

WD Red Plus 8TB (5640 RPM)

~23-25 dB

~27-29 dB

The interesting thing about dBs is that they are measured on a logarithmic scale. Even though the 5 dB difference in idle noise seems small, it’s a significant difference to the ear.

Power consumption

The whole rack draws about 100W, but that includes my router and access point, which are around 30W between them. Take the networking out and the homelab itself sits at roughly 70W, running 24/7. The compute node is about 30W of that. PBS barely registers since it's off most of the time, apart from a short spike each night when it wakes up for the backup.

Next Steps

Now that I have reliable backups in place, I’m looking forward to self-hosting some critical services like Vaultwarden (passwords) and Immich (photos). Subscribe to read about it when I do :)