Private Internet Access Client (OpenVPN+Iptables+DNS over TLS on Alpine Linux)

Lightweight VPN client to tunnel to private internet access servers

PIA Docker OpenVPN

Build Status Docker Build Status

GitHub last commit GitHub commit activity GitHub issues

Docker Pulls Docker Stars Docker Automated

Image size Image version

Donate PayPal

Image size RAM usage CPU usage
19.6MB 14MB to 80MB Low to Medium
Click to show base components

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

  1. 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

  2. Ensure /dev/net/tun is setup on your host with either:

    insmod /lib/modules/tun.ko
    # or...
    modprobe tun
    
  3. 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
      

  4. 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

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:pia when 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 8000 of container xyz and 9000 of container abc connected to PIA, you will need a reverse proxy such as qmcgaw/caddy-scratch

    1. Create the file Caddyfile with:

      :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!)

    2. 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.

    3. 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 nginx.conf accordingly

    If 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 8000 of container xyz and 9000 of container abc connected 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

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%