For example, a sample WireGuard configuration looks like this:
[Interface] ListenPort = <listen port> PrivateKey = <privkey> Address = <link local>/64 Table = off [Peer] PublicKey = <pubkey> PresharedKey = <psk> Endpoint = <endpoint> AllowedIPs = ::/0
It is good practice to create a separate WireGuard tunnel for each peer. In this tutorial,
wg-quick is used to manage the WireGaurd tunnels.
<listen port> is the local port to which the peer connects. This must be opened in the firewall using the UDP protocol. The only requirement for the port is that it is not already in use.
<privkey> is the private key. This should never be shared.
<link local> is link-local IPv6 address. It does not matter which one is used, because it is only valid for this interface. The only requirement is that the peer uses a different link-local IPv6 address.
Table = off prevents the creation of a default route for the
<pubkey> is the public key of the peer.
<psk> In addition to asymmetric keys, a symmetric pre-shared key can be used. This must be agreed in advance between the peers via a secure channel. A PSK is optional, but is recommended.
<endpoint> is the remote station, i.e. the peer. This is usually the host name or the IP address and the port. For example,
AllowedIPs specifies the IP addresses that may be transported via the interface.
::/0 stands for any IPv6 address. If this is used, it is recommended to use firewall rules to avoid that peers can enter the clearnet via you.
On Debian systems you store the configuration in
/etc/wireguard with the file extension
.conf. This may differ depending on the system. The name of the file also becomes the name of the interfaces. For example, you can save the file as
crxn_<peername>.conf. The name of the interface then becomes
The tunnel can be enabled with
wg-quick up <name> and disabled with
wg-quick down <name>. If can also control the tunnel with systemd:
$ sudo systemctl start wg-quick@<name> $ sudo systemctl stop wg-quick@<name>
Furthermore you can autostart the tunnel with systemd:
$ sudo systemctl enable wg-quick@<name> $ sudo systemctl disable wg-quick@<name>
With the command
wg genkey you can create a key:
$ wg genkey 4HMlCI/Oz+sVmlM90c5YLpFR0/NaoMGv1uFT28qx1Gg=
To calculate the public key that you share with your peer, you can use the
wg pubkey command. For this you can type
wg pubkey, insert the private key and press CTRL+D. Alternatively, you can pipe the private key.
$ wg pubkey 4HMlCI/Oz+sVmlM90c5YLpFR0/NaoMGv1uFT28qx1Gg= RmK5OX34MLbEwJTRNl8i9ghrAS4SkKDsr24NIK2bWSY=
$ echo 4HMlCI/Oz+sVmlM90c5YLpFR0/NaoMGv1uFT28qx1Gg= | wg pubkey RmK5OX34MLbEwJTRNl8i9ghrAS4SkKDsr24NIK2bWSY=
(This method is not secure because it stores the private key in the command history).
wg shows all tunnels. The command
wg show <name> shows only one specific tunnel.
# wg show <name> interface: <name> public key: <my pubkey> private key: (hidden) listening port: <listen port> peer: <pubkey> preshared key: (hidden) endpoint: <endpoint> allowed ips: ::/0 latest handshake: 1 minute, 30 seconds ago transfer: 30.79 MiB received, 37.33 MiB sent
A WireGuard tunnel only becomes active and performs a handshake when it is used. If a tunnel is not used, there will be no handshake. The tunnel can be activated with a ping on the peers inner tunnel address, for example. Whether the tunnel is working can be seen by
latest handshake. If this line is present, the handshake was successful.
$ ping fe80::2%<name>
If only one peer has a public IP address and the other does not, for example because it is behind a NAT, WireGuard will also work. In this case, you do not specify an endpoint for the public peer. For the peer that is not public, omit the
ListenPort and add an extra line. This causes the peer to send a kind of “ping” every
<sec> seconds to maintain the tunnel.
[Peer] ... some config ... PersistentKeepalive = <sec> ... some config ...
The interval may be different depending on NAT and firewall. 20 to 60 seconds is recommended. Often used values are
Dynamic IP addresses
It may happen that one peer has a dynamic IP address. Often a DNS name is then specified. However, WireGuard only resolves the DNS once at the start of the connection and therefore does not know of the new IP address. Therefore, you must manually tell WireGuard to resolve the new IP address:
wg set <name> peer "<pubkey>" endpoint "<endpoint>"
This can then be executed as a cronjob every 30 minutes, for example:
*/30 * * * * /usr/bin/wg set <name> peer "<pubkey>" endpoint "<endpoint>"
The MTU for WireGuard is calculated from the following components:
- IP header
- For IPv4 20 Bytes
- For IPv6 40 bytes
- UDP header
- This is a constant 8 bytes
- WireGuard header
- This is a constant 32 bytes
So if the Clearnet connection has an MTU of 1500, the tunnel MTU when tunneling over IPv4 is 1440 and for IPv6 it is 1420. This has been taken into account in WireGuard, so the default MTU of WireGuard is 1420. This means that WireGuard can be tunneled over IPv4 or IPv6 without worry. However, if you are sure that you want to tunnel over IPv4 and you want a higher packet size, you can set the MTU to 1440. On the other hand, if the Clearnet interface has a lower MTU than 1500, you should lower the WireGuard MTU to avoid bugs and IP fragmentation.
When using wg-quick, you can adjust the MTU with the following statement under
[Interface] in the configuration file:
MTU = <mtu>
<mtu> is replaced by the desired MTU.
WireGuard configuration errors are normally somewhat difficult to detect. However, it is possible to enable logging. With the following command, you can enable logging:
echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control
The log can be viewed with dmesg, for example:
dmesg --follow --human
The dn42 Wiki also has a guide to WireGuard: in dn42 or in clearnet