Gluetun is a lightweight VPN client that runs as its own Docker container, acting as a network gateway that other containers route their traffic through — giving you a per-app VPN tunnel with a built-in kill switch, without touching your host system’s network configuration.
Running Sonarr, SABnzbd, and similar archival tools inside Docker is convenient until you realize all their traffic flows out through your ISP in the clear. For anyone serious about privacy, that is a problem. Gluetun solves it by sitting between your apps and the internet, tunneling everything through a supported VPN provider using either OpenVPN or WireGuard.
The setup is cleaner than installing a VPN client on the host. Each container that needs protection simply borrows Gluetun’s network stack. If the VPN drops, the firewall kill switch cuts all outbound traffic instantly, so your real IP never leaks.
This guide walks through the full process: understanding what Gluetun actually does at the network layer, choosing a provider and protocol, writing the Compose configuration, and verifying that your traffic truly stays inside the tunnel.
What Gluetun Does for Docker Networking
Gluetun operates as a dedicated VPN client container that other services attach to, rather than a system-wide solution applied to the host. It supports connecting other containers directly to its network namespace, and LAN devices can also route through it via its built-in proxy servers.
Why a VPN Client Container Is Different From a System-Wide VPN
A system-wide VPN forces every process on the host through the tunnel. That includes services you may not want behind a VPN, and it complicates routing when some apps need direct access.
A VPN client container like Gluetun scopes the tunnel to exactly the containers you attach to it. Everything else on the host or in Docker continues on the normal network path.
This separation matters for home lab setups where you might run a mix of public-facing services, internal tools, and privacy-sensitive archival clients side by side.
How the Sidecar Model Protects Selected Apps
The sidecar model means Gluetun runs alongside your application containers without being embedded in them. A dependent container such as SABnzbd uses network_mode: service:gluetun in Compose, which hands its entire network namespace over to the Gluetun container.
From that point, SABnzbd has no independent network access. It can only reach the internet through whatever tunnel Gluetun has established.
Gluetun also works as a Kubernetes sidecar container, making the same pattern available in cluster environments. The core idea is identical: one container owns the VPN connection, and others inherit it.
When Gluetun Makes Sense for Usenet and Archival Workflows
Usenet indexers, download clients, and automation tools like Sonarr generate regular, identifiable traffic patterns. Routing them through a VPN limits what your ISP can observe about those connections.
Gluetun is particularly well suited here because the kill switch is automatic. If the VPN session drops during a large archival download, the firewall blocks all outbound traffic from attached containers immediately. There is no window where your real IP is exposed.
For anyone running SABnzbd or similar clients on a home server, this is a more controlled approach than hoping a provider-level VPN app stays connected.
Gluetun VPN Docker Setup Basics
Getting Gluetun running requires a few specific host-level permissions and a properly structured Compose file. The image itself is compact, and the official tags make it easy to choose between stability and cutting-edge builds.
Core Requirements on the Docker Host
Gluetun needs two things from the host that standard containers do not require.
First, the NET_ADMIN capability must be granted. This allows Gluetun to configure network interfaces, set up routing tables, and apply iptables rules for the kill switch.
Second, the /dev/net/tun device must be passed through to the container. This is the virtual network interface that VPN tunnels use. Without it, neither OpenVPN nor WireGuard can establish a tunnel.
Your Compose service block needs both:
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
Some hosts, particularly certain NAS platforms or locked-down VPS environments, restrict /dev/net/tun access. Check that the device exists on your host with ls /dev/net/tun before troubleshooting Gluetun itself.
The Official Docker Image and Common Tags
The primary image is qmcgaw/gluetun, and it is also available as ghcr.io/qdm12/gluetun through the GitHub Container Registry.
Common tags include:
| Tag | Purpose |
|---|---|
latest | Most recent stable build |
v3 | Version 3 release branch |
test | Pre-release testing builds |
The image is built on Alpine 3.23, keeping the footprint around 43MB. It supports amd64, i686 (32-bit), ARM 64-bit, ARM 32-bit v6 and v7, and ppc64le. Most home lab hardware running a standard x86 server will use amd64 without any additional configuration.
The developer behind the project is qmcgaw, and the canonical documentation lives on the gluetun wiki.
Key Compose Options Like NET_ADMIN and /dev/net/tun
A minimal working Compose block for the Gluetun container looks like this:
services:
gluetun:
image: qmcgaw/gluetun
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- /your/config/path:/gluetun
ports:
- 8888:8888/tcp # HTTP proxy
- 8388:8388/tcp # Shadowsocks TCP
- 8388:8388/udp # Shadowsocks UDP
environment:
- VPN_SERVICE_PROVIDER=
- VPN_TYPE=openvpn
- OPENVPN_USER=
- OPENVPN_PASSWORD=
- TZ=America/New_York
- UPDATER_PERIOD=
The container_name line is required if you plan to attach external containers that live in separate Compose files. Without a fixed name, other containers cannot reliably reference the Gluetun network by name.
Choosing a Provider and Protocol
Gluetun supports a large number of VPN providers out of the box, each configured through the VPN_SERVICE_PROVIDER environment variable. The right protocol and provider combination depends on your priorities around speed, compatibility, and credential structure.
OpenVPN vs WireGuard for Containerized Traffic
OpenVPN has been around longer and works with every provider Gluetun supports. It is reliable, well-tested, and handles complex network environments well. The trade-off is that it is slower than WireGuard due to its older cryptographic design and userspace implementation.
WireGuard is significantly faster and leaner. It uses modern cryptography and has lower CPU overhead, which matters on lower-powered hardware like a Raspberry Pi or older NAS. Gluetun supports WireGuard in both kernelspace and userspace modes.
For archival download workloads where you are pulling large datasets, WireGuard’s throughput advantage is noticeable.
Provider Compatibility and Credential Differences
Gluetun natively supports providers including NordVPN, Mullvad (WireGuard only), Private Internet Access, Surfshark, ExpressVPN, IPVanish, ProtonVPN, AirVPN, CyberGhost, FastestVPN, HideMyAss, IVPN, Perfect Privacy, Privado, PrivateVPN, PureVPN, SlickVPN, TorGuard, VPNSecure.me, VPNUnlimited, VyprVPN, and Windscribe.
Credential requirements differ by provider. Some use a standard username and password pair via OPENVPN_USER and OPENVPN_PASSWORD. Others, like Mullvad with WireGuard, require a WIREGUARD_PRIVATE_KEY and assigned WIREGUARD_ADDRESSES. Always check the gluetun wiki page for your specific provider before writing the Compose file.
Get Newshosting with SSL-encrypted Usenet access
When Custom WireGuard or AmneziaWG Is Useful
The custom provider option in Gluetun lets you paste in your own WireGuard configuration when your provider is not natively listed or when you want to use a manually generated peer config.
AmneziaWG is supported only through the custom provider path for now. It is a WireGuard variant designed to resist deep packet inspection, which is useful in network environments where standard WireGuard traffic is throttled or blocked.
Custom WireGuard configuration is also the right choice for self-hosted VPN servers using tools like wg-easy or Algo.
Configuration Variables That Matter Most
The environment variables you set in the Gluetun service definition control everything from authentication to DNS behavior and server refresh schedules. Getting these right the first time saves significant troubleshooting time later.
OpenVPN Credentials and Provider-Specific Logins
For OpenVPN connections, the two required variables are:
OPENVPN_USER— your VPN account usernameOPENVPN_PASSWORD— your VPN account password
Some providers like Private Internet Access use a service-specific credential pair that differs from your main account login. Others generate OpenVPN credentials separately in the account dashboard.
Storing credentials directly in a Compose file works for local home lab use, but Docker secrets offer a cleaner approach for anything production-facing. Gluetun reads from both environment variables and secrets files at the /run/secrets/ path.
WireGuard Keys, Addresses, and Server Selection
WireGuard requires a different set of variables:
WIREGUARD_PRIVATE_KEY— the private key for your WireGuard peer, generated by your provider or manually usingwg genkeyWIREGUARD_ADDRESSES— the internal VPN IP assigned to your client, typically in CIDR notation like10.64.222.21/32
Server selection for both protocols is handled through additional variables like SERVER_COUNTRIES, SERVER_CITIES, and SERVER_HOSTNAMES, depending on the provider. Check the gluetun wiki for your specific provider’s filtering options.
Server List Refresh, DNS, and Time Settings
UPDATER_PERIOD controls how often Gluetun refreshes its internal server list. Setting this to something like 24h keeps the server data current without hammering the update endpoint. Leaving it empty disables automatic updates.
DNS over TLS is baked in and active by default, routing DNS queries through encrypted channels to prevent leaks at the resolver level. You can configure multiple DNS over TLS providers to enable split horizon DNS, which resolves internal hostnames through a local resolver while sending external queries through the VPN’s DNS.
Set TZ to your local timezone so that log timestamps are readable without mental math.
Routing Apps Through the Tunnel
Once the Gluetun container is running and connected, the next step is attaching other containers to its network. There are two main approaches: sharing the network namespace directly in Compose, or using the built-in proxy servers for more flexible routing.
Using network_mode Service Sharing in Compose
The cleanest method for containers in the same Compose file is network_mode: service:gluetun. This replaces the container’s own network stack with Gluetun’s, meaning all traffic from that container flows through the VPN tunnel automatically.
sabnzbd:
image: lscr.io/linuxserver/sabnzbd:latest
network_mode: service:gluetun
depends_on:
- gluetun
With this configuration, SABnzbd has no independent internet access. It cannot reach any address that Gluetun’s firewall does not permit.
Exposing Web Interfaces Without Breaking Isolation
When using network_mode: service:gluetun, the dependent container loses its own port mapping capability. Ports must be declared on the Gluetun service, not on SABnzbd or Sonarr.
Add the web interface port to the Gluetun ports section:
ports:
- 8080:8080 # SABnzbd web UI
- 8989:8989 # Sonarr web UI
This keeps the containers isolated at the network level while still making their interfaces accessible from your LAN. It is counterintuitive at first, but it is the correct approach.
Connecting SABnzbd and Other Archival Tools Safely
For containers in separate Compose stacks, or for LAN devices that cannot run Docker, Gluetun exposes a built-in HTTP proxy on port 8888 and a SOCKS5 proxy on a configurable port. There is also a Shadowsocks proxy available, which adds an encryption layer on top of the SOCKS5 protocol for environments where unencrypted proxy traffic is a concern.
Pointing SABnzbd’s proxy settings at http://gluetun:8888 routes its Usenet server connections through the VPN without requiring network namespace sharing. This is useful when Gluetun lives in a different Compose project.
Get Newshosting — Fast Usenet Access with SSL Encryption
Kill Switch, Port Forwarding, and Testing
The kill switch and port forwarding features are where Gluetun earns its place in a serious archival workflow. Knowing how to verify these are working correctly is just as important as setting them up.
How the Firewall Kill Switch Prevents Leaks
Gluetun implements the kill switch using iptables rules applied inside the container’s network namespace. When the VPN tunnel goes down, whether due to a server-side disconnect, credential failure, or network hiccup, the firewall rules immediately block all outbound traffic from any container sharing that namespace.
There is no grace period and no fallback to the host’s IP. The connection simply stops until the VPN reconnects.
This is fundamentally different from software kill switches that operate at the application layer and can be bypassed by a crash or misconfiguration. Gluetun’s approach is enforced at the network level.
Port Forwarding Limits and Server-Side Support
Server-side port forwarding is available natively for a limited set of providers: Perfect Privacy, Private Internet Access, PrivateVPN, and ProtonVPN. This feature lets inbound connections reach containers behind the VPN, which is relevant for applications that need to accept incoming connections.
For providers not on that list, you can use the FIREWALL_VPN_INPUT_PORTS variable to statically allow specific inbound ports when you already have a forwarded port from your provider. Dynamic port negotiation through Gluetun’s control server API is also available for more advanced setups.
How to Test That Traffic Really Stays Inside the Tunnel
The most reliable test is running a plain curl request from inside a container attached to Gluetun:
docker exec sabnzbd curl -s https://api.ipify.org
The returned IP address should match your VPN provider’s server, not your home IP. If it returns your real IP, network_mode is not configured correctly.
A DNS leak test works the same way. Run docker exec sabnzbd curl -s https://1.1.1.1/cdn-cgi/trace and check the ip field in the response. Checking both the exit IP and the DNS resolver confirms that neither is leaking outside the tunnel.
Frequently Asked Questions
How do I set up a container to route traffic through a VPN using Docker Compose?
Add network_mode: service:gluetun to any container you want to tunnel, and make sure depends_on: gluetun is also set. The Gluetun container must be running and connected before the dependent container starts, or its network will have no valid route.
Which environment variables and configuration options are required to connect to different VPN providers?
At minimum, set VPN_SERVICE_PROVIDER, VPN_TYPE, and the matching credentials (OPENVPN_USER and OPENVPN_PASSWORD for OpenVPN, or WIREGUARD_PRIVATE_KEY and WIREGUARD_ADDRESSES for WireGuard). Each provider has its own additional variables; the gluetun wiki has a dedicated setup page for every supported provider.
How can I route specific containers through the VPN while keeping others on the normal network?
Only containers that explicitly use network_mode: service:gluetun are routed through the tunnel. Containers without that setting keep their own network stack and connect normally. This selective model is one of the core advantages of the sidecar approach over a system-wide VPN.
What is the recommended way to bind other containers to the VPN container’s network namespace?
For containers in the same Compose file, use network_mode: service:gluetun. For containers in separate stacks or external services, either set container_name: gluetun in the Gluetun service and reference it by name, or use the built-in HTTP or SOCKS5 proxy that Gluetun exposes on ports 8888 and configurable SOCKS5 ports.
How do I troubleshoot connectivity issues, DNS leaks, or IP not changing inside the container?
Start by running docker logs gluetun to check whether the VPN actually connected. Then exec into a dependent container and run curl https://api.ipify.org to confirm the exit IP. If DNS is leaking, verify that the container is fully sharing Gluetun’s network namespace and not falling back to the host’s resolver.
How can I add a kill switch and allow only specific inbound ports for an app behind the VPN?
The kill switch is active by default through Gluetun’s iptables firewall; no extra configuration is needed to enable it. To allow specific inbound ports, set the FIREWALL_VPN_INPUT_PORTS environment variable on the Gluetun service with a comma-separated list of ports. This is the correct way to expose application ports like SABnzbd’s web interface or an NZB API endpoint while keeping everything else locked down.