WireGuard is an exciting, new, extremely simple VPN system that uses state-of-the-art cryptography. Its Linux implementation runs in the kernel, which provides a significant performance boost compared to traditional userspace VPN implementations

The WireGuard kernel module is great, but sometimes you might not be able to install new kernel modules. One example scenario is on a VPS that uses OpenVZ or LXC. For these cases, we can use wireguard-go, a userspace implementation of WireGuard. This is the same implementation used on MacOS, Windows, and the WireGuard mobile apps. This implementation is slower than the kernel module, but still plenty fast.

This post focuses on Debian, however the instructions should mostly work on other Linux distros too.

Install WireGuard Tools

We need to install the WireGuard tools (wg-quick). On Debian, you can run this as root:

echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable.list
printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable
apt update
apt install wireguard-tools --no-install-recommends

(see the WireGuard site for instructions if you're not on Debian)

Install Go

Unfortunately, since wireguard-go is not packaged for Debian, we need to compile it ourselves. To compile it, we first need to install the latest version of the Go programming language (currently version 1.13.4):

cd /tmp
wget https://dl.google.com/go/go1.13.4.linux-amd64.tar.gz
tar zvxf go1.13.4.linux-amd64.tar.gz
sudo mv go /opt/go1.13.4
sudo ln -s /opt/go1.13.4/bin/go /usr/local/bin/go

Now, running go version should show the version number.

Compile wireguard-go

Now that we've got Go, we can download and compile wireguard-go. Download the latest release version:

cd /usr/local/src
wget https://git.zx2c4.com/wireguard-go/snapshot/wireguard-go-0.0.20191012.tar.xz
tar xvf wireguard-go-0.0.20191012.tar.xz
cd wireguard-go-0.0.20191012

If you are on a system with limited RAM (such as a 256 MB or lower "LowEndSpirit" VPS), you will need to do a small tweak to the wireguard-go code to make it use less RAM. Open device/queueconstants_default.go and replace this:

MaxSegmentSize             = (1 << 16) - 1 // largest possible UDP datagram
	PreallocatedBuffersPerPool = 0 // Disable and allow for infinite memory growth

With these values (taken from device/queueconstants_ios.go):

MaxSegmentSize             = 1700
	PreallocatedBuffersPerPool = 1024

This will make it use a fixed amount of RAM (~20 MB max), rather than allowing memory usage to grow infinitely.

Now we can compile it:

make
# "Install" it
sudo cp wireguard-go /usr/local/bin

Running wireguard-go --version should work and show the version number.

If you have multiple VPSes that use the same OS version and architecture (eg. Debian 10, 64-bit), you can compile it on one of them and then just copy the wireguard-go binary to all the others.

Configuration

wg0.conf

You'll need to configure /etc/wireguard/wg0.conf to contain the configuration for your peer. This post won't go into significant detail about this; please refer to another general WireGuard guide (like this one) for more details. The basic jist is that you need to run:

wg genkey | tee privatekey | wg pubkey > publickey

to generate a public/private key pair for each peer, then configure the [Interface] with the private key for the peer, and a [Peer] section for each peer that can connect to it.

Your wg0.conf should end up looking something like:

[Interface]
Address = 10.123.0.2
PrivateKey = 12345678912345678912345678912345678912345678
ListenPort = 51820

[Peer]
PublicKey = 987654321987654321987654321987654321987654321
AllowedIPs = 10.123.0.1/32
Endpoint = 198.51.100.1:51820

systemd

We need to modify the systemd unit to pass the WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD flag to wireguard-go, to allow it to run on Linux. Open /lib/systemd/system/wg-quick@.service, find:

Environment=WG_ENDPOINT_RESOLUTION_RETRIES=infinity

and add this line directly below:

Environment=WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD=1

Finally, enable and start the systemd service:

systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0

Enabling the systemd service will connect the VPN on boot, and starting the systemd service will connect it right now.

You're Done

Now, everything should be working! You can check the status of wg-quick by running systemctl status wg-quick@wg0, which should return something like:

● wg-quick@wg0.service - WireGuard via wg-quick(8) for wg0
   Loaded: loaded (/lib/systemd/system/wg-quick@.service; enabled; vendor preset: enabled)
   Active: active (exited) since Mon 2019-07-01 06:30:30 UTC; 1 day 22h ago

Running wg will give you a list of all the peers, and some details about them:

interface: wg0
  public key: 987654321987654321987654321987654321987654321
  private key: (hidden)
  listening port: 38917

peer: 987654321987654321987654321987654321987654321
  endpoint: 198.51.100.1:51820
  allowed ips: 10.123.0.1/32
  latest handshake: 1 day, 22 hours, 59 minutes, 34 seconds ago
  transfer: 2.75 KiB received, 2.83 KiB sent
Short URL for sharing: https://d.sb/B5S. This entry was posted on 2nd July 2019 and is filed under Linux. You can leave a comment if you'd like to, or subscribe to the RSS feed to keep up-to-date with all my latest blog posts!

Comments

  1. Avatar for Galeej Galeej said:

    This is what I get on debian OpenVZ. Any help please.

    INFO: (wg0) 2019/08/02 15:29:46 Starting wireguard-go version v0.0.20190517-68-g1ff37e2-dirty
    ERROR: (wg0) 2019/08/02 15:29:46 Failed to create TUN device: operation not permitted
    Unable to access interface: Protocol not supported
    [#] ip link delete dev wg0
    Cannot find device "wg0"

    1. Avatar for Daniel15 Daniel15 said:

      This likely means that your VPS provider has not enabled TUN support for your VPS. You'll need to contact them and get them to enable it.

      1. Avatar for Billy G Billy G said:

        Can you suggest a provider which is inexpensive and reliable? As you mentioned in the other post $4/year that's a crazy attractive price.

        1. Avatar for Daniel15 Daniel15 said:

          If you don't need much RAM or disk space, MrVM has some plans starting at $4/year for 128 MB RAM and 3 GB disk space: https://mrvm.net/natvps/. I usually stick to 256 MB RAM as a minimum though. I'm using several of these 256 MB RAM MrVM VPSes for my site at https://dnstools.ws/, as it needs locations all around the world.

  2. Avatar for Tim X Tim X said:

    I got this failure while compiling on a new OpenVZ box, using Debian 9:

    Makefile:20: recipe for target 'wireguard-go' failed
    make[1]: *** [wireguard-go] Error 2
    Makefile:11: recipe for target 'generate-version-and-build' failed
    make: *** [generate-version-and-build] Error 2
    boink@localhost:/usr/local/src/wireguard-go$ go version
    go version go1.13.3 linux/amd64

    Will it not compile on go1.13.1?

    1. Avatar for Daniel15 Daniel15 said:

      What's the full output you got from the build?

      1. Avatar for Tim X Tim X said:

        I made the mistake of trying to compile it on a OpenVZ VPS. I got memory errors *doh*

        Instead, I compiled it on a VPS with enough memory. I will see how it goes. I used the git clone function.

    2. Avatar for Daniel15 Daniel15 said:

      I just uploaded a version that I compiled myself. Try that and see if it works for you?
      https://d.ls/wireguard/wire...

      This was compiled on a 64-bit machine running Debian 10.

      1. Avatar for Tim X Tim X said:

        Thanks for the pre-compiled version. I still could not get it to compile. heh.

  3. Avatar for Tim X Tim X said:

    And using go1.12.12, it did not compile as well:

    go: golang.org/x/net@v0.0.0-201... git fetch -f origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /root/go/pkg/mod/cache/vcs/4a22365141bc4eea5d5ac4a1395e653f2669485db75ef119e7bbec8e19b12a21: exit status 128:
    fatal: early EOF
    go: error loading module requirements
    Makefile:20: recipe for target 'wireguard-go' failed
    make[1]: *** [wireguard-go] Error 1
    Makefile:11: recipe for target 'generate-version-and-build' failed
    make: *** [generate-version-and-build] Error 2
    root@localhost:/usr/local/src/wireguard-go# go version
    go version go1.12.12 linux/amd64

  4. Avatar for Tim X Tim X said:

    And just for good measure, it would not compile with go1.12.6 either on Debian 9, OpenVZ.

  5. Avatar for h021kk h021kk said:

    Big thanks to Daniel who wrote guide on "WireGuard on OpenVZ/LXC" https://d.sb/2019/07/wiregu... . I have tried & tested Daniel's guide and its even working on Debian OpenVZ6 & 7 NAT VPS

    OpenVZ6
    Debian 8.11 x64 - 128MB NAT VPS Kernal: 2.6.32-042stab130.1
    Debian 8.11 x64 - 256MB NAT VPS Kernal: 2.6.32-042stab140.1

    Only one client is working, tried to add multiple clients but still only one client worked
    IPv6 doesn't work
    Speed is faster than Openvpn
    low memory usage
    OpenVZ7
    Debian 9.11 x64 - 512MB NAT VPS - Kernal: 4.9.0

    Multiple clients working
    IPv6 working
    Speed is good
    low memory usage
    KVM
    Used installer of https://github.com/l-n-s/wi...

    Automated installer for setup, adding clients & clients profile file.
    IPv6 worked when added manually in wg0.conf
    Speed is very good
    low memory usage
    Big Thanks to Daniel (https://d.sb/2019/07/wiregu.... If anyone try to play, here are the details and commands. I have used Daniel's guide, please follow all steps, I added few commands as i got errors i.e apt install make and wg-quick up wg0 and wg-quick down wg0

    echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable.list && printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable && apt update

    apt install wireguard-tools --no-install-recommends

    cd /tmp && wget https://dl.google.com/go/go... && tar zvxf go1.13.4.linux-amd64.tar.gz && sudo mv go /opt/go1.13.4 && sudo ln -s /opt/go1.13.4/bin/go /usr/local/bin/go

    go version

    (have to install make, it wasn't install in my vps)
    apt install make

    cd /usr/local/src && wget https://git.zx2c4.com/wireg... && tar xvf wireguard-go-0.0.20191012.tar.xz && cd wireguard-go-0.0.20191012

    (set these variables if you are using VPS less than 256MB)

    nano device/queueconstants_default.go

    MaxSegmentSize = 1700
    PreallocatedBuffersPerPool = 1024

    (Run make command)
    make

    sudo cp wireguard-go /usr/local/bin

    wireguard-go --version

    (Create public & private keys for Server)
    wg genkey | tee private key | wg pubkey > publickey

    nano /lib/systemd/system/wg-quick@.service

    add this line directly below
    Environment=WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD=1

    (Perform these commands or wg0-quick will give error and wg0 interface won't come UP)
    wg-quick up wg0

    wg-quick down wg0

    Add following two lines in Server [Interface] /etc/wireguard/wg0.conf only if you using only IPv4

    PostUp = iptables -t nat -A POSTROUTING -o venet0 -j MASQUERADE
    PostDown = iptables -t nat -D POSTROUTING -o venet0 -j MASQUERADE)

    For IPv6, add these in /etc/wireguard/wg0.conf

    PostUp = iptables -t nat -A POSTROUTING -o venet0 -j MASQUERADE; ip6tables -t nat -A POSTROUTING -o venet0 -j MASQUERADE
    PostDown = iptables -t nat -D POSTROUTING -o venet0 -j MASQUERADE; ip6tables -t nat -D POSTROUTING -o venet0 -j MASQUERADE

    systemctl enable wg-quick@wg0
    systemctl start wg-quick@wg0

    wg
    (check wg running)

    Install Wireguard Client. I have used android and windows 10 client. Generate public and private keys in client software/App and set client "public key" in server wg0.conf on SERVER & set server "public key" in CLIENT

    thats it

    ===============
    Following are my conf

    OpenVZ6 VPS

    Server Config /etc/wireguard/wg0.conf

    [Interface]
    Address = 10.66.66.1/24
    PrivateKey = PRIVATE KEY OF SERVER
    ListenPort = PORT
    PostUp = iptables -t nat -A POSTROUTING -o venet0 -j MASQUERADE
    PostDown = iptables -t nat -D POSTROUTING -o venet0 -j MASQUERADE
    SaveConfig = false
    [Peer]
    PublicKey = PUBLIC KEY OF CLIENT
    AllowedIPs = 10.66.66.3/24

    Client Config

    [Interface]
    PrivateKey = PRIVATE KEY OF CLIENT
    Address = 10.66.66.3/24
    DNS = 8.8.8.8, 8.8.4.4

    [Peer]
    PublicKey = PUBLIC KEY OF SERVER
    AllowedIPs = 0.0.0.0/0, ::/0
    Endpoint = SERVER IP:PORT
    PersistentKeepalive = 25

    Frequently used commands

    nano /etc/wireguard/wg0.conf

    systemctl enable wg-quick@wg0

    systemctl status wg-quick@wg0

    systemctl start wg-quick@wg0

    systemctl stop wg-quick@wg0

    wg-quick up wg0

    wg-quick down wg0

    ===============

    OpenVZ7

    Server Config /etc/wireguard/wg0.conf

    [Interface]
    Address = 10.123.0.1/24,fd42:42:42::1/80
    PrivateKey = PRIVATE KEY OF SERVER
    ListenPort = PORT
    PostUp = iptables -t nat -A POSTROUTING -o venet0 -j MASQUERADE; ip6tables -t nat -A POSTROUTING -o venet0 -j MASQUERADE
    PostDown = iptables -t nat -D POSTROUTING -o venet0 -j MASQUERADE; ip6tables -t nat -D POSTROUTING -o venet0 -j MASQUERADE
    SaveConfig = false

    [Peer]
    PublicKey = PUBLIC KEY OF CLIENT1
    AllowedIPs = 10.123.0.3/32,fd42:42:42::3/128

    [Peer]
    PublicKey = PUBLIC KEY OF CLIENT2
    AllowedIPs = 10.123.0.4/32,fd42:42:42::4/128

    Client1 Config

    [Interface]
    PrivateKey = PRIVATE KEY OF CLIENT1
    Address = 10.123.0.3/24, fd42:42:42::3/80
    DNS = 8.8.8.8, 8.8.4.4, 2001:4860:4860::8888

    [Peer]
    PublicKey = PUBLIC KEY OF SERVER
    AllowedIPs = 0.0.0.0/0, ::/0
    Endpoint = SERVER IP:PORT
    PersistentKeepalive = 25

    Client2 Config

    [Interface]
    PrivateKey = PRIVATE KEY OF CLIENT2
    Address = 10.123.0.4/24, fd42:42:42::4/80
    DNS = 8.8.8.8, 8.8.4.4, 2001:4860:4860::8888

    [Peer]
    PublicKey = PUBLIC KEY OF SERVER
    AllowedIPs = 0.0.0.0/0, ::/0
    Endpoint = SERVER IP:PORT
    PersistentKeepalive = 25

  6. Avatar for Tim X Tim X said:

    Has anyone ever got this working on Debian 10 (OpenVZ) ?

    I just tried it on Debian 10 and there was no routing (though, I could have done something very stupid).

    I went back to Debian 9, and it worked right away. Though. for the routing I am using ufw instead.

    1. Avatar for Daniel15 Daniel15 said:

      I got it working fine on Debian 10. However, I don't route anything over the VPN tunnel other than traffic directly for the VPN IP addresses (I just use it for a point-to-point VPN). That configuration doesn't require any special routing config.

  7. Avatar for Tim X Tim X said:

    Hi Everyone! This is great documentation, as OpenVZ vps's have their limitations.

    Though, this documentation is a little old. Would an update be possible for the newer versions of golang (18.3) and the latest wireguard-go (0.0.20220316).

    Once I have it written, I'll pass on the link. There are just a few little adjustments needed.

    1. Avatar for Daniel15 Daniel15 said:

      If you let me know what changes are required, I'll update the post. Thanks!

  8. Avatar for Alex Toshev Alex Toshev said:

    Great guide! Managed to get it working on Ubuntu 22.04 OpenVZ VPS. Didn't have the `tun` device so just added two commands about it:
    ```bash
    mkdir -p /dev/net
    mknod /dev/net/tun c 10 200
    ```