← All articles
LINUX Automated Updates for Your Home Lab: A Complete Stra... 2026-02-09 · updates · automation · unattended-upgrades

Automated Updates for Your Home Lab: A Complete Strategy

Linux 2026-02-09 updates automation unattended-upgrades linux

One of the quiet risks of running a homelab is forgetting to update things. You set up a server, it works, and three months later you're running a kernel with known exploits, Docker images with unpatched CVEs, and a reverse proxy with a critical security fix you never applied.

Automated updates fix this, but they come with their own risks. A bad kernel update can make your server unbootable. A Docker image update can introduce breaking changes. Blindly auto-updating everything is just as dangerous as never updating.

This guide covers a practical update strategy: auto-update what's safe, notify on what's risky, and have a rollback plan for everything.

The Strategy: What to Auto-Update and What Not To

Before configuring anything, decide what gets auto-updated and what gets manual review.

Safe to auto-update:

Update automatically but review if something breaks:

Never auto-update:

Unattended Upgrades (Debian/Ubuntu)

The unattended-upgrades package handles automatic security updates on Debian-based systems. Most Ubuntu Server installations have it installed by default, but it's often not configured optimally.

Install and Enable

sudo apt install unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades

Select "Yes" when asked to enable automatic updates.

Configure What Gets Updated

Edit /etc/apt/apt.conf.d/50unattended-upgrades:

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}";
    "${distro_id}:${distro_codename}-security";
    "${distro_id}ESMApps:${distro_codename}-apps-security";
    "${distro_id}ESM:${distro_codename}-infra-security";
    // Uncomment to also auto-update regular (non-security) packages:
    // "${distro_id}:${distro_codename}-updates";
};

By default, only security updates are applied. This is the right starting point. Adding -updates includes regular package updates, which are generally safe but occasionally break things.

Configure Automatic Reboots

Some updates (especially kernel updates) require a reboot. You can configure unattended-upgrades to reboot automatically at a specific time:

// Automatically reboot if required
Unattended-Upgrade::Automatic-Reboot "true";

// Reboot at 4 AM, not immediately
Unattended-Upgrade::Automatic-Reboot-Time "04:00";

// Don't reboot if users are logged in
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";

For a homelab server that runs 24/7 services, automatic reboots at 4 AM are usually fine. But if you run VMs on bare metal, think carefully. A surprise reboot kills all running VMs. In that case, disable automatic reboots and reboot manually during maintenance windows:

Unattended-Upgrade::Automatic-Reboot "false";

Email Notifications

Get notified when updates are applied:

Unattended-Upgrade::Mail "your-email@example.com";
Unattended-Upgrade::MailReport "on-change";

You'll need a working MTA (like msmtp or postfix) configured on the server for email delivery.

Configure Update Frequency

Edit /etc/apt/apt.conf.d/20auto-upgrades:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";

These values are in days. The config above checks for updates daily, applies them daily, and cleans old packages weekly.

Verify It's Working

# Dry run — shows what would be updated
sudo unattended-upgrades --dry-run --debug

# Check the log
cat /var/log/unattended-upgrades/unattended-upgrades.log

# See the last update run
systemctl status apt-daily-upgrade.timer

dnf-automatic (Fedora/RHEL/AlmaLinux)

Fedora and RHEL-family distributions use dnf-automatic (or dnf5-plugin-automatic on Fedora 43+) for unattended updates.

Install and Configure

# Fedora 43+
sudo dnf install dnf5-plugin-automatic

# Fedora 40-42 / RHEL 9 / AlmaLinux 9
sudo dnf install dnf-automatic

Edit /etc/dnf/automatic.conf:

[commands]
# What to do: download and apply
apply_updates = yes

# Only security updates (recommended)
# For all updates, set upgrade_type = default
upgrade_type = security

# Reboot behavior
reboot = when-needed
reboot_command = "shutdown -r +5 'Applying updates, rebooting in 5 minutes'"

[emitters]
# How to notify
emit_via = email,stdio

[email]
email_from = root@homelab.local
email_to = your-email@example.com
email_host = localhost

Enable the Timer

# Enable the timer (runs daily)
sudo systemctl enable --now dnf-automatic.timer

# Verify the timer is active
systemctl status dnf-automatic.timer
systemctl list-timers | grep dnf

Security-Only Updates on RHEL/AlmaLinux

RHEL-family distributions have excellent security metadata, making security-only updates reliable:

# See available security updates
sudo dnf updateinfo list security

# Apply only security updates manually
sudo dnf update --security

# dnf-automatic handles this when upgrade_type = security

Checking Update History

# See what was updated and when
sudo dnf history
sudo dnf history info last

# Check the dnf-automatic log
journalctl -u dnf-automatic.service --since today

Watchtower: Auto-Updating Docker Containers

Watchtower monitors your running Docker containers and automatically updates them when new images are available. It pulls the latest image, stops the container, and recreates it with the same configuration.

Basic Setup

# ~/docker/watchtower/docker-compose.yml
services:
  watchtower:
    image: containrrr/watchtower
    container_name: watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_SCHEDULE: "0 0 4 * * *"  # 4 AM daily
      WATCHTOWER_TIMEOUT: 30s

This checks for updates to ALL running containers at 4 AM daily and cleans up old images.

Selective Updates with Labels

You probably don't want to auto-update everything. Use labels to control which containers Watchtower manages:

# docker-compose.yml for watchtower
services:
  watchtower:
    image: containrrr/watchtower
    container_name: watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_SCHEDULE: "0 0 4 * * *"
      WATCHTOWER_LABEL_ENABLE: "true"  # Only update labeled containers
    command: --label-enable

Then label the containers you want auto-updated:

# In each service's docker-compose.yml
services:
  pihole:
    image: pihole/pihole:latest
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

  nextcloud:
    image: nextcloud:28  # Pinned — don't auto-update major versions
    # No watchtower label = not auto-updated

Notifications

Watchtower can notify you when it updates containers:

environment:
  WATCHTOWER_NOTIFICATIONS: "email"
  WATCHTOWER_NOTIFICATION_EMAIL_FROM: "watchtower@homelab.local"
  WATCHTOWER_NOTIFICATION_EMAIL_TO: "your-email@example.com"
  WATCHTOWER_NOTIFICATION_EMAIL_SERVER: "smtp.example.com"
  WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT: "587"
  WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER: "your-user"
  WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD: "your-password"

Other notification options include Slack, Discord, Telegram, Gotify, and generic webhooks:

environment:
  WATCHTOWER_NOTIFICATIONS: "shoutrrr"
  WATCHTOWER_NOTIFICATION_URL: "discord://token@webhookid"

Monitor-Only Mode

If you want to know about available updates without applying them:

environment:
  WATCHTOWER_MONITOR_ONLY: "true"
  WATCHTOWER_NOTIFICATIONS: "email"

This sends you a notification when updates are available, but doesn't apply them. You can then update manually at your convenience.

Renovate and Dependabot for Docker Compose Files

Watchtower updates running containers, but it doesn't update your docker-compose.yml files. If you pin image versions (which you should for critical services), the compose file still references the old version.

Renovate and Dependabot solve this by scanning your compose files, detecting outdated image versions, and creating pull requests to update them.

Renovate with a Git Repository

If your Docker Compose files are in a Git repository (they should be):

Create renovate.json in the repo root:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:base"],
  "docker-compose": {
    "enabled": true,
    "fileMatch": ["(^|/)docker-compose\\.ya?ml$"]
  },
  "packageRules": [
    {
      "matchDatasources": ["docker"],
      "matchUpdateTypes": ["minor", "patch"],
      "automerge": true
    },
    {
      "matchDatasources": ["docker"],
      "matchUpdateTypes": ["major"],
      "automerge": false,
      "labels": ["major-update"]
    }
  ]
}

This auto-merges minor and patch version bumps but requires manual review for major version changes.

GitHub Dependabot

If your compose files are on GitHub, add .github/dependabot.yml:

version: 2
updates:
  - package-ecosystem: "docker-compose"
    directory: "/"
    schedule:
      interval: "weekly"
    reviewers:
      - "your-username"

Dependabot will create PRs for outdated Docker images in your compose files.

Reboot Policies

Updates often require reboots, especially kernel updates. Having a clear reboot policy prevents both "I never reboot and I'm running a 6-month-old kernel" and "my server rebooted during a backup and corrupted my data."

For Standalone Docker Hosts

Auto-reboot is generally safe. Docker containers restart automatically after a reboot (if configured with restart: unless-stopped or restart: always).

# Check if a reboot is needed (Debian/Ubuntu)
[ -f /var/run/reboot-required ] && echo "Reboot needed"

# Check if a reboot is needed (Fedora/RHEL)
needs-restarting -r

Schedule reboots during low-usage hours:

# Cron job to reboot at 4 AM on Sundays if needed (Debian/Ubuntu)
echo '0 4 * * 0 root [ -f /var/run/reboot-required ] && /sbin/shutdown -r now' | sudo tee /etc/cron.d/auto-reboot

For Proxmox/Virtualization Hosts

Do not auto-reboot virtualization hosts. A reboot kills all running VMs and containers. Instead:

  1. Get notified when a reboot is needed
  2. Schedule a maintenance window
  3. Gracefully shut down VMs
  4. Reboot the host
  5. Verify VMs come back up
# Script to check and notify (add to cron)
#!/bin/bash
if [ -f /var/run/reboot-required ]; then
    echo "Proxmox host $(hostname) needs a reboot for kernel update" | \
    mail -s "Reboot required: $(hostname)" your-email@example.com
fi

For High-Availability Clusters

If you run a Proxmox HA cluster, you can reboot nodes one at a time. VMs migrate to other nodes automatically:

  1. Put the node in maintenance mode (migrates VMs away)
  2. Update and reboot
  3. Bring the node back online
  4. Repeat for the next node

needrestart: Handling Service Restarts

Some updates don't require a full reboot — just a service restart. The needrestart package detects which services need restarting after library updates:

# Install
sudo apt install needrestart

# Check what needs restarting
sudo needrestart

# Auto-restart services (add to unattended-upgrades config)
# In /etc/needrestart/needrestart.conf:
# $nrconf{restart} = 'a';  # Automatically restart services

This is particularly useful for OpenSSL and glibc updates, which affect nearly every running service but don't require a reboot.

A Complete Homelab Update Strategy

Here's a concrete strategy that balances security with stability:

Daily (Automated)

Weekly (Automated with Review)

Monthly (Manual)

Before Any Manual Update

# Snapshot if on Proxmox/ZFS
zfs snapshot rpool/data@pre-update-$(date +%Y%m%d)

# Or backup the VM/container
vzdump <VMID> --storage local --mode snapshot

# For Docker, back up volumes
docker compose stop
tar czf backup-$(date +%Y%m%d).tar.gz ./data ./config
docker compose up -d

When NOT to Auto-Update

There are situations where automatic updates cause more problems than they solve:

Production services with SLAs: If your homelab runs services other people depend on (Nextcloud for family, Jellyfin for friends), a bad auto-update at 4 AM means you wake up to complaints. Pin versions and update manually.

Services with complex upgrade procedures: Nextcloud major versions require running occ upgrade. PostgreSQL major versions require pg_upgrade. These can't be automated safely with Watchtower.

When you're going on vacation: Disable auto-updates before extended absences. If an update breaks something while you're gone, you can't fix it.

# Temporarily disable unattended-upgrades
sudo systemctl stop unattended-upgrades
sudo systemctl disable unattended-upgrades

# Re-enable when you're back
sudo systemctl enable --now unattended-upgrades

Bleeding-edge distributions: Fedora, Arch, and other rolling releases get updates that occasionally break things. Auto-updating Arch is a recipe for returning to a broken system. Use these distros in your homelab if you enjoy the learning, but update manually.

The goal isn't to automate everything. It's to automate the boring, safe stuff (security patches, minor updates) so you can focus your limited time on the updates that actually need human attention. A homelab that's 95% auto-updated with the remaining 5% handled during monthly maintenance is dramatically more secure than one where you "get around to it eventually."