Gluetun VPN client
Lightweight swiss-knife-like VPN client to tunnel to Private Internet Access, Mullvad and Windscribe VPN servers, using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and Tinyproxy
ANNOUNCEMENT: Support for Windscribe



Click to show base components
Features
- Based on Alpine 3.11 for a small Docker image below 50MB
- Supports Private Internet Access, Mullvad and Windscribe servers
- DNS over TLS baked in with service provider(s) of your choice
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses
- Choose the vpn network protocol,
udp or tcp
- Built in firewall kill switch to allow traffic only with needed PIA 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 π
Private Internet Access
- Pick the region
- Pick the level of encryption
- Enable port forwarding
Mullvad
Windscribe
- 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
-
Ideally, Docker 1.13, in order to have Docker API 1.25 which supports init (and, if you use docker-compose, docker-compose version 1.22.0)
-
A VPN account with one of the service providers:
-
Private Internet Access: username and password
-
Mullvad: user ID (sign up)
-
Windscribe: username and password | Signup up using my affiliate link below

-
If you have a host or router firewall, please refer to the firewall documentation
-
Launch the container with:
docker run -d --init --name=pia --cap-add=NET_ADMIN \
-e REGION="CA Montreal" -e USER=js89ds7 -e PASSWORD=8fd9s239G \
qmcgaw/private-internet-access
or use docker-compose.yml with:
docker-compose up -d
Note that you can:
- Change the many environment variables available
- Use
-p 8888:8888/tcp to access the HTTP web proxy (and put your LAN in EXTRA_SUBNETS environment variable, in example 192.168.1.0/24)
- Use
-p 8388:8388/tcp -p 8388:8388/udp to access the SOCKS5 proxy (and put your LAN in EXTRA_SUBNETS environment variable, in example 192.168.1.0/24)
- Pass additional arguments to openvpn using Docker's command function (commands after the image name)
-
You can update the image with docker pull qmcgaw/private-internet-access:latest. There are also docker tags for older versions available:
qmcgaw/private-internet-access:v2 linked to the v2 release (Golang based, only PIA)
qmcgaw/private-internet-access:v1 linked to the v1 release (shell scripting based, no support, only PIA)
qmcgaw/private-internet-access:old tag, which is the latest shell scripting version (shell scripting based, no support, only PIA)
Testing
Check the PIA IP address matches your expectations
docker run --rm --network=container:pia alpine:3.11 wget -qO- https://ipinfo.io
Environment variables
Note: VPNSP means VPN service provider
| Environment variable |
Default |
Properties |
PIA |
Mullvad |
Windscribe |
Description |
Choices |
VPNSP |
private internet access |
|
β
|
β
|
β
|
VPN Service Provider |
private internet access, mullvad, windscribe |
REGION |
Austria |
|
β
|
β |
β
|
VPN server region |
One of the PIA regions or of the Windscribe regions |
COUNTRY |
Sweden |
Optional |
β |
β
|
β |
VPN server country |
One of the Mullvad countries |
CITY |
|
Optional |
β |
β
|
β |
VPN server city |
One of the Mullvad cities |
ISP |
|
Optional |
β |
β
|
β |
VPN server ISP |
One of the Mullvad ISP |
PORT |
|
Optional |
β |
β
|
β
|
Custom VPN port to use |
Mullvad: 80 or 443 for TCP; or 53 for UDP. Leave blank for default Mullvad server port. Windscribe see this list of ports |
PROTOCOL |
udp |
|
β
|
β
|
β
|
Network protocol to use |
tcp, udp |
PIA_ENCRYPTION |
strong |
|
β
|
β |
β |
Encryption preset |
normal, strong |
USER |
|
To fill |
β
|
β
|
β
|
PIA/Windscribe username or Mullvad user ID |
|
PASSWORD |
|
To fill |
β
|
β |
β
|
PIA/Windscribe password |
|
DOT |
on |
|
β
|
β
|
β
|
Activate DNS over TLS |
on, off |
DOT_PROVIDERS |
cloudflare |
|
β
|
β
|
β
|
Comma delimited list of DNS over TLS providers |
cloudflare, google, quad9, quadrant, cleanbrowsing, securedns, libredns |
DOT_CACHING |
on |
|
β
|
β
|
β
|
DNS over TLS Unbound caching |
on, off |
DOT_IPV6 |
on |
|
β
|
β
|
β
|
DNS over TLS IPv6 resolution |
on, off |
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 |
|
β
|
β
|
β
|
DNS over TLS Unbound verbosity level |
0, 1, 2, 3, 4, 5 |
DOT_VERBOSITY_DETAILS |
0 |
|
β
|
β
|
β
|
Unbound details verbosity level |
0, 1, 2, 3, 4 |
DOT_VALIDATION_LOGLEVEL |
0 |
|
β
|
β
|
β
|
Unbound validation log level |
0, 1, 2 |
BLOCK_MALICIOUS |
on |
|
β
|
β
|
β
|
Block malicious hostnames and IPs with Unbound DNS over TLS |
on, off |
BLOCK_SURVEILLANCE |
off |
|
β
|
β
|
β
|
Block surveillance hostnames and IPs with Unbound DNS over TLS |
on, off |
BLOCK_ADS |
off |
|
β
|
β
|
β
|
Block ads hostnames and IPs with Unbound DNS over TLS |
on, off |
UNBLOCK |
|
Optional |
β
|
β
|
β
|
Comma separated list of domain names to leave unblocked |
In example domain1.com,x.domain2.co.uk |
EXTRA_SUBNETS |
|
Optional |
β
|
β
|
β
|
Comma separated subnets allowed in the container firewall |
In example 192.168.1.0/24,192.168.10.121,10.0.0.5/28 |
PORT_FORWARDING |
off |
|
β
|
β |
β |
Enable port forwarding on the VPN server |
on, off |
PORT_FORWARDING_STATUS_FILE |
/forwarded_port |
|
β
|
β |
β |
File path to store the forwarded port number |
Any valid file path |
IP_STATUS_FILE |
/ip |
|
β
|
β
|
β
|
File path to store the public IP address assigned |
Any valid file path |
TINYPROXY |
off |
|
β
|
β
|
β
|
Enable the internal HTTP proxy tinyproxy |
on, off |
TINYPROXY_LOG |
Info |
|
β
|
β
|
β
|
Tinyproxy log level |
Info, Connect, Notice, Warning, Error, Critical |
TINYPROXY_PORT |
8888 |
|
β
|
β
|
β
|
Internal port number for Tinyproxy to listen on |
1024 to 65535 |
TINYPROXY_USER |
|
|
β
|
β
|
β
|
Username to use to connect to the HTTP proxy |
|
TINYPROXY_PASSWORD |
|
|
β
|
β
|
β
|
Password to use to connect to the HTTP proxy |
|
SHADOWSOCKS |
off |
|
β
|
β
|
β
|
Enable the internal SOCKS5 proxy Shadowsocks |
on, off |
SHADOWSOCKS_LOG |
off |
|
β
|
β
|
β
|
Enable Shadowsocks logging |
on, off |
SHADOWSOCKS_PORT |
8388 |
|
β
|
β
|
β
|
Internal port number for Shadowsocks to listen on |
1024 to 65535 |
SHADOWSOCKS_PASSWORD |
|
|
β
|
β
|
β
|
Passsword to use to connect to the SOCKS5 proxy |
|
SHADOWSOCKS_METHOD |
chacha20-ietf-poly1305 |
|
β
|
β
|
β
|
Method to use for Shadowsocks |
One of these ciphers |
TZ |
|
Optional |
β
|
β
|
β
|
Specify a timezone to use |
In example Europe/London |
OPENVPN_VERBOSITY |
1 |
|
β
|
β
|
β
|
Openvpn verbosity level |
0, 1, 2, 3, 4, 5, 6 |
OPENVPN_ROOT |
no |
|
β
|
β
|
β
|
Run OpenVPN as root |
yes, no |
OPENVPN_TARGET_IP |
|
Optional |
β
|
β
|
β
|
Specify a target VPN server IP address to use |
In example 199.65.55.100 |
OPENVPN_CIPHER |
|
Optional |
β
|
β
|
β
|
Specify a custom cipher to use. It will also set ncp-disable if using AES GCM for PIA |
In example aes-256-gcm |
OPENVPN_AUTH |
|
Optional |
β
|
β |
β
|
Specify a custom auth algorithm to use |
In example sha256 |
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 |
|
Connect to it
There are various ways to achieve this, depending on your use case.
-
Connect containers in the same docker-compose.yml as PIA
Add network_mode: "service:pia" to your docker-compose.yml (no need for depends_on)
-
Connect other containers to PIA
Add --network=container:pia when launching the container, provided PIA is already running
-
Connect containers from another docker-compose.yml
Add network_mode: "container:pia" to your docker-compose.yml, provided PIA 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 PIA container is launched with:
- port
8888 published -p 8888:8888/tcp
- your LAN subnet, i.e.
192.168.1.0/24, set as -e EXTRA_SUBNETS=192.168.1.0/24
- With your HTTP proxy client, connect to the Docker host (i.e.
192.168.1.10) on port 8888. You need to enter your credentials if you set them with TINYPROXY_USER and TINYPROXY_PASSWORD.
- If you set
TINYPROXY_LOG to Info, 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 PIA 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 PIA container is launched with:
- port
8388 published -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
- 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)
8388 as 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
- If you set
SHADOWSOCKS_LOG to on, (a lot) more information will be logged in the Docker logs
-
Access ports of containers connected to PIA
In example, to access port 8000 of container xyz and 9000 of container abc connected to PIA,
publish ports 8000 and 9000 for the PIA container and access them as you would with any other container
-
Access ports of containers connected to PIA, all in the same docker-compose.yml
In example, to access port 8000 of container xyz and 9000 of container abc connected to PIA, publish port 8000 and 9000 for the PIA container.
The docker-compose.yml file would look like:
version: '3.7'
services:
pia:
image: qmcgaw/private-internet-access
container_name: pia
init: true
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:pia"
xyz:
image: xyz
container_name: xyz
network_mode: "service:pia"
Private Internet Access port forwarding
Note that not all regions support port forwarding.
When PORT_FORWARDING=on, a port will be forwarded on the PIA 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.
FAQ
Please refer to the FAQ table of content
Development and contributing
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 @Ralph521 for supporting me financially π₯π