blog/source/_posts/2016-11-09-wireguard-with-floating-endpoints.markdown

2.6 KiB

layout title date comments categories
post Wireguard with floating endpoints 2016-11-09 19:01:39 +0100 true
wireguard
vpn
dynamic dns

Since systemd-networkd v23x support Wireguard. It supports dns hostnames as endpoint but will resolve them only once at startup. This breaks if the endpoint is only reachable via a dynamic addresses behind dyndns. The following systemd timer will update networkd configuration every five minute in case the endpoint address changes. That way also ipv4 or ipv6 can be enforced.

Save the following to files as /etc/systemd/update-wireguard-endpoint.timer and /etc/systemd/update-wireguard-endpoint.service:

# /etc/systemd/update-wireguard-endpoint.timer
[Unit]
Description="Update wireguard endpoint five minute"

[Timer]
OnBootSec=1min
OnUnitActiveSec=5min

[Install]
WantedBy=multi-user.target
# /etc/systemd/update-wireguard-endpoint.service
[Unit]
Description="Update wireguard endpoint"

[Service]
ExecStart=/usr/local/bin/update-wireguard-endpoint

Replace all the the <PLACEHOLDERS> with the approciate values and save as /usr/local/bin/update-wireguard-endpoint:

#!/usr/bin/env bash
set -eu pipeofail

PRIVATE_KEY="<PRIVATE_KEY_OF_LOCAL_HOST>"
PUBLIC_KEY="<PUBLIC_KEY_OF_DYNAMIC_ENDPOINT>"
ENDPOINT_HOST="<ADDRESS_OF_DYNAMIC_HOST>"
ENDPOINT_PORT="<PORT_OF_DYNAMIC_HOST>"
# other possible values: ahostsv4 or ahostsv6 to enforce either ipv4 or ipv6
ADDRESS_FAMILY="hosts"

tempfile="$(mktemp)"
trap "rm -r '$tempfile'" EXIT

resolved_endpoint="$(getent "$ADDRESS_FAMILY" "$ENDPOINT_HOST" | awk '{if ($1 ~ /:/) {printf "[%s]", $1; exit} else { print $1; exit} }')"

cat > "$tempfile" <<EOF
[NetDev]
Name=wg0
Kind=wireguard

[Wireguard]
PrivateKey=$PRIVATE_KEY

[WireguardPeer]
## configure as usual, example:
#AllowedIPs=192.168.77.1/32,fe80::/64
Endpoint=$resolved_endpoint:$ENDPOINT_PORT
PublicKey=$PUBLIC_KEY
PersistentKeepalive=10
EOF

if ! diff "$tempfile" /etc/systemd/network/wg0.netdev >/dev/null 2>&1; then
  cp "$tempfile" /etc/systemd/network/wg0.netdev
  systemctl restart systemd-networkd
fi

Also make sure that the script is executable using the the following command:

$ chmod +x /usr/local/bin/update-wireguard-endpoint

To configure addresses on the interface create a new .network file as usual:

#/etc/systemd/network/wg0.network
[Match]
Name=wg0

[Network]
## example:
#Address=fe80::1/64
#Address=192.168.77.2/24

Then enable the timer and check the status of the command:

systemctl enable --now update-wireguard-endpoint.timer
systemctl status update-wireguard-endpoint.service