Configure WireGuard site-to-site VPN connections with advanced routing and security

Intermediate 45 min Apr 18, 2026 142 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up secure network-to-network VPN tunnels using WireGuard with advanced routing, firewall rules, and monitoring for connecting multiple office locations or data centers.

Prerequisites

  • Two Linux servers with public IP addresses
  • Root or sudo access on both servers
  • Basic understanding of networking and IP routing
  • Firewall configuration knowledge

What this solves

WireGuard site-to-site VPN connections enable secure communication between entire networks rather than individual clients. This setup allows offices, data centers, or cloud environments to connect their internal networks securely over the internet, creating a unified private network infrastructure.

WireGuard site-to-site architecture and planning

Site-to-site VPN requires careful network planning to avoid IP conflicts and ensure proper routing. Each site needs a unique subnet, and both sites must route traffic destined for the remote network through their respective WireGuard interfaces.

Network planning example: Site A uses 192.168.1.0/24, Site B uses 192.168.2.0/24. The WireGuard tunnel uses 10.100.0.0/30 with Site A as 10.100.0.1 and Site B as 10.100.0.2.

This tutorial demonstrates connecting two sites with full network access between their internal subnets. Each site will act as a gateway for its local network, routing traffic through the WireGuard tunnel.

Step-by-step configuration

Install WireGuard on both sites

Install WireGuard and related networking tools on the gateway servers at both locations.

sudo apt update
sudo apt install -y wireguard wireguard-tools iptables-persistent
sudo dnf update -y
sudo dnf install -y wireguard-tools iptables-services
sudo systemctl enable --now iptables

Generate key pairs for both sites

Create public and private key pairs for each site. Run these commands on each gateway server to generate its own keys.

sudo mkdir -p /etc/wireguard
sudo wg genkey | sudo tee /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key
sudo chmod 600 /etc/wireguard/private.key
sudo chmod 644 /etc/wireguard/public.key

Display the keys for configuration exchange between sites:

echo "Private key:" && sudo cat /etc/wireguard/private.key
echo "Public key:" && cat /etc/wireguard/public.key

Configure primary site WireGuard server

Configure the primary site (Site A) with network 192.168.1.0/24. This server will listen for connections from the secondary site.

[Interface]
PrivateKey = SITE_A_PRIVATE_KEY_HERE
Address = 10.100.0.1/30
ListenPort = 51820
SaveConfig = false

Enable IP forwarding for this interface

PreUp = sysctl -w net.ipv4.ip_forward=1

Add route to Site B's network

PostUp = ip route add 192.168.2.0/24 dev wg0

Configure firewall rules for forwarding

PostUp = iptables -A FORWARD -i wg0 -o eth0 -j ACCEPT PostUp = iptables -A FORWARD -i eth0 -o wg0 -j ACCEPT PostUp = iptables -A FORWARD -i wg0 -o wg0 -j ACCEPT PostUp = iptables -t nat -A POSTROUTING -s 10.100.0.0/30 -o eth0 -j MASQUERADE

Cleanup rules on shutdown

PreDown = ip route del 192.168.2.0/24 dev wg0 2>/dev/null || true PreDown = iptables -D FORWARD -i wg0 -o eth0 -j ACCEPT 2>/dev/null || true PreDown = iptables -D FORWARD -i eth0 -o wg0 -j ACCEPT 2>/dev/null || true PreDown = iptables -D FORWARD -i wg0 -o wg0 -j ACCEPT 2>/dev/null || true PreDown = iptables -t nat -D POSTROUTING -s 10.100.0.0/30 -o eth0 -j MASQUERADE 2>/dev/null || true [Peer] PublicKey = SITE_B_PUBLIC_KEY_HERE AllowedIPs = 10.100.0.2/32, 192.168.2.0/24 PersistentKeepalive = 25

Configure secondary site WireGuard server

Configure the secondary site (Site B) with network 192.168.2.0/24. This server connects to the primary site.

[Interface]
PrivateKey = SITE_B_PRIVATE_KEY_HERE
Address = 10.100.0.2/30
SaveConfig = false

Enable IP forwarding for this interface

PreUp = sysctl -w net.ipv4.ip_forward=1

Add route to Site A's network

PostUp = ip route add 192.168.1.0/24 dev wg0

Configure firewall rules for forwarding

PostUp = iptables -A FORWARD -i wg0 -o eth0 -j ACCEPT PostUp = iptables -A FORWARD -i eth0 -o wg0 -j ACCEPT PostUp = iptables -A FORWARD -i wg0 -o wg0 -j ACCEPT PostUp = iptables -t nat -A POSTROUTING -s 10.100.0.0/30 -o eth0 -j MASQUERADE

Cleanup rules on shutdown

PreDown = ip route del 192.168.1.0/24 dev wg0 2>/dev/null || true PreDown = iptables -D FORWARD -i wg0 -o eth0 -j ACCEPT 2>/dev/null || true PreDown = iptables -D FORWARD -i eth0 -o wg0 -j ACCEPT 2>/dev/null || true PreDown = iptables -D FORWARD -i wg0 -o wg0 -j ACCEPT 2>/dev/null || true PreDown = iptables -t nat -D POSTROUTING -s 10.100.0.0/30 -o eth0 -j MASQUERADE 2>/dev/null || true [Peer] PublicKey = SITE_A_PUBLIC_KEY_HERE AllowedIPs = 10.100.0.1/32, 192.168.1.0/24 Endpoint = SITE_A_PUBLIC_IP:51820 PersistentKeepalive = 25

Enable permanent IP forwarding

Configure the kernel to forward IP packets between networks permanently. This setting persists across reboots.

net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1

Apply the changes immediately:

sudo sysctl -p /etc/sysctl.d/99-wireguard.conf

Set up advanced routing and firewall rules

Configure additional routing rules for better traffic control and security. Create a routing table specifically for WireGuard traffic.

echo "200 wireguard" | sudo tee -a /etc/iproute2/rt_tables

Add advanced routing rules to both sites:

#!/bin/bash

Advanced routing script for WireGuard site-to-site

Create custom routing table rules

ip rule add from 10.100.0.0/30 table wireguard priority 100 ip route add 10.100.0.0/30 dev wg0 table wireguard ip route add 192.168.1.0/24 dev wg0 table wireguard ip route add 192.168.2.0/24 dev wg0 table wireguard

Configure firewall rules for enhanced security

iptables -A INPUT -i wg0 -j ACCEPT iptables -A OUTPUT -o wg0 -j ACCEPT

Rate limiting for VPN traffic

iptables -A FORWARD -i wg0 -m limit --limit 1000/sec --limit-burst 2000 -j ACCEPT iptables -A FORWARD -i wg0 -j DROP

Log dropped packets for monitoring

iptables -A FORWARD -j LOG --log-prefix "WG-FORWARD-DROP: " --log-level 4
sudo chmod +x /etc/wireguard/routing.sh

Configure client network routing

Set up routing on client machines in each network to use the WireGuard gateway for remote network access. Add these routes on client machines or configure them via DHCP.

# On Site A clients (to reach Site B network)
sudo ip route add 192.168.2.0/24 via 192.168.1.1

On Site B clients (to reach Site A network)

sudo ip route add 192.168.1.0/24 via 192.168.2.1

To make these routes permanent, add them to network configuration:

network:
  version: 2
  ethernets:
    eth0:
      dhcp4: true
      routes:
        - to: 192.168.2.0/24
          via: 192.168.1.1

Start and enable WireGuard services

Start the WireGuard interface on both sites and enable automatic startup.

sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
sudo systemctl status wg-quick@wg0

Configure firewall ports

Open the required ports in your firewall for WireGuard communication.

sudo ufw allow 51820/udp
sudo ufw allow from 192.168.1.0/24 to 192.168.2.0/24
sudo ufw allow from 192.168.2.0/24 to 192.168.1.0/24
sudo ufw reload
sudo firewall-cmd --permanent --add-port=51820/udp
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" destination address="192.168.2.0/24" accept'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.2.0/24" destination address="192.168.1.0/24" accept'
sudo firewall-cmd --reload

Monitor and troubleshoot site-to-site connections

Set up connection monitoring

Create monitoring scripts to track tunnel health and automatically restart failed connections.

#!/bin/bash

WireGuard site-to-site monitoring script

LOGFILE="/var/log/wireguard-monitor.log" REMOTE_IP="10.100.0.2" # Change based on site REMOTE_NETWORK="192.168.2.1" # Gateway of remote network

Function to log messages

log_message() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> $LOGFILE }

Check tunnel connectivity

ping -c 3 -W 5 $REMOTE_IP > /dev/null 2>&1 if [ $? -ne 0 ]; then log_message "Tunnel connectivity failed, checking interface" # Check if WireGuard interface is up if ! ip link show wg0 > /dev/null 2>&1; then log_message "WireGuard interface down, restarting" systemctl restart wg-quick@wg0 sleep 10 fi # Test remote network connectivity ping -c 1 -W 5 $REMOTE_NETWORK > /dev/null 2>&1 if [ $? -eq 0 ]; then log_message "Remote network reachable" else log_message "Remote network unreachable" fi else log_message "Tunnel connectivity OK" fi

Log connection statistics

wg show wg0 >> $LOGFILE
sudo chmod +x /etc/wireguard/monitor.sh

Set up automated monitoring

Configure a systemd timer to run the monitoring script every 5 minutes.

[Unit]
Description=WireGuard Site-to-Site Monitor
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/etc/wireguard/monitor.sh
User=root
[Unit]
Description=Run WireGuard Monitor every 5 minutes
Requires=wireguard-monitor.service

[Timer]
OnCalendar=*:0/5
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now wireguard-monitor.timer
sudo systemctl status wireguard-monitor.timer

Configure traffic analysis and logging

Set up detailed logging for traffic analysis and troubleshooting.

# WireGuard logging configuration
:msg, contains, "WG-" /var/log/wireguard.log
& stop
sudo systemctl restart rsyslog
sudo logrotate -d /etc/logrotate.d/wireguard
/var/log/wireguard.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 644 syslog syslog
    postrotate
        systemctl reload rsyslog
    endscript
}

Verify your setup

Test the site-to-site connection from both locations to ensure full network connectivity.

# Check WireGuard interface status
sudo wg show
ip addr show wg0

Test tunnel connectivity between gateways

ping -c 4 10.100.0.2 # From Site A to Site B ping -c 4 10.100.0.1 # From Site B to Site A

Test network-to-network connectivity

ping -c 4 192.168.2.1 # From Site A to Site B gateway ping -c 4 192.168.1.1 # From Site B to Site A gateway

Check routing table

ip route show table wireguard

Monitor real-time traffic

sudo tcpdump -i wg0 -n

Check firewall rules

sudo iptables -L FORWARD -n -v

Verify monitoring logs

sudo tail -f /var/log/wireguard-monitor.log
Performance test: Use tools like iperf3 to test bandwidth between sites. Install on both networks and run iperf3 -s on one side and iperf3 -c remote_ip on the other.

Common issues

Symptom Cause Fix
Tunnel establishes but no network traffic IP forwarding disabled or missing routes sudo sysctl -w net.ipv4.ip_forward=1 and check routing table
Connection fails after firewall restart Iptables rules not persistent Save rules with sudo iptables-save > /etc/iptables/rules.v4
One-way connectivity only Missing return route on client networks Add static routes on client machines or DHCP server
High latency or packet loss MTU size issues Set MTU to 1420: ip link set mtu 1420 dev wg0
Frequent connection drops NAT timeout or keepalive issues Reduce PersistentKeepalive to 15 seconds
DNS resolution fails across sites DNS server not accessible from remote network Configure DNS forwarding or add remote DNS servers

Next steps

Running this in production?

Want this handled for you? Setting up site-to-site VPN once is straightforward. Keeping it monitored, maintained, and secure across multiple locations with proper failover is the harder part. See how we run infrastructure like this for European teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle private cloud infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.