Setting up lean, modern encryption on Linux
OpenVPN and IPsec have been the standard for site to site VPNs for years, but they carry a code footprint, configuration complexity, and handshake overhead that WireGuard deliberately avoids. With roughly four thousand lines of kernel code, modern cryptography, and a single configuration file, WireGuard has established itself as a lean alternative for secure server to server connections.
Table of Contents
- 1. Why WireGuard is lighter than OpenVPN and IPsec
- 2. The Noise Protocol Framework and the lean handshake
- 3. Generating key pairs: the first step of any WireGuard configuration
- 4. Interface configuration: the structure of wg0.conf in detail
- 5. Peer setup and the meaning of AllowedIPs
- 6. PersistentKeepalive: keeping connections stable behind NAT
- 7. MTU considerations and best practices for production use
- 8. Practical example: securing database replication across sites
- 9. Troubleshooting and monitoring WireGuard connections
- 10. Summary
- 11. FAQ
1. Why WireGuard is lighter than OpenVPN and IPsec
OpenVPN is built on OpenSSL and offers an enormous range of configurable ciphers, authentication methods, and operating modes, which in practice leads to configuration files with dozens of options and a correspondingly large attack surface. IPsec, in turn, spreads its logic across several protocols like IKE, ESP, and AH, whose interplay regularly poses debugging challenges even for experienced administrators, especially once NAT traversal comes into play.
WireGuard takes a radically different approach: it offers exactly one modern cryptography suite, Curve25519 for key exchange and ChaCha20-Poly1305 for authenticated encryption, with no negotiation between multiple ciphers. This deliberate constraint keeps the kernel code down to roughly four thousand lines, compared to sometimes several hundred thousand lines in established IPsec implementations, which drastically shrinks both the attack surface and the number of potential implementation bugs.
2. The Noise Protocol Framework and the lean handshake
WireGuard is built on the Noise Protocol Framework, a formally verified collection of handshake patterns for authenticated key exchange. The handshake it uses, known as Noise_IK, needs only a single round trip between two peers to establish a new session with perfect forward secrecy, while classic IPsec IKEv2 handshakes go through several round trips depending on configuration.
Every connection is also conceptually stateless compared to the classic connection model: WireGuard has no explicit connection in the sense of a TCP handshake, instead processing UDP packets based on cryptographic identity. That means a client can change its public IP address, for example when switching between mobile data and WiFi, and the connection survives once the next authenticated packet arrives, with no need for a full renegotiation.
3. Generating key pairs: the first step of any WireGuard configuration
WireGuard uses a dedicated Curve25519 key pair for every peer, consisting of a private and a public key. Unlike classic VPN solutions with a central certificate authority, there is no public key infrastructure, no certificate chains, and no revocation lists to manage, which significantly simplifies initial setup, but also means key rotation and peer management across many servers must be handled organizationally.
The private key ideally never leaves the server it was generated on, while the public key is handed to the peer and entered into its peer configuration. For environments with many servers, a central but securely stored directory of public keys is worthwhile, for example in a secrets management system, while private keys stay strictly local with restrictive file permissions.
# Generate a private key and restrict permissions immediately
umask 077
wg genkey > /etc/wireguard/privatekey
# Derive the public key from the private key
wg pubkey < /etc/wireguard/privatekey > /etc/wireguard/publickey
cat /etc/wireguard/publickey
4. Interface configuration: the structure of wg0.conf in detail
The central configuration file of a WireGuard interface follows a simple INI style structure with exactly two section types: a single [Interface] block for the local configuration and any number of [Peer] blocks, one for each remote party. The [Interface] section sets the private key, the IP address assigned to the interface within the VPN subnet, and the UDP listen port through which WireGuard accepts incoming handshakes.
Optionally, the [Interface] block can carry extra shell logic via PostUp and PostDown, for example to automatically set firewall forwarding rules when the interface comes up and remove them again when it goes down. These hooks are especially useful in server to server scenarios where the WireGuard interface acts as a gateway for further network traffic, such as database replication that should be routed through the tunnel.
# /etc/wireguard/wg0.conf on the primary database server
[Interface]
PrivateKey = <private_key_server_a>
Address = 10.10.0.1/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
[Peer]
# Replication standby at the second site
PublicKey = <public_key_server_b>
AllowedIPs = 10.10.0.2/32
Endpoint = replica.example.com:51820
PersistentKeepalive = 25
5. Peer setup and the meaning of AllowedIPs
AllowedIPs serves a dual purpose in WireGuard that is often underestimated: it defines which source IP addresses are accepted from a given peer, and it also acts as the routing table for outbound traffic that should be tunneled through that peer. Setting AllowedIPs too broadly, for example to 0.0.0.0/0, unintentionally routes the server's entire traffic through the tunnel, while defining it too narrowly silently drops legitimate packets without producing an error message.
For a server to server scenario with database replication across two sites, it is usually enough to restrict AllowedIPs to the single /32 address of each peer within the VPN subnet. If entire subnets behind a peer also need to be reachable, for example an internal network segment at the second site, the corresponding subnet is added to AllowedIPs and must additionally be supported by IP forwarding and matching routing entries on both sides.
6. PersistentKeepalive: keeping connections stable behind NAT
Since WireGuard is UDP based and has no explicit connection state like TCP, NAT gateways and stateful firewalls can drop the mapping between a client port and a session after a period of inactivity. Without a countermeasure, that means incoming packets from the server can no longer be delivered to the original client once its NAT mapping expires, effectively breaking the connection in one direction.
The PersistentKeepalive option solves this by sending an empty UDP packet to the peer at fixed intervals, typically every 25 seconds, to artificially keep the NAT mapping alive. For pure server to server connections with fixed, publicly reachable IP addresses on both sides, PersistentKeepalive is often unnecessary, but it is recommended once at least one side sits behind NAT or a restrictive firewall with a session timeout.
# Bring the interface up and check status including handshake age
wg-quick up wg0
wg show wg0
# Expected output shows the latest handshake and transferred bytes
# peer: <public_key>
# endpoint: replica.example.com:51820
# allowed ips: 10.10.0.2/32
# latest handshake: 12 seconds ago
# transfer: 4.21 MiB received, 3.98 MiB sent
7. MTU considerations and best practices for production use
WireGuard wraps every packet in UDP and adds its own protocol header, which is why the interface defaults to an MTU of 1420 bytes instead of the usual 1500 bytes, to avoid fragmentation inside the tunnel. If WireGuard runs on top of an already reduced base MTU, for example inside another tunnel or over a PPPoE connection, the WireGuard MTU needs to be adjusted manually, since otherwise the same Path MTU Discovery problems that affect other tunneling technologies can show up here too.
For production use, it is also worth never storing private keys with world readable permissions, consistently using mode 600 with root ownership instead, and keeping AllowedIPs as narrow as possible rather than defaulting to 0.0.0.0/0 out of convenience. On Debian and Ubuntu systems, WireGuard can also be configured natively through systemd-networkd, which, compared to the classic wg-quick script, has the advantage that interface state and routing are managed consistently through the same network management as every other interface on the server.
# Manually adjust a WireGuard interface's MTU if the underlying
# path already has a reduced MTU of its own
ip link set mtu 1380 dev wg0
# Check the private key's permissions before going to production
chmod 600 /etc/wireguard/privatekey
chown root:root /etc/wireguard/privatekey
8. Practical example: securing database replication across sites
A typical use case in a hosting context is securing MySQL or PostgreSQL replication between two physically separated data centers without sending replication traffic unprotected over the open internet. Instead of securing the database itself with per connection TLS certificates, WireGuard wraps the entire traffic at the network layer, so the database configuration stays unchanged and simply points at the peer's internal VPN address.
In practice, the primary database server binds only to its WireGuard address in the 10.10.0.0/24 subnet, while the public network interface stays closed for the database port. That way, the replication link stays protected even if an attacker could otherwise reach a server's public database port directly, since the actual replication traffic runs exclusively inside the encrypted WireGuard tunnel.
9. Troubleshooting and monitoring WireGuard connections
The most important diagnostic signal is the latest handshake timestamp in the output of wg show: if that value is far in the past or missing entirely, no valid communication is happening between the peers, usually due to a wrong public key, UDP packets blocked at the firewall level, or a misconfigured endpoint. Since WireGuard deliberately stays silent on invalid packets instead of sending error messages, checking transferred byte counts often helps more than classic logging.
For ongoing monitoring, wg show wg0 dump produces machine readable output that can be fed into monitoring systems such as Prometheus through a simple exporter, tracking handshake age and transfer volume per peer continuously. A handshake older than about three minutes reliably indicates a problem in production server to server connections and should trigger an alert before replication itself starts to stall.
| Aspect | OpenVPN | IPsec | WireGuard |
|---|---|---|---|
| Code footprint | Tens of thousands of lines, OpenSSL dependency | Several hundred thousand lines across IKE/ESP/AH | Roughly four thousand lines in the kernel |
| Configuration effort | Certificates, many options | IKE policies, often complex NAT traversal | One file per interface, key pairs |
| Handshake | TLS handshake with several round trips | IKEv2 with several round trips | Noise_IK with a single round trip |
| Cryptography choice | Negotiable across many ciphers | Negotiable across many suites | Fixed, no negotiation overhead |
| Typical use | Client VPN with certificate management | Site linking in enterprise environments | Server to server and lean site to site VPNs |
Mironsoft
Server administration, Docker hosts, and performance tuning
Linux servers nobody on the team really understands anymore?
We handle setup, hardening, and performance tuning of Linux servers and Docker hosts for Magento deployments, documented and traceable instead of grown and unclear.
Server Audit
Review the existing server configuration for security gaps and performance bottlenecks.
Docker Host Setup
Set up and secure production-ready Docker environments for Magento cleanly.
Monitoring & Tuning
Measure resource usage and tune systemd, kernel, and services with purpose.
10. Summary
WireGuard VPN
Cryptography
Curve25519 for key exchange, ChaCha20-Poly1305 for encryption
Core configuration
One wg0.conf per interface with interface and peer blocks
Critical option
AllowedIPs controls both access and routing at once
Typical use case
Encrypted server to server connections like database replication