From 0f98c395a09972f087331e746e8edc86d9c9be78 Mon Sep 17 00:00:00 2001 From: John Morrow Date: Tue, 28 Feb 2023 17:06:27 -0500 Subject: [PATCH 01/10] Added a process running check Validates that the qbittorrent process is running during the health check loop. If it's not running, start it back up. --- qbittorrent/start.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/qbittorrent/start.sh b/qbittorrent/start.sh index b0d5cfe..b0541b6 100644 --- a/qbittorrent/start.sh +++ b/qbittorrent/start.sh @@ -161,6 +161,13 @@ if [ -e /proc/$qbittorrentpid ]; then echo "[INFO] HEALTH_CHECK_AMOUNT is set to ${HEALTH_CHECK_AMOUNT}" | ts '%Y-%m-%d %H:%M:%.S' while true; do + # Confirm the process is still running, start it back up if it's not. + if ! ps -p $qbittorrentpid > /dev/null; then + echo "[ERROR] qBittorrent daemon is not running. Restarting..." | ts '%Y-%m-%d %H:%M:%.S' + /bin/bash /etc/qbittorrent/qbittorrent.init start + wait $! + qbittorrentpid=$(cat /var/run/qbittorrent.pid) + fi # Ping uses both exit codes 1 and 2. Exit code 2 cannot be used for docker health checks, therefore we use this script to catch error code 2 ping -c ${HEALTH_CHECK_AMOUNT} $HOST > /dev/null 2>&1 STATUS=$? From 9084ccd4e3286464defc24a0b02dfd6ffa6afbd1 Mon Sep 17 00:00:00 2001 From: John Morrow Date: Wed, 28 Jun 2023 13:32:52 -0400 Subject: [PATCH 02/10] Update Dockerfile Leaving curl installed. --- Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d2dcd12..684c010 100644 --- a/Dockerfile +++ b/Dockerfile @@ -149,7 +149,6 @@ RUN apt update \ && apt purge -y \ build-essential \ ca-certificates \ - curl \ git \ jq \ libssl-dev \ From 243f9fbe3823deb08a4c10b1dd693694103379df Mon Sep 17 00:00:00 2001 From: John Morrow Date: Wed, 28 Jun 2023 14:58:46 -0400 Subject: [PATCH 03/10] Added new SSL mode, ignore When leaving the ENABLE_SSL variable unset or set to something other than yes/no, true/false, 1/0, uses ignore mode, which makes no changes to qBittorrent.conf file for SSL. This is useful for when you are managing certificates manually. --- qbittorrent/start.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qbittorrent/start.sh b/qbittorrent/start.sh index b0541b6..00d047a 100644 --- a/qbittorrent/start.sh +++ b/qbittorrent/start.sh @@ -63,10 +63,12 @@ if [[ ${ENABLE_SSL} == "1" || ${ENABLE_SSL} == "true" || ${ENABLE_SSL} == "yes" echo "[WARNING] /config/qBittorrent/config/qBittorrent.conf doesn't have the WebUI\HTTPS\Enabled loaded. Added it to the config." | ts '%Y-%m-%d %H:%M:%.S' echo 'WebUI\HTTPS\Enabled=true' >> "/config/qBittorrent/config/qBittorrent.conf" fi -else +elif [[ ${ENABLE_SSL} == "0" || ${ENABLE_SSL} == "false" || ${ENABLE_SSL} == "no" ]]; then echo "[WARNING] ENABLE_SSL is set to '${ENABLE_SSL}', SSL is not enabled. This could cause issues with logging if other apps use the same Cookie name (SID)." | ts '%Y-%m-%d %H:%M:%.S' echo "[WARNING] Removing the SSL configuration from the config file..." | ts '%Y-%m-%d %H:%M:%.S' sed -i '/^WebUI\\HTTPS*/d' "/config/qBittorrent/config/qBittorrent.conf" +else + echo "[WARNING] ENABLE_SSL is set to '${ENABLE_SSL}', SSL config ignored. No changes made." | ts '%Y-%m-%d %H:%M:%.S' fi # Check if the PGID exists, if not create the group with the name 'qbittorrent' From bd859824d4708223a1d95ccdfc215e7b7962146f Mon Sep 17 00:00:00 2001 From: John Morrow Date: Wed, 28 Jun 2023 15:11:32 -0400 Subject: [PATCH 04/10] Update README.md Added SSL ignore mode functionality to the readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 98d0fa6..d338e52 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ $ docker run -d \ |`VPN_PASSWORD`| No | If username and password provided, configures ovpn file automatically |`VPN_PASSWORD=ac98df79ed7fb`|| |`LAN_NETWORK`| Yes (atleast one) | Comma delimited local Network's with CIDR notation |`LAN_NETWORK=192.168.0.0/24,10.10.0.0/24`|| |`LEGACY_IPTABLES`| No | Use `iptables (legacy)` instead of `iptables (nf_tables)` |`LEGACY_IPTABLES=yes`|| -|`ENABLE_SSL`| No | Let the container handle SSL (yes/no)? |`ENABLE_SSL=yes`|`yes`| +|`ENABLE_SSL`| No | Let the container handle SSL (yes/no/ignore)? |`ENABLE_SSL=yes`|`ignore`| |`NAME_SERVERS`| No | Comma delimited name servers |`NAME_SERVERS=1.1.1.1,1.0.0.1`|`1.1.1.1,1.0.0.1`| |`PUID`| No | UID applied to /config files and /downloads |`PUID=99`|`99`| |`PGID`| No | GID applied to /config files and /downloads |`PGID=100`|`100`| From 2fec07525285d041ad1e7ce13add8e4083723313 Mon Sep 17 00:00:00 2001 From: John Morrow Date: Fri, 30 Jun 2023 10:16:29 -0400 Subject: [PATCH 05/10] Update start.sh Disabling the find/chown line because it slows down start up considerably for me and isn't needed. --- qbittorrent/start.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qbittorrent/start.sh b/qbittorrent/start.sh index 00d047a..5466ee3 100644 --- a/qbittorrent/start.sh +++ b/qbittorrent/start.sh @@ -6,8 +6,9 @@ fi # Set the correct rights accordingly to the PUID and PGID on /config/qBittorrent chown -R ${PUID}:${PGID} /config/qBittorrent +##Disabling this because the downloads folder is my whole NAS and file ownerships are already managed by ACL. # Set the rights on the /downloads folder -find /downloads -not -user ${PUID} -execdir chown ${PUID}:${PGID} {} \+ +#find /downloads -not -user ${PUID} -execdir chown ${PUID}:${PGID} {} \+ # Check if qBittorrent.conf exists, if not, copy the template over if [ ! -e /config/qBittorrent/config/qBittorrent.conf ]; then From 4073a4fbbd19460e91b33f5fc3c2c1e0d7e0fe34 Mon Sep 17 00:00:00 2001 From: John Morrow Date: Wed, 13 Mar 2024 14:13:20 -0400 Subject: [PATCH 06/10] Adding new features Dockerfile: Now downloads and extracts VueTorrent for optional use; leaves jq and natpmpc installed for port forwarding. README.md: Updated the features listing to include the qBittorrent PID watch, VueTorrent, and Proton VPN port forwarding; updated the sample docker run command to use tenseiken/qbittorrentvpn instead of dyonr/qbittorrentvpn; added info about new environment variables. qbittorrent/iptables.sh: Now calls new script file portfwd.sh to run indefinitely in the background. qbittorrent/portfwd.sh: New script that keeps a working Proton VPN port forward set up within the container. qbittorrent/start.sh: Added a section within the health check loop that ensures the listen port in qBittorrent matches up with the port being forwarded. It can change. --- Dockerfile | 26 +++++++++++++++++++++++++- README.md | 9 ++++++++- qbittorrent/iptables.sh | 4 ++++ qbittorrent/portfwd.sh | 9 +++++++++ qbittorrent/start.sh | 13 +++++++++++++ 5 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 qbittorrent/portfwd.sh diff --git a/Dockerfile b/Dockerfile index 684c010..423ca08 100644 --- a/Dockerfile +++ b/Dockerfile @@ -149,6 +149,7 @@ RUN apt update \ && apt purge -y \ build-essential \ ca-certificates \ + curl \ git \ jq \ libssl-dev \ @@ -163,16 +164,39 @@ RUN apt update \ /tmp/* \ /var/tmp/* +# Download and extract VueTorrent +RUN apt update \ + && apt upgrade -y \ + && apt install -y --no-install-recommends \ + ca-certificates \ + curl \ + unzip \ + && VUETORRENT_RELEASE=v2.7.1 \ + && curl -o /config/vuetorrent.zip -L "https://github.com/VueTorrent/VueTorrent/releases/download/${VUETORRENT_RELEASE}/vuetorrent.zip" \ + && cd /config \ + && unzip vuetorrent.zip \ + && apt purge -y \ + ca-certificates \ + curl \ + && apt-get clean \ + && apt --purge autoremove -y \ + && rm -rf \ + /var/lib/apt/lists/* \ + /tmp/* \ + /var/tmp/* + # Install WireGuard and some other dependencies some of the scripts in the container rely on. RUN echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable-wireguard.list \ && printf 'Package: *\nPin: release a=unstable\nPin-Priority: 150\n' > /etc/apt/preferences.d/limit-unstable \ && apt update \ && apt install -y --no-install-recommends \ ca-certificates \ + curl \ dos2unix \ inetutils-ping \ ipcalc \ iptables \ + jq \ kmod \ libqt5network5 \ libqt5xml5 \ @@ -180,6 +204,7 @@ RUN echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.li libssl1.1 \ moreutils \ net-tools \ + natpmpc \ openresolv \ openvpn \ procps \ @@ -199,7 +224,6 @@ RUN echo "deb http://deb.debian.org/debian/ bullseye non-free" > /etc/apt/source && apt -y install --no-install-recommends \ unrar \ p7zip-full \ - unzip \ zip \ && apt-get clean \ && apt --purge autoremove -y \ diff --git a/README.md b/README.md index d338e52..2c8a582 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,9 @@ Docker container which runs the latest [qBittorrent](https://github.com/qbittorr * Configurable UID and GID for config files and /downloads for qBittorrent * Created with [Unraid](https://unraid.net/) in mind * BitTorrent port 8999 exposed by default +* Automatically restarts the qBittorrent process in the event of it crashing. +* Adds VueTorrent (alternate web UI) which can be enabled (or not) by the user. +* Works with Proton VPN's port forward VPN servers to automatically enable forwarding in your container, and automatically sets the connection port in qBittorrent to match the forwarded port. ## Run container from Docker registry The container is available from the Docker registry and this is the simplest way to get it @@ -34,7 +37,7 @@ $ docker run -d \ --cap-add NET_ADMIN \ --sysctl "net.ipv4.conf.all.src_valid_mark=1" \ --restart unless-stopped \ - dyonr/qbittorrentvpn + tenseiken/qbittorrentvpn:latest ``` ## Docker Tags @@ -69,6 +72,10 @@ $ docker run -d \ |`RESTART_CONTAINER`| No |Set to `no` to **disable** the automatic restart when the network is possibly down.|`RESTART_CONTAINER=yes`|`yes`| |`INSTALL_PYTHON3`| No |Set this to `yes` to let the container install Python3.|`INSTALL_PYTHON3=yes`|`no`| |`ADDITIONAL_PORTS`| No |Adding a comma delimited list of ports will allow these ports via the iptables script.|`ADDITIONAL_PORTS=1234,8112`|| +|`ENABLEPROTONVPNPORTFWD` | No | Enables Proton VPN port forwarding logic. 1 to enable, 0 to disable. | `ENABLEPROTONVPNPORTFWD=1` | 0 | +|`WEBUI_URL` | Only if port fwd enabled | Allows the script to use the WebUI API to set the forwarded port automatically. | `WEBUI_URL=https://webui.domain.com` / `WEBUI_URL=http://192.168.1.17` || +|`WEBUI_USER` | Only if port fwd enabled | Allows the script to use the WebUI API to set the forwarded port automatically. | `WEBUI_USER=admin` || +|`WEBUI_PASS` | Only if port fwd enabled | Allows the script to use the WebUI API to set the forwarded port automatically. | `WEBUI_PASS=adminadmin` || ## Volumes | Volume | Required | Function | Example | diff --git a/qbittorrent/iptables.sh b/qbittorrent/iptables.sh index e54230d..d94347e 100644 --- a/qbittorrent/iptables.sh +++ b/qbittorrent/iptables.sh @@ -197,4 +197,8 @@ echo "--------------------" iptables -S echo "--------------------" +# start the NAT-PMP port forward loop +if [[ $ENABLEPROTONVPNPORTFWD -eq 1 ]] ; then + nohup /etc/qbittorrent/portfwd.sh > /dev/null 2>&1 & +fi exec /bin/bash /etc/qbittorrent/start.sh diff --git a/qbittorrent/portfwd.sh b/qbittorrent/portfwd.sh new file mode 100644 index 0000000..97b04eb --- /dev/null +++ b/qbittorrent/portfwd.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +port=$(natpmpc -a 1 0 udp 60 -g 10.2.0.1 | grep "public port" | awk '/Mapped public port/ {print $4}') + +# find and replace "Session\Port=.*" in /config/qBittorrent/config/qBittorrent.conf with $port +sed -i -r "s/^(Session\\\Port=).*/\1$port/" /config/qBittorrent/config/qBittorrent.conf + +# run the port forward loop. +while true ; do date ; natpmpc -a 1 0 udp 60 -g 10.2.0.1 && natpmpc -a 1 0 tcp 60 -g 10.2.0.1 || { echo -e "ERROR with natpmpc command \a" ; break ; } ; sleep 45 ; done \ No newline at end of file diff --git a/qbittorrent/start.sh b/qbittorrent/start.sh index 5466ee3..dafc20d 100644 --- a/qbittorrent/start.sh +++ b/qbittorrent/start.sh @@ -185,6 +185,19 @@ if [ -e /proc/$qbittorrentpid ]; then if [[ ${HEALTH_CHECK_SILENT,,} == "0" || ${HEALTH_CHECK_SILENT,,} == "false" || ${HEALTH_CHECK_SILENT,,} == "no" ]]; then echo "[INFO] Network is up" | ts '%Y-%m-%d %H:%M:%.S' fi + + # Check the NAT port forward and update qBittorrent config if there is a change. + if [[ $ENABLEPROTONVPNPORTFWD -eq 1 ]] ; then + loginData="username=$WEBUI_USER&password=$WEBUI_PASS" + cookie=$(curl -i --silent --header "Referer: $WEBUI_URL" --data $loginData $WEBUI_URL/api/v2/auth/login | grep "set-cookie" | awk '/set-cookie:/ {print $2}' | sed 's/;//') + setPort=$(curl --silent $WEBUI_URL/api/v2/app/preferences --cookie $cookie | jq '.listen_port') + currentPort=$(natpmpc -a 1 0 udp 60 -g 10.2.0.1 | grep "public port" | awk '/Mapped public port/ {print $4}') + if [[ $setPort -ne $currentPort ]] ; then + portData="json={\"listen_port\":$currentPort}" + curl -i --silent --data $portData $WEBUI_URL/api/v2/app/setPreferences --cookie $cookie > /dev/null 2>&1 + fi + fi + sleep ${INTERVAL} & # combine sleep background with wait so that the TERM trap above works wait $! From 8d892a99392b8f5684570f91fecef645a2cd56b6 Mon Sep 17 00:00:00 2001 From: John Morrow Date: Wed, 13 Mar 2024 18:42:20 -0400 Subject: [PATCH 07/10] Update start.sh Added a line to log back out of the web UI API after each login. Prevents a bunch of orphaned login cookies from being valid longer than they need to be. --- qbittorrent/start.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/qbittorrent/start.sh b/qbittorrent/start.sh index dafc20d..14bf585 100644 --- a/qbittorrent/start.sh +++ b/qbittorrent/start.sh @@ -196,6 +196,7 @@ if [ -e /proc/$qbittorrentpid ]; then portData="json={\"listen_port\":$currentPort}" curl -i --silent --data $portData $WEBUI_URL/api/v2/app/setPreferences --cookie $cookie > /dev/null 2>&1 fi + curl --silent -X 'POST' "$WEBUI_URL/api/v2/auth/logout" -H 'accept: */*' -d '' --cookie $cookie > /dev/null 2>&1 fi sleep ${INTERVAL} & From aee4fbf58c15dfae932cc4e783c5f5855daa5660 Mon Sep 17 00:00:00 2001 From: John Morrow Date: Thu, 14 Mar 2024 11:05:18 -0400 Subject: [PATCH 08/10] Update start.sh Redirecting output to /dev/null to suppress occasional error messages from curl. --- qbittorrent/start.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qbittorrent/start.sh b/qbittorrent/start.sh index 14bf585..d9d7b5d 100644 --- a/qbittorrent/start.sh +++ b/qbittorrent/start.sh @@ -189,8 +189,8 @@ if [ -e /proc/$qbittorrentpid ]; then # Check the NAT port forward and update qBittorrent config if there is a change. if [[ $ENABLEPROTONVPNPORTFWD -eq 1 ]] ; then loginData="username=$WEBUI_USER&password=$WEBUI_PASS" - cookie=$(curl -i --silent --header "Referer: $WEBUI_URL" --data $loginData $WEBUI_URL/api/v2/auth/login | grep "set-cookie" | awk '/set-cookie:/ {print $2}' | sed 's/;//') - setPort=$(curl --silent $WEBUI_URL/api/v2/app/preferences --cookie $cookie | jq '.listen_port') + cookie=$(curl -i --silent --header "Referer: $WEBUI_URL" --data $loginData $WEBUI_URL/api/v2/auth/login | grep "set-cookie" | awk '/set-cookie:/ {print $2}' | sed 's/;//') > /dev/null 2>&1 + setPort=$(curl --silent $WEBUI_URL/api/v2/app/preferences --cookie $cookie | jq '.listen_port') > /dev/null 2>&1 currentPort=$(natpmpc -a 1 0 udp 60 -g 10.2.0.1 | grep "public port" | awk '/Mapped public port/ {print $4}') if [[ $setPort -ne $currentPort ]] ; then portData="json={\"listen_port\":$currentPort}" From e63dfaea27bbef1e8a90cb22fb4166c9f8e517a8 Mon Sep 17 00:00:00 2001 From: John Morrow Date: Thu, 14 Mar 2024 21:18:14 -0400 Subject: [PATCH 09/10] Update start.sh Still getting errors from curl about the API login cookie being unset, so I've added some error handling around that. --- qbittorrent/start.sh | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/qbittorrent/start.sh b/qbittorrent/start.sh index d9d7b5d..cfadaca 100644 --- a/qbittorrent/start.sh +++ b/qbittorrent/start.sh @@ -190,13 +190,18 @@ if [ -e /proc/$qbittorrentpid ]; then if [[ $ENABLEPROTONVPNPORTFWD -eq 1 ]] ; then loginData="username=$WEBUI_USER&password=$WEBUI_PASS" cookie=$(curl -i --silent --header "Referer: $WEBUI_URL" --data $loginData $WEBUI_URL/api/v2/auth/login | grep "set-cookie" | awk '/set-cookie:/ {print $2}' | sed 's/;//') > /dev/null 2>&1 - setPort=$(curl --silent $WEBUI_URL/api/v2/app/preferences --cookie $cookie | jq '.listen_port') > /dev/null 2>&1 - currentPort=$(natpmpc -a 1 0 udp 60 -g 10.2.0.1 | grep "public port" | awk '/Mapped public port/ {print $4}') - if [[ $setPort -ne $currentPort ]] ; then - portData="json={\"listen_port\":$currentPort}" - curl -i --silent --data $portData $WEBUI_URL/api/v2/app/setPreferences --cookie $cookie > /dev/null 2>&1 + if [[ $cookie ]]; then + setPort=$(curl --silent $WEBUI_URL/api/v2/app/preferences --cookie $cookie | jq '.listen_port') > /dev/null 2>&1 + currentPort=$(natpmpc -a 1 0 udp 60 -g 10.2.0.1 | grep "public port" | awk '/Mapped public port/ {print $4}') + if [[ $setPort -ne $currentPort ]] ; then + portData="json={\"listen_port\":$currentPort}" + curl -i --silent --data $portData $WEBUI_URL/api/v2/app/setPreferences --cookie $cookie > /dev/null 2>&1 + fi + curl --silent -X 'POST' "$WEBUI_URL/api/v2/auth/logout" -H 'accept: */*' -d '' --cookie $cookie > /dev/null 2>&1 + else + echo "[WARNING] Unable to log into the web UI." | ts '%Y-%m-%d %H:%M:%.S' fi - curl --silent -X 'POST' "$WEBUI_URL/api/v2/auth/logout" -H 'accept: */*' -d '' --cookie $cookie > /dev/null 2>&1 + unset cookie fi sleep ${INTERVAL} & From c1a79458acc74ab2b727fea232f303c2f28ce55b Mon Sep 17 00:00:00 2001 From: tenseiken Date: Wed, 27 Mar 2024 12:12:54 -0400 Subject: [PATCH 10/10] Update README.md Adding instructions for the Proton VPN port forward functionality. --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 2c8a582..61d6926 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,17 @@ If you do not do this, the container will keep on stopping with the error `RTNET Since I do not have IPv6, I am did not test. Thanks to [mchangrh](https://github.com/mchangrh) / [Issue #49](https://github.com/DyonR/docker-qbittorrentvpn/issues/49) +## Proton VPN Port Forwarding with Wireguard +If you use Proton VPN as your VPN provider, they offer a feature called port forwarding that will improve your connectability from peers in the swarm. This works by running a script on a loop in the background that periodically refreshes your port forward. That's necessary because they have to be set with an expiration time, even though we don't want it to expire while our client is running. We don't get to choose the port that's going to be forwarded (that is handled by Proton VPN), and it can change periodically, so we need to be able to change the listen port in qBittorrent in the event of a change. In order to update the listen port in qBittorrent, an authenticated API call to your local qBittorrent instance is required. If you want to have this functionality enabled, you can do the following: + +- Use your Proton VPN account to acquire a Wireguard config file for one of their port-forwarding-enabled servers. These are paid servers--the free ones do not support it. Save this config file as wg0.conf in the Wireguard config directory just like you would any other Wireguard config file. +- Set the `ENABLEPROTONVPNPORTFWD` environment variable in your container to 1. +- Set the `WEBUI_URL` environment variable in your container to the URL you use to access your qBittorrent web UI. This can be the local IP (ex: http://192.168.1.17) or a public URL if you have one (ex: https://qbittorrent.mydomain.com). As long as the container can reach this URL over its network, it's fine. +- Set the `WEBUI_USER` environment variable in your container to the username you use to authenticate with your qBittorrent web UI. +- Set the `WEBUI_PASS` environment variable in your container to the password you use to authenticate with your qBittorrent web UI. + +With all of that set up, port forwarding will be automatically established for you, and the listen port in qBittorrent will be set automatically. + # How to use OpenVPN The container will fail to boot if `VPN_ENABLED` is set and there is no valid .ovpn file present in the /config/openvpn directory. Drop a .ovpn file from your VPN provider into /config/openvpn (if necessary with additional files like certificates) and start the container again. You may need to edit the ovpn configuration file to load your VPN credentials from a file by setting `auth-user-pass`.