Gluetun VPN client
Lightweight swiss-knife-like VPN client to tunnel to Private Internet Access, Mullvad, Windscribe, Surfshark Cyberghost, VyprVPN and NordVPN VPN servers, using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and Tinyproxy
ANNOUNCEMENT: Video of the Git history of Gluetun
Click to show base components
- Alpine 3.12 for a tiny image (37MB of packages, 6.7MB of Go binary and 5.6MB for Alpine)
- OpenVPN 2.4.9 to tunnel to your VPN provider servers
- IPtables 1.8.4 enforces the container to communicate only through the VPN or with other containers in its virtual network (acts as a killswitch)
- Unbound 1.10.1 configured with Cloudflare's 1.1.1.1 DNS over TLS (configurable with 5 different providers)
- Files and blocking lists built periodically used with Unbound (see
BLOCK_MALICIOUS,BLOCK_SURVEILLANCEandBLOCK_ADSenvironment variables) - TinyProxy 1.10.0
- Shadowsocks 3.3.4
Features
- Based on Alpine 3.12 for a small Docker image of 52MB
- Supports Private Internet Access, Mullvad, Windscribe, Surfshark, Cyberghost, Vyprvpn and NordVPN servers
- DNS over TLS baked in with service provider(s) of your choice
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours
- Choose the vpn network protocol,
udportcp - Built in firewall kill switch to allow traffic only with needed the VPN servers and LAN devices
- Built in SOCKS5 proxy (Shadowsocks, tunnels TCP+UDP)
- Built in HTTP proxy (Tinyproxy, tunnels TCP)
- Connect other containers to it
- Connect LAN devices to it
- Compatible with amd64, i686 (32 bit), ARM 64 bit, ARM 32 bit v6 and v7 🎆
VPN provider specifics
- Private Internet Access: pick the region, the level of encryption and enable port forwarding
- Mullvad: Pick the country, city and ISP and optionally a custom port to use (i.e.
53(udp) or80(tcp)) - Windscribe: Pick the region, and optionally a custom port to use
- Surfshark: Pick the region or a multi hop region name
- Cyberghost: Pick the region and server group.
- VyprVPN: Pick the region, port forwarding works by default
- NordVPN: Pick the region and optionally the server number
Extra niche features
- Possibility of split horizon DNS by selecting multiple DNS over TLS providers
- Subprograms all drop root privileges once launched
- Subprograms output streams are all merged together
- Can work as a Kubernetes sidecar container, thanks @rorph
Setup
-
Requirements
- A VPN account with one of the service providers:
-
Private Internet Access: username and password (sign up)
-
Mullvad: user ID (sign up)
-
Windscribe: username and password | Signup up using my affiliate link below
-
Surfshark: username and password (sign up)
-
Cyberghost: username, password and device client key file (sign up)
-
Vyprvpn: username and password
-
NordVPN: username and password
-
- If you have a host or router firewall, please refer to the firewall documentation
- A VPN account with one of the service providers:
-
On some devices you may need to setup your tunnel kernel module on your host with
insmod /lib/modules/tun.koormodprobe tun- Synology users: please read this part of the Wiki
-
Launch the container with:
docker run -d --name gluetun --cap-add=NET_ADMIN \ -e REGION="CA Montreal" -e USER=js89ds7 -e PASSWORD=8fd9s239G \ qmcgaw/private-internet-accessor use docker-compose.yml with:
docker-compose up -dNote that you can:
- Change the many environment variables available
- Use
-p 8888:8888/tcpto access the HTTP web proxy (and put your LAN inEXTRA_SUBNETSenvironment variable, in example192.168.1.0/24) - Use
-p 8388:8388/tcp -p 8388:8388/udpto access the SOCKS5 proxy (and put your LAN inEXTRA_SUBNETSenvironment variable, in example192.168.1.0/24) - Use
-p 8000:8000/tcpto access the HTTP control server built-in
If you encounter an issue with the tun device not being available, see the FAQ
-
You can update the image with
docker pull qmcgaw/private-internet-access:latest. See the wiki for more information on other tags available.
Testing
Check the VPN IP address matches your expectations
docker run --rm --network=container:gluetun alpine:3.12 wget -qO- https://ipinfo.io
Want more testing? ▶ see the Wiki
Environment variables
TLDR; only set the 🏁 marked environment variables to get started.
VPN
| Variable | Default | Choices | Description |
|---|---|---|---|
🏁 VPNSP |
private internet access |
private internet access, mullvad, windscribe, surfshark, vyprvpn, nordvpn |
VPN Service Provider |
IP_STATUS_FILE |
/ip |
Any filepath | Filepath to store the public IP address assigned |
PROTOCOL |
udp |
udp or tcp |
Network protocol to use |
OPENVPN_VERBOSITY |
1 |
0 to 6 |
Openvpn verbosity level |
OPENVPN_ROOT |
no |
yes or no |
Run OpenVPN as root |
OPENVPN_TARGET_IP |
Valid IP address | Specify a target VPN server (or gateway) IP address to use | |
OPENVPN_CIPHER |
i.e. aes-256-gcm |
Specify a custom cipher to use. It will also set ncp-disable if using AES GCM for PIA |
|
OPENVPN_AUTH |
i.e. sha256 |
Specify a custom auth algorithm to use |
-
Private Internet Access
Variable Default Choices Description 🏁 USERYour username 🏁 PASSWORDYour password REGIONAustriaOne of the PIA regions VPN server region PIA_ENCRYPTIONstrongnormal,strongEncryption preset PORT_FORWARDINGoffon,offEnable port forwarding on the VPN server PORT_FORWARDING_STATUS_FILE/forwarded_portAny filepath Filepath to store the forwarded port number -
Mullvad
Variable Default Choices Description 🏁 USERYour user ID COUNTRYSwedenOne of the Mullvad countries VPN server country CITYOne of the Mullvad cities VPN server city ISPOne of the Mullvad ISP VPN server ISP PORT80or443for TCP; or53for UDP. Leave blank for default Mullvad server portCustom VPN port to use -
Windscribe
Variable Default Choices Description 🏁 USERYour username 🏁 PASSWORDYour password REGIONAustriaOne of the Windscribe regions VPN server region PORTOne from the this list of ports Custom VPN port to use -
Surfshark
Variable Default Choices Description 🏁 USERYour service username, found at the bottom of the manual setup page 🏁 PASSWORDYour service password REGIONAustriaOne of the Surfshark regions (subdomains) VPN server region -
Cyberghost
Variable Default Choices Description 🏁 USERYour username 🏁 PASSWORDYour password 🏁 CLIENT_KEYYour device client key content, see below REGIONAustriaOne of the Cyberghost countries VPN server country CYBERGHOST_GROUPPremium UDP EuropeOne of the server groups Server group To specify your client key, you can either:
-
Bind mount it at
/files/client.key, for example with-v /yourpath/client.key:/files/client.key:ro -
Convert it to a single line value using:
docker run -it --rm -v /yourpath/client.key:/files/client.key:ro qmcgaw/private-internet-access clientkeyAnd use the line produced as the value for the environment variable
CLIENT_KEY.
-
-
Vyprvpn
Variable Default Choices Description 🏁 USERYour username 🏁 PASSWORDYour password REGIONAustriaOne of the VyprVPN regions VPN server region -
NordVPN
Variable Default Choices Description 🏁 USERYour username 🏁 PASSWORDYour password 🏁 REGIONAustria(wrong)One of the NordVPN server country, i.e. SwitzerlandVPN server country SERVER_NUMBERServer integer number Optional server number. For example 251forItaly #251
DNS over TLS
None of the following values are required.
| Variable | Default | Choices | Description |
|---|---|---|---|
DOT |
on |
on, off |
Activate DNS over TLS with Unbound |
DOT_PROVIDERS |
cloudflare |
cloudflare, google, quad9, quadrant, cleanbrowsing, securedns, libredns |
Comma delimited list of DNS over TLS providers |
DOT_CACHING |
on |
on, off |
Unbound caching |
DOT_IPV6 |
off |
on, off |
DNS IPv6 resolution |
DOT_PRIVATE_ADDRESS |
All private CIDRs ranges | Comma separated list of CIDRs or single IP addresses Unbound won't resolve to. Note that the default setting prevents DNS rebinding | |
DOT_VERBOSITY |
1 |
0 to 5 |
Unbound verbosity level |
DOT_VERBOSITY_DETAILS |
0 |
0 to 4 |
Unbound details verbosity level |
DOT_VALIDATION_LOGLEVEL |
0 |
0 to 2 |
Unbound validation log level |
DNS_UPDATE_PERIOD |
24h |
i.e. 0, 30s, 5m, 24h |
Period to update block lists and cryptographic files and restart Unbound. Set to 0 to deactivate updates |
BLOCK_MALICIOUS |
on |
on, off |
Block malicious hostnames and IPs with Unbound |
BLOCK_SURVEILLANCE |
off |
on, off |
Block surveillance hostnames and IPs with Unbound |
BLOCK_ADS |
off |
on, off |
Block ads hostnames and IPs with Unbound |
UNBLOCK |
i.e. domain1.com,x.domain2.co.uk |
Comma separated list of domain names to leave unblocked with Unbound | |
DNS_PLAINTEXT_ADDRESS |
1.1.1.1 |
Any IP address | IP address to use as DNS resolver if DOT is off |
DNS_KEEP_NAMESERVER |
off |
on or off |
Keep the nameservers in /etc/resolv.conf untouched, but disabled DNS blocking features |
Firewall
That one is important if you want to connect to the container from your LAN for example, using Shadowsocks or Tinyproxy.
| Variable | Default | Choices | Description |
|---|---|---|---|
FIREWALL |
on |
on or off |
Turn on or off the container built-in firewall. You should use it for debugging purposes only. |
EXTRA_SUBNETS |
i.e. 192.168.1.0/24,192.168.10.121,10.0.0.5/28 |
Comma separated subnets allowed in the container firewall | |
FIREWALL_DEBUG |
off |
on or off |
Prints every firewall related command. You should use it for debugging purposes only. |
Shadowsocks
| Variable | Default | Choices | Description |
|---|---|---|---|
SHADOWSOCKS |
off |
on, off |
Enable the internal SOCKS5 proxy Shadowsocks |
SHADOWSOCKS_LOG |
off |
on, off |
Enable logging |
SHADOWSOCKS_PORT |
8388 |
1024 to 65535 |
Internal port number for Shadowsocks to listen on |
SHADOWSOCKS_PASSWORD |
Password to use to connect to Shadowsocks | ||
SHADOWSOCKS_METHOD |
chacha20-ietf-poly1305 |
One of these ciphers | Method to use for Shadowsocks |
Tinyproxy
| Variable | Default | Choices | Description |
|---|---|---|---|
TINYPROXY |
off |
on, off |
Enable the internal HTTP proxy tinyproxy |
TINYPROXY_LOG |
Info |
Info, Connect, Notice, Warning, Error, Critical |
Tinyproxy log level |
TINYPROXY_PORT |
8888 |
1024 to 65535 |
Internal port number for Tinyproxy to listen on |
TINYPROXY_USER |
Username to use to connect to Tinyproxy | ||
TINYPROXY_PASSWORD |
Password to use to connect to Tinyproxy |
System
| Variable | Default | Choices | Description |
|---|---|---|---|
TZ |
i.e. Europe/London |
Specify a timezone to use to have correct log times | |
UID |
1000 |
User ID to run as non root and for ownership of files written | |
GID |
1000 |
Group ID to run as non root and for ownership of files written |
Other
| Variable | Default | Choices | Description |
|---|---|---|---|
PUBLICIP_PERIOD |
12h |
Valid duration | Period to check for public IP address. Set to 0 to disable. |
Connect to it
There are various ways to achieve this, depending on your use case.
-
Connect containers in the same docker-compose.yml as Gluetun
Add
network_mode: "service:gluetun"to your docker-compose.yml (no need fordepends_on) -
Connect other containers to Gluetun
Add
--network=container:gluetunwhen launching the container, provided Gluetun is already running -
Connect containers from another docker-compose.yml
Add
network_mode: "container:gluetun"to your docker-compose.yml, provided Gluetun is already running -
Connect LAN devices through the built-in HTTP proxy *Tinyproxy* (i.e. with Chrome, Kodi, etc.)
You might want to use Shadowsocks instead which tunnels UDP as well as TCP, whereas Tinyproxy only tunnels TCP.
- Setup a HTTP proxy client, such as SwitchyOmega for Chrome
- Ensure the Gluetun container is launched with:
- port
8888published-p 8888:8888/tcp - your LAN subnet, i.e.
192.168.1.0/24, set as-e EXTRA_SUBNETS=192.168.1.0/24
- port
- With your HTTP proxy client, connect to the Docker host (i.e.
192.168.1.10) on port8888. You need to enter your credentials if you set them withTINYPROXY_USERandTINYPROXY_PASSWORD. - If you set
TINYPROXY_LOGtoInfo, more information will be logged in the Docker logs
-
Connect LAN devices through the built-in SOCKS5 proxy *Shadowsocks* (per app, system wide, etc.)
- Setup a SOCKS5 proxy client, there is a list of ShadowSocks clients for all platforms
- note some clients do not tunnel UDP so your DNS queries will be done locally and not through Gluetun and its built in DNS over TLS
- Clients that support such UDP tunneling are, as far as I know:
- iOS: Potatso Lite
- OSX: ShadowsocksX
- Android: Shadowsocks by Max Lv
- Ensure the Gluetun container is launched with:
- port
8388published-p 8388:8388/tcp -p 8388:8388/udp - your LAN subnet, i.e.
192.168.1.0/24, set as-e EXTRA_SUBNETS=192.168.1.0/24
- port
- With your SOCKS5 proxy client
- Enter the Docker host (i.e.
192.168.1.10) as the server IP - Enter port TCP (and UDP, if available)
8388as the server port - Use the password you have set with
SHADOWSOCKS_PASSWORD - Choose the encryption method/algorithm to the method you specified in
SHADOWSOCKS_METHOD
- Enter the Docker host (i.e.
- If you set
SHADOWSOCKS_LOGtoon, (a lot) more information will be logged in the Docker logs
- Setup a SOCKS5 proxy client, there is a list of ShadowSocks clients for all platforms
-
Access ports of containers connected to Gluetun
In example, to access port
8000of containerxyzand9000of containerabcconnected to Gluetun, publish ports8000and9000for the Gluetun container and access them as you would with any other container -
Access ports of containers connected to Gluetun, all in the same docker-compose.yml
In example, to access port
8000of containerxyzand9000of containerabcconnected to Gluetun, publish port8000and9000for the Gluetun container. The docker-compose.yml file would look like:version: '3.7' services: gluetun: image: qmcgaw/private-internet-access container_name: gluetun cap_add: - NET_ADMIN environment: - USER=js89ds7 - PASSWORD=8fd9s239G ports: - 8000:8000/tcp - 9000:9000/tcp abc: image: abc container_name: abc network_mode: "service:gluetun" xyz: image: xyz container_name: xyz network_mode: "service:gluetun"
Private Internet Access port forwarding
Note that not all regions support port forwarding.
When PORT_FORWARDING=on, a port will be forwarded on the VPN server side and written to the file specified by PORT_FORWARDING_STATUS_FILE=/forwarded_port.
It can be useful to mount this file as a volume to read it from other containers, for example to configure a torrenting client.
HTTP control server
A built-in HTTP server listens on port 8000 to modify the state of the container. You have the following routes available:
http://<your-docker-host-ip>:8000/openvpn/actions/restartrestarts the openvpn processhttp://<your-docker-host-ip>:8000/unbound/actions/restartre-downloads the DNS files (crypto and block lists) and restarts the unbound process
Development and contributing
- Contribute with code: see the Wiki.
- The list of existing contributors 👍
- Github workflows to know what's building
- List of issues and feature requests
License
This repository is under an MIT license
Support
Sponsor me on Github, donate to paypal.me/qmcgaw or subscribe to a VPN provider through one of my affiliate links:
Feel also free to have a look at the Kanban board and contribute to the code or the issues discussion.
Many thanks to @Frepke, @Ralph521, G. Mendez, M. Otmar Weber, J. Perez and A. Cooper for supporting me financially 🥇👍


