Private internet access openvpn client in a lightweight Docker container
Clone or download
qdm12 Changed healthcheck to only ping to check connectivity
This is because your VPN public IP might not be the VPN server entrance IP address, resulting in the container being unhealthy most of the time.
Latest commit a3bfa2d Jan 15, 2019

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
17.1MB 14MB to 80MB Low to Medium

Three tags:

  • qmcgaw/private-internet-access for x86/amd64
  • qmcgaw/private-internet-access:arm32v6 for arm 32 bit v6 (Raspberry Pi)
  • qmcgaw/private-internet-access:arm64v8 for arm 64 bit v8

It is based on:

Extra features

  • Configure everything with environment variables
    • Destination region
    • Internet protocol
    • Level of encryption
    • Username and password
    • Malicious DNS blocking
    • Extra subnets allowed by firewall
  • Connect other containers to it
  • The iptables firewall allows traffic only with needed PIA servers (IP addresses, port, protocol) combination
  • OpenVPN restarts on failure using another PIA IP address for the same region
  • Docker healthcheck uses to check that the current public IP address exists in the selected OpenVPN configuration file
  • Openvpn and Unbound do not run as root


  • A Private Internet Access username and password - Sign up
  • Docker installed on the host
  • If you use a strict firewall on the host/router:
    • Allow outbound TCP 853 to 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


  1. Make sure you have your /dev/net/tun device setup on your host with one of the following commands, depending on your OS:

    insmod /lib/modules/tun.ko


    modprobe tun
  2. Launch the container with:

    docker run -d --name=pia -v ./auth.conf:/auth.conf:ro \
    --cap-add=NET_ADMIN --device=/dev/net/tun --network=pianet \
    -e REGION="CA Montreal" -e PROTOCOL=udp -e ENCRYPTION=strong \
    -e USER=js89ds7 -e PASSWORD=8fd9s239G \

    or use docker-compose.yml with:

    docker-compose up -d

    Note that you can change all the environment variables

  3. Wait about 5 seconds for it to connect to the PIA server. You can check with:

    docker logs -f pia
  4. Follow the Testing section


You can simply use the Docker healthcheck. The container will mark itself as unhealthy if the public IP address is not part of the PIA IPs. Otherwise you can follow these instructions:

  1. Check your host IP address with:

    wget -qO-
  2. Run the same command in a Docker container using your pia container as network with:

    docker run --rm --network=container:pia alpine:3.8 wget -qO-

    If the displayed IP address appears and is different that your host IP address, the PIA client works !

Environment variables

Environment variable Default Description
REGION CA Montreal One of the PIA regions
PROTOCOL udp tcp or udp
ENCRYPTION strong normal or strong
BLOCK_MALICIOUS off on or off
USER Your PIA username
PASSWORD Your PIA password
EXTRA_SUBNETS Comma separated subnets allowed in the container firewall

EXTRA_SUBNETS can be in example:,,

Connect other containers to it

Connect other Docker containers to the PIA VPN connection by adding --network=container:pia when launching them.

For containers in the same docker-compose.yml as PIA, you can use network: "service:pia (see below)

Access ports of PIA-connected containers

General case

  1. For example, the following containers are launched connected to PIA:

    docker run -d --name=deluge --network=container:pia linuxserver/deluge
    docker run -d --name=hydra --network=container:pia linuxserver/hydra

    We want to access: - The HTTP web UI of Deluge at port 8112 - The HTTP Web UI of Hydra at port 5075

  2. In this case we use Nginx for its small size. Create ./nginx.conf with:

    # nginx.conf
    user nginx;
    worker_processes 1;
    events {
      worker_connections 64;
    http {
      server {
        listen 8000;
        location /deluge {
          proxy_pass http://deluge:8112/;
          proxy_set_header X-Deluge-Base "/deluge";
      server {
        listen 8001;
        location / {
          proxy_pass http://hydra:5075/;
  3. Run the Nginx Alpine container:

    docker run -d -p 8001:8001/tcp -p 8002:8002/tcp \
    --link pia:deluge --link pia:hydra \
    -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \

    WARNING: Make sure the Docker network in which Nginx runs is the same as the one of PIA. It can be the default bridge network.

  4. Access the WebUI of Deluge at localhost:8000 and Hydra at localhost:8001

For more containers, add more --link pia:xxx and modify nginx.conf accordingly

Containers with PIA in one docker-compose.yml

This is simpler but restrictive in terms of management as all containers must be in the same docker-compose.yml.

For example, the following file

version: '3'
    image: qmcgaw/private-internet-access
    container_name: pia
      - NET_ADMIN
      - /dev/net/tun
    network_mode: bridge
      - 8112:8112/tcp
      - USER=js89ds7
      - PASSWORD=8fd9s239G
      - PROTOCOL=udp
      - ENCRYPTION=strong
      - REGION=CA Montreal
    restart: always
    image: linuxserver/deluge
      - pia
    network_mode: "service:pia"
    restart: always

will publish port 8112 as Deluge WebUI without any trouble.

For the paranoids

  • You can review the code which essential consits in the Dockerfile and

  • Build the images yourself:

    docker build -t qmcgaw/private-internet-access
  • 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


  • Travis CI for arm images
  • Nginx scratch
  • SOCKS proxy/Hiproxy/VPN server for other devices to use the container
  • Port forwarding


This repository is under an MIT license