A Docker-in-Docker (DinD) based VPN failover system that provides automatic failover between multiple VPN configurations. The system uses a single privileged container that manages multiple VPN services internally and handles failover, while the host manages routing to direct Docker network traffic through the active VPN.
- Host Script (
vpn-solution.sh): Runs on the host, manages the DinD container and sets upip route/ip rulerouting - DinD Container: Runs Docker internally, manages VPN containers defined in your docker-compose.yml, handles failover
- VPN Network: Docker network that other containers can connect to for VPN access
- Multiple VPN Support: Works with Gluetun, WARP, and any containerized VPN
- Automatic Failover: Round-robin failover when VPNs fail health checks
- Flexible Configuration: Use any docker-compose.yml with VPN services
- Host-level Routing: Uses
iproute2for transparent routing (like your originalvpn-up.sh) - Easy Integration: Other containers just connect to the
vpn-network
cd vpn-manager
docker build -t vpn-fallback:latest .Create a docker-compose.yml file with your VPN services. Services will be tried in the order they appear (top to bottom). See example-vpn-compose.yml for a complete example.
services:
gluetun-de:
image: ghcr.io/qdm12/gluetun
cap_add: [NET_ADMIN]
devices: ["/dev/net/tun:/dev/net/tun"]
environment:
VPN_SERVICE_PROVIDER: custom
# ... your VPN config
warp:
image: caomingjun/warp:latest
cap_add: [NET_ADMIN, MKNOD, AUDIT_WRITE]
# ... your WARP config# Make the script executable
chmod +x vpn-solution.sh
# Start with your compose file (requires root for routing)
sudo ./vpn-solution.sh start --compose-file ./my-vpns.yml# Run any container through the VPN
docker run --rm --network vpn-network curlimages/curl:latest https://api.ipify.org
# Or in docker-compose:
services:
my-app:
image: my-app:latest
networks:
- vpn-network
networks:
vpn-network:
external: true# Start with default settings
sudo ./vpn-solution.sh start --compose-file ./vpns.yml
# Start with custom network
sudo ./vpn-solution.sh start --compose-file ./vpns.yml --network-name my-vpn --network-cidr 10.50.0.0/16
# Check status
sudo ./vpn-solution.sh status
# View logs
sudo ./vpn-solution.sh logs
# Stop
sudo ./vpn-solution.sh stop# Pass compose content as environment variable
sudo ./vpn-solution.sh start --compose-content "$(cat my-vpns.yml)"sudo ./vpn-solution.sh start \
--compose-file ./vpns.yml \
--network-name production-vpn \
--network-cidr 172.20.0.0/16 \
--image my-custom-vpn-fallback:latest- Host Script: Creates a Docker network and starts the DinD container
- DinD Container:
- Reads your docker-compose.yml file
- Extracts service names as VPN options (in order)
- Starts the first VPN service
- Sets up internal routing to forward traffic through the active VPN
- Host Routing: Uses
iproute2to route traffic from the Docker network through the DinD container - Health Monitoring: Continuously checks VPN health and switches to the next VPN on failure
- Failover: Round-robin through VPN services when failures occur
You can set these in your docker-compose.yml or pass them to the container:
PREMIUMIZE_CUSTOMER_ID: Your Premiumize customer IDPREMIUMIZE_API_KEY: Your Premiumize API keyWARP_LICENSE_KEY: Your Cloudflare WARP license keyPREMIUMIZE_DE_IPV4_ADDRESS: Custom German server IPPREMIUMIZE_NL_IPV4_ADDRESS: Custom Netherlands server IPPREMIUMIZE_US_IPV4_ADDRESS: Custom US server IP
start: Start the VPN solutionstop: Stop the VPN solutionrestart: Restart the VPN solutionstatus: Show current statuslogs: Show VPN manager logs
--compose-file <path>: Path to docker-compose.yml with VPN services- OR
--compose-content <yaml>: Docker compose content as string
--network-name <name>: Docker network name (default: vpn-network)--network-cidr <cidr>: Docker network CIDR (default: 10.45.0.0/16)--network-gateway <ip>: Docker network gateway (default: 10.45.0.1)--image <image>: VPN manager image (default: vpn-fallback:latest)
sudo ./vpn-solution.sh statussudo ./vpn-solution.sh logs# Test that traffic goes through VPN
docker run --rm --network vpn-network curlimages/curl:latest https://api.ipify.org- Permission Denied: Script must be run as root for
ip route/ip rulecommands - VPN Not Working: Check that your docker-compose.yml VPN configurations are correct
- Container Can't Start: Ensure the vpn-fallback image is built
- Network Issues: Check that the Docker network was created correctly
- Linux host with Docker
- Root privileges (for
ip route/ip rulecommands) - Docker Compose support in the DinD container
- The DinD container runs privileged to manage VPN containers
- Host routing requires root privileges
- VPN credentials should be properly secured in your compose file
This solution is provided as-is for educational and personal use.