2020-03-04 23:52:41 +00:00
2019-12-14 17:59:25 -05:00
2020-02-29 21:05:20 -05:00
2019-11-24 11:04:37 -05:00
2020-02-25 11:47:08 +00:00
2020-02-22 17:07:06 +00:00
2020-02-22 17:43:17 +00:00
2020-03-01 02:03:57 +00:00
2020-03-01 02:03:57 +00:00
2019-12-20 07:28:33 -05:00

Private Internet Access Client

Lightweight swiss-knife-like VPN client to tunnel to Private Internet Access or Mullvad VPN servers, using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and Tinyproxy

ANNOUNCEMENT: Support for Mullvad

Build Status Docker Pulls Docker Stars

GitHub last commit GitHub commit activity GitHub issues

Image size Image version Join Slack channel

Click to show base components

Features

  • Based on Alpine 3.11 for a small Docker image below 50MB
  • Supports Private Internet Access and Mullvad 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, ppc64le and even that s390x 🎆

Private Internet Access

  • Pick the region
  • Pick the level of encryption
  • Enable port forwarding

Mullvad

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

  1. Requirements

    • 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 Private Internet Access username and password (sign up) or Mullvad user ID (sign up)

    • External firewall requirements, if you have one

      • At start only
        • Allow outbound TCP 443 to github.com
        • If DOT=on, allow outbound TCP 853 to allow Unbound to resolve github.com and the PIA subdomain name if you use PIA.
        • If DOT=off and VPNSP=pia, allow outbound UDP 53 to your DNS provider to resolve the PIA subdomain name.
      • If VPNSP=pia, ENCRYPTION=strong and PROTOCOL=udp: allow outbound UDP 1197 to the corresponding VPN server IPs
      • If VPNSP=pia, ENCRYPTION=normal and PROTOCOL=udp: allow outbound UDP 1198 to the corresponding VPN server IPs
      • If VPNSP=pia, ENCRYPTION=strong and PROTOCOL=tcp: allow outbound TCP 501 to the corresponding VPN server IPs
      • If VPNSP=pia, ENCRYPTION=normal and PROTOCOL=tcp: allow outbound TCP 502 to the corresponding VPN server IPs
      • If VPNSP=mullvad and PORT=, please refer to the mapping of Mullvad servers in these source code lines to find the corresponding UDP port number and IP address(es) of your choice
      • If VPNSP=mullvad and PORT=53, allow outbound UDP 53 to the corresponding VPN server IPs, which you can fine in the mapping of Mullvad servers
      • If VPNSP=mullvad and PORT=80, allow outbound TCP 80 to the corresponding VPN server IPs, which you can fine in the mapping of Mullvad servers
      • If VPNSP=mullvad and PORT=443, allow outbound TCP 443 to the corresponding VPN server IPs, which you can fine in the mapping of Mullvad servers
      • If SHADOWSOCKS=on, allow inbound TCP 8388 and UDP 8388 from your LAN
      • If TINYPROXY=on, allow inbound TCP 8888 from your LAN

  2. 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)
    • Use -p 8388:8388/tcp -p 8388:8388/udp to access the SOCKS5 proxy (and put your LAN in EXTRA_SUBNETS environment variable)
    • Pass additional arguments to openvpn using Docker's command function (commands after the image name)
  3. 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

Environment variable Default Description
VPNSP pia VPN Service Provider, one of pia, mullvad
REGION CA Montreal (PIA only) one of the PIA regions
COUNTRY Sweden (Mullvad only) one of the Mullvad countries
CITY (Mullvad only, optional) one of the Mullvad cities
ISP (Mullvad only, optional) one of the Mullvad ISP
PORT (Mullvad only, optional) For TCP, 80 or 443, or 53 for UDP. Leave blank for default Mullvad server port
PROTOCOL udp tcp or udp
ENCRYPTION strong (PIA only) normal or strong
USER PIA username or Mullvad user ID
PASSWORD Your PIA password
DOT on on or off, to activate DNS over TLS to 1.1.1.1
DOT_PROVIDERS cloudflare Comma delimited list of DNS over TLS providers from cloudflare, google, quad9, quadrant, cleanbrowsing, securedns, libredns
DOT_CACHING on Unbound caching feature, on or off
DOT_PRIVATE_ADDRESS All IPv4 and IPv6 CIDRs private ranges Comma separated list of CIDRs or single IP addresses. Note that the default setting prevents DNS rebinding
DOT_VERBOSITY 1 Unbound verbosity level from 0 to 5 (full debug)
DOT_VERBOSITY_DETAILS 0 Unbound details verbosity level from 0 to 4
DOT_VALIDATION_LOGLEVEL 0 Unbound validation log level from 0 to 2
BLOCK_MALICIOUS on on or off, blocks malicious hostnames and IPs
BLOCK_SURVEILLANCE off on or off, blocks surveillance hostnames and IPs
BLOCK_ADS off on or off, blocks ads hostnames and IPs
UNBLOCK comma separated string (i.e. web.com,web2.ca) to unblock hostnames
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)
PORT_FORWARDING off (PIA only) Set to on to forward a port on PIA server
PORT_FORWARDING_STATUS_FILE /forwarded_port (PIA only) File path to store the forwarded port number
TINYPROXY off on or off, to enable the internal HTTP proxy tinyproxy
TINYPROXY_LOG Info Info, Connect, Notice, Warning, Error or Critical
TINYPROXY_PORT 8888 1024 to 65535 internal port for HTTP proxy
TINYPROXY_USER Username to use to connect to the HTTP proxy
TINYPROXY_PASSWORD Passsword to use to connect to the HTTP proxy
SHADOWSOCKS off on or off, to enable the internal SOCKS5 proxy Shadowsocks
SHADOWSOCKS_LOG off on or off to enable logging for Shadowsocks
SHADOWSOCKS_PORT 8388 1024 to 65535 internal port for SOCKS5 proxy
SHADOWSOCKS_PASSWORD Passsword to use to connect to the SOCKS5 proxy
TZ Specify a timezone to use i.e. Europe/London
OPENVPN_VERBOSITY 1 Openvpn verbosity level from 0 to 6

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.

    1. Setup a HTTP proxy client, such as SwitchyOmega for Chrome
    2. 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
    3. 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.
    4. 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.)

    1. 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
    2. 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
    3. 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 chacha20-ietf-poly1305
    4. 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

Private Internet Access: Why do I see openvpn warnings at start?

You might see some warnings similar to:

openvpn: Sat Feb 22 15:55:02 2020 WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this
openvpn: Sat Feb 22 15:55:02 2020 WARNING: 'link-mtu' is used inconsistently, local='link-mtu 1569', remote='link-mtu 1542'
openvpn: Sat Feb 22 15:55:02 2020 WARNING: 'cipher' is used inconsistently, local='cipher AES-256-CBC', remote='cipher BF-CBC'
openvpn: Sat Feb 22 15:55:02 2020 WARNING: 'auth' is used inconsistently, local='auth SHA256', remote='auth SHA1'
openvpn: Sat Feb 22 15:55:02 2020 WARNING: 'keysize' is used inconsistently, local='keysize 256', remote='keysize 128'
openvpn: Sat Feb 22 15:55:02 2020 WARNING: 'comp-lzo' is present in remote config but missing in local config, remote='comp-lzo'
openvpn: Sat Feb 22 15:55:02 2020 [a121ce520d670b71bfd3aa475485539b] Peer Connection Initiated with [AF_INET]xx.xx.xx.xx:1197

It is mainly because the option disable-occ was removed for transparency with you.

Private Internet Access explains here why the warnings show up.

What files does it download at start before tunneling?

At start, the Go entrypoint only downloads, depending on your settings:

How to build Docker images of older or alternate versions

First, install Git.

The following will build the Docker image locally and replace the previous one you built or pulled.

  • Build the latest image

    docker build -t qmcgaw/private-internet-access https://github.com/qdm12/private-internet-access-docker.git
    
  • Find a commit you want to build for, in example 095623925a9cc0e5cf89d5b9b510714792267d9b, then:

    docker build -t qmcgaw/private-internet-access https://github.com/qdm12/private-internet-access-docker.git#095623925a9cc0e5cf89d5b9b510714792267d9b
    
  • Find a branch you want to build for, in example mullvad, then:

    docker build -t qmcgaw/private-internet-access https://github.com/qdm12/private-internet-access-docker.git#mullvad
    

What's all this Go code?

The Go code is a big rewrite of the previous shell entrypoint, it allows for:

  • better testing
  • better maintainability
  • ease of implementing new features
  • faster boot
  • asynchronous/parallel operations

It is mostly made of the internal directory and the entry Go file cmd/main.go.

How to test DNS over TLS?

How to fix OpenVPN failing to start?

You can try:

  • Installing the tun kernel module on your host with insmod /lib/modules/tun.ko or modprobe tun
  • Adding --device=/dev/net/tun to your docker run command (equivalent for docker-compose, kubernetes, etc.)

Development

Using VSCode and Docker

  1. Install Docker
    • On Windows, share a drive with Docker Desktop and have the project on that partition
  2. With Visual Studio Code, install the remote containers extension
  3. In Visual Studio Code, press on F1 and select Remote-Containers: Open Folder in Container...
  4. Your dev environment is ready to go!... and it's running in a container 👍

The Go code is in the Go file cmd/main.go and the internal directory, you might want to start reading the main.go file.

Contributors

Thanks for all the contributions, wether small or not so small!

TODOs

Expand me

  • Support Windscribe
  • Gotify support for notificactions
  • Periodic update of malicious block lists with Unbound restart
  • Improve healthcheck
    • Check IP address belongs to selected region
    • Check for DNS provider somehow if this is even possible
  • Support for other VPN protocols
    • Wireguard (wireguard-go)
  • Show new versions/commits available at start
  • Colors & emojis
    • Setup
    • Logging streams
  • More unit tests
  • Write in Go

License

This repository is under an MIT license

Description
VPN client in a thin Docker container for multiple VPN providers, written in Go, and using OpenVPN or Wireguard, DNS over TLS, with a few proxy servers built-in.
Readme MIT 33 MiB
Languages
Go 99.4%
Dockerfile 0.6%