turning my laptop into a thin client

Many years ago before I got my first job, I dipped into my savings to get myself a Chromebook to run Linux on so I had something to play with at school. That laptop has been through GalliumOS, Manjaro, and probably at least 5 Arch installs. In recent years I’ve had less use for it so it fell into neglect, but the times I have cleaned it up and got it working again I’ve found it really starting to struggle.

Specs wise it has a Celeron N3160, 4GiB memory, 32GiB of flash storage, and a 15" 1080p screen. It struggled with Firefox from the start, but 4+ years on it is not a pleasant machine to browse the web on. It also has some other hardware issues, such as the on-board audio being truly broken. The headphone jack does not produce any sound, and the speakers crackle and sometimes let out what I can only describe as demonic screeching. On the last install it had it was also starting to get visual glitches and screen flickering occasionally.

Safe to say this machine is not going to be particularly useful by itself, so I decided to turn it into a thin client to my desktop so I’d be able to work on stuff I have there from my bedroom or friends' houses.

tmux

Connection is done via SSH using my GPG key that is loaded onto the laptop and its authentication key is authorised for connection to my desktop. I’m not just connecting with a single SSH session though as that’s very limited, so instead I decided to revisit something I did before with my laptop which was to run tmux entirely in text mode and to customise it to resemble a tiling window manager.

This screenshot is from tmux running on my desktop as I haven’t found a way to capture kmscon on the laptop as fbcat doesn’t work with it unlike with a regular text mode TTY, however visually it’s largely the same. I have a clock at the top left, workspace (“window”) indicators in the middle, and a battery indicator on the right. If you want to look at my tmux config it’s in my dots repo.

The battery indicator was a challenge because tmux is running on the desktop, not the laptop, so I can’t just query /sys/class/power_supply/BAT0/capacity as that file doesn’t exist on the desktop. What I ended up doing was having a script on the laptop copying that information to a temporary file on the desktop with scp every minute or so which tmux then reads and uses to present the information.

console

On the laptop, I just did a regular bare-bones Arch install with LUKS. The TTY has very limited character/colour support, so I used kmscon which is a drop-in replacement. Specifically I used the kmscon-patched-git package from the AUR as the main one no longer seems maintained. kmscon does 256 colours rather than 16 or 8, supports unicode either with the bundled Unifont or with any font of your choosing with Pango. To use it it should replace the getty service (source):

# one at a time
systemctl disable getty@tty1
systemctl enable kmsconvt@tty1
# or all at once
sudo ln -s /usr/lib/systemd/system/kmsconvt@.service \
    /etc/systemd/system/autovt@.service

Config goes in /etc/kmscon/kmscon.conf:

xkb-layout=gb
xkb-variant=dvorak
font-engine=unifont

palette=custom
...

Note that the colours are in r, g, b format rather than hex, which is a pain as I had to manually convert them. See the man page.

power and encryption

Something important to consider with the thin client is that my desktop isn’t necessarily going to be powered on when I want to connect to it, so I need a way to remotely power it on. To make things more complicated, I have full-disk encryption on my desktop with LUKS which requires typing in a password before anything will be accessible.

Wake-on-LAN solves the former issue:

# on desktop
nmcli con show
nmcli con modify $connection 802-3-ethernet.wake-on-lan magic
# now make sure it's enabled in UEFI

# on laptop
wol -p 9 $mac_address

The latter is more complicated, requiring a small SSH server to be installed in initramfs on the desktop that can startup on boot and allow remote connection for entering the LUKS password only. Fortunately the Arch wiki once again helps us.

First, install mkinitcpio-netconf, mkinitcpio-utils, and mkinitcpio-dropbear. Next, copy your SSH public key into /etc/dropbear/root_key the same way as you would for putting it on a server. Following this blog post, I set the following in /etc/dropbear/config:

DROPBEAR_OPTIONS="-I 300 -j -k -p 2222 -s"

Next we need to ensure that the right mkinitcpio hooks are being loaded. On my machine, the relevant line in /etc/mkinitcpio.conf looks like this (important ones highlighted):

HOOKS=(base udev autodetect keyboard keymap consolefont modconf
    block netconf dropbear encryptssh filesystems fsck)

Finally, we need to make sure we have our kernel parameters set correctly in /boot/loader/entries/*.conf:

options ip=dhcp netconf_timeout=30 ...

Make sure you have an Arch USB ready if you need to rescue the system, then reboot and sweat profusely. If things work well, then you should see Dropbear’s logging and the LUKS prompt show up. Then from the laptop:

ssh root@$host

If you get shouted at about host fingerprints, then this is (probably) fine because Dropbear will present a different fingerprint than OpenSSH even if the host keys are identical (believe me I checked). To work around this, copy the existing fingerprint out of ~/.ssh/known_hosts, connect again and type in the LUKS password, then copy the other fingerprint back into ~/.ssh/known_hosts but importantly keeping the new fingerprint that’ll be there, so you now have two fingerprints for the desktop. SSH should no longer complain unless something actually bad is happening.

tidying up

So now I can start up my desktop from the laptop, connect to type in the LUKS password remotely, then SSH and start tmux and have my comfy setup, but that’s a very involved process, so naturally I want to automate as much of it as possible. After fiddling with scripts trying to handle edge cases I decided that the much simpler and more entertaining solution would be to make a fun little TUI using dialog. The .bashrc on the laptop automatically starts it up if I’m in /dev/pts/0 (kmscon in TTY1) and it looks like this:

The source for the script is in my dot files. It tells me useful information such as the time and date, battery level, and also if my desktop is reachable. From the menu I can connect to the desktop, turn it on (which also automatically connects for typing in the LUKS password), launch nmtui for connecting to wifi (and will later also allow starting WireGuard so I can connect from other networks), and shutdown the laptop. You can also exit out to the shell if anything more complicated needs to be done.