Homelab Automation: Scheduled Backups, Updates, and Monitoring
Set your homelab to back itself up, update its own containers, and tell you when something breaks. A practical automation stack using cron, Watchtower, Proxmox vzdump, and Uptime Kuma.
A homelab you have to babysit is a homelab you will eventually neglect. The containers go stale, the backups quietly stop running, a disk fills up at 2am and you find out three days later when a service is already down. The fix is not discipline. It is automation. A well-set-up homelab backs itself up, keeps its own containers current, and messages you the moment something actually breaks, so the only time you log in is when there is a real decision to make.
This guide pulls the automation layer together into one place. It assumes you already have services running, so if you are still building the foundation, start with how to start a homelab and the best self-hosted apps for beginners first, then come back here. Everything below maps onto a normal budget setup like the one on my stack page: Proxmox on a mini PC, Docker containers, and a couple of cheap drives.
This guide contains no paid affiliate links. Hardware picks live in the linked storage and stack guides.
The Three Things Worth Automating
There are a hundred things you could automate. Three of them earn their keep immediately:
- Backups. The one task you cannot afford to do inconsistently.
- Updates. Stale images are the slow leak: missed bug fixes and unpatched security holes.
- Monitoring. Automation that runs silently is worthless. You need to know when a job fails or a service falls over.
Notice the order. Monitoring is last to set up but it is what makes the other two trustworthy. An automated backup you never verify is just a job that might be running. Build all three and they reinforce each other.
1. Scheduled Backups
Backups are layered. Proxmox handles the whole VM or container. A small script handles individual Docker volumes for faster, more granular restores. Off-site sync handles the disaster case.
Proxmox backups (vzdump)
Proxmox has a scheduler built in. Go to Datacenter, then Backup, then Add:
- Schedule: daily, something like 3am when nothing is in use
- Storage: a target on a different disk than your VMs, ideally an external drive or NAS share
- Mode:
Snapshotfor live backups with minimal downtime - Retention: 7 daily copies is a sane default
I run daily vzdump with 7-day retention. The oldest backup rolls off automatically, so storage stays bounded. The full mechanics of vzdump, including restoring from one, are covered in Proxmox snapshots and backups. The important word here is scheduled: set it once and stop thinking about it.
You want that backup target to be a separate physical drive. A cheap external SSD plugged into the mini PC is enough to get backups off the boot disk for a home setup, and the homelab storage options rundown covers which budget drives are actually worth buying.
Docker volume backups
vzdump captures the whole VM, but when one app’s config gets corrupted, restoring an entire VM to recover a single volume is heavy. A small per-volume backup script makes recovery surgical.
Create /opt/scripts/backup-volumes.sh:
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/mnt/backups/docker-volumes"
DATE=$(date +%Y-%m-%d)
RETENTION_DAYS=14
mkdir -p "$BACKUP_DIR"
# One line per service: container name and the host path of its data
declare -A VOLUMES=(
["vaultwarden"]="/opt/vaultwarden/data"
["paperless"]="/opt/paperless/data"
["uptime-kuma"]="/opt/uptime-kuma/data"
)
for name in "${!VOLUMES[@]}"; do
src="${VOLUMES[$name]}"
echo "Backing up $name from $src"
docker stop "$name"
tar czf "$BACKUP_DIR/${name}-${DATE}.tar.gz" -C "$(dirname "$src")" "$(basename "$src")"
docker start "$name"
done
# Prune archives older than the retention window
find "$BACKUP_DIR" -name '*.tar.gz' -mtime +"$RETENTION_DAYS" -delete
echo "Volume backup complete: $DATE"
Make it executable and test it once by hand:
chmod +x /opt/scripts/backup-volumes.sh
/opt/scripts/backup-volumes.sh
Stopping each container before archiving guarantees a consistent copy, especially for anything using SQLite, which does not like being read mid-write. The containers are down for a few seconds each. For homelab services that is fine. Schedule it overnight with cron:
crontab -e
# Docker volume backups, nightly at 2:30am
30 2 * * * /opt/scripts/backup-volumes.sh >> /var/log/volume-backup.log 2>&1
Off-site copies with restic
Local backups die with the building. The cheapest fix is restic pushing an encrypted copy to Backblaze B2. B2 runs about $0.006 per GB per month, so 50GB of critical data costs roughly $0.30 a month.
# Install restic
sudo apt install restic
# Set credentials (store these in your password manager, not in the script)
export B2_ACCOUNT_ID="your-key-id"
export B2_ACCOUNT_KEY="your-application-key"
export RESTIC_REPOSITORY="b2:your-bucket-name:homelab"
export RESTIC_PASSWORD="a-long-random-passphrase"
# Initialize the repo once
restic init
# Back up your local backup directory
restic backup /mnt/backups
Wrap that in /opt/scripts/restic-offsite.sh (with the exports inside the script, locked down to root-only read), then schedule a daily backup and a weekly prune:
# Off-site restic backup, nightly at 4am
0 4 * * * /opt/scripts/restic-offsite.sh >> /var/log/restic.log 2>&1
# Prune old off-site snapshots, Sundays at 5am
0 5 * * 0 restic forget --keep-daily 7 --keep-weekly 4 --prune >> /var/log/restic.log 2>&1
That is the 3-2-1 rule, automated: three copies (live, local, off-site), two media, one off-site. If you would rather sync between your own machines instead of paying a provider, the Syncthing guide covers a no-cloud alternative for the off-site leg.
2. Automated Updates
Two layers update on their own schedule: your Docker containers and the host operating system underneath them.
Containers with Watchtower
Watchtower watches your running containers and pulls newer images on a schedule. Full setup and the notification config are in the Watchtower guide. The short version:
services:
watchtower:
image: containrrr/watchtower:latest
container_name: watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- WATCHTOWER_CLEANUP=true
- WATCHTOWER_SCHEDULE=0 0 4 * * *
restart: unless-stopped
The rule I follow: let Watchtower update everything on rolling tags, and opt out the fragile, stateful containers so I update those deliberately. Add this label to anything you want to hold back, database containers especially:
labels:
- "com.centurylinklabs.watchtower.enable=false"
This is exactly why the volume backups above run first, at 2:30am, before Watchtower runs at 4am. If a 4am update breaks a service, last night’s volume archive is sitting right there.
The host with unattended-upgrades
Watchtower handles containers, but the Linux host they run on needs patches too. On a Debian or Ubuntu VM, unattended-upgrades applies security updates automatically:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
That enables automatic security patching with no further babysitting. For Proxmox itself, I patch the host manually rather than unattended, because a hypervisor reboot takes everything down with it. Take a snapshot, run the updates, confirm the node comes back, then move on. Some things stay deliberate on purpose.
3. Monitoring and Alerts
Here is the part people skip, and it is the part that makes everything above trustworthy. A backup job that silently stopped running two weeks ago is worse than no backup, because you think you are covered.
Uptime Kuma for services
Uptime Kuma gives you a dashboard plus alerts for every service. Point an HTTP monitor at each one and configure a notification channel (Telegram, Discord, ntfy, email). When a service stops answering, you get a message in under a minute.
Push monitors as a dead man’s switch
The real trick for automation is the push monitor. Instead of Uptime Kuma checking your service, your scheduled job checks in with Uptime Kuma. If the check-in never arrives, you get alerted.
In Uptime Kuma, add a monitor of type Push. It gives you a URL. Then append a curl to the end of each backup script so it only pings on success:
# Last line of backup-volumes.sh, after the work succeeds
curl -fsS "https://uptime.yourdomain.com/api/push/AbCdEf123?status=up&msg=ok" > /dev/null
Set the monitor’s expected interval to a bit longer than the job’s schedule, say 26 hours for a daily job. If a backup fails partway, the script exits on set -e before reaching the curl, the ping never lands, and Uptime Kuma raises the alarm. This single pattern catches the failure mode that quietly ruins homelabs: a job that stopped working and told no one.
Tying It Together: A Weekly Schedule
Stacking everything on the same time slot is asking for an I/O traffic jam. Stagger the jobs so backups finish before updates start, and monitoring sits on top of all of it.
| Time (daily) | Job | Tool |
|---|---|---|
| 2:30am | Docker volume backups | cron + tar |
| 3:00am | Proxmox VM/LXC backups | vzdump |
| 4:00am | Off-site copy + container updates | restic + Watchtower |
| Continuous | Service and push monitoring | Uptime Kuma |
| Sundays 5am | Prune old off-site snapshots | restic forget |
Every one of those jobs reports success to Uptime Kuma. If your phone is quiet, the homelab took care of itself last night. If it buzzes, something needs you, and you know exactly what.
For the backup-strategy thinking behind which tool does what, the homelab backup strategy breakdown compares Syncthing, restic, and Duplicati head to head.
What I Don’t Automate
Automation has a limit, and pretending otherwise is how people lose data.
- Restores. I test a restore by hand every quarter. An untested backup is a hope, not a backup. Pull a real archive, restore it to a throwaway VM, and confirm the data is intact.
- Database major-version upgrades. A Postgres 15 to 16 jump can require a migration step. Watchtower would just break it. These containers carry the opt-out label.
- Proxmox host updates. Snapshot, patch, verify, by hand. The blast radius is the whole node.
Everything else, the boring nightly grind of copying files and pulling images, the machine does better than I would. Automation is not about doing more. It is about making sure the things that must happen actually happen, every single night, whether you remember them or not. A small UPS under the desk rounds it out, so a power blip during a 3am backup does not corrupt the very thing you were trying to protect.
Set this up once and your homelab stops being a pet you feed daily. It becomes infrastructure that runs itself and tells you when it needs you. That is the whole point of doing this on your own terms instead of renting it from someone else.