Title: Qubes OS backup transfer from old to new computer
       Author: Solène
       Date: 24 December 2023
       Tags: security qubesos networking
       Description: In this article you will learn how to efficiently move all
       the qubes from an old Qubes OS system to a new one
       
       # Introduction
       
       With the recent release of Qubes OS 4.2, I took the opportunity to
       migrate to a newer laptop (from a Thinkpad T470 to a NovaCustom NV41)
       so I had to backup all the qubes from the T470 and restore them on the
       NV41.
       
       The fastest way to proceed is to create the backups on the new laptop
       directly from the old one, which is quite complicated to achieve due to
       Qubes OS compartmentalization.
       
       In this guide, I'll share how I created a qube with a network file
       server to allow one laptop to send the backups to the new laptop.
       
 (HTM) Qubes OS official project website
       
       Of course, this whole process could be avoided by using a NAS or
       external storage, but they are in my opinion slower than directly
       transferring the files on the new machine, and you may not want to
       leave any trace of your backups.
       
       # Explanation about the setup
       
       As the new laptop has a very fast NVME disk, I thought it would be nice
       to use it for saving the backups as it will offload a bit of disk
       activity for the one doing backups, and it shouldn't be slowed down
       during the restore process even if it has to write and read the backups
       at the same time.
       
       The setup consists in creating a dedicated qube on the new laptop
       offering an NFS v4 share, make the routing at the different levels, and
       mount this disk in a qube on the old laptop, so the backup could be
       saved there.
       
       I used a direct Ethernet connection between the two computers as it
       allows to not think much about NFS security
       
       # Preparing the backup receiver
       
       ## Storage qube configuration
       
       On the new laptop, create a standalone qube with the name of your
       choice (I'll refer to it as `nfs`), the following commands have been
       tested with the fedora-38-xfce template. Make sure to give it enough
       storage space for the backup.
       
       First we need to configure the NFS server, we need to install the
       related package first:
       
       ```
       $ sudo dnf install nfs-utils
       ```
       
       After this, edit the file `/etc/exports` to export the path
       `/home/user/backup` to other computers, using the following content:
       
       ```
       /home/user/backup *(rw,sync)
       ```
       
       Create the directory we want to export, and make `user` the owner of
       it:
       
       ```
       install -d -o user /home/user/backup
       ```
       
       Now, run the NFS server now and at boot time:
       
       ```
       systemctl enable --now nfs-server
       ```
       
       You can verify the service started successfully by using the command
       `systemctl status nfs-server`
       
       You can check the different components of the NFS server are running
       correctly, if the two following commands have an output this mean it's
       working:
       
       * `ss -lapteun | grep 2049`
       * `ss -lapteun | grep 111`
       
       Allow the NFS server at the firewall level, run the following commands
       AND add them at the end of `/rw/config/rc.local`:
       
       ```
       nft add rule qubes custom-input tcp dport 2049 accept
       nft add rule qubes custom-input udp dport 111 accept
       ```
       
       ## Route the service from the physical LAN
       
       Now the service is running within the qube, we need to allow the remote
       computer to reach it, by default the network should look like this:
       
       We will make sys-net to nat the UDP port 111 and TCP port 2049 to
       sys-firewall, which will nat them to the nfs qube, which will already
       accept connections on those ports.
       
       ```
                                +------------------------------------------------+
         +--------+             |               DESTINATION SYSTEM               |
         | SOURCE |  ethernet   |  +---------+     +--------------+     +-----+  |
         | SYSTEM | <-------->  |  | sys-net | --> | sys-firewall | --> | nfs |  |
         +--------+             |  +---------+     +--------------+     +-----+  |
                                +------------------------------------------------+
       ```
       
       ### sys-net routing
       
       Write the following script inside the `sys-net` qube of the destination
       system, make sure to update the value of the variable `DESTINATION`
       with `sys-firewall`'s IP address, it can be found by looking at the
       qube settings.
       
       ```
       #!/bin/sh
       
       PORT=111
       DESTINATION=10.138.31.246
       
       if ! nft -nn list table ip qubes | grep "chain nat {" ; then
               nft add chain qubes nat { type nat hook prerouting priority dstnat\; }
       fi
       
       nft add rule qubes custom-input udp dport "${PORT}" accept
       nft add rule qubes custom-forward udp dport "${PORT}" accept
       nft add rule qubes nat iifname != "vif*" udp dport "${PORT}" dnat "${DESTINATION}"
       
       PORT=2049
       nft add rule qubes custom-input tcp dport "${PORT}" accept
       nft add rule qubes custom-forward tcp dport "${PORT}" accept
       nft add rule qubes nat iifname != "vif*" tcp dport "${PORT}" dnat "${DESTINATION}"
       ```
       
       Make the script executable by running the command `chmod +x` on the
       script file. You will execute them later once the network is safe.
       
       ### sys-firewall routing
       
       Write the following script inside the `sys-firewall` qube of the
       destination system, make sure to update the value of the variable
       `DESTINATION` with `nfs`'s IP address, it can be found by looking at
       the qube settings.
       
       ```
       #!/bin/sh
       
       PORT=111
       DESTINATION=10.137.0.10
       
       if ! nft -nn list table ip qubes | grep "chain nat {" ; then
               nft add chain qubes nat { type nat hook prerouting priority dstnat\; }
       fi
       
       nft add rule qubes custom-input udp dport "${PORT}" accept
       nft add rule qubes custom-forward udp dport "${PORT}" accept
       nft add rule qubes nat iifname != "vif*" udp dport "${PORT}" dnat "${DESTINATION}"
       
       PORT=2049
       nft add rule qubes custom-input tcp dport "${PORT}" accept
       nft add rule qubes custom-forward tcp dport "${PORT}" accept
       nft add rule qubes nat iifname != "vif*" tcp dport "${PORT}" dnat "${DESTINATION}"
       ```
       
       Make the script executable by running the command `chmod +x` on the
       script file. You will execute them later once the network is safe.
       
       # Backup process
       
       On the source system, we need to have a running qube that will mount
       the remote NFS server, this can be a disposable qube, an AppVM qube
       with temporary changes, a standalone etc...
       
       ## Mounting qube
       
       On the mounting qube, run the following command to install the NFS
       tools we need:
       
       ```
       dnf install nfs-utils
       ```
       
       ## Configure both systems network
       
       In this step, you need to configure the network with the direct
       Ethernet cable, so the two systems can speak to each other, please
       disconnect from any Wi-Fi connections as you didn't set any security
       for the file transfer (it's encrypted but still).
       
       You can choose any address as long as the two hosts are in the same
       subnet, an easy pick could be `192.168.0.2` for the source system, and
       `192.168.0.3` for the new system.
       
       Now, both systems should be able to ping each other, it's time to
       execute the scripts in `sys-firewall` and `sys-net` to enable the
       routing.
       
       On the "mounting" qube, run the following command as root to mount the
       remote file system:
       
       ```
       mount.nvfs4 192.168.0.3:/home/user/backup /mnt
       ```
       
       You can verify it worked if the output of `df` shows a line starting by
       `192.168.0.3:/home/user/backup`, and you can ensure your user can
       actually write in this remote directory by running `touch /mnt/test`
       with the regular user `user`.
       
       Now, we can start the backup tool to send the backup to the remote
       storage.
       
       ## Run the backup
       
       In the source system dom0, run the Qubes OS backup tool, choose the
       qubes you want to transfer, uncheck "Compress backups" (except if you
       are tight on storage for the new system) and click on "Next".
       
       In the field "Target qube", select the "mounting qube" and set the path
       to `/mnt/`, choose an encryption passphrase and run the backup.
       
       If everything goes well, you should see a new file named
       `qubes-backup-YYYY-MM-DDThhmmss` in the directory `/home/user/backups/`
       of the `nfs` qube.
       
       ## Restore the backups
       
       In the destination system dom0, you can run the Restore backup tool to
       restore all the qubes, if the old `sys-net` and `sys-firewall` have any
       value, you may want to delete yours first otherwise the restored one
       will be renamed.
       
       ## how to restore dom0 $home
       
       When you backup and restore dom0, only the directory `/home/` is part
       of the backup, so it's only about the desktop settings themselves and
       not the Qubes OS system configuration. I actually use versioned files
       in the salt directories to have reproducible Qubes OS machines because
       the backups aren't enough.
       
 (HTM) Blog post: Using git bundle to synchronize a repository between Qubes OS dom0 and an AppVM
 (HTM) Blog post: Qubes OS dom0 files workflow using fossil
       
       When you restore dom0, it creates a directory
       `/home/solene/home-restore-YYYY-MM-DDThhmmss` on the new dom0 that
       contains the previous `/home/` directory.
       
       Restoring this directory verbatim requires some clever trick as you
       should not be logged in for the operation!
       
       * reboot qubes OS
       * don't log in, instead press ctrl+alt+F2 to run commands as the root
       user in a console (tty)
       * move the backup outside `/home/solene` with `mv
       /home/solene/home-restore* /home/`
       * delete your home directory `/home/solene` with `rm -fr /home/solene`
       * put the old backup at the right place with `mv
       /home/home-restore*/dom0-home/solene /home/`
       * press ctrl+alt+F1
       * log-in as user
       
       Your desktop environment should be like you left if during the backup.
       If you used some specific packages or desktop environment, make sure
       you also installed the according packages in the new dom0
       
       # Cleaning up
       
       After you restored your backups, you can remove the scripts in
       `sys-firewall` and `sys-net` and even delete the nfs qube.
       
       # Conclusion
       
       Moving my backup from the old system to the new one was pretty
       straightforward once the NFS server was established, I was able to
       quickly have a new working computer that looked identical to the
       previous one, ready to be used.