Wireguard on Openwrt - an obscurely specific HowTo
Posted: Wed Feb 04, 2026 1:37 am
WireGuard VPN Tunnel: OpenWrt Router to Debian Trixie Server
Technical reference for establishing a full-tunnel VPN exit using an OpenWrt router as client and a Debian Trixie VPS as server.
Overview
• Router: OpenWrt (tested on 25.12.0-rc4, ramips/mt7621)
• Server: Debian 13 (Trixie) VPS
• Tunnel network: 10.0.100.0/24
• Router tunnel IP: 10.0.100.2/32
• Server tunnel IP: 10.0.100.1/24
• WireGuard port: 51820/udp
Server Setup (Trixie)
Install WireGuard
Enable IP Forwarding
Verify:
Generate Server Keys
Generate Router Keys
On the router (or any machine with wg installed):
You now have four values:
• <SERVER_PRIVATE_KEY> - used only in server's wg0.conf
• <SERVER_PUBLIC_KEY> - used in router's peer config
• <ROUTER_PRIVATE_KEY> - used only in router's interface config
• <ROUTER_PUBLIC_KEY> - used in server's peer config
Create Server Configuration
Replace <SERVER_PRIVATE_KEY> and <ROUTER_PUBLIC_KEY> with actual values:
Note: Adjust -o eth0 if the server's public interface has a different name.
Adding Multiple Peers
Each device connecting to the server needs its own keypair and tunnel IP. Generate keys on each device as above, then add a [Peer] block for each in the server's wg0.conf:
Assign each device a unique IP within the 10.0.100.0/24 range. All peers can be active simultaneously without conflict.
To add a peer without restarting the tunnel (preserving existing connections):
Verify all peers are registered:
Configure UFW Firewall
Note: If using nftables or iptables directly instead of UFW, the equivalent rules are:
Start WireGuard
Router Setup (OpenWrt)
Configure WireGuard Interface via UCI
Replace placeholders with actual values:
Configure Firewall
Add the WireGuard interface to the wan zone for masquerading and forwarding:
Bring Up Interface
VPN Toggle Script
Create /root/vpn-toggle.sh:
Critical Notes
Endpoint Route
When replacing the default route to go through the WireGuard tunnel, the router must still be able to reach the VPN server's public IP via the normal WAN gateway. Without this, encapsulated packets have nowhere to go:
The toggle script handles this automatically.
Testing
From router:
From LAN client:
Verify Tunnel Health
Look for:
• endpoint: showing server IP and port
• latest handshake: within last 2 minutes
• transfer: showing bytes in both directions
Troubleshooting
No handshake
• Check server firewall allows 51820/udp
• Check endpoint is set: wg show wgserver
• Manually set endpoint if missing (see bug below)
Handshake but no traffic
• Check server IP forwarding: cat /proc/sys/net/ipv4/ip_forward
• Check server NAT rule: sudo iptables -t nat -L POSTROUTING -v
• Check UFW forwarding rules
Traffic sent but nothing received
• Missing endpoint route - packets can't reach server
• Server not masquerading - check iptables rule
Preserve Across Sysupgrade
Add to /etc/sysupgrade.conf:
Technical reference for establishing a full-tunnel VPN exit using an OpenWrt router as client and a Debian Trixie VPS as server.
Overview
• Router: OpenWrt (tested on 25.12.0-rc4, ramips/mt7621)
• Server: Debian 13 (Trixie) VPS
• Tunnel network: 10.0.100.0/24
• Router tunnel IP: 10.0.100.2/32
• Server tunnel IP: 10.0.100.1/24
• WireGuard port: 51820/udp
Server Setup (Trixie)
Install WireGuard
Code: Select all
sudo apt update && sudo apt install wireguardCode: Select all
echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.conf
sudo /sbin/sysctl -pCode: Select all
cat /proc/sys/net/ipv4/ip_forward
# Should return: 1Code: Select all
wg genkey | tee /tmp/server_private | wg pubkey > /tmp/server_public
cat /tmp/server_private # <SERVER_PRIVATE_KEY> - keep secret
cat /tmp/server_public # <SERVER_PUBLIC_KEY> - give to router configOn the router (or any machine with wg installed):
Code: Select all
wg genkey | tee /tmp/router_private | wg pubkey > /tmp/router_public
cat /tmp/router_private # <ROUTER_PRIVATE_KEY> - keep secret
cat /tmp/router_public # <ROUTER_PUBLIC_KEY> - give to server config• <SERVER_PRIVATE_KEY> - used only in server's wg0.conf
• <SERVER_PUBLIC_KEY> - used in router's peer config
• <ROUTER_PRIVATE_KEY> - used only in router's interface config
• <ROUTER_PUBLIC_KEY> - used in server's peer config
Create Server Configuration
Replace <SERVER_PRIVATE_KEY> and <ROUTER_PUBLIC_KEY> with actual values:
Code: Select all
sudo tee /etc/wireguard/wg0.conf << 'EOF'
[Interface]
Address = 10.0.100.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>
PostUp = iptables -t nat -A POSTROUTING -s 10.0.100.0/24 -o eth0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.0.100.0/24 -o eth0 -j MASQUERADE
[Peer]
PublicKey = <ROUTER_PUBLIC_KEY>
AllowedIPs = 10.0.100.2/32
EOFAdding Multiple Peers
Each device connecting to the server needs its own keypair and tunnel IP. Generate keys on each device as above, then add a [Peer] block for each in the server's wg0.conf:
Code: Select all
[Peer]
# Second router or device
PublicKey = <SECOND_DEVICE_PUBLIC_KEY>
AllowedIPs = 10.0.100.3/32
[Peer]
# Phone, laptop, etc.
PublicKey = <THIRD_DEVICE_PUBLIC_KEY>
AllowedIPs = 10.0.100.4/32To add a peer without restarting the tunnel (preserving existing connections):
Code: Select all
sudo bash -c 'wg syncconf wg0 <(wg-quick strip wg0)'Code: Select all
sudo wg showCode: Select all
sudo ufw allow 51820/udp
sudo ufw route allow in on wg0 out on eth0
sudo ufw route allow in on eth0 out on wg0Code: Select all
# Allow WireGuard port
iptables -A INPUT -p udp --dport 51820 -j ACCEPT
# Allow forwarding between wg0 and eth0
iptables -A FORWARD -i wg0 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPTCode: Select all
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
sudo wg showConfigure WireGuard Interface via UCI
Replace placeholders with actual values:
Code: Select all
# Create interface
uci set network.wgserver=interface
uci set network.wgserver.proto='wireguard'
uci set network.wgserver.private_key='<ROUTER_PRIVATE_KEY>'
uci set network.wgserver.addresses='10.0.100.2/32'
# Add peer (the server)
uci add network wireguard_wgserver
uci set network.@wireguard_wgserver[-1].public_key='<SERVER_PUBLIC_KEY>'
uci set network.@wireguard_wgserver[-1].endpoint='<SERVER_IP>:51820'
uci set network.@wireguard_wgserver[-1].allowed_ips='0.0.0.0/0'
uci set network.@wireguard_wgserver[-1].persistent_keepalive='25'
uci commit networkAdd the WireGuard interface to the wan zone for masquerading and forwarding:
Code: Select all
uci add_list firewall.@zone[1].network='wgserver'
uci commit firewall
/etc/init.d/firewall restartCode: Select all
ifdown wgserver && ifup wgserver
wg show wgserverCreate /root/vpn-toggle.sh:
Code: Select all
#!/bin/sh
WG_INTERFACE="wgserver"
WG_ENDPOINT="<SERVER_IP>"
WG_PUBKEY="<SERVER_PUBLIC_KEY>"
WAN_GATEWAY="192.168.1.254" # Adjust to your upstream gateway
case "$1" in
on)
# Ensure endpoint route exists (critical!)
ip route add $WG_ENDPOINT via $WAN_GATEWAY dev wan 2>/dev/null
# Set endpoint if missing (workaround for netifd bug)
wg set $WG_INTERFACE peer $WG_PUBKEY endpoint $WG_ENDPOINT:51820 2>/dev/null
ip route replace default dev $WG_INTERFACE
logger -t vpn-toggle "VPN enabled"
;;
off)
ip route replace default via $WAN_GATEWAY dev wan
logger -t vpn-toggle "VPN disabled"
;;
status)
if ip route | grep -q "default dev $WG_INTERFACE"; then
echo "VPN: active"
curl -s ipinfo.io | grep -E '"(ip|city|country)"'
else
echo "VPN: inactive"
fi
;;
*)
echo "Usage: $0 {on|off|status}"
;;
esacCode: Select all
chmod +x /root/vpn-toggle.shEndpoint Route
When replacing the default route to go through the WireGuard tunnel, the router must still be able to reach the VPN server's public IP via the normal WAN gateway. Without this, encapsulated packets have nowhere to go:
Code: Select all
ip route add <SERVER_IP> via <WAN_GATEWAY> dev wanTesting
From router:
Code: Select all
./vpn-toggle.sh on
curl -s ipinfo.io # Should show server location
./vpn-toggle.sh offCode: Select all
curl -s ipinfo.io # Should match router's exitCode: Select all
wg show wgserver• endpoint: showing server IP and port
• latest handshake: within last 2 minutes
• transfer: showing bytes in both directions
Troubleshooting
No handshake
• Check server firewall allows 51820/udp
• Check endpoint is set: wg show wgserver
• Manually set endpoint if missing (see bug below)
Handshake but no traffic
• Check server IP forwarding: cat /proc/sys/net/ipv4/ip_forward
• Check server NAT rule: sudo iptables -t nat -L POSTROUTING -v
• Check UFW forwarding rules
Traffic sent but nothing received
• Missing endpoint route - packets can't reach server
• Server not masquerading - check iptables rule
Preserve Across Sysupgrade
Add to /etc/sysupgrade.conf:
Code: Select all
/root/