Deploy a scalable WireGuard mesh network across multiple sites with automatic routing, failover mechanisms, and centralized management for high-availability site-to-site connectivity.
Prerequisites
- Multiple servers with public IP addresses
- Root access on all mesh nodes
- Basic understanding of networking and routing
- Firewall configuration knowledge
What this solves
Traditional site-to-site VPN setups create single points of failure with hub-and-spoke architectures. This tutorial implements a WireGuard mesh network where multiple sites can communicate directly with automatic routing and failover. You get encrypted inter-site connectivity that automatically routes around failed nodes, perfect for distributed infrastructure, branch offices, or multi-datacenter deployments.
Step-by-step installation
Install WireGuard on all nodes
Install WireGuard on each server that will participate in the mesh network. These will be your site gateway nodes.
sudo apt update
sudo apt install -y wireguard iptables-persistent bird2
Enable IP forwarding system-wide
Configure each node to forward packets between network interfaces for mesh routing.
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.core.netdev_max_backlog = 2000
net.ipv4.tcp_congestion_control = bbr
sudo sysctl --system
Generate key pairs for each site
Create unique cryptographic keys for each mesh node. Store these securely as they authenticate your sites.
sudo mkdir -p /etc/wireguard/keys
sudo chmod 700 /etc/wireguard/keys
sudo wg genkey | sudo tee /etc/wireguard/keys/private.key | wg pubkey | sudo tee /etc/wireguard/keys/public.key
sudo chmod 600 /etc/wireguard/keys/private.key
sudo chmod 644 /etc/wireguard/keys/public.key
Plan your mesh topology and IP allocation
Design your network addressing scheme. Use a dedicated subnet for the mesh overlay and plan your site networks.
# Mesh Network Plan
Overlay Network: 10.100.0.0/16
Site A (London): Gateway 10.100.1.1/24, LAN 192.168.1.0/24
Site B (Berlin): Gateway 10.100.2.1/24, LAN 192.168.2.0/24
Site C (Paris): Gateway 10.100.3.1/24, LAN 192.168.3.0/24
Site D (Madrid): Gateway 10.100.4.1/24, LAN 192.168.4.0/24
Configure WireGuard mesh interface for Site A
Create the WireGuard configuration for the first site. This node will connect to all other sites directly.
[Interface]
PrivateKey = $(sudo cat /etc/wireguard/keys/private.key)
Address = 10.100.1.1/24
ListenPort = 51820
PostUp = iptables -t nat -A POSTROUTING -s 10.100.0.0/16 -o eth0 -j MASQUERADE
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -s 10.100.0.0/16 -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT
Site B (Berlin)
[Peer]
PublicKey = SITE_B_PUBLIC_KEY_HERE
Endpoint = 203.0.113.20:51820
AllowedIPs = 10.100.2.0/24, 192.168.2.0/24
PersistentKeepalive = 25
Site C (Paris)
[Peer]
PublicKey = SITE_C_PUBLIC_KEY_HERE
Endpoint = 203.0.113.30:51820
AllowedIPs = 10.100.3.0/24, 192.168.3.0/24
PersistentKeepalive = 25
Site D (Madrid)
[Peer]
PublicKey = SITE_D_PUBLIC_KEY_HERE
Endpoint = 203.0.113.40:51820
AllowedIPs = 10.100.4.0/24, 192.168.4.0/24
PersistentKeepalive = 25
Configure dynamic routing with BIRD
Set up BIRD routing daemon for automatic route discovery and failover between mesh nodes.
log syslog all;
router id 10.100.1.1;
protocol kernel {
learn;
persist;
scan time 20;
import all;
export all;
}
protocol device {
scan time 10;
}
protocol direct {
interface "wg0", "eth0";
}
protocol ospf v2 mesh {
tick 2;
rfc1583compat yes;
area 0.0.0.0 {
interface "wg0" {
cost 10;
hello 5;
dead 20;
type pointopoint;
};
interface "eth0" {
cost 100;
hello 10;
dead 40;
stub yes;
};
};
}
Create mesh management scripts
Build automation scripts for mesh operations, health monitoring, and failover detection.
#!/bin/bash
WireGuard Mesh Health Monitor
MESH_CONFIG="/etc/wireguard/wg0.conf"
LOG_FILE="/var/log/wireguard-mesh.log"
EMAIL_ALERT="admin@example.com"
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
}
check_peer_connectivity() {
local peer_ip="$1"
local peer_name="$2"
if ping -c 3 -W 2 "$peer_ip" >/dev/null 2>&1; then
log_message "HEALTHY: $peer_name ($peer_ip) is reachable"
return 0
else
log_message "ALERT: $peer_name ($peer_ip) is unreachable"
return 1
fi
}
check_routing_table() {
local expected_routes=$(grep -c "AllowedIPs" "$MESH_CONFIG")
local active_routes=$(ip route | grep -c "dev wg0")
if [ "$active_routes" -ge "$expected_routes" ]; then
log_message "ROUTING: $active_routes routes active (expected >= $expected_routes)"
else
log_message "ALERT: Only $active_routes routes active (expected >= $expected_routes)"
systemctl restart bird
fi
}
Monitor peer connectivity
check_peer_connectivity "10.100.2.1" "Berlin"
check_peer_connectivity "10.100.3.1" "Paris"
check_peer_connectivity "10.100.4.1" "Madrid"
Verify routing
check_routing_table
Check WireGuard interface status
if ! wg show wg0 >/dev/null 2>&1; then
log_message "ALERT: WireGuard interface wg0 is down"
systemctl restart wg-quick@wg0
fi
sudo chmod 755 /usr/local/bin/wg-mesh-monitor.sh
Configure automatic failover script
Create a failover mechanism that reroutes traffic when primary paths fail.
#!/bin/bash
WireGuard Mesh Failover Handler
BIRD_SOCKET="/var/run/bird/bird.ctl"
LOG_FILE="/var/log/wireguard-mesh.log"
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') FAILOVER: $1" >> "$LOG_FILE"
}
trigger_route_update() {
local failed_peer="$1"
log_message "Updating routes due to $failed_peer failure"
# Recalculate OSPF routes
echo "configure\nprotocol ospf mesh { disabled; }\nprotocol ospf mesh { disabled no; }\nexit" | birdc
# Wait for convergence
sleep 10
# Verify new routes
ip route show table main | grep "dev wg0" | while read route; do
log_message "Active route: $route"
done
}
handle_peer_failure() {
local peer_ip="$1"
local peer_name="$2"
# Check if peer is consistently down
local failures=0
for i in {1..3}; do
if ! ping -c 1 -W 2 "$peer_ip" >/dev/null 2>&1; then
((failures++))
fi
sleep 2
done
if [ "$failures" -eq 3 ]; then
log_message "Peer $peer_name ($peer_ip) confirmed down, initiating failover"
trigger_route_update "$peer_name"
# Send alert
echo "WireGuard mesh peer $peer_name failed. Automatic failover activated." |
mail -s "Mesh Network Alert: $peer_name Down" admin@example.com
fi
}
Check each peer and trigger failover if needed
handle_peer_failure "10.100.2.1" "Berlin"
handle_peer_failure "10.100.3.1" "Paris"
handle_peer_failure "10.100.4.1" "Madrid"
sudo chmod 755 /usr/local/bin/wg-mesh-failover.sh
Set up automated monitoring with systemd timers
Configure regular health checks and automatic failover detection using systemd timers.
[Unit]
Description=WireGuard Mesh Network Monitor
After=wg-quick@wg0.service bird.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/wg-mesh-monitor.sh
User=root
StandardOutput=journal
StandardError=journal
[Unit]
Description=Run WireGuard Mesh Monitor every 2 minutes
Requires=wg-mesh-monitor.service
[Timer]
OnCalendar=::00/120
Persistent=true
[Install]
WantedBy=timers.target
[Unit]
Description=WireGuard Mesh Failover Handler
After=wg-quick@wg0.service bird.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/wg-mesh-failover.sh
User=root
StandardOutput=journal
StandardError=journal
[Unit]
Description=Run WireGuard Mesh Failover Check every 5 minutes
Requires=wg-mesh-failover.service
[Timer]
OnCalendar=::00/300
Persistent=true
[Install]
WantedBy=timers.target
Configure firewall rules for mesh traffic
Open the necessary ports and configure packet filtering for secure mesh communication.
# Allow WireGuard traffic
sudo iptables -I INPUT -p udp --dport 51820 -j ACCEPT
Allow mesh subnet traffic
sudo iptables -I INPUT -s 10.100.0.0/16 -j ACCEPT
sudo iptables -I FORWARD -s 10.100.0.0/16 -j ACCEPT
sudo iptables -I FORWARD -d 10.100.0.0/16 -j ACCEPT
Allow OSPF protocol
sudo iptables -I INPUT -p ospf -j ACCEPT
sudo iptables -I OUTPUT -p ospf -j ACCEPT
Save rules
sudo netfilter-persistent save
Start and enable all services
Activate the WireGuard interface, routing daemon, and monitoring services.
# Enable WireGuard interface
sudo systemctl enable --now wg-quick@wg0
Enable BIRD routing daemon
sudo systemctl enable --now bird
Enable monitoring timers
sudo systemctl enable --now wg-mesh-monitor.timer
sudo systemctl enable --now wg-mesh-failover.timer
Check service status
sudo systemctl status wg-quick@wg0 bird wg-mesh-monitor.timer
Replicate configuration for remaining sites
Deploy similar configurations to Sites B, C, and D with appropriate IP addresses and peer configurations.
[Interface]
PrivateKey = SITE_B_PRIVATE_KEY
Address = 10.100.2.1/24
ListenPort = 51820
PostUp = iptables -t nat -A POSTROUTING -s 10.100.0.0/16 -o eth0 -j MASQUERADE
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -s 10.100.0.0/16 -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT
Site A (London)
[Peer]
PublicKey = SITE_A_PUBLIC_KEY
Endpoint = 203.0.113.10:51820
AllowedIPs = 10.100.1.0/24, 192.168.1.0/24
PersistentKeepalive = 25
Site C (Paris)
[Peer]
PublicKey = SITE_C_PUBLIC_KEY
Endpoint = 203.0.113.30:51820
AllowedIPs = 10.100.3.0/24, 192.168.3.0/24
PersistentKeepalive = 25
Site D (Madrid)
[Peer]
PublicKey = SITE_D_PUBLIC_KEY
Endpoint = 203.0.113.40:51820
AllowedIPs = 10.100.4.0/24, 192.168.4.0/24
PersistentKeepalive = 25
/etc/bird/bird.conf to match each site's gateway IP (10.100.2.1 for Site B, 10.100.3.1 for Site C, etc.)Verify your setup
Test mesh connectivity and verify automatic routing between all sites.
# Check WireGuard interface status
sudo wg show wg0
Verify all peers are connected
sudo wg show wg0 allowed-ips
Test connectivity to all mesh nodes
ping -c 3 10.100.2.1 # Site B
ping -c 3 10.100.3.1 # Site C
ping -c 3 10.100.4.1 # Site D
Check OSPF routing table
sudo birdc show route
Verify site-to-site connectivity
ping -c 3 192.168.2.10 # Test host at Site B
ping -c 3 192.168.3.10 # Test host at Site C
Check monitoring logs
sudo journalctl -u wg-mesh-monitor.service --since "1 hour ago"
tail -f /var/log/wireguard-mesh.log
Test failover (disable one peer temporarily)
sudo wg-quick down wg0
sudo wg-quick up wg0
Site-to-site connectivity testing
Perform comprehensive testing to verify mesh functionality and failover behavior.
#!/bin/bash
Comprehensive mesh connectivity test
SITES=("10.100.1.1:London" "10.100.2.1:Berlin" "10.100.3.1:Paris" "10.100.4.1:Madrid")
LAN_SUBNETS=("192.168.1.0/24" "192.168.2.0/24" "192.168.3.0/24" "192.168.4.0/24")
echo "=== WireGuard Mesh Connectivity Test ==="
echo "Started: $(date)"
echo
Test mesh node connectivity
echo "Testing mesh node connectivity:"
for site in "${SITES[@]}"; do
ip="${site%%:*}"
name="${site##*:}"
if ping -c 3 -W 2 "$ip" >/dev/null 2>&1; then
echo "✓ $name ($ip) - REACHABLE"
else
echo "✗ $name ($ip) - UNREACHABLE"
fi
done
echo
Test cross-site routing
echo "Testing cross-site LAN routing:"
for subnet in "${LAN_SUBNETS[@]}"; do
gateway="${subnet%.*}.1"
if ping -c 2 -W 2 "$gateway" >/dev/null 2>&1; then
echo "✓ $subnet via $gateway - ROUTABLE"
else
echo "✗ $subnet via $gateway - NOT ROUTABLE"
fi
done
echo
Check routing table
echo "Active WireGuard routes:"
ip route | grep "dev wg0" | while read route; do
echo " $route"
done
echo
Test bandwidth between sites
echo "Network performance test (if iperf3 available):"
if command -v iperf3 >/dev/null 2>&1; then
for site in "${SITES[@]}"; do
ip="${site%%:*}"
name="${site##*:}"
if [ "$ip" != "$(hostname -I | awk '{print $1}')" ]; then
echo "Testing bandwidth to $name ($ip):"
timeout 10 iperf3 -c "$ip" -t 5 2>/dev/null || echo " Bandwidth test failed or iperf3 server not running"
fi
done
else
echo " iperf3 not installed, skipping bandwidth tests"
fi
echo "Test completed: $(date)"
sudo chmod 755 /usr/local/bin/mesh-connectivity-test.sh
sudo /usr/local/bin/mesh-connectivity-test.sh
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Peers show as connected but can't ping | Firewall blocking mesh traffic | sudo iptables -I INPUT -s 10.100.0.0/16 -j ACCEPT |
| Some sites unreachable after failover | BIRD routing convergence delay | Check sudo birdc show route and wait 30 seconds |
| Handshake fails between peers | Incorrect public keys in config | Verify public keys with sudo wg show wg0 peers |
| Monitoring scripts not running | Systemd timers not enabled | sudo systemctl enable --now wg-mesh-monitor.timer |
| High CPU usage from BIRD | Too frequent OSPF hello intervals | Increase hello timer to 10 seconds in BIRD config |
| NAT not working for site LANs | Missing MASQUERADE rules | sudo iptables -t nat -A POSTROUTING -s 10.100.0.0/16 -o eth0 -j MASQUERADE |
Monitoring and maintenance
Set up comprehensive monitoring for your mesh network with automated alerts and performance tracking.
#!/bin/bash
Generate mesh network health report
REPORT_FILE="/tmp/mesh-health-$(date +%Y%m%d-%H%M).txt"
echo "WireGuard Mesh Network Health Report" > "$REPORT_FILE"
echo "Generated: $(date)" >> "$REPORT_FILE"
echo "====================================" >> "$REPORT_FILE"
echo >> "$REPORT_FILE"
Interface status
echo "WireGuard Interface Status:" >> "$REPORT_FILE"
sudo wg show wg0 >> "$REPORT_FILE"
echo >> "$REPORT_FILE"
Peer statistics
echo "Peer Connection Statistics:" >> "$REPORT_FILE"
sudo wg show wg0 transfer >> "$REPORT_FILE"
echo >> "$REPORT_FILE"
Routing table
echo "Active Routes:" >> "$REPORT_FILE"
ip route | grep "dev wg0" >> "$REPORT_FILE"
echo >> "$REPORT_FILE"
BIRD protocol status
echo "OSPF Protocol Status:" >> "$REPORT_FILE"
sudo birdc show protocols >> "$REPORT_FILE"
echo >> "$REPORT_FILE"
System resources
echo "System Resource Usage:" >> "$REPORT_FILE"
echo "CPU: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | sed 's/%us,//')" >> "$REPORT_FILE"
echo "Memory: $(free -m | awk 'NR==2{printf "%.1f%%", $3*100/$2}')" >> "$REPORT_FILE"
echo "Disk: $(df -h / | awk 'NR==2{print $5}')" >> "$REPORT_FILE"
echo >> "$REPORT_FILE"
Recent log entries
echo "Recent Mesh Events:" >> "$REPORT_FILE"
tail -20 /var/log/wireguard-mesh.log >> "$REPORT_FILE"
echo "Report saved to: $REPORT_FILE"
Email report if configured
if command -v mail >/dev/null 2>&1; then
mail -s "WireGuard Mesh Health Report - $(hostname)" admin@example.com < "$REPORT_FILE"
fi
sudo chmod 755 /usr/local/bin/mesh-health-report.sh
Run weekly health reports
echo "0 8 1 /usr/local/bin/mesh-health-report.sh" | sudo crontab -
Next steps
- Integrate WireGuard VPN server with LDAP authentication for enterprise user management
- Configure WireGuard site-to-site VPN connections with advanced routing and security
- Implement WireGuard mesh monitoring with Prometheus and Grafana
- Configure WireGuard mesh load balancing with HAProxy for high availability
- Set up WireGuard mesh backup routing with BGP for enterprise networks
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Global variables
SITE_ID=""
MESH_PORT="51820"
OVERLAY_BASE="10.100"
WIREGUARD_DIR="/etc/wireguard"
KEYS_DIR="$WIREGUARD_DIR/keys"
# Cleanup function
cleanup() {
echo -e "${RED}Installation failed. Cleaning up...${NC}" >&2
systemctl stop wg-quick@wg0 2>/dev/null || true
systemctl stop bird 2>/dev/null || true
rm -f "$WIREGUARD_DIR/wg0.conf" 2>/dev/null || true
rm -rf "$KEYS_DIR" 2>/dev/null || true
}
trap cleanup ERR
usage() {
echo "Usage: $0 <site_id> [listen_port]"
echo " site_id: Unique site identifier (1-254)"
echo " listen_port: WireGuard listen port (default: 51820)"
echo ""
echo "Example: $0 1 51820"
exit 1
}
log() {
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}"
}
warn() {
echo -e "${YELLOW}[WARNING] $1${NC}"
}
error() {
echo -e "${RED}[ERROR] $1${NC}" >&2
exit 1
}
# Check prerequisites
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root"
fi
if [[ $# -lt 1 || $# -gt 2 ]]; then
usage
fi
SITE_ID="$1"
if [[ $# -eq 2 ]]; then
MESH_PORT="$2"
fi
# Validate site ID
if ! [[ "$SITE_ID" =~ ^[1-9][0-9]*$ ]] || [[ $SITE_ID -gt 254 ]]; then
error "Site ID must be a number between 1-254"
fi
# Detect OS and package manager
if [[ ! -f /etc/os-release ]]; then
error "Cannot detect OS. /etc/os-release not found"
fi
source /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_INSTALL="apt install -y"
BIRD_SERVICE="bird"
SYSCTL_RELOAD="systemctl restart systemd-sysctl"
;;
almalinux|rocky|centos|rhel|ol)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
BIRD_SERVICE="bird"
SYSCTL_RELOAD="sysctl --system"
;;
fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
BIRD_SERVICE="bird"
SYSCTL_RELOAD="sysctl --system"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
BIRD_SERVICE="bird"
SYSCTL_RELOAD="sysctl --system"
;;
*)
error "Unsupported distribution: $ID"
;;
esac
log "[1/8] Updating system packages..."
$PKG_UPDATE
log "[2/8] Installing WireGuard and dependencies..."
case "$PKG_MGR" in
apt)
$PKG_INSTALL wireguard iptables-persistent bird2 curl
;;
dnf|yum)
$PKG_INSTALL epel-release 2>/dev/null || true
$PKG_INSTALL wireguard-tools iptables-services bird curl
systemctl enable iptables
;;
esac
log "[3/8] Configuring kernel parameters..."
cat > /etc/sysctl.d/99-wireguard.conf << EOF
# WireGuard mesh network optimizations
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.core.netdev_max_backlog = 2000
net.ipv4.tcp_congestion_control = bbr
EOF
$SYSCTL_RELOAD
log "[4/8] Generating WireGuard keys..."
mkdir -p "$KEYS_DIR"
chmod 700 "$KEYS_DIR"
wg genkey | tee "$KEYS_DIR/private.key" | wg pubkey > "$KEYS_DIR/public.key"
chmod 600 "$KEYS_DIR/private.key"
chmod 644 "$KEYS_DIR/public.key"
PRIVATE_KEY=$(cat "$KEYS_DIR/private.key")
PUBLIC_KEY=$(cat "$KEYS_DIR/public.key")
log "[5/8] Creating WireGuard configuration..."
GATEWAY_IP="$OVERLAY_BASE.$SITE_ID.1"
cat > "$WIREGUARD_DIR/wg0.conf" << EOF
[Interface]
PrivateKey = $PRIVATE_KEY
Address = $GATEWAY_IP/24
ListenPort = $MESH_PORT
PostUp = iptables -t nat -A POSTROUTING -s $OVERLAY_BASE.0.0/16 -o eth0 -j MASQUERADE
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -s $OVERLAY_BASE.0.0/16 -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT
# Add peer configurations manually using:
# [Peer]
# PublicKey = PEER_PUBLIC_KEY
# Endpoint = PEER_EXTERNAL_IP:51820
# AllowedIPs = $OVERLAY_BASE.X.0/24, 192.168.X.0/24
# PersistentKeepalive = 25
EOF
chmod 600 "$WIREGUARD_DIR/wg0.conf"
log "[6/8] Configuring BIRD routing daemon..."
cat > /etc/bird.conf << EOF
log syslog all;
router id $GATEWAY_IP;
protocol kernel {
learn;
persist;
scan time 20;
import all;
export all;
}
protocol device {
scan time 10;
}
protocol direct {
interface "wg0", "eth0";
}
protocol ospf v2 mesh {
tick 2;
rfc1583compat yes;
area 0.0.0.0 {
interface "wg0" {
cost 10;
hello 5;
dead 20;
type pointopoint;
};
interface "eth0" {
cost 100;
hello 10;
dead 40;
stub yes;
};
};
}
EOF
log "[7/8] Creating mesh management script..."
cat > /usr/local/bin/wg-mesh-monitor << 'EOF'
#!/bin/bash
MESH_CONFIG="/etc/wireguard/wg0.conf"
LOG_FILE="/var/log/wireguard-mesh.log"
check_peers() {
wg show wg0 latest-handshakes | while read peer timestamp; do
if [[ $(($(date +%s) - timestamp)) -gt 300 ]]; then
echo "$(date): Peer $peer is stale (last handshake: $timestamp)" >> "$LOG_FILE"
fi
done
}
if systemctl is-active --quiet wg-quick@wg0; then
check_peers
else
echo "$(date): WireGuard interface is down, restarting..." >> "$LOG_FILE"
systemctl restart wg-quick@wg0
fi
EOF
chmod 755 /usr/local/bin/wg-mesh-monitor
# Create cron job for monitoring
echo "*/5 * * * * root /usr/local/bin/wg-mesh-monitor" > /etc/cron.d/wireguard-mesh
log "[8/8] Starting and enabling services..."
systemctl enable wg-quick@wg0
systemctl enable "$BIRD_SERVICE"
systemctl start wg-quick@wg0
systemctl start "$BIRD_SERVICE"
# Configure firewall
if command -v ufw >/dev/null; then
ufw allow "$MESH_PORT"/udp
elif command -v firewall-cmd >/dev/null; then
firewall-cmd --permanent --add-port="$MESH_PORT"/udp
firewall-cmd --reload
fi
log "WireGuard mesh node installation complete!"
echo ""
echo -e "${BLUE}=== Configuration Summary ===${NC}"
echo "Site ID: $SITE_ID"
echo "Gateway IP: $GATEWAY_IP/24"
echo "Listen Port: $MESH_PORT"
echo "Public Key: $PUBLIC_KEY"
echo ""
echo -e "${YELLOW}Next steps:${NC}"
echo "1. Exchange public keys with other sites"
echo "2. Add peer configurations to $WIREGUARD_DIR/wg0.conf"
echo "3. Restart WireGuard: systemctl restart wg-quick@wg0"
echo "4. Check status: wg show"
echo "5. Monitor logs: tail -f /var/log/wireguard-mesh.log"
Review the script before running. Execute with: bash install.sh