Home Assistant addon : qbittorrent (supports openvpn & smb mounts)

Is it not just, that no one needs your torrents?

I’ve spent hours working on this on my own to try and avoid posting here and asking, but at this point I’m just doing the same things over and over with no change. I’m very new to HA OS and any sort of coding in general, so I’m hoping this is going to be a stupidly simple issue.

I’ve set qBittorrent up and it works great witihout any VPN settings, but when I try and connect through PIA I cannot successfully set it up to where it launches. Here is the error message I keep stumbling on when attempting to start the add-on with OpenVPN enabled:

WARNING: ca-toronto.privacy.network is referenced in your ovpn file but does not exist, and can’t be found either in the /config/openvpn/ directory

As best I can tell, rather than recognizing ca-toronto.privacy.network as an endpoint hostname, it’s reading it as a file name that it cannot locate on my RPi. I’m at a loss as to what to do now.

Here is the relevant part of my .opvn file:

client
dev tun
proto udp
remote ca-toronto.privacy.network 1198
resolv-retry infinite
nobind
persist-key
persist-tun
cipher aes-128-cbc
auth sha1
tls-client
remote-cert-tls server

auth-user-pass
compress
verb 1
reneg-sec 0

-----BEGIN X509 CRL-----

Hi, indeed it thinks it is a filename. However it should not be a blocking point, it is only a warning : hassio-addons/qbittorrent/rootfs/etc/cont-init.d/93-openvpn.sh at master Ā· alexbelgium/hassio-addons

I’ve pushed a new version please try it at least it won’t show the error message. Btw have you tried transmission? I think it works out of the box with PIA (never tried myself).

Thank you for the reply. I’ve updated to your new version, and while the prior warning isn’t showing up anymore, it’s now in an endless loop. I took a screenshot of the log. Basically every 5 or so seconds it appears to be trying a new IP address and then fails and moves to a new IP address 5 seconds later. Does that cycle for about a minute, then qBittorrent restarts and the process of trying different IP addresses resumes.

I haven’t tried Transmission, but I can definitely give it a look. Your add-on was just the first that came up when I was searching.

And now I start wondering if some people didn’t have issues because Pia doesn’t support openvpn v3… I think it was already quite hard for people in the past to use Pia…

So it sounds like I’m not going to get this to work because of a PIA limitation? If that’s the case I will begin investigating Transmission as you had suggested. Thank you so much for your replies and help. Sorry to have bothered you.

I think some people have better luck with the transmission_openvpn in my repo . But looking in my issues log it seems some people had a solution : šŸ› [qbittorrent] Since last update no longer starts up Ā· Issue #1351 Ā· alexbelgium/hassio-addons Ā· GitHub by Ā« removing the crl-verify block Ā»

Yup, that fixed it! Thank you for the suggestion.

Now, about that pesky port forwarding… All the things I’ve read thus far state to have the PIA application installed to enable port forwarding! That obviously isn’t going to work. I’ll keep hunting away to see what I can find (again, I’m new to HA and coding in general, so this is an uphill process).

1 Like

Which port is needed ?

I realize this is a rather old post but with Mullvad stopping openVPN support i wanted to see if you had any plans to revisit Wireguard support.

I’m here for the same reason @alexbelgium
Ive noticed a huge spike in CPU and RAM since adding a VPN to my qBittorrent, and my research suggests OpenVPN is the cause & that Wireguard is significantly more efficient.

I would very much appreciate if you could revisit this (or advise on another potential fix?).

Cheers!

1 Like

I managed to get the PIA port forwarding working with this addon. It is a bit wonky but it works so far.

The add-on needs to be already running!

First you need to go to SSH terminal and access the qbittorent add on container(modify it to the correct name of your addon):

docker exec -it addon_a0d7b954_qbittorrent sh

Once inside the add on container, you then access the manual github setting page:

git clone https://github.com/pia-foss/manual-connections
cd manual-connections
bash ./run_setup.sh

This will start the manual setting where you will be prompt to input your username/password, the different settings of the VPN and activate port forwarding. Wireguard did not work for me, only openvpn…At the end of this, you will get the port you need to put in the qbittorent UI connection settings.

You will also need to choose the newly created network interface in the advance settings of qbittorent UI. Mine was called ā€œtun06ā€. Once you have change both this and the port forwarding, it will work.

Note that every time you restart the add-on, you will need to do theese steps again as it will delete the newly created interface. I think you also need to keep the settup script running in the terminal as it refresh every 15 min to keep the same port open.

As I said, wonky, but if anybody knows a better way please come foreward :slight_smile:

Is there a way to make the addon start with a different network interface automatically than the standard selection of ā€˜Any interface’?

I would like it to default to my VPN (tun0) but can’t seem to find a way to do so & when I restart the container or HA, it resets and will potentially download without VPN.

Now that @alexbelgium has very nicely implemented wireguard in this addon, chatGPT made me a nice script to automaticaly configure the PIA vpn with wireguard and port forwarding when starting the addon. It has a killswitch to make sure the downloads are paused if the vpn is not up. It also automaticaly put the port in qbittorrent and selects the pia web interface.
I am not a coding expert by any mean but it has been working flawlessly so far.

A few requisites:

  • OpenVPN and Wireguard options need to be disabled in the addon configuration.
  • You need to add those 4 env_vars in the addon configuration(pia and qbittorent user and password):
env_vars:
  - name: PIA_USER
    value: pxxxxxx
  - name: PIA_PASS
    value: xxxxxx
  - name: QBIT_USER
    value: admin
  - name: QBIT_PASS
    value: xxxxxx(can be found in the logs when you start the addon if you don't know it)
  • The script below needs to be added to the file located there:
    /addon_configs/xxxxx_qbittorrent/qbittorrent.sh
# PIA WireGuard + Port Forwarding (pia-foss/manual-connections)
# + qBittorrent "killswitch":
#   - bind qBittorrent to interface "pia"
#   - STOP all torrents until VPN is up (qB v5 uses stop/start; fallback to pause/resume)
#   - STOP again if VPN drops, START when back
#   - auto-update qB listen port when PIA forwarded port changes
#   - gentler backoff after failures so we don't hammer PIA login

set -uo pipefail

# ---- interface name created by manual-connections (wg-quick up <name>) ----
PIA_IFACE="${PIA_IFACE:-pia}"

# ---- creds from env_vars ----
PIA_USER="${PIA_USER:-}"
PIA_PASS="${PIA_PASS:-}"
QBIT_USER="${QBIT_USER:-admin}"
QBIT_PASS="${QBIT_PASS:-}"

if [ -z "$PIA_USER" ] || [ -z "$PIA_PASS" ]; then
  bashio::log.error "Missing PIA_USER/PIA_PASS in env_vars."
  exit 0
fi
if [ -z "$QBIT_PASS" ]; then
  bashio::log.error "Missing QBIT_PASS in env_vars."
  exit 0
fi

# qB WebUI (inside container)
QBIT_URL="http://127.0.0.1:8080"
COOKIEJAR="/tmp/qb_cookie.txt"

# storage
WORKDIR="/data/pia-manual"
LAST_PORT_FILE="/data/pia_forwarded_port.txt"
VPN_OK_FILE="/data/pia_vpn_ok.flag"

# ---------------- qBittorrent API helpers ----------------

qb_wait_ready() {
  for _ in $(seq 1 60); do
    if curl -fsS -H "Referer: $QBIT_URL" "$QBIT_URL/api/v2/app/version" >/dev/null 2>&1; then
      return 0
    fi
    sleep 1
  done
  return 1
}

qb_login() {
  rm -f "$COOKIEJAR"
  curl -fsS -c "$COOKIEJAR" -b "$COOKIEJAR" \
    -H "Referer: $QBIT_URL" \
    --data "username=${QBIT_USER}&password=${QBIT_PASS}" \
    "$QBIT_URL/api/v2/auth/login" >/dev/null
}

qb_set_prefs() {
  local json="$1"
  curl -fsS -b "$COOKIEJAR" \
    -H "Referer: $QBIT_URL" \
    --data-urlencode "json=$json" \
    "$QBIT_URL/api/v2/app/setPreferences" >/dev/null
}

# POST helper that returns HTTP status code (lets us fallback cleanly)
qb_post_code() {
  local endpoint="$1"
  local data="$2"
  curl -sS -o /dev/null -w "%{http_code}" -b "$COOKIEJAR" \
    -H "Referer: $QBIT_URL" \
    --data "$data" \
    "$QBIT_URL$endpoint" || echo "000"
}

qb_stop_all() {
  # qB v5: /api/v2/torrents/stop ; fallback v4: /api/v2/torrents/pause
  local code
  code="$(qb_post_code "/api/v2/torrents/stop" "hashes=all")"
  if [ "$code" = "200" ]; then return 0; fi
  code="$(qb_post_code "/api/v2/torrents/pause" "hashes=all")"
  [ "$code" = "200" ]
}

qb_start_all() {
  # qB v5: /api/v2/torrents/start ; fallback v4: /api/v2/torrents/resume
  local code
  code="$(qb_post_code "/api/v2/torrents/start" "hashes=all")"
  if [ "$code" = "200" ]; then return 0; fi
  code="$(qb_post_code "/api/v2/torrents/resume" "hashes=all")"
  [ "$code" = "200" ]
}

qb_apply_killswitch_settings() {
  qb_login || return 0

  qb_stop_all || bashio::log.warning "Could not stop/pause torrents via API (endpoint mismatch?)"

  # New torrents paused; bind qB to VPN interface; disable UPnP; avoid random port
  local prefs
  prefs=$(printf '{"start_paused_enabled":true,"upnp":false,"random_port":false,"current_network_interface":"%s","current_interface_address":""}' "$PIA_IFACE")
  qb_set_prefs "$prefs" || true

  bashio::log.warning "KILLSWITCH ON: torrents stopped; qB bound to interface '${PIA_IFACE}'."
}

qb_lift_killswitch() {
  qb_login || return 0

  qb_set_prefs '{"start_paused_enabled":false}' || true
  qb_start_all || bashio::log.warning "Could not start/resume torrents via API (endpoint mismatch?)"

  bashio::log.info "KILLSWITCH OFF: VPN OK; torrents started."
}

qb_set_listen_port() {
  local port="$1"
  qb_login || return 0

  local prefs
  prefs=$(printf '{"listen_port":%s,"random_port":false,"upnp":false}' "$port")
  qb_set_prefs "$prefs" || true

  bashio::log.info "qBittorrent updated: listen_port -> $port"
}

# ---------------- VPN checks ----------------

vpn_iface_up() {
  ip link show "$PIA_IFACE" >/dev/null 2>&1
}

vpn_can_reach_inet() {
  # If this fails, treat VPN as down (keeps torrents stopped).
  curl -fsS --interface "$PIA_IFACE" --max-time 6 https://api.ipify.org >/dev/null 2>&1
}

# ---------------- manual-connections setup ----------------

mkdir -p "$WORKDIR"
if [ ! -d "$WORKDIR/manual-connections" ]; then
  git clone https://github.com/pia-foss/manual-connections "$WORKDIR/manual-connections"
fi
cd "$WORKDIR/manual-connections"

# Force PF curls through the VPN interface (prevents bindPort going out wrong route)
if ! grep -q -- "--interface ${PIA_IFACE}" port_forwarding.sh; then
  sed -i "s/curl -/curl --interface ${PIA_IFACE} -/g" port_forwarding.sh
  bashio::log.info "Patched port_forwarding.sh to use: curl --interface ${PIA_IFACE}"
fi

# ---------------- background workers ----------------

# 1) qB killswitch initializer (runs ASAP once WebUI is up)
(
  if qb_wait_ready; then
    qb_apply_killswitch_settings
  else
    bashio::log.warning "qB WebUI not ready; killswitch API init skipped (will still bind later)."
  fi
) &

# 2) VPN + PF loop (restarts on failure) with smarter backoff
(
  rm -f "$VPN_OK_FILE"

  while true; do
    bashio::log.info "Starting PIA WireGuard + Port Forwarding (manual-connections)…"

    auth_failed=0
    net_failed=0

    # Feed answers to interactive prompts:
    #   Dedicated IP token? -> n
    #   Force PIA DNS?      -> y
    #
    # Read output, detect forwarded port, detect auth/network problems
    while IFS= read -r line; do
      echo "$line"

      # Detect the "auth failed" message (can also appear on transient failures)
      if echo "$line" | grep -q "Could not authenticate"; then
        auth_failed=1
      fi

      # Detect common transient network/DNS/TLS failures
      if echo "$line" | grep -qiE "Could not resolve host|Failed to connect|Connection timed out|Operation timed out|TLS|SSL|Network is unreachable|curl: \\(|429|Too Many Requests"; then
        net_failed=1
      fi

      # When PF succeeds, it prints: "Forwarded port  51872"
      if echo "$line" | grep -qE 'Forwarded port[[:space:]]+[0-9]+'; then
        port="$(echo "$line" | grep -oE '[0-9]+' | tail -n1)"
        old=""
        [ -f "$LAST_PORT_FILE" ] && old="$(cat "$LAST_PORT_FILE" 2>/dev/null || true)"

        if [ "$port" != "$old" ]; then
          echo "$port" > "$LAST_PORT_FILE"
          qb_set_listen_port "$port"
        fi

        # Treat VPN as "OK" only when:
        #   - interface exists
        #   - we can reach the internet via that interface
        if vpn_iface_up && vpn_can_reach_inet; then
          if [ ! -f "$VPN_OK_FILE" ]; then
            touch "$VPN_OK_FILE"
            qb_lift_killswitch
          fi
        fi
      fi
    done < <(
      printf "n\ny\n" | \
        VPN_PROTOCOL="wireguard" AUTOCONNECT="true" PIA_PF="true" PIA_DNS="true" DISABLE_IPV6="no" \
        PIA_USER="$PIA_USER" PIA_PASS="$PIA_PASS" \
        ./run_setup.sh 2>&1
    )

    # If we got here, the PIA setup/PF process exited
    bashio::log.warning "PIA process exited (bindPort not OK / tunnel flap). Enabling killswitch…"
    rm -f "$VPN_OK_FILE"
    qb_wait_ready && qb_apply_killswitch_settings || true

    # Backoff so we don't hammer PIA login / API when it's flaky
    if [ "$auth_failed" -eq 1 ] || [ "$net_failed" -eq 1 ]; then
      bashio::log.warning "PIA login/network looked unstable. Backing off 10 minutes before retry…"
      sleep 600
    else
      bashio::log.warning "Retrying in 3 minutes…"
      sleep 180
    fi
  done
) &

# 3) Watchdog: if VPN drops later, stop; if it comes back, start
(
  while true; do
    sleep 20

    if qb_wait_ready; then
      if vpn_iface_up && vpn_can_reach_inet; then
        if [ ! -f "$VPN_OK_FILE" ]; then
          touch "$VPN_OK_FILE"
          qb_lift_killswitch
        fi
      else
        if [ -f "$VPN_OK_FILE" ]; then
          rm -f "$VPN_OK_FILE"
          qb_apply_killswitch_settings
        fi
      fi
    fi
  done
) &

exit 0

Hi everyone!

I’ve been trying to upgrade my config to use WireGuard and after a couple hours iterating with ChatGPT (which originally helped me set all of this up), I’m now desperate and resort to asking for help here.

Here’s what I’ve tried:

Steps:

  1. Placed a valid Surfshark WireGuard config in

/addon_configs/db21ed7f_qbittorrent/wireguard/wg0.conf

  1. Enabled:
wireguard_enabled: true
wireguard_config: wg0.conf
openvpn_enabled: false
  1. Cold-started the add-on.

Resulting log:

FATAL: WireGuard start failed.
Starting WireGuard interface wg0...
Retrying WireGuard using iptables-legacy wrappers.
Initial WireGuard connection failed. Trying IPv4-only endpoints.
ERROR: WireGuard failed to establish connection.
ERROR: [#] ip link add dev wg0-ipv4 type wireguard

Has anyone been able to successfully make this work with Surfshark?

Thanks in advance, have a great day!

I am having completely same issue with the Proton wireguard VPN - placed valid config into wg.conf, referenced in the addon configuration, but WG fails during startup:

[17:25:49] FATAL: WireGuard start failed.
[17:25:50] INFO: Starting WireGuard interface wg0...
[17:25:51] WARNING: Retrying WireGuard using iptables-legacy wrappers.
[17:25:51] WARNING: Initial WireGuard connection failed. Trying IPv4-only endpoints.
[17:25:51] WARNING: Retrying WireGuard using iptables-legacy wrappers.
[17:25:52] ERROR: WireGuard failed to establish connection.
[17:25:52] ERROR: [#] ip link add dev wg0-ipv4 type wireguard
[#] wg setconf wg0-ipv4 /dev/fd/63
.....

@alexbelgium Can I provide any more detailed information so this can be solved?

The issue seems to be already well reported a month ago. @alexbelgium would it be please possible to implement it? I can test any beta you release. Thank you.

I was able to pinpoint and fix issue with the wireguard (and consequently qbittorent) not starting and I created PR with the fix. Now it is on Alex to merge it.

Thanks merged!

I have no experience with HA and/or coding and have been trying for days with ChatGPT and Gemini to get it to work. When I use the SOCK5 proxy with NordVPN the download speeds are extremely slow. I’ve also tried with a VPN on my router, but same story…

Now I tried to get Wireguard to work as it’s supposed to be the fastest, but whatever I try I keep running into problems that AI can’t help me with. Is there a easier way or a good tutorial on how to get it to work with VPN and high download speeds. I cancelled my NordVPN, so I’m able to buy whatever VPN works with this in Home Assistant OS.

Thank you guys in advance!