The trick is that gluetun ships its own built-in healthcheck, and the "VPN not ready yet" problem usually comes from either (a) overriding it or (b) qBittorrent trying to bind before the tun device is up. A working pattern:
services:
gluetun:
image: qmcgaw/gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
environment:
- VPN_SERVICE_PROVIDER=yourprovider
healthcheck:
test: ["CMD", "sh", "-c", "wget -qO- https://ipinfo.io/ip"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
qbittorrent:
image: linuxserver/qbittorrent
network_mode: "service:gluetun"
depends_on:
gluetun:
condition: service_healthy
restart: unless-stopped
Notes:
start_period: 60s(or higher) is the key setting people miss — docker doesn't count failures againstretriesduring the start period, so gluetun gets its full handshake window (some providers take 30-60s) before qBt is allowed to start.- The default gluetun healthcheck pings its internal HTTP server, which is up before the tunnel is actually established on some providers. Testing with an external IP lookup inside the gluetun container confirms the tunnel itself works, not just the process.
- Don't add port/health checks against qBittorrent itself — with
network_mode: "service:gluetun"qBt has no network of its own, so those checks will always fail. - To verify qBt actually goes through the tunnel, check its listening IP in the qBt UI (should show the VPN exit IP, not your home IP). Gluetun's built-in kill switch (
firewall) handles the drop-protection case.
Reference: gluetun wiki, Healthcheck page.