Setting Up Gluetun: VPN Container for All Your Docker Services

You’ve got a media stack running — maybe Sonarr, Radarr, qBittorrent. Or you’re running a web scraper, a Tor relay, or just a browser that needs to look like it’s in another country. You want VPN protection, but you don’t want to tunnel your entire server through a VPN and lose access to everything else.

Gluetun solves this elegantly. It’s a lightweight Docker container that runs a VPN client (WireGuard or OpenVPN), and any other container can use it as its network gateway. Only the containers you choose get routed through the VPN. Everything else stays on your normal network.

Think of it as a VPN sidecar for Docker — with a built-in kill switch, DNS over TLS, and support for over 60 VPN providers out of the box.

Why Gluetun Over Other VPN Approaches

You could install a VPN client directly on your host, but that routes everything through the tunnel — including SSH, web UIs, and monitoring. You lose local access unless you set up split tunneling manually.

You could also use each app’s built-in VPN support (some torrent clients have this), but it’s inconsistent and not every app supports it.

Gluetun’s approach is better:

  • Selective routing — Only containers connected to Gluetun use the VPN. Your Portainer, reverse proxy, and monitoring stay on your regular network.
  • Kill switch built in — If the VPN drops, connected containers lose all internet access. No IP leaks.
  • 60+ providers supported — Mullvad, NordVPN, Surfshark, PIA, ProtonVPN, Windscribe, AirVPN, and many more. Plus a custom provider option for any WireGuard or OpenVPN config.
  • WireGuard and OpenVPN — Use whichever your provider supports. WireGuard is faster; OpenVPN has broader compatibility.
  • DNS over TLS — Prevents DNS leaks by routing queries through encrypted DNS (Cloudflare, Quad9, or custom).
  • Built-in proxies — HTTP and SOCKS5 proxy servers so even non-Docker apps on your LAN can use the tunnel.
  • Tiny footprint — Based on Alpine Linux, the image is around 43 MB.

Prerequisites

  • Docker and Docker Compose installed
  • A VPN subscription with a supported provider (or any WireGuard/OpenVPN config)
  • Your VPN credentials or WireGuard private key
  • Basic familiarity with Docker networking

Docker Compose Setup

Here’s a complete setup with Gluetun protecting a qBittorrent container — the most common use case:

services:
  gluetun:
    image: qmcgaw/gluetun
    container_name: gluetun
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    ports:
      # qBittorrent Web UI (exposed through gluetun)
      - 8080:8080
      # qBittorrent incoming connections
      - 6881:6881
      - 6881:6881/udp
      # Gluetun HTTP proxy (optional)
      - 8888:8888
      # Gluetun SOCKS5 proxy (optional)
      - 8388:8388
    environment:
      - VPN_SERVICE_PROVIDER=mullvad
      - VPN_TYPE=wireguard
      - WIREGUARD_PRIVATE_KEY=your_private_key_here
      - WIREGUARD_ADDRESSES=10.x.x.x/32
      - SERVER_COUNTRIES=Switzerland
      # DNS over TLS
      - DOT=on
      - DOT_PROVIDERS=cloudflare
      # Built-in proxies
      - HTTPPROXY=on
      - SHADOWSOCKS=on
    volumes:
      - ./gluetun:/gluetun
    restart: unless-stopped

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    network_mode: "service:gluetun"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
      - WEBUI_PORT=8080
    volumes:
      - ./qbittorrent/config:/config
      - /path/to/downloads:/downloads
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

The key line is network_mode: "service:gluetun". This tells qBittorrent to use Gluetun’s network stack instead of its own. All of qBittorrent’s traffic — including DNS — goes through the VPN tunnel.

Important: When a container uses network_mode: service:gluetun, its ports must be defined on the Gluetun container, not on the app container. That’s why port 8080 (qBittorrent’s web UI) is listed under Gluetun’s ports.

Provider Configuration Examples

Mullvad (WireGuard)

environment:
  - VPN_SERVICE_PROVIDER=mullvad
  - VPN_TYPE=wireguard
  - WIREGUARD_PRIVATE_KEY=your_key
  - WIREGUARD_ADDRESSES=10.x.x.x/32
  - SERVER_COUNTRIES=Switzerland

NordVPN (OpenVPN)

environment:
  - VPN_SERVICE_PROVIDER=nordvpn
  - VPN_TYPE=openvpn
  - OPENVPN_USER=your_service_username
  - OPENVPN_PASSWORD=your_service_password
  - SERVER_COUNTRIES=Netherlands

ProtonVPN (WireGuard)

environment:
  - VPN_SERVICE_PROVIDER=protonvpn
  - VPN_TYPE=wireguard
  - WIREGUARD_PRIVATE_KEY=your_key
  - WIREGUARD_ADDRESSES=10.2.0.2/32
  - SERVER_COUNTRIES=Iceland

Custom Provider (Any WireGuard Config)

If your provider isn’t directly supported, use the custom provider with your WireGuard config:

environment:
  - VPN_SERVICE_PROVIDER=custom
  - VPN_TYPE=wireguard
  - WIREGUARD_PRIVATE_KEY=your_key
  - WIREGUARD_ADDRESSES=10.x.x.x/32
  - WIREGUARD_PUBLIC_KEY=server_public_key
  - WIREGUARD_ENDPOINT_IP=server_ip
  - WIREGUARD_ENDPOINT_PORT=51820
  - VPN_ENDPOINT_IP=server_ip

Connecting Multiple Containers

The real power of Gluetun is routing multiple services through the same VPN. Add any container by setting its network_mode:

services:
  gluetun:
    # ... (config from above)
    ports:
      - 8080:8080   # qBittorrent
      - 9696:9696   # Prowlarr
      - 8191:8191   # FlareSolverr

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    network_mode: "service:gluetun"
    # ...

  prowlarr:
    image: lscr.io/linuxserver/prowlarr:latest
    network_mode: "service:gluetun"
    environment:
      - PUID=1000
      - PGID=1000
    volumes:
      - ./prowlarr:/config
    depends_on:
      gluetun:
        condition: service_healthy

  flaresolverr:
    image: ghcr.io/flaresolverr/flaresolverr:latest
    network_mode: "service:gluetun"
    depends_on:
      gluetun:
        condition: service_healthy

All three services share the same VPN tunnel and the same external IP address.

Using the Built-in Proxies

Gluetun includes HTTP and SOCKS5 proxy servers. Any device on your LAN can route traffic through the VPN without running Docker:

# Test the HTTP proxy
curl -x http://your-server-ip:8888 https://ifconfig.me

# Test the SOCKS5 proxy
curl -x socks5://your-server-ip:8388 https://ifconfig.me

You can configure browsers, apps, or even other machines to use these proxy addresses. Useful for occasionally browsing through a VPN without installing a client on every device.

Health Checks and Kill Switch

Gluetun has a built-in health check that verifies the VPN connection is active. This is why we use condition: service_healthy in our depends_on — containers won’t start until the VPN is confirmed working.

The kill switch is automatic. If the VPN tunnel drops, all containers using Gluetun’s network lose internet access immediately. No traffic leaks through your real IP. When the tunnel reconnects, traffic resumes.

You can verify the health check:

# Check Gluetun's health status
docker exec gluetun wget -qO- https://ifconfig.me

# Compare with your real IP
curl https://ifconfig.me

If both commands return different IPs, the VPN is working correctly.

Port Forwarding

Some VPN providers support port forwarding — essential for good torrent seeding ratios. Gluetun can request a forwarded port automatically:

environment:
  - VPN_PORT_FORWARDING=on
  - VPN_PORT_FORWARDING_PROVIDER=protonvpn

The forwarded port is saved to /tmp/gluetun/forwarded_port inside the container. You can use a script to update qBittorrent’s listening port automatically:

#!/bin/bash
PORT=$(docker exec gluetun cat /tmp/gluetun/forwarded_port)
echo "Forwarded port: $PORT"
# Update qBittorrent via its API
curl -s -b /tmp/qbt_cookies.txt \
  "http://localhost:8080/api/v2/app/setPreferences" \
  -d "json={\"listen_port\":$PORT}"

Providers that support port forwarding include ProtonVPN, AirVPN, and Private Internet Access, among others.

Reverse Proxy Setup

Since the web UIs are exposed through Gluetun’s ports, your reverse proxy config points to Gluetun’s host ports as usual:

# Caddy example
qbit.yourdomain.com {
    reverse_proxy localhost:8080
}
# Nginx example
server {
    server_name qbit.yourdomain.com;
    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Troubleshooting

Container can’t reach the internet

Check Gluetun’s logs first:

docker logs gluetun

Look for healthy in the output. Common issues:

  • Wrong credentials — Double-check your VPN username/password or WireGuard key
  • Missing /dev/net/tun — Ensure the device mapping and NET_ADMIN capability are set
  • Firewall blocking — Some hosts block UDP 51820 (WireGuard) or UDP 1194 (OpenVPN)

Web UI not accessible

Remember: ports for connected containers go on Gluetun, not on the app container. If you put ports: 8080:8080 on qBittorrent instead of Gluetun, it won’t work.

DNS issues

If containers can reach IPs but not domains, there might be a DNS leak or misconfiguration:

environment:
  - DOT=on
  - DOT_PROVIDERS=cloudflare
  - DNS_KEEP_NAMESERVER=off

Server selection

If a specific server is slow, try switching countries or cities:

environment:
  - SERVER_COUNTRIES=Netherlands,Sweden,Switzerland
  - SERVER_CITIES=Amsterdam,Stockholm

Gluetun will pick a random server matching your criteria.

Checking your VPN IP

# From inside a connected container
docker exec qbittorrent curl -s https://ifconfig.me

# Should show VPN IP, not your real IP

Gluetun Control Server

Gluetun exposes a REST API on port 8000 (inside the container) for runtime control:

# Get current public IP
docker exec gluetun wget -qO- http://localhost:8000/v1/publicip/ip

# Get VPN status
docker exec gluetun wget -qO- http://localhost:8000/v1/openvpn/status

# Switch servers without restarting
docker exec gluetun wget -qO- --post-data='{"country":"Germany"}' \
  http://localhost:8000/v1/openvpn/settings

This is useful for automation — you can rotate servers on a schedule or trigger switches based on speed tests.

Resource Usage

Gluetun is remarkably lightweight:

MetricTypical Usage
RAM15–30 MB
CPUNear zero (idle), minimal under load
Image size~43 MB
Startup time5–15 seconds

WireGuard uses less CPU than OpenVPN. For most home servers, Gluetun’s overhead is negligible.

Best Practices

  1. Use WireGuard when possible — It’s faster, uses less CPU, and establishes connections quicker than OpenVPN.
  2. Always use service_healthy — Don’t let containers start before the VPN is confirmed active.
  3. Enable DNS over TLS — Prevents DNS leaks that could reveal your browsing even with a VPN.
  4. Pin your server country — Random server selection across all countries can give inconsistent performance.
  5. Monitor with the control API — Check /v1/publicip/ip periodically to confirm the VPN is still active.
  6. Back up your config — Your WireGuard keys and credentials are the only things you need to recreate the setup.

Conclusion

Gluetun is one of those Docker containers that, once you set it up, you wonder how you lived without it. Selective VPN routing for containers, a built-in kill switch, proxy servers for LAN devices, and support for virtually every VPN provider — all in a 43 MB Alpine-based image.

The network_mode: service:gluetun pattern is simple and powerful. Any container that needs VPN protection gets one line added to its config, and everything just works. No complex iptables rules, no host-level VPN configuration, no split tunneling headaches.

Start with your torrent client, then consider routing indexers and scrapers through it too. Your real IP stays hidden where it matters, and everything else on your server stays accessible.