diff --git a/Dockerfile b/Dockerfile index 053cfe07..254e0f19 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,11 +34,17 @@ ENV USER= \ TINYPROXY_LOG=Critical \ TINYPROXY_PORT=8888 \ TINYPROXY_USER= \ - TINYPROXY_PASSWORD= + TINYPROXY_PASSWORD= \ + SHADOWSOCKS=on \ + SHADOWSOCKS_LOG=on \ + SHADOWSOCKS_PORT=8388 \ + SHADOWSOCKS_PASSWORD= ENTRYPOINT /entrypoint.sh -EXPOSE 8888 +EXPOSE 8888/tcp 8388/tcp 8388/udp HEALTHCHECK --interval=3m --timeout=3s --start-period=20s --retries=1 CMD /healthcheck.sh RUN apk add -q --progress --no-cache --update openvpn wget ca-certificates iptables unbound unzip tinyproxy jq && \ + echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \ + apk add -q --progress --no-cache --update shadowsocks-libev && \ wget -q https://www.privateinternetaccess.com/openvpn/openvpn.zip \ https://www.privateinternetaccess.com/openvpn/openvpn-strong.zip \ https://www.privateinternetaccess.com/openvpn/openvpn-tcp.zip \ @@ -65,9 +71,10 @@ RUN apk add -q --progress --no-cache --update openvpn wget ca-certificates iptab rm -f /tmp/* COPY unbound.conf /etc/unbound/unbound.conf COPY tinyproxy.conf /etc/tinyproxy/tinyproxy.conf +COPY shadowsocks.json /etc/shadowsocks.json COPY entrypoint.sh healthcheck.sh portforward.sh / RUN chown nonrootuser -R /etc/unbound /etc/tinyproxy && \ chmod 700 /etc/unbound /etc/tinyproxy && \ - chmod 600 /etc/unbound/unbound.conf /etc/tinyproxy/tinyproxy.conf && \ + chmod 600 /etc/unbound/unbound.conf /etc/tinyproxy/tinyproxy.conf /etc/shadowsocks.json && \ chmod 500 /entrypoint.sh /healthcheck.sh /portforward.sh && \ chmod 400 /etc/unbound/root.hints /etc/unbound/root.key /etc/unbound/*.bz2 diff --git a/README.md b/README.md index 3e151acf..30b5a696 100644 --- a/README.md +++ b/README.md @@ -53,12 +53,14 @@ - Connect other containers to it, [see this](https://github.com/qdm12/private-internet-access-docker#connect-to-it) - **ARM** compatible - Port forwarding -- HTTP proxy for LAN devices - The *iptables* firewall allows traffic only with needed PIA servers (IP addresses, port, protocol) combinations - OpenVPN reconnects automatically on failure - Docker healthcheck pings the DNS 1.1.1.1 to verify the connection is up - Unbound DNS runs *without root* - OpenVPN can run *without root* but this disallows OpenVPN reconnecting, it can be set with `NONROOT=yes` +- Connect your LAN devices + - HTTP Web proxy *tinyproxy* + - SOCKS5 proxy *shadowsocks* ## Setup @@ -72,6 +74,7 @@ - For TCP strong encryption, allow outbound TCP 501 - For TCP normal encryption, allow outbound TCP 502 - For the built-in web HTTP proxy, allow inbound TCP 8888 + - For the built-in SOCKS5 proxy, allow inbound TCP 8388 and UDP 8388 - Docker API 1.25 to support `init` - If you use Docker Compose, docker-compose >= 1.22.0, to support `init: true` @@ -130,6 +133,7 @@ Note that you can: - Change the many [environment variables](#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) ## Testing @@ -162,6 +166,10 @@ docker run --rm --network=container:pia alpine:3.10 wget -qO- https://ipinfo.io | `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` | `on` | `on` or `off`, to enable the internal SOCKS5 proxy Shadowsocks | +| `SHADOWSOCKS_LOG` | `on` | `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 | ## Connect to it @@ -182,15 +190,25 @@ There are various ways to achieve this, depending on your use case. Add `network_mode: "container:pia"` to your *docker-compose.yml*, provided PIA is already running

--
Connect LAN devices through the built-in HTTP proxy (i.e. with Chrome, Kodi, etc.)

+-

Connect LAN devices through the built-in HTTP proxy *Tinyproxy* (i.e. with Chrome, Kodi, etc.)

1. Setup a HTTP proxy client, such as [SwitchyOmega for Chrome](https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif?hl=en) 1. 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` - 1. With your HTTP proxy client, connect to the Docker host (i.e. `192.168.1.10`) on port `8888`. You might need to enter your credentials if you set them with the environment variables `PROXY_USER` and `PROXY_PASSWORD`. + - 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` + 1. 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`. + 1. If you set `PROXY_LOG_LEVEL` to `Info`, more information will be logged in the Docker logs, merged with the OpenVPN logs. + `TINYPROXY_LOG` defaults to `Critical` to avoid logging everything, for privacy purposes. + +

+-
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**](https://shadowsocks.org/en/download/clients.html) + 1. 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` + 1. With your SOCKS5 proxy client, connect to the Docker host (i.e. `192.168.1.10`) on port `8388`, using the password you have set with `SHADOWSOCKS_PASSWORD`. 1. If you set `PROXY_LOG_LEVEL` to `Info`, more information will be logged in the Docker logs, merged with the OpenVPN logs. - `PROXY_LOG_LEVEL` defaults to `Critical` to avoid logging everything, for privacy purposes.

-
Access ports of containers connected to PIA

@@ -264,7 +282,10 @@ Note that not all regions support port forwarding. ## TODOs -- Mix logs from unbound, tinyproxy and openvpn in Docker logs +- Shadowsocks + - Test DNS queries + - Get logs from file and merge with docker stdout +- Mix Logs of Unbound - Maybe use `--inactive 3600 --ping 10 --ping-exit 60` as default behavior - Try without tun diff --git a/docker-compose.yml b/docker-compose.yml index 811a4f87..ef176fae 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3.7' +version: "3.7" services: pia: build: https://github.com/qdm12/private-internet-access-docker.git @@ -12,7 +12,9 @@ services: init: true ports: - 8888:8888/tcp - # command: + - 8388:8388/tcp + - 8388:8388/udp + # command: environment: - USER=js89ds7 - PASSWORD=8fd9s239G @@ -26,9 +28,11 @@ services: - UNBLOCK= - FIREWALL=on - EXTRA_SUBNETS= - - PROXY=on - - PROXY_LOG_LEVEL=Critical - - PROXY_USER= - - PROXY_PASSWORD= + - TINYPROXY=on + - TINYPROXY_LOG=Critical + - TINYPROXY_USER= + - TINYPROXY_PASSWORD= + - SHADOWSOCKS=on + - SHADOWSOCKS_LOG=on + - SHADOWSOCKS_PASSWORD= restart: always - \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh index f86a576f..e14073e5 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -50,6 +50,7 @@ printf "OpenVPN version: $(openvpn --version | head -n 1 | grep -oE "OpenVPN [0- printf "Unbound version: $(unbound -h | grep "Version" | cut -d" " -f2)\n" printf "Iptables version: $(iptables --version | cut -d" " -f2)\n" printf "TinyProxy version: $(tinyproxy -v | cut -d" " -f2)\n" +printf "ShadowSocks version: $(ss-server --help | head -n 2 | tail -n 1 | cut -d" " -f 2)\n" ############################################ # BACKWARD COMPATIBILITY PARAMETERS @@ -127,6 +128,25 @@ elif [ -z "$TINYPROXY_USER" ] && [ ! -z "$TINYPROXY_PASSWORD" ]; then printf "TINYPROXY_USER is not set but TINYPROXY_PASSWORD is set\n" exit 1 fi +exitIfNotIn SHADOWSOCKS "on,off" +exitIfNotIn SHADOWSOCKS_LOG "on,off" +if [ -z $SHADOWSOCKS_PORT ]; then + SHADOWSOCKS_PORT=8388 +fi +if [ `echo $SHADOWSOCKS_PORT | grep -E "^[0-9]+$"` != $SHADOWSOCKS_PORT ]; then + printf "SHADOWSOCKS_PORT is not a valid number\n" + exit 1 +elif [ $SHADOWSOCKS_PORT -lt 1024 ]; then + printf "SHADOWSOCKS_PORT cannot be a privileged port under port 1024\n" + exit 1 +elif [ $SHADOWSOCKS_PORT -gt 65535 ]; then + printf "SHADOWSOCKS_PORT cannot be a port higher than the maximum port 65535\n" + exit 1 +fi +if [ -z $SHADOWSOCKS_PASSWORD ]; then + printf "SHADOWSOCKS_PASSWORD is not set\n" + exit 1 +fi ############################################ # SHOW PARAMETERS @@ -156,6 +176,7 @@ if [ "$TINYPROXY" == "on" ]; then printf " * Tinyproxy has authentication: $tinyproxy_auth\n" unset -v tinyproxy_auth fi +printf " * ShadowSocks SOCKS5 proxy: $SHADOWSOCKS\n" printf "PIA parameters:\n" printf " * Remote port forwarding: $PORT_FORWARDING\n" [ "$PORT_FORWARDING" == "on" ] && printf " * Remote port forwarding status file: $PORT_FORWARDING_STATUS_FILE\n" @@ -421,6 +442,33 @@ if [ "$TINYPROXY" == "on" ]; then tinyproxy -d & fi +############################################ +# SHADOWSOCKS +############################################ +if [ "$SHADOWSOCKS" == "on" ]; then + ARGS="-c /etc/shadowsocks.json" + # add -d 127.0.0.1 for DNS? + if [ "$SHADOWSOCKS_LOG" == " on" ]; then + printf "[INFO] Setting ShadowSocks logging..." + ARGS="$ARGS -v" + printf "DONE\n" + fi + printf "[INFO] Setting ShadowSocks port to $SHADOWSOCKS_PORT..." + jq ".port_password = {\"$SHADOWSOCKS_PORT\":\"\"}" /etc/shadowsocks.json > /tmp/shadowsocks.json && mv /tmp/shadowsocks.json /etc/shadowsocks.json + exitOnError $? + printf "DONE\n" + printf "[INFO] Setting ShadowSocks password..." + jq ".port_password[\"$SHADOWSOCKS_PORT\"] = \"$SHADOWSOCKS_PASSWORD\"" /etc/shadowsocks.json > /tmp/shadowsocks.json && mv /tmp/shadowsocks.json /etc/shadowsocks.json + exitOnError $? + printf "DONE\n" + ARGS="$ARGS -s `jq --raw-output '.server' /etc/shadowsocks.json`" + unset -v SERVER + ARGS="$ARGS -p $SHADOWSOCKS_PORT" + ARGS="$ARGS -k $SHADOWSOCKS_PASSWORD" + ss-server $ARGS & + unset -v ARGS +fi + ############################################ # READ FORWARDED PORT ############################################ diff --git a/shadowsocks.json b/shadowsocks.json new file mode 100644 index 00000000..7293bf8d --- /dev/null +++ b/shadowsocks.json @@ -0,0 +1,14 @@ +{ + "server": "0.0.0.0", + "user": "nonrootuser", + "method": "chacha20-ietf-poly1305", + "timeout": 30, + "fast_open": false, + "mode": "tcp_and_udp", + "port_password": { + "8388": "" + }, + "workers": 2, + "interface": "tun", + "nameserver": "127.0.0.1" +} \ No newline at end of file