WireGuard VPN Client

Posted on 3 2026

WireGuard is the right VPN protocol for this network. It is built into the Linux kernel, has minimal attack surface compared to OpenVPN or IPsec, uses modern cryptography by default, and roams cleanly between networks without dropping connections. On Kubuntu it integrates natively with NetworkManager, which means connecting and disconnecting is a single click or keyboard shortcut rather than a terminal command.

This page covers the desktop client configuration. The server-side WireGuard setup, running on the Ubiquiti UniFi routers at each site, is covered in the router section of this series. This page assumes that the server-side configuration is in place and you have a client configuration file ready.

Two use cases

There are two distinct ways you will use WireGuard on the desktop, and they have slightly different configurations.

Roaming client. When the desktop leaves the home network and connects from elsewhere, WireGuard provides a tunnel back to the home network. This gives access to all internal services and all three sites as if you were physically present. This is split-tunnel: only traffic destined for the internal subnets goes through the VPN, and internet traffic uses whatever network you are on.

Site-to-site connectivity. When the desktop is at one of the three sites, WireGuard is already handling inter-site routing at the router level. The desktop does not need its own VPN tunnel in this case: traffic to the other sites routes through the Ubiquiti router automatically. The desktop-level WireGuard configuration is for the roaming case.

Installation

WireGuard is included in the Linux kernel from version 5.6. Kubuntu 24.04 includes it natively. Install the tools and NetworkManager integration:

sudo apt install wireguard wireguard-tools

NetworkManager’s WireGuard support is included by default on Kubuntu 24.04. No additional packages are required.

Generating a key pair

Each WireGuard peer needs a key pair. Generate one for the desktop:

wg genkey | tee /tmp/desktop-private.key | wg pubkey > /tmp/desktop-public.key

Store the private key securely. It should never leave the desktop. The public key is what you give to the WireGuard server (your router) to add this desktop as a permitted peer.

cat /tmp/desktop-public.key

Copy this output and add it to your router’s WireGuard peer configuration. The router section covers the server-side steps.

Move the private key to the WireGuard configuration directory and lock down permissions:

sudo mkdir -p /etc/wireguard
sudo mv /tmp/desktop-private.key /etc/wireguard/desktop-private.key
sudo chmod 600 /etc/wireguard/desktop-private.key
sudo chown root:root /etc/wireguard/desktop-private.key
rm /tmp/desktop-public.key

Client configuration file

Create /etc/wireguard/home.conf. This is the configuration for the tunnel back to Prevernal, which acts as the primary VPN endpoint when roaming:

[Interface]
# Desktop's private key
PrivateKey = <contents of /etc/wireguard/desktop-private.key>

# The VPN address assigned to this desktop
# Allocate from a range set aside for VPN clients in your network design
# For example, a dedicated VPN client subnet within the 10.1.x.x space
Address = 10.1.254.2/32

# Use your internal DNS server when connected
DNS = 10.1.0.1
DNS = yourdomain.net lan

# Optional: restrict the connection to a specific port if your router
# is behind a NAT that maps to a non-standard port
# ListenPort = 51820

[Peer]
# Prevernal's public key (from the router configuration)
PublicKey = <Prevernal's WireGuard public key>

# The router's external IP or hostname and WireGuard port
Endpoint = vpn.yourdomain.net:51820

# Split tunnel: route only internal subnets through the VPN
# Covers all three sites
AllowedIPs = 10.1.0.0/16, 10.2.0.0/16, 10.3.0.0/16

# Keep the tunnel alive through NAT (sends a keepalive every 25 seconds)
PersistentKeepalive = 25

Set correct permissions on the config file:

sudo chmod 600 /etc/wireguard/home.conf
sudo chown root:root /etc/wireguard/home.conf

Importing into NetworkManager

NetworkManager can manage WireGuard connections directly, which integrates it into the system tray and allows on-demand connect/disconnect.

Import the configuration:

sudo nmcli con import type wireguard file /etc/wireguard/home.conf

Verify it was imported:

nmcli con show

A connection named home should appear in the list with type wireguard.

The connection is now accessible from the KDE network applet in the system tray. Find it under VPN connections and toggle it on or off as needed.

Configuring via the KDE Network Manager applet

Alternatively, configure the connection entirely through the GUI. Open the network applet, click the settings icon, and add a new VPN connection of type WireGuard.

The fields map directly to the configuration file:

  • Interface name: wg0 or any name
  • Private key: the contents of desktop-private.key
  • IP address: 10.1.254.2/32
  • DNS: 10.1.0.1
  • Peer public key: Prevernal’s public key
  • Allowed IPs: 10.1.0.0/16, 10.2.0.0/16, 10.3.0.0/16
  • Endpoint: vpn.yourdomain.net:51820
  • Persistent keepalive: 25

Save and connect.

DNS when connected

The DNS line in the configuration sets the DNS server used when the tunnel is active. NetworkManager adds this as a per-connection DNS override, so while the VPN is connected your internal domain names resolve correctly through the tunnel.

When the VPN disconnects, DNS reverts to whatever Unbound is configured to use, which for external networks is the fallback public resolvers set in the Unbound configuration.

Verify DNS is routing correctly when connected:

resolvectl status

The WireGuard interface should show 10.1.0.1 as its DNS server and yourdomain.net and lan as search domains.

Full tunnel vs split tunnel

The configuration above uses split tunnelling: only the three internal subnets (10.1.0.0/16, 10.2.0.0/16, 10.3.0.0/16) go through the VPN. Internet traffic uses whatever network you are currently on.

For full tunnel, where all traffic including internet goes through the home network, change AllowedIPs to:

AllowedIPs = 0.0.0.0/0, ::/0

Full tunnel is useful when on untrusted networks (public WiFi, hotel networks) and you want all traffic protected. The downside is that internet speed is limited by your home connection’s upload capacity. Split tunnel is the better default for day-to-day use.

Auto-connect on specific networks

If you want the VPN to connect automatically when the desktop is away from the home network but not when it is on the home network, a NetworkManager dispatcher script handles this:

Create /etc/NetworkManager/dispatcher.d/40-wireguard-autoconnect:

#!/usr/bin/env bash
#
# Auto-connect WireGuard VPN when not on the home network.
#

INTERFACE=$1
ACTION=$2
VPN_CONNECTION="home"

# Only act on physical connections, not the VPN interface itself
if [[ "$INTERFACE" == wg* ]]; then
    exit 0
fi

case "$ACTION" in
    up)
        # Get the current subnet
        SUBNET=$(nmcli -g IP4.ADDRESS device show "$INTERFACE" 2>/dev/null | \
            head -1 | awk -F'.' '{print $1"."$2}')

        # If we are on one of the home subnets, do not connect the VPN
        if [[ "$SUBNET" == "10.1" ]] || \
           [[ "$SUBNET" == "10.2" ]] || \
           [[ "$SUBNET" == "10.3" ]]; then
            exit 0
        fi

        # On an external network, bring up the VPN
        nmcli con up "$VPN_CONNECTION" &
        ;;

    down)
        # Bring down the VPN when the underlying connection drops
        nmcli con down "$VPN_CONNECTION" 2>/dev/null
        ;;
esac
sudo chmod 0744 /etc/NetworkManager/dispatcher.d/40-wireguard-autoconnect
sudo chown root:root /etc/NetworkManager/dispatcher.d/40-wireguard-autoconnect

Testing the connection

Bring the VPN up manually:

nmcli con up home

Test connectivity to all three sites:

ping -c3 10.1.0.1   # Prevernal
ping -c3 10.2.0.1   # Vernal
ping -c3 10.3.0.1   # Estival

Test internal DNS resolution through the tunnel:

dig server.yourdomain.net +short

Check the WireGuard interface status:

sudo wg show

This shows the current handshake time, bytes transferred, and allowed IPs for each peer. A recent handshake (within the last few minutes) confirms the tunnel is active.

Checking for DNS leaks

When using split tunnel, verify that external DNS queries are not going through the VPN:

dig google.com +short

This should resolve quickly using your local Unbound instance. If it is slow or failing, check that AllowedIPs does not include 0.0.0.0/0 and that Unbound is running correctly.

Troubleshooting

Handshake never completes: Check that the router’s WireGuard port is reachable from outside:

nc -u -v vpn.yourdomain.net 51820

If it times out, the port may not be forwarded through the router’s WAN firewall.

DNS not resolving internal names: Verify the DNS setting was applied:

resolvectl status wg0

If the DNS server is not showing, reload the connection:

nmcli con down home && nmcli con up home

Connection drops when switching networks: WireGuard handles roaming by design. If connections are dropping, check that PersistentKeepalive = 25 is set in the peer configuration. This is important for NAT traversal.

Cannot reach sites 2 or 3: Verify the router at Prevernal has routes to the other site subnets and that the inter-site VPN between routers is up. The desktop tunnel only needs to connect to Prevernal: inter-site routing is handled at the router level from there.

The private key in /etc/wireguard/home.conf and /etc/wireguard/desktop-private.key is the most sensitive file in the WireGuard setup. Anyone with this key can authenticate to your VPN as this desktop. The permissions set above (600, root-owned) are the minimum. Store a backup in KeePassXC.