Alpine Linux set up WireGuard VPN server

How do I install and set up WireGuard VPN server on an Alpine Linux cloud server? How can I configure Alpine Linux as the WireGuard VPN server? How can I configure snat to route all VPN traffic on my Alpine Linux?

Tutorial details
Difficulty level Advanced
Root privileges Yes
Requirements Alpine Linux
Est. reading time 7 mintues
WireGuard is a free, open-source advanced, and high-speed VPN with state-of-the-art cryptography. It is quicker and simpler as compared to IPSec and OpenVPN implementations. It was initially released for the Linux kernel, but it is getting cross-platform support for other operating systems. This page explains how to install and set up WireGuard VPN on the Alpine Linux cloud server.

Procedure: Alpine Linux set up WireGuard VPN server

Our sample setup includes a simple peer connection between a cloud server running Alpine Linux server, and a CentOS/Ubuntu/Debian Linux desktop client. You can use iOS/Android mobile clients too. The steps are as follows for installing and configuring WireGuard on Alpine Linux as a VPN server.
How to Set Up WireGuard VPN on Alpine Linux

Please note that [root@alpine-linux ~]# OR {vivek@client:~ }$ is my shell prompt and is not part of actual commands. In other words, you need to copy and paste command after my shell prompt.

Step 1 – Update your system

Run the apk command to install Alpine Linux security updates:
[root@alpine-linux ~]# apk update
[root@alpine-linux ~]# apk upgrade

Outputs:

fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
v3.12.0-373-gddde33ae67 [http://dl-cdn.alpinelinux.org/alpine/v3.12/main]
v3.12.0-372-g0452e24486 [http://dl-cdn.alpinelinux.org/alpine/v3.12/community]
OK: 12744 distinct packages available

Step 2 – Installing a WireGuard VPN server on Alpine Linux LTS

To find Linux kernel version, run:
[root@alpine-linux ~]# uname -mrs
Linux 5.4.43-1-virt x86_64

For virt kernel use the wireguard-virt package and for lts kernel use the wireguard-lts package. In other words, setting up a WireGuard VPN server on Alpine Linux server, enter:
[root@alpine-linux ~]# apk add wireguard-tools wireguard-virt
Alpine Linux LTS install WireGuard using apk

Step 3 – Configuring WireGuard server

First we need to create a private and public key pair for the WireGuard server. Let us cd into /etc/wireguard using the cd command:
[root@alpine-linux ~]# cd /etc/wireguard/
Execute the following umask command along with wg command:
[root@alpine-linux ~]# umask 077; wg genkey | tee privatekey | wg pubkey > publickey
To view keys created use the cat command and ls command:
[root@alpine-linux ~]# ls -l privatekey publickey
[root@alpine-linux ~]# cat privatekey
## Please note down the private key ##
[root@alpine-linux ~]# cat publickey

Set Up WireGuard VPN on Alpine Linux Linux

Set Up WireGuard VPN on Alpine Linux by Editing wg0.conf

Edit or update the /etc/wireguard/wg0.conf file as follows:
[root@alpine-linux ~]# nano /etc/wireguard/wg0.conf
## OR ##
[root@alpine-linux ~]# vi /etc/wireguard/wg0.conf

Append the following config directives:

## Set Up WireGuard VPN on Alpine Linux By Editing/Creating wg0.conf File ##
[Interface]
## My VPN server port ##
ListenPort = 31194
 
## VPN server's private key i.e. /etc/wireguard/privatekey ##
PrivateKey = 2IHAoIOz+tWxRZ4oRlI1xHiD5FADVBTKOePnLSZNSkw=
 
[Peer]
## Desktop/client VPN public key (created in step # 6) ##
PublicKey = d7TRyBXIX0I3sC/tPOqrIpNAGwEt2bW43QXKK4cEeGw=
 
## client VPN IP address (note  the /32 subnet) ##
AllowedIPs = 192.168.20.2/32

Save and close the file when using vim text editor.

Step 4 – Set up Awall firewall rules

I am assuming that you have Awall configured on Alpine Linux. If not, please configure Awall, which is needed for the following config to work correctly.

Open UDP 31194 port using the following config file

[root@alpine-linux ~]# cat /etc/awall/private/custom-services.json
Let us define WireGuard and Squid server port on Alpine Linux for Awall:

{
    "service": {
        "wireguard": [
            { "proto": "udp", "port": 31194 }
        ],
        "squid": [
            { "proto": "tcp", "port": 3128 }
        ]
    }
}

Update Awall config

Next update your main config file to enable routing and other stuff. In my case:
[root@alpine-linux ~]# cat /etc/awall/optional/cloud-server.json
Add/edit with import custom-services and policy for WireGuard and Internet zone as follows:

{
  "description": "Default awall policy to protect Cloud server",
  "import": "custom-services",
  "variable": { "internet_if": "eth0"},
  "zone": {
    "internet": { "iface": "$internet_if" },
    "vpn": { "iface": "wg0" }
  },
  "policy": [
    { "in": "internet", "action": "drop" },
    { "in": "vpn", "out": "internet", "action": "accept" },
    { "out": "vpn", "in": "internet", "action": "accept" },
    { "action": "reject" }
  ],
  "snat": [ { "out": "internet", "src": "192.168.20.1/24" } ]
}

Save and close the file and then open WireGuard port:
[root@alpine-linux ~]# cat /etc/awall/optional/wireguard.json

{
    "description": "Allow incoming WireGuard UDP port 31194",
    "filter": [
        {
            "in": "internet",
            "out": "_fw",
            "service": "wireguard",
            "action": "accept"
        }
    ]
}

Accept incoming traffic on WireGuard VPN port from WG0 sub/net

[root@alpine-linux ~]# cat /etc/awall/optional/vpntraffic.json
Sample config:

{
    "description": "Allow VPN traffic for selected ports",
    "filter": [
        {
            "in": "vpn",
            "out": "_fw",
            "service": [ "ssh", "dns", "squid", "ping" ],
            "action": "accept",
	    "src": "192.168.20.1/24"
        }
    ]
}

Activate all Awall firewall rule as follows

Run:
[root@alpine-linux ~]# awall list
[root@alpine-linux ~]# awall enable wireguard
[root@alpine-linux ~]# awall enable vpntraffic
[root@alpine-linux ~]# awall activate
## VERIFY that port opened ##
[root@alpine-linux ~]# iptables -S | grep 31194
[root@alpine-linux ~]# ip6tables -S | grep 31194

Alpine Linux Awall Open WireGuard UDP 31194 port

Allow forwarding of IP packets

Edit the /etc/conf.d/iptables file:
[root@alpine-linux ~]# vi /etc/conf.d/iptables
Find:
IPFORWARD="no"
Update as follows:
IPFORWARD="yes"
Save and close the file. Make sure we activate IP forwarding:
[root@alpine-linux ~]# rc-service iptables restart
[root@alpine-linux ~]# rc-service ip6tables restart
[root@alpine-linux ~]# sysctl net.ipv4.ip_forward

Value 1 indicating that Alpine Linux is now acting as a router:

net.ipv4.ip_forward = 1

Step 5 – Enable and start WireGuard service

Make sure bash installed on Alpine Linux as needed by /etc/network/interfaces:
[root@alpine-linux ~]# apk add bash
Edit the /etc/network/interfaces, run:
[root@alpine-linux ~]# vi /etc/network/interfaces
Append config options for wg0 so that it will start automatically when Alpine Linux boots:

# WireGuard interface with private IP #
auto wg0
iface wg0 inet static
	address 192.168.20.1
	netmask 255.255.255.0
	pre-up ip link add dev wg0 type wireguard
	pre-up wg setconf wg0 /etc/wireguard/wg0.conf
	post-up ip route add 192.168.20.1/24 dev wg0
	post-down ip link delete wg0

Use the ip command or ifconfig command to start WireGuard interface called wg0 manually. It is a one-time, reboot-less option else rebooting the Linux box to activate WiregGuard from /etc/network/interfaces file:
[root@alpine-linux ~]# ip link add dev wg0 type wireguard
[root@alpine-linux ~]# wg setconf wg0 /etc/wireguard/wg0.conf
[root@alpine-linux ~]# ifconfig wg0 192.168.20.1 netmask 255.255.255.0
## [ FLUSH it to avoid RTNETLINK error for existing routing table ] ##
[root@alpine-linux ~]# ip addr flush dev wg0
[root@alpine-linux ~]# ip route add 192.168.20.1/24 dev wg0
[root@alpine-linux ~]# ifconfig wg0 up

We can take down wg0 as follows:
[root@alpine-linux ~]# ifconfig wg0 down
Verify that WireGuard is up and running using the ss command/netstat command/lsmod command along with the grep command:
[root@alpine-linux ~]# netstat -tulpn | grep 31194
## OR ##
[root@alpine-linux ~]# ss -tulpn | grep 31194
[root@alpine-linux ~]# lsmod | grep -i wireguard
## See routing and interface information ##
[root@alpine-linux ~]# ifconfig wg0
[root@alpine-linux ~]# route -n

Step 6 – Wireguard VPN client configuration

The procedure for installing and configuring a VPN client is the same as setting up the server. Let us install the client on Ubuntu Linux LTS desktop:
{vivek@client:~ }$ apt install wireguard
Next we need create VPN client config on Linux desktop client:
{vivek@client:~ }$ sh -c 'umask 077; touch /etc/wireguard/wg0.conf'
{vivek@client:~ }$ sudo -i
{vivek@client:~ }$ cd /etc/wireguard/
{vivek@client:~ }$ umask 077; wg genkey | tee privatekey | wg pubkey > publickey
{vivek@client:~ }$ ls -l publickey privatekey
## Note down the privatekey ##
{vivek@client:~ }$ cat privatekey

Edit the /etc/wireguard/wg0.conf file:
{vivek@client:~ }$ nano /etc/wireguard/wg0.conf
## OR ##
{vivek@client:~ }$ vi /etc/wireguard/wg0.conf

Append the following directives:

[Interface]
## This Desktop/client's private key ##
PrivateKey = yK3iYrAN6p3OjqO7i1EZHOFpjRwsW+KoSnYqVKWYJWQ=
 
## Client ip address ##
Address = 192.168.20.2/24
 
[Peer]
## Alpine Linux  server public key ##
PublicKey = jrmb57ih/aiW/a3/eLWP4Aq4av2UkcQyDpTkVaHq0ks=
 
## set ACL and turn on VPN routing ##
AllowedIPs = 0.0.0.0/0  
 
## Your Alpine Linux  LTS server's public IPv4/IPv6 address and port ##
Endpoint = 172.105.63.200:31194
 
##  Key connection alive ##
PersistentKeepalive = 20

Enable and start VPN client/peer connection, run:
{vivek@client:~ }$ systemctl enable wg-quick@wg0
{vivek@client:~ }$ systemctl start wg-quick@wg0
{vivek@client:~ }$ systemctl status wg-quick@wg0

Step 7 – Verification

That is all, folks. By now, both Alpine Linux server and clients must be connected securely using a peer-to-peer VPN called WireGuard. Let us test the connection. Type the following ping command/ip command on your client machine/desktop system:
{vivek@client:~ }$ ping -c 4 192.168.20.1
{vivek@client:~ }$ sudo wg
{vivek@client:~ }$ ip r

Check or find your public IP address from command line on a Linux desktop. You must get your VPN servers IP address:
$ dig TXT +short o-o.myaddr.l.google.com @ns1.google.com
$ dig +short myip.opendns.com @resolver1.opendns.com
$ curl checkip.amazonaws.com

Test Wireguard VPN on Alpine Linux

Conclusion

Congratulation! You just learned about setting up a WireGuard VPN server on Alpine Linux and peer (client machine) on both Alpine Linux/Ubuntu Linux desktop. I strongly suggest that you read WireGuard project documentation.

This entry is 6 of 7 in the WireGuard moden Linux/Unix/*BSD VPN Tutorial series. Keep reading the rest of the series:
  1. Ubuntu 20.04 set up WireGuard VPN server
  2. CentOS 8 set up WireGuard VPN server
  3. Debian 10 set up WireGuard VPN server
  4. WireGuard Firewall Rules in Linux
  5. Wireguard VPN client in a FreeBSD jail
  6. Alpine Linux set up WireGuard VPN server
  7. Import WireGuard profile using nmcli on Linux


🐧 Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or Weekly email newsletter.

🐧 17 comments so far... add one

CategoryList of Unix and Linux commands
Disk space analyzersdf ncdu pydf
File Managementcat tree
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Network UtilitiesNetHogs dig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg jobs killall kill pidof pstree pwdx time
Searchinggrep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04
17 comments… add one
  • Anonymous Oct 8, 2020 @ 23:06

    How can I restart WireGuard service when I added a new VPN client?

    • 🐧 Vivek Gite Oct 9, 2020 @ 7:45

      Take down interface and bring it back:
      ifconfig wg0 down \
      && ip link delete wg0 \
      && ip link add dev wg0 type wireguard \
      && wg setconf wg0 /etc/wireguard/wg0.conf \
      && ifconfig wg0 $YOUR_IP netmask $SUB_NET up \
      && ip route add $YOUR_ROUTE dev wg0

      Connect from Peer (VPN clinet) and verify it with:
      wg

  • AppU Oct 9, 2020 @ 7:50

    Hey,

    Instead of using the wg command in /etc/network/interfaces we can use wg-quick[1].

    auto wg0
    iface wg0 inet static
    	address 192.168.20.1
    	netmask 255.255.255.0
    	post-up wg-quick up /etc/wireguard/wg0.conf
    	post-down wg-quick down /etc/wireguard/wg0.conf

    This will be easy when we add new clients. We can add address in wg0.conf too.
    [1]https://manpages.debian.org/unstable/wireguard-tools/wg-quick.8.en.html

  • Zia Oct 13, 2020 @ 8:50

    Hi Vivek,
    So I ran the apk upgrade
    apk upgrade
    My wireguard server and linux kernel has been updated by Alpine:

    (1/2) Upgrading linux-virt (5.4.43-r1 -> 5.4.70-r0)
    (2/2) Upgrading wireguard-virt (5.4.43-r1 -> 5.4.70-r0)
    Executing busybox-1.31.1-r19.trigger
    Executing kmod-27-r0.trigger
    Executing mkinitfs-3.4.5-r3.trigger
    ==> initramfs: creating /boot/initramfs-virt
    Executing grub-2.04-r1.trigger
    Generating grub configuration file ...
    Found linux image: /boot/vmlinuz-virt
    Found initrd image: /boot/initramfs-virt
    done
    Executing syslinux-6.04_pre1-r6.trigger
    /boot is device /dev/sda
    extlinux: no previous syslinux boot sector found
    OK: 382 MiB in 200 packages

    My questions to you: Do i need to reboot the box to get wireguard updates? what will happen to my wg0.conf config files? do i need to recreate those config again on the server? would appreciate reply.

    • 🐧 Vivek Gite Oct 13, 2020 @ 8:54

      Yes, reboot the Alpine Linux server to get an updated version of Linux kernel including WireGuard.

      No need to create config files. Old files will load automatically.

  • Yures Dec 28, 2020 @ 12:46

    Great article, thank you. But what firewall rules do I need to create so that vpn clients can connect to each other, for example via ssh or rdp?

    • 🐧 Vivek Gite Dec 28, 2020 @ 13:58

      Edit the /etc/awall/optional/vpntraffic.json (see above) and allows ssh and rdp port from firewall to vpn client. For instance:

      {
          "description": "Allow VPN traffic for selected ports",
          "filter": [
              {
                  "in": "vpn_wg0",
                  "out": "_fw",
                  "service": [ "ssh", "dns", "squid", "ping" ],
                  "action": "accept",
                  "src": "$wg0_sub_net"
              },
              {
                  "out": "vpn_wg0",
                  "service": [ "ssh", "rdp" ],
                  "action": "accept",
                  "src": "$wg0_sub_net"
              }
          ]
      }
      

      Activate the firewall:
      awall activate
      From client1 to client2
      ssh user@client2

      • Yures Dec 28, 2020 @ 14:11

        Thank you very much. And how do I allow all connections between clients?

        • 🐧 Vivek Gite Dec 28, 2020 @ 16:46

          The above allows connection between ALL VPN clients only for ssh and rdp. So, feel free to edit the "src": "1.2.3.4", OR "src": [ "vpn_client_ip_1", "vpn_client_ip_1", "vpn_client_ip_1" ].

          • Yures Dec 29, 2020 @ 7:44

            I apologize, I misspoke. I meant to allow all services (or ports) between clients.

            • 🐧 Vivek Gite Dec 29, 2020 @ 8:49

              In that case don’t edit the /etc/awall/optional/vpntraffic.json. Edit the /etc/awall/optional/cloud-server.json and set up default policy to allow all traffic between vpn interfaces:

              {
                "description": "Default awall policy to protect Cloud server",
                "import": "custom-services",
                "variable": { "internet_if": "eth0"},
                "zone": {
                  "internet": { "iface": "$internet_if" },
                  "vpn": { "iface": "wg0" }
                },
                "policy": [
                  { "in": "internet", "action": "drop" },
                  { "in": "vpn_wg0", "action": "accept" },                                                                                                                                                                                                                  
                  { "out": "vpn_wg0", "action": "accept" },                                                                                                                                                                                                                 
                  { "in": "vpn", "out": "internet", "action": "accept" },
                  { "out": "vpn", "in": "internet", "action": "accept" },
                  { "action": "reject" }
                ],
                "snat": [ { "out": "internet", "src": "192.168.20.1/24" } ]
              }
              • Yures Mar 31, 2021 @ 13:23

                What if I want to access the entire network behind one of the clients?

                • 🐧 Vivek Gite Mar 31, 2021 @ 19:35

                  You need to adjust those firewall and NAT rules. Just play with it.

  • Owen Jan 1, 2021 @ 9:30

    Hi, getting RTNETLINK answers: Invalid argument when adding
    ip route add 192.168.20.1/24 dev wg0
    on Linux 5.4.84-0-virt x86_64

    Also there is a type rounte -n => route -n

    -Owen

    • 🐧 Vivek Gite Jan 1, 2021 @ 9:57

      First, try to flush it as it cannot add existing route again:
      ip addr flush dev wg0
      ip route add 192.168.20.1/24 dev wg0

      Fixed the typo. Thanks!

  • Nawir Feb 18, 2021 @ 0:42

    In Wireguard Server this part
    [Peer]
    ## Desktop/client VPN public key (created in step # 6) ##
    PublicKey = d7TRyBXIX0I3sC/tPOqrIpNAGwEt2bW43QXKK4cEeGw=

    How if I have 3 clients. Do I need to type 3 lines of client PublicKey

    tq

    • 🐧 Vivek Gite Feb 18, 2021 @ 6:30

      yes. You need 3 [peer] lines. For instance:

      [Peer]
      # iphone11
      PublicKey = iphone-11-pub-key
      AllowedIPs = 10.8.0.3/32
      
      [Peer]
      # android 
      PublicKey = android-pub-key
      AllowedIPs = 10.8.0.4/32
      
      [Peer]
      # macbookpro
      PublicKey = mac-pub-key
      AllowedIPs = 10.8.0.5/32

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre> for code samples. Still have questions? Post it on our forum