Recreate bootable hard drive from backup image

Situation

I made a mistake and need to fix it by converting the backup image to a fully partitioned hard drive. At the same time I will apply encryption.

Mount qcow2 image

As root:

  • Install qemu-base (ArchLinux): pacman -S qemu-base
  • Make sure the nbd module is loaded: modprobe nbd max_part=8
  • Connect the image as a network block device: qemu-nbd --connect=/dev/nbd0 /path/to/image.qcow2
  • Check: fdisk -l /dev/nbd0
  • Mount it: mount /dev/nbd0 /some/mount/point nota bene: since I messed up, I need to mount the whole disk. Normally one would mount a partition at this point, something like /dev/nbd0p1.
  • cd /some/mount/point

(source)

Prepare the (remote) target drive

Now boot the system that allows you to format the remote machine's drive

Optional for servers

At this point you might want to read the rest of this article before taking your server offline.

My ISP offers a rescue system that can be live-booted through their web interface and runs as root. It also allows root login via ssh.

  • Make sure only one user can ssh in (nano /etc/ssh/sshd_config), then change the password for that user to something really long with passwd user. Or set up an ssh key pair, even better.
  • Enable the ssh daemon on the live boot - in my case it was enough to systemctl start ssh

Partition the disk

I created a 500MB ext2 /boot/ partition, the whole rest goes into one big partition. I used Gparted to create the big partition as ext4. Let's say we now have /dev/sda1 with 500MB and /dev/sda2, our encryption target.

Encrypt

Mostly following this page; the local system is Arch, but the target is Debian stable.

  • Format the partition (again): cryptsetup luksFormat /dev/sda2
  • Open it: cryptsetup open /dev/sda2 system

Since I won't be needing several partitions inside this (I plan to use a swap file later), I'm not going to create a volume group (LVM, the usual recommendation in most tutorials) but instead just make one big filesystem: mkfs.ext4 /dev/mapper/system

Finally, mount both partitions to some temporary mountpoints on the live system:

mount /dev/mapper/system /media/system
mount /dev/sda1 /media/boot

Copy the system over

We will use rsync for this. Remember the mounted qcow2 image, which contains a (theoretically) working OS.

Populate the /boot partition:

rsync -arvPAXH -e ssh /some/mount/point/boot/ root@serverIP:/media/boot

Then the rest, excluding volatile system directories (these shouldn't be present on an offline backup anyhow):

rsync -arvPAXH --exclude={/tmp,/run,/srv,/media,/dev,/boot} -e ssh /some/mount/point/ root@serverIP:/media/system

You should do this as root (I have since learned that rsync can be told to run the ssh process as another user, while still doing things with root privileges on both sides).

Finalize

To install and update GRUB we need to chroot into the mounted partition (source):

cd /media/system
mkdir -p dev/pts proc sys boot run tmp
mount --bind /dev dev && mount --bind /dev/pts dev/pts && \
  mount --bind /proc proc && mount --bind /sys sys && \
  mount --bind ../boot boot
chroot . /bin/bash # The /bin/bash is not always required

Configure GRUB and InitramFS

  • Find out the cryptdevice's UUID with blkid
  • Edit /etc/default/grub and add or edit this line:
    GRUB_CMDLINE_LINUX_DEFAULT="cryptdevice=UUID=XXXXXXXXXXXXXXXXXX:system root=/dev/mapper/system rw"
  • edit /etc/crypttab to add this line: `system UUID=XXXXXXXXXXXXXXXXX
  • Install and update GRUB: grub-install /dev/sda && update-grub
  • Check the configuration: less /boot/grub/grub.cfg
  • update the intrd image: update-initramfs -uv -k all | grep cryptsetup - this should mention cryptsetup - if not, try this: echo "CRYPTSETUP=y" >> /etc/cryptsetup-initramfs/conf-hook and/or see here.

Exit the chroot and Unmount

exit
cd ..
umount system/dev/pts system/dev system/proc system/boot system/sys system

Reboot...

Minor hiccups - two services failed:

  • atd: "Cannot change to /var/spool/cron/atjobs: Permission denied" - the man page has the answer:

    /var/spool/cron/atjobs The directory for storing jobs; this should be mode 700, owner daemon. /var/spool/cron/atspool The directory for storing output; this should be mode 700, owner daemon.

  • logrotate: apparently just needed a restart. Race condition during boot?