Back to Blog
Infrastructure9 April 2024Michael Hettwer5 min read

WireGuard as a site-to-site VPN in practice

How we connect two locations with WireGuard: peers, AllowedIPs semantics, keepalive details, and the operational habits that keep tunnels boring.

Two locations that need to talk securely do not require a large appliance stack: for site-to-site links between servers and office networks, WireGuard has become the most relaxed answer. The tool has been part of the Linux kernel for years, needs no certificate infrastructure, and works with a small, readable configuration file. This post walks through a tunnel between two sites and the details that keep it stable months later.

The model: peers, keys, routes

WireGuard does not think in certificates and chains, but in peers: each tunnel end holds a key pair, and each side knows the public key of the other. Which traffic may enter the tunnel is decided by the AllowedIPs list of the respective peer: it acts as routing table and ingress filter at once. A packet that does not match the sender's AllowedIPs list is dropped; a destination network not in the list is not routed into the tunnel.

That dual role is why clean network enumeration matters. A site carrying the network 10.20.0.0/24 behind it declares that to the peer on the other side, and vice versa. When networks are added later, we extend both lists and keep the map honest. In practice it has proven wise to document the assignment as a small table: which site, which network, which peer, which key.

The configuration in two files

The setup is compact. On each side an interface file appears, for example /etc/wireguard/wg0.conf, holding the own private key, the address inside the tunnel network, the listener port, and the peer entry with public key, endpoint and AllowedIPs. One site should know the endpoint of the other; the other side does not have to be reachable to still bring a tunnel up: a peer behind a dynamic address refreshes its counterpart simply by sending traffic through an incoming connection.

For site-to-site links, PersistentKeepalive belongs in the configuration, usually with a value of 25 seconds. It keeps the NAT mapping between the sites open and makes sure the tunnel re-forms after an address change without anyone intervening. The value is not a matter of taste: smaller intervals only produce noise.

The operations that outlast the setup

The setup is the easy part. What keeps the tunnel boring are three habits. First: the service belongs in persistence, it must come back on its own after a reboot, and it should start early enough in the boot sequence that services depending on the tunnel find it up. Second: monitoring that checks the tunnel from the far side, not only from the local host. A ping through the tunnel from a third vantage point catches the problem the local ping cannot see: the partner side is missing. Third: key rotation as a planned event with the same seriousness as certificate rotation, even though WireGuard enforces no expiry.

One more point deserves attention: firewall ownership. The tunnel terminates on an interface that should be treated with the same suspicion as an external interface. We allow exactly the traffic the network enumeration implies; everything else falls through the general rules. Marking tunnel traffic trusted wholesale buys short-term convenience and, in the long run, an escape route for every compromised partner site.

When WireGuard is the right size

For site couplings, server-to-server links and the access paths of small administrative environments, WireGuard is the size that holds. Giving up a certificate infrastructure is not a limitation but a deliberate simplification: keys are small, distribution is a documented procedure, and the configuration fits on one screen. Where large, rotating user populations need fine-grained per-device policies, simpler models hit their limits, and other tools exist for exactly that. For the case in between, small teams connecting their sites, the plain tunnel is the answer one still understands years later.

What the tunnel delivers beyond the link

A well-kept tunnel between two sites is more than an encrypted line: it changes how the networks get considered as a whole. Services that used to be reachable only inside one site become, through the tunnel, names with clear ownership, and the question "allowed or blocked" moves from network geometry into configuration. That shift is the real gain, because it makes decisions visible: whoever allows states exactly whom they allow, and whoever blocks states exactly what they block.

In maintenance a small yearly rhythm has proven itself: rotate the keys once a year, check the network enumerations against reality, and bring the documentation up to date. The effort is half an hour per site, and the harvest is a tunnel whose state can be explained without investigating it first. That explainability is exactly the quality marker that separates good tunnel operations: not the encryption makes the difference, but the fact that during a fault the first question, "what changed last", has an inspectable answer.

A look at the limits belongs to the honesty of the topic: WireGuard encrypts the path between the peers, but it manages neither users nor per-person policies. Where access changes frequently, where external participants work with their own devices, or where fine-grained control is needed over who may reach which application, the tunnel's job ends and the job of an ingredient the tunnel does not deliver begins. That is no weakness but a clear assignment of roles: the tunnel carries the route, the access management carries the people. Landscapes that keep the two apart re-decide less often, because every question gets answered at the place where it belongs.

If you want to connect sites or rebuild your existing tunnels on such a footing, the network and firewall page describes the matching service, Linux administration the ongoing operations, and the contact page is the fastest way to reach us.

Sources

  • WireGuard project overview, https://www.wireguard.com/ (accessed 2026-11-03)
  • WireGuard quickstart, https://www.wireguard.com/quickstart/ (accessed 2026-11-03)
  • wg(8) manual page, https://man.archlinux.org/man/wg.8.en (accessed 2026-11-03)
  • wg-quick(8) manual page, https://man.archlinux.org/man/wg-quick.8.en (accessed 2026-11-03)
  • wireguard-tools project, https://git.zx2c4.com/wireguard-tools/about/ (accessed 2026-11-03)