MarkusMcNugen / docker-qBittorrentvpn

Docker container which runs a headless qBittorrent client with WebUI and optional OpenVPN
https://hub.docker.com/r/markusmcnugen/qbittorrentvpn/
GNU General Public License v3.0
168 stars 92 forks source link

Port Forward #88

Open Pompey69 opened 3 years ago

Pompey69 commented 3 years ago

How would I add port forward for the VPN on this docker?

MathyEM commented 3 years ago

I am using PIA and also looking at a way to integrate a port forward request. I found this article on the subject from 2018. I haven't tried anything yet but I thought I would share the ressource. I really am out of my depth here so deep in networking...

Pompey69 commented 3 years ago

I finally got it to work! Had to use TORGuard VPN to do it.

1) Had to connect to their VPN using the docker. Write down the IP address from the logs. (at this point Port Forwarding not working yet). I went through Mullvad, NordVPN and PIA to no success. Finally tried Torguard-they port forward with a static IP address. 2) Go to Torguard account manager and request a port forward from the VPN IP address in my container, I used UDP/1912 when requesting the static IP and port forward (something like 56001) 3) I added UDP and TCP port forwards for the port 56001 on torguard. 4) I created an OPEN VPN Configuration using their configuration website using the IP Address and UDP/1912. 5) Loaded it to docker config directory using Filezilla 6)Started docker and set qbittorrent port to 56001. 7) It took overnight to start seeding but it has been working for 20 hours now.

goldie-wils0n commented 3 years ago

@pompeytir thank you for your guide. Works like a charm!!

Tailslide commented 3 years ago

I got it working with PIA.. you need to install jq and traceroute inside the container then edit /etc/qbittorrent/start.sh to call this script right before the sleep infinity line. Remember to docker commit to make the changes stick. The port can change over time causing qbittorrent to get restarted. Adapted from https://github.com/fm407/PIA-NextGen-PortForwarding/blob/master/pia-nextgen-pf.sh

!/bin/bash
echo "Starting script"
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin

# Vers: 0.1 beta
# Date: 9/14/2020

###### PIA Variables ######
curl_max_time=15
curl_retry=5
curl_retry_delay=15
user='PIAUSERNAME'
pass='PIAPASSWORD'
CONFFILE=/config/qBittorrent/config/qBittorrent.conf

###### Nextgen PIA port forwarding      ##################

get_auth_token () {
    tok=$(curl --insecure --silent --show-error --request POST --max-time $curl_max_time \
        --header "Content-Type: application/json" \
        --data "{\"username\":\"$user\",\"password\":\"$pass\"}" \
        "https://www.privateinternetaccess.com/api/client/v2/token" | jq -r '.token')
    [ $? -ne 0 ] && echo "Failed to acquire new auth token" && exit 1
    echo "$tok"
}

echo "getting token"
get_auth_token #> /dev/null 2>&1
echo "done getting token"

bind_port () {
  pf_bind=$(curl --insecure --get --silent --show-error \
      --retry $curl_retry --retry-delay $curl_retry_delay --max-time $curl_max_time \
      --data-urlencode "payload=$pf_payload" \
      --data-urlencode "signature=$pf_getsignature" \
      $verify \
      "https://$pf_host:19999/bindPort")
  if [ "$(echo $pf_bind | jq -r .status)" != "OK" ]; then
    echo "$(date): bindPort error"
    echo $pf_bind
    fatal_error
  fi
}

get_sig () {
  pf_getsig=$(curl --insecure --get --silent --show-error \
    --retry $curl_retry --retry-delay $curl_retry_delay --max-time $curl_max_time \
    --data-urlencode "token=$tok" \
    $verify \
    "https://$pf_host:19999/getSignature")
  if [ "$(echo $pf_getsig | jq -r .status)" != "OK" ]; then
    echo "$(date): getSignature error"
    echo $pf_getsig
    fatal_error
  fi
  pf_payload=$(echo $pf_getsig | jq -r .payload)
  pf_getsignature=$(echo $pf_getsig | jq -r .signature)
  pf_port=$(echo $pf_payload | base64 -d | jq -r .port)
  pf_token_expiry_raw=$(echo $pf_payload | base64 -d | jq -r .expires_at)
  if date --help 2>&1 /dev/null | grep -i 'busybox' > /dev/null; then
    pf_token_expiry=$(date -D %Y-%m-%dT%H:%M:%S --date="$pf_token_expiry_raw" +%s)
  else
    pf_token_expiry=$(date --date="$pf_token_expiry_raw" +%s)
  fi
}

pf_port () {
  # Get current NAT port number using xmlstarlet to parse the config file.
  CURPORT=`cat $CONFFILE | grep PortRangeMin | cut -d\= -f2`
  echo "Current Port: $CURPORT"
  echo "pia-port: Current port forward: $CURPORT"
  # The port mapping doesn't always change.
  # We don't want to force pfSense to re-read it's config if we don't need to.
  if [ "$CURPORT" = "$pf_port" ]; then
        echo "pia-port: Current Port: $CURPORT, PIA Port: $pf_port - Port not changed. Exiting."
        # Create the pia_port file, as it's possible it could have been
        # removed by external means.
        echo $pf_port > /config/pia_port.txt
  else
        # Port forward has changed, so we update the rules in the config file.
        source /etc/qbittorrent/qbittorrent.init stop
        sleep 5
        sed -i.bak 's/^\(Connection\\PortRangeMin=\).*/\1'$pf_port'/' $CONFFILE
        echo "pia-port: New port number ($pf_port) inserted into config file $CONFFILE."
        # This can then be read by other hosts in order to update the open port in
        # whatever torrent client is in use.
        echo $pf_port > /config/pia_port.txt
        source /etc/qbittorrent/qbittorrent.init start
  fi

}

# Rebind every 15 mins (same as desktop app)
pf_bindinterval=$(( 15 * 60))
# Get a new token when the current one has less than this remaining
# Defaults to 7 days (same as desktop app)
pf_minreuse=$(( 60 * 60 * 24 * 7 ))

pf_remaining=0
pf_firstrun=1

while true; do
  echo "starting port forwarding check"
  vpn_ip=$(traceroute -m 1 privateinternetaccess.com | tail -n 1 | awk '{print $2}')
  pf_host="$vpn_ip"
  pf_remaining=$((  $pf_token_expiry - $(date +%s) ))
  # Get a new pf token as the previous one will expire soon
  if [ $pf_remaining -lt $pf_minreuse ]; then
    if [ $pf_firstrun -ne 1 ]; then
      echo "$(date): PF token will expire soon. Getting new one."
    else
      echo "$(date): Getting PF token"
      pf_firstrun=0

    fi
    get_sig
    echo "$(date): Obtained PF token. Expires at $pf_token_expiry_raw"
    bind_port
    echo "$(date): Server accepted PF bind"
    echo "$(date): Forwarding on port $pf_port"
    pf_port
    echo "$(date): Rebind interval: $pf_bindinterval seconds"
  fi
  sleep $pf_bindinterval &
  wait $!

  bind_port

done