WireGuard - ArchWiki

# WireGuard

From ArchWiki
Jump to navigation Jump to search

From the WireGuard project homepage:

  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. It intends to be considerably more performant than OpenVPN. WireGuard is designed as a general purpose VPN for running on embedded interfaces and super computers alike, fit for many different circumstances. Initially released for the Linux kernel, it plans to be cross-platform and widely deployable.

Warning: WireGuard has not undergone proper degrees of security auditing and the protocol is still subject to change [1].

## Installation

1. Install the wireguard-tools package.
2. Install the appropriate kernel module:
   - wireguard-arch for the default linux kernel.
   - wireguard-lts for the LTS linux-lts kernel.
   - wireguard-dkms for the DKMS variant for other kernels.

Tip: systemd-networkd has native support for setting up Wireguard interfaces since version 237. See #Using systemd-networkd for details.

## Usage

The below commands demonstrate how to setup a basic tunnel between two peers with the following settings:

| Peer A | Peer B
--- | --- | ---
External IP address | 198.51.100.101 | 203.0.113.102
Internal IP address | 10.0.0.1/24 | 10.0.0.2/24
Wireguard listening port | UDP/48574 | UDP/39814

The external addresses should already exist. For example, peer A should be able to ping peer B via `ping 203.0.113.102`, and vice versa. The internal addresses will be new addresses created by the ip(8) commands below and will be shared internally within the new WireGuard network using wg(8). The `/24` in the IP addresses is the CIDR.

### Key generation

To create a private key:

    $ wg genkey > privatekey

Note: It is recommended to only allow reading and writing access for the owner:

    $ chmod 600 privatekey

To create a public key:

    $ wg pubkey < privatekey > publickey

Alternatively, do this all at once:

    $ wg genkey | tee privatekey | wg pubkey > publickey

One can also generate a preshared key to add an additional layer of symmetric-key cryptography to be mixed into the already existing public-key cryptography, for post-quantum resistance.

    # wg genpsk > preshared

### Peer A setup

This peer will listen on UDP port 48574 and will accept connection from peer B by linking its public key with both its inner and outer IPs addresses.

    # ip link add dev wg0 type wireguard
    # ip addr add 10.0.0.1/24 dev wg0
    # wg set wg0 listen-port 48574 private-key ./privatekey
    # wg set wg0 peer [Peer B public key] persistent-keepalive 25 allowed-ips 10.0.0.2/32 endpoint 203.0.113.102:39814
    # ip link set wg0 up

`[Peer B public key]` should have the same format as `EsnHH9m6RthHSs+sd9uM6eCHe/mMVFaRh93GYadDDnM=`. The keyword `allowed-ips` is a list of addresses that peer A will be able to send traffic to; `allowed-ips 0.0.0.0/0` would allow sending traffic to any IPv4 address, `::/0` allows sending traffic to any IPv6 address.

### Peer B setup

As with peer A, whereas the wireguard daemon is listening on the UDP port 39814 and accept connection from peer A only.

    # ip link add dev wg0 type wireguard
    # ip addr add 10.0.0.2/24 dev wg0
    # wg set wg0 listen-port 39814 private-key ./privatekey
    # wg set wg0 peer [Peer A public key] persistent-keepalive 25 allowed-ips 10.0.0.1/32 endpoint 198.51.100.101:48574
    # ip link set wg0 up

### Basic checkups

Invoking the wg(8) command without parameter will give a quick overview of the current configuration.

As an example, when Peer A has been configured we are able to see its identity and its associated peers:

    [user@peer-a]# wg

    interface: wg0
      public key: UguPyBThx/+xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8=
      private key: (hidden)
      listening port: 48574

    peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw=
      endpoint: 203.0.113.102:39814
      allowed ips: 10.0.0.2/32

At this point one could reach the end of the tunnel:

    [user@peer-a]$ ping 10.0.0.2

### Persistent configuration

The configuration can be saved by utilizing `showconf`:

    # wg showconf wg0 > /etc/wireguard/wg0.conf
    # wg setconf wg0 /etc/wireguard/wg0.conf

### Example peer configuration

    /etc/wireguard/wg0.conf

    [Interface]
    Address = 10.0.0.1/32
    PrivateKey = [CLIENT PRIVATE KEY]

    [Peer]
    PublicKey = [SERVER PUBLICKEY]
    AllowedIPs = 10.0.0.0/24, 10.123.45.0/24, 1234:4567:89ab::/48
    Endpoint = [SERVER ENDPOINT]:48574
    PersistentKeepalive = 25

### Example configuration for systemd-networkd

    /etc/systemd/network/30-wg0.netdev

    [NetDev]
    Name = wg0
    Kind = wireguard
    Description = Wireguard

    [WireGuard]
    PrivateKey = [CLIENT PRIVATE KEY]

    [WireGuardPeer]
    PublicKey = [SERVER PUBLIC KEY]
    PresharedKey = [PRE SHARED KEY]
    AllowedIPs = 10.0.0.0/24
    Endpoint = [SERVER ENDPOINT]:48574
    PersistentKeepalive = 25

    /etc/systemd/network/30-wg0.network

    [Match]
    Name = wg0

    [Network]
    Address = 10.0.0.3/32
    DNS = 10.0.0.1

    [Route]
    Gateway = 10.0.0.1
    Destination = 10.0.0.0/24

## Specific use-case: VPN server

The purpose of this section is to setup a WireGuard "server" and generic "clients" to enable access to the server/network resources through an encrypted and secured tunnel like OpenVPN and others. The server runs on Linux and the clients can run any number of platforms (the WireGuard Project offers apps on both iOS and Android platforms in addition to Linux-native and MacOS). See the official project install link for more.

Tip: Instead of using wireguard-tools for server/client configuration, one may want to use systemd-networkd native WireGuard support.

### Server

On the machine acting as the server, first enable IPv4 forwarding using sysctl:

    # sysctl -w net.ipv4.ip_forward=1

To make the change permanent, add `net.ipv4.ip_forward = 1` to `/etc/sysctl.d/99-sysctl.conf`.

A properly configured firewall is HIGHLY recommended for any Internet-facing device. Be sure to:

- Allow UDP traffic on the specified port(s) on which WireGuard will be running (for example allowing traffic on 51820/udp).
- Setup the forwarding policy for the firewall if it is not included in the WireGuard config for the interface itself `/etc/wireguard/wg0.conf`. The example below should work as-is.

Finally, WireGuard port(s) need to be forwarded to the server's LAN IP from the router so they can be accessed from the WAN (ie router port forwarding).

### Key generation

Generate key pairs for the server and for each client as explained in #Key generation.

### Server config

Create the server config file:

    /etc/wireguard/wg0.conf

    [Interface]
    Address = 10.200.200.1/24
    SaveConfig = true
    ListenPort = 51820
    PrivateKey = [SERVER PRIVATE KEY]

    # note - substitute eth0 in the following lines to match the Internet-facing interface
    PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

    [Peer]
    # client foo
    PublicKey = [FOO's PUBLIC KEY]
    PresharedKey = [PRE-SHARED KEY]
    AllowedIPs = 10.200.200.2/32

    [Peer]
    # client bar
    PublicKey = [BAR's PUBLIC KEY]
    AllowedIPs = 10.200.200.3/32

Additional peers can be listed in the same format as needed. Each peer required the `PublicKey` to be set. However, specifying `PresharedKey` is optional.

The interface can be managed manually using wg-quick(8) or using a systemd service managed via systemctl(1).

The interface may be brought up using `wg-quick up wg0` respectively by starting and potentially enabling the interface via `wg-quick@interface.service`, e.g. `wg-quick@wg0.service`. To close the interface use `wg-quick down wg0` respectively stop `wg-quick@interface.service`.

### Client config

Create the corresponding client config file(s):

    foo.conf

    [Interface]
    Address = 10.200.200.2/24
    PrivateKey = [FOO's PRIVATE KEY]
    DNS = 10.200.200.1

    [Peer]
    PublicKey = [SERVER PUBLICKEY]
    PresharedKey = [PRE-SHARED KEY]
    AllowedIPs = 0.0.0.0/0, ::/0
    Endpoint = my.ddns.address.com:51820

    bar.conf

    [Interface]
    Address = 10.200.200.3/24
    PrivateKey = [BAR's PRIVATE KEY]
    DNS = 10.200.200.1

    [Peer]
    PublicKey = [SERVER PUBLICKEY]
    PresharedKey = [PRE-SHARED KEY]
    AllowedIPs = 0.0.0.0/0, ::/0
    Endpoint = my.ddns.address.com:51820

Using the catch-all `AllowedIPs = 0.0.0.0/0, ::/0` will forward all IPv4 (`0.0.0.0/0`) and IPv6 (`::/0`) traffic over the VPN.

Note: Users of NetworkManager, may need to enable the `NetworkManager-wait-online.service` and users of systemd-networkd may need to enable the `systemd-networkd-wait-online.service` to wait until devices are network ready before attempting wireguard connection.

## Testing the tunnel

Once a tunnel has been established, one can use gnu-netcat to send traffic through it to test out throughput, CPU usage, etc. On one side of the tunnel, run `nc` in listen mode and on the other side, pipe some data from `/dev/zero` into `nc` in sending mode.

In the example below, port 2222 is used for the traffic (be sure to allow traffic on port 2222 if using a firewall).

On one side of the tunnel listen for traffic:

    $ nc -vvlnp 2222

On the other side of the tunnel, send some traffic:

    $ dd if=/dev/zero bs=1024K count=1024 | nc -v 10.0.0.203 2222

Status can be monitored using `wg` directly.

    # wg

    interface: wg0
      public key: UguPyBThx/+xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8=
      private key: (hidden)
      listening port: 51820

    peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw=
      preshared key: (hidden)
      endpoint: 192.168.1.216:53207
      allowed ips: 10.0.0.0/0
      latest handshake: 1 minutes, 17 seconds ago
      transfer: 56.43 GiB received, 1.06 TiB sent

## Troubleshooting

### Routes are periodically reset

Make sure that NetworkManager is not managing the Wireguard interface:

    /etc/NetworkManager/conf.d/unmanaged.conf

    [keyfile]
    unmanaged-devices=interface-name:wg0

### Connection loss with NetworkManager

On desktop, connection loss can be experienced when all the traffic is tunneled through a Wireguard interface: typically, the connection is seemingly lost after a while or upon new connection to an access point.

By default wg-quick uses a resolvconf provider such as openresolv to register new DNS entries (i.e. `DNS` keyword in the configuration file). However NetworkManager does not use resolvconf by default: every time a new DHCP lease is acquired, NetworkManager overwrites the global DNS addresses with the DHCP-provided ones which might not be available through the tunnel.

#### Using resolvconf

If resolvconf is already used by the system and connection losses persist, make sure NetworkManager is configured to use it: NetworkManager#Use openresolv.

#### Using dnsmasq

See Dnsmasq#openresolv for configuration.

#### Using systemd-resolved

This article or section is out of date.

Reason: FS#59459 is fixed, systemd-resolved's resolvconf interface works. (Discuss in Talk:WireGuard#)

At the time of writing (Sept. 2018), the resolvconf-compatible mode offered by systemd-resolvconf does not work with wg-quick. However systemd-resolved can still be used by wg-quick through the `PostUp` hook. First make sure that NetworkManager is configured with systemd-resolved: NetworkManager#systemd-resolved and then alter the tunnel configuration:

    /etc/wireguard/wg0.conf

    [Interface]
    Address = 10.0.0.2/24  # The client IP from wg0server.conf with the same subnet mask
    PrivateKey = [CLIENT PRIVATE KEY]
    PostUp = resolvectl domain %i "~."; resolvectl dns %i 10.0.0.1; resolvectl dnssec %i yes

    [Peer]
    PublicKey = [SERVER PUBLICKEY]
    AllowedIPs = 0.0.0.0/0, ::0/0
    Endpoint = [SERVER ENDPOINT]:51820
    PersistentKeepalive = 25

Setting `"~."` as a domain name is necessary for systemd-resolved to give priority to the newly available DNS server.

No `PostDown` key is necessary as systemd-resolved automatically revert all parameters when `wg0` is torn down.

## Tips and tricks

### Using systemd-networkd

systemd-networkd has native support for WireGuard protocols and therefore does not require the wireguard-tools package.

In order to prevent leak of private keys, it is recommended to set the permissions of the .netdev file:

    # chown root:systemd-network /etc/systemd/network/99-*.netdev
    # chmod 0640 /etc/systemd/network/99-*.netdev

#### Server

    /etc/systemd/network/99-server.netdev

    [NetDev]
    Name = wg0
    Kind = wireguard
    Description = Wireguard

    [WireGuard]
    ListenPort = 51820
    PrivateKey = [SERVER PRIVATE KEY]

    [WireGuardPeer]
    PublicKey = [FOO's PUBLIC KEY]
    PresharedKey = [PRE-SHARED KEY]
    AllowedIPs = 10.200.200.2/32

    [WireGuardPeer]
    PublicKey = [BAR's PUBLIC KEY]
    PresharedKey = [PRE-SHARED KEY]
    AllowedIPs = 10.200.200.3/32

    /etc/systemd/network/99-server.network

    [Match]
    Name = wg0

    [Network]
    Address = 10.200.200.1/32

    [Route]
    Gateway = 10.200.200.1
    Destination = 10.200.200.0/24

#### Client foo

    /etc/systemd/network/99-client.netdev

    [NetDev]
    Name = wg0
    Kind = wireguard
    Description = Wireguard

    [WireGuard]
    PrivateKey = [FOO's PRIVATE KEY]

    [WireGuardPeer]
    PublicKey = [SERVER PUBLICKEY]
    PresharedKey = [PRE-SHARED KEY]
    AllowedIPs = 10.200.0.0/24
    Endpoint = my.ddns.address.com:51820
    PersistentKeepalive = 25

    /etc/systemd/network/99-client.network

    [Match]
    Name = wg0

    [Network]
    Address = 10.200.200.2/32

    [Route]
    Gateway = 10.200.200.1
    Destination = 10.200.200.0/24
    GatewayOnlink=true

#### Client bar

    /etc/systemd/network/99-client.netdev

    [NetDev]
    Name = wg0
    Kind = wireguard
    Description = Wireguard

    [WireGuard]
    PrivateKey = [BAR's PRIVATE KEY]

    [WireGuardPeer]
    PublicKey = [SERVER PUBLICKEY]
    PresharedKey = [PRE-SHARED KEY]
    AllowedIPs = 10.200.0.0/24
    Endpoint = my.ddns.address.com:51820
    PersistentKeepalive = 25

    /etc/systemd/network/99-client.network

    [Match]
    Name = wg0

    [Network]
    Address = 10.200.200.3/32

    [Route]
    Gateway = 10.200.200.1
    Destination = 10.200.200.0/24
    GatewayOnlink=true

### Store private keys in encrypted form

It may be desirable to store private keys in encrypted form, such as through use of pass. Just replace the PrivateKey line under [Interface] in the configuration file with:

    PostUp = wg set %i private-key <(su user -c "export PASSWORD_STORE_DIR=/path/to/your/store/; pass WireGuard/private-keys/%i")

where user is the Linux username of interest. See the wg-quick(8) man page for more details.

### Endpoint with changing IP

After resolving a server's domain, WireGuard will not check for changes in DNS again.

If the WireGuard server is frequently changing its IP-address due DHCP, Dyndns, IPv6, ..., any WireGuard client is going to lose its connection, until its endpoint is updated via something like `wg set "$INTERFACE" peer "$PUBLIC_KEY" endpoint "$ENDPOINT"`.

Also be aware, if the endpoint is ever going to change its address (for example when moving to a new provider/datacenter), just updating DNS will not be enough, so periodically running reresolve-dns might make sense on any DNS-based setup.

Luckily, wireguard-tools provides an example script `/usr/share/wireguard/examples/reresolve-dns/reresolve-dns.sh`, that parses WG configuration files and automatically resets the endpoint address.

One needs to run the `/usr/share/wireguard/examples/reresolve-dns/reresolve-dns.sh /etc/wireguard/wg.conf` periodically to recover from an endpoint that has changed its IP.

One way of doing so is by updating all WireGuard endpoints once every thirty seconds[2] via a systemd timer:

    /etc/systemd/system/wireguard_reresolve-dns.timer

    [Unit]
    Description=Periodically reresolve DNS of all WireGuard endpoints

    [Timer]
    OnCalendar=*:*:0/30

    [Install]
    WantedBy=timers.target

    /etc/systemd/system/wireguard_reresolve-dns.service

    [Unit]
    Description=Reresolve DNS of all WireGuard endpoints
    Wants=network-online.target
    After=network-online.target

    [Service]
    Type=oneshot
    ExecStart=/bin/sh -c 'for i in /etc/wireguard/*.conf; do /usr/share/wireguard/examples/reresolve-dns/reresolve-dns.sh "$i"; done'

Afterwards enable and start `wireguard_reresolve-dns.timer`

### Generate QR code

If the client is a mobile device such as a phone, qrencode can be used to generate client's configuration QR code and display it in terminal:

    $ qrencode -t ansiutf8 < client.conf

## See also

- Presentations by Jason Donenfeld.
- Mailing list

Category:

- Virtual Private Network

Hidden category:

- Pages or sections flagged with Template:Out of date