Issue resolved — posting the full diagnosis in case it helps others.
Root cause
OVH private network (vRack / ens4) DHCP was injecting a default route at the same metric (100) as the public interface (ens3). For locally-originated traffic this was harmless — the kernel picked ens3 via source-address selection. But for forwarded Docker traffic (172.18.0.0/16), there's no source preference, so the kernel fell back to FIB order and picked ens4 first. The ens4 gateway (10.10.0.1) doesn't actually exist on OVH private networks — ARP resolution failed, the kernel returned EHOSTUNREACH, and every outbound container connection died with No route to host.
- IPv6 unaffected — only one IPv6 default gateway existed (on
ens3), no competition. - Host itself unaffected — source-address selection always preferred
ens3for locally-originated packets.
Fix applied — /etc/netplan/50-cloud-init.yaml
ens4:
match:
macaddress: "fa:16:3e:ee:32:6a"
dhcp4: true
dhcp4-overrides:
use-routes: false
use-dns: false
set-name: "ens4"
mtu: 1500
netplan apply
This drops the phantom default route while keeping the 10.10.0.0/24 connected route intact, so private network traffic still works. Container outbound IPv4 restored immediately.
Note for OVH + vRack users — if you run Cloudron with a second interface for private networking, add
use-routes: falseon that interface. OVH's DHCP silently advertises a default gateway that doesn't route to the internet, which breaks Docker NAT for all containers while leaving the host itself seemingly fine.