Private Internet Access Client (OpenVPN+Iptables+DNS over TLS on Alpine Linux)
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_MALICIOUSandBLOCK_NSAenvironment variables)
Features
-
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
Setup
-
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/tunis 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-accessor use docker-compose.yml with:
docker-compose up -dNote that you can change all the environment variables
Testing
Check the PIA IP address matches your expectations
docker run --rm --network=container:pia alpine:3.9 wget -qO- https://ipinfo.io
Environment variables
| 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 |
Connect to it
There are various ways to achieve this, depending on your use case.
-
Connect other containers to PIA
Add
--network=container:piawhen launching the container -
Connect containers from another docker-compose.yml
Add
network_mode: "container:pia"to your docker-compose.yml -
Access ports of containers connected to PIA
To access port
8000of containerxyzand9000of containerabcconnected to PIA, you will need a reverse proxy such asqmcgaw/caddy-scratch-
Create the file Caddyfile with:
:8000 { proxy / xyz:8000 } :9000 { proxy / abc:9000 }You can of course make more complicated Caddyfile (such as proxying
/xyzto xyz:8000 and/abcto 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-scratchWARNING: Make sure the Docker network in which Caddy runs is the same as the one of PIA. It can be the default
bridgenetwork. -
You can now access xyz:8000 at localhost:8000 and abc:9000 at localhost:9000
For more containers, add more
--link pia:xxxand modify nginx.conf accordinglyIf you want to user a docker-compose.yml, use this example:
version: '3' services: piaproxy: image: qmcgaw/caddy-scratch container_name: piaproxy ports: - 8000:8000/tcp - 9000:9000/tcp external_links: - pia:xzy - 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
8000of containerxyzand9000of containerabcconnected to PIA, you can put all the configuration in one single docker-compose.yml file. According to issue 21, this should do (untested):version: '3' services: pia: image: qmcgaw/private-internet-access container_name: pia cap_add: - NET_ADMIN devices: - /dev/net/tun environment: - USER= - PASSWORD= - REGION= abc: image: abc container_name: abc network_mode: "service:pia" ports: - 8000:8000/tcp xyz: image: xyz container_name: xyz network_mode: "service:pia" ports: - 9000:9000/tcp
For the paranoids
-
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)
TODOs
- SOCKS/HTTP proxy or VPN server for LAN devices to use the container
- Port forwarding
- Nginx scratch
License
This repository is under an MIT license
