Gluetun Docker Setup: Split-Tunnel VPN Guide (2026)
Route only qBittorrent or Prowlarr through a VPN using Gluetun and Docker split-tunneling, with a built-in kill switch and provider examples.
In my previous guides, we built the server and we built the automation stack. Now, we need to talk about Operational Security (OpSec).
I've been using various types of VPN tech personally and professionally for two decades by this point and they have assisted me greatly, in both respects. I consider VPNs to be crucial as a tool for online security & privacy, and simply to access what I need at home. Especially when I am travelling or otherwise living a bit as a "digital nomad".
Whether you are sailing the high seas of the internet or just want to keep your ISP's nose out of your business, a VPN is non-negotiable. But running a VPN on your entire server is messy. It breaks remote access, screws with DNS, confuses Plex & Jellyfin, and adds latency where you don't want it. We're going to carve up your homelab with a scalpel, not bash it with a sledge hammer.
The solution? Split-Tunneling via Docker.
We are going to use Gluetun, a lightweight, "Swiss Army Knife" VPN client container. It acts as a secure gateway. We will configure specific containers (like your download clients) to route through Gluetun, while the rest of your server stays fast and directly connected.
This guide covers:
- Setting up the Gluetun container.
- Configuration examples for NordVPN, PIA, and Mullvad.
- How to "attach" other containers (NZBGet, qBittorrent, etc.) to the tunnel.
🛠️ Step 1: The Master Container (Gluetun)
Gluetun is unique. It doesn't just connect to a VPN; it acts as a network supervisor. If the VPN connection drops, Gluetun acts as a "Kill Switch," instantly cutting networking to any container attached to it. No leaks. Ever.
Additionally there's a LOT of settings you can configure regarding DNS for Gluetun, but that's more advanced and might be worth a part 2. General rule of thumb if you have DNS issues - check to see which DNS resolver you have set in your system with cat /etc/resolv.conf. Full explanation of DNS settings for Gluetun here. Notice the defaults first. Don't change anything here unless you need to.
Here's a logical diagram of Gluetun in action -
flowchart TB
%% ==========================
%% 1. Local Network
subgraph Local ["🏠 Home / Local Network"]
Laptop["💻 User / Laptop"]
Router["🧱 EDGE Router / Firewall"]
end
%% ==========================
%% 2. Docker Host & Gluetun Stack
subgraph Host ["🐳 Docker Host Server"]
%% Gluetun Namespace
subgraph VPN_Stack ["🛡️ Gluetun Network Namespace"]
Gluetun["🛡️ Gluetun Container"]
%% Apps routed through Gluetun
subgraph Apps ["Protected Apps"]
qBit["⬇️ qBittorrent"]
Prowl["🔍 Prowlarr"]
NZB["📦 NZBGet"]
end
end
end
%% ==========================
%% 3. The Tunnel
subgraph Tunnel ["🔒 The Encrypted Tunnel"]
Nord["🛡️ VPN Provider (Nord / PIA / Mullvad)"]
end
%% ==========================
%% 4. The Internet
subgraph Internet ["🌍 The Public Internet"]
ISP["🏢 ISP (Rogers / Bell)"]
Swarm["🐝 Torrent Swarm"]
Indexers["🗂️ Usenet / Trackers"]
end
%% ==========================
%% CONNECTIONS (Top-Down Flow)
Laptop -->|"WebUI Ports 8080 / 9696"| Gluetun
Gluetun -.->|"Internal Port Mapping"| Apps
Apps ==>|"All Traffic"| Gluetun
Gluetun ==>|"WireGuard / OpenVPN"| Nord
Nord ==>|"Masked IP"| Swarm
Nord ==>|"Masked IP"| Indexers
%% Kill Switch Logic
Gluetun -.->|"⛔ BLOCKED (Kill Switch)"| ISP
Apps -.->|"⛔ NO DIRECT ACCESS"| Router
%% ==========================
%% STYLING
style Laptop fill:#f77f00,stroke:#d95d39,stroke-width:2px,color:#111
style Router fill:#457b9d,stroke:#1d3557,stroke-width:2px,color:#fff
style Gluetun fill:#0033a0,stroke:#001f66,stroke-width:4px,color:#fff
style qBit fill:#d62828,stroke:#a71d2a,stroke-width:2px,color:#fff
style Prowl fill:#d62828,stroke:#a71d2a,stroke-width:2px,color:#fff
style NZB fill:#d62828,stroke:#a71d2a,stroke-width:2px,color:#fff
style Nord fill:#0033a0,stroke:#001f66,stroke-width:4px,color:#fff
style ISP fill:#555,stroke:#333,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
style Swarm fill:#ffcc00,stroke:#996600,stroke-width:2px,color:#111
style Indexers fill:#ffcc00,stroke:#996600,stroke-width:2px,color:#111
style Local fill:transparent,stroke:#888,stroke-width:1px,stroke-dasharray:4 4
style Host fill:#f1f1f1,stroke:#333,stroke-width:2px,color:#333
style VPN_Stack fill:#e0e7ff,stroke:#0033a0,stroke-width:2px,stroke-dasharray:5 5,color:#0033a0
style Tunnel fill:transparent,stroke:#0055aa,stroke-width:3px,stroke-dasharray:2 2
style Internet fill:transparent,stroke:#aa0000,stroke-width:1px,stroke-dasharray:4 4
The Base Compose File
Here is the base docker-compose structure. You will choose ONE of the provider blocks below to fill in the environment variables. Their full list of compatible providers is here.
Create a new directory (e.g., /opt/appdata/gluetun or /opt/DOCKERS/gluetun) and a docker-compose.yml file.
services:
gluetun:
image: qmcgaw/gluetun:latest
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
# --- WEB UI PORTS ONLY ---
# We only map ports that YOU need to access from your LAN.
# We do NOT map torrent ports (like 6881) here because
# incoming VPN traffic is handled by the VPN provider, not Docker.
- "8080:8080" # qBittorrent Web UI
- "9696:9696" # Prowlarr Web UI
- "6789:6789" # NZBGet Web UI
volumes:
- /opt/appdata/gluetun:/gluetun
environment:
- TZ=America/Toronto
# --- VPN SETTINGS ---
# See full list of providers here:
# https://github.com/qdm12/gluetun-wiki/tree/main/setup/providers
- VPN_SERVICE_PROVIDER=nordvpn
- VPN_TYPE=openvpn
- OPENVPN_USER=your_service_username
- OPENVPN_PASSWORD=your_service_password
- SERVER_REGIONS=Canada
#- FIREWALL_VPN_INPUT_PORTS=21754 #Only if specified by your VPN provider
#- FIREWALL_OUTBOUND_SUBNETS=10.0.0.0/16 #Only if you require a docker using Gluetun to have access to the outside world NOT using the VPN!
restart: alwaysSee: https://www.reddit.com/r/gluetun/comments/1p7htlb/comment/nqxyrl9/
Alternatively, you can simply add it to your existing docker-compose.yml if you'd prefer.
Complete Gluetun & Wireguard Example
📄 View Full Gluetun YAML Conf (Click to Expand)
services:
gluetun:
image: qmcgaw/gluetun:v3
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- "8080:8080/tcp" # qBittorrent Web UI
environment:
- TZ=${TZ}
- UPDATER_PERIOD=24h
- VPN_SERVICE_PROVIDER=protonvpn
- VPN_TYPE=${VPN_TYPE}
- BLOCK_MALICIOUS=off
# OpenVPN
- OPENVPN_USER=${OPENVPN_USER}
- OPENVPN_PASSWORD=${OPENVPN_PASSWORD}
- OPENVPN_CIPHERS=AES-256-GCM
# WireGuard
- WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
# Port forwarding
- PORT_FORWARD_ONLY=on
- VPN_PORT_FORWARDING=on
- VPN_PORT_FORWARDING_UP_COMMAND=/bin/sh -c 'wget -O- --retry-connrefused --post-data "json={\"listen_port\":{{PORTS}}}" http://127.0.0.1:8080/api/v2/app/setPreferences 2>&1'
# ProtonVPN server selection
- SERVER_COUNTRIES=${SERVER_COUNTRIES}
volumes:
- ${MEDIA_DIR}/gluetun/config:/gluetun
restart: unless-stopped
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
depends_on:
gluetun:
condition: service_healthy
environment:
- PUID=1000
- PGID=1000
- TZ=${TZ}
- WEBUI_PORT=8080
volumes:
- ${MEDIA_DIR}/qbittorrent/config:/config
- ${MEDIA_DIR}/qbittorrent/downloads:/downloads
restart: unless-stopped
network_mode: "service:gluetun"
# .env file to match
# ==============================================================================
# Base Configuration
# ==============================================================================
TZ=Australia/Brisbane
MEDIA_DIR=/media
# ==============================================================================
# Gluetun VPN Configuration
# ==============================================================================
# Choose either:
# wireguard
# openvpn
VPN_TYPE=wireguard
# Comma-separated list of ProtonVPN server countries.
#
# To get the available ProtonVPN countries:
# docker run --rm -v eraseme:/gluetun qmcgaw/gluetun format-servers -protonvpn
SERVER_COUNTRIES=Albania,Algeria,Angola,Argentina,Australia,Austria,Azerbaijan
# ==============================================================================
# OpenVPN Configuration
# ==============================================================================
#
# These values are ignored when VPN_TYPE=wireguard
OPENVPN_USER=username+pmp
OPENVPN_PASSWORD=password
# ==============================================================================
# WireGuard Configuration
# ==============================================================================
#
# This value is ignored when VPN_TYPE=openvpn
WIREGUARD_PRIVATE_KEY=wOEI9rqqbDwnN8/Bpp22sVz48T71vJ4fYmFWujulwUU=
From: https://www.reddit.com/r/gluetun/comments/1kpbfs2/comment/mswnynw/
🔌 Connecting Your VPN Provider (PIA, Mullvad, NordVPN)
Copy the block for your specific provider and paste it into the environment section above. Order is in simple list, not order of preference. I personally use PIA.
Option A: NordVPN (WireGuard Recommended)
Note: While Nord supports WireGuard (NordLynx), extracting the private key is complex. OpenVPN is the easiest setup. You should however switch to WireGuard (Right below).
- VPN_SERVICE_PROVIDER=nordvpn
- OPENVPN_USER=service_user
- OPENVPN_PASSWORD=service_passNordVPN has been actively retiring their OpenVPN infrastructure globally to migrate users onto NordLynx (WireGuard). You must extract your WireGuard Private Key (usually via a quick Linux script or Docker container), as it is now the only reliable and performant way to use NordVPN in Gluetun.
- VPN_SERVICE_PROVIDER=nordvpn
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=your_extracted_private_key
- SERVER_REGIONS=Canada
Option B: Private Internet Access (PIA)
PIA works excellently with Gluetun and supports port forwarding automation.
- VPN_SERVICE_PROVIDER=private internet access
- OPENVPN_USER=p1234567
- OPENVPN_PASSWORD=password
- SERVER_REGIONS=CA Toronto #(Or wherever you prefer)
- VPN_PORT_FORWARDING=on #Gluetun will automate the port assignment!Option C: Mullvad (WireGuard)
Mullvad is the privacy gold standard and works natively with WireGuard in Gluetun for blazing speeds.
- VPN_SERVICE_PROVIDER=mullvad
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=your_key
- WIREGUARD_ADDRESS=10.xx.xx.xx/32🔗 Step 2: Routing Your "Bad" Traffic
Now for the magic. We generally only route Download Clients (qBittorrent, NZBGet, SABnzbd) or Index Managers (Prowlarr) through the VPN.
Do you need to route Sonarr/Radarr? Generally, no.
- The Traffic is Safe: Sonarr and Radarr communicate with indexers via HTTPS. This means your traffic is encrypted; your ISP can see you are talking to a tracker, but they cannot see what you are searching for or downloading (the
.torrentfile). Mind you this is why I prefer usingmagnetlinks... - The Risk is Low: You aren't transferring the copyrighted content itself through these apps; you're just grabbing metadata.
- The Complexity: Routing them through the VPN can make it harder for them to talk to your download clients if you aren't careful.
Torrenting is the risk. The actual peer-to-peer transfer in qBittorrent is often unencrypted and easily visible to ISPs and copyright trolls. This is what must go through the tunnel.
⛓ Attaching Your Downloaders (qBittorrent & NZBGet)
We use the network_mode directive in Docker. This tells a container: "Don't use your own network card. Plug directly into Gluetun's network card instead."
- Remove Ports: You must remove the
ports:section from your app container (e.g., qBittorrent). Since it doesn't have its own network anymore, it can't open its own ports. - Move Ports: Ensure those Web UI ports (e.g.,
8080for qBit) are listed in the Gluetun container'sports:section instead. - Add Network Mode: Add the line
network_mode: service:gluetun
Example: Routing NZBGet through Gluetun
nzbget:
image: lscr.io/linuxserver/nzbget:latest
container_name: nzbget
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/Toronto
volumes:
- /opt/appdata/nzbget:/config
- /data/downloads:/downloads
# OLD WAY:
# ports:
# - 6789:6789
# NEW WAY (The Secure Way):
network_mode: service:gluetun
# This tells Docker: "Don't give this container a network.
# Use Gluetun's network stack instead."
Example: Routing QBittorrent through Gluetun
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
# ... environment and volumes ...
# ❌ OLD WAY (Delete this section):
# ports:
# - 8080:8080
# ✅ NEW WAY (The Secure Way):
network_mode: service:gluetun
depends_on:
gluetun:
condition: service_healthyFor more details on various ways to connect dockers in the same compose or in a different compose, read up here:
Putting it all Together - Full Stack
services:
gluetun:
image: qmcgaw/gluetun:latest
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
# --- WEB UI PORTS ONLY ---
# We only map ports that YOU need to access from your LAN.
# We do NOT map torrent ports (like 6881) here because
# incoming VPN traffic is handled by the VPN provider, not Docker.
- "8080:8080" # qBittorrent Web UI
- "9696:9696" # Prowlarr Web UI
- "6789:6789" # NZBGet Web UI
volumes:
- /opt/appdata/gluetun:/gluetun
environment:
- TZ=America/Toronto
# --- VPN SETTINGS ---
# See full list of providers here:
# https://github.com/qdm12/gluetun-wiki/tree/main/setup/providers
- VPN_SERVICE_PROVIDER=nordvpn
- VPN_TYPE=openvpn
- OPENVPN_USER=your_service_username
- OPENVPN_PASSWORD=your_service_password
- SERVER_REGIONS=Canada
# --- NETWORK PERMISSIONS (Optional) ---
# Only uncomment this if your containers inside the VPN (e.g. Prowlarr)
# need to talk to services OUTSIDE the VPN (e.g. Sonarr on your LAN).
# - FIREWALL_OUTBOUND_SUBNETS=192.168.1.0/24
restart: always
# -------------------------------------------------------
# QBITTORRENT (Attached to Gluetun)
# -------------------------------------------------------
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
environment:
- PUID=1000
- PGID=1000
- TZ=America/Toronto
- WEBUI_PORT=8080
volumes:
- /opt/appdata/qbittorrent:/config
- /data/downloads:/downloads
network_mode: service:gluetun
depends_on:
gluetun:
condition: service_healthy
restart: unless-stopped🔑 Crucial Docker Networking Rules (Avoiding Leaks)
- Port Moving is Mandatory: If you try to keep
ports: 8080:8080inside the qBittorrent service, Docker will throw an error. You are effectively unplugging qBittorrent's network cable and plugging it into Gluetun. Therefore, Gluetun becomes the only door in or out. All Web UI ports must be declared in the Gluetun service. FIREWALL_OUTBOUND_SUBNETS(The Common Myth): You might see guides claiming you need this setting to access the Web UI from your browser. This is false.- Inbound is Automatic: Docker handles the inbound traffic from your browser to the Web UI via the port mapping. You don't need extra firewall rules for this.
- When DO you need it? You only need to define
FIREWALL_OUTBOUND_SUBNETSif the container inside the VPN needs to initiate a connection to something outside on your LAN. - Example: If Prowlarr is inside the VPN, but Sonarr is running normally on your LAN IP (
192.168.1.50), Prowlarr needs this setting to be allowed to "reach out" and talk to Sonarr.
- NordVPN Credentials:
- Do NOT use your regular email/password. NordVPN (and many others) use special "Service Credentials" for manual setups like this.
- Find them in your Nord Account dashboard under Set up NordVPN manually.
- Verification: You don't need complex commands to see if it works. Just check the logs! Run
docker logs gluetun. If successful, you will see a message confirming the connection and displaying the Public IP assigned by the VPN provider. If you see this IP, your traffic is secure.
⚡ Maximizing Speed: Why WireGuard is Mandatory for Gigabit Throughput
The example above uses VPN_TYPE=openvpn because it is easiest to set up with just a username/password. For details on WG in Gluetun, read here:
The definitive HOWTO for setting up ProtonVPN, Gluetun, and Qbittorernt with fully automated port forwarding.
by u/sboger in gluetun
If you want faster speeds with WireGuard, change these lines in the Gluetun section:
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=your_extracted_private_key
# Remove OPENVPN_USER and OPENVPN_PASSWORDNote: Getting the WireGuard private key from NordVPN requires a few extra manual steps (usually running a quick script on a Linux machine), as they don't show it plainly in the dashboard.
Also head over to this thread for the latest details on WG setup which require some work
🕵️ Step 3: Verification (The "Is it Working?" Test)
Forget about running complex terminal commands inside containers. Gluetun is smart; it checks its own connection status and tells you the result.
To verify your connection, simply check the container logs:
docker logs gluetun
# Or to see live running log:
docker logs -f gluetunWhat to look for: Scroll to the bottom. If the connection is successful, you will see a message explicitly stating your new Public IP.
INFO [ip getter] Public IP address is 185.xxx.xxx.xxx (Region: Toronto, CA)- If you see an IP that is NOT your home IP: Success! You are secure.
- If you see errors or "unhealthy": The container will likely restart or stop. Because we used
network_mode: service:gluetun, if Gluetun isn't healthy, your apps literally have no network connection. The "Kill Switch" is built-in by design.
🛡️ A Note on the "Kill Switch"
You don't need to configure a separate kill switch. By removing the network interface from your app (qBittorrent) and plugging it into Gluetun, you have created a physical dependency.
- Gluetun Up = Internet Access via VPN.
- Gluetun Down = No Network Card = Zero Traffic.
It is physically impossible for qBittorrent to leak traffic over your normal ISP connection because it no longer has access to that hardware interface.
Secure your traffic, protect your privacy, and sail safely. 🚤🛡️

❓ Frequently Asked Questions (FAQ)
What is Gluetun and why do I need it?
Gluetun is a lightweight Docker container that acts as a VPN "network supervisor" for other containers. Instead of routing your entire server through a VPN — which breaks remote access, DNS, and streaming apps — Gluetun lets you attach only specific containers (like qBittorrent or Prowlarr) to a VPN tunnel via network_mode: service:gluetun, leaving the rest of your server fast and directly connected.
Do I need to route Sonarr and Radarr through the VPN too?
Generally, no. Sonarr and Radarr talk to indexers over HTTPS, so that traffic is already encrypted — your ISP can see you're contacting a tracker, but not what you're searching for or downloading. The real risk is torrenting itself: the peer-to-peer transfer in qBittorrent is often unencrypted and visible to ISPs, which is why the download client is what actually needs to go through Gluetun.
Does Gluetun have a built-in kill switch?
Yes, and you don't need to configure anything extra for it. Because attached containers use network_mode: service:gluetun instead of their own network interface, they have no network access at all if Gluetun goes down or loses its VPN connection. It's physically impossible for them to leak traffic over your normal ISP connection, since they no longer have access to that hardware interface.
Do I need FIREWALL_OUTBOUND_SUBNETS to access my Web UI?
No — that's a common myth. Docker handles inbound traffic from your browser to a Web UI automatically through the port mapping on the Gluetun container; you don't need extra firewall rules for that. You only need FIREWALL_OUTBOUND_SUBNETS if a container inside the VPN (like Prowlarr) needs to initiate a connection to something outside the VPN on your LAN (like Sonarr).
How do I know if Gluetun is actually working?
Check the container logs with docker logs gluetun. A successful connection prints a message showing your new public IP and its region — if that IP isn't your home IP, you're secure. If you see errors or the container reports "unhealthy," any attached containers will have zero network access until Gluetun recovers, since they share its network stack.
Which VPN provider works best with Gluetun?
It depends on your priorities. NordVPN is easiest to set up with just OpenVPN username/password credentials (extracting its WireGuard key is more involved). PIA works excellently with Gluetun and supports automated port forwarding. Mullvad is the privacy gold standard and works natively with WireGuard in Gluetun for the fastest speeds.
Written by
