Step-by-step installation instructions for Ubuntu 24.04 LTS.
- Ubuntu 24.04 LTS (or compatible Debian-based system)
- Root access
- External HDD with ext4 filesystem
- Shelly Plug Plus (optional, can be disabled in config)
sudo apt update
sudo apt install -y borgbackup curl hdparm lsof util-linuxVerify installations:
borg --version # Should show BorgBackup version
curl --version # Should show curl version
hdparm -V # Should show hdparm versionSkip to step 4 if your HDD is already formatted.
# Find your device (e.g., /dev/sdc)
lsblk
# Format as ext4 (REPLACE /dev/sdX with your device!)
sudo mkfs.ext4 -L "BackupDrive" /dev/sdX1
# Get UUID
sudo blkid /dev/sdX1
# Example output: UUID="f2c4624a-72ee-5e4b-85f8-a0d7f02e702f"Save the UUID - you'll need it for configuration!
# Create installation directory
sudo mkdir -p /opt/backup-system
# Extract archive
sudo unzip backup-system.zip -d /opt/
# Verify structure
ls -la /opt/backup-system/Expected structure:
/opt/backup-system/
├── main.sh
├── config/
├── segments/
├── tests/
├── systemd/
└── docs/
For easier command-line access, create a wrapper script in /usr/local/bin/:
# Create wrapper script
sudo tee /usr/local/bin/backup-system > /dev/null << 'EOF'
#!/bin/bash
# Backup System Wrapper
exec /opt/backup-system/main.sh "$@"
EOF
# Make it executable
sudo chmod +x /usr/local/bin/backup-system
# Test it
backup-system
# Should show: [ERROR] Profile not found: system (this is OK - config not done yet)Why a wrapper instead of a symlink?
- Symlinks can confuse path resolution in scripts
- Wrapper ensures correct working directory
- More reliable for systemd integration
Usage after installation:
# With wrapper (short)
sudo backup-system system
# Without wrapper (full path)
sudo /opt/backup-system/main.sh systemsudo mkdir -p /mnt/extern_backupsudo nano /etc/fstabAdd this line (replace UUID with yours):
UUID=f2c4624a-72ee-5e4b-85f8-a0d7f02e702f /mnt/extern_backup ext4 noauto,x-systemd.automount 0 2
Important flags:
noauto- Don't mount automatically at bootx-systemd.automount- Enable systemd automount
Save and exit (Ctrl+X, Y, Enter).
# Test mount without actually mounting
sudo mount -fav
# Should show: /mnt/extern_backup : successfully simulated# Copy example file
sudo cp /opt/backup-system/config/common.env.example /opt/backup-system/config/common.env
# Edit configuration
sudo nano /opt/backup-system/config/common.envAdjust these values:
# Shelly Plug IP address (REPLACE with your IP)
export SHELLY_IP="192.168.X.X"
# Auto-off timeout (12 hours = 43200 seconds)
export SHELLY_TOGGLE_AFTER_SEC="43200"# Copy example file
sudo cp /opt/backup-system/config/profiles/system.env.example /opt/backup-system/config/profiles/system.env
# Edit configuration
sudo nano /opt/backup-system/config/profiles/system.envMust adjust:
# UUID of your backup drive (find with: sudo blkid)
export BACKUP_UUID="REPLACE-WITH-YOUR-BACKUP-HDD-UUID"
# Target directory (REPLACE 'hostname' with your actual hostname)
export TARGET_DIR="${BACKUP_MNT}/hostname_nvme0n1_System"
# HDD device for spindown (find with: lsblk)
export HDD_DEVICE="/dev/sdX"
# Archive name prefix (REPLACE 'hostname' with your actual hostname)
export ARCHIVE_PREFIX="hostname-nvme0n1-system"Optional adjustments:
# Backup sources (semicolon-separated)
export BACKUP_SOURCES="/;/boot/efi"
# Excludes (semicolon-separated)
export BACKUP_EXCLUDES="/proc;/sys;/dev;/run;/tmp;/var/tmp;${BACKUP_MNT}"
# Retention policy
export KEEP_DAILY="7"
export KEEP_WEEKLY="4"
export KEEP_MONTHLY="6"
# Disable Shelly if not using
export SHELLY_ENABLED="false"# Create config directory
sudo mkdir -p /root/.config/borg
# Create passphrase file (use a strong passphrase!)
echo "your-very-secure-passphrase-here" | sudo tee /root/.config/borg/passphrase
# Secure the file
sudo chmod 600 /root/.config/borg/passphrase
# Verify
sudo cat /root/.config/borg/passphrasesudo mkdir -p /var/log/extern_backupcd /opt/backup-system
sudo ./segments/01_validate_config.shShould output:
[01] Configuration valid
[01] Profile: system
[01] Sources: /;/boot/efi
...
If errors occur, review your configuration files.
Test individual segments without running full backup:
# Test Shelly connection (if enabled)
sudo ./segments/03_shelly_power_on.sh
# Wait for device
sudo ./segments/04_wait_device.sh
# Test mount
sudo ./segments/05_mount_backup.sh
# Validate mount
sudo ./segments/06_validate_mount.sh
# Clean up
sudo ./segments/12_unmount_backup.sh
sudo ./segments/13_shelly_power_off.sh# Run backup
sudo /opt/backup-system/main.sh system
# Monitor progress (will take some time for first backup)Expected output:
===============================================================================
BACKUP SYSTEM v2.0.1
===============================================================================
Profile: system
Started: 2026-01-12T10:30:00+01:00
===============================================================================
[01] Validating configuration...
[01] Configuration valid
...
[08] Creating Borg backup archive...
[08] Archive created successfully
[09] Verifying backup integrity...
[09] Verification successful
...
===============================================================================
BACKUP COMPLETED SUCCESSFULLY
===============================================================================
Check logs:
ls -la /var/log/extern_backup/
cat /var/log/extern_backup/system_*.logcd /opt/backup-system/systemd
sudo ./install-systemd-units.shThis installs:
- Mount and automount units
- Backup service (parametric for profiles)
- Weekly timer
# Enable weekly timer
sudo systemctl enable backup-system-weekly.timer
# Start timer
sudo systemctl start backup-system-weekly.timer
# Verify next run time
systemctl list-timers backup-system-weekly.timerExpected output:
NEXT LEFT LAST PASSED UNIT
Sun 2026-01-13 02:00:00 CET 15h left n/a n/a backup-system-weekly.timer
# Trigger backup via systemd
sudo systemctl start backup-system@system.service
# View live logs
journalctl -u backup-system@system.service -f
# Check status
sudo systemctl status backup-system@system.servicecd /opt/backup-system/tests
sudo ./run_all_tests.sh system# List archives (after first successful backup)
sudo borg list /mnt/extern_backup/hostname_nvme0n1_System/borgrepo
# List files in latest archive
sudo borg list /mnt/extern_backup/hostname_nvme0n1_System/borgrepo::your-archive-namecd /opt/backup-system/config/profiles
sudo cp data.env.example data.env
sudo nano data.envAdjust:
BACKUP_UUID- UUID of second HDDBACKUP_SOURCES- What to backupSHELLY_ENABLED- Probably "false" if always-onHDD_SPINDOWN_ENABLED- Probably "false"
sudo nano /etc/systemd/system/backup-data-daily.timer[Unit]
Description=Daily Data Backup Timer
Requires=backup-system@data.service
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.targetEnable:
sudo systemctl enable backup-data-daily.timer
sudo systemctl start backup-data-daily.timersudo /opt/backup-system/main.sh data# Check device exists
ls -la /dev/disk/by-uuid/
# Verify UUID matches config
sudo blkid
# Check Shelly is powered on
curl http://192.168.10.164/rpc/Switch.GetStatus?id=0# Check fstab entry
cat /etc/fstab | grep extern_backup
# Test manual mount
sudo mount /mnt/extern_backup
# Check systemd units
systemctl status mnt-extern_backup.automount# Find what's using the mount
sudo lsof +f -- /mnt/extern_backup
# Kill offending processes or close file managers# Local logs
ls -la /var/log/extern_backup/
tail -f /var/log/extern_backup/system_*.log
# systemd journal
journalctl -u backup-system@system.service -n 100
# Follow live
journalctl -u backup-system@system.service -f# Backup passphrase
sudo cp /root/.config/borg/passphrase ~/borg-passphrase-backup.txt
# Backup configs
sudo tar czf ~/backup-system-configs.tar.gz /opt/backup-system/config/Store these files securely (encrypted USB, password manager, etc.)!
See SYSTEMD.md for detailed restore procedures.
With Verify (Segment 09):
- Duration: ~60 minutes per backup
- Full data integrity check every backup
- Recommended for: Weekly or less frequent backups
Without Verify (Segment 09 disabled):
- Duration: ~2 minutes per backup
- Backup still safe, just no immediate verification
- Recommended for: Daily backups
- Important: Run manual verify monthly!
sudo nano /opt/backup-system/main.shFind this section (around line 40):
MAIN_SEGMENTS=(
"01_validate_config.sh"
"02_init_logging.sh"
"03_shelly_power_on.sh"
"04_wait_device.sh"
"05_mount_backup.sh"
"06_validate_mount.sh"
"07_init_borg_repo.sh"
"08_borg_backup.sh"
"09_borg_verify.sh" # ← Comment out this line
"10_borg_prune.sh"
)Change to:
MAIN_SEGMENTS=(
"01_validate_config.sh"
"02_init_logging.sh"
"03_shelly_power_on.sh"
"04_wait_device.sh"
"05_mount_backup.sh"
"06_validate_mount.sh"
"07_init_borg_repo.sh"
"08_borg_backup.sh"
# "09_borg_verify.sh" # Disabled for daily fast backups
"10_borg_prune.sh"
)Save: Ctrl+X, then Y, then Enter
Option 1: Manual Command
# Run once per month
sudo borg check --verify-data /mnt/extern_backup/creaThink_nvme0n1_System/borgrepoOption 2: Monthly systemd Timer (Automated)
Create monthly verification timer:
# Create timer
sudo tee /etc/systemd/system/backup-system-monthly-verify.timer > /dev/null << 'EOF'
[Unit]
Description=Monthly Backup Verification Timer
[Timer]
OnCalendar=*-*-01 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
EOF
# Create service
sudo tee /etc/systemd/system/backup-system-monthly-verify.service > /dev/null << 'EOF'
[Unit]
Description=Monthly Backup Verification
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/borg check --verify-data /mnt/extern_backup/creaThink_nvme0n1_System/borgrepo
User=root
Environment="BORG_PASSCOMMAND=cat /root/.config/borg/passphrase"
StandardOutput=journal
StandardError=journal
EOF
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable backup-system-monthly-verify.timer
sudo systemctl start backup-system-monthly-verify.timerVerify:
systemctl list-timers backup-system-monthly-verify.timer❌ Common Misconception: "Daily timer runs without verify, weekly timer runs with verify"
✅ Reality:
Both timers use the same main.sh. If Segment 09 is commented out:
- Manual backups: NO verify
- Daily timer: NO verify
- Weekly timer: NO verify
- ALL backups use the same configuration!
For different verify behavior per schedule, you need:
- Two separate profiles (e.g.,
system.envandsystem-full.env) - Two timers pointing to different profiles
- Segment 09 enabled, but separate configs
This is an advanced setup not covered in this guide.
- ✅ Monitor first few scheduled backups
- ✅ Test restore procedure (mount repo, list files)
- ✅ Document your passphrase location
- ✅ Set up second profile for data backup (optional)
- ✅ Configure email notifications (see SYSTEMD.md)
For issues or questions:
- Check logs:
/var/log/extern_backup/ - Review systemd status:
systemctl status backup-system@system.service - Run tests:
sudo ./tests/run_all_tests.sh system - Verify hardware:
lsblk,sudo hdparm -C /dev/sdc