Difference between revisions of "WireGuard"

From ArchWiki
Jump to navigation Jump to search
(add example of saturating a pipe for testing purposes)
(→‎Connection loss with NetworkManager: the issue should not be limited to NetworkManager, the same would happen when using e.g. dhclient)
 
(52 intermediate revisions by 12 users not shown)
Line 3: Line 3:
 
[[zh-hans:WireGuard]]
 
[[zh-hans:WireGuard]]
 
From the [https://www.wireguard.com/ WireGuard] project homepage:  
 
From the [https://www.wireguard.com/ 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.
+
: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 [https://www.wireguard.com/#work-in-progress].}}
 
{{Warning|WireGuard has not undergone proper degrees of security auditing and the protocol is still subject to change [https://www.wireguard.com/#work-in-progress].}}
Line 9: Line 9:
 
== Installation ==
 
== Installation ==
  
# [[Install]] the {{Pkg|wireguard-tools}} package.
+
# [[Install]] {{Pkg|wireguard-tools}}.
 
# Install the appropriate kernel module:
 
# Install the appropriate kernel module:
 
#* {{Pkg|wireguard-arch}} for the default {{Pkg|linux}} kernel.
 
#* {{Pkg|wireguard-arch}} for the default {{Pkg|linux}} kernel.
Line 15: Line 15:
 
#* {{Pkg|wireguard-dkms}} for the DKMS variant for other [[kernel]]s.
 
#* {{Pkg|wireguard-dkms}} for the DKMS variant for other [[kernel]]s.
  
{{Tip|[[systemd-networkd]] has native support for setting up Wireguard interfaces since version 237. See [[#Using systemd-networkd]] for details.}}
+
{{Note|1=As of November 2019, it is looking like WireGuard could be [https://www.phoronix.com/scan.php?page=news_item&px=WireGuard-RFC-Looking-Like-5.6 mainlined] as soon as kernel version 5.6.}}
 +
 
 +
{{Tip|[[systemd-networkd]] has native support for setting up WireGuard interfaces since version 237. See [[#Using systemd-networkd]] for details.}}
  
 
== Usage ==
 
== Usage ==
  
 
The below commands demonstrate how to setup a basic tunnel between two peers with the following settings:
 
The below commands demonstrate how to setup a basic tunnel between two peers with the following settings:
 +
 +
{{Expansion|Add Peer C to better demonstrate routing and PSK, and add IPv6.}}
  
 
{| class="wikitable"
 
{| class="wikitable"
Line 25: Line 29:
 
! Peer A
 
! Peer A
 
! Peer B
 
! Peer B
|----------------------------------------------------------
+
|-
| External IP address
+
! External IP address
| 10.10.10.1/24
+
| 198.51.100.101
| 10.10.10.2/24
+
| 203.0.113.102
|----------------------------------------------------------
+
|-
| Internal IP address
+
! Internal IP address
 
| 10.0.0.1/24
 
| 10.0.0.1/24
 
| 10.0.0.2/24
 
| 10.0.0.2/24
|----------------------------------------------------------
+
|-
| Wireguard listening port
+
! WireGuard listening port
| UDP/48574
+
| UDP/51871
| UDP/39814
+
| UDP/51902
 
|}
 
|}
  
The external addresses should already exist. For example, peer A should be able to ping peer B via {{ic|ping 10.10.10.2}}, and vice versa. The internal addresses will be new addresses created by the {{man|8|ip}} commands below and will be shared internally within the new WireGuard network using {{man|8|wg}}. The {{ic|/24}} in the IP addresses is the [[wikipedia:Classless_Inter-Domain_Routing#CIDR_notation|CIDR]].
+
The external addresses should already exist. For example, peer A should be able to ping peer B via {{ic|ping 203.0.113.102}}, and vice versa. The internal addresses will be new addresses created by the {{man|8|ip}} commands below and will be shared internally within the new WireGuard network using {{man|8|wg}}. The {{ic|/24}} in the IP addresses is the [[wikipedia:Classless_Inter-Domain_Routing#CIDR_notation|CIDR]].
  
 
=== Key generation ===
 
=== Key generation ===
Line 48: Line 52:
  
 
{{Note|It is recommended to only allow reading and writing access for the owner:
 
{{Note|It is recommended to only allow reading and writing access for the owner:
 +
 
  $ chmod 600 privatekey
 
  $ chmod 600 privatekey
 +
 
}}
 
}}
  
Line 60: Line 66:
  
 
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.
 
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.
 +
 +
{{Expansion|A pre-shared key should be created for each peer pair. E.g. with peers A, B and C, there should be three pre-shared keys, {{ic|peer_A-peer_B-psk}} for the connection between Peer A and Peer B, {{ic|peer_A-peer_C-psk}} for the connection between Peer A and Peer C and {{ic|peer_B-peer_C-psk}} for the connection between Peer B and Peer C.}}
  
 
  # wg genpsk > preshared
 
  # wg genpsk > preshared
Line 65: Line 73:
 
=== Peer A setup ===
 
=== 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.
+
This peer will listen on UDP port 51871 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 link add dev wg0 type wireguard
 
  # ip addr add 10.0.0.1/24 dev wg0
 
  # ip addr add 10.0.0.1/24 dev wg0
  # wg set wg0 listen-port 48574 private-key ./privatekey
+
  # wg set wg0 listen-port 51871 private-key ./privatekey
  # wg set wg0 peer [Peer B public key] persistent-keepalive 25 allowed-ips 10.0.0.2/32 endpoint 10.10.10.2:39814
+
  # wg set wg0 peer ''PEER_B_PUBLIC_KEY'' persistent-keepalive 25 allowed-ips 10.0.0.2/32 endpoint 203.0.113.102:51902
 
  # ip link set wg0 up
 
  # ip link set wg0 up
  
{{ic|[Peer B public key]}} should have the same format as {{ic|1=EsnHH9m6RthHSs+sd9uM6eCHe/mMVFaRh93GYadDDnM=}}. The keyword {{ic|allowed-ips}} is a list of addresses that peer A will be able to send traffic to; {{ic|allowed-ips 0.0.0.0/0}} would allow sending traffic to any IPv4 address, {{ic|::/0}} allows sending traffic to any IPv6 address.
+
{{ic|''PEER_B_PUBLIC_KEY''}} should have the same format as {{ic|1=EsnHH9m6RthHSs+sd9uM6eCHe/mMVFaRh93GYadDDnM=}}. The keyword {{ic|allowed-ips}} is a list of addresses that peer A will be able to send traffic to; {{ic|allowed-ips 0.0.0.0/0}} would allow sending traffic to any IPv4 address, {{ic|::/0}} allows sending traffic to any IPv6 address.
  
 
=== Peer B setup ===
 
=== 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.
+
As with peer A, whereas the wireguard daemon is listening on the UDP port 51902 and accept connection from peer A only.
  
 
  # ip link add dev wg0 type wireguard
 
  # ip link add dev wg0 type wireguard
 
  # ip addr add 10.0.0.2/24 dev wg0
 
  # ip addr add 10.0.0.2/24 dev wg0
  # wg set wg0 listen-port 39814 private-key ./privatekey
+
  # wg set wg0 listen-port 51902 private-key ./privatekey
  # wg set wg0 peer [Peer A public key] persistent-keepalive 25 allowed-ips 10.0.0.1/32 endpoint 10.10.10.1:48574
+
  # wg set wg0 peer ''PEER_A_PUBLIC_KEY'' persistent-keepalive 25 allowed-ips 10.0.0.1/32 endpoint 198.51.100.101:51871
 
  # ip link set wg0 up
 
  # ip link set wg0 up
  
Line 91: Line 99:
 
As an example, when Peer A has been configured we are able to see its identity and its associated peers:
 
As an example, when Peer A has been configured we are able to see its identity and its associated peers:
  
  peer-a$ wg
+
{{hc|[user@peer-a]# wg|2=
  interface: wg0
+
interface: wg0
    public key: UguPyBThx/+xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8=
+
  public key: UguPyBThx/+xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8=
    private key: (hidden)
+
  private key: (hidden)
    listening port: 48574
+
  listening port: 51871
 
+
 
  peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw=
+
peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw=
    endpoint: 10.10.10.2:39814
+
  endpoint: 203.0.113.102:51902
    allowed ips: 10.0.0.2/32
+
  allowed ips: 10.0.0.2/32
 +
}}
  
 
At this point one could reach the end of the tunnel:
 
At this point one could reach the end of the tunnel:
  peer-a$ ping 10.0.0.2
+
 
 +
[user@peer-a]$ ping 10.0.0.2
  
 
=== Persistent configuration ===
 
=== Persistent configuration ===
Line 116: Line 126:
 
[Interface]
 
[Interface]
 
Address = 10.0.0.1/32
 
Address = 10.0.0.1/32
PrivateKey = [CLIENT PRIVATE KEY]
+
PrivateKey = ''CLIENT_PRIVATE_KEY''
  
 
[Peer]
 
[Peer]
PublicKey = [SERVER PUBLICKEY]
+
PublicKey = ''SERVER_PUBLICKEY''
 
AllowedIPs = 10.0.0.0/24, 10.123.45.0/24, 1234:4567:89ab::/48
 
AllowedIPs = 10.0.0.0/24, 10.123.45.0/24, 1234:4567:89ab::/48
Endpoint = [SERVER ENDPOINT]:51820
+
Endpoint = ''SERVER_ENDPOINT'':51871
 
PersistentKeepalive = 25
 
PersistentKeepalive = 25
 
}}
 
}}
Line 127: Line 137:
 
=== Example configuration for systemd-networkd ===
 
=== Example configuration for systemd-networkd ===
  
{{hc|1=/etc/systemd/network/30-wg0.netdev|2=
+
See [[#Using systemd-networkd]].
[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]:51820
 
PersistentKeepalive = 25
 
}}
 
 
 
{{hc|1=/etc/systemd/network/30-wg0.network|2=
 
[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 ==
 
== Specific use-case: VPN server ==
 +
{{Note|Usage of the terms "server" and "client" are used here specifically for newcomers to WireGuard and for current users of OpenVPN to help familiarize with the construction of configuration files. WireGuard documentation simply refers to both of these concepts as "peers."}}
  
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 [https://www.wireguard.com/install/ install link] for more.
+
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, Windows and MacOS).  See the official project [https://www.wireguard.com/install/ install link] for more.
  
 
{{Tip|Instead of using {{pkg|wireguard-tools}} for server/client configuration, one may want to use [[#Using systemd-networkd|systemd-networkd]] native WireGuard support.}}
 
{{Tip|Instead of using {{pkg|wireguard-tools}} for server/client configuration, one may want to use [[#Using systemd-networkd|systemd-networkd]] native WireGuard support.}}
Line 165: Line 148:
 
=== Server ===
 
=== Server ===
  
On the machine acting as the server, first enable IPv4 forwarding using [[sysctl]]:
+
On the peer that will act as the "server", first enable IPv4 forwarding using [[sysctl]]:
  
  # sysctl net.ipv4.ip_forward=1
+
  # sysctl -w net.ipv4.ip_forward=1
  
 
To make the change permanent, add {{ic|1=net.ipv4.ip_forward = 1}} to {{ic|/etc/sysctl.d/99-sysctl.conf}}.
 
To make the change permanent, add {{ic|1=net.ipv4.ip_forward = 1}} to {{ic|/etc/sysctl.d/99-sysctl.conf}}.
  
 
A properly configured [[firewall]] is ''HIGHLY recommended'' for any Internet-facing device.
 
A properly configured [[firewall]] is ''HIGHLY recommended'' for any Internet-facing device.
Be sure to:
+
 
 +
If the server have the public IP configured, be sure to:
  
 
* Allow UDP traffic on the specified port(s) on which WireGuard will be running (for example allowing traffic on 51820/udp).
 
* 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 {{ic|/etc/wireguard/wg0.conf}}. The example below should work as-is.
+
* Setup the forwarding policy for the firewall if it is not included in the WireGuard config for the interface itself {{ic|/etc/wireguard/wg0.conf}}. The example below should have the iptables rules and 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).
+
If the server is behind NAT, be sure to forward the specified port(s) on which WireGuard will be running (for example, 51820/UDP) from the router to the WireGuard server.
  
 
=== Key generation ===
 
=== Key generation ===
Line 185: Line 169:
 
=== Server config ===
 
=== Server config ===
  
Create the server config file:
+
Create the "server" config file:
  
{{hc|1=/etc/wireguard/wg0.conf|2=
+
{{hc|/etc/wireguard/wg0.conf|2=
 
[Interface]
 
[Interface]
 
Address = 10.200.200.1/24
 
Address = 10.200.200.1/24
SaveConfig = true
 
 
ListenPort = 51820
 
ListenPort = 51820
PrivateKey = [SERVER PRIVATE KEY]
+
PrivateKey = ''SERVER_PRIVATE_KEY''
  
 
# note - substitute ''eth0'' in the following lines to match the Internet-facing interface
 
# note - substitute ''eth0'' in the following lines to match the Internet-facing interface
 +
# if the server is behind a router and receive traffic via NAT, this iptables rules are not needed
 
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
 
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
 
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
  
 
[Peer]
 
[Peer]
# client foo
+
# foo
PublicKey = [FOO's PUBLIC KEY]
+
PublicKey = ''PEER_FOO_PUBLIC_KEY''
PresharedKey = [PRE-SHARED KEY]
+
PresharedKey = ''PRE-SHARED_KEY''
 
AllowedIPs = 10.200.200.2/32
 
AllowedIPs = 10.200.200.2/32
  
 
[Peer]
 
[Peer]
# client bar
+
# bar
PublicKey = [BAR's PUBLIC KEY]
+
PublicKey = ''PEER_BAR_PUBLIC_KEY''
 
AllowedIPs = 10.200.200.3/32
 
AllowedIPs = 10.200.200.3/32
 
}}
 
}}
  
Additional peers can be listed in the same format as needed. Each peer required the {{ic|PublicKey}} to be set. However, specifying {{ic|PresharedKey}} is optional.
+
Additional peers ("clients") can be listed in the same format as needed. Each peer requires the {{ic|PublicKey}} to be set. However, specifying {{ic|PresharedKey}} is optional.
 +
 
 +
Notice that the {{ic|Address}} have mask "/24" and the clients on {{ic|AllowedIPs}} "/32". The client only use their IP and the server only send back their respective address.
  
 
The interface can be managed manually using {{man|8|wg-quick}} or using a [[systemd]] service managed via {{man|1|systemctl}}.
 
The interface can be managed manually using {{man|8|wg-quick}} or using a [[systemd]] service managed via {{man|1|systemctl}}.
Line 218: Line 204:
 
=== Client config ===
 
=== Client config ===
  
Create the corresponding client config file(s):
+
Create the corresponding "client" config file(s):
  
{{hc|1=foo.conf|2=
+
{{hc|foo.conf|2=
 
[Interface]
 
[Interface]
 
Address = 10.200.200.2/24
 
Address = 10.200.200.2/24
PrivateKey = [FOO's PRIVATE KEY]
+
PrivateKey = ''PEER_FOO_PRIVATE_KEY''
 
DNS = 10.200.200.1
 
DNS = 10.200.200.1
  
 
[Peer]
 
[Peer]
PublicKey = [SERVER PUBLICKEY]
+
PublicKey = ''SERVER_PUBLICKEY''
PresharedKey = [PRE-SHARED KEY]
+
PresharedKey = ''PRE-SHARED_KEY''
 
AllowedIPs = 0.0.0.0/0, ::/0
 
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = my.ddns.address.com:51820
+
Endpoint = my.ddns.example.com:51820
 
}}
 
}}
  
{{hc|1=bar.conf|2=
+
{{hc|bar.conf|2=
 
[Interface]
 
[Interface]
 
Address = 10.200.200.3/24
 
Address = 10.200.200.3/24
PrivateKey = [BAR's PRIVATE KEY]
+
PrivateKey = ''PEER_BAR_PRIVATE_KEY''
 
DNS = 10.200.200.1
 
DNS = 10.200.200.1
  
 
[Peer]
 
[Peer]
PublicKey = [SERVER PUBLICKEY]
+
PublicKey = ''SERVER_PUBLICKEY''
PresharedKey = [PRE-SHARED KEY]
+
PresharedKey = ''PRE-SHARED KEY''
 
AllowedIPs = 0.0.0.0/0, ::/0
 
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = my.ddns.address.com:51820
+
Endpoint = my.ddns.example.com:51820
 
}}
 
}}
  
Line 250: Line 236:
 
{{Note|Users of [[NetworkManager]], may need to [[enable]] the {{ic|NetworkManager-wait-online.service}} and users of [[systemd-networkd]] may need to [[enable]] the {{ic|systemd-networkd-wait-online.service}} to wait until devices are network ready before attempting wireguard connection.}}
 
{{Note|Users of [[NetworkManager]], may need to [[enable]] the {{ic|NetworkManager-wait-online.service}} and users of [[systemd-networkd]] may need to [[enable]] the {{ic|systemd-networkd-wait-online.service}} to wait until devices are network ready before attempting wireguard connection.}}
  
{{Tip|If the client is a mobile device such as a phone, {{Pkg|qrencode}} can be used to share the config with the client:
+
== Testing the tunnel ==
$ qrencode -t ansiutf8 < foo.conf
 
}}
 
  
== Testing the tunnel ==
+
Once a tunnel has been established, one can use {{Pkg|gnu-netcat}} to send traffic through it to test out throughput, CPU usage, etc.
Once a tunnel has been established, one can use {{pkg|netcat}} to send traffic through it to test out throughput, CPU usage, etc.
 
 
On one side of the tunnel, run {{ic|nc}} in listen mode and on the other side, pipe some data from {{ic|/dev/zero}} into {{ic|nc}} in sending mode.
 
On one side of the tunnel, run {{ic|nc}} in listen mode and on the other side, pipe some data from {{ic|/dev/zero}} into {{ic|nc}} in sending mode.
  
Line 261: Line 244:
  
 
On one side of the tunnel listen for traffic:
 
On one side of the tunnel listen for traffic:
 +
 
  $ nc -vvlnp 2222
 
  $ nc -vvlnp 2222
  
 
On the other side of the tunnel, send some traffic:
 
On the other side of the tunnel, send some traffic:
  $ dd if=/dev/zero bs=1024K count=1024 | nc -v 10.200.200.203 2222
+
 
 +
  $ dd if=/dev/zero bs=1024K count=1024 | nc -v 10.0.0.203 2222
  
 
Status can be monitored using {{ic|wg}} directly.
 
Status can be monitored using {{ic|wg}} directly.
# wg
+
 
interface: wg0
+
{{hc|# wg|2=
  public key: UguPyBThx/+xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8=
+
interface: wg0
  private key: (hidden)
+
  public key: UguPyBThx/+xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8=
  listening port: 48574
+
  private key: (hidden)
  fwmark: 0xca6c
+
  listening port: 51820
+
 
peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw=
+
peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw=
  endpoint: 192.168.1.216:53207
+
  preshared key: (hidden)
  allowed ips: 10.0.0.0/0
+
  endpoint: 192.168.1.216:53207
  latest handshake: 1 minute, 36 seconds ago
+
  allowed ips: 10.0.0.0/0
  transfer: 39.44 GiB received, 2.26 GiB sent
+
  latest handshake: 1 minutes, 17 seconds ago
 +
  transfer: 56.43 GiB received, 1.06 TiB sent
 +
}}
  
 
== Troubleshooting ==
 
== Troubleshooting ==
Line 284: Line 271:
 
=== Routes are periodically reset ===
 
=== Routes are periodically reset ===
  
Make sure that [[NetworkManager]] is not managing the Wireguard interface:
+
If you are not configuring WireGuard from [[NetworkManager]], make sure that NetworkManager is not managing the WireGuard interface(s):
  
{{hc|1=/etc/NetworkManager/conf.d/unmanaged.conf|2=
+
{{hc|/etc/NetworkManager/conf.d/unmanaged.conf|2=
 
[keyfile]
 
[keyfile]
unmanaged-devices=interface-name:wg0
+
unmanaged-devices=interface-name:wg*
}}  
+
}}
 
 
=== 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.
+
=== Broken DNS resolution ===
  
By default ''wg-quick'' uses a resolvconf provider such as [[openresolv]] to register new [[DNS]] entries (i.e. {{ic|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.
+
When tunneling all traffic through a WireGuard interface, the connection can become seemingly lost after a while or upon new connection. This could be caused by a [[network manager]] or [[DHCP]] client overwriting {{ic|/etc/resolv.conf}}.
  
==== Using resolvconf ====
+
By default ''wg-quick''  uses ''resolvconf'' to register new [[DNS]] entries (from the {{ic|DNS}} keyword in the configuration file). This will cause issues with [[network manager]]s and [[DHCP]] clients that do not use ''resolvconf'', as they will overwrite {{ic|/etc/resolv.conf}} thus removing the DNS servers added by wg-quick.
  
If resolvconf is already used by the system and connection losses persist, make sure NetworkManager is configured to use it: [[NetworkManager#Use openresolv]].
+
The solution is to use networking software that supports [[resolvconf]].
  
==== Using dnsmasq ====
+
{{Note|If you are using [[systemd-resolved]], make sure that {{Pkg|systemd-resolvconf}} is [[install]]ed.}}
  
See [[Dnsmasq#openresolv]] for configuration.
+
In case of [[NetworkManager]], it does not use resolvconf by default. This will not be an issue when using [[systemd-resolved]], but if you do not use systemd-resolved, [[install]] {{Pkg|openresolv}} and configure NetworkManager to use it: [[NetworkManager#Use openresolv]].
  
==== Using systemd-resolved ====
+
=== Low MTU ===
  
{{Out of date|{{Bug|59459}} is fixed, systemd-resolved's resolvconf interface works.}}
+
Due to too low MTU (lower than 1280), wg-quick may have failed to create the WireGuard interface. This can be solved by setting the MTU value in WireGuard configuration in Interface section on client.
 
+
{{hc|/foo.config|2=
At the time of writing (Sept. 2018), the resolvconf-compatible mode offered by {{Pkg|systemd-resolvconf}} does not work with ''wg-quick''. However [[systemd-resolved]] can still be used by ''wg-quick'' through the {{ic|PostUp}} hook. First make sure that NetworkManager is configured with ''systemd-resolved'': [[NetworkManager#systemd-resolved]] and then alter the tunnel configuration:
 
 
 
{{hc|1=/etc/wireguard/wg0.conf|2=
 
 
[Interface]
 
[Interface]
Address = 10.0.0.2/24 # The client IP from wg0server.conf with the same subnet mask
+
Address = 10.200.200.2/24
PrivateKey = [CLIENT PRIVATE KEY]
+
MTU = 1500
PostUp = resolvectl domain %i "~."; resolvectl dns %i 10.0.0.1; resolvectl dnssec %i yes
+
PrivateKey = ''PEER_FOO_PRIVATE_KEY''
 
+
DNS = 10.200.200.1
[Peer]
+
}}  
PublicKey = [SERVER PUBLICKEY]
 
AllowedIPs = 0.0.0.0/0, ::0/0
 
Endpoint = [SERVER ENDPOINT]:51820
 
PersistentKeepalive = 25
 
}}
 
 
 
Setting {{ic|"~."}} as a domain name is necessary for ''systemd-resolved'' to give priority to the newly available DNS server.
 
 
 
No {{ic|PostDown}} key is necessary as ''systemd-resolved'' automatically revert all parameters when {{ic|wg0}} is torn down.
 
  
 
== Tips and tricks ==
 
== Tips and tricks ==
Line 341: Line 314:
 
==== Server ====
 
==== Server ====
  
{{hc|1=/etc/systemd/network/99-server.netdev|2=
+
{{hc|/etc/systemd/network/99-server.netdev|2=
 
[NetDev]
 
[NetDev]
 
Name = wg0
 
Name = wg0
 
Kind = wireguard
 
Kind = wireguard
Description = Wireguard
+
Description = WireGuard
  
 
[WireGuard]
 
[WireGuard]
 
ListenPort = 51820
 
ListenPort = 51820
PrivateKey = [SERVER PRIVATE KEY]
+
PrivateKey = ''SERVER_PRIVATE_KEY''
  
 
[WireGuardPeer]
 
[WireGuardPeer]
PublicKey = [FOO's PUBLIC KEY]
+
PublicKey = PEER_FOO_PUBLIC_KEY''
PresharedKey = [PRE-SHARED KEY]
+
PresharedKey = ''PRE-SHARED_KEY''
 
AllowedIPs = 10.200.200.2/32
 
AllowedIPs = 10.200.200.2/32
  
 
[WireGuardPeer]
 
[WireGuardPeer]
PublicKey = [BAR's PUBLIC KEY]
+
PublicKey = ''PEER_BAR_PUBLIC_KEY''
PresharedKey = [PRE-SHARED KEY]
+
PresharedKey = ''PRE-SHARED_KEY''
 
AllowedIPs = 10.200.200.3/32
 
AllowedIPs = 10.200.200.3/32
 
}}
 
}}
{{hc|1=/etc/systemd/network/99-server.network|2=
+
 
 +
{{hc|/etc/systemd/network/99-server.network|2=
 
[Match]
 
[Match]
 
Name = wg0
 
Name = wg0
Line 375: Line 349:
 
==== Client foo ====
 
==== Client foo ====
  
{{hc|1=/etc/systemd/network/99-client.netdev|2=
+
{{hc|/etc/systemd/network/99-client.netdev|2=
 
[NetDev]
 
[NetDev]
 
Name = wg0
 
Name = wg0
 
Kind = wireguard
 
Kind = wireguard
Description = Wireguard
+
Description = WireGuard
  
 
[WireGuard]
 
[WireGuard]
PrivateKey = [FOO's PRIVATE KEY]
+
PrivateKey = ''FOO_PRIVATE_KEY''
  
 
[WireGuardPeer]
 
[WireGuardPeer]
PublicKey = [SERVER PUBLICKEY]
+
PublicKey = ''SERVER_PUBLICKEY''
PresharedKey = [PRE-SHARED KEY]
+
PresharedKey = ''PRE-SHARED_KEY''
 
AllowedIPs = 10.200.0.0/24
 
AllowedIPs = 10.200.0.0/24
Endpoint = my.ddns.address.com:51820
+
Endpoint = my.ddns.example.com:51820
 
PersistentKeepalive = 25
 
PersistentKeepalive = 25
 
}}
 
}}
{{hc|1=/etc/systemd/network/99-client.network|2=
+
 
 +
{{hc|/etc/systemd/network/99-client.network|2=
 
[Match]
 
[Match]
 
Name = wg0
 
Name = wg0
Line 406: Line 381:
 
==== Client bar ====
 
==== Client bar ====
  
{{hc|1=/etc/systemd/network/99-client.netdev|2=
+
{{hc|/etc/systemd/network/99-client.netdev|2=
 
[NetDev]
 
[NetDev]
 
Name = wg0
 
Name = wg0
 
Kind = wireguard
 
Kind = wireguard
Description = Wireguard
+
Description = WireGuard
  
 
[WireGuard]
 
[WireGuard]
PrivateKey = [BAR's PRIVATE KEY]
+
PrivateKey = ''PEER_BAR_PRIVATE_KEY''
  
 
[WireGuardPeer]
 
[WireGuardPeer]
PublicKey = [SERVER PUBLICKEY]
+
PublicKey = ''SERVER_PUBLICKEY''
PresharedKey = [PRE-SHARED KEY]
+
PresharedKey = ''PRE-SHARED_KEY''
 
AllowedIPs = 10.200.0.0/24
 
AllowedIPs = 10.200.0.0/24
Endpoint = my.ddns.address.com:51820
+
Endpoint = my.ddns.example.com:51820
 
PersistentKeepalive = 25
 
PersistentKeepalive = 25
 
}}
 
}}
  
{{hc|1=/etc/systemd/network/99-client.network|2=
+
{{hc|/etc/systemd/network/99-client.network|2=
 
[Match]
 
[Match]
 
Name = wg0
 
Name = wg0
Line 433: Line 408:
 
Gateway = 10.200.200.1
 
Gateway = 10.200.200.1
 
Destination = 10.200.200.0/24
 
Destination = 10.200.200.0/24
GatewayOnlink=true
+
GatewayOnLink=true
 
}}
 
}}
  
Line 440: Line 415:
 
It may be desirable to store private keys in encrypted form, such as through use of {{pkg|pass}}. Just replace the PrivateKey line under [Interface] in the configuration file with:
 
It may be desirable to store private keys in encrypted form, such as through use of {{pkg|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")
+
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 {{man|8|wg-quick}} man page for more details.
 
where ''user'' is the Linux username of interest. See the {{man|8|wg-quick}} man page for more details.
Line 477: Line 452:
 
[Service]
 
[Service]
 
Type=oneshot
 
Type=oneshot
ExecStart=/bin/sh -c 'for i in /etc/wireguard/*.conf; do /usr/share/wireguard/examples/reresolve-dns/reresolve-dns.sh "\$i"; done'
+
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]] {{ic|wireguard_reresolve-dns.timer}}
 
Afterwards [[enable]] and [[start]] {{ic|wireguard_reresolve-dns.timer}}
 +
 +
=== Generate QR code ===
 +
 +
If the client is a mobile device such as a phone, {{Pkg|qrencode}} can be used to generate client's configuration QR code and display it in terminal:
 +
 +
$ qrencode -t ansiutf8 < client.conf
  
 
== See also ==
 
== See also ==
  
 +
* [[Wikipedia:WireGuard]]
 
* [https://www.wireguard.com/presentations/ Presentations by Jason Donenfeld].
 
* [https://www.wireguard.com/presentations/ Presentations by Jason Donenfeld].
 
* [https://lists.zx2c4.com/mailman/listinfo/wireguard Mailing list]
 
* [https://lists.zx2c4.com/mailman/listinfo/wireguard Mailing list]
 +
* [https://docs.sweeting.me/s/wireguard Unofficial WireGuard Documentation]
 +
* [[Debian:Wireguard]]

Latest revision as of 10:06, 2 December 2019

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 wireguard-tools.
  2. Install the appropriate kernel module:
Note: As of November 2019, it is looking like WireGuard could be mainlined as soon as kernel version 5.6.
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:

Tango-view-fullscreen.pngThis article or section needs expansion.Tango-view-fullscreen.png

Reason: Add Peer C to better demonstrate routing and PSK, and add IPv6. (Discuss in Talk:WireGuard#)
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/51871 UDP/51902

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.

Tango-view-fullscreen.pngThis article or section needs expansion.Tango-view-fullscreen.png

Reason: A pre-shared key should be created for each peer pair. E.g. with peers A, B and C, there should be three pre-shared keys, peer_A-peer_B-psk for the connection between Peer A and Peer B, peer_A-peer_C-psk for the connection between Peer A and Peer C and peer_B-peer_C-psk for the connection between Peer B and Peer C. (Discuss in Talk:WireGuard#)
# wg genpsk > preshared

Peer A setup

This peer will listen on UDP port 51871 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 51871 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:51902
# 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 51902 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 51902 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:51871
# 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: 51871

peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw=
  endpoint: 203.0.113.102:51902
  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:51871
PersistentKeepalive = 25

Example configuration for systemd-networkd

See #Using systemd-networkd.

Specific use-case: VPN server

Note: Usage of the terms "server" and "client" are used here specifically for newcomers to WireGuard and for current users of OpenVPN to help familiarize with the construction of configuration files. WireGuard documentation simply refers to both of these concepts as "peers."

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, Windows 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 peer that will act 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.

If the server have the public IP configured, 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 have the iptables rules and work as-is.

If the server is behind NAT, be sure to forward the specified port(s) on which WireGuard will be running (for example, 51820/UDP) from the router to the WireGuard server.

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
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY

# note - substitute eth0 in the following lines to match the Internet-facing interface
# if the server is behind a router and receive traffic via NAT, this iptables rules are not needed
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]
# foo
PublicKey = PEER_FOO_PUBLIC_KEY
PresharedKey = PRE-SHARED_KEY
AllowedIPs = 10.200.200.2/32

[Peer]
# bar
PublicKey = PEER_BAR_PUBLIC_KEY
AllowedIPs = 10.200.200.3/32

Additional peers ("clients") can be listed in the same format as needed. Each peer requires the PublicKey to be set. However, specifying PresharedKey is optional.

Notice that the Address have mask "/24" and the clients on AllowedIPs "/32". The client only use their IP and the server only send back their respective address.

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 = PEER_FOO_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.example.com:51820
bar.conf
[Interface]
Address = 10.200.200.3/24
PrivateKey = PEER_BAR_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.example.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

If you are not configuring WireGuard from NetworkManager, make sure that NetworkManager is not managing the WireGuard interface(s):

/etc/NetworkManager/conf.d/unmanaged.conf
[keyfile]
unmanaged-devices=interface-name:wg*

Broken DNS resolution

When tunneling all traffic through a WireGuard interface, the connection can become seemingly lost after a while or upon new connection. This could be caused by a network manager or DHCP client overwriting /etc/resolv.conf.

By default wg-quick uses resolvconf to register new DNS entries (from the DNS keyword in the configuration file). This will cause issues with network managers and DHCP clients that do not use resolvconf, as they will overwrite /etc/resolv.conf thus removing the DNS servers added by wg-quick.

The solution is to use networking software that supports resolvconf.

Note: If you are using systemd-resolved, make sure that systemd-resolvconf is installed.

In case of NetworkManager, it does not use resolvconf by default. This will not be an issue when using systemd-resolved, but if you do not use systemd-resolved, install openresolv and configure NetworkManager to use it: NetworkManager#Use openresolv.

Low MTU

Due to too low MTU (lower than 1280), wg-quick may have failed to create the WireGuard interface. This can be solved by setting the MTU value in WireGuard configuration in Interface section on client.

/foo.config
[Interface]
Address = 10.200.200.2/24
MTU = 1500
PrivateKey = PEER_FOO_PRIVATE_KEY
DNS = 10.200.200.1

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 = PEER_FOO_PUBLIC_KEY
PresharedKey = PRE-SHARED_KEY
AllowedIPs = 10.200.200.2/32

[WireGuardPeer]
PublicKey = PEER_BAR_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_PRIVATE_KEY

[WireGuardPeer]
PublicKey = SERVER_PUBLICKEY
PresharedKey = PRE-SHARED_KEY
AllowedIPs = 10.200.0.0/24
Endpoint = my.ddns.example.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 = PEER_BAR_PRIVATE_KEY

[WireGuardPeer]
PublicKey = SERVER_PUBLICKEY
PresharedKey = PRE-SHARED_KEY
AllowedIPs = 10.200.0.0/24
Endpoint = my.ddns.example.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