# The Missing Wireguard Documentation

API reference guide for Wireguard including Setup, Configuration, and Usage, with full example.
Also published on https://docs.sweeting.me/s/wireguard.
---
This is my attempt at writing the "Missing Wireguard Documentation" to make up for the lacking offical docs for an otherwise great piece of software.
[WireGuard](https://www.wireguard.com/) is an open-source VPN solution written in Go, aiming to fix many of the problems that have plagued other good server-to-server VPN offerings like IPSec/IKEv2 or OpenVPN.
**WireGuard Goals**
- strong, modern security by default
- minimal config and key management
- fast, both low-latency and high-bandwidth
- simple internals and small protocol surface area
- simple CLI and seamless integration with system networking
---
# Table of Contents
See https://docs.sweeting.me/s/wireguard.
# Intro
Over the last 8 years I've tried a wide range of VPN solutions. From the original PPTP back in the early 2010's to break through the Great Firewall of China while I was living in Shanghai, to OpenVPN and IPSec/IKEv2 later on. From the recommendation of a few people in the [RC](https://recurse.com) Zulip community, I decided to try WireGuard and was surprised to find it checked all the boxes.
## My Requirements for a VPN Solution
- create a LAN like 10.0.0.0/24 between all my servers, every peer can connect to every peer
- must be able to bust through middebox NATs/routers
- requiring a central server for coordination/NAT busting is ok, but it shouldn't have to route all traffic through the central node if a direct connection is possible
- wont be used for routing *all* traffic, only traffic to the VPN subnet (i.e. I'm not passing my web browsing through it, just server-to-server stuff like NFS/SSH/redis/etc)
- robust automatic reconnects after reboots / network downtime
- fast (lowest possible latency and line-rate bandwidth)
- encrypted, but doesn't have to be super secure (i.e. doesn't have to be state-level secure or undetectable)
- minimal config and key management overhead, 1 or 2 preshared keys or certs is ok, but ideally not both
- support for any type of Level 2 traffic, e.g. UDP/ARP/ICMP (or ideally raw ethernet frames), not just TCP/HTTP
- ability to join the VPN from Ubuntu, FreeBSD, iOS, macOS (ideally without needing an app), Windows/Android not needed but would be nice
- not a requirement, but ideally it would support running in docker with a single container, config file, and preshared key on each server, but with a full network interface exposed to the host system (maybe with tun/tap on the host passing traffic to the container, but ideally just a single container without outside dependencies)
## List of Possible VPN Solutions
- PPTP: ancient, inflexible, insecure, doens't solve all the requirements
- SOCKS: proxy tunnel, not a VPN, not great for this use case
- [IPSec (IKEv2)](https://github.com/jawj/IKEv2-setup)/strongSwan: lots of brittle config that's different for each OS, NAT busting setup is very manual and involves updating the central server and starting all the others in the correct order, not great at reconnecting after network downtime, had to be manually restarted often
- [TINC](https://www.tinc-vpn.org/): haven't tried it yet, but it doesn't work on iOS, worst case senario I could live with that if it's the only option
- [OpenVPN](https://openvpn.net/vpn-server-resources/site-to-site-routing-explained-in-detail/): I don't like it from past experience but could be convinced if it's the only option
- [Algo](https://github.com/trailofbits/algo): haven't tried it yet, should I?
- [Striesand](https://github.com/StreisandEffect/streisand): haven't tried it yet, whats the best config to try?
- [SoftEther](https://www.softether.org/): haven't tried it yet, should I?
- [WireGuard](https://www.wireguard.com/): the subject of this post
- [ZeroTier](https://www.zerotier.com): haven't tried it yet, sould I?
---
# Wireguard Documentation
## Glossary
### Peer/Node/Device
A host that connects to the VPN and has registers a VPN subnet address like 10.0.0.3 for itself. It can also optionally route traffic for more than its own address(es) by specifing subnet ranges in comma-separated CIDR notation.
### Bounce Server
A publicly reachable peer/node that serves as a fallback to relay traffic for other VPN peers behind NATs.
### Subnet
A group of IPs separate from the public internet, e.g. 10.0.0.1-255 or 192.168.1.1/24. Generally behind a NAT provided by a router, e.g. in office internet LAN or a home WiFi network.
### CIDR Notation
A way of defining the size of a subnet. Most common ones:
+ 10.0.0.1/32 (a single IP address, 10.0.0.1) netmask = 255.255.255.255
+ 10.0.0.1/24 (255 ips from 10.0.0.1-255) netmask = 255.255.255.0
+ 10.0.0.1/16 (65,536 ips from 10.0.0.0 - 10.0.255.255) netmask = 255.255.0.0
+ 10.0.0.1/8 (16,777,216 ips from 10.0.0.0 - 10.255.255.255) netmask = 255.0.0.0
+ 0.0.0.1/0 (4,294,967,296 ips from 0.0.0.0 - 255.255.255.255) netmask = 0.0.0.0
https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
### NAT
A subnet with private IPs provided by a router standing in front of them doing Network Address Translation, individual nodes are not publicly accessible from the internet, instead the router keeps track of outgoing connections and forwards responses to the correct internal ip (e.g. standard office networks, home wifi networks, free public wifi networks, etc)
### Public Endpoint
The publicly accessible address:port for a node, e.g. `123.124.125.126:1234` or `some.domain.tld:1234` (must be accessible via the public internet, generally can't be a private ip like `10.0.0.1` or `192.168.1.1` unless it's directly accessible using that address by other peers on the same subnet).
### Private key
A wireguard private key for a single node, generated with:
`wg genkey > example.key`
(never leaves the node it's generated on)
### Public key
A wireguard public key for a single node, generated with:
`wg pubkey < example.key > example.key.pub `
(shared with other peers)
### DNS
Domain Name Server, used to resolve hostnames to IPs for VPN clients, instead of allowing DNS requests to leak outside the VPN and reveal traffic. Leaks are testable with http://dnsleak.com.
## Usage
### Quickstart
Overview of the general process:
0. Install `wireguard` or `wireguard-tools` on each node
1. Generate public and private keys locally on each node
2. Create a `wg0.conf` wireguard config file on the main relay server
- `[Interface]` Make sure to specify a CIDR range for the entire VPN subnet when defining the address the server accepts routes for `Address = 10.0.0.1/24`
- `[Peer]` Create a peer section for every client joining the VPN, using their corresponding remote public keys
3. Crete a `wg0.conf` on each client node
- `[Interface]` Make sure to specify only a single IP for client peers that don't relay traffic `Address = 10.0.0.3/32`.
- `[Peer]` Create a peer section for each public peer not behind a NAT, make sure to specify a CIDR range for the entire VPN subnet when defining the remote peer acting as the bounce server `AllowedIPs = 10.0.0.1/24`. Make sure to specify individual IPs for remote peers that don't relay traffic and only act as simple clients `AllowedIPs = 10.0.0.3/32`.
4. Start wireguard on the main relay server with `wg-quick up /full/path/to/wg0.conf`
5. Start wireguard on all the client peers with `wg-quick up /full/path/to/wg0.conf`
6. Traffic is routed from peer to peer using most optimal route over the WireGuard interface, e.g. `ping 10.0.0.3` checks for local direct route first, then checks for route via public internet, then finally tries to route by bouncing through the public relay server.
### Setup
```bash
# install on Ubuntu
sudo add-apt-repository ppa:wireguard/wireguard
apt install wireguard
# install on macOS
brew install wireguard-tools
# install on FreeBSD
pkg install wireguard
# install on iOS/Andoid using Apple App Store/Google Play Store
# install on other systems using https://www.wireguard.com/install/#installation
```
```
# to enable kernel relaying/forwarding ability on bounce servers
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
echo "net.ipv4.conf.all.proxy_arp" >> /etc/sysctl.conf
sudo sysctl -p /etc/sysctl.conf
# to add iptables forwarding rules on bounce servers
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wg0 -o wg0 -m conntrack --ctstate NEW -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
```
### Config Creation
```bash
nano wg0.conf # can be placed anywhere, must be referred to using absolute path
```
### Key Generation
```bash
# generate private key
wg genkey > example.key
# generate public key
wg pubkey < example.key > example.key.pub
```
### Start / Stop
```bash
wg-quick up /full/path/to/wg0.conf
wg-quick down /full/path/to/wg0.conf
```
```bash
# start/stop VPN network interface
ip link set wg0 up
ip link set wg0 down
# register/unregister VPN network interface
ip link add dev wg0 type wireguard
ip link delete dev wg0
# register/unregister local VPN address
ip address add dev wg0 10.0.0.3/32
ip address delete dev wg0 10.0.0.3/32
# register/unregister VPN route
ip route add 10.0.0.3/32 dev wg0
ip route delete 10.0.0.3/32 dev wg0
```
### Inspect
#### Interfaces
```bash
# show system LAN and WAN network interfaces
ifconfig
ip address show
# show system VPN network interfaces
ifconfig wg0
ip link show wg0
# show wireguard VPN interfaces
wg show all
wg show wg0
```
#### Addresses
```bash
# show public ip address
ifconfig eth0
ip address show eth0
dig -4 +short myip.opendns.com @resolver1.opendns.com
# show VPN ip address
ip address show wg0
```
#### Routes
```bash
# show wireguard routing table and peer connections
wg show
wg show wg0 allowed-ips
# show system routing table
ip route show table main
ip route show table local
# show system route to specific address
ip route get 10.0.0.3
```
### Testing
#### Ping Speed
```bash
# check that main relay server is accesible directly via public internet
ping public-server1.example-vpn.dev
# check that the main relay server is available via VPN
ping 10.0.0.1
# check that public peers are available via VPN
ping 10.0.0.2
# check that remote NAT-ed peers are available via VPN
ping 10.0.0.3
# check that NAT-ed peers in your local lan are available via VPN
ping 10.0.0.4
```
#### Bandwidth
```bash
# check bandwidth over public internet to relay server
iperf -s # on public relay server
iperf -c public-server1.example-vpn.dev # on local client
# check bandwidth over VPN to relay server
iperf -s # on public relay server
iperf -c 10.0.0.1 # on local client
# check bandwidth over VPN to remote public peer
iperf -s # on remote public peer
iperf -c 10.0.0.2 # on local client
# check bandwidth over VPN to remote NAT-ed peer
iperf -s # on remote NAT-ed peer
iperf -c 10.0.0.3 # on local client
# check bandwidth over VPN to local NAT-ed peer (on same LAN)
iperf -s # on local NAT-ed peer
iperf -c 10.0.0.4 # on local client
```
## Config Reference
### `[Interface]`
Defines the VPN settings for the local node.
**Examples**
* Node is a client that only routes traffic for itself and only exposes one IP
```ini
[Interface]
# Name = phone.example-vpn.dev
Address = 10.0.0.5/32
PrivateKey =