Skip to content

Instantly share code, notes, and snippets.

@djoreilly
Last active July 1, 2022 15:54
Show Gist options
  • Save djoreilly/5206a4e7f0e4e62a7b86ce4c0b811fea to your computer and use it in GitHub Desktop.
Save djoreilly/5206a4e7f0e4e62a7b86ce4c0b811fea to your computer and use it in GitHub Desktop.
WireGuard MicroOS Raspberry Pi

WireGuard on MicroOS / Raspberry Pi

Install MicroOS

Download the Raspberry Pi image from https://en.opensuse.org/Portal:MicroOS/Downloads and copy it the MicsoSD card.

# xz -d openSUSE-MicroOS.aarch64-ContainerHost-RaspberryPi.raw.xz
# dd bs=4M if=openSUSE-MicroOS.aarch64-ContainerHost-RaspberryPi.raw of=/dev/mmcblk0 iflag=fullblock oflag=direct status=progress; sync

In the past it was necessary to use ignition or combustion to set a root password or add an ssh key to .ssh/authorized_keys. You can still do that - see https://en.opensuse.org/Portal:MicroOS/Combustion - but today the "Jeos First Boot" will be presented if a USB drive with label "iginition" is not found, and it allows you to set the root password.

After the dd/sync is done, insert the SD card into the Pi, attach monitor, keyboard and network cable and power it up. The screen goes black after about 40sec and stays like that for another few minutes (maybe a serial console would show more?). Then the "Jeos First Boot" prompts you to set the language, timezone and root password. After that you should be able to login at the console as root. You can curl your ssh public key from somewhere and add it to authorized_keys.

Install wireguard-tools

This package provides the wg tool and qg-quick. With MicroOS you need to use transactional-update to install packages and reboot after. Note reboot can take a few minutes because selinux relabeling is slow on microSD storage.

# transactional-update pkg install wireguard-tools
# reboot

Configure WireGuard

There are many possible topologies - this doc just shows a simple point-to-point example between a laptop and the Pi. Also there are different ways to configure/persist WireGuard. This guide uses wg-quick. See https://www.wireguard.com/ for other ways.

Create private/public key-pairs

For Pi:

laptop # TTY=$(tty); wg genkey | tee $TTY | wg pubkey
6FAsBgy1OmGRzCMOoXJK5tz2esx0ElfArAhvaTX800k=
1INU+lEE6Jo0XxqENneInEqgjctXQZQj6dX1y1OJZgE=

For laptop:

laptop# TTY=$(tty); wg genkey | tee $TTY | wg pubkey
aAtkn8TfFA5+cm/YVoC0gV1RsFThz997dpaPKe2eMls=
DZwInXs4evwwR0EzZKU7Dhn2Y/wToraT4t2GCrrZFGU=

Create /etc/wireguard/wg0.conf files

The latop's eth0 ip is 192.168.0.31 and the pi's is 192.168.0.234. The port 51871 was choosen for the laptop, so that port will need to be opened on the firewall for UDP.

For Pi:

[Interface]
ListenPort = 51872
PrivateKey = 6FAsBgy1OmGRzCMOoXJK5tz2esx0ElfArAhvaTX800k=
Address = 172.31.0.2/30

[Peer]
PublicKey = DZwInXs4evwwR0EzZKU7Dhn2Y/wToraT4t2GCrrZFGU=
AllowedIPs = 172.31.0.1/32
Endpoint = 192.168.0.31:51871

For latop:

[Interface]
ListenPort = 51871
PrivateKey = aAtkn8TfFA5+cm/YVoC0gV1RsFThz997dpaPKe2eMls=
Address = 172.31.0.1/30

[Peer]
PublicKey = 1INU+lEE6Jo0XxqENneInEqgjctXQZQj6dX1y1OJZgE=
AllowedIPs = 172.31.0.2/32
Endpoint = 192.168.0.234:51872

Enable the wg0 interfaces

pi# chmod 0600 /etc/wireguard/wg0.conf
laptop# chmod 0600 /etc/wireguard/wg0.conf

pi # systemctl enable [email protected] --now
latop # systemctl enable [email protected] --now

Test

pi# ping -c1 172.31.0.1
PING 172.31.0.1 (172.31.0.1) 56(84) bytes of data.
64 bytes from 172.31.0.1: icmp_seq=1 ttl=64 time=5.09 ms

--- 172.31.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 5.089/5.089/5.089/0.000 ms


pi# wg
interface: wg0
  public key: 1INU+lEE6Jo0XxqENneInEqgjctXQZQj6dX1y1OJZgE=
  private key: (hidden)
  listening port: 51872

peer: DZwInXs4evwwR0EzZKU7Dhn2Y/wToraT4t2GCrrZFGU=
  endpoint: 192.168.0.31:51871
  allowed ips: 172.31.0.1/32
  latest handshake: 23 seconds ago
  transfer: 476 B received, 564 B sent

pi# ip -4 address show dev wg0
6: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 172.31.0.2/30 scope global wg0
       valid_lft forever preferred_lft forever

Performance tests

iperf

Instead of installing iperf on the pi we can build and run it as a container.

pi# mkdir iperf; cd iperf

pi# cat > Containerfile <<EOF
FROM registry.opensuse.org/opensuse/tumbleweed
RUN zypper --non-interactive install iperf && zypper clean --all
EOF

pi# podman build -t iperf .

pi# podman run -it --rm --net=host localhost/iperf iperf3 -s

Results

These tests were done on a Model B Rev 1.2

# cat /sys/firmware/devicetree/base/model 
Raspberry Pi 3 Model B Rev 1.2

laptop --> pi over eth0 interfaces

laptop# iperf3 --omit 5 --time 25 -c 192.168.0.234
...
[  5]   0.00-25.01  sec   278 MBytes  93.2 Mbits/sec                  receiver

laptop --> pi over wg0 interfaces

laptop# iperf3 --omit 5 --time 25 -c 172.31.0.2
...
[  5]   0.00-25.01  sec   263 MBytes  88.3 Mbits/sec                  receiver

pi --> laptop over eth0 interfaces

latop# # iperf3 --reverse --omit 5 --time 25 -c 192.168.0.234
...
[  5]   0.00-25.01  sec   282 MBytes  94.5 Mbits/sec    0             sender

pi --> laptop over wg0 interfaces

laptop# iperf3 --reverse --omit 5 --time 25 -c 172.31.0.2
...
[  5]   0.00-25.01  sec   270 MBytes  90.5 Mbits/sec    0             sender

So it looks like a 4-5% performance drop.

Troubleshooting

On MicoOS you can use the toolbox container

pi # toolbox 
Trying to pull registry.opensuse.org/opensuse/toolbox:latest...
...
Entering container. To exit, type 'exit'.
toolbox-root:/ # 
toolbox-root:/ # tcpdump -c2 -ni eth0 udp port 51872
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:47:15.893910 IP 192.168.0.31.51871 > 192.168.0.234.51872: UDP, length 148
12:47:15.897386 IP 192.168.0.234.51872 > 192.168.0.31.51871: UDP, length 92
2 packets captured
4 packets received by filter
0 packets dropped by kernel

Updates

The systemd timer transactional-update.timer runs transactional-update once per day by default, and the schedule can be changed. When transactional-update installs updates it informs rebootmgr that a reboot is needed and rebootmgr will do the reboot within the set maintenance window.

pi# rebootmgrctl get-window
Maintenance window is set to *-*-* 03:30:00, lasting 01h30m.

To change the maintenance window:

pi# cp /usr/etc/rebootmgr.conf /etc/rebootmgr.conf
pi# vi /etc/rebootmgr.conf
pi# systemctl restart rebootmgr
pi# rebootmgrctl get-window
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment