Guide: WireGuard on OpenVZ/LXC VPS

DanielDaniel OG
edited November 2019 in Technical

I posted something like this somewhere in the old forum (and on my blog), but figured it was worth reposting in this new forum.

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 (256 MB or lower), which you probably are if you're on this forum, 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/[email protected], 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:

[email protected] - WireGuard via wg-quick(8) for wg0 
   Loaded: loaded (/lib/systemd/system/[email protected]; 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
Tagged:
«1

Comments

  • InceptionHostingInceptionHosting Hosting ProviderOG

    @Daniel i really appreciate you taking the time to post this, its exactly the sort of content that makes the community backbone stronger!

    https://inceptionhosting.com
    Please do not use the PM system here for Inception Hosting support issues.

  • AnthonySmith said: i really appreciate you taking the time to post this, its exactly the sort of content that makes the community backbone stronger!

    I'm happy to help! :)

    In case anyone doesn't want to compile wireguard-go themselves for some reason, here's a version I built on a 64-bit machine running Debian 10: https://d.ls/wireguard/wireguard-go-v0.0.20191012. Do prefer compiling it yourself though

    Thanked by (3)flips uptime greensysadmin
  • Thanks @Daniel, I didn't know you were an active user on here, I posted a link to your guide last week:

    https://talk.lowendspirit.com/discussion/comment/3897#Comment_3897

    Notes from me:

    • Pinning the unstable Debian repo to get the wireguard-tools package in a 128MB LES NAT VPS gave me "failed to fork" errors with apt commands. Switching to Anthony's new slimline Ubuntu 18.04 template meant I could use the Wireguard PPA instead, which doesn't use as much resources. Pinning the unstable repo might work fine on the new 256MB plans though...

    • Compiling the wireguard-go binary is much better done on a local machine with more resources than a LES box (be sure to make the necessary adjustments detailed to keep RAM usage low!) Once it spits out the binary, push it onto your LES box with SCP/SFTP etc., copy it to /usr/local/bin and make it executable

    I've got this setup working nicely on one of Ant's UK 128MB NAT VPSes, and even though Wireguard is the userspace go implementation, speeds have been better than OpenVPN for me. Of course, OpenVPN is older and much more thoroughly historically audited compared to Wireguard (but that's a digression for someone else to take up).

    And thanks again @Daniel! Yours was the most comprehensive guide I found to get Wireguard working on OpenVZ!

  • greensysadmin said: Pinning the unstable Debian repo to get the wireguard-tools package in a 128MB LES NAT VPS gave me "failed to fork" errors with apt commands.

    Interesting! I didn't have any issues with it on my MrVM 128 MB NAT VPS. Another alternative is to just manually download the .deb from https://packages.debian.org/sid/amd64/wireguard-tools/download (for example by using wget) and install it using apt install./wireguard-tools_0.0.20191012-1_amd64.deb. You do need to manually install updates in that case though.

    greensysadmin said: Compiling the wireguard-go binary is much better done on a local machine with more resources than a LES box (be sure to make the necessary adjustments detailed to keep RAM usage low!)

    That's a good suggestion. Having said that, Wireguard-go is very light so compilation generally takes less than a minute, and I didn't have any issues with it on a 256 MB VPS. I did it on one VPS and then scp'd it to several others.

    greensysadmin said: Of course, OpenVPN is older and much more thoroughly historically audited

    The OpenVPN codebase is enormous though. Wireguard is significantly smaller, which also makes it easier to audit the entire codebase.

  • Has anyone done a "start wireguard on host then move to LXC container" configuration?

    There is a tutorial on wireguard's website but I wonder if there is an LXC-kosher way of doing it.

    The all seeing eye sees everything...

  • @terrorgen said:
    Has anyone done a "start wireguard on host then move to LXC container" configuration?

    There is a tutorial on wireguard's website but I wonder if there is an LXC-kosher way of doing it.

    Nvm got it working...

    The all seeing eye sees everything...

  • terrorgen said: Has anyone done a "start wireguard on host then move to LXC container" configuration?

    I haven't tried that yet, but it's something I'm interested in looking into. WireGuard's docs aren't very clear at the moment... But that's understandable, as far as I know it's mostly one guy (the creator, Jason Donenfield) writing most of the code and the docs. Pretty impressive.

    Thanked by (2)mfs terrorgen
  • flipsflips OG
    edited January 2020

    @Daniel said: Endpoint = 198.51.100.1:51820

    Hm, if using a NAT VPS, the endpoint would be my assigned NAT IPv4? And, what's the port number for?
    Or should I set it to the official IP I'm NAT'ed behind?
    Maybe I am confused as to the conceptual part?
    (I haven't read all docs yet, just started playing for the first time right now, just compiled the binary.) :)

  • WSSWSS OGRetired

    @flips said:

    @Daniel said: Endpoint = 198.51.100.1:51820

    Hm, if using a NAT VPS, the endpoint would be my assigned NAT IPv4? And, what's the port number for?
    Or should I set it to the official IP I'm NAT'ed behind?
    Maybe I am confused as to the conceptual part?
    (I haven't read all docs yet, just started playing for the first time right now, just compiled the binary.) :)

    You use the external IP to one of the ports allocated to your NAT VPS that aren't in use. It'll be sent magically to your private IP.

    Thanked by (1)flips

    My pronouns are like/subscribe.

  • DanielDaniel OG
    edited January 2020

    @flips said: if using a NAT VPS, the endpoint would be my assigned NAT IPv4? And, what's the port number for?

    For all my NAT VPSes, I'm using the IPv6 addresses (in general I use only IPv6 for inbound connections to NAT VPSes). You could use the IPv4 as long as you use a port number in your NAT port range, but I found it easier to use IPv6 so that every VPS can use the same port for WireGuard (makes my life easier when managing the configs).

    For IPv6, wrap them in [ and ], eg this is a part of my config:

    # it01
    [Peer]
    PublicKey = ....
    AllowedIPs = 10.123.1.15/32
    Endpoint = [2a00:dcc0:dead:ba59:248::1]:38917
    
    # de01
    [Peer]
    PublicKey = ...
    AllowedIPs = 10.123.1.16/32
    Endpoint = [2a01:4f8:a0:83b4:0585::1]:38917
    
    # fr01
    [Peer]
    PublicKey = ...
    AllowedIPs = 10.123.1.17/32
    Endpoint = [2a00:c70:1:213:246:58:3641:1]:38917
    
    

    or use domain names.

    That port number is just one I made up or took from the WireGuard docs (can't remember). It can be anything as long as you're not using that UDP port for anything else. If you do use the NAT IPv4, it needs to be a port in your port range.

    Thanked by (1)flips
  • @WSS said: You use the external IP to one of the ports allocated to your NAT VPS that aren't in use. It'll be sent magically to your private IP.

    Hehe, I do understand how NAT and the port forwarding of my ports work ... So the endpoint here in the server config should just correspond to what I put in the client config, then ...
    (I assumed it would be enough to tell my NAT VPS wireguard config about the local IP, listen on i.e. 192.168.20.20:12345, and then the client would be the one requiring <official IP>:12345 ...) :)

    Thanked by (1)WSS
  • @Daniel said:
    For all my NAT VPSes, I'm using the IPv6 addresses (in general I use only IPv6 for inbound connections to NAT VPSes). You could use the IPv4 as long as you use a port number in your NAT port range, but I found it easier to use IPv6 so that every VPS can use the same port for WireGuard (makes my life easier when managing the configs).

    For IPv6, wrap them in [ and ], eg this is a part of my config:

    # it01
    [Peer]
    PublicKey = ....
    AllowedIPs = 10.123.1.15/32
    Endpoint = [2a00:dcc0:dead:ba59:248::1]:38917
    ...
    

    Makes sense. :) Thank you. Another question, a couple of my frequent (wifi) location don't have IPv6 at all. Can I somehow connect via IPv4 to my Wireguard node, and then have full IPv6 from there? The config you showed here assumes IPv6 all the way?
    (Or maybe I should get some sleep, not thinking clearly now.)

    BTW: Thanks! This is super helpful! :+1: =)

  • @flips said: a couple of my frequent (wifi) location don't have IPv6 at all.

    You could get a HE Tunnelbroker IPv6 tunnel and set that up on your laptop :)

    @flips said: Can I somehow connect via IPv4 to my Wireguard node, and then have full IPv6 from there?

    I think it's possible (tunnelling 'public' IPv6 over WireGuard), not sure though. I just use it for a point-to-point VPN, connecting a bunch of VPSes together. Some VPN providers are using WireGuard now, so it should be doable.

    @flips said: The config you showed here assumes IPv6 all the way?

    Yeah, every internet connection I use frequently (home, work, phone) are all fully native IPv6, so I haven't had to worry about anything without IPv6 support.

  • My phone/LTE just offer CGNAT and no IPv6 ... :s

  • flipsflips OG
    edited January 2020

    @flips said: Can I somehow connect via IPv4 to my Wireguard node, and then have full IPv6 from there?

    @Daniel said: I think it's possible (tunnelling 'public' IPv6 over WireGuard), not sure though. I just use it for a point-to-point VPN, connecting a bunch of VPSes together. Some VPN providers are using WireGuard now, so it should be doable.

    Got it working. :)

    Thanked by (1)Daniel
  • @flips said: My phone/LTE just offer CGNAT and no IPv6 ...

    I've heard that CGNAT is relatively popular in various European countries, and in China. On the other hand, a lot of the American phone carriers are almost exclusively IPv6 now... T-Mobile is ~95% IPv6, using NAT64 to connect to legacy (IPv4-only) services.

  • (Got some help from this article too: https://angristan.xyz/how-to-setup-vpn-server-wireguard-nat-ipv6/)

    Do you guys know if setting up L2TP/Ipsec, openswan or something is doable/will work on an OpenVZ7 NAT VPS? (Some routers don't speek Wireguard.) :)

  • Hi all, a little late to this thread but hopefully someone might be able to shed some light. The guide is great and much appreciated, I have managed to get wireguard-go running on a 128mb LES NAT VPS. As the VPS has a /64 IPV6 subnet assigned, would it be possible to assign a /80 IPV6 subnet to the wireguard interface and assign IPV6 addresses to my devices that way? My home network has IPV6 but my mobile network is IPV4 only. I've read the angristan.xyz guide, and I can get IPV6 NAT using ULAs working but this is not what I'm after.

    I've managed to do this at home with a raspberry pi as the wireguard server. I had to add IPV6 routes for the wireguard subnets from the router to the raspberry pi for it to work. I think I can also install NDP Proxy Daemon on the raspberry pi instead but have not tried that yet as manually adding routes on the router worked and I left it at that.

    On the VPS however, I used tcpdump to listen to IPV6 packets on wg0 and venet0. I can see traffic from my device to the VPS on wg0 (on the /80 subnet I assigned), and I can see traffic from venet0 going out, however there are no incoming packets on venet0. There are also no neighbor solicitation packets on venet0. How do I add a route for the /80 wireguard subnet? I thought the entire /64 subnet should be routed to the VPS but this does not seem to be the case. What am I missing here?

    Thanked by (1)iandk
  • iandkiandk Hosting ProviderOG

    I‘d be interested as well

    AMD EPYC / NVMe / 10GBPs KVM in Frankfurt - https://v6node.com
    Looking for an unbeatable AMD EPYC Baremetal Server in Frankfurt? Drop me a PM

  • @atth said: would it be possible to assign a /80 IPV6 subnet to the wireguard interface and assign IPV6 addresses to my devices that way?

    Not 100% sure but I have a feeling this won't work on OpenVZ due to how it configures the network device, and you'll need to try it on KVM instead.

  • HarambeHarambe OG
    edited March 2020

    @Daniel might be interesting to you: https://blog.cloudflare.com/boringtun-userspace-wireguard-rust/

    Cloudflare built their own WireGuard userspace implementation in Rust called BoringTun.

    Little bit of drama with them building their own instead of contributing directly to a WireGuard subproject, but there's an explainer in the comments from Cloudflare:

    We communicated with Jason throughout the process and have a ton of respect for him and the entire WireGuard community. In the short term, we need the flexibility to quickly update BoringTun's code base to support the project we built it for. That's harder when you need to coordinate with people outside Cloudflare and when we need to move as fast as we plan to. However, we really believe in Open Source and want the WireGuard community to thrive. We licensed the code very openly (3-paragraph BSD) and WireGuard may choose to fork it. If they do, we'll support it and plan to contribute any improvements in our own fork back. Over the long term, I think we're very open to merging this back into the upstream project.

    🦍🍌

  • DanielDaniel OG
    edited March 2020

    When I was doing my initial prototyping, I couldn't get BoringTun working on OpenVZ: https://github.com/cloudflare/boringtun/issues/90. Seems like the issue I had was fixed though, I just haven't tried it again since Wireguard-go is working for me. I'd be interested in hearing whether anyone tries it out and how it compares to the Go implementation :)

  • I tried to do wg-quick up wg0 but get this error:
    iptables v1.8.4 (nf_tables): Could not fetch rule set generation id: Invalid argument
    any idea how to solve this?
    my vps is OVZ7 container from InceptionHost

  • InceptionHostingInceptionHosting Hosting ProviderOG

    @antibomb said: my vps is OVZ7 container from InceptionHost

    install iptables and/or 'touch /option.netfilter'

    https://inceptionhosting.com
    Please do not use the PM system here for Inception Hosting support issues.

  • @AnthonySmith said: install iptables and/or 'touch /option.netfilter'

    I already tried the suggestion from knowledgebase section, but still getting that error.

    wg-quick up wg0
    [#] ip link add wg0 type wireguard
    RTNETLINK answers: Operation not supported
    [!] Missing WireGuard kernel module. Falling back to slow userspace implementation.
    [#] wireguard-go wg0
    INFO: (wg0) 2020/05/01 11:45:18 Starting wireguard-go version 0.0.20200320
    [#] wg setconf wg0 /dev/fd/63
    [#] ip -4 address add 10.123.0.1/24 dev wg0
    [#] ip -6 address add fd42:42:42::1/80 dev wg0
    [#] ip link set mtu 1420 up dev wg0
    [#] iptables -t nat -A POSTROUTING -o venet0 -j MASQUERADE; ip6tables -t nat -A POSTROUTING -o venet0 -j MASQUERADE
    iptables v1.8.4 (nf_tables): Could not fetch rule set generation id: Invalid argument

    [#] ip link delete dev wg0`

  • InceptionHostingInceptionHosting Hosting ProviderOG

    Ah ok on actually reading your previous post it is likely that you are using a version of deb/ubuntu that expects nf_tables whole the host node kernel is actually el7 based, there was an article on using legacy rather than nf and I forgot the exact method, I will look it up when I get a minute, someone else I am sure will know so feel free to post.

    it has been mentioned here before.

    https://inceptionhosting.com
    Please do not use the PM system here for Inception Hosting support issues.

  • InceptionHostingInceptionHosting Hosting ProviderOG

    @antibomb said:

    @AnthonySmith said: install iptables and/or 'touch /option.netfilter'

    I already tried the suggestion from knowledgebase section, but still getting that error.

    Found the post: https://talk.lowendspirit.com/discussion/290/resolved-ufw-iptables-not-working-in-debian-10-minimal/p1

    Thanked by (2)antibomb flips

    https://inceptionhosting.com
    Please do not use the PM system here for Inception Hosting support issues.

  • @AnthonySmith thankyou. that solved the problem.

    Thanked by (1)InceptionHosting
  • InceptionHostingInceptionHosting Hosting ProviderOG
    edited May 2020

    @antibomb said:
    @AnthonySmith thankyou. that solved the problem.

    cool beans, KB updated.

    https://inceptionhosting.com
    Please do not use the PM system here for Inception Hosting support issues.

Sign In or Register to comment.