Migrating a Linux Installation with rsync
NoteDifferent Linux installations come with different partition layouts. This guide assumes the layout described in https://barn.bigstool.com/post/arch-linux-installation-guide/, but the general idea should apply to other layouts.
Preparation
Partition layout, mountpoints, mount options of the source disk
Note down this information, as it can be helpful for recreating the partitioning on the target disk. The mount options of root (/) filesystem on the source disk are useful when mounting the source disk in the live environment later.
In the source OS, find the partition layout with:
sudo fdisk -l
Find the mountpoints with:
findmnt
Ignore virtual filesystems such as those mounted on /dev, /sys, /proc, /run, and /tmp. Alternatively, to list only the mountpoints mounted with btrfs and vfat:
findmnt -t btrfs,vfat
Find the mount options with:
cat /etc/fstab
Pay special attention to the entry for the root (/) filesystem. For example:
UUID=6471c5e6-21d5-4c7b-abb7-92f8cc7972a5 / btrfs rw,relatime,compress=zstd:3,ssd,space_cache=v2,subvol=/@ 0 0
In this example, the mount options are:
rw,relatime,compress=zstd:3,ssd,space_cache=v2,subvol=/@
For Btrfs, find the subvolumes with:
sudo btrfs subvolume list -t /
Live environment
Prepare a live USB using the image of the source OS’s distribution. For Arch Linux, refer to https://archlinux.org/download/.
Migration
NoteIt is recommended to perform the migration from a live environment so that the source installation is not running during the process.
Boot into the live environment from the flash drive and navigate to the CLI. It is assumed that the commands below are run as root.
Create mount points
For the source disk:
mkdir /mnt/src
For the target disk:
mkdir /mnt/tgt
Mount the source disk
Find the source disk with:
fdisk -l
NoteHere, we assume that the source disk is
/dev/sdx. Change it to the actual value.
If the root filesystem of the source disk is protected with LUKS, open it first:
cryptsetup open /dev/sdx2 src
Mount the root filesystem with the mount options specified in Partition layout, mountpoints, mount options of the source disk:
mount -o rw,relatime,compress=zstd:3,ssd,space_cache=v2,subvol=/@ /dev/mapper/src /mnt/src
Mount all other partitions as specified in the /etc/fstab on the source disk:
mount --all --target-prefix /mnt/src --fstab /mnt/src/etc/fstab
--all: Mount all filesystems (of the given types) mentioned in fstab (except for those whose line contains the noauto keyword).
--target-prefix: Prepend the specified directory to all mount targets.
--fstab: Specifies an alternative fstab file.
Partition the target disk
Refer to Mount the source disk to find the target disk.
Partition the target disk as needed. refer to https://barn.bigstool.com/post/arch-linux-installation-guide/#partition-the-disk.
Then, mount the root filesystem at /mnt/tgt, and mount all other relevant partitions accordingly.
Verify mountpoints
As a sanity check before running rsync, verify that every target filesystem is mounted at its intended mountpoint:
findmnt
Rsync
Ref: https://wiki.archlinux.org/title/Rsync#Full_system_backup
Perform a dry run first:
rsync -aHAWXSh --numeric-ids --info=progress2 --exclude='/dev/*' --exclude='/proc/*' --exclude='/sys/*' --exclude='/tmp/*' --exclude='/run/*' --exclude='/mnt/*' --exclude='/media/*' --exclude='/lost+found/' --exclude='/.snapshots/*' --dry-run /mnt/src/ /mnt/tgt/
-a: Archive mode is -rlptgoD (recurse into directories, copy symlinks as symlinks, preserve permissions, preserve modification times, preserve group, preserve owner (super-user only), preserve device files (super-user only), and preserve special files) (no -A, -X, -U, -N, -H).
-H: Preserve hard links.
-A: Preserve ACLs (implies --perms).
-W: Copy files whole (w/o delta-xfer algorithm).
-X: Preserve extended attributes.
-S: Turn sequences of nulls into sparse blocks. Tries to handle sparse files efficiently so they take up less space on the destination.
-h: Output numbers in a human-readable format.
--numeric-ids: Don’t map uid/gid values by user/group name. With this option rsync will transfer numeric group and user IDs rather than using user and group names and mapping them at both ends. This prevents the live USB environment from applying its own user mappings to the migrated files.
--info=progress2: Outputs statistics based on the whole transfer, rather than individual files.
--exclude options: Exclude virtual filesystems and Btrfs snapshots. Adjust as needed.
--dry-run: Perform a trial run with no changes made.
TipTo migrate the filesystems on the source OS one by one, add the
-xflag (don’t cross filesystem boundaries) and repeat the process for every relevant filesystem. This can be useful when trying to avoid migrating virtual filesystems when the source OS is running, rather than migrating in a live environment as recommended by this guide. However, note that Btrfs subvolumes and LVM logical volumes are treated as separate filesystems and therefore need to be migrated one by one.
When satisfied, migrate the Linux installation from the source disk to the target disk by running the command above without the --dry-run flag.
Device identifiers
Update the device identifiers in /etc/kernel/cmdline, /etc/fstab and /etc/crypttab so that they refer to the corresponding target-disk partitions, filesystems, and encryption containers. Use blkid and, where appropriate, lsblk to verify the identifiers.
Chroot
Chroot into the target disk:
arch-chroot /mnt/tgt
NoteThe specific command varies by distribution. Check the available options in the live environment, including the rescue/recovery options. Alternatively, for a more general command:
mount --rbind /dev /mnt/tgt/dev mount --make-rslave /mnt/tgt/dev mount --rbind /proc /mnt/tgt/proc mount --make-rslave /mnt/tgt/proc mount --rbind /sys /mnt/tgt/sys mount --make-rslave /mnt/tgt/sys mount --rbind /run /mnt/tgt/run mount --make-rslave /mnt/tgt/run chroot /mnt/tgt /bin/bash
Boot loader
Install the boot loader. Refer to https://barn.bigstool.com/post/arch-linux-installation-guide/#boot-loader.
Initramfs
Regenerate initramfs. For mkinitcpio-based installations, execute:
mkinitcpio -P
Machine ID
Delete the existing machine ID:
rm /etc/machine-id
Create a new one:
systemd-machine-id-setup
Exit
Exit the chroot environment:
exit
Finalize
Write changes to disk:
sync
Unmount the source disk:
umount -R /mnt/src
Unmount the target disk:
umount -R /mnt/tgt
Shut down the live environment:
poweroff
Boot into the target disk to verify that the installation was migrated successfully.
References
https://manpages.debian.org/trixie/rsync/rsync.1.en.html
https://superuser.com/questions/307541/copy-entire-file-system-hierarchy-from-one-drive-to-another
https://forums.debian.net/viewtopic.php?t=159710
https://wiki.archlinux.org/title/Rsync#Full_system_backup
https://wiki.archlinux.org/title/Install_Arch_Linux_from_existing_Linux
https://manpages.debian.org/testing/systemd/systemd-machine-id-setup.1.en.html
ChatGPT
Gemini
Claude