DEV Community

Cover image for Site-to-Site VPN with WireGuard: Key and Route Design
Mustafa ERBAY
Mustafa ERBAY

Posted on Originally published at mustafaerbay.com.tr

Site-to-Site VPN with WireGuard: Key and Route Design

WireGuard Core Concepts

WireGuard is an L3 VPN protocol integrated into the Linux kernel. Each "peer" is identified by a public-key/private-key pair, and packets are transmitted in an encrypted format over UDP port 51820. As stated in the Ubuntu Server documentation, "no additional firewall rules are required on hosts inside the networks" (Ubuntu, site-to-site documentation). This means the WireGuard interface only needs to be configured on the gateways. This kernel-level module offers low latency and high throughput; furthermore, thanks to "cryptokey routing," packets are added directly to the kernel routing table.

Key Management and Security

Keys can be generated using the wg genkey and wg pubkey commands:

# Generate private key
wg genkey | tee /etc/wireguard/privkey | wg pubkey > /etc/wireguard/pubkey
Enter fullscreen mode Exit fullscreen mode

These commands are provided by the wireguard package; it must be installed from the Ubuntu 22.04 LTS repositories. The private key should never be exported; it is kept only in the /etc/wireguard/ directory of the relevant gateway, and file permissions should be set to 600. The public key is added to the Peer section of the remote site's configuration.

Security note: Generating and backing up the private key once simplifies the "key rotation" procedure for future reconfigurations. The Ubuntu documentation suggests creating a new private key for key rotation and restarting the existing tunnel using wg-quick downwg-quick up.

Route Planning and Subnet Selection

In a site-to-site VPN, the LANs of two offices must be connected in an isolated manner. Choosing non-overlapping subnets is critical; otherwise, a "routing loop" will occur. For example:

  • Site A LAN: 10.10.0.0/16
  • Site B LAN: 10.20.0.0/16

Routing between these two networks is achieved by defining the other side's LAN in the AllowedIPs field of each gateway. In Ubuntu documentation, "cryptokey routing" is automatically added with a line like AllowedIPs = 10.20.0.0/16.

Edge case: If two offices have the same subnet (e.g., 10.0.0.0/16), you must use NAT-over-VPN; in this case, iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE is added via PostUp and PostDown scripts. However, since this can lead to performance loss, non-overlapping subnets should be preferred whenever possible.

Ubuntu Server Installation Steps

The basic steps for installing WireGuard on Ubuntu Server 22.04 LTS are as follows:

# 1. install packages
sudo apt update
sudo apt install wireguard

# 2. create configuration directory
sudo mkdir -p /etc/wireguard
sudo chmod 700 /etc/wireguard

# 3. generate private and public keys
wg genkey | sudo tee /etc/wireguard/siteA.key | wg pubkey | sudo tee /etc/wireguard/siteA.pub
Enter fullscreen mode Exit fullscreen mode

The generated keys are saved to siteA.key and siteA.pub files. Subsequently, the wg0.conf file follows this example structure:

[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <siteA_private_key>

[Peer]
PublicKey = <siteB_public_key>
Endpoint = 203.0.113.2:51820
AllowedIPs = 10.20.0.0/16
PersistentKeepalive = 25
Enter fullscreen mode Exit fullscreen mode

<siteA_private_key> and <siteB_public_key> must be replaced with actual values. After creating the file:

sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0.service
Enter fullscreen mode Exit fullscreen mode

These commands activate the interface and start it automatically at system boot. The statement "no changes needed on individual hosts" in the official Ubuntu documentation confirms that this step only needs to be performed on the gateways.

Example Scenario: Site-to-Site Connection Between Two Offices

Scenario:

  • Site A: Istanbul office, 10.10.0.0/16, external IP 198.51.100.10.
  • Site B: Ankara office, 10.20.0.0/16, external IP 203.0.113.2.

Both sites install WireGuard on a VM running Ubuntu 22.04 LTS. The following steps show how to establish the two-way tunnel.

# Site A (Istanbul) – get public key from Site B
sudo wg set wg0 peer <siteB_pub> allowed-ips 10.20.0.0/16 endpoint 203.0.113.2:51820 persistent-keepalive 25
Enter fullscreen mode Exit fullscreen mode
# Site B (Ankara) – perform the same process in reverse
sudo wg set wg0 peer <siteA_pub> allowed-ips 10.10.0.0/16 endpoint 198.51.100.10:51820 persistent-keepalive 25
Enter fullscreen mode Exit fullscreen mode

To verify the connection:

sudo wg show
Enter fullscreen mode Exit fullscreen mode

The output shows the latest handshake time and the amount of data transferred for each peer. The warning in the Ubuntu documentation that "no changes needed on individual hosts" emphasizes that machines within the LAN do not require additional configuration; communication is simply checked with tests like ping 10.20.0.1.

Verification and Monitoring

The operational status of WireGuard can be monitored with the wg command:

sudo wg show wg0
Enter fullscreen mode Exit fullscreen mode

This lists the received and sent byte values for each peer. Additionally, examining logs via the systemd journal is useful for detecting potential handshake errors:

journalctl -u wg-quick@wg0 -f
Enter fullscreen mode Exit fullscreen mode

Ubuntu's official guide states that "no additional firewall rules" are required; however, allowing only UDP 51820 via ufw or iptables is a good security layer:

sudo ufw allow 51820/udp
Enter fullscreen mode Exit fullscreen mode

This step prevents external attackers from establishing a tunnel over a different port.

Rollback and Maintenance

It is recommended to take a copy of the existing file before making configuration changes:

sudo cp /etc/wireguard/wg0.conf /etc/wireguard/wg0.conf.bak
Enter fullscreen mode Exit fullscreen mode

When a new key is generated or a subnet is changed, the following steps are followed:

  1. wg-quick down wg0 – close the active tunnel.
  2. Update the wg0.conf file.
  3. wg-quick up wg0 – load the new configuration.

This process is defined as the "rollback" procedure in Ubuntu documentation. If the new configuration creates an unexpected routing problem, restoring the backup file and repeating the same steps resolves the issue.

sudo cp /etc/wireguard/wg0.conf.bak /etc/wireguard/wg0.conf
sudo wg-quick down wg0 && sudo wg-quick up wg0
Enter fullscreen mode Exit fullscreen mode

Network Topology – Mermaid Diagram

Key Rotation Strategy

Key rotation keeps a WireGuard tunnel resilient against long-term key compromise.
The rotation process is deliberately simple: generate a new private key, stop the tunnel, replace the key in the configuration, and bring the tunnel back up.
The following sequence illustrates the minimal steps required on a Ubuntu 22.04 gateway:

# 1. Generate a fresh private key
sudo wg genkey | sudo tee /etc/wireguard/new.key
# 2. Derive the corresponding public key
sudo cat /etc/wireguard/new.key | wg pubkey | sudo tee /etc/wireguard/new.pub
# 3. Preserve the current configuration
sudo cp /etc/wireguard/wg0.conf /etc/wireguard/wg0.conf.bak
# 4. Update the private key in the interface section
sudo sed -i 's|PrivateKey =.*|PrivateKey = '"$(cat /etc/wireguard/new.key)"'|' /etc/wireguard/wg0.conf
# 5. Restart the tunnel
sudo wg-quick down wg0
sudo wg-quick up wg0
Enter fullscreen mode Exit fullscreen mode

If the tunnel fails to reconnect, the original key is restored with:

sudo cp /etc/wireguard/wg0.conf.bak /etc/wireguard/wg0.conf
sudo wg-quick down wg0 && sudo wg-quick up wg0
Enter fullscreen mode Exit fullscreen mode

Because the public key changes, each peer must be notified and updated with the new public key via wg set or by exchanging the updated wg0.conf file. The rotation procedure is idempotent: running the steps multiple times does not introduce side effects, and the rollback path is always available through the backup file.


Firewall and NAT Considerations

WireGuard itself operates over UDP port 51820; however, explicit firewall rules are recommended to restrict inbound traffic and prevent accidental exposure.
On Ubuntu, the uncomplicated UFW utility can be leveraged:

sudo ufw allow 51820/udp
sudo ufw enable
Enter fullscreen mode Exit fullscreen mode

When both sites share identical internal subnets, NAT-over-VPN becomes necessary to avoid routing ambiguity. This is handled by adding PostUp and PostDown directives to the interface configuration:

[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <private_key>
PostUp   = iptables -t nat -A POSTROUTING -s 10.10.0.0/24 -o %i -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.10.0.0/24 -o eth0 -j MASQUERADE
Enter fullscreen mode Exit fullscreen mode

The PostUp rule ensures that traffic originating from the VPN subnet is masqueraded to the public interface (eth0), while PostDown cleanly removes the rule when the tunnel is torn down. This setup preserves packet integrity on the LAN side and eliminates the need for per-host configuration changes, keeping the “no additional firewall rules” principle intact for internal hosts.


Performance Monitoring and Alerting

Operational visibility is critical for a site-to-site VPN. WireGuard exposes real-time statistics via the wg command, which can be scraped by monitoring tools. A lightweight Prometheus exporter for WireGuard, such as wg-exporter, aggregates metrics like wireguard_peer_handshakes, wireguard_peer_bytes_received, and wireguard_peer_bytes_sent.
A typical Prometheus scrape configuration looks like:

scrape_configs:
  - job_name: wireguard
    static_configs:
      - targets: ['localhost:9798']
Enter fullscreen mode Exit fullscreen mode

On the alerting side, Grafana dashboards can display latency, packet loss, and handshake frequency. Simple alert rules are:

groups:
- name: wireguard
  rules:
  - alert: WireGuardDown
    expr: node_wg_interface_up{device="wg0"} == 0
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "WireGuard interface wg0 is down"
  - alert: HandshakeStale
    expr: time() - node_wg_peer_latest_handshake{device="wg0"} > 600
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "No handshake with peer in the last 10 minutes"
Enter fullscreen mode Exit fullscreen mode

These alerts trigger when the tunnel is inactive or when peers fail to perform a handshake within a defined window. Coupling the exporter with Grafana provides a single pane of glass for both health and performance, allowing administrators to react before user-visible degradation occurs.

Conclusion

This guide demonstrated step-by-step how to perform key generation, configuration, and route design for a WireGuard-based site-to-site VPN in an Ubuntu Server 22.04 LTS environment. Through correct subnet selection, public/private key management, and AllowedIPs definitions, a secure, low-latency connection can be established between two offices. The rollback procedure simplifies reverting configuration changes, while monitoring commands allow you to check the health of the tunnel in real-time.

Next step: If you have a high availability (HA) requirement in your network, try creating a "redundant tunnel" with two separate WireGuard gateways; this ensures that the connection continues uninterrupted in the event of a single endpoint failure.

Official Sources

Top comments (0)