Hands-On Guide to Gluetun: Deploying a Secure Network Exit and Container Proxy from Scratch
A hands-on tutorial to deploying Gluetun with Docker. This guide walks you through setting up a secure OpenVPN/WireGuard tunnel, configuring DNS over TLS to prevent hijacking, and routing traffic for multiple containers through the Gluetun network stack for zero-configuration proxying.

Hands-On Guide to Gluetun: Building a Private Secure Network Exit from Scratch
Why This Tutorial?
As a developer, have you encountered these issues?
- Corporate networks blocking access to certain dev resources or documentation.
- Self-hosted services (e.g., GitHub Webhooks, API syncs) requiring a stable overseas network exit.
- Privacy concerns on public Wi-Fi, but not wanting to install a global VPN client.
- Wanting other Docker containers to use an encrypted channel uniformly, rather than configuring each one individually.
The tool we are deploying today, Gluetun, solves these problems in one go. It is a lightweight Docker container written in Go, featuring built-in OpenVPN/WireGuard support, DNS over TLS (DoT) encryption, and HTTP/SOCKS5 proxies. Crucially, other containers can directly join its network stack, achieving a "proxy hub" effect. After this tutorial, you will have a reusable template for a secure network exit.
Prerequisites
Ensure your environment meets the following requirements:
- Docker 20.10+ and Docker Compose installed (v2 recommended).
- Basic Linux networking knowledge (understanding of
iptables,DNS). - An active VPN provider account (This tutorial uses Mullvad/Pia as examples; others work similarly).
- A server or local dev machine (Ubuntu 22.04 / CentOS 8 / macOS compatible).
Step 1: Deploying the Gluetun Container
Create a docker-compose.yml file. Let's start with a minimal configuration to get it running:
yaml
version: '3.8'
services:
gluetun:
image: qmcgaw/gluetun
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- 8888:8888/tcp # HTTP proxy
- 8388:8388/tcp # SOCKS5 proxy
volumes:
- /etc/gluetun:/gluetun
environment:
- VPN_SERVICE_PROVIDER=mullvad
- OPENVPN_USER=your_mullvad_account
- OPENVPN_PASSWORD=your_mullvad_password
restart: always
Why this configuration?
cap_add: NET_ADMIN: Grants the container permission to modify network interfaces, which is foundational for establishing the VPN tunnel./dev/net/tun: Maps the VPN virtual network device into the container.- Exposing proxy ports allows other services to use them. Later, we will demonstrate how to make other containers automatically proxy through it.
Startup command:
bash
docker-compose up -d
docker logs -f gluetun # Observe the connection status; success is indicated by "VPN status: connected"
Step 2: Configuring DNS over TLS Encryption
By default, DNS queries might be hijacked. Gluetun has built-in unbound support for DNS over TLS (DoT). Modify the environment variables:
yaml
environment:
- DNS_PLAINTEXT_ADDRESS= # Leave empty to disable plaintext DNS
- DOT=on # Enable DNS over TLS
- DOT_PROVIDERS=cloudflare
After restarting the container, internal DNS requests will be sent to Cloudflare nodes via TLS encryption, effectively preventing Man-In-The-Middle (MITM) attacks on DNS resolution results.
Step 3: Practical Drill — Routing Downstream Containers Through Gluetun
Suppose you have a Node.js service that needs to access overseas APIs. How do you make it automatically use Gluetun's proxy?
Modify your docker-compose.yml:
yaml
services:
api-client:
image: node:18-alpine
network_mode: "service:gluetun" # Key: Share the network stack
depends_on:
- gluetun
How it works: network_mode: service:gluetun makes this container share the network namespace with Gluetun. All traffic automatically passes through the VPN tunnel without needing extra proxy address configurations. This is a native advanced Docker networking feature, more reliable than traditional http_proxy.
Verification method:
bash
docker exec api-client curl -s ifconfig.me
## The returned IP should match the VPN exit IP shown in Gluetun logs
Troubleshooting Guide
- Connection Timeouts: Check if
cap_addand/dev/net/tunare mapped correctly. 90% of failures stem from permission issues or missing device mounts. - Slow DNS Resolution: After enabling DOT, initial queries might have a 1-2s delay, which is normal. You can adjust
DOT_ADDRESSESto specify backup nodes. - Routing Conflicts: If the host already has a global VPN, ensure the Gluetun container IP does not overlap. It is recommended to add
FIREWALL_VPN_INPUT_PORTS=1194,51820inenvironmentto explicitly allow protocol ports.
Summary
Through this practical guide, we have completed:
✅ One-click deployment of the encrypted tunnel container via Docker.
✅ Configuration of DNS over TLS to prevent DNS hijacking.
✅ Implementation of multi-container network stack sharing for zero-configuration proxy forwarding.
✅ Mastering key troubleshooting steps.
Next Steps: Combine Nginx reverse proxy with Gluetun for a full-link encryption setup; explore the VPN_INTERFACE parameter for multi-line failover. Secure network infrastructure is like water and electricity—once built, other services naturally benefit. Give it a try!
Extended Configuration Example (Reference)
bash
## Advanced: Specify country servers + Enable WireGuard
environment:
- VPN_SERVICE_PROVIDER=nordvpn
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=your_base64_private_key
- SERVER_COUNTRIES=US,SG
- FIREWALL_OUTBOUND_SUBNETS=192.168.1.0/24 # Allow access to internal network subnets
Keep your configuration modular, and your network architecture will become increasingly elegant.