This guide will help you set up WireGuard VPN on your ESP32-CAM device.
- A WireGuard server (can be set up on a VPS, home server, or cloud instance)
- Admin access to configure the WireGuard server
- Basic understanding of networking concepts
The ESP32-CAM implementation:
- Synchronizes time with NTP (required for WireGuard)
- Establishes a WireGuard VPN tunnel to your server
- Maintains encrypted communication through the tunnel
# Install WireGuard
sudo apt update
sudo apt install wireguard
# Generate server keys
cd /etc/wireguard
umask 077
wg genkey | tee server_private.key | wg pubkey > server_public.key
# Create server configuration
sudo nano /etc/wireguard/wg0.confAdd this configuration:
[Interface]
PrivateKey = <SERVER_PRIVATE_KEY_FROM_FILE>
Address = 10.0.0.1/24
ListenPort = 51820
SaveConfig = true
# Enable IP forwarding and NAT (optional, for internet routing)
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE# Enable IP forwarding
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
# Start WireGuard
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0On your WireGuard server:
# Generate ESP32 client keys
wg genkey | tee esp32_private.key | wg pubkey > esp32_public.key
# Display the keys
echo "ESP32 Private Key:"
cat esp32_private.key
echo ""
echo "ESP32 Public Key:"
cat esp32_public.keyOn your server, add the ESP32 as a peer:
sudo wg set wg0 peer <ESP32_PUBLIC_KEY> allowed-ips 10.0.0.2/32
sudo wg-quick save wg0Or manually edit /etc/wireguard/wg0.conf:
[Peer]
PublicKey = <ESP32_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32
PersistentKeepalive = 25Then restart WireGuard:
sudo systemctl restart wg-quick@wg0Edit include/secrets.h in your project:
// NTP Time Server (required for WireGuard)
#define NTP_SERVER "pool.ntp.org"
#define GMT_OFFSET_SEC 0
#define DAYLIGHT_OFFSET_SEC 0
// WireGuard Configuration
#define WG_PRIVATE_KEY "YOUR_ESP32_PRIVATE_KEY_HERE" // From esp32_private.key
#define WG_LOCAL_IP "10.0.0.2" // ESP32's tunnel IP
#define WG_ENDPOINT_ADDRESS "YOUR_SERVER_IP" // Server's public IP
#define WG_ENDPOINT_PORT 51820 // Server's WireGuard port
#define WG_PUBLIC_KEY "YOUR_SERVER_PUBLIC_KEY_HERE" // From server_public.keyImportant Notes:
WG_PRIVATE_KEY: The private key fromesp32_private.key(base64 encoded)WG_PUBLIC_KEY: The public key fromserver_public.key(base64 encoded)WG_ENDPOINT_ADDRESS: Must be an IP address (not a domain name in this version)WG_LOCAL_IP: Must match the IP you assigned in the server's peer configuration
On your WireGuard server:
# Check WireGuard status
sudo wg show
# Check if UDP port is open
sudo netstat -unlp | grep 51820
# Check firewall (if using ufw)
sudo ufw allow 51820/udp- Build and upload the firmware to your ESP32-CAM
- Monitor the Serial output (115200 baud):
Expected output:
ESP32-CAM with Firebase Starting...
Connecting to Wi-Fi...
Connected with IP: 192.168.1.100
=== SYNCHRONIZING TIME WITH NTP ===
Waiting for NTP time sync....
✅ Time synchronized successfully!
Current time: Wed Oct 29 12:34:56 2025
=== INITIALIZING WIREGUARD ===
WireGuard Local IP: 10.0.0.2
WireGuard Endpoint: YOUR_SERVER_IP:51820
✅ WireGuard initialized successfully!
✅ WireGuard tunnel IP: 10.0.0.2
✅ WireGuard VPN tunnel established
- Check WiFi connection is stable
- Try different NTP server:
time.google.com,time.cloudflare.com - Check timezone settings in secrets.h
- Verify server is running:
sudo wg show - Check firewall: Ensure UDP port 51820 is open
- Verify keys: Make sure you're using the correct keys
- Check IP addresses: Ensure
WG_LOCAL_IPdoesn't conflict with existing peers - Server logs:
sudo journalctl -u wg-quick@wg0 -f
# Check WireGuard status
sudo wg show
# Expected output should show your ESP32 peer
interface: wg0
public key: <SERVER_PUBLIC_KEY>
private key: (hidden)
listening port: 51820
peer: <ESP32_PUBLIC_KEY>
endpoint: <ESP32_PUBLIC_IP>:<random_port>
allowed ips: 10.0.0.2/32
latest handshake: X seconds ago
transfer: X.XX KiB received, X.XX KiB sentOnce connected, you can ping the ESP32 through the tunnel:
# From your WireGuard server
ping 10.0.0.2You can also access the ESP32's web interface through the tunnel:
http://10.0.0.2/
ws://10.0.0.2:81/ws
- Keep private keys secret - Never commit them to version control
- Use strong keys - Always generate keys using
wg genkey - Firewall rules - Only open necessary ports on your server
- Regular updates - Keep your WireGuard server updated
- Monitor connections - Regularly check
sudo wg showfor unauthorized peers
The current implementation requires an IP address. For domain name support, you would need to add DNS resolution code before calling initWireGuard().
The ESP32 should send keepalive packets to maintain the connection. This is especially important if the ESP32 is behind NAT. The WireGuard-ESP32 library handles this automatically.