Thursday, June 18, 2020

WireGuard kernel module for Alpine Linux on diskless Raspberry Pi

As of writing (Alpine Linux v3.12), the WireGuard kernel module is not part of the Alpine Linux Raspberry Pi kernel by default. There's a community module called wireguard-rpi2, but it doesn't work in a system set up in diskless mode. The reason it doesn't work, is because in diskless mode on a Raspberry Pi, Alpine Linux uses a read-only loopback file system to store its kernel modules. This filesystem is mounted on /.modloop .

The workaround I came up with, is to use an overlay file system to make the kernel modules directory writable.

Here's the workaround:
# Remount the kernel module directory /.modloop as an overlay, to allow writing
modprobe overlay
mkdir -p /.modloop.lower /.modloop.upper /.modloop.workdir
mount /dev/loop0 /.modloop.lower
umount /.modloop/
mount -t overlay -o lowerdir=/.modloop.lower,upperdir=/.modloop.upper,workdir=/.modloop.workdir none /.modloop
lbu include /.modloop.upper
lbu commit -d

# Manually get the Wireguard kernel module to avoid installing the wireguard-rpi2 which does not work with diskless systems
cd /tmp
pkgname=$(apk list | grep wireguard-rpi2 | cut -d " " -f 1)
wget http://dl-cdn.alpinelinux.org/alpine/v3.12/community/armhf/$pkgname.apk
mkdir /tmp/$pkgname
tar -xzf $pkgname.apk -C /tmp/$pkgname
mkdir -p /lib/modules/$(uname -r)/extra/
cp /tmp/$pkgname/lib/modules/$(uname -r)/extra/wireguard.ko /lib/modules/$(uname -r)/extra/
rm -fr /tmp/$pkgname /tmp/$pkgname.apk
depmod

# Create an init script to remount the /.modloop overlay on next boot
cat > /etc/init.d/modloopoverlay <<EOF
#!/sbin/openrc-run

depend() {
    before networking
    need modules
}

start() {
    ebegin "Starting modloop overlay"
    modprobe overlay
    mkdir -p /.modloop.lower /.modloop.upper /.modloop.workdir
    if [ ! -d /.modloop.lower/modules ]; then
        mount /dev/loop0 /.modloop.lower
    fi
    umount /.modloop
    mount -t overlay -o lowerdir=/.modloop.lower,upperdir=/.modloop.upper,workdir=/.modloop.workdir none /.modloop
    eend 0
}
EOF
chmod +x /etc/init.d/modloopoverlay
/etc/init.d/modloopoverlay restart
rc-update add modloopoverlay boot
lbu include /etc/init.d/modloopoverlay

apk add wireguard-tools

# Create an init script to start wg0
cat > /etc/init.d/wg0 <<EOF
#!/sbin/openrc-run

depend() {
    need networking ntpd modloopoverlay
}

start() {
    ebegin "Starting Wireguard tunnel wg0"
    ntpd -n -q -p pool.ntp.org
    date
    wg-quick up wg0
    eend $?
}

stop() {
    ebegin "Stopping Wireguard tunnel wg0"
    wg-quick down wg0
    eend 0
}
EOF
chmod +x /etc/init.d/wg0
/etc/init.d/wg0 restart
rc-update add wg0 default
lbu include /etc/init.d/wg0

lbu commit -d

# inspect the overlay file
tar -tvf /media/mmcblk0p1/localhost.apkovl.tar.gz

2 comments:

  1. I am facing this issue too (Alpine in diskless mode, but not rPI) and trying to decide how to deal with it. How does your approach compare with what's in the Alpine wiki https://wiki.alpinelinux.org/wiki/Configure_a_Wireguard_interface_(wg) in "Running with modloop" section?

    ReplyDelete