WireGuard Docker Configuration Drift
Disclaimer: This blog article has been generated with the assistance of AI. While the content is AI-generated, the software itself and the ideas behind it are the result of real development work and genuine user needs.
WireGuard Docker Configuration Drift: A Debugging Journey
Recently, I encountered a frustrating networking issue with my containerized WireGuard VPN setup. My Android client could connect to the WireGuard server running in Docker, but couldn’t access the internet or any services. What started as a simple connectivity problem turned into a lesson about configuration drift and the importance of understanding how different network layers interact.
The Setup
I was running WG-Easy in Docker Compose with a custom network configuration:
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy:15
container_name: wg-easy
networks:
wg:
ipv4_address: 10.42.42.42 # Static IP in custom network
volumes:
- etc_wireguard:/etc/wireguard
ports:
- "51820:51820/udp"
cap_add:
- NET_ADMIN
- SYS_MODULE
# ... other config
networks:
wg:
driver: bridge
ipam:
config:
- subnet: 10.42.42.0/24
The container was running fine, WireGuard clients could connect, but they couldn’t reach the internet.
The Investigation
Network Traffic Analysis
Using tcpdump, I captured the network traffic and noticed something interesting:
07:59:26.193202 IP RT-AC68U-4740.local.35734 > zk.docker.dev.https: Flags [P.]
08:05:27.821764 IP6 fdcc:ad94:bacf:61a4::cafe:2.39226 > whatsapp-chatd-edge6-shv-02-iad3.facebook.com.https
08:05:28.076785 IP 10.42.42.2.38844 > whatsapp-chatd-edge-shv-02-mia3.facebook.com.https
The traffic showed:
- Container was at
10.42.42.42(Docker network IP) - Android client was assigned
10.42.42.2(VPN client IP) - WireGuard handshakes were successful
Everything looked normal from a network perspective, so I dug deeper.
Configuration Inspection
Inside the WireGuard container, I found the first clue:
$ docker exec -it wg-easy wg show
interface: wg0
public key: gi/bShTv06aiw1x8NT48x93oS5gx9drWdUEUtJMUpQ0=
listening port: 51820
peer: zEEv0Ig9h5zjHGYZMai06DSNnCsqgz7tD4oJK7JL0y0=
allowed ips: 10.42.42.2/32
latest handshake: 1 minute, 48 seconds ago
transfer: 469.18 KiB received, 4.66 KiB sent
But then I checked the actual WireGuard interface:
$ docker exec -it wg-easy ip addr show wg0
4: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN
inet 10.8.0.1/24 scope global wg0 # ← This was the problem!
The Root Cause
Here’s what was happening:
| Component | Expected IP | Actual IP | Status |
|---|---|---|---|
| Docker Container | 10.42.42.42 | 10.42.42.42 | ✅ Correct |
| WireGuard Server | 10.42.42.1 | 10.8.0.1 | ❌ Wrong |
| WireGuard Client | 10.42.42.2 | 10.8.0.2 | ❌ Wrong |
| NAT Rules | 10.42.42.0/24 | 10.8.0.0/24 | ❌ Wrong |
The WireGuard configuration file showed one thing, but the running interface used completely different IP ranges!
$ docker exec -it wg-easy cat /etc/wireguard/wg0.conf
[Interface]
Address = 10.42.42.1/24 # Config file said this
# But actual interface was 10.8.0.1/24
Why This Happened
WG-Easy’s Auto-Configuration Behavior:
- WG-Easy automatically generates WireGuard configs on first startup
- It uses its own default VPN subnet (
10.8.0.0/24) regardless of Docker network settings - The Docker network (
10.42.42.0/24) is for container-to-container communication - The WireGuard network (
10.8.0.0/24) is for VPN clients connecting to the server - These networks are intentionally separate in WG-Easy’s design
Configuration Drift:
The config file (/etc/wireguard/wg0.conf) contained stale or template data that didn’t match the actual running configuration. This can happen when:
- Container versions change behavior between updates
- Manual configuration edits conflict with auto-generated settings
- Persistent volumes retain old configs when you expect them to refresh
The Debugging Process
- IP Forwarding: ✅ Enabled (
/proc/sys/net/ipv4/ip_forward= 1) - Container Internet Access: ✅ Working (
ping 8.8.8.8succeeded) - WireGuard Interface: ❌ Wrong IP range
- NAT Rules: ❌ Only masquerading
10.8.0.0/24, not10.42.42.0/24
$ docker exec -it wg-easy iptables -t nat -L POSTROUTING -n
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 10.8.0.0/24 0.0.0.0/0 # Only 10.8.x traffic!
The Solution
Rather than trying to manually fix the configuration drift, I chose to just re-create the wg-easy container
# Complete teardown
docker-compose down -v
# Remove the persistent volume (destroys all WireGuard configs)
docker volume rm $(docker volume ls -q | grep etc_wireguard)
# Recreate everything
docker-compose up -d
Key Learnings
1. Understand Network Layer Separation
Docker networks and VPN tunnels serve different purposes:
- Docker network: Container-to-container communication
- VPN network: Client-to-server tunnel communication
Don’t assume they should use the same IP ranges.
Have you encountered similar Docker networking issues? Share your debugging stories in the comments below!