Data loss is one of those things we always assume won’t happen to us—until it does.
For us, that wake-up call came when my wife’s laptop suddenly crashed. Years of personal files, documents, and photos were gone in an instant. The worst part? All her data had been saved locally on the laptop’s internal hard drive. None of it had been backed up to our home server, even though we had a NAS (Network Attached Storage) sitting right there—underused and mostly idle.
That incident was the jolt we needed.
We realized that while setting up a NAS is a great first step, it’s not enough if devices around the house aren’t actually using it. And even then, relying solely on the NAS without backing that up is just moving the vulnerability one layer deeper.
That’s when I decided to make our home data workflow more resilient—automating backups from all laptops to the NAS, and then backing up the NAS itself to an external hard drive using BackupPC, a powerful and efficient backup system.
This article is a result of that experience. If you’re someone who has a home server setup or is considering one, and you’re serious about preserving your data, this write-up might help you avoid the mistakes we made—and save you from learning the hard way.
Part 1: The System
After the crash, it was clear we needed a centralized, always-available, and secure storage solution for the household. Fortunately, we already had the hardware—a Gentoo Linux server—so the next step was to turn it into a functional NAS (Network Attached Storage).
The NAS Setup
I configured the NAS using a combination of NFS and Samba:
- NFS (Network File System) was set up primarily for Linux-based devices (including the server itself), given its performance and integration with Unix-like systems.
- Samba was configured to allow seamless access from the Windows laptops in the house. All shared folders on the NAS were exposed via Samba shares with proper user permissions and access control.
The goal was to make the NAS the default location for all files—documents, downloads, photos, everything. This way, the laptops would essentially function as terminals, and no important data would be stored locally on them anymore. Losing a laptop wouldn’t mean losing data.
Secure Remote Access
When we’re at home, all devices connect to the NAS over the local network. But what about when someone’s on the road or working remotely?
To solve that, I set up a Cloudflare Tunnel to securely expose the NAS to the internet without having to open any ports on the router. This approach provides an encrypted, authenticated connection that’s also protected from common attack vectors like port scanning or brute force attempts.
Now, even when away from home, the same mapped network drives remain accessible, making the experience consistent and seamless for all users.
Part 2: Backing Up the NAS Using BackupPC
With all our laptops configured to save data directly to the NAS, the next step was clear: back up the NAS itself. Centralizing storage simplifies backup tremendously — now, I only need to back up one machine (the NAS) instead of each laptop individually.
For this purpose, I chose BackupPC, a high-performance, enterprise-grade backup system that works exceptionally well for home setups too.
Why BackupPC?
BackupPC stood out for a few reasons:
- It’s open-source and actively maintained.
- It supports incremental backups, saving only changes after the first full backup — making it space- and time-efficient.
- It offers a web-based interface for managing and restoring backups.
- It can back up via various protocols like rsync, tar over SSH, SMB, etc.
- It uses deduplication, so if multiple files or even blocks are identical, they’re stored only once.
For a home setup with limited storage and multiple laptops sharing similar files (e.g., OS updates, duplicate media), deduplication is a huge win.
Backup Strategy
But instead of installing it directly on the Gentoo host, I opted to run BackupPC inside a Docker container. This approach keeps the system modular, easier to manage, and avoids cluttering the base OS with additional packages and dependencies.
Why Docker + BackupPC?
Running BackupPC in a Docker container offered several advantages:
- Isolation: The backup environment is sandboxed, reducing the risk of interference with the main OS or other services on the NAS.
- Portability: Configuration and volumes can be easily migrated to another system if needed.
- Ease of updates: Pulling newer versions of BackupPC is straightforward without worrying about compatibility with Gentoo’s package manager.
- Cleaner management: Everything related to backups (configs, logs, data) is encapsulated in a single container.
Backup Setup Overview
Here’s how the setup works:
- Host System: Gentoo Linux (running Docker)
- Container: Official or community-maintained BackupPC Docker image
- Backup Source: The NAS data directories (shared via local mounts inside the container)
- Backup Destination: An external USB hard drive, mounted on the host and passed through to the container as a volume
- Access & Control: BackupPC’s web interface is exposed securely over the local network
This gives us a rolling backup history, allowing restoration not just of the latest data, but also previous versions if needed — a feature that helped us recover an accidentally deleted file more than once.
Reliability & Safety Measures
- The external HDD is only mounted during the backup window and unmounted afterward to protect against potential ransomware or accidental deletion.
- BackupPC sends email notifications on backup status, failures, or warnings.
Part 3: Automating Backups When the External HDD Is Connected
Once BackupPC was up and running in a Docker container, the final step was automation. I wanted backups to run automatically whenever the external HDD (used for backup storage) was connected.
However, since the external HDD is not always plugged in — for safety and wear reasons — the system needed to:
- Detect when the correct external HDD is connected,
- Start the Docker container running BackupPC (if not already running),
- Trigger an incremental backup.
It sounds straightforward, but due to Gentoo using OpenRC (rc-sysinit) instead of systemd, I had to take a slightly different route.
Challenge: Udev’s Restricted Environment
My first approach was to trigger the backup directly from a udev rule. However, udev is very limited:
- No access to a full shell
- Cannot interact with Docker reliably
- No environment or logging
- Commands often silently fail
So instead, I used udev as a simple event trigger, which then starts an OpenRC service. That service runs a proper shell script that handles the real backup logic.
The Working Solution: Udev + OpenRC Service
Here’s how the final solution works:
- Udev rule detects when the external HDD is connected
- Udev triggers a custom OpenRC service
- The OpenRC service executes a script that:
- Verifies the correct HDD is mounted (using its UUID)Starts the BackupPC Docker container (if not already running)
- Triggers an incremental backup via BackupPC CLI
1. Get the UUID of Your Backup Drive
blkid
Look for the UUID of the external HDD (e.g., 1234-ABCD).
2. Create the Udev Rule
I used a udev rule to detect when any block device is added. Specifically, it watches for new sd* devices and triggers an OpenRC init script asynchronously:
File: /etc/udev/rules.d/99-backuppc.rules
ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd*", RUN+="/bin/sh -c '/etc/init.d/backuppc-usb-backup start > /dev/null 2>&1 &'"
Note: We use /bin/sh -c and background the command (&) to avoid blocking udev’s processing, which must be non-blocking and fast
This script (backuppc-usb-backup) will not run the backup directly — it will instead call an OpenRC service.
The OpenRC Init Script
The real logic is handled by an OpenRC-compatible init script located at:
File: /etc/init.d/backuppc-usb-backup
#!/bin/sh
### BEGIN INIT INFO
# Provides: backuppc-usb-backup
# Required-Start: $local_fs $network
# Required-Stop: $local_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start BackupPC USB backup job
### END INIT INFO
BACKUP_SCRIPT="/usr/local/bin/mount_and_backup.sh"
LOG_FILE="/var/log/backuppc_service.log"
PID_FILE="/var/run/backuppc-usb-backup.pid"
TARGET_UUID="<UUID_of_the_drive"
case "$1" in
start)
echo "Starting BackupPC USB backup service..." >> "$LOG_FILE"
if [ -f "$PID_FILE" ]; then
echo "Service is already running." >> "$LOG_FILE"
exit 1
fi
echo "Scanning for device with UUID $TARGET_UUID..." >> "$LOG_FILE"
MAX_RETRIES=10
RETRY_DELAY=5
DEVICE_PATH=""
for i in $(seq 1 $MAX_RETRIES); do
DEVICE_PATH=$(/usr/bin/timeout 5 /usr/bin/blkid -U "$TARGET_UUID")
if [ -n "$DEVICE_PATH" ]; then
echo "Found matching device at $DEVICE_PATH." >> "$LOG_FILE"
nohup "$BACKUP_SCRIPT" >> "$LOG_FILE" 2>&1 &
echo $! > "$PID_FILE"
echo "Backup service started with PID: $(cat "$PID_FILE")" >> "$LOG_FILE"
exit 0
fi
echo "Retry $i/$MAX_RETRIES: No matching device found. Waiting $RETRY_DELAY seconds..." >> "$LOG_FILE"
sleep $RETRY_DELAY
done
echo "Max retries exceeded. No matching device found. Aborting." >> "$LOG_FILE"
exit 0
;;
stop)
echo "Stopping BackupPC USB backup service..." >> "$LOG_FILE"
if [ ! -f "$PID_FILE" ]; then
echo "Service is not running." >> "$LOG_FILE"
exit 1
fi
if kill "$(cat "$PID_FILE")" >/dev/null 2>&1; then
echo "Service stopped." >> "$LOG_FILE"
else
echo "Failed to stop process or process already terminated." >> "$LOG_FILE"
fi
rm -f "$PID_FILE"
;;
*)
echo "Usage: $0 {start|stop}" >> "$LOG_FILE"
exit 1
;;
esac
exit 0
What This Does
- When any sd* block device is added, the udev rule triggers the OpenRC script.
- The script checks (up to 10 times, with 5-second intervals) if the correct HDD (by UUID) is present.
- Once found, it calls a custom script (mount_and_backup.sh) to mount the drive (if needed), start the Docker container, and trigger BackupPC.
- It records the process PID so it can be stopped or managed later.
- All output is logged to /var/log/backuppc_service.log for review and troubleshooting.
Robust and Controlled Automation
This approach:
✅ Works cleanly with OpenRC (rc-sysinit)
✅ Avoids udev’s restricted shell by offloading to a full script
✅ Allows for mount verification, retries, and backgrounding
✅ Logs everything, so nothing is a black box
✅ Makes the system fully automatic: plug in the HDD, and the backup just runs
Part 4: The Automation Script – mount_and_backup.sh
With all the infrastructure in place — udev trigger, OpenRC init service, and Docker-based BackupPC — the last piece was a script that does the actual work:
- Mounts the backup drive,
- Starts the BackupPC container,
- Triggers an incremental backup,
- Shuts everything down once done.
Here’s a breakdown of the script I created: /usr/local/bin/mount_and_backup.sh.
🧠 Purpose
This script is designed to:
- Mount the external backup drive using its known configuration,
- Start the backuppc-app Docker container,
- Wait until the BackupPC server is ready,
- Trigger an incremental backup job for the NAS,
- Cleanly shut down:
- Stop the containerUnmount the drive
- Stop the associated init service
All of this happens automatically, without manual intervention.
🔧 Script Highlights
Here’s the complete logic, followed by explanations:
Locking and Logging
LOCK_FILE="/var/run/mount_and_backup.lock"
LOG_FILE="/var/log/backuppc_auto.log"
# Exit if already running
if [ -f "$LOCK_FILE" ]; then
echo "$DATE_TIME: Script is already running. Exiting." >> "$LOG_FILE"
exit 0
fi
# Set lock and ensure it's removed on exit
trap "rm -f $LOCK_FILE" EXIT
echo "$$" > "$LOCK_FILE"
🔐 Prevents accidental double execution
📝 Logs everything for audit and troubleshooting
Mount the External Drive
HDD_MOUNT_POINT="/mnt/external-HDD"
MOUNT_CMD="mount -t btrfs -o defaults,compress=zstd,subvol=backuppc-backup /dev/sdd3 $HDD_MOUNT_POINT"
# Check and mount if needed
if ! mountpoint -q "$HDD_MOUNT_POINT"; then
echo "$DATE_TIME: HDD not mounted. Attempting to mount..."
$MOUNT_CMD
- Checks if the drive is already mounted.
- Mounts using btrfs with compression and a specific subvolume.
- Verifies mount success before proceeding.
Start the Docker Container
docker start "$BACKUPPC_CONTAINER"
- Brings up the BackupPC container (assumed already created via Docker Compose).
Wait for BackupPC to Be Ready
# Wait up to 90 seconds for the daemon to appear
until docker exec --user backuppc "$BACKUPPC_CONTAINER" pgrep -f 'BackupPC'; do
sleep 5
done
- Loops until the BackupPC process is detected inside the container.
- Prevents triggering the backup too early.
Trigger the Incremental Backup
docker exec --user root "$BACKUPPC_CONTAINER" /usr/local/BackupPC/bin/BackupPC_dump -i <server_ip>
- Performs an incremental backup for a specific client (in this case, the NAS).
- You can easily extend this to include multiple hosts or run a full job cycle.
Cleanup
docker stop "$BACKUPPC_CONTAINER"
umount "$HDD_MOUNT_POINT"
/etc/init.d/backuppc-usb-backup stop
- Stops the container to free system resources.
- Unmounts the drive to allow for safe removal.
- Stops the OpenRC service to reset state.
✅ Why This Works Well
- Fully autonomous: plug the drive in, walk away.
- Log-based: everything is recorded in /var/log/backuppc_auto.log.
- Safe: avoids concurrency, only acts if the correct drive is present.
- Clean: container and device are shut down after use.
- Modular: easily adaptable for multiple clients or schedules.
🧭 What’s Next?
This completes the core of the automated backup system. You now have:
- A reliable NAS for central data storage,
- BackupPC managing incremental backups,
- External HDD automation via udev + OpenRC + scripting.
Part 5: Formatting the Backup Disk – Btrfs vs ZFS
With the automation infrastructure ready, the last foundational step was preparing the external USB backup drive. Choosing the right filesystem for backup storage is not just about formatting — it’s about ensuring data integrity, space efficiency, and ease of recovery.
After evaluating both Btrfs and ZFS, I chose Btrfs for this project. Below, I’ll walk through why, and also outline the technical comparison to help others make an informed choice.
🔧 What the Backup Drive Needs
Since the drive is used for scheduled, automated backups of the NAS, the filesystem should ideally support:
- Efficient compression to save space
- Checksumming to detect silent data corruption
- Snapshots, in case I want to freeze a backup state before running the next one
- Good Linux integration
- Lightweight operation — especially important on a home server
Both Btrfs and ZFS offer these features. But they differ significantly in how they implement them and what trade-offs they require.
⚙️ Why I Chose Btrfs
I formatted the backup drive with Btrfs, mounted using the following options:
mount -t btrfs -o defaults,compress=zstd,subvol=backuppc-backup /dev/sdd3 /mnt/external-HDD
Here’s why Btrfs was the right choice for my setup:
- ✅ Built-in compression: I used zstd, which offers a great balance of compression ratio and speed — ideal for backing up large files and many small ones.
- ✅ Checksumming: Btrfs ensures both data and metadata are checksummed, detecting corruption early.
- ✅ Snapshots: Although not as powerful as ZFS snapshots, Btrfs still allows me to take snapshots of the backup volume if needed — e.g., before running a risky backup or cleanup job.
- ✅ Linux-native: As a kernel-native filesystem, Btrfs works out of the box on Gentoo, without any need to compile external modules or deal with license issues.
- ✅ Low resource usage: Btrfs has a much smaller RAM footprint compared to ZFS, which is ideal on a home server that also runs Docker containers.
⚖️ ZFS: A Powerful Alternative
I also considered ZFS, particularly the OpenZFS implementation available for Linux. It is widely regarded as one of the most robust and battle-tested filesystems for backup and data integrity. However, for my use case, it introduced a few constraints:
| Feature | ZFS | Btrfs |
| License | CDDL (not in mainline Linux) | GPL-compatible, kernel-native |
| Kernel integration | Requires external kernel modules | Built into Linux kernel |
| RAM requirements | High (1 GB per 1 TB recommended) | Low (<512 MB usable) |
| Compression | Yes (lz4, zstd, others) | Yes (zlib, lzo, zstd) |
| Snapshots | Excellent (send/receive, clones) | Good (basic local snapshots) |
| Checksumming | Very strong | Strong (covers data & metadata) |
| Recovery tools | Advanced (e.g., scrub, resilver) | Basic (btrfs scrub, etc.) |
| Ease of setup | Moderate to complex | Simple |
| Best use case | Multi-disk pools, enterprise setups | Single-disk or light RAID |
ZFS truly shines in multi-disk, redundant, or enterprise environments. If I were building a ZFS pool across multiple drives, or needed snapshot replication (e.g., offsite), I would strongly consider it. But for a single USB disk used periodically, the complexity and memory overhead were unnecessary.
📦 Formatting the Drive
Once Btrfs was selected, I formatted the drive as follows:
mkfs.btrfs -f -L backupdrive /dev/sdd3
I then created a dedicated subvolume for the BackupPC data:
mount /dev/sdd3 /mnt/external-HDD
btrfs subvolume create /mnt/external-HDD/backuppc-backup
umount /mnt/external-HDD
And mounted it during backup like this:
mount -t btrfs -o defaults,compress=zstd,subvol=backuppc-backup /dev/sdd3 /mnt/external-HDD
🧾 Final Thoughts
Btrfs gave me the features I needed — compression, checksums, snapshots, and easy Linux integration — without the additional complexity or resource usage of ZFS. It’s not without its quirks, but for a single-disk backup target on a Gentoo Linux home server, it strikes a very good balance.
That said, ZFS remains an excellent option for users with:
- Higher RAM capacity
- Multi-disk arrays
- Need for snapshot replication
- Enterprise-grade requirements
Part 6: Lessons Learned
This home backup project — born out of the panic of a laptop crash — has been both educational and deeply satisfying. What started as a reactive effort to protect data evolved into a structured, automated, and resilient backup system. Along the way, I learned several important lessons that may help others building something similar:
🧨 1. Data Loss Will Happen — Eventually
The catalyst for this entire setup was a personal one: my wife’s laptop drive failed without warning, and her data was stored entirely on that local disk. There was no backup. That incident was a stark reminder that hard drives fail, and often silently. The cost of prevention is tiny compared to the cost of loss.
🧱 2. Backups Are Not Just Copies — They’re Systems
A good backup system isn’t just about having a second copy of data. It’s about:
- Automation (so you don’t forget)
- Isolation (so the backup isn’t affected by local failures)
- Verification (so you know it’s working)
- Restorability (so it’s easy to get data back when needed)
Using BackupPC with scheduled, incremental backups and compression ensured that I wasn’t just copying data, but backing it up intelligently and efficiently.
🧠 3. Centralization Helps — But Only If You Use It
Before the crash, the NAS was already present on the network — but unused. Data was still being saved on individual laptops. This exposed a key issue: users default to what’s easy, even if there’s a better alternative available.
We solved this by configuring laptops to store everything on the NAS via Samba, removing the temptation to use local-only folders. The lesson? Build systems around people, not just technology.
🔄 4. Automation Should Be Event-Driven When Possible
One of the more satisfying aspects was getting backups to trigger automatically when the external HDD is plugged in. Instead of relying on cron or a manual step, I used:
- udev to detect device connection,
- An OpenRC init script to coordinate the response,
- A custom shell script to mount, start, backup, and shut down.
This event-driven approach is not only elegant but also reliable — no need to worry about missed schedules or human forgetfulness.
🧰 5. Gentoo and OpenRC Can Handle It — But It Takes Work
Many tutorials assume a systemd-based Linux distro, but my setup uses Gentoo with OpenRC (rc-sysinit). It meant I had to write my own init scripts and think carefully about service orchestration. The reward? A system that’s lean, fully under my control, and tailored to my needs.
Lesson: If you understand your tools, minimalism scales.
🗃 6. Filesystem Choice Matters
Between Btrfs and ZFS, I chose Btrfs due to its lighter footprint, kernel-native support, and feature set that matched my single-disk use case. But both filesystems are robust and worth understanding.
Takeaway: Don’t just format your backup drive with ext4 by habit — choose a filesystem that’s built for data integrity and backup.
🔒 7. Backups Need to Be Verified, Not Assumed
Even with automation in place, I realized it’s important to:
- Monitor logs (/var/log/backuppc_auto.log)
- Periodically test restores
- Occasionally do a manual dry-run or diff check
A backup system that silently fails is worse than no system at all — it gives you false confidence.
📈 Final Reflection
The project taught me that a home-grown backup solution doesn’t need to be complex — but it must be intentional. Every choice — from the filesystem to the automation — affects the reliability and usability of the end system. I’m now confident that:
- Our data is centralized,
- Backups are versioned and space-efficient,
- The process is repeatable and self-maintaining,
- Recovery, if ever needed again, will be painless.
Part 7: BackupPC Can Also Handle Decentralized Devices
While my current approach ensures all data is centralized on the NAS, it’s worth highlighting that BackupPC is fully capable of backing up remote machines directly — including laptops — even if they store data locally.
In fact, one of BackupPC’s strengths is its ability to:
- Automatically wake up sleeping laptops (via Wake-on-LAN, if configured),
- Run scheduled incremental or full backups over the network,
- Use rsync, SMB, or tar over SSH to access files securely,
- Deduplicate data across multiple clients to save space,
- Handle compression and versioning for each client.
This means that even in a more traditional, decentralized home setup — where family members still store files on their individual laptops — BackupPC can still provide comprehensive backups, without needing to change how people use their devices.
In fact, I still use this feature to back up a few machines in parallel with the NAS-based strategy, just as an added layer of protection.
What began as a reactive fix to an unfortunate data loss has evolved into a proactive, automated, and reliable backup system tailored for a home environment. By combining open-source tools like BackupPC, Btrfs, udev, and Docker on a Gentoo Linux server, I’ve built a solution that is both technically sound and practically sustainable. The system now ensures that all family data is centralized, versioned, and regularly backed up — with minimal manual intervention. More importantly, it brings peace of mind. If you’re managing digital data at home, I encourage you to build something similar — because it’s not a matter of if data loss will happen, but when.