LinuxDojo

ZFS System Migration: A Complete Working Guide

This document is a comprehensive guide to your working ZFS backup solution. It includes the full script, an explanation of its components, and detailed instructions for using the backup to migrate your system to new hardware without having to look up additional information.

Your Setup

Part 1: The Automated Backup Process

The script you've created is designed for automated, incremental backups. It runs as the root user, which is necessary to manage the system's ZFS pools and file systems.

The Backup Script: /usr/local/bin/zfsbackup_to_pi.sh

#!/bin/sh

# --- ZFS Backup Configuration ---
# Pool on your FreeBSD machine to be backed up
SOURCE_POOL="zroot"
# Destination dataset on your Raspberry Pi (parent pool is 'tank')
REMOTE_DESTINATION="tank/fbsdserver-backup"
# Raspberry Pi user and IP address
REMOTE_USER="joe"
REMOTE_HOST="192.168.1.12"
# A tag to identify snapshots created by this script
SNAPSHOT_TAG="auto-backup"

# --- Script Logic ---
# Get the full name of the last snapshot created by this script
LATEST_SNAPSHOT=$(zfs list -H -t snapshot -o name -S creation "${SOURCE_POOL}" | grep "${SNAPSHOT_TAG}" | head -n 1)

# Create a new snapshot with today's date and the tag
DATE=$(date +%Y-%m-%d)
NEW_SNAPSHOT_NAME="${SOURCE_POOL}@${SNAPSHOT_TAG}_${DATE}"

# Check if a snapshot with today's date already exists to prevent an error
if zfs list -H -t snapshot | grep -q "${NEW_SNAPSHOT_NAME}"; then
    echo "Snapshot ${NEW_SNAPSHOT_NAME} already exists. Exiting."
    exit 0
fi

echo "Creating new snapshot: ${NEW_SNAPSHOT_NAME}"
zfs snapshot -r "${NEW_SNAPSHOT_NAME}"

# Send the new snapshot incrementally or as a full send if no previous snapshots exist
if [ -z "${LATEST_SNAPSHOT}" ]; then
    echo "No previous snapshot found. Performing a full send."
    zfs send -R "${NEW_SNAPSHOT_NAME}" | ssh "${REMOTE_USER}"@"${REMOTE_HOST}" "sudo zfs receive -F '${REMOTE_DESTINATION}'"
else
    echo "Sending incremental stream from ${LATEST_SNAPSHOT}..."
    zfs send -R -i "${LATEST_SNAPSHOT}" "${NEW_SNAPSHOT_NAME}" | ssh "${REMOTE_USER}"@"${REMOTE_HOST}" "sudo zfs receive -F '${REMOTE_DESTINATION}'"
fi

echo "Backup complete."

How the Script Works

The Cron Job

The crontab command schedules jobs to run automatically. It's important to understand the difference between editing your personal crontab and the root user's.

Your working cron job runs as root and is set to execute your script every Sunday at 3:00 AM.

# crontab entry for the root user
0 3 * * 0 /usr/local/bin/zfsbackup_to_pi.sh > /dev/null 2>&1

Part 2: The System Migration Process

When you get your new server, here are the steps to use this backup to restore a complete, working system.

What Your Backup Contains

Your ZFS backup is not just a copy of files. It's a block-level replication of your entire system's state, including:

Step 1: Prepare the New Machine

On your new server, install a minimal version of FreeBSD 14-RELEASE. This ensures you have a functioning bootloader and a ZFS pool to receive the data. Once complete, you will destroy the new zroot pool to prepare for the transfer.

Step 2: Transfer the Final Data from the Raspberry Pi

On your new server, run the following commands to pull the latest backup from the Raspberry Pi.

# Destroy the temporary zroot pool from the new install
zfs destroy -r zroot

# Pull the final, latest backup from your Raspberry Pi
# The snapshot name is the most recent one on your Pi's 'tank' pool
ssh joe@192.168.1.12 "sudo zfs send -R tank/fbsdserver-backup@auto-backup_2025-07-26" | zfs receive -F zroot

Step 3: Adjust System Configuration for New Hardware

This is the most critical step for making your machine bootable and functional. Your new hardware is different, so a few settings must be adjusted.

Step 4: Reboot and Verify

Once you've made these changes, reboot your new machine. It will boot into a fully functional clone of your original FreeBSD server, with all your services and custom configurations intact.