Installing wireguard on CentOS Stream 9
As I do a lot of my research on new Domino versions, Connections versions and HCL DX on my own server at home and as I’m often not at home, I figured I needed a VPN tunnel to my server, so I can work as if I am home. Wireguard has become kind of the de facto standard for these kind of situations, so I looked into installing it on my CentOS Stream 9 host.
I’m rarely installing anything straight on my host these days. I prefer containers as it makes it easier to configure and more secure. In this case, Wireguard isn’t even in one of the default CentOS 9 repositories, so it makes even more sense to use a container. On Docker Hub, there are two container images that grabbed my attention. By far the most popular image for the Wireguard server comes from linuxserver.io. I like their images. I use them for a plethora of things, so that’s a logical candidate. The other image of interest comes from an individual, but it’s been downloaded over a million times and updated frequently. It’s a UI for Wireguard. If you’re going to use Wireguard for a single connection you don’t really need it, but if you want some form of VPN administration, I can see that it could be handy. The documentation for the linuxserver.io Wireguard image is quite good, but I needed to make some alterations to get it to work on CentOS 9 Stream, hence this article.
Let’s start with my docker compose file:
---
version: "2.1"
services:
wireguard:
image: lscr.io/linuxserver/wireguard:latest
container_name: wireguard
cap_add:
- NET_ADMIN
- NET_RAW
environment:
- PUID=977
- PGID=977
- TZ=Europe/Amsterdam
- SERVERURL=zeus.martdj.nl
- SERVERPORT=51820 #optional
- PEERS=myLenovo,myDell,myMacbook,myiPhone,myiPad
- PEERDNS=auto #optional
- INTERNAL_SUBNET=10.13.13.0 #optional
- ALLOWEDIPS=0.0.0.0/0 #optional
- LOG_CONFS=true #optional
volumes:
- /local/wireguard/config:/config
ports:
- 51820:51820/udp
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
restart: unless-stopped
The deviation from the docker compose file from the documentation is the NET_RAW cap_add. This one turned essential to get everything to work. However, with just this docker compose file, you will see the following message in the log:
[#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE iptables v1.8.9 (legacy): can't initialize iptables table `filter': Table does not exist (do you need to insmod?) Perhaps iptables or your kernel needs to be upgraded. [#] ip link delete dev wg0 [wireguard] | **** Tunnel /config/wg_confs/wg0.conf failed, will stop all others! **** [wireguard] | **** All tunnels are now down. Please fix the tunnel config /config/wg_confs/wg0.conf and restart the container **** [wireguard] | [ls.io-init] done.
To solve this, you need to add a module to your kernel on your host:
modprobe iptable_raw
This was the only one I needed. take notice, this depends on your kernel version. If your Linux kernel is pre-5.6, you’re going to need more! If you entered this command, but used the docker compose file from the documentation (so without the NET_RAW), you’re going to see the next message in the log.
[#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE iptables v1.8.9 (legacy): can't initialize iptables table `filter': Permission denied (you must be root) Perhaps iptables or your kernel needs to be upgraded. [#] ip link delete dev wg0 **** Tunnel /config/wg_confs/wg0.conf failed, will stop all others! **** **** All tunnels are now down. Please fix the tunnel config /config/wg_confs/wg0.conf and restart the container **** [ls.io-init] done.
That’s where the NET_RAW comes in to grant the container the necessary permissions to make the changes to iptables. When both are present, wireguard starts properly:
[#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE **** All tunnels are now active **** [ls.io-init] done.
As I use Podman instead of Docker, I created a small systemd-service file for wireguard:
# container wireguard.service [Unit] Description=Podman container for wireguard Documentation=https://github.com/linuxserver/docker-wireguard [Service] Type=simple TimeoutStartSec=1m ExecStartPre=/usr/bin/podman rm -i wireguard ExecStartPre=/usr/sbin/modprobe iptable_raw ExecStart=/usr/bin/podman-compose -f /local/wireguard/wireguard.yml up ExecStop=-/usr/bin/podman-compose -f /local/wireguard/wireguard.yml down ExecReload=-/usr/bin/podman-compose -f /local/wireguard/wireguard.yml down ExecReload=-/usr/bin/podman-compose -f /local/wireguard/wireguard.yml up Restart=always RestartSec=30 KillMode=none [Install] WantedBy=multi-user.target
As you can see from my docker compose file, I don’t use the wireguard-ui. Personally, I found no need for it.
Resources
There were a couple of url’s that gave me the information I needed to get my setup to work.