Skip to content

Linux: WireGuard VPN

int0x80 edited this page Apr 17, 2019 · 3 revisions

Overview

WireGuard is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache.

These are my setup notes.

Pre-Requisites

WireGuard was included in the kernel source in some 4.x release. At the time of writing, the vps hosting the WireGuard server is running a 4.19 kernel. The kernel headers will be needed, and IP forwarding needs to be enabled.

$ sudo apt install linux-headers-$(uname -r)
$ echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.d/99-sysctl.conf
$ sudo sysctl net.ipv4.ip_forward=1

Install

The install can be completed with apt on a Debian-based distro. After installation, load the kernel module.

$ sudo add-apt-repository ppa:wireguard/wireguard
$ sudo apt update
$ sudo apt install wireguard
$ sudo modprobe wireguard

Key Pair and Configuration

Time to generate some keys.

$ (umask 077 && printf "[Interface]\nPrivateKey = " | sudo tee /etc/wireguard/wg0.conf > /dev/null)
$ wg genkey | sudo tee -a /etc/wireguard/wg0.conf | wg pubkey | sudo tee /etc/wireguard/publickey

The final config looks like this.

# /etc/wireguard/wg0.conf

[Interface]
PrivateKey = <base64 encoded private key string>
ListenPort = 5555
SaveConfig = false
Address = 10.0.0.1/24
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Mobile Clients

Both Android and iOS can install WireGuard clients from their respective Play/App Store. In the mobile app, set up a new connection and name it accordingly. Click Generate to create a new client key pair. Copy the mobile client public key up to the server (ashamedly, I did mine through pastebin). Apply the following settings:

This is the internal private IP that the VPN interface will be assigned on the client.

  • Addresses: 10.0.0.2/32

We run our own DNS server to prevent leaking DNS queries, and so that we can null-route undesirable domains.

  • DNS Servers: 10.0.0.1

Copy the server's public key from /etc/wireguard/pubkey.

  • Peer Public Key:

Allow the client to communicate out the internet.

  • Allowed IPs: 0.0.0.0/0

Specify the VPN server's IP address so the client knows where to connect. The port should correspond with ListenPort in the WireGuard configuration.

  • Endpoint: 1.2.3.4:5555

Configuration Updates

Add the public keys from any clients into /etc/wireguard/wg0.conf. This is what my final config looks like.

# /etc/wireguard/wg0.conf

[Interface]
PrivateKey = <base64 encoded private key string>
ListenPort = 5555
SaveConfig = false
Address = 10.0.0.1/24
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = <base64 encoded public key string of mobile client>
AllowedIPs = 10.0.0.2/32

[Peer]
PublicKey = <base64 encoded public key string of mobile client>
AllowedIPs = 10.0.0.4/32

DNS FTW

Earlier there was mention of hosing our own DNS so that we could null-route undesirable domains. The DNS server in this case is unbound, and it needs to be seeded.

$ sudo apt install unbound unbound-host
$ sudo wget -O /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache

Next the zones need to be set for the blacklisted domains. I'm using the aggregate from StevenBlack.

$ sudo mv /etc/unbound/unbound.conf.d/ads.conf /etc/unbound/unbound.conf.d/ads.conf.$(date +%s) 2>/dev/null
$ wget -q -O - https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts | grep '^0.0.0.0 ' | while read entry; do
  fqdn=$(echo "${entry}" | awk '{print $2}')
  echo "local-zone: \"${fqdn}\" redirect" | sudo tee -a /etc/unbound/unbound.conf.d/ads.conf >/dev/null
  echo "local-data: \"${fqdn} A 0.0.0.0\"" | sudo tee -a /etc/unbound/unbound.conf.d/ads.conf >/dev/null
done

Note: You need the ca-certificates package, otherwise wget will bail from failing the cert check. Also:

$ wget -qO- https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts | wc -l
40056

😭 😭 😭 😭 😭 😭 😭 😭 😭 😭 😭 😭 😭 😭 😭

Finishing Touches

A few last items to finalize the DNS setup.

$ sudo chown -R unbound:unbound /var/lib/unbound
$ sudo systemctl enable unbound
$ sudo unbound-host -C /etc/unbound/unbound.conf -v ietf.org
$ sudo systemctl restart unbound.service  # don't recall why I did this but it's in my history ¯\_(ツ)_/¯

FIN

I think that does it. Give a shout if this doesn't work. Obviously technology moves quickly so adapt relevant changes as necessary.