wireguard quickstart

⊕ 2017-05-20

EDITED: 2017-07-15

In the never ending hunt for the ideal VPN software we recently got to play with WireGuard, which has become a quick favourite. This text will serve as a quick-start guide for setting up a OpenVPN-esque default gateway server and a roaming client.

WireGuard offers some extremely powerful features that set it apart from the competition:

first steps

After installing WireGuard, it is necessary to generate keys on both hosts.

$ umask 077 && mkdir -p /etc/wireguard && cd /etc/wireguard
$ wg genkey | tee privatekey | wg pubkey > publickey

server configuration

Next the server needs a configuration file, we will set the listening port to 51820 and allow the client to connect from any IP address. Replace SERVER_PRIVATE_KEY with the servers previously generated key and CLIENT_PUBLIC_KEY with the clients public key, both are base64 encoded strings.

ListenPort = 51820

AllowedIPs =

Now that we have a configuration we need to set up the interfaces and ensure the server can route the clients with an iptables NAT rule. Do not forget to make this rule persistent across reboots. The internal network will be set to and the server will have an internal IP of, and should be changed to suite the needs of the network.

# ip link add dev wg0 type wireguard
# ip address add dev wg0
# ip link set wg0 up
# wg setconf wg0  /etc/wireguard/wg0.conf
# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# sysctl net.ipv4.ip_forward = 1
# printf "sysctl net.ipv4.ip_forward = 1\n" >> /etc/sysctl.conf

client configuration

The client is configured in a very similar manner as the server, but it needs to know the IP of the server. Setting the PersistentKeepalive is optional, but WireGuard is purposefully as silent in its default configuration and if a client is idle on a NAT the connection may be interrupted. This option prevents that by sending a keep alive every declared seconds. Replace CLIENT_PRIVATE_KEY with the clients previously generated key and SERVER_PUBLIC_KEY with the servers public key.

ListenPort = 51820

AllowedIPs =
Endpoint =
PersistentKeepalive = 25

Now we initialize the interfaces and set the configuration. The client in this example will have an internal IP of on the same subnet as declared on the server.

# ip link add dev wg0 type wireguard
# ip address add dev wg0
# ip link set wg0 up
# wg setconf wg0  /etc/wireguard/wg0.conf

Finally, the client needs to set its default routes (or which ever routes that are necessary) to the server. This requires knowing the original gateway and the IP of the server, in this example the gateway is and the server IP is

# ip route add via
# ip route del default
# ip route add default dev wg0

NOTE: It is important understand that this configuration does will leak DNS requests if the original DHCP acquired DNS server is still routable. To prevent this set a nameserver in /etc/resolv.conf to an internal VPN host or to a trusted DNS server elsewhere. There is also the problem of default routes being changed when reconnecting to a wireless network, so there is some manual configuration that may need to be done.

wrapping up

After the server and client are set up the configuration and status can be checked with the wg(8) utility, if everything was configured properly an example of output on the server would look like the following.

# wg
interface: wg0
  public key: jHhuAqsPKZC25/zjQ9G+1JEGO2FglLxqq4t8gWWW73U=
  private key: (hidden)
  listening port: 51820

peer: f2LdqRAog0FfdCbdZLkGKdJfPBkwrSt8XKl1kG8N2Vg=
  allowed ips:
  latest handshake: 8 seconds ago
  transfer: 4.40 MiB received, 322.38 MiB sent

The final step is adding the configuration to the default network configuration so that it starts at reboot. This step may be different depending on what distribution of Linux being used, this example will be using /etc/network/interfaces on the server.

auto wg0
iface wg0 inet static
  pre-up ip link add dev wg0 type wireguard
  post-up wg setconf wg0 /etc/wireguard/wg0.conf
  post-up ip link set dev wg0 up 

If everything is routing properly just check the external IP matches the server, if not traceroute can help debug any potential issues.