Installing Void Linux on the Hardkernel Odroid H4+ ======================================================================== Contents ======================================================================== Materials Flashing the USB Stick Configuring BIOS on the H4+ Installation Post-Installation Tasks - Update the System - Install Intel Microcode Updates - Install Development Tools - Install Xorg - Install Other Packages - Install dwm - Configuring Yubico Security Keys - Install doas(1) and Create Basic Rules - Configure Audio - CD Ripping - Configure Printing - Importing a ZFS Pool - Enabling sshd(8) References ======================================================================== Materials ======================================================================== I started with these: - Hardkernel Odroid H4+ - 32GB Crucial DDR5-5600 DRAM module - Patriot P220 256GB internal 2.5" Sata III SSD - A small USB stick (8GB is sufficient) - A computer with USB and Internet connectivity (I used Void Linux on another x86-64 system) ======================================================================== Flashing the USB Stick ======================================================================== Download the live .iso image. I downloaded the x86_64 musl image: wget https://repo-default.voidlinux.org/live/current/void-live-x86_64-musl-20250202-base.iso wget https://repo-default.voidlinux.org/live/current/sha256sum.{sig,txt} Verify the image. I already had a Void Linux system with Void's minisign(1), so I did the following according to the Void Handbook: minisign -V -p /usr/share/void-release-keys/void-release-20250202.pub -x sha256sum.sign -m sha256sum.txt sha256sum -c --ignore-missing sha256sum.txt Flash the image to a USB stick (/dev/sde here, but use the right device on your system): dd if=void-live-x86_64-musl-20250202-base.iso of=/dev/sde bs=4M Remove the USB drive. ======================================================================== Configuring BIOS on the H4+ ======================================================================== Boot the Odroid H4+. When the Hardkernel logo appears, pres the "Del" key repeatedly until the BIOS configuration screen appears. I did the following: - Disable Intel VT-d. I did not plan to run virtual machines. - Disable Intel VTX. I did not plan to run virtual machines. - Adjust the automatic fan settings. I bought the Odroid-H4 type 4 case for my board, which came with a fan, and I wanted my fan to run most of the time. So I lowered the temperature threshold for the fan and adjusted other fan settings. - Disable Secure Boot. - Change the G3 ACPI state from "S5" (stay powered off after shutdown even when power is available) to "S0" (turn on when power is available) thus: - Go to the "Chipset" menu at the top of the BIOS screen. - Select "PCH-IO Configuration". - Change "State After G3" from "S5" to "S0". - Set a supervisor password to lock people out of BIOS. Exit saving changes. ======================================================================== Installation ======================================================================== Insert your USB flash drive into a USB port. When you turn the H4+ on or reboot, the system should load the USB flash drive's Void boot menu. Select the first (default) option. Log in as root (the instructions that appear during boot tell you what the password is) and format the boot disk (the Patriot 256GB drive in my case). I listed all sd(4) drives Void detected by running: ls /dev/sd* mount mount(8) helped me determine which of /dev/sd* was the mounted USB flash drive. When I determined which sd(4) device was my SSD drive, I opened it with fdisk(8) (the drive was /dev/sda in my case): fdisk /dev/sda I did the following: - Type "g" to create a new, empty GPT partition table. - Type "w" to write the empty partition table to disk and exit. Then I opened the drive with cfdisk(8): cfdisk /dev/sda I did the following: - Create a 100MB partition (accept the default starting sector, which should be 2048) and change its type to "EFI System". UEFI systems like the H4+ require this. - Create a 48GB partition (accept the default starting sector) and change its type to "Linux swap". The Void Handbook recommends 1.5x your system's RAM for the swap partition. - Create a partition with the remaining free space and change its type to "Linux filesystem". Then run the Void Linux installer: void-installer I plugged my Ethernet cable into one of the 2.5GB Ethernet ports and chose to install the base system from the network. In the filesystem screen, I told the installer to: - Format the 100MB "EFI System" partition as FAT32 and mount it at /boot/efi (as required by Void Linux). - Format the "Linux swap" partition as swap. - Format the "Linux filesystem" partition as ext4 and mount it at /. ======================================================================== Post-Installation Tasks ======================================================================== ------------------------------------------------------------------------ Update the System ------------------------------------------------------------------------ Update all packages: sudo xbps-install -Su ------------------------------------------------------------------------ Install Intel Microcode Updates ------------------------------------------------------------------------ Install the intel-ucode package and regenerate initrmfs per the Void Handbook (this example assumes you are running Linux kernel 6.6.z): sudo xbps-install -S void-repo-nonfree sudo xbps-install -S intel-ucode sudo xbps-reconfigure --force linux6.6 ------------------------------------------------------------------------ Install Development Tools ------------------------------------------------------------------------ For example: sudo xbps-install -S clang git make zig ------------------------------------------------------------------------ Install Xorg ------------------------------------------------------------------------ Install X and the Mesa OpenGL library: sudo xbps-install -S xorg-minimal libX11-devel libXft-devel libXinerama-devel freetype-devel mesa Install some recommended fonts: sudo xbps-install -S freefont-ttf google-fonts-ttf liberation-fonts-ttf nerd-fonts noto-fonts-ttf xorg-fonts Per the Void Linux Handbook, disable bitmap fonts: sudo ln -s /usr/share/fontconfig/conf.avail/70-no-bitmaps.conf /etc/fonts/conf.d/ sudo xbps-reconfigure -f fontconfig Then exit and restart your X session if you are already running one. Many PDFs (such as financial statements) cannot render properly with the default fonts and the ones in the previous section. You have to configure font replacements so that programs use your fonts instead of common but non-free ones like Arial. Run Firefox. In the URI bar, enter "about:config" and find the "gfx.font_rendering.fontconfig.max_generic_substitutions" setting and set it to 127. (It defaults to a low number like 3.) This allows Firefox to use more substitute fonts. $HOME/.config/fontconfig/fonts.conf is an XML file that configures Fontconfig. Among other things, it can specify substitute fonts. Here is my fonts.conf: ------------------------------------------------------------------------ my font settings Arial Liberation Sans DejaVu Sans Arial MT Liberation Sans DejaVu Sans ArialMT Liberation Sans DejaVu Sans Times New Roman Liberation Serif DejaVu Serif Times New Roman MT Liberation Serif DejaVu Serif TimesNewRomanMT Liberation Serif DejaVu Serif TimesNewRomanPSMT Liberation Serif DejaVu Serif ------------------------------------------------------------------------ ------------------------------------------------------------------------ Install Other Packages ------------------------------------------------------------------------ I installed these packages: sudo xbps-install -S exfatprogs firefox gnupg lynx neovim signify wget xterm xz ------------------------------------------------------------------------ Install dwm ------------------------------------------------------------------------ Download the latest dwm release. As of this writing, the latest is 6.6, so the download is: wget https://dl.suckless.org/dwm/dwm-6.6.tar.gz Alternatively, clone the git(1) repo: git clone https://git.suckless.org/dwm Change config.def.h as you like. I changed the terminal from "st" to "/usr/bin/xterm". When you are done changing the source, build it: make dwm If you do not have gcc(1), change "CC" in Makefile to another compiler, such as /usr/bin/clang. Install the dwm executable file wherever you want. Remember its path. In my case, I put it in $HOME/bin. Put the full path to the dwm executable file (where you installed it) into $HOME/.xinitrc. For example, mine looks like this: exec /home/myuser/bin/dwm startx(1) should load dwm. ------------------------------------------------------------------------ Configuring Yubico Security Keys ------------------------------------------------------------------------ You have to make udevd(8) recognize your security key via a rule. First, plug your security key in and, assuming it is a USB device, get its vendor and product IDs from lsusb(8): lsusb Create /etc/udev/rules.d/70-u2f.rules as follows. Set the correct vendor and product IDs. For my security key: ------------------------------------------------------------------------ # Yubico Security Key KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0120" ------------------------------------------------------------------------ This should let non-root users (in the plugdev group) use the device. Add your user to the plugdev group to give it access: sudo usermod -a -G plugdev YOURUSER If you want to create ed25519-sk or ecdsa-sk ssh(1) keys, install openssh-sk-helper: sudo xbps-install -S openssh-sk-helper ------------------------------------------------------------------------ Install doas(1) and Create Basic Rules ------------------------------------------------------------------------ doas(1) is much simpler than sudo(1) -- no surprise given its OpenBSD origins. Install it thus: sudo xbps-install -S opendoas Configure it by creating /etc/doas.conf, owned by root:root. See doas.conf(5) for the syntax. Here is a great initial doas.conf: permit nopass YOURUSER as root cmd /usr/bin/reboot args permit nopass YOURUSER as root cmd /usr/bin/shutdown args -h now permit nopass YOURUSER as root cmd /usr/bin/xbps-install args -Su permit nopass YOURUSER as root cmd /usr/bin/xbps-install args -S xbps This permits the user YOURUSER to reboot, shutdown, and update the system without entering a password. ------------------------------------------------------------------------ Configure Audio ------------------------------------------------------------------------ Install the alsa-utils, pipewire, and sof-firmware packages. You will need the void-repo-nonfree package to get the latter one: sudo xbps-install -S alsa-utils pipewire sof-firmware Enable the dbus service on system startup (this will also immediately start it): sudo ln -s /etc/sv/dbus /var/service/ Create system-wide PipeWire configuration for wireplumber(1) and the pipewire-pulse interface: mkdir -p /etc/pipewire/pipewire.conf.d ln -s /usr/share/examples/wireplumber/10-wireplumber.conf /etc/pipewire/pipewire.conf.d/ ln -s /usr/share/examples/pipewire/20-pipewire-pulse.conf /etc/pipewire/pipewire.conf.d/ Ensure that your user's profile defines the XDG_RUNTIME_DIR environment variable. Here's a good value: export XDG_RUNTIME_DIR=/tmp//$(id -u) /usr/bin/mkdir -p -m 0700 "$XDG_RUNTIME_DIR" Reboot your system and log in as a user in the audio group. You need to run pipewire(1) in a D-Bus session, usually via dbus-run-session(1). To do this for your X window manager, run the window manager in a D-Bus session in your .xinitrc. For example, if your window manager is dwm, your .xinitrc might look like this: exec dbus-run-session -- /path/to/dwm Run pipewire(1) as a user in the audio group: pipewire Use wpctl(1) to control wireplumber(1). To see everything: wpctl status To set device 53 to 75% volume: wpctl set-volume 53 0.75 To toggle mute on an audio input or output device, such as device 53: wpctl set-mute 53 toggle ------------------------------------------------------------------------ CD Ripping ------------------------------------------------------------------------ Install abcde(1), cdparanoia(1) (for reading raw CD data), an audio encoder such as the Opus encoder, and cd-discid(1): sudo xbps-install -S abcde cdparanoia opus-tools cd-discid abcde(1) will rip the CD into a subdirectory of the current directory. Here is a good way to rip music CDs to Opus: abcde -l -o opus:"--bitrate 128" -x ------------------------------------------------------------------------ Configure Printing ------------------------------------------------------------------------ Install cups(1) and cups-filters: sudo xbps-install -S cups cups-filters Enable cupsd(8): sudo ln -s /etc/sv/cupsd /etc/runit/runsvdir/default Some printer manufacturers have additional drivers. For example, if you have an HP printer, install hplip: sudo xbps-install -S hplip Then run hp-setup thus after cupsd(8) starts. The defaults are usually sufficient: sudo hp-setup -i If hp-setup(1) cannot find your printer's PPD file, look for it in /usr/share/ppd/HP and provide the full path tp hp-setup when it asks for it. You might also have to run a dbus session to finish installation; in that case, change your $HOME/.xinitrc so that it runs your window manager with dbus-run-session(1). I use dwm, so my .xinitrc looks something like this: /usr/bin/dbus-run-session -- /path/to/dwm enscript(1) is helpful for printing plain text files: sudo xbps-install -S enscript Then printing a plain text file named document.txt is as simple as: enscript -B -p document.ps -M Letter document.txt lpr -P my_printer -o sides=two-sided-long-edge document.ps You can print PostScript and PDF files directly with lpr(1) as above. ------------------------------------------------------------------------ Importing a ZFS Pool ------------------------------------------------------------------------ Install ZFS: sudo xbps-install -S zfs You should be able to see your pool: zpool import If you see it, import it (in this case, it is called "shared"): zpool import shared If your ZFS filesystems are encrypted and the keys are files on a USB flash drive, plug the flash drive in, then determine the label of the partition the key files are in. The partition should appear in /dev/disk/by-partlabel: ls /dev/disk/by-partlabel Supposing the partition is /dev/disk/by-partlabel/keydisk and contains a FAT filesystem, put the following in /etc/fstab: ------------------------------------------------------------------------ PARTLABEL=keydisk /mnt/rootonly/keys vfat auto,ro,nofail,noatime,nosuid,nodev,noexec,nosymfollow 0 2 ------------------------------------------------------------------------ The above assumes that /mnt/rootonly/keys is a root-owned directory with restrictive permissions, preferably 0700, so that only root can read it. This prevents other users from reading the ZFS keys. Reboot your system or run: sudo mount -a Now you can mount your encrypted ZFS filesystems. To automatically mount encrypted ZFS filesystems on boot, put the following into a new /etc/runit/core-services/80-encrypted-zfs.sh file: ------------------------------------------------------------------------ # vim: set ts=4 sw=4 et: [ -n "$IS_CONTAINER" ] && return 0 if [ -x /usr/bin/zpool -a -x /usr/bin/zfs ]; then msg "Mounting encrypted ZFS filesystems..." /usr/bin/zfs mount -a -l fi ------------------------------------------------------------------------ You have to do this because runit(8)'s default /etc/runit/core-services scripts try to mount ZFS filesystems before mounting non-ZFS filesystems (that is, traditional filesystems managed by fstab(5) and mount(8)), including your USB flash drive containing the encryption keys. The above script tries to mount all ZFS filesystems again, and the high numeric prefix in the filename ensures that it runs after the script that mounts traditional filesystems. ------------------------------------------------------------------------ Enabling sshd(8) ------------------------------------------------------------------------ If you did not already enable sshd(8) via the Void Linux installer, run: ln -s /etc/sv/sshd /etc/runit/runsvdir/default/ Change or add the following settings in /etc/ssh/sshd_config: PermitRootLogin no KbdInteractiveAuthentication yes PermitEmptyPasswords no PubkeyAuthentication yes ======================================================================== References ======================================================================== - Arch Linux Wiki, "Font Configuration" https://wiki.archlinux.org/title/Font_configuration - Hardkernel Odroid H4+ product page https://www.hardkernel.com/shop/odroid-h4-plus - Hardkernel Odroid H4/H4+/H4-Ultra wiki page https://wiki.odroid.com/odroid-h4/start