Lightweight VPN client to tunnel to private internet access servers
Image size | RAM usage | CPU usage |
---|---|---|
19.6MB | 14MB to 80MB | Low to Medium |
Click to show base components
- Alpine 3.9 for a tiny image
- OpenVPN 2.4.6-r3 to tunnel to PIA servers
- IPtables 1.6.2-r0 enforces the container to communicate only through the VPN or with other containers in its virtual network (acts as a killswitch)
- Unbound 1.7.3-r0 configured with Cloudflare's 1.1.1.1 DNS over TLS
- Files and blocking lists built periodically used with Unbound (see
BLOCK_MALICIOUS
andBLOCK_NSA
environment variables)
-
Configure everything with environment variables
- Destination region
- Internet protocol
- Level of encryption
- Username and password
- Malicious DNS blocking
- Extra subnets allowed by firewall
- Run openvpn without root (but will give reconnect problems)
-
Connect other containers to it (and thus computers, see this)
-
The iptables firewall allows traffic only with needed PIA servers (IP addresses, port, protocol) combinations
-
OpenVPN restarts on failure using another PIA IP address for the same region encryption combination
-
Docker healthcheck pings the DNS 1.1.1.1 to verify the connection is up
-
Openvpn and Unbound run without root
-
Requirements
- A Private Internet Access username and password - Sign up
- Firewall requirements
- Allow outbound TCP 853 to 1.1.1.1 to allow Unbound to resolve the PIA domain name at start. You can then block it once the container is started.
- For UDP strong encryption, allow outbound UDP 1197
- For UDP normal encryption, allow outbound UDP 1198
- For TCP strong encryption, allow outbound TCP 501
- For TCP normal encryption, allow outbound TCP 502
-
Ensure
/dev/net/tun
is setup on your host with either:insmod /lib/modules/tun.ko # or... modprobe tun
-
CLICK IF YOU HAVE AN ARM DEVICE
-
If you have a ARM 32 bit v6 architecture
docker build -t qmcgaw/private-internet-access \ --build-arg BASE_IMAGE=arm32v6/alpine \ https://github.com/qdm12/private-internet-access-docker.git
-
If you have a ARM 32 bit v7 architecture
docker build -t qmcgaw/private-internet-access \ --build-arg BASE_IMAGE=arm32v7/alpine \ https://github.com/qdm12/private-internet-access-docker.git
-
If you have a ARM 64 bit v8 architecture
docker build -t qmcgaw/private-internet-access \ --build-arg BASE_IMAGE=arm64v8/alpine \ https://github.com/qdm12/private-internet-access-docker.git
-
-
Launch the container with:
docker run -d --name=pia --cap-add=NET_ADMIN --device=/dev/net/tun \ -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 all the environment variables
Check the PIA IP address matches your expectations
docker run --rm --network=container:pia alpine:3.9 wget -qO- https://ipinfo.io
Environment variable | Default | Description |
---|---|---|
REGION |
CA Montreal |
One of the PIA regions |
PROTOCOL |
udp |
tcp or udp |
ENCRYPTION |
strong |
normal or strong |
USER |
Your PIA username | |
PASSWORD |
Your PIA password | |
NONROOT |
no |
Run OpenVPN without root, yes or no |
EXTRA_SUBNETS |
comma separated subnets allowed in the container firewall (i.e. 192.168.1.0/24,192.168.10.121,10.0.0.5/28 ) |
|
BLOCK_MALICIOUS |
off |
on or off , blocks malicious hostnames and IPs |
BLOCK_NSA |
off |
on or off , blocks NSA hostnames |
UNBLOCK |
comma separated string (i.e. web.com,web2.ca ) to unblock hostnames |
There are various ways to achieve this, depending on your use case.
-
Connect other containers to PIA
Add
--network=container:pia
when launching the container -
Connect containers from another docker-compose.yml
Add
network_mode: "container:pia"
to your docker-compose.yml -
Connect containers in the same docker-compose.yml as PIA
Add
network_mode: "service:pia"
to your docker-compose.yml (no need fordepends_on
) -
Access ports of containers connected to PIA
To access port
8000
of containerxyz
and9000
of containerabc
connected to PIA, you will need a reverse proxy such asqmcgaw/caddy-scratch
(you can build it for ARM, see its readme)-
Create the file Caddyfile
touch Caddyfile chown 1000 Caddyfile # chown 1000 because caddy-scratch runs as user ID 1000 by default chmod 600 Caddyfile
with this content:
:8000 { proxy / xyz:8000 } :9000 { proxy / abc:9000 }
You can of course make more complicated Caddyfile (such as proxying
/xyz
to xyz:8000 and/abc
to abc:9000, just ask me!) -
Run Caddy with
docker run -d -p 8000:8000/tcp -p 9000:9000/tcp \ --link pia:xyz --link pia:abc \ -v $(pwd)/Caddyfile:/Caddyfile:ro \ qmcgaw/caddy-scratch
WARNING: Make sure the Docker network in which Caddy runs is the same as the one of PIA. It can be the default
bridge
network. -
You can now access xyz:8000 at localhost:8000 and abc:9000 at localhost:9000
For more containers, add more
--link pia:xxx
and modify the Caddyfile accordinglyIf you want to user a docker-compose.yml, you can use this example - make sure PIA is launched and connected first:
version: '3' services: piaproxy: image: qmcgaw/caddy-scratch container_name: piaproxy ports: - 8000:8000/tcp - 9000:9000/tcp external_links: - pia:xyz - pia:abc volumes: - ./Caddyfile:/Caddyfile:ro abc: image: abc container_name: abc network_mode: "container:pia" xyz: image: xyz container_name: xyz network_mode: "container:pia"
-
-
Access ports of containers connected to PIA, all in the same docker-compose.yml
To access port
8000
of containerxyz
and9000
of containerabc
connected to PIA, you could use:version: '3' services: pia: image: qmcgaw/private-internet-access container_name: pia cap_add: - NET_ADMIN devices: - /dev/net/tun 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"
-
Access ports of containers connected to PIA, all in the same docker-compose.yml, using a reverse proxy
To access port
8000
of containerxyz
and9000
of containerabc
connected to PIA, you will need a reverse proxy such asqmcgaw/caddy-scratch
(you can build it for ARM, see its readme)-
Create the file Caddyfile
touch Caddyfile chown 1000 Caddyfile # chown 1000 because caddy-scratch runs as user ID 1000 by default chmod 600 Caddyfile
with this content:
:8000 { proxy / xyz:8000 } :9000 { proxy / abc:9000 }
You can of course make more complicated Caddyfile (such as proxying
/xyz
to xyz:8000 and/abc
to abc:9000, just ask me!) -
Use this example:
version: '3' services: pia: image: qmcgaw/private-internet-access container_name: pia cap_add: - NET_ADMIN devices: - /dev/net/tun environment: - USER=js89ds7 - PASSWORD=8fd9s239G piaproxy: image: qmcgaw/caddy-scratch container_name: piaproxy ports: - 8000:8000/tcp - 9000:9000/tcp external_links: - pia:xyz - pia:abc volumes: - ./Caddyfile:/Caddyfile:ro abc: image: abc container_name: abc network_mode: "service:pia" xyz: image: xyz container_name: xyz network_mode: "service:pia"
-
-
Connect to the PIA through an HTTP proxy (i.e. with Firefox)
This is in progress, using Tiny Proxy, thanks for waiting !
-
You can review the code which essential consists in the Dockerfile and entrypoint.sh
-
Build the images yourself:
docker build -t qmcgaw/private-internet-access https://github.com/qdm12/private-internet-access-docker.git
-
The download and unziping of PIA openvpn files is done at build for the ones not able to download the zip files
-
Checksums for PIA openvpn zip files are not used as these files change often (but HTTPS is used)
-
Use
-e ENCRYPTION=strong -e BLOCK_MALICIOUS=on
-
DNS Leaks tests might not work because of this (TLDR: DNS server is a local caching intermediary)
- Tiny proxy for LAN devices to use the container
- Port forwarding
This repository is under an MIT license