Based on this guide and this blog-post, I decided I wanted to try "deploying" GNU Guix on a Hetzner Cloud Server (aka VPS).
It seems the only requirements for Hetzner guest images are:
virtio_*
drivers- Plain non-EFI grub
- dhcp
The process was surprisingly straight-forward! The only necessary step was really to copy the disk image from guix system image hetzner.scm
over to the VPS's /dev/sda
.
First, a little background. You can use guix system vm ...
to launch a VM on your host machine, but Guix also has a command to produce a complete disk image: guix system image ...
. It's not overly complicated to launch this manually with qemu
. Here's how you might do that:
I think
if=virtio
only works since we have added thevirtio_scsi
initrd-module to our guest system (this is used by Hetzner and probably all VPS providers for performance reasons. If your guest doesn't have that virtio disk driver, you can just omitif=virtio
and go for qemu's default at a small price in disk IO performance.
klm@pal ~$ disk=$(guix system image ~/src/guix/gnu/system/examples/hetzner.scm)
klm@pal ~$ file $disk
/gnu/store/19s26kg73vag3smmlfhw88q6pgs39k8h-disk-image: DOS/MBR boot sector
klm@pal ~$ qemu-system-x86_64 --enable-kvm -m 512M -drive file=$disk,format=raw,if=virtio -snapshot
So that's a GNU Guix operating system created for us and running in a qemu
instance locally. Now, in order to get this working on Hetzner, we're simply going to overwrite the existing VPS disk image with our newly created $disk
.
I was happy to find this was relatively easy to do using Hetzner's "rescue mode". Navigate to the "RESCUE" tab in your web Cloud Console, and click "ENABLE RESCUE & POWER CYCLE". The reason we're using this mode is that we can't really overwrite /dev/sda
which its partitions are mounted or otherwise in use. The rescue boot does not use /dev/sda
.
This should promt you for a ssh public key. Enter your suitable settings and hit "ENABLE RESCUE & POWER CYCLE":
From here, you can use the web-console to make sure you rescue system is up and running. Click the "Console" button, located at the top-right. Once the "rescue boot" has completed, it should look like this:
Next, we're going to send our raw disk image over ssh
and dump it onto /dev/sda
. Let's check that our rescue mode ssh is up and running:
klm@pal ~$ ssh -o 'StrictHostKeyChecking no' [email protected] lsblk
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
....
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop0 7:0 0 3.1G 1 loop
sda 8:0 0 19.1G 0 disk
├─sda1 8:1 0 40M 0 part
└─sda2 8:2 0 1.5G 0 part
sr0 11:0 1 1024M 0 rom
You'll obviously have to change the IP to your own. Also, I'm using StringHostKeyChecking no
to skip testing of the remove host keys. These are generated each time we boot into rescue mode, and running ssh-keygen -R 167.235.141.165
became a bit of a hassle as I was doing all this repeatedly.
As you can see, I went for the smalles VPS Hetzner has with 20GB SDD. Still plenty for our 1.5G minimal Guix system image. And now for the grand finale!
This next command will delete everything on your VPS disk! Take backups!
klm@pal ~$ pv $disk | ssh -o 'StrictHostKeyChecking no' [email protected] dd bs=1MiB of=/dev/sda
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
...
1.56GiB 0:00:22 [70.0MiB/s] [==========================================================>] 100%
0+50755 records in
0+50755 records out
1671286784 bytes (1.7 GB, 1.6 GiB) copied, 20.5225 s, 81.4 MB/s
Using pv
instead of just cat
gives us nice progress bar. Now, let's reboot into our new Guix system!
klm@pal ~$ ssh -o 'StrictHostKeyChecking no' [email protected] reboot
We're in! Very exciting. Now, since the new guest system will have permanent SSH host keys, we'll want to keep them. So we delete the existing ones, if there are any, and accept them on first connection.
klm@pal ~$ ssh-keygen -R 167.235.141.165
klm@pal ~$ ssh [email protected]
The authenticity of host '167.235.141.165 (167.235.141.165)' can't be established.
ED25519 key fingerprint is SHA256:q9+ik7EQOog8ZQhYHTNYUEuEoS4wgc25lrLHgnvaCyk.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '167.235.141.165' (ED25519) to the list of known hosts.
root@my-guix-server ~# guix system describe
Generation 1 Aug 25 2022 21:29:34 (current)
file name: /var/guix/profiles/system-1-link
canonical file name: /gnu/store/br6hwhlrb575y0i72wh9y63xxvy7mpr6-system
label: GNU with Linux-Libre 5.18.16
bootloader: grub
root device: UUID: 38af4c98-eb55-2b70-ad36-132e38af4c98
kernel: /gnu/store/iz6xn1b1dyk6pwaf6dym3jm3vwnh4gz9-linux-libre-5.18.16/bzImage
From here, there are probably a number of thing's you'll want to do.
- Resize
/dev/sda2
to fill the entire VPS disk space. - Tweak
hetzner.scm
to your liking.
Also, it's be nice if this could be integrated with guix deploy
for automation, but I haven't looked into that.