Skip to content

WireGuard VPN

Martin Gergeleit edited this page Jun 12, 2026 · 2 revisions

WireGuard VPN

The router supports an optional WireGuard VPN tunnel for upstream traffic. When enabled, traffic from AP clients is routed through the WireGuard tunnel while the physical STA WiFi link remains unchanged.

Features

  • Auto-reconnect: VPN reconnects automatically when the STA interface goes down and comes back up
  • Web Configuration: Full configuration via the /vpn page
  • Config Import: Paste a standard WireGuard .conf file (e.g. from ProtonVPN) on the /vpn page to auto-fill all settings
  • CLI Configuration: Use set_vpn command for console-based setup
  • Custom DNS: Optionally hand a specific DNS server to AP clients while the VPN is enabled, preventing DNS leaks outside the tunnel
  • Split Tunneling: Route all traffic through VPN (default) or only VPN-subnet traffic, letting internet traffic go direct via STA (configurable via -R flag or web UI)
  • Kill Switch: Blocks non-local AP client traffic when VPN is enabled but not connected, preventing data leakage outside the tunnel. In route-all mode, blocks all non-local traffic; in split tunnel mode, blocks only VPN-subnet-destined traffic (enabled by default, configurable via -K flag or web UI)
  • Automatic MSS/PMTU: MSS clamping (1380) and Path MTU (1440) are automatically enabled when VPN is active

Quick Start

  1. Configure via web interface (/vpn page) or CLI:
set_vpn <your_private_key> <peer_public_key> <endpoint_ip> <tunnel_ip> -e 1
  1. Check status:
show vpn

Configuration

Setting CLI Flag Default Description
Private Key (positional) - Your WireGuard private key (base64)
Public Key (positional) - Peer's public key (base64)
Endpoint (positional) - Peer endpoint IP or hostname
Tunnel IP (positional) - Your tunnel IP (e.g. 10.0.0.2)
Preshared Key -k empty Optional preshared key
Netmask -m 255.255.255.0 Tunnel netmask
DNS -d empty DNS server handed to AP clients while VPN is enabled (optional)
Port -p 51820 Peer UDP port
Keepalive -a 0 Persistent keepalive (seconds, 0=disabled)
Enabled -e 0 Enable VPN (0 or 1)
Kill Switch -K 1 Block AP client internet when VPN is down (0 or 1)
Route All -R 1 Route all traffic through VPN (1) or only VPN subnet (0, split tunnel)

All settings are persisted in NVS and applied after restart.

Importing a Config File

Most VPN providers (ProtonVPN, Mullvad, etc.) and wg-quick produce a standard WireGuard .conf file. Instead of copying each field by hand, open the /vpn page, paste the whole file into the Import Config box, and click Import & Reboot.

The importer maps the standard config keys onto the router's settings:

.conf line Mapped to
PrivateKey Private Key
Address = 10.2.0.2/32 Tunnel IP + Netmask (CIDR prefix converted to a dotted netmask)
DNS = 10.2.0.1 DNS
PublicKey Public Key
PresharedKey Preshared Key
Endpoint = host:51820 Endpoint + Port
PersistentKeepalive Keepalive
AllowedIPs Route All (0.0.0.0/0 → on; anything else → split tunnel)

After a successful import the VPN is enabled and the device reboots to apply the settings.

Notes / limitations:

  • IPv4 only — IPv6 addresses and DNS entries are skipped, and only the first Address is used.
  • A single peer is supported; with multiple [Peer] sections the last one wins.
  • PrivateKey, PublicKey, Endpoint, and Address are required. A file missing any of these is rejected and the current configuration is left unchanged.
  • wg-quick directives the router doesn't use (MTU, Table, PreUp/PostUp, etc.) are ignored.

Setting Up a WireGuard Server on Linux

To use the ESP32 NAT Router as a VPN client, you need a WireGuard server (peer) to connect to. Here's how to set one up on a Linux machine.

1. Install WireGuard

# Debian/Ubuntu
sudo apt install wireguard

# Fedora
sudo dnf install wireguard-tools

# Arch
sudo pacman -S wireguard-tools

2. Generate Keys

# Server keys
wg genkey | tee server_private.key | wg pubkey > server_public.key

# ESP32 client keys
wg genkey | tee esp32_private.key | wg pubkey > esp32_public.key

# Optional: preshared key for extra security
wg genpsk > preshared.key

3. Configure the Server

Create /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = <contents of server_private.key>
Address = 10.0.0.1/24
ListenPort = 51820

# Enable IP forwarding and NAT for client traffic
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; sysctl -w net.ipv4.ip_forward=1
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
# ESP32 NAT Router
PublicKey = <contents of esp32_public.key>
# PresharedKey = <contents of preshared.key>    # optional
AllowedIPs = 10.0.0.2/32, 192.168.4.0/24

Replace eth0 with your server's internet-facing interface (check with ip route show default).

The AllowedIPs line includes:

  • 10.0.0.2/32 - the ESP32's tunnel address
  • 192.168.4.0/24 - the ESP32's AP subnet, so the server can route traffic back to AP clients

4. Start the Server

# Start and enable on boot
sudo systemctl enable --now wg-quick@wg0

# Verify
sudo wg show

5. Open the Firewall

sudo ufw allow 51820/udp

6. Configure the ESP32

Use the server's public key and the ESP32's private key to configure the router:

Web interface (/vpn page):

  • Private Key: contents of esp32_private.key
  • Public Key: contents of server_public.key
  • Endpoint: your server's public IP or hostname
  • Port: 51820
  • Tunnel IP: 10.0.0.2
  • Netmask: 255.255.255.0
  • DNS: (optional) DNS server to push to AP clients, e.g. 10.0.0.1
  • Keepalive: 25 (recommended when ESP32 is behind NAT)
  • Enable: checked

CLI:

set_vpn <esp32_private_key> <server_public_key> <server_ip> 10.0.0.2 -p 51820 -a 25 -e 1

7. Verify the Connection

On the server:

sudo wg show

You should see a handshake timestamp and data transfer for the ESP32 peer. On the ESP32, show vpn or the /vpn web page should show "Connected".

Troubleshooting

  • No handshake: Check that UDP port 51820 is reachable on the server. Verify keys are correct (public/private not swapped).
  • Handshake but no traffic: Ensure IP forwarding is enabled (sysctl net.ipv4.ip_forward) and the MASQUERADE rule is active (iptables -t nat -L).
  • DNS not working: The ESP32 routes all client traffic through the tunnel. Make sure the server can forward DNS queries, set a tunnel DNS with set_vpn -d <dns_ip> (or the DNS field on the /vpn page) to push a specific resolver to AP clients while the VPN is up, or set a public DNS on the ESP32's AP (set_ap_dns 1.1.1.1).
  • MTU issues: The ESP32 automatically applies MSS clamping (1380) and Path MTU (1440). If you still see issues, try reducing the server's tunnel MTU: add MTU = 1420 to the server's [Interface] section.

Clone this wiki locally