Background

I purchased a Raspberry Pi in 2016 (version 3B v1.2) to use as a web server for serving the static HTML pages I render my journal into. With SSH local forwarding, I can view the HTML pages on other devices over SSH, which limits attack vectors.

I recently decided to reimage this system after having bootstrapped more knowledge of system management over the past several years. The beauty and horror of Linux is that there are multiple ways to do everything. I had already made most of the decisions based on what I had used in previous projects, so I had a particular list of requirements:

I succeeded in getting this system to run stably, and have not had any issues due to my setup over the past several months since I’ve done this.

I wrote the outline of this tutorial while working through the rather extensive process of getting this to work for my reference in case I need to do this again in the future after I’ve forgotten what I did.

This could save me hours of work: while the steps themselves are not that complicated to perform—I suspect I could redo this in under an hour, maybe even 30 minutes—I spent probably tens of hours debugging and investigating various issues that came up while I was following other tutorials and trying to piece them together to get what I wanted.

That is to say: this was a difficult project for me and this is not a tutorial for beginners; familiarity with the following concepts (from more common to most specific) will make debugging any issues that arise substantially easier:

I wrote this tutorial for myself, so it’s structured in a way that I understand: I gloss over some of the details—like configuring sshd—and reference several other tutorials that I used while going through this process with only minor notes about different steps that I took.

I’m still publishing this because I think anyone with a decent level of technical sophistication should be able to follow it. With those disclaimers, good luck, and I hope this might save you some time.

Instructions

Partitioning and initial installation

The instructions in this tutorial, which in turn rely on the official Raspberry Pi 3 installation instructions, are pretty good, but some comments:

Stop following the instructions once it starts talking about the QEMU chroot.

Accessing the mounted SD card

The instructions for accessing the mounted SD card via QEMU provided by this tutorial didn’t work for me.

The Arch wiki provided some instructions that did.

Specifically, I had to install qemu-user-static and qemu-user-static-binfmt.

I used

# systemd-nspawn -D /mnt/sdcard -M sdcard

which provides a root shell into the new environment.

chroot environment tasks

Get network and pacman working

pacman will not work at all in this environment due to the fact that network doesn’t work. rm /etc/resolv.conf (removes a symlink) and then add nameserver 192.168.0.1 (or whatever an appropriate DNS address is) to it.

Now initialize pacman and update:

# pacman-key --init && pacman-key --populate archlinuxarm
# pacman -Syu

The update will probably trigger a rebuild of mkinitcpio, which takes FOREVER.

Now, some helpful tools:

# pacman -S sudo uboot-tools cryptsetup

Optionally a text editor is helpful as well.

Set up boot for unlocking encrypted root partition

mkinitcpio

I prefer using sd-encrypt, and I copied the hooks verbatim from the Arch Wiki.

HOOKS=(base systemd autodetect modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)

Bootloader

We also need to edit the bootloader. 32-bit Arch Linux ARM uses /boot/cmdline.txt, but 64-bit Arch Linux ARM uses Das U-boot, which is configured in /boot/boot.txt:

Add the appropriate kernel parameters here, e.g. for sd-encrypt:

rd.luks.name=UUID=632923a5-2c9a-44dd-ab1c-73ff1c40b93e=cryptroot root=/dev/mapper/cryptroot

fstab

/etc/fstab also needs to be told about the encrypted drive.

/dev/mapper/cryptroot  /  ext4 defaults,noatime 0 1

It should already have the boot partition listed under /boot.

Finish up in the chroot environment

Exit with exit: unmount everything (see Tips and Tricks; and close the decrypted volume.

Boot

The first time I unlocked the encrypted root, I had to type my password twice for some reason, but it unlocked successfully.

Complete the typical Arch-recommended system configuration tasks. These could also have been done in the chroot environment, which would probably be more convenient. I did them post-successful boot because I had to make several tweaks, which required starting over at least twice, so the extra work wasn’t worth it to me until I knew I had a system that would boot.

Create a new user and add them to sudo so you no longer have to use root:

# useradd -m karepker
# passwd karepker
# groupadd sudo
# gpasswd -a karepker sudo

Uncomment the %sudo … line in the /etc/sudoers file to allow members of the sudo group to run sudo commands:

# visudo

Network

systemd-network was already running by default. I configured it to use a static IP address. In /etc/systemd/network/enu1u1.network:

[Match]
Name=enu1u1

[Network]
Address=192.168.X.Y/24
Gateway=192.168.X.Z
DNS=192.168.X.Z
DNSSEC=no

Replace X, Y, and Z and the interface name with appropriate values.

sshd

The ssh daemon was already running by default. After logging in with my created user and copying the keys from my clients into the daemon, I removed root login and disabled password-based authentication.

Remote access

The key decision here is choosing how to remotely decrypt the root filesystem. I prefer using mkinitcpio-systemd-tool for its modularity and consistency with other boot tasks.

I followed this tutorial, with a few changes:

Tips and Tricks

I found this one-liner useful for decrypting and mounting my SD card when chrooting (get the appropriate device from blkid and modify partitions as appropriate):

$ sudo cryptsetup open /dev/sdc2 sdroot && sudo mount /dev/mapper/sdroot /mnt/sdcard && sudo mount /dev/sdc1 /mnt/sdcard/boot

And equivalently for unmounting and closing the chrooted encrypted volume:

$ sudo umount -R /mnt/sdcard/ && sudo cryptsetup close sdroot

Issues

Why did this project take tens of hours? Because I routinely messed stuff up. Here’s a list of the problems that I had to debug and some resolutions:

Not my fault