Skip to Content
DocsOperationsUpgrade & MigrationPre-Upgrade Backup Checklist

Pre-Upgrade Backup Checklist

System upgrades carry some risk; thorough backups are a prerequisite for a safe upgrade. The following checklist helps you prepare fully before upgrading.

Backup Priority

PriorityContentReason
HighestUser data and databasesCannot be recreated
HighSystem configuration filesManually customized configs
MediumPackage lists and service statesHelps rebuild the environment
LowFull system snapshotQuick rollback

1. User Data Backup

Personal Files

# Back up the entire home directory sudo rsync -avzP /home/ /backup/home/ # Or pack with tar sudo tar czf /backup/home-backup-$(date +%Y%m%d).tar.gz /home/ # Back up a specific user only sudo rsync -avzP /home/username/ /backup/home-username/

Database Backup

# MySQL / MariaDB mysqldump -u root -p --all-databases > /backup/mysql-all-$(date +%Y%m%d).sql # Single database mysqldump -u root -p mydb > /backup/mysql-mydb-$(date +%Y%m%d).sql # PostgreSQL sudo -u postgres pg_dumpall > /backup/postgres-all-$(date +%Y%m%d).sql # Single database sudo -u postgres pg_dump mydb > /backup/postgres-mydb-$(date +%Y%m%d).sql # Redis redis-cli BGSAVE sudo cp /var/lib/redis/dump.rdb /backup/redis-$(date +%Y%m%d).rdb # MongoDB mongodump --out /backup/mongodb-$(date +%Y%m%d)/ # SQLite cp /path/to/database.db /backup/sqlite-$(date +%Y%m%d).db

Website and Application Data

# Web root directory sudo tar czf /backup/www-$(date +%Y%m%d).tar.gz /var/www/ # Docker data volumes docker volume ls for vol in $(docker volume ls -q); do docker run --rm -v ${vol}:/data -v /backup:/backup ubuntu \ tar czf /backup/docker-vol-${vol}-$(date +%Y%m%d).tar.gz -C /data . done # Docker Compose projects cd /path/to/project && docker compose down tar czf /backup/docker-project-$(date +%Y%m%d).tar.gz /path/to/project/

2. System Configuration Backup

Key Configuration Files

# Pack the entire /etc directory sudo tar czf /backup/etc-$(date +%Y%m%d).tar.gz /etc/ # Back up key configurations individually sudo cp -a /etc/ssh/ /backup/ssh-config/ sudo cp -a /etc/nginx/ /backup/nginx-config/ sudo cp -a /etc/apache2/ /backup/apache2-config/ sudo cp -a /etc/netplan/ /backup/netplan-config/ sudo cp -a /etc/samba/ /backup/samba-config/ sudo cp -a /etc/fstab /backup/fstab sudo cp -a /etc/hosts /backup/hosts sudo cp -a /etc/crontab /backup/crontab

Cron Jobs

# System cron sudo cp -a /etc/cron.d/ /backup/cron.d/ sudo cp -a /etc/crontab /backup/crontab # User cron crontab -l > /backup/crontab-$(whoami)-$(date +%Y%m%d).txt # All users' cron jobs for user in $(cut -d: -f1 /etc/passwd); do cron=$(sudo crontab -u $user -l 2>/dev/null) if [ -n "$cron" ]; then echo "=== $user ===" >> /backup/crontabs-all.txt echo "$cron" >> /backup/crontabs-all.txt fi done

Custom systemd Services

# Back up custom systemd service files sudo tar czf /backup/systemd-custom-$(date +%Y%m%d).tar.gz \ /etc/systemd/system/*.service \ /etc/systemd/system/*.timer \ /etc/systemd/system/*.mount \ 2>/dev/null

Firewall Rules

# UFW rules sudo ufw status numbered > /backup/ufw-rules.txt sudo cp -a /etc/ufw/ /backup/ufw-config/ # iptables rules sudo iptables-save > /backup/iptables-$(date +%Y%m%d).rules sudo ip6tables-save > /backup/ip6tables-$(date +%Y%m%d).rules

3. System State Recording

Installed Packages

# Full package list dpkg --get-selections > /backup/packages-selections-$(date +%Y%m%d).txt # Manually installed packages (excluding auto-dependencies) apt-mark showmanual > /backup/packages-manual-$(date +%Y%m%d).txt # With version numbers dpkg -l > /backup/packages-versions-$(date +%Y%m%d).txt # Snap packages snap list > /backup/snap-packages-$(date +%Y%m%d).txt # Flatpak packages (if applicable) flatpak list > /backup/flatpak-packages-$(date +%Y%m%d).txt 2>/dev/null # pip packages pip3 list > /backup/pip-packages-$(date +%Y%m%d).txt 2>/dev/null

APT Source Configuration

# DEB822 format sources sudo cp -a /etc/apt/sources.list.d/ /backup/apt-sources.list.d/ # APT keys sudo cp -a /etc/apt/keyrings/ /backup/apt-keyrings/ 2>/dev/null sudo cp -a /usr/share/keyrings/ /backup/usr-keyrings/ 2>/dev/null # APT preferences sudo cp /etc/apt/preferences.d/* /backup/apt-preferences/ 2>/dev/null

Network Configuration

# Network state ip addr > /backup/ip-addr-$(date +%Y%m%d).txt ip route > /backup/ip-route-$(date +%Y%m%d).txt cat /etc/resolv.conf > /backup/resolv-conf-$(date +%Y%m%d).txt ss -tlnp > /backup/listening-ports-$(date +%Y%m%d).txt

Running Services

systemctl list-units --type=service --state=running > /backup/services-running-$(date +%Y%m%d).txt systemctl list-unit-files --state=enabled > /backup/services-enabled-$(date +%Y%m%d).txt

Kernel and Boot Information

uname -a > /backup/kernel-$(date +%Y%m%d).txt cat /proc/cmdline > /backup/cmdline-$(date +%Y%m%d).txt dpkg --list | grep linux-image > /backup/kernel-packages-$(date +%Y%m%d).txt

4. Full System Backup

Using Timeshift

# Install Timeshift sudo apt install timeshift -y # Create a system snapshot (RSYNC mode) sudo timeshift --create --comments "Pre-upgrade backup $(date +%Y%m%d)" --tags D # List snapshots sudo timeshift --list

Full Disk Backup with rsync

# Full disk backup to an external drive sudo rsync -aAXv --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found","/backup/*"} / /mnt/backup/full-system/

Disk Image with dd

# Create a full disk image (should be done from a Live USB) sudo dd if=/dev/sda of=/mnt/external/disk-image-$(date +%Y%m%d).img bs=4M status=progress # Compressed image sudo dd if=/dev/sda bs=4M status=progress | gzip > /mnt/external/disk-image-$(date +%Y%m%d).img.gz

LVM Snapshots

# If using LVM, create a logical volume snapshot sudo lvcreate -L 10G -s -n root-snap /dev/vg0/root # After a failed upgrade, you can restore from the snapshot sudo lvconvert --merge /dev/vg0/root-snap

Virtual Machine Snapshots

# KVM/libvirt VMs virsh snapshot-create-as vm-name pre-upgrade-$(date +%Y%m%d) # VirtualBox VBoxManage snapshot "VM Name" take "pre-upgrade" # Cloud servers # Create a system disk snapshot in the cloud console

5. One-Click Backup Script

Consolidate the above steps into a script:

#!/bin/bash # pre-upgrade-backup.sh set -euo pipefail BACKUP_DIR="/backup/pre-upgrade-$(date +%Y%m%d)" mkdir -p "$BACKUP_DIR" echo "=== Starting pre-upgrade backup ===" echo "Backup directory: $BACKUP_DIR" # System information echo ">> Recording system state..." lsb_release -a > "$BACKUP_DIR/lsb-release.txt" 2>&1 uname -a > "$BACKUP_DIR/kernel.txt" dpkg --get-selections > "$BACKUP_DIR/packages-selections.txt" apt-mark showmanual > "$BACKUP_DIR/packages-manual.txt" systemctl list-units --type=service --state=running > "$BACKUP_DIR/services-running.txt" ip addr > "$BACKUP_DIR/ip-addr.txt" ss -tlnp > "$BACKUP_DIR/listening-ports.txt" # Configuration files echo ">> Backing up configuration files..." sudo tar czf "$BACKUP_DIR/etc.tar.gz" /etc/ 2>/dev/null # Cron echo ">> Backing up cron jobs..." crontab -l > "$BACKUP_DIR/crontab-user.txt" 2>/dev/null || true # Firewall echo ">> Backing up firewall rules..." sudo ufw status numbered > "$BACKUP_DIR/ufw-rules.txt" 2>/dev/null || true sudo iptables-save > "$BACKUP_DIR/iptables.rules" 2>/dev/null || true # Package sources echo ">> Backing up APT sources..." cp -a /etc/apt/sources.list.d/ "$BACKUP_DIR/sources.list.d/" 2>/dev/null || true echo "=== Backup complete ===" echo "Backup file listing:" ls -lh "$BACKUP_DIR/" echo "" echo "Please also manually back up:" echo " - Databases (MySQL/PostgreSQL, etc.)" echo " - User data (/home)" echo " - Web data (/var/www)" echo " - Docker data volumes" du -sh "$BACKUP_DIR"
# Use the script chmod +x pre-upgrade-backup.sh sudo ./pre-upgrade-backup.sh

Backup Verification

After completing backups, be sure to verify their integrity:

# Verify tar archive integrity tar tzf /backup/etc-*.tar.gz > /dev/null && echo "etc backup is OK" # Verify database backup # WARNING: a full dump usually contains CREATE DATABASE / USE statements, # so never SOURCE it directly into a production instance, or it will overwrite existing databases! # Safe approach 1: only check the integrity of the dump file gunzip -t /backup/mysql-all-*.sql.gz && echo "database backup archive is intact" # For an uncompressed .sql, check whether it ends with the dump-completed marker tail -n1 /backup/mysql-all-20260324.sql | grep -q "Dump completed" && echo "dump is complete" # Safe approach 2: restore and verify in an isolated, throwaway instance (e.g. a separate container/port), never against the production database # Verify file count echo "Original file count: $(find /etc -type f | wc -l)" echo "Backup file count: $(tar tzf /backup/etc-*.tar.gz | wc -l)" # Confirm the backup disk has enough space df -h /backup/

Checklist Summary

  • User home directory backed up
  • All databases exported
  • /etc configuration directory backed up
  • Cron jobs recorded
  • Firewall rules saved
  • Installed package list exported
  • APT source configuration backed up
  • Network configuration recorded
  • Service list recorded
  • System snapshot created (if using LVM/Timeshift)
  • Backup file integrity verified
  • Backups stored on a different disk from the system
Last updated on