broke my bed now it's dead

Setup WireGuard server on Alpine Linux

Posted on

Let's do this baremetal, no Docker!

I will do this inside a Proxmox virtual machine.

Get started

Start by installing Alpine Linux: Run the installer, next, next, next, and boot the os once it's done.

Setup ssh

Copy ssh key (run this on your local machine):

ssh-copy-id -i ~/.ssh/ user@ip

Login via ssh, and install your favorite editor:

doas apk add vim

Edit ssh config to force ssh key use:

doas vim /etc/ssh/sshd_config

Find and update these statements:

PermitRootLogin no
PubkeyAuthentication yes

Restart ssh service, logout, and log back in

doas rc-service sshd restart

Setup alpine package manager

I use as my mirror



add the community repo, and run updates:

doas apk -U upgrade

WireGuard basics

Install WireGuard:

doas apk add wireguard-tools

Kernel module

Load the module

doas modprobe wireguard

To launch the module on startup, edit


and simply add


at the bottom, and save the file.

IP forwarding



and add

net.ipv4.ip_forward = 1

at the bottom of the file, and save

Launch sysctl on startup with

doas rc-update add sysctl

and reboot.

IP Addresses

Pick a range if ip addresses to use: RFC 1918

I'll pick 10.131.111.x for the WireGuard peers.

Calculate your CIDR:

Here's my network layout:

Network services:


Generate keys for WireGuard

Do everything as root (doas is the equivalent of sudo):

doas su

Move to the wireguard configuration, I'll store everything there for easy access:

cd /etc/wireguard/

Generate the private and public key, store them in files (we'll use them later):

wg genkey | tee philt3r-privatekey | wg pubkey > philt3r-publickey

Configure server interface

All the server configuration will happen in


Protip for vim users: To add content of a file in current buffer directly: StackOverflow answer

# Name = wg0
Address =
ListenPort = 51820
PrivateKey = <server-private-key>
PostUp = iptables -t nat -A POSTROUTING -s -o %i -j MASQUERADE;
PostUp = iptables -t nat -A POSTROUTING -s -o %i -j MASQUERADE;
PostUp = iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT;
PostUp = iptables -A FORWARD -i %i -j ACCEPT;
PostUp = iptables -A FORWARD -o %i -j ACCEPT;
PostDown = iptables -t nat -D POSTROUTING -s -o %i -j MASQUERADE;
PostDown = iptables -t nat -D POSTROUTING -s -o %i -j MASQUERADE;
PostDown = iptables -D INPUT -p udp -m udp --dport 51820 -j ACCEPT;
PostDown = iptables -D FORWARD -i %i -j ACCEPT;
PostDown = iptables -D FORWARD -o %i -j ACCEPT;

Once it's good, make sure only root can read and write to the files:

chmod 600 /etc/wireguard/*

Add new peer

You will need to repeat this for each new peer

cd /etc/wireguard/

Generate keys

Starting now, name is a placeholder for the name of the peer.

I typically use the format name-of-person followed by device-name. For example, the peer for my phone will be phil-iphone.

Create folder to store keys for the peer:

mkdir -p peers/name

Generate preshared key (not required):

wg genpsk | tee peers/name/preshared.psk

Generate private and public keys for the peer:

wg genkey | tee peers/name/private.key | wg pubkey > peers/name/public.key

Update server configuration

Edit your wg0.conf, add at the bottom:

# Name = name
PublicKey = <peers/name/public.key>
PresharedKey = <peers/name/preshared.psk>
AllowedIPs =
AllowedIPs =
AllowedIPs =

Peer configuration

Now let's create the configuration to give to the peer:

Create the file


And put the following

PrivateKey = <peers/name/private.key>
Address =
#DNS =

PublicKey = <server-public-key>
PresharedKey = <peers/name/preshared.psk>
Endpoint = <server-ip>:51820
AllowedIPs =
AllowedIPS =
PersistentKeepalive = 25

DNS info is not used yet, it's normal, I will enable it once my DNS server will be created (not in this blog post though).

Distribute config

Either give the configuration file we just created, or you can have multiple choices.

QR Code

Start by installing

apk add libqrencode

And run

qrencode -t ansiutf8 < peers/name/philt3r-name.wg.conf


Note: I'm using base64 on Alpine, which comes from BusyBox, the CLI may be different depending on the operating system you're using.

Encode the configuration file to a base64 string:

cat philt3r-name.wg.conf | base64 -w 0

And on the other device, decode the string and save to a file:

base64 -d > philt3r-name.wg.conf

Put the base64 encoded string, and send a EOF (usually ctrl + d).

Restart WireGuard

If you already have WireGuard running, simply run

rc-service wg restart

to restart the server with your new peer.

Start WireGuard manually

Make sure to open the port on your router in UDP mode! I spent a lot of time debugging to realize that my port was in TCP, double check!

Make sure to be root before, don't use doas or sudo!

wg-quick up wg0

On the peer, start the tunnel.

On the server, run


to check the status of WireGuard. You should see the peer and some stats it is connected.

If you do not see info about the peer even if it is not connected, that means you did something wrong in the configuration!

From your peer, you should be able to ping the WireGuard internal IP:

If you can ping the ip, you're good!

You may not be able to go on the internet, or even make DNS requests, it's normal.

We are just testing if the tunnel works. You can stop the tunnel.

Stop WireGuard manually

wg-quick down wg0

Script to launch on server startup

To start WireGuard on startup, we will write an OpenRC script. It will be located in


Put the following:



depend() {
    need localmount net sysctl
    after bootmisc

start() {
    ebegin "Starting WireGuard"
    wg-quick up wg0
    eend $?

stop() {
    ebegin "Stopping WireGuard"
    wg-quick down wg0
    eend $?

status() {
    wg show wg0

Give it executable access

chmod +x /etc/init.d/wg



Reboot and make sure everything works, you should see WireGuard logs when your server is starting.


These resources helped me when setting up my WireGuard server. Thanks!