Friday December 14 2018
Installing Void Linux on Digital Ocean - A Void Linux VPS Part I
Not too long ago I was able to get OpenBSD installed on Digital Ocean, I figure since it’s not really a “foreign” operating system, this should be even easier. Spoiler, it’s not. But it’s not too much harder either.
Create a new VM, boot to the recovery ISO
You should be able to SSH to the machine with the SSH keys you tied to the instance straight away.
Partition the disk
I first used gdisk
’s advanced option to “zap” the disk and clear all GPT
and MBR entries:
root@void:~# gdisk /dev/vda
GPT fdisk (gdisk) version 1.0.3
Partition table scan:
MBR: protective
BSD: not present
APM: not present
GPT: present
Found valid GPT with protective MBR; using GPT.
Command (? for help): p
Disk /dev/vda: 52428800 sectors, 25.0 GiB
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): 858A66B1-0062-4F12-A9A8-B52406B9C71D
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 52428766
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)
Number Start (sector) End (sector) Size Code Name
1 227328 52428766 24.9 GiB 8300
14 2048 10239 4.0 MiB EF02
15 10240 227327 106.0 MiB 0700
Command (? for help): x
Expert command (? for help): z
About to wipe out GPT on /dev/vda. Proceed? (Y/N): y
GPT data structures destroyed! You may now partition the disk using fdisk or
other utilities.
Blank out MBR? (Y/N): y
root@void:~#
If you have trouble reading the output above, the commands are x
to get to
advanced mode and z
to zap the disk
Now to setup our new partitions:
root@void:~# gdisk /dev/vda
GPT fdisk (gdisk) version 1.0.3
Partition table scan:
MBR: not present
BSD: not present
APM: not present
GPT: not present
Creating new GPT entries.
Command (? for help): n
Partition number (1-128, default 1):
First sector (34-52428766, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-52428766, default = 52428766) or {+-}size{KMGTP}: +500m
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'
Command (? for help): n
Partition number (2-128, default 2):
First sector (34-52428766, default = 1026048) or {+-}size{KMGTP}:
Last sector (1026048-52428766, default = 52428766) or {+-}size{KMGTP}:
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 8e00
Changed type of partition to 'Linux LVM'
Command (? for help): n
Partition number (3-128, default 3):
First sector (34-2047, default = 34) or {+-}size{KMGTP}:
Last sector (34-2047, default = 2047) or {+-}size{KMGTP}:
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): ef02
Changed type of partition to 'BIOS boot partition'
Command (? for help): p
Disk /dev/vda: 52428800 sectors, 25.0 GiB
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): CF56F288-92ED-4FA2-BA8F-462FBE075BB0
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 52428766
Partitions will be aligned on 2048-sector boundaries
Total free space is 0 sectors (0 bytes)
Number Start (sector) End (sector) Size Code Name
1 2048 1026047 500.0 MiB 8300 Linux filesystem
2 1026048 52428766 24.5 GiB 8E00 Linux LVM
3 34 2047 1007.0 KiB EF02 BIOS boot partition
Command (? for help): wq
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!
Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/vda.
The operation has completed successfully.
We’re creating a small 500mb partition for /boot
, a large one for LVM and
a tiny one for the grub bios boot partition. Although you could get away
with one large, single XFS filesystem I rather like the snapshotting abilities
that LVM gives you.
Setup LVM and mount the filesystems
# lvm pvcreate /dev/vda2
# lvm vgcreate vg /dev/vda2
# lvm lvcreate vg --name root --size 4G
# lvm lvcreate vg --name var --size 5G
# lvm lvcreate vg --name home --size 2G
# mkfs.xfs /dev/vg/root
# mkfs.xfs /dev/vg/var
# mkfs.xfs /dev/vg/home
# mkfs.ext4 /dev/vda1
# mount /dev/vg/root /mnt
# mkdir /mnt/var
# mount /dev/vg/var /mnt/var
# mkdir /mnt/home
# mount /dev/vg/home /mnt/home
# mkdir /mnt/boot
# mount /dev/vda1 /mnt/boot
Download minimal root filesystem
Be sure to check the website for a mirror
near you and change the URL accordingly. You might need to browse the
live/current/
path to figure out the current ROOTFS
tarball
# cd /mnt
# wget http://mirror.clarkson.edu/voidlinux/live/current/void-x86_64-musl-ROOTFS-20181111.tar.xz
# tar xJf void-*ROOTFS*
Chroot into the new system and setup the basics
# cd /mnt
# mount -t proc none proc
# mount -o bind /sys sys
# mount -o bind /dev dev
# chroot /mnt /bin/bash
bash-4.4# export PS1="(CHROOT) # "
Setup nameservers
(CHROOT) # echo nameserver 8.8.8.8 > /etc/resolv.conf
Setup the package repository to point at your local mirror
(CHROOT) # echo repository=http://mirror.clarkson.edu/voidlinux/current/musl \
> /etc/xbps.d/00-repository-main.conf
Install the base system, lvm2
, and a few other useful packages
(CHROOT) # xbps-install -Syu base-system lvm2 curl wget ed grub gptfdisk lzop \
lzip openvpn nmap pv rrdtool rsync sipcalc whois xz
Configure bootloader, initrd and /etc/fstab
Kind of a hack to setup the fstab
, but it works:
(CHROOT) # cat /proc/mounts | grep -E '(xfs|ext4)' >> /etc/fstab
The Void Linux kernel by default does not build in the necessary module to
handle booting off of a logical volume with associated snapshots. To make
matters worse, it does not load it automatically even if you put it in the
initial ramdisk. Thankfully dracut
has an option to force load kernel modules
Simply:
# echo 'force_drivers="dm_snapshot"' >> /etc/dracut.conf
Then go ahead and rebuild the initrd:
(CHROOT) # dracut -f --kver $(ls -t /lib/modules | sed 1q)
Now to check the generated initrd and make sure that it has LVM support:
(CHROOT) # lsinitrd /boot/initramfs-* | grep lvm
lvm
drwxr-xr-x 2 root root 0 Dec 14 04:02 etc/lvm
-rw-r--r-- 1 root root 44 Dec 14 04:02 etc/lvm/lvm.conf
-rw-r--r-- 1 root root 776 Oct 30 10:51 etc/udev/rules.d/64-lvm.rules
-rwxr-xr-x 1 root root 2110744 Nov 18 17:54 usr/bin/lvm
-rwxr-xr-x 1 root root 3527 Oct 30 10:51 usr/bin/lvm_scan
-rwxr-xr-x 1 root root 487 Oct 30 10:51 usr/lib/dracut/hooks/cmdline/30-parse-lvm.sh
-r--r--r-- 1 root root 2453 Nov 18 17:54 usr/lib/udev/rules.d/11-dm-lvm.rules
-r--r--r-- 1 root root 6371 Dec 14 04:02 usr/lib/udev/rules.d/69-dm-lvm-metad.rules
(CHROOT) #
Grub is straightforward
(CHROOT) # grub-install --target=i386-pc /dev/vda
Installing for i386-pc platform.
Installation finished. No error reported.
(CHROOT) # grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-4.19.9_1
Found initrd image: /boot/initramfs-4.19.9_1.img
done
(CHROOT) #
Network configuration
This one is a little bit more tricky at first, but somewhat more straightfoward
than other distrubitions. Simply edit /etc/rc.local
to contain the normal
commands you would run to setup the network by hand.
The contents of the file are as follows:
/etc/rc.local
# Default rc.local for void; add your custom commands here.
#
# This is run by runit in stage 2 before the services are executed
# (see /etc/runit/2).
ip link set up eth0
ip -4 addr add 10.156.156.156/20 dev eth0
ip -4 route add default via 10.156.144.1 dev eth0
ip -6 addr add fc00:a880:400:d0::76e:6001/64 dev eth0
ip -6 route add default via fc00:a880:400:d0::1 dev eth0
You will need to replace the addresses above with the ones on your machine,
you can see these in the recovery environment via ip addr show | grep inet
and the routes with ip -4 route
and ip -6 route
for IPv4 and IPv6
respectively
Take care of user configuration and remote [ssh] login
Set a password, enable SSH:
(CHROOT) # passwd
(CHROOT) # ln -sv /etc/sv/sshd/ /etc/runit/runsvdir/default/
I highly recommend disabling PasswordAuthenticatoin
, relevant lines to change
in /etc/ssh/sshd_config
:
PermitRootLogin without-password
PasswordAuthenticatoin no
I also recommend creating a user account
(CHROOT) # useradd -m -g users -G wheel $username
(CHROOT) # passwd $uesrname
Set a hostname
(CHROOT) # echo mysvr.example.com > /etc/hostname
(optional) Set a timezone
(CHROOT) # ln -sv /usr/share/zoneinfo/America/Detroit /etc/localtime
Where America/Detroit
is replaced with your timezone.
(optional) Remove unnecessary getty
s
(CHROOT) # rm /etc/runit/runsvdir/default/agetty-tty2
(CHROOT) # rm /etc/runit/runsvdir/default/agetty-tty3
(CHROOT) # rm /etc/runit/runsvdir/default/agetty-tty4
(CHROOT) # rm /etc/runit/runsvdir/default/agetty-tty5
(CHROOT) # rm /etc/runit/runsvdir/default/agetty-tty6
(CHROOT) # rm /etc/runit/runsvdir/default/agetty-tty7
If you’re confident that you won’t need the console whatsoever, you can also
disable agetty-tty1
But this means that if you muck up SSH for whatever
reason it’s going to be a hard reboot into the recovery ISO to fix it.
End of Part I, and the future
If you followed along you now have a VPS sitting somewhere in a data center with Void Linux doing nothing but serving up a shell for you. In Part II we’ll setup logging, a firewall and backups.