27 June, 2021

The QUICK quick guide to setting up a WireGurd VPN tunnel

Download WireGuard Logo in SVG Vector or PNG File Format - Logo.wine 

 Background story (skippable)

So I've been maintaining a set of OpenVPN tunnels into various NAT-routed networks for several years now and every now and then a software update will declare some of the keys too old and insecure to be used. This means I have to dust-off the TLS PKI files and remember how to use it so I can press-out a new set of keys and distribute these to all the places they need to be. PKI is generally a drag and I decided it was finally time to learn how to set-up the new and hip WireGuard tunnelling solution.
Unfortunately it took me a couple of hours to set it up just the way I wanted as there are a few large differences between the two systems:
  • Wireguard does not use TLS/PKI, it just uses pre-shared public/private key pairs
  • Wireguard uses a peer-to-peer setup, not client-server like OpenVPN
  • Wireguard ignores NAT by default and is fairly "quiet" so you may need keep-alive messages to keep UDP ports open trhough NAT routers

The situation

We want to replace an OpenVPN client/server pair with WireGuard peer equivalents. The OpenVPN server uses a static DNS address with a port-forward through a NAT router. The OpenVPN client is behind another NAT router, but with a dynamic port and address.


Do this on both nodes:
  • Install wireguard-tools
  • Go to /etc/wireguard and execute (as root) wg genkey | tee privatekey | wg pubkey > publickey.
  • Edit the config file wg0.conf.
    • Only on the "server" peer, enter:
      •  [Interface]
        Address = {{ SERVER_VPN_INTERNAL_ADDRESS }}
        PrivateKey = {{ SERVER_PRIVATE_KEY }}

        PublicKey = {{ CLIENT_PUBLIC_KEY }}
        AllowedIPs = {{ CLIENT_VPN_INTERNAL_ADDRESS }}/32

    •   Only on the "client" peer, enter
      • [Interface]
        Address = {{ CLIENT_VPN_INTERNAL_ADDRESS }}
        PrivateKey = {{ CLIENT_PRIVATE_KEY }}

        PublicKey = {{ SERVER_PUBLIC_KEY }}
        Endpoint = {{ SERVER_DNS_ADDRESS }}:{{ FORWARDED_PORT }}
        AllowedIPs = {{ SERVER_VPN_INTERNAL_ADDRESS }}/32
        PersistentKeepalive = 25

  • Issue (as root) nmcli con import type wireguard file /etc/wireguard/wg0.conf
  •  Start pinging each end


The VPN_INTERNAL_ADDRESS fields are just any RFC-1918 private address pair (e.g. and So long as you're just connecting two hosts (not forwarding/bounching traffic), use the single host "/32" netmask for the "AllowedIPs" fields.

The PersistentKeepalive field ensures the dynamic-port "client" keeps the connection alive every 25 seconds and thus the NAT router will keep the port open. Without this, If the connection goes "quiet" for a while, the router might drop the port-forward and the "server" won't be able to send any traffic in until the "client" sends something out again.

UPDATE - Jan-2022

OK, So I've been using static Linux <-> Linux WireGuard tunnels just great for some months now. I'd like to also replace the Windows client machine OpenVPN tunnels with WireGuard too (Mostly because maintaining the PKI system is a pain). I know there's a Windows implementation of the protocol and it's relatively easy to find, download and install.

The trouble started when I realised that the setup I had configured for OpenVPN isn't directly the same for WireGuard and the devs are trying hard not to add "creeping features". There's also no "complete" config file documentation (Although the man-page has most of the settings).

I could relatively straightforwardly create another point-to-point peer setup like above, but I wanted it to do some extra things:
  • The interface starts by default - I want it to be off by default and started manually on demand
  • I want to be able to forward a subnet through the tunnel

The first point (starting by default) is relatively easy to fix when you know enough about Windows (I'm a casual amateur in this regard). Both the WireGuard manager (API) and all the defined interfaces are standard Widows services. As such they can be configured to start by default or not through the Windows "Services" manager.

The second point was a little more complicated, but worked-out in the end. Basically there are 3 things to do:

  1. Ensure your "server" peer is set-up to forward traffic (I'm not going to detail that common practice here). Fortunately mine was already set-up this way because it was doing much the same thing using OpenVPN
  2. Configure the "Client" peer's Peer -> AllowedIPs field (which is a comma-separated list of ip/cidr-prefix pairs) to have the subnet you want to route into (as well as the "VPN address" of the other peer)
  3. The config file's Interface section has PostUp and PreDown fields for command lines to run after the interface come up and before it goes down. Configure the "Client" peer's initially execute route add ${SUBNET} mask ${NETMASK} ${PEER_IP}, then route delete ${SUBNET} mask ${NETMASK} before shutdown.

With all those changes, the WireGuard tunnel behaves substantially as the old OpenVPN one did for clients. It also starts a lot quicker.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.