Linux Migration

Migrating a Linux installation with rsync

Migrating a Linux Installation with rsync

๐Ÿ“ Note

Different 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

๐Ÿ“ Note

It 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
๐Ÿ“ Note

Here, 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.

๐Ÿ’ก Tip

To migrate the filesystems on the source OS one by one, add the -x flag (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
๐Ÿ“ Note

The 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

Code licensed under the MIT License; all other content under CC BY-SA 4.0.
Last updated on Sep 05, 2026 17:21 UTC
Built with Hugo
Theme Stack designed by Jimmy