Skip to content
Muhammet Şafak
tr
Asked by: Mert Answered:

WireGuard collides with Docker networks — how do I stabilize routing?


Question

On my Ubuntu VPS I have a database cluster closed to the outside; the main interface is `ens192`. I set up a WireGuard tunnel for secure access. When the VPN comes up, IP conflicts and routing errors appear between the local Docker networks (`docker0`) and the WireGuard subnets. How do I permanently stabilize network isolation and the routing table at the server level?

Answer

Short answer: the root cause is overlapping RFC1918 ranges. The fix isn’t a runtime trick, it’s a deterministic addressing plan: pin Docker’s pool, narrow WireGuard’s AllowedIPs, make routes persistent.

This isn’t a “route bug”, it’s a planning problem: once WireGuard comes up there are two networks sitting in the same 172.x/10.x range, and the kernel can’t decide which one to route.

  1. Pin Docker’s pool. With default-address-pools in daemon.json, pin the block Docker auto-assigns networks from to a range that can never collide with the WireGuard subnet. As long as Docker picks random subnets, a clash is inevitable; decide it by hand.
  2. Give WireGuard a TIGHT AllowedIPs. Let AllowedIPs be only the DB subnet — not 0.0.0.0/0. Keep it broad and WireGuard hijacks the host’s entire default route, and everything tries to flow through the tunnel. Narrow it and the kernel only sends DB traffic to wg0.
  3. Make routes persistent. Ad-hoc ip route add commands die on reboot. Define routes via systemd-networkd/netplan so they come back automatically after a restart. That’s the only durable cure for “it worked, then a reboot broke it”.
  4. Keep the DB box inbound-only over wg0. Don’t NAT the database to the world; let it accept only connections from the tunnel. That’s the whole point of a closed cluster — access through one door, and that door is WireGuard.
  5. Verify. Use ip route get <db-ip> to confirm the packet really leaves via wg0, and wg show to confirm the handshake is live. Confirm with these two commands, not by guessing.

Bottom line: stop chasing collisions at runtime; this is a planning problem. I’d write a documented, non-overlapping subnet plan per interface (ens192 / docker0 / wg0). Pin the Docker pool, narrow AllowedIPs, make routes persistent via systemd, reach the DB only through the tunnel. With a clean addressing plan, routing stabilizes on its own.

Related Reading

Tags: #infrastructure#networking#docker
Share:

Comments

Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.

More Questions

All questions

Search the site

Start typing to search posts, projects and pages.

Esc to close Powered by Pagefind