Background
The server runs on my home network and, by default, is only reachable from there. I wanted access from outside the house without exposing SSH or the admin interface to the public internet, which rules out plain port forwarding.
A VPN solves this cleanly, and WireGuard is a lightweight, modern option with a small attack surface and simple key-based configuration. The requirement was narrow: reach the server from my laptop on any network, over an encrypted tunnel, with a single port open to the outside.
Outcome: the server is reachable over the tunnel from any network, the connection re-establishes automatically after a reboot, and only one UDP port is exposed to the internet.
Network layout
The laptop connects as a WireGuard client. The server runs the WireGuard interface and assigns addresses from a private 10.0.0.0/24 range: the server is 10.0.0.1 and the laptop is 10.0.0.2. Once the tunnel is established, the server is reachable at 10.0.0.1 as though it were on the local network, regardless of which network the client is on.
Implementation
Troubleshooting
The interface came up on the first attempt and the client reported an active tunnel, but no traffic passed. Pings to the server from outside the network timed out.
I worked through the obvious causes first. The firewall was inactive, the router was forwarding the correct port, and the server was listening. Packets were reaching the network interface but not entering the tunnel.
Two separate faults were involved. The masquerade rules referenced the wrong network interface, so return traffic had no path out; correcting the interface in the PostUp and PostDown rules fixed the routing. The second fault was a key mismatch. The client's public key stored on the server did not match the key derived from its private key, off by one character, since a capital I and a lowercase l are easy to confuse in many fonts. Deriving the public key with wg pubkey and comparing it against the peer configuration confirmed it. With both corrected, the connection established immediately.
Neither was a flaw in the design. Both were small configuration errors that were easy to introduce and slow to find, which is fairly typical of first-time VPN setups.
In use
Running wg show on the server reports the tunnel state, the connected peer, the last handshake, and throughput. To connect, I enable the tunnel on my laptop and SSH to 10.0.0.1 as though the server were on the local network.
Because the service starts with the machine, remote access survives a reboot without manual steps. It has been stable since, and it removed any need to expose management services publicly.