Docker has been perfect for self-hosting several open-source apps as containers in my home lab. That’s how I tried several apps and services as containers without messing up my Raspberry Pi much. Some of those containers, such as indexers and download automators, fetch data (and metadata) from the Internet. So, I tried using a VPN to prevent my IP address from being exposed on the Internet. Putting everything behind a VPN for all traffic did slow down many things.
I tried Gluetun, a VPN client for Docker containers, just for the apps on my home server. That has been a game-changer for container-specific routing of traffic, alleviating privacy and preventing IP leaks through a secure VPN tunnel. That’s why I believe Gluetun is the best way to route all outbound traffic from Docker containers. Even though it’s not a full-blown VPN with inbound connectivity options, it works perfectly for a self-hosted home lab or development purposes.
Why do I use Gluetun to route Docker containers through a VPN?
Fine-grained control, isolation, and privacy for a few containers
Using a VPN to provide blanket coverage for all traffic on my home network didn’t work as smoothly as I expected. Several personal and work-related access didn’t work when software or service detected a VPN connection. Finally, using Gluetun for container-specific VPN routing made it easier to use without making changes to my network settings. As a lightweight VPN client for Docker containers, its integration was straightforward. All I did was install it as yet another Docker container. No further configuration is required to modify any firewall rules or other network changes at the OS level.
By default, Gluetun supports several VPN providers, like Private Internet Access, Surfshark, NordVPN, ExpressVPN, Mullvad, and many others. So, I only had to provide my login credentials for the VPN I used (Surfshark), and Gluetun managed the settings to configure the account using WireGuard or OpenVPN protocols. While acting as a VPN client, Gluetun uses the VPN provider’s settings to create a secure tunnel for all outgoing traffic from the containers using its network. That way, it utilizes secure or encrypted DNS providers to prevent DNS leaks from the secure tunnel.
If VPN connectivity breaks, Gluetun automatically blocks all traffic from the configured containers to prevent IP leaks. Gluetun uses iptables to enforce the kill switch for traffic in case the VPN drops, which means the connected containers won’t work unless the VPN is active. That’s much better than using any system-wide VPNs without a kill switch or firewall in place, which could expose my machine’s IP address.
Handling outbound traffic from sensitive containers using Gluetun
Routing outbound traffic securely through a VPN tunnel
I use Docker Compose files in Dockge to deploy the ARR app stack to work with Gluetun. By default, the containers use Gluetun’s network stack and have no access to my real IP or my host machine. For my stacks, I used Surfshark VPN’s credentials. I logged into my Surfshark VPN account and enabled the option to set it up manually. That generated a specific alphanumeric code for username and password. Use that in Gluetun’s container configuration.
I recommend using the Wireguard protocol over OpenVPN for better speeds, stability, and less CPU load when using Gluetun on an SBC like a Raspberry Pi.
Here’s how the Gluetun setup code appears in a Docker Compose file typically:
services:gluetun:
image: qmcgaw/gluetun
container_name: gluetun
cap_add:
- NET_ADMIN
environment:
- VPN_SERVICE_PROVIDER=surfshark
- OPENVPN_USER=username
- OPENVPN_PASSWORD=password
- FIREWALL=on
- TZ=Asia/Kolkata
volumes:
- ./gluetun:/gluetun
ports:
- 8080:8080 # qBittorrent web UI
- 8989:8989 # Sonarr
- 7878:7878 # Radarr
- 8686:8686 # Lidarr
- 6767:6767 # Bazarr
restart: unless-stopped
Adding this code at the top of a fresh stack ensured that Gluetun got installed first. Following that, I added network mode to make the rest of the containers use Gluetun’s network. Also, I included the firewall environment variable to block internet access entirely when the VPN connection drops. Technically, the firewall is on by default. As part of my defensive practice, I added using the same compose file across different environments. Here’s what the code for a container using Gluetun’s network looks like:
sonarr:image: lscr.io/linuxserver/sonarr
container_name: sonarr
network_mode: service:gluetun
depends_on:
- gluetun
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Kolkata
volumes:
- ./sonarr:/config
- ./downloads:/downloads
- ./media/tv:/tv
restart: unless-stopped
Notice that I specified the network_mode variable to use the Gluetun service. After deploying the entire ARR stack of apps, it was necessary to check whether the containers were indeed using Gluetun’s network for their outgoing traffic. I ran this command to check that:
docker exec radarr curl ifconfig.meThe command showed me the IP address assigned by the VPN service provider I used in Gluetun’s setup. That meant all the containers use VPN tunnels set by Gluetun.
Not all Docker containers work with Gluetun
Number of exceptions for multiple reasons
Gluetun is the best option for routing outbound traffic, but it doesn’t work with all container-based apps and services that require direct exposure of incoming ports to the LAN. For instance, torrent apps like qBittorrent, Transmission, or Deluge require exposing specific incoming ports for TCP and UDP.
Also, the apps and services that require local network discovery through multicast or broadcast. Like Home Assistant, it requires the discovery of devices on the LAN for easy integration. Similarly, Pi-hole and Unbound will cause DNS conflicts with Gluetun’s DNS and firewall rules.
One major shortcoming I learned is that exposing the HTTPS ports doesn’t work with Gluetun. So, I had to run a container, such as Nginx Proxy Manager, without Gluetun’s network. Also, I was unable to access the apps using the VPN IP since Surfshark doesn’t support port forwarding. However, setting up a reverse proxy that is not behind a VPN, even one that doesn’t forward ports, fixed the issue since it communicates outside Gluetun, over the Docker stack’s network.
Better VPN routing for container-based apps
Gluetun turned out to be a lightweight yet powerful game-changer to route traffic from containers. I can continue using select containers to circumvent geolocation lockups and avoid IP bans. Most importantly, it doesn’t interfere with system files and can run smoothly on low-powered SBCs as well. While it still requires me to use a VPN service provider’s account, it solves the requirement for VPN tunneling for select Docker containers. I recommend setting up Health Checks using webhooks to have Gluetun notify you whenever the VPN drops.