Coder Social home page Coder Social logo

docker-wireguard-pia's Introduction

docker-wireguard-pia

A Docker container for using WireGuard with PIA.

Requirements

  • Ideally the host must already support WireGuard. Pre 5.6 kernels may need to have the module manually installed. wg-quick should automatically fall back to a userspace implementation (wireguard-go) if the kernel module is missing, however the container may need access to the /dev/net/tun device for this to work.
  • An active PIA subscription.

Config

The following ENV vars are required:

ENV Var Function
LOC=swiss Location id to connect to. Available server location ids are listed here. Example values include us_california, ca_ontario, and swiss. If left empty the container will print out all currently available location ids and exit.
Multiple ids can be listed, separated by either a space or a comma, and are used as fallback if the initial endpoint registration fails.
USER=xxxxxxxx PIA username
PASS=xxxxxxxx PIA password

The rest are optional:

ENV Var Function
LOCAL_NETWORK=192.168.1.0/24 Whether to route and allow input/output traffic to the LAN. LAN access will be unavailable if not specified. Multiple ranges can be specified, separated by a comma or space. Note that there may be DNS issues if this overlaps with PIA's default DNS servers (10.0.0.243 and 10.0.0.242 as of July 2022). Custom DNS servers can be defined using VPNDNS (see below) if this is an issue.
KEEPALIVE=25 If defined, PersistentKeepalive will be set to this in the WireGuard config.
MTU=1420 This can be used to override wg-quick's automatic MTU setting on the Wireguard interface if needed. By default this remains unset (ie. let wg-quick choose).
VPNDNS=8.8.8.8, 8.8.4.4 Use these DNS servers in the WireGuard config. PIA's DNS servers will be used if not specified. Use 0 to disable making any changes to the default container DNS settings. (Note: Using any DNS servers other than PIA's may lead to DNS queries being leaked outside the VPN connection.)
PORT_FORWARDING=0/1 Whether to enable port forwarding. Requires a supported server. Defaults to 0 if not specified.
PORT_FILE=/pia-shared/port.dat The forwarded port number is dumped here for possible access by scripts in other containers. By default this is /pia-shared/port.dat.
PORT_FILE_CLEANUP=0/1 Remove the file containing the forwarded port number on exit. Defaults to 0 if not specified.
PORT_PERSIST=0/1 Set to 1 to attempt to keep the same port forwarded when the container is restarted. The port number may persist for up to two months. Defaults to 0 (always acquire a new port number) if not specified.
PORT_FATAL=0/1 Whether to consider port forwarding errors as fatal or not. May be useful when combined with EXIT_ON_FATAL if needed. Defaults to 0 if not specified.
PORT_SCRIPT=/path/to/script.sh A mounted custom script can be run inside the container once a port is successfully forwarded if needed. The forwarded port number is passed as the first command line argument. By default this remains unset. See issue #26 for more info.
FIREWALL=0/1 Whether to block non-WireGuard traffic. Defaults to 1 if not specified.
EXIT_ON_FATAL=0/1 There is no error recovery logic at this stage. If something goes wrong we simply go to sleep. By default the container will continue running until manually stopped. Set this to 1 to force the container to exit when an error occurs. Exiting on an error may not be desirable behaviour if other containers are sharing the connection.
FATAL_SCRIPT=/path/to/script.sh A mounted custom script can be run inside the container if a fatal error occurs. By default this remains unset.
USER_FILE=/run/secrets/pia-username PASS_FILE=/run/secrets/pia-password PIA credentials can also be read in from existing files (eg for use with Docker secrets)
PIA_IP=x.x.x.x PIA_CN=hostname401 PIA_PORT=1337 Connect to a specific server by manually setting all three of these. This will override whatever LOC is set to.
FWD_IFACE PF_DEST_IP If needed, the container can be used as a gateway for other containers or devices by setting these. See issue #20 for more info. Note that these are for a specific use case, and in many cases using Docker's --net=container:xyz or docker-compose's network_mode: service:xyz instead, and leaving these vars unset, would be an easier way of accessing the VPN and forwarded port from other containers.
PRE_UP POST_UP PRE_DOWN POST_DOWN Custom commands and/or scripts can be run at certain stages if needed. See below for more info.
PIA_DIP_TOKEN A dedicated ip token can be used by setting this. When set, LOC is not used.

Scripting

Custom commands and/or scripts can be run at certain stages of the container's life-cycle by setting the PRE_UP, POST_UP, PRE_DOWN, and POST_DOWN env vars. PRE_UP is run prior to generating the WireGuard config, POST_UP is run after the WireGuard interface is brought up, and PRE_DOWN and POST_DOWN are run before and after the interface is brought down again when the container exits.

In addition, scripts mounted in /pia/scripts named pre-up.sh, post-up.sh, pre-down.sh and post-down.sh will be run at the appropriate stage if present. See issue #33 for more info.

Networking

To keep things simple, network setup is mostly handled by wg-quick. All traffic is routed down the WireGuard tunnel, with exceptions added for any ranges manually defined by LOCAL_NETWORK. Note that LOCAL_NETWORK must be set correctly if LAN access is needed.

Firewall rules are added dropping all traffic by default, and only encrypted/tunneled traffic, attached Docker network traffic, and LOCAL_NETWORK traffic is explicitly allowed. This can be disabled by setting the FIREWALL=0 env var if desired.

Other containers can access the VPN connection using Docker's --net=container:xyz or docker-compose's network_mode: service:xyz. Note that network related settings for other containers (such as exposing ports) need to be set on the VPN container itself.

The container doesn't support IPv6. Any IPv6 traffic is dropped unless using FIREWALL=0, though it might be worth disabling IPv6 on container creation anyway.

Examples

An example docker-compose.yml is available. Some more working examples can be found here.

Notes

  • WireGuard config generation and port forwarding was based on what was found in the source code to the PIA desktop app. The standalone Bash scripts used by the container are available for use outside of Docker.
  • As of Sep 2020, PIA have released their own scripts for using WireGuard and port forwarding outside of their app.
  • Persistent data is stored in /pia.
  • If strict reverse path filtering is used, then the net.ipv4.conf.all.src_valid_mark=1 sysctl should be set on container creation to prevent incoming packets being dropped. See issue #96 for more info.
  • The userspace implementation through wireguard-go is very stable but lacks in performance. Looking into supporting (boringtun) might be beneficial.

Credits

Some bits and pieces and ideas have been borrowed from the following:

docker-wireguard-pia's People

Contributors

def324 avatar filharr avatar saulblake avatar stumpylog avatar thrnz avatar zwimer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

docker-wireguard-pia's Issues

webgui from other containers on network

I can't figure out how to get access to other containers webui when connected to the vpn docker's network. I have published the ports needed on the VPN container itself but it doesn't pass it through to the nzbget docker properly so the webgui never loads.

Unable to use credentials in files using USER_FILE and PASS_FILE

In my docker-compose.yml, I tried:
- USER_FILE=/path/on/dockerhost/piauser.txt
- PASS_FILE=/path/on/dockerhost/piapass.txt

But the container would get a "file does not exist" error, so then I tried putting the files in the pia volume. Now the container is able to read the files, but fails with
PIA password not set. Unable to retrieve new auth token.

Before the addition of USER_FILE and USER_PASS I was able to reference the file in my docker-compose using USER/PASS environment variables:
- USER=/path/on/dockerhost/piauser.txt
- PASS=/path/on/dockerhost/piapass.txt

Works for 4 minutes, then dies

Hey. Any idea why this might be happening?:

I have docker-wireguard-pia and I'm running a docker container of qBittorrent through it. It works fine at first and is super fast (50 MB/s down). All my external IP testing seems to show it's working properly. Then after exactly 4 minutes, the VPN dies. No traffic can get through at all. qBittorrent shows 0 MB/s and everything is "stalled".

If I recreate qBittorrent and docker-wireguard-pia, it works again at first, and then dies after 4 minutes.

I've done extensive testing and can confirm the problem isn't with qBittorrent. docker-wireguard-pia's health pings return unhealthy.

Here's my compose:

  vpn:
    container_name: vpn
    image: thrnz/docker-wireguard-pia
    privileged: true
    cap_add:
      - NET_ADMIN
      - SYS_MODULE # SYS_MODULE might not be needed with a 5.6+ kernel?
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1 # wg-quick fails to set this without --privileged, so set it here instead if needed
      - net.ipv6.conf.default.disable_ipv6=1 # May as well disable ipv6. Should be blocked anyway.
      - net.ipv6.conf.all.disable_ipv6=1
      - net.ipv6.conf.lo.disable_ipv6=1
    healthcheck:
      test: ping -c 1 ca.yahoo.com || exit 1
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      t2_proxy:
        ipv4_address: $VPN_IP
    ports:
      - "6881:6881"
      - "6881:6881/udp"
    # Mounting the tun device may be necessary for userspace implementations
    # devices: 
    #   - /dev/net/tun:/dev/net/tun
    volumes:
      - $DIR_DOCKER/vpn/pia:/pia # Auth token is stored here
      - $DIR_DOCKER/vpn/pia-shared:/pia-shared # If enabled, the forwarded port is dumped to /pia-shared/port.dat for potential use in other containers
    environment:
      - USER=$VPN_USERNAME
      - PASS=$VPN_PASSWORD
      - LOCAL_NETWORK=192.168.1.0/24 192.168.90.0/24 192.168.91.0/24
      # - VPNDNS=192.168.1.251
      # - PORT_FORWARDING=1
      - LOC=ca_toronto
      # - USEMODERN=1
      # - KEEPALIVE=25
      # - EXIT_ON_FATAL=0
      # - WG_USERSPACE=1

Run as a specified user?

Would it be possible to update this image to allow running it as a certain user? Perhaps using
s6-overlay would make it easier?

I prefer to run my containers as particular users, at the very least so created files outside are owned by the service user, instead of root.

Accessing ports routed via docker

I have a unique setup where I use zerotier to access my home network (part of a larger network). I also have this docker-wireguard-pia to route other container traffic through here.

The containers outside of this connected on bridge / host I am able to access typing in my zerotier address (e.g. portainer jellyfin etc.) However, ports that I am routing through the docker I cannot access outside using zerotier IP.

For example I should be able to access plex via 192.168.10.2:32400/web just like I am able to access portainer via 192.168.10.2:9000

How can I expose the ports being routed through this docker. I have already added the ip. From what it looks like I can access it locally because I am remote at the moment I ssh into my server and can curl using localhost / local network ip address.

version: "3"
services:
  pia-wg:
    container_name: vpn
    privileged: true
    image: thrnz/docker-wireguard-pia
    volumes:
      # Auth token is stored here
      - pia:/pia
      # If enabled, the forwarded port is dumped to /pia-shared/port.dat for potential use in other containers
      - pia-shared:/pia-shared
    cap_add:
      - NET_ADMIN
      # SYS_MODULE might not be needed with a 5.6+ kernel?
      - SYS_MODULE
    # Mounting the tun device may be necessary for userspace implementations
    #devices:
    #  - /dev/net/tun:/dev/net/tun
    environment:
      # The following env vars are required:
      - LOC=uk
      - USER=xx
      - PASS=yy
      # The rest are optional:
      - LOCAL_NETWORK=192.168.0.0/24
      #- KEEPALIVE=25
      #- VPNDNS=8.8.8.8,8.8.4.4
      #- PORT_FORWARDING=1
      #- WG_USERSPACE=1
    ports:
      - 8000:8000 #pyload
      - 32400:32400 #plex
      #- :
    sysctls:
      # wg-quick fails to set this without --privileged, so set it here instead if needed
      - net.ipv4.conf.all.src_valid_mark=1
      # May as well disable ipv6. Should be blocked anyway.
      - net.ipv6.conf.default.disable_ipv6=1
      - net.ipv6.conf.all.disable_ipv6=1
      - net.ipv6.conf.lo.disable_ipv6=1
    # The container has no recovery logic. Use a healthcheck to catch disconnects.
    healthcheck:
      test: ping -c 1 8.8.8.8 || exit 1
      interval: 30s
      timeout: 10s
      retries: 3
    restart: always

HowTo: How to enable cross docker host/device internet sharing of the WireGuard VPN tunnel and port forward the port to an IP address (suggestion)

A little addition to enable other containers on a seperate docker host OR other network devices access to the wireguard VPN tunnel, as well as portforwarding for torrents etc.

This is a suggestion, and I hope it helps others, it took me a while to figure this out, as I'm just starting out with Linux/Docker.

Connect to the WireGuard container shell and locate the /scripts/pf.sh file.

Find line 252 - echo "$(date): Press Ctrl+C to exit" - start a new line and add the following:

echo "$(date): Enabling Internet Sharing..."
iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
iptables -A FORWARD -i wg0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i eth1 -o wg0 -j ACCEPT
echo "$(date): Internet Sharing DONE!"

If you wish to enable port forwarding and setup the forward to an IP address, in the next line add:

echo "$(date): Forwarding port $pf_port to transmission container on second host (192.168.1.48)"
iptables -t nat -A PREROUTING -p tcp --dport $pf_port -j DNAT --to-destination 192.168.1.48:$pf_port
echo "$(date): Port Forwarding DONE!"

It would be great if we could add the above IPTABLES entries as Environment Variables.

If you have more than one docker host, and wish to allow all containers on other hosts access to the WireGuard internet connection, you will need to the following (this worked for me):

  1. Create (or use an existing macvlan on the docker host hosting this wireguard container - this is so it has a known/valid local IP address.
  2. Create a new macvlan on the other host, using the IP address of the WireGuard container as the gateway.
  3. Move your containers onto this new macvlan network
  4. Use the above IPTABLES script and add to the relevant pf.sh file and location.

Obviously if the container is upgraded to the latest version you will lose the changes to pf.sh, so re-add them.

unclear how to config deluge port forwarding

I have wireguard-pia and deluge working fine, but I don't upload, I think I misconfigured my compose docker, I'm a beginner and I'm lost, can somebody help me pls. ty !

#===============================================================================
#=============================== V.2.0 =========================================
#===============================================================================
version: '3.7'
services:
#===============================================================================
    vpn:
        image: thrnz/docker-wireguard-pia
        container_name: vpn
        volumes:
            - ${ROOT}/pia:/pia
            - ${ROOT}/pia-shared:/pia-shared
        cap_add:
            - NET_ADMIN
            - SYS_MODULE
        environment:
            - LOC=swiss
            - USER=pxxxxxxxx
            - "PASS=xxxxxxxxx"
            #- LOCAL_NETWORK=192.168.1.0/24
            #- KEEPALIVE=25
            #- VPNDNS=8.8.8.8,8.8.4.4
            - PORT_FORWARDING=1
            #- WG_USERSPACE=1
        sysctls:
            # wg-quick fails to set this without --privileged, so set it here instead if needed
            - net.ipv4.conf.all.src_valid_mark=1
            # May as well disable ipv6. Should be blocked anyway.
            - net.ipv6.conf.default.disable_ipv6=1
            - net.ipv6.conf.all.disable_ipv6=1
            - net.ipv6.conf.lo.disable_ipv6=1
        # The container has no recovery logic. Use a healthcheck to catch disconnects.
        healthcheck:
            test: ping -c 1 www.google.com || exit 1
            interval: 30s
            timeout: 10s
            retries: 3
        ports:
            - 9111:9000 # portainer.io
            - 9983:80 # Organizrr
            - 4545:4545
            - 6767:6767
            - 6789:6789
            - 8989:8989
            - 7878:7878      
            - 3579:3579
            - 8112:8112 # Deluge
#===============================================================================
    deluge:
        container_name: deluge
        image: linuxserver/deluge:latest
        restart: always
        network_mode: service:vpn 
        depends_on:
          - vpn    
        environment:
          - PUID=${PUID} 
          - PGID=${PGID} 
          - TZ=${TZ} 
        volumes:
          - ${ROOT}/downloads:/downloads 
          - ${ROOT}/config/deluge:/config 
#===============================================================================
    deluge-port-helper:
        container_name: deluge_port_forwarding
        build: /media/homemedia/pia/pia
        volumes:
            - ${ROOT}/pia-shared:/pia-shared
            - ${ROOT}/config/deluge:/config 
        network_mode: "service:vpn"
        depends_on:
            - vpn
            - deluge

Fatal error, cannot start container after image update

Hello,

This worked fine until last image update. Since I updated the image, the container won't start.
I tried removing it, removing the volumes and starting again, same issue. I even tried on a different computer and it's not working either.

At startup the following error appear:

[#] iptables-restore -n
iptables-restore v1.8.7 (legacy): iptables-restore: unable to initialize table 'raw'

[#] resolvconf -d wg0 -f
[#] ip -4 rule delete table 51820
[#] ip -4 rule delete table main suppress_prefixlength 0
[#] ip link delete dev wg0
Thu Sep 16 09:05:05 UTC 2021: Fatal error

Here is my docker run command:

docker run -d \
    --name pia \
    --cap-add=NET_ADMIN \
    --cap-add=SYS_MODULE \
    --device /dev/net/tun \
    --sysctl net.ipv4.conf.all.src_valid_mark=1 \
    --sysctl net.ipv6.conf.default.disable_ipv6=1 \
    --sysctl net.ipv6.conf.all.disable_ipv6=1 \
    --sysctl net.ipv6.conf.lo.disable_ipv6=1 \
    -p 8282:8112 \
    -p 58846:58846 \
    -v /volume1/docker/pia:/pia \
    -v /volume1/docker/pia-port:/pia-shared \
    -e USER=my-username -e PASS='my-password' \
    -e LOC=swiss \
    -e LOCAL_NETWORK=192.168.1.0/24 \
    -e VPNDNS="8.8.8.8, 8.8.4.4" \
    -e PORT_FORWARDING=1 \
    -e PORT_PERSIST=1 \
    -e EXIT_ON_FATAL=1 \
    --restart unless-stopped \
    thrnz/docker-wireguard-pia:latest

Something has changed since last version? What should I do to make it work again?
Thanks.

No Internet access

I do not seem to be able to get Internet access when connected. Guessing I do not have something setup correctly, but not having any luck trying different options. Any ideas on what I am missing?

Here is what I used to create the container:

docker create --name=wireguard -e TZ=America/Chicago -e WG_USERSPACE=1 -e USER="<redacted>" -e PASS="<redacted>" -e LOC="us_chicago" -e VPNDNS="8.8.8.8, 8.8.4.4" -e LOCAL_NETWORK="0.0.0.0/0" --cap-add=NET_ADMIN --cap-add=SYS_MODULE -v C:\Users\user\Documents\Docker\wireguard\pia:/pia -v C:\Users\user\Documents\Docker\wireguard\pia-shared:/pia-shared thrnz/docker-wireguard-pia

Here is the result on an nslookup:

docker exec -it wireguard bash
bash-5.0# nslookup google.com
;; connection timed out; no servers could be reached

Here are the docker logs:

Fetching next-gen PIA server list
Verified OK
Verified server list
Registering public key with PIA endpoint; id: us_chicago, cn: chicago420, ip: <redacted, but gets IP from PIA>
Generating /etc/wireguard/wg0.conf
Using custom DNS servers: 8.8.8.8, 8.8.4.4
Successfully generated /etc/wireguard/wg0.conf
Sun Dec 20 22:36:27 UTC 2020: Bringing up WireGuard interface wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.4.235.41 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] resolvconf -a wg0 -m 0 -x
[#] wg set wg0 fwmark 51820
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
sysctl: error setting key 'net.ipv4.conf.all.src_valid_mark': Read-only file system
[#] iptables-restore -n

interface: wg0
  public key: 3eSesYxi14wlMOXFN6gTrLE3tPHZZYBHEoA/M2QUchQ=
  private key: (hidden)
  listening port: 36817
  fwmark: 0xca6c

peer: MpeTTu6PDbWQqJ41cB4zBJv6DbTSgtFeWp3qjIeLbWM=
  endpoint: <redacted, but is an IP from PIA>:1337
  allowed ips: 0.0.0.0/0

How to connect to a US Streaming TCP server?

I got this container working great with all the containers using its vpn connection but I am having issues accessing USTVGO.TV, which is not the docker containers fault but PIA Servers itself. Talking to a customer service agent he recomended me to use TCP port 443 and see if it works but I have no idea how to set this to use TCP. I was able to do it on the desktop app and was able to access the VPN required channels on USTVGO, but need to run the docker container with these settings to get it working.

What would be the way to go about starting the docker stack using TCP? I added OPENVPN_PROTO=tcp to the stack but I am still not able to access the videos.

Some questions about docker and Yacht

Hi, finally I'm changing my NAS, and now I can run Docker.
I Installed Yacht then I tried to import the example docker-compose file

version: '3'
services:
    vpn:
        image: thrnz/docker-wireguard-pia
        volumes:
            # Auth token is stored here
            - /yacht/AppData/Config/pia:/pia
            # If enabled, the forwarded port is dumped to /pia-shared/port.dat for potential use in other containers
            - /yacht/AppData/Config/pia:/pia-shared
        cap_add:
            - NET_ADMIN
            # SYS_MODULE might not be needed with a 5.6+ kernel?
            - SYS_MODULE
        # Mounting the tun device may be necessary for userspace implementations
        devices:
            - /dev/net/tun:/dev/net/tun
        environment:
            # The following env vars are required:
            - LOC=italy
            - USER=xxx
            - PASS=xxx
            # The rest are optional:
            #- LOCAL_NETWORK=192.168.1.0/24
            - KEEPALIVE=25
            #- VPNDNS=8.8.8.8,8.8.4.4
            - PORT_FORWARDING=1
            #- WG_USERSPACE=1
        sysctls:
            # wg-quick fails to set this without --privileged, so set it here instead if needed
            - net.ipv4.conf.all.src_valid_mark=1
            # May as well disable ipv6. Should be blocked anyway.
            - net.ipv6.conf.default.disable_ipv6=1
            - net.ipv6.conf.all.disable_ipv6=1
            - net.ipv6.conf.lo.disable_ipv6=1
        # The container has no recovery logic. Use a healthcheck to catch disconnects.
        healthcheck:
            test: ping -c 1 www.google.com || exit 1
            interval: 30s
            timeout: 10s
            retries: 3

    # Example of another service sharing the VPN
    #other-service:
        #image: linuxserver/qbittorrent
        # Other services can share the VPN using 'network_mode'
        #network_mode: "service:vpn"

    # Other containers can access the forwarded port number via /pia-shared/port.dat
    # Here's an example of a bare-bones 'helper' container that passes the forwarded port to Deluge
    # See https://gist.github.com/thrnz/dcbaa0af66c70af8e302a1c7eb75484a
    #deluge-port-helper:
        #build: /path/to/deluge-port-helper
        #volumes:
            #- pia-shared:/pia-shared:ro
            #- /path/to/deluge/conf:/deluge/conf
        #network_mode: "service:vpn"
        #depends_on:
            #- vpn
            #- other-service

volumes:
    pia:
    pia-shared:

And this's the log of the container

Sun May 30 16:23:08 UTC 2021: Generating auth token
Fetching next-gen PIA server list
Verified OK
Verified server list
Registering public key with PIA endpoint; id: italy, cn: milano403, ip: 156.146.41.70
Generating /etc/wireguard/wg0.conf
Using PIA DNS servers: 10.0.0.243,10.0.0.242
Port forwarding is available at this location
Successfully generated /etc/wireguard/wg0.conf
Sun May 30 16:23:11 UTC 2021: Bringing up WireGuard interface wg0
[#] ip link add wg0 type wireguard
RTNETLINK answers: Not supported
[!] Missing WireGuard kernel module. Falling back to slow userspace implementation.
[#] wireguard-go wg0
┌───────────────────────────────────────────────────┐
│                                                   │
│   Running this software on Linux is unnecessary,  │
│   because the Linux kernel has built-in first     │
│   class support for WireGuard, which will be      │
│   faster, slicker, and better integrated. For     │
│   information on installing the kernel module,    │
│   please visit: <https://wireguard.com/install>.  │
│                                                   │
└───────────────────────────────────────────────────┘
[#] wg setconf wg0 /dev/fd/63

I see one device under the container
1
But I don't see any file for PF and I think wg is not connected

The final purpose is to use WG with qBittorrent with PF, so qBittorrent network is set to this
2

Anyone know how can I check and fix if wg is running and up?

J

Issue: Cannot find device "wg0"

I am having an issue similar to issue #31.

Below is my output.

Mon Nov 29 20:46:24 UTC 2021: Bringing up WireGuard interface wg0
[#] ip link add wg0 type wireguard
RTNETLINK answers: Operation not permitted
Unable to access interface: Operation not permitted
[#] ip link delete dev wg0
Cannot find device "wg0"

I have tried image thrnz/docker-wireguard-pia:testing but it too is giving me this error.

Port Forwarding: Port Expired results in fatal error

I noticed today that my port forwarding had stopped working due to the port expiring, I've been using PORT_PERSIST=1 for apparently 2 months so the expiration is expected however I expected the pf.sh script to be able to recover from this issue instead it exited.

Would it possible to make the port forwarding script gracefully recover in the event of a "port expired" error, or alternatively could a script be executed on a fatal error so I can setup a notification when an issue occurs.

Logs:

Fri Feb 25 15:51:57 UTC 2022: PF token will expire soon. Getting new one.
Fri Feb 25 15:51:57 UTC 2022 Reusing previous PF token
Fri Feb 25 15:51:58 UTC 2022: Obtained PF token. Expires at 2022-02-25T15:02:54.649836403Z
Fri Feb 25 15:51:58 UTC 2022: Server accepted PF bind
Fri Feb 25 15:51:58 UTC 2022: Forwarding on port 52157
Fri Feb 25 15:51:58 UTC 2022: Running /scripts/pf_success.sh
Fri Feb 25 15:51:58 UTC 2022: Allowing incoming traffic on port 52157
Fri Feb 25 15:51:58 UTC 2022: Forwarding incoming VPN traffic on port 52157 to 192.168.2.4:52157
Fri Feb 25 15:51:58 UTC 2022: Running user-defined script: /pia-shared/port.sh
Fri Feb 25 15:51:58 UTC 2022: Rebind interval: 900 seconds
Fri Feb 25 15:51:58 UTC 2022: Port dumped to /pia-shared/port.dat
Fri Feb 25 15:51:58 UTC 2022: This script should remain running to keep the forwarded port alive
Fri Feb 25 15:51:58 UTC 2022: Press Ctrl+C to exit
Fri Feb 25 16:06:58 UTC 2022: bindPort error
{
    "status": "ERROR",
    "message": "port expired"
}
Fri Feb 25 16:06:58 UTC 2022: Fatal error

Docker routing doesn't seem to be working

Hello @thrnz,

First thanks for this image, it's exactly what I was going to put together. However, for the life of me I can't get routing from other containers through the VPN working correctly.

They have routing set up correctly:

/ # ip r
default via 172.17.0.2 dev eth0 
172.17.0.0/16 dev eth0 scope link  src 172.17.0.3 
/ # 

Where 172.17.0.2 is the container running docker-wireguard-pia.

version: '3'
services:
    vpn:
        # networks:
            # wg-vpn:
        network_mode: "bridge"
        image: docker-wireguard-pia
        volumes:
            # Auth token is stored here
            - pia:/pia
            # If enabled, the forwarded port is dumped to /pia-shared/port.dat for potential use in other containers
            - pia-shared:/pia-shared
        # privileged is needing for adding the 0.0.0.0/0 route
        privileged: true
        cap_add:
            - NET_ADMIN
            # SYS_MODULE might not be needed with a 5.6+ kernel?
            - SYS_MODULE
        environment:
            # - LOCAL_NETWORK=172.17.0.0/16
            - ALLOW_DOCKER=1
            - LOC=swiss
            - USER=fffffff
            - PASS=ffff
            - KEEPALIVE=25
            #- VPNDNS=8.8.8.8,8.8.4.4
            - USEMODERN=1
            # - PORT_FORWARDING=1
        # May as well disable ipv6. Should be blocked by iptables anyway.
        sysctls:
            - net.ipv6.conf.default.disable_ipv6=1
            - net.ipv6.conf.all.disable_ipv6=1
            - net.ipv6.conf.lo.disable_ipv6=1
        

volumes:
    pia:
    pia-shared:

So the VPN container is on the bridge network, and it is pingable.

On the docker-wireguard-pia container:

Chain INPUT (policy DROP 2 packets, 152 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   99 12124 ACCEPT     all  --  any    any     anywhere             anywhere             ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     all  --  lo     any     anywhere             anywhere            
    1    84 ACCEPT     all  --  eth0   any     172.17.0.0/16        anywhere            

Chain FORWARD (policy DROP 473 packets, 31594 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   88 10328 ACCEPT     all  --  any    any     anywhere             anywhere             mark match 0xca6c
   22  1729 ACCEPT     all  --  any    any     anywhere             anywhere             ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     all  --  any    lo      anywhere             anywhere            
    0     0 ACCEPT     all  --  any    eth0    anywhere             172.17.0.0/16       
   34  2248 ACCEPT     all  --  any    wg0     anywhere             anywhere            

It seems the FORWARD policy is dropping the packets (I notice this increases as I ping).

Any thoughts?

Connection established but no internet

I am on an ARM device and have been trying in vain for days to get PIA wg to work.

First I got a iptables raw error which I managed to resolve by editing the wg-gen.sh and replacing allowed ips.

After this I get an error, couldnt load match `mark : no such file or directory.

After much googling this has to do with routing all traffic throug WG therefore I set the firewall to 0 which means that the logs show connection established successfully. However i still have no connection and the weird thing is, it breaks my hosts connection too and I have to reboot device eventually to access wan.

Have tried wg userpace and in privileged mode with no success.

I thought I'd post it to see if there was something else I could try.

It is my understanding that iptables-restore is the culprit for the latest error. Where as iptables-legacy-restore could resolve it.

However I'm lost as to what to do next without breaking it further

scripts/run: line 180: [: -eq: unary operator expected

Not sure what this means, but I cannot access qbittorrent.
I have it running with similar compose on a different system. But for some reason, with the same compose, I keep getting this issue:


Sat Jun  5 17:47:48 UTC 2021: WireGuard successfully started


Sat Jun  5 17:47:48 UTC 2021: Allowing network access to 172.20.0.2/16 on eth0


Sat Jun  5 17:47:48 UTC 2021: Firewall enabled: Blocking non-WireGuard traffic


Sat Jun  5 17:47:48 UTC 2021: Allowing network access to 192.168.1.0/24


Sat Jun  5 17:47:48 UTC 2021: Adding route to 192.168.1.0/24


Sat Jun  5 17:47:48 UTC 2021: Starting port forward script


/scripts/run: line 180: [: -eq: unary operator expected


Sat Jun  5 17:47:48 UTC 2021: Verifying API requests. CN: frankfurt410


Sat Jun  5 17:47:48 UTC 2021: Getting PF token


Sat Jun  5 17:47:49 UTC 2021: Obtained PF token. Expires at 2021-08-07T05:47:35.869962964Z


Sat Jun  5 17:47:49 UTC 2021: Server accepted PF bind


Sat Jun  5 17:47:49 UTC 2021: Forwarding on port 28424


Sat Jun  5 17:47:49 UTC 2021: Running /scripts/pf_success.sh


Sat Jun  5 17:47:49 UTC 2021: Allowing incoming traffic on port 28424


Sat Jun  5 17:47:49 UTC 2021: Rebind interval: 900 seconds


Sat Jun  5 17:47:49 UTC 2021: Port dumped to /pia-shared/port.dat


Sat Jun  5 17:47:49 UTC 2021: This script should remain running to keep the forwarded port alive


Sat Jun  5 17:47:49 UTC 2021: Press Ctrl+C to exit

sysctl: error setting key 'net.ipv4.conf.all.src_valid_mark': Read-only file system

I have privileged mode enabled, net_admin and sys_module capabilities are on, and the environment variables

USER=*Redacted*
LOCAL_NETWORK=192.168.1.0/24
PASS=*Redacted*
LOC=*Redacted*
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PIA_IP=*Redacted*
PIA_PORT=1337
PIA_CN=*Redacted*
VPNDNS=8.8.8.8, 8.8.4.4
FIREWALL=0

Here is my startup log

[!] Missing WireGuard kernel module. Falling back to slow userspace implementation.
[#] wireguard-go wg0
┌──────────────────────────────────────────────────────┐
│                                                      │
│   Running wireguard-go is not required because this  │
│   kernel has first class support for WireGuard. For  │
│   information on installing the kernel module,       │
│   please visit:                                      │
│         https://www.wireguard.com/install/           │
│                                                      │
└──────────────────────────────────────────────────────┘
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add *Redacted* dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] resolvconf -a wg0 -m 0 -x
[#] wg set wg0 fwmark 51820
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
sysctl: error setting key 'net.ipv4.conf.all.src_valid_mark': Read-only file system
[#] iptables-restore -n

interface: wg0
  public key: *Redacted*
  private key: (hidden)
  listening port: 49302
  fwmark: 0xca6c

peer: *Redacted*
  endpoint: *Redacted*:1337
  allowed ips: 0.0.0.0/0

Mon Sep 13 16:50:24 UTC 2021: WireGuard successfully started
Mon Sep 13 16:50:24 UTC 2021: Adding route to 192.168.1.0/24

Even though it says it started successfully, I can't ping out to anything, and when I put a port forward on it, it times out trying to pull the port number.

I am running CentOS 8 with kernel 4.18 (I should update that)

Thank you

Fatal error on Synology

I'm encountering the same issue as in #31

This is my log output:

[#] iptables-restore -n
[#] ip -4 rule delete table 51820
iptables-restore v1.8.7 (legacy): iptables-restore: unable to initialize table 'raw'
Error occurred at line: 1
Try `iptables-restore -h' or 'iptables-restore --help' for more information.
[#] resolvconf -d wg0 -f
[#] ip link delete dev wg0
Wed Feb  2 22:41:18 UTC 2022: Fatal error

This is my compose:

wireguard:
    container_name: wireguard-pia
    image: thrnz/docker-wireguard-pia:latest
    volumes:
      - $DOCKER_PATH/wireguard-pia/config/:/pia
      - $DOCKER_PATH/wireguard-pia/port:/pia-shared
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - LOC=swiss
      - USER=$PIA_USER
      - PASS=$PIA_PWD
      - LOCAL_NETWORK=192.168.0.0/24
      - PORT_FORWARDING=1
      - PORT_PERSIST=1
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv6.conf.default.disable_ipv6=1
      - net.ipv6.conf.all.disable_ipv6=1
      - net.ipv6.conf.lo.disable_ipv6=1
    network_mode: bridge
    privileged: true
    restart: always

I've tried adding/removing the cap_add: - NET_ADMIN, privileged: true and WG_USERSPACE=1 but to no avail.

This is running on a Synology machine with kernel 3.10 so I installed the runfalk/synology-wireguard package beforehand and rebooted the machine.

Anything else I can try?

Fatal error after recreating container

Ubuntu 20.10 host.
I did not change my compose file, but did delete the container+non-persistent volumes and had to create it again via compose up. Unfortunately, that lead to this:

Mon Apr 26 09:52:23 UTC 2021: Generating auth token
Fetching next-gen PIA server list
Verified OK
Verified server list
Registering public key with PIA endpoint; id: swiss, cn: zurich408, ip: 212.102.37.8
curl: (60) SSL certificate problem: certificate has expired
More details here: https://curl.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
WG key registration failed
Mon Apr 26 09:52:24 UTC 2021: Failed to generate WireGuard config
Mon Apr 26 09:52:24 UTC 2021: Fatal error   

I tried again after deleting my persistent folder pia-shared:, same issue.
I did not change my compose file except for the port, from 9090:9090 to 9090:8080.

How can I fix this?

My compose:

  vpn-proxy:
    container_name: vpn-proxy
    image: thrnz/docker-wireguard-pia
    restart: always
    networks: 
      - vpn-proxy
    volumes:
      # Auth token is stored here
      - $DOCKERDIR/vpn/pia:/pia
      # If enabled, the forwarded port is dumped to /pia-shared/port.dat for potential use in other containers
      - $DOCKERDIR/vpn/pia-shared:/pia-shared
    cap_add:
      - NET_ADMIN
      #- SYS_MODULE might not be needed with a 5.6+ kernel?
      #- SYS_MODULE
      # Mounting the tun device may be necessary for userspace implementations
      #devices:
      #- /dev/net/tun:/dev/net/tun
    environment:
      LOCAL_NETWORK: 192.168.88.0/24,10.6.0.1/24
      LOC: swiss
      USER: $VPN_USER_PIA
      PASS: $VPN_PW_PIA
      #KEEPALIVE: 25
      #VPNDNS: 8.8.8.8,8.8.4.4
      PORT_FORWARDING: 1
      PORT_PERSIST: 
      #WG_USERSPACE: 1
    privileged: 'true'
    sysctls:
      # wg-quick fails to set this without --privileged, so set it here instead if needed
      - net.ipv4.conf.all.src_valid_mark=1
      # May as well disable ipv6. Should be blocked anyway.
      - net.ipv6.conf.default.disable_ipv6=1
      - net.ipv6.conf.all.disable_ipv6=1
      - net.ipv6.conf.lo.disable_ipv6=1
    # The container has no recovery logic. Use a healthcheck to catch disconnects.
    healthcheck:
      test: ping -c 1 www.google.com || exit 1
      interval: 30s
      timeout: 10s
      retries: 3
    ports:
      - 9090:8080 #Qbittorrent webUI

Dedicated IP

Will support be added for the Dedicated IP offering from PIA? Or maybe it is already there and I am just missing it.

pf.sh's api-ip seems to be the wrong ip to use when asking for the forward port (wireguard)

Hello!

When the pf.sh script runs, this happens:

curl: (7) Failed to connect to vancouver412 port 19999 after 0 ms: Connection refused
Mon Nov  1 06:17:01 UTC 2021: getSignature error

Mon Nov  1 06:17:01 UTC 2021: Fatal error

I exec'd into the running container and traced through the code, and it is correctly using traceroute to retrieve the first hop ip address, but that ip address doesn't have port 19999 open, so the connection is refused:

curl --get --silent --show-error --retry 5 --retry-delay 15 --max-time 15 --data-urlencode token=<redacted> --cacert /tmp/tmp.bFhmHP --resolve vancouver412:19999:10.33.128.1 https://vancouver412:19999/getSignature
curl: (7) Failed to connect to vancouver412 port 19999 after 0 ms: Connection refused

10.33.128.1 also matched what was found in the /etc/wireguard/wg0.conf file:
#pf api ip: 10.33.128.1
I was able to get it to work by using the ip address of the peer endpoint found in the /etc/wireguard/wg0.conf file:

[Peer]
PublicKey = <redacted>
AllowedIPs = 0.0.0.0/0
Endpoint = 208.78.42.223:1337
curl --get --silent --show-error --retry 5 --retry-delay 15 --max-time 15 --data-urlencode token=<redacted> --cacert /tmp/tmp.bFhmHP --resolve vancouver412:19999:208.78.42.223 https://vancouver412:19999/getSignature
{
    "status": "OK",
    "payload": "<redacted>",
    "signature": "<redacted>"
}

Issue? VPN is still working....

curl: (7) Failed to connect to miami404 port 19999 after 5203 ms: Connection refused Thu Dec 30 06:37:42 UTC 2021: getSignature error

Startup error: `iptables-restore v1.8.7 (legacy): unknown option "--save-mark"`

I just noticed this error in the logs/output from this image on startup:;

[#] iptables-restore -n
iptables-restore v1.8.7 (legacy): unknown option "--save-mark"
Error occurred at line: 5
Try `iptables-restore -h' or 'iptables-restore --help' for more information.

I've confirmed that I'm running the latest version of the image:

# docker-compose images vpn
Container           Repository            Tag       Image Id       Size  
-------------------------------------------------------------------------
vpn         thrnz/docker-wireguard-pia   latest   48ec994b71c7   20.29 MB
# docker-compose pull vpn
Pulling vpn ... done
# docker-compose images vpn
Container           Repository            Tag       Image Id       Size  
-------------------------------------------------------------------------
vpn         thrnz/docker-wireguard-pia   latest   48ec994b71c7   20.29 MB

Cannot access container from lan network (outside host machine)

Hello,

i have recently setup this docker. It is working fine so far.
However, i am not able to access the container from my other LAN machines. Therefore i have not access to my other container connected to this one.
My docker is creating the range 172.17.x.x with 172.17.0.2 being the pia docker. What i have notices is that i can ping the container while the startup is in progress, but not anymore once everything is finished. It seems that the packets (ping) get dropped.

I can access from the host itself and have already tried disabling the firewall (env) + flushing iptables from within.

I have not problems with other containers. I do not think that is has something to do with wg0 Allowed_IP since 0.0.0.0/0 should be fine?

Any suggestions?

Update 1:

I have also added my local network (LOCAL_NETWORK=) and i am able to ping my machine on LAN from within the docker. However, i am still not able to ping the pia container.

The routes seem all fine:

default via 172.17.0.1 dev eth0 -> main docker network
10.7.0.0/24 via 172.17.0.1 dev eth0 -> network access
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3 -> pia container

Update 2:

The problem only exists when wg is activated.
wg-quick down /etc/wireguard/wg0.conf make the container accessable for lan devices.

Suggestion: add env variable to run script in addition to saving port to file

May I suggest to add a tiny feature?
Currently, when port forwarding with PIA has been configured, the port is saved to port.dat. Would it be possible to add a secondary action to that: run a bash script.
Allow users to add an environment variable in Compose that specifies the path of the .sh file. This way we do not need inotify, a seperate container etc. and users can use a script for their favourite torrent client to update the port.

For QBittorrent: #3 (comment)
For Transmission: #3 (comment)
For Deluge: #16 (comment)

This github has become a nice repository of interesting info :)

Info: List of all PIA NextGen WireGuard Servers, with IDs (with and without port forwarding enabled) - as of 28 April 2021

Here is a list of the current (as of 28 April 2021) Private Internet Access (PIA) NextGen servers that have WireGuard enabled, in both text (csv format) and MS Excel.

The structure of the files, are Country, ID, Port Forwarding enabled, example: UK Manchester,uk_manchester,Yes

Note: US servers do not have port forwarding enabled, nor do they have any streaming optimsed servers.

@thrnz hopefully, this will help others identify server IDs for your LOC= environment variable.

PIA_NextGen_WG_Servers-28-04-21.txt
PIA_NextGen_WG_Servers-28-04-21.xlsx

How can I change the allowedips?

I want the script to change from allowedips= 0.0.0.0/0 to 0.0.0.0/1, 128.0.0.0/1 as it is a known problem on some systems.

As it stands I have an error which I believe can be resolved with this:

[#] resolvconf -a wg0 -m 0 -x
[#] wg set wg0 fwmark 51820
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
RTNETLINK answers: File exists
[#] resolvconf -d wg0 -f
[#] ip link delete dev wg0

Off topic: privoxy

I have this docker working great on my rpi4 with this docker-compose:

version: '3'
services:
  vpn:
#    networks:
#      wg-vpn:
    image: thrnz/docker-wireguard-pia
    cap_add:
      - NET_ADMIN
    environment:
      - LOC=swiss
      - USER_FILE=/run/secrets/pia_username
      - PASS_FILE=/run/secrets/pia_password
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv6.conf.default.disable_ipv6=1
      - net.ipv6.conf.all.disable_ipv6=1
      - net.ipv6.conf.lo.disable_ipv6=1
    secrets:
        - pia_username
        - pia_password

secrets:
    pia_username:
        file: /opt/pia/pia_user_file
    pia_password:
        file: /opt/pia/pia_pass_file

I was wondering if anyone could assist me with adding a Privoxy docker to my compose file to proxy traffic through this wireguard connection? My goal is to have an http proxy on port 8118 on the rpi's LAN IP address.

Apologies is this off-topic.

Communicate vpn-internal docker with vpn-external docker

Hi, I was successfully set-up Pia-wireguard + qBittorrent + Port-forward script, now I'm trying to configure others containers but I've some difficulties, I need to reach qBittorrent from another docker that is not under vpn.
So If I point to Pia-wireguard ip, I can't get reply.
The Wireguard-Pia is under 172.24.0.1, qBittorrent is under 172.24.0.2, and other container is under 172.17.0.8, so I also tried to set LOCAL_NETWORK=172.17.0.0/24 but without lucky

Any help/suggestion?

Fails to register public token

The following is what I get when starting the container... I have deleted everything and reinstalled it and still get the same issue.

FYI this is on UNRAID and it was working great until a week or 2 ago. What can I do?

`Fetching next-gen PIA server list
Verified OK
Verified server list
Registering public key with PIA endpoint; id: ca_toronto, cn: toronto423, ip: 154.3.42.48
WG key registration failed

Mon Nov 2 18:27:41 UTC 2020: Failed to generate WireGuard config

Mon Nov 2 18:27:41 UTC 2020: Fatal error
`

Connection refused error

Here is the error I'm getting:

Tue Jan 26 17:11:27 UTC 2021: WireGuard successfully started,
Tue Jan 26 17:11:27 UTC 2021: Firewall enabled: Blocking non-WireGuard traffic,
Tue Jan 26 17:11:27 UTC 2021: Starting port forward script,
Tue Jan 26 17:11:27 UTC 2021: Verifying API requests. CN: losangeles416,
Tue Jan 26 17:11:27 UTC 2021: Getting PF token,
curl: (7) Failed to connect to losangeles416 port 19999: Connection refused,
Tue Jan 26 17:11:27 UTC 2021: getSignature error,
Tue Jan 26 17:11:27 UTC 2021: Fatal error,
sysctl: error setting key 'net.ipv4.conf.all.src_valid_mark': Read-only file system

My compose.yml

wireguardvpn:
    image: thrnz/docker-wireguard-pia
    container_name: wireguardvpn
    volumes:
      # Auth token is stored here
      - pia:/pia
      # If enabled, the forwarded port is dumped to /pia-shared/port.dat for potential use in other containers
      - pia-shared:/pia-shared
    cap_add:
      - ALL
      # SYS_MODULE might not be needed with a 5.6+ kernel?
      #- SYS_MODULE
      # Mounting the tun device may be necessary for userspace implementations
    devices:
      - /dev/net/tun:/dev/net/tun
    environment:
      #- LOCAL_NETWORK=192.168.1.0/24
      - LOC=us_california
      - USER=pxxxxx
      - PASS=xxxxxxxx
      #- KEEPALIVE=25
      - VPNDNS=1.1.1.1,1.0.0.1
      - PORT_FORWARDING=1
      #- WG_USERSPACE=1
    sysctls:
      # wg-quick fails to set this without --privileged, so set it here instead if needed
      - net.ipv4.conf.all.src_valid_mark=1
      # May as well disable ipv6. Should be blocked anyway.
      - net.ipv6.conf.default.disable_ipv6=1
      - net.ipv6.conf.all.disable_ipv6=1
      - net.ipv6.conf.lo.disable_ipv6=1
    # The container has no recovery logic. Use a healthcheck to catch disconnects.
    healthcheck:
      test: ping -c 1 www.google.com || exit 1
      interval: 30s
      timeout: 10s
      retries: 3

Feature: Pick server based on latency

Any chance of incorporating this if so it picks the server with the best latency?

PIA-FOSS/get_region.sh

Also I don't know if such a thing is possible but to switch servers without dropping the interface (Understand this might be a wireguard issue but thought I'd ask anyway)

using wireguard with external IP addresses.

Nice! I've updated the image so it should be up on Docker Hub shortly. Otherwise check out the most recent pf_forward.sh if you want to manually update it yourself.

I copied this to a new issue as the other one is closed:

I am having trouble getting this setup. I can’t get my transmission container to route. I’ve included the pertinent docker compose configs. any idea where i’m going wrong?

Version: “3.7”
services:
wireguard-pia:
    container_name: wireguard-pia
    image: thrnz/docker-wireguard-pia
    networks:
      vlan60:
        ipv4_address: 192.168.60.45
    volumes:
      - pia:/pia
      - pia-shared:/pia-shared
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - LOCAL_NETWORK=192.168.0.0/16
      - LOC=server
      - USER=user
      - PASS=pass
      - KEEPALIVE=25
      - VPNDNS=1.1.1.1,1.0.0.1,8.8.8.8
      - PORT_FORWARDING=1
      - PORT_PERSIST=1
      - PORT_SCRIPT=${USERDIR}/docker/transmission/port_script.sh
      - FIREWALL=0
      - WG_USERSPACE=0
      - FWD_IFACE=eth0
      - PF_DEST_IP=192.168.80.42
    sysctls:
      # wg-quick fails to set this without --privileged, so set it here i>
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv4.ip_forward=1
      # May as well disable ipv6. Should be blocked anyway.
      - net.ipv6.conf.default.disable_ipv6=1
      - net.ipv6.conf.all.disable_ipv6=1
      - net.ipv6.conf.lo.disable_ipv6=1
  # The container has no recovery logic. Use a healthcheck to catch disco>
    healthcheck:
      test: ping -c 1 www.google.com || exit 1
      interval: 30s
      timeout: 10s
      retries: 3

 transmission:
    image: ghcr.io/linuxserver/transmission
    container_name: transmission
    networks:
      vlan80:
        ipv4_address: 192.168.80.42
    depends_on:
      - wireguard-pia

networks:
 vlan60:
    driver: macvlan
    driver_opts:
      parent: bond0.60
      enable_ipv6: "true"
    ipam:
      config:
        - subnet: 192.168.60.0/24
 vlan80:
    driver: macvlan
    driver_opts:
      parent: bond0.80
      enable_ipv6: "false"
    ipam:
      config:
        - subnet: 192.168.80.0/25
          gateway: 192.168.60.45

Originally posted by @noumenon272 in #20 (comment)

Option to keep the last IP address

Some trackers complain if your IP address bounces around. Please add in an option to directly connect to a PIA IP address, or to attempt to connect to the previously connected IP address before detecting a new one.

Custom Scripts

Hey there. I love this repo, it is very useful. Thanks for your work on it.

Summary

I would like to consider adding support for custom scripts written by the end user, to be run at various points in this container's lifecycle.

Suggested Implementation

  1. pre-up.sh Runs before WireGuard is brought up or iptables rules are created; essentially runs right away on container start.
  2. post-up.sh Runs after WireGuard is brought up and iptables rules are established, right before we would normally sleep.
  3. pre-down.sh Runs on container stop before bringing WireGuard down or removing any iptables rules.
  4. post-down.sh Runs on container stop after bringing WireGuard down and removing iptables rules.

The run entrypoint would look for these scripts in /pia/scripts and run them at the right time if they exist. If the script fails, the container should exit there.

Usage

In my case this is useful so that I can add custom iptables rules. I am running this container alongside another Wireguard container which requires an extra bit of networking. I could fork and modify this repo, but that would be excessive when all I need to do is run a couple commands.

Feedback

I'm of course open to ideas, opinions, criticisms, etc., and I am also willing to implement this.

Thanks for your consideration!

How to set --privileged in Compose?

Host: Ubuntu 20.04

The container starts successfully, I am running transmission and checked with the testfile from torguard what my IP is in Transmission, its PIA. So all is well. However in the logfile (checked via Portainer) I notice:
sysctl: error setting key 'net.ipv4.conf.all.src_valid_mark': Read-only file system

And in your docker-compose.yml example the comment says:
# wg-quick fails to set this without --privileged, so set it here instead if needed
I Googled a bit but I do not see how to set --privileged via docker-compose. I believe it can only be done via docker command?

Also I noticed in your docker-compose.yml you forgot to add a ports section as an example, to allow web interfaces. And a name for the container:

container_name: VPN
(...)
    ports:
      - 9091:9091 

Otherwise if ppl copy/paste the example file, it will be named docker_vpn_1. Not an issue of course, but might as well give it a nice name :)

QNAP QTS 5.0 "iptables-restore v1.8.8 (legacy): iptables-restore: unable to initialize table 'raw'"

I have recently upgraded my home server to a QNAP TVS-h1688X NAS/Server and am currently porting over all of my docker containers, however I am running into an issue getting this docker container running on the new server.

Here is my compose.yml

---
version: '3'
services:
  vpn:
    image: thrnz/docker-wireguard-pia
    container_name: vpn
    cap_add:
      - NET_ADMIN
    volumes:
      - '/share/Docker/config/vpn/pia:/pia'
      - '/share/Docker/config/vpn/wireguard:/etc/wireguard'
      - '/dev/net/tun:/dev/net/tun'
    environment:
      - PUID=(redacted)
      - GUID=(redacted)
      - TZ=America/Chicago
      - LOC=ca_ontario
      - USER=(redacted)
      - PASS=(redacted)
      - PORT_FORWARDING=1
      - FIREWALL=1
      - KEEPALIVE=25
      - EXIT_ON_FATAL=1
      - LOCAL_NETWORK=192.168.0.0/16
      - PORT_FILE=/pia/forwarded_port
    ports:
      - '(redacted)' #deluge
      - '(redacted)' #delugedaemon
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv6.conf.default.disable_ipv6=1
      - net.ipv6.conf.all.disable_ipv6=1
      - net.ipv6.conf.lo.disable_ipv6=1
    privileged: true
    healthcheck:
      test: ping -c 1 www.google.com || exit 1
      interval: 30s
      timeout: 10s
      retries: 3
    restart: always

Here is the error that I am encountering when spinning the container up:

Warning: `/etc/wireguard/wg0.conf' is world accessible
wg-quick: `wg0' is not a WireGuard interface
Fetching next-gen PIA server list
Verified OK
Verified server list
Registering public key with PIA endpoint; id: ca_ontario, cn: ontario411, ip: (redacted)
Generating /etc/wireguard/wg0.conf
Using PIA DNS servers: 10.0.0.243,10.0.0.242
Port forwarding is available at this location
Successfully generated /etc/wireguard/wg0.conf
Sun Jun  5 15:24:06 UTC 2022: Bringing up WireGuard interface wg0
Warning: `/etc/wireguard/wg0.conf' is world accessible
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add (redacted) dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] resolvconf -a wg0 -m 0 -x
[#] wg set wg0 fwmark 51820
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
[#] iptables-restore -n
iptables-restore v1.8.8 (legacy): iptables-restore: unable to initialize table 'raw'

Error occurred at line: 1
Try `iptables-restore -h' or 'iptables-restore --help' for more information.
[#] resolvconf -d wg0 -f
[#] ip -4 rule delete table 51820
[#] ip -4 rule delete table main suppress_prefixlength 0
[#] ip link delete dev wg0
Sun Jun  5 15:24:06 UTC 2022: Fatal error

While the compose file hasn't changed from one server to the next, and it was running successfully on the old server, nevertheless I've tried using - NFTABLES=1, WG_USERSPACE=1 and even - ALLOWEDIPS=0.0.0.0/1,128.0.0.0/1 even though I do not think that latter is implemented here.
I've also tried multiple other potential solutions outside modifying the compose.yml file, of which I couldn't begin to remember, none of which had any change on the results here.

I'm afraid I'm at a complete loss as to where to go from here.

Edit: Additional info: I'm running this through ContainerStation v2.6.0.483 on QNAP firmware QTS 5.0.1.2034

Question: Can IP Leakage be an Issue?

First I would like to say that this is an awesome image! I was looking for something exactly like this as I like to have the VPN client service standalone and not built in as part of another image.

I was looking into the source code as I am trying to learn a bit myself, however, I do not know a lot of the mechanic behind iptables and networking so I was just wondering; Is there any chance of IP leakage if the VPN connection goes down or in any other scenarios?

Btw, you probably know of it already, but if you don't, binhex has some good quality Wireguard VPN images and he seems to really know what he is doing in that regard. Unfortunately, they are bundled together with other services and port forwarding is not "transparent" for use with services in other containers. However, you could probably steal some ideas from them to refine your own great image.

Information request

Hi, this's not an issue, only some information request :)

I've one R7800 with openwrt on it, and with openwrt I modified a script (https://pastebin.com/P9nmpyxh), to run with openwrt. The script get the port forward with "client_id" that is generated with client_id="$(__hash128)$(__hash128)".
I'm new with WG, I succesfully configured WG inside the router and routed only to my nas, but I can't find a way to take the port-forwar, I'm at the very beginning.
So, I generated the token with pia-auth.sh and till here all ok, but when I try pf.sh I get this error

root@OpenWrt:~# ./pf.sh -t ~/.pia-token
Sat Sep 19 00:11:39 CEST 2020: Automatically getting API IP failed.
Sat Sep 19 00:11:39 CEST 2020: Fatal error

I think I've to adapt the script in some way, first vpn_ip=$(traceroute -4 -m 1 privateinternetaccess.com | tail -n 1 | awk '{print $2}') in my case point to my modem. What about some like this? vpn_ip=$(curl --silent --interface $inferface ipinfo.io/ip) where interface is the interface that run the wg. I know that with this I use an external site, is only one starting point, maybe I can get the wg ip within the router settings too. I said this because I see https://$vpn_ip:19999 and I know that there's nothing on 19999 modem port.
Second question is, do you think there's an alternative to base64 -d? I know that I don't have this on my router so, I'm tying to use openssl enc -base64 -d instead but I always got error

++ curl --get --silent --show-error --retry 5 --retry-delay 15 --max-time 15 --data-urlencode token=token --insecure https://156.146.41.57:19999/getSignature
+ pf_getsig='{
    "status": "ERROR",
    "message": "Unauthorized client"
}'

I tried even within 2 minutes after wg connection, but with no luck

Any idea?

FR: ARM support

[Feature request]
Compile an ARM (specifically a armhf) docker image

Thanks for considering.

iptables is broken with latest centos update

modprobe: can't change directory to '/lib/modules': No such file or directory
iptables v1.8.7 (legacy): can't initialize iptables table `filter': Table does not exist (do you need to insmod?)
Perhaps iptables or your kernel needs to be upgraded.

That keeps repeating in the log. it has to do with the version of iptables on the container not being compatible with the iptables of the kernal of the host OS. (In my case CentOS 8, but also Rocky Linux)

I was helping the gluetun maintainer with the same issue here.

qdm12/gluetun#734

INFO about pf + router

Hi,
I am not an expert on docker, I know very little, so sorry if the questions I will ask seem like simple problems.
I am currently using this docker in a single stack with qbittorrent, everything works fine, but I am asking myself some questions, especially about PF and the possibility to create 2 different stacks, one for WG and one for the torrent client, but let's go in order.
Is there a possibility to be able to take advantage of upnp and open the pia port on the router?
For example, if from windows I simply try to connect to pia and then copy the pf manually into qbittorrent then the port is automatically opened on the router and even a check with https://portchecker.co/ confirms that the port is open
If instead I try on the nas through docker and this repository the port is not opened on the router.
I checked the qbittorrent logs and find this:

(N) 2022-06-12T11:14:45 - qBittorrent v4.4.3.1 started
(N) 2022-06-12T11:14:45 - Using config directory: /config/qBittorrent
(I) 2022-06-12T11:14:45 - Trying to listen on: 0.0.0.0:55488,[::]:55488
(N) 2022-06-12T11:14:45 - Peer ID: -qB4431-
(N) 2022-06-12T11:14:45 - HTTP User-Agent is 'qBittorrent/4.4.3.1'
(I) 2022-06-12T11:14:45 - DHT support [ON]
(I) 2022-06-12T11:14:45 - Local Peer Discovery support [ON]
(I) 2022-06-12T11:14:45 - PeX support [ON]
(I) 2022-06-12T11:14:45 - Anonymous mode [ON]
(I) 2022-06-12T11:14:45 - Encryption support [ON]
(I) 2022-06-12T11:14:45 - UPnP / NAT-PMP support [ON]
(I) 2022-06-12T11:14:45 - IP geolocation database loaded. Type: DBIP-Country-Lite. Build time: Wed Jun 1 02:25:04 2022.
(N) 2022-06-12T11:14:45 - Using built-in Web UI.
(N) 2022-06-12T11:14:45 - Web UI translation for selected locale (en) has been successfully loaded.
(N) 2022-06-12T11:14:45 - Web UI: Now listening on IP: *, port: 8081
(I) 2022-06-12T11:14:45 - Successfully listening on IP: 127.0.0.1, port: TCP/55488
(I) 2022-06-12T11:14:45 - Successfully listening on IP: 127.0.0.1, port: UTP/55488
(I) 2022-06-12T11:14:45 - Successfully listening on IP: 172.31.0.2, port: TCP/55488
(I) 2022-06-12T11:14:45 - Successfully listening on IP: 172.31.0.2, port: UTP/55488
(I) 2022-06-12T11:14:46 - Detected external IP: 37.103.84.75
(N) 2022-06-12T11:14:45 - Watching folder: "/data/Download"
(N) 2022-06-12T11:14:57 - Web UI: Now listening on IP: *, port: 8081
(C) 2022-06-12T11:17:21 - UPnP/NAT-PMP: Port mapping failure, message: could not map port using UPnP[172.31.0.2]: no router found
(C) 2022-06-12T11:17:21 - UPnP/NAT-PMP: Port mapping failure, message: could not map port using UPnP[172.31.0.2]: no router found
(C) 2022-06-12T11:17:21 - UPnP/NAT-PMP: Port mapping failure, message: could not map port using UPnP[172.31.0.2]: no router found
(N) 2022-06-12T11:24:06 - WebAPI login success. IP: ::ffff:172.31.0.1

And this's my actual docker-compose:

version: '3'
services:
    vpn:
        image: thrnz/docker-wireguard-pia
        container_name: pia-wireguard-vpn-proxy
        hostname: pia-wg-vpn-proxy
        volumes:
            # Auth token is stored here
            - /docker-config/AppData/Config/pia:/pia
            # If enabled, the forwarded port is dumped to /pia-shared/port.dat for potential use in other containers
            - /docker-config/AppData/Config/pia:/pia-shared
        cap_add:
            - NET_ADMIN
            - SYS_MODULE
        environment:
            - PUID=65534
            - PGID=65534
            - LOC=***
            - USER=***
            - PASS=***
            - PORT_FORWARDING=1
            - PORT_PERSIST=1
            - PORT_SCRIPT=/pia-shared/qBittorrent-pia-port.sh
            - qbt_host=http://localhost # qbittorrent machine
            - qbt_username=admin # Username for qbittorrent remote machine
            - qbt_password=adminadmin # Password for qbittorrent remote machine
            - qbt_port=8081 # Port for qbittorrent webui
            - FIREWALL=0
            - VPNDNS=1.1.1.1, 1.0.0.1
            - LOCAL_NETWORK=10.0.0.0/24, 10.8.0.0/29
        sysctls:
            # wg-quick fails to set this without --privileged, so set it here instead if needed
            - net.ipv4.conf.all.src_valid_mark=1
            # May as well disable ipv6. Should be blocked anyway.
            - net.ipv6.conf.default.disable_ipv6=1
            - net.ipv6.conf.all.disable_ipv6=1
            - net.ipv6.conf.lo.disable_ipv6=1
        ports:
            - 6881:6881
            - 6881:6881/udp
            - 8081:8081
        # The container has no recovery logic. Use a healthcheck to catch disconnects.
        healthcheck:
            test: ping -c 1 www.google.com || exit 1
            interval: 30s
            timeout: 10s
            retries: 3
        restart: unless-stopped

    # Example of another service sharing the VPN
    qbittorrent:
        image: lscr.io/linuxserver/qbittorrent:latest
        container_name: qbittorrent
        environment:
            - PUID=65534
            - PGID=65534
            - TZ=Europe/Rome
            - WEBUI_PORT=8081
        volumes:
            - /docker-config/AppData/Config/qBittorrent:/config
            - /data:/data
            - /data/Sharing:/freeleech
        network_mode: "service:vpn"
        depends_on: [ "vpn", ]

        healthcheck:
            test: curl --fail http://localhost:8081 || exit 1
            interval: 5m
            retries: 5
            start_period: 1m
            timeout: 1m
        restart: unless-stopped

It seems to consider 172.31.0.2 to be a router, but instead it is the network address assigned to it by docker.
Now, if I understand correctly, dockers can work in host or bridge network mode. In host mode no port is specified, and it is like a program on the normal network, while in bridge mode it is assigned another ip and communicates with the host computer.
Question: is there any way to use the WG connection with pia in host mode? Is it worth it? Would it change anything?
Or, can't you manipulate the docker ip tables by setting the router ip address and opening the pf port?
It seems to me that there is no option to set the router address in the script options, or did I not see it?
Since the web interface responds from the local network, I tried manually opening the pf port to the nas ip address, but the port always remains closed.

Btw, if I activate the FIREWALL a lot of tracker not working, is normal right?

Any ideas on how I can forward the port?

PS can be one idea to "split" the docker? I mean one docker for the wg+pia and another one or as many as I need to run extra services like qbittorrent that use the wg+pia docker. Is that possible?

J

Can't deploy this into swarm

I've been trying to find a service for a VPN that I can deploy into a tiny Docker Swarm of Raspberry Pi computers. I've tried 3 different VPN providers and countless containers from here. No amount of tweaking can get any VPN service to deploy.

Thoughts?

Network settings reset on connected containers when restarting docker-wireguard-pia

I am running this container on a Synology NAS, I got it working great on a stack that starts 2 other containers and I have 2 more containers running through it using --net=container. I tested the IP on all of them and they are all successfully going through the VPN. My issue is that whenever I restart the stack running docker-wireguard-pia, the 2 containers using --net=container stop working. In Portainer I have to edit the 2 containers Network settings, On Network it keeps the "container" option but on the Container option it goes blank so I have to choose docker-wireguard-pia and restart the containers. I know I can just add the containers to the stack but the container has a lot of "labels" that I have no idea how to add to the docker compose on the stack.

Here is a screenshot of the labels https://imgur.com/a/5ss78f4

This is the docker command of the stack:

version: '3'
services:
    vpn:
        image: thrnz/docker-wireguard-pia
        container_name: vpn
        volumes:
            # Auth token is stored here
            - pia:/pia
            # If enabled, the forwarded port is dumped to /pia-shared/port.dat for potential use in other containers
            - pia-shared:/pia-shared
        cap_add:
            - NET_ADMIN
            # SYS_MODULE might not be needed with a 5.6+ kernel?
            - SYS_MODULE
        # Mounting the tun device may be necessary for userspace implementations
        #devices:
        #  - /dev/net/tun:/dev/net/tun
        environment:
            # The following env vars are required:
            - LOC=us_chicago
            - USER=MYUSER
            - PASS=PASSWORD
            # The rest are optional:
            - LOCAL_NETWORK=192.168.69.0/24
            #- KEEPALIVE=25
            #- VPNDNS=8.8.8.8,8.8.4.4
            #- PORT_FORWARDING=1
            #- WG_USERSPACE=1
        ports:
            - 9696:9696
            - 6177:6077
            - 8310:7878
            - 8989:8989
        sysctls:
            # wg-quick fails to set this without --privileged, so set it here instead if needed
            - net.ipv4.conf.all.src_valid_mark=1
            # May as well disable ipv6. Should be blocked anyway.
            - net.ipv6.conf.default.disable_ipv6=1
            - net.ipv6.conf.all.disable_ipv6=1
            - net.ipv6.conf.lo.disable_ipv6=1
        # The container has no recovery logic. Use a healthcheck to catch disconnects.
        healthcheck:
            test: ping -c 1 www.google.com || exit 1
            interval: 30s
            timeout: 10s
            retries: 3
            
    cabernet:
        image: ghcr.io/cabernetwork/cabernet:latest
        container_name: cabernet
        network_mode: service:vpn
        environment:
            - WEBUI_PORT=6077
            - PUID=1026
            - PGID=101
        volumes:
            - /volume1/docker/cabernet:/app
        depends_on:
            - vpn
        restart: always
        
    prowlarr:
        image: lscr.io/linuxserver/prowlarr:develop
        container_name: prowlarr
        network_mode: service:vpn
        environment:
            - WEBUI_PORT=9696
            - PUID=1026
            - PGID=101
        volumes:
            - /volume1/docker/prowlarr:/config
        depends_on:
            - vpn
        restart: always
volumes:
    pia:
    pia-shared:

The ports 8310 and 8989 are for the 2 containers outside the stack that are using the stack vpn network using --net=container.
So, how can I either add Radarr and Sonarr to the stack with all the labels and variables easily or how do I make it so they stay in the vpn network even after restarting the vpn stack?

Docker secrets?

Any plans to implement docker secrets for the username and password? Ideally I could use secrets for the u/p for both PIA and the proxies.

Unclear how to use port.dat with Transmission

I have wireguard-pia and transmission working fine, but I'm not sure what the best practice is for using the port.dat to allow incoming connections to Transmission. My Docker-compose is like this (slightly redacted):

version: '3.8'
services:

  vpn:
    networks:
      wg-vpn:
    image: thrnz/docker-wireguard-pia
    container_name: wireguard-pia
    volumes:
      # Auth token
      - /data/software/wireguard-pia/:/pia
      # Forwarded port
      - /data/software/wireguard-pia/:/pia-shared
      # Edited wg-quick script
      - /data/software/wireguard-pia/wg-quick:/usr/bin/wg-quick
    cap_add:
      - NET_ADMIN
    environment:
      - LOC=Blah
      - USER=Blah
      - PASS=Blah
      - USEMODERN=1
      - PORT_FORWARDING=1
      - LOCAL_NETWORK=10.10.10.0/24
    ports:
      - 9091:9091
      - 51413:51413
      - 51413:51413/udp

transmission:
    image: linuxserver/transmission
    container_name: transmission
    environment:
      - PUID=00002
      - PGID=00002
      - TZ="US/Pacific"
      - USER=Blah
      - PASS=Blah
    volumes:
      - /data/software/transmission:/config
      - /var/torrents:/downloads/complete
    network_mode: "service:vpn"
    depends_on:
      - vpn

I get a port.dat file with a port number in it...should I setup a transmission-remote to push that as the port into Transmission? If so, what's a good programmatic way to do that? (I don't see a Transmission way to invoke a script on start, and making a container just to do the RPC call to push the port seems..overkill, and I don't want to override any of the entrypoints...)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.