What's new
  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

Tutorial Automatically update qbittorrent connection port on ubuntu with ProtonVPN port forwarding via Wireguard on Merlin

el_pedr0

Occasional Visitor

Automating ProtonVPN Port Forwarding with qBittorrent (WireGuard + Asuswrt-Merlin)​


🎯 Objective​


This guide explains how to automatically update qBittorrent’s listening port with the current port forwarded by ProtonVPN when using WireGuard on Asuswrt-Merlin.

Why? ProtonVPN rotates your forwarded port regularly when NAT-PMP is enabled. If qBittorrent isn’t updated, you’ll might lose incoming connections.

We’ll:
  • Run ProtonVPN WireGuard on an Asuswrt-Merlin router
  • Run qBittorrent on an Ubuntu host (could be bare metal, LXC, VM, etc.)
  • Use a Bash script + systemd service to keep qBittorrent’s port in sync with ProtonVPN
  • Store credentials safely and keep logs clean
This setup is hands-off once deployed.

Caution
I tested with UDP, I haven't confirmed if it works with TCP.

âś… Prerequisites​

  • ProtonVPN Plus or Unlimited subscription (port forwarding requires it)
  • Asus router running Asuswrt-Merlin firmware with WireGuard client configured
  • ProtonVPN WireGuard profile set to:
  • Ubuntu (or Debian-based) host running qbittorrent-nox or qBittorrent desktop
  • A user called qbittorrent which will run and own the script (alter the relevant steps below if you use a different username)
  • natpmpc installed on the Ubuntu host:
    • Code:
      sudo apt update && sudo apt install natpmpc curl
  • Access to qBittorrent’s WebUI (e.g. http://127.0.0.1:8080)



⚙️ Step 1 – Test NAT-PMP with ProtonVPN​


On your torrent host, run:

Code:
natpmpc -a 1 0 tcp 60 -g 10.2.0.1

  • 10.2.0.1 is the default ProtonVPN WireGuard gateway (check your WG config if different).
  • Output should include a mapped TCP port.

If this works, you’re good to automate.




⚙️ Step 2 – Config File​


Create a config file at /etc/qbportupdater.conf:

Code:
# qBittorrent updater config
QBIT_USER='admin'
QBIT_PASS='yourpassword'
QBIT_HOST='127.0.0.1:8080'
GATEWAY='10.2.0.1'

Notes:

  • Wrap the password in single quotes to avoid issues with special characters (!, #, %).
  • Keep this file owned by qbittorrent user and permissions 600:
    • Code:
      sudo chown qbittorrent:qbittorrent /etc/qbportupdater.conf
      sudo chmod 600 /etc/qbportupdater.conf

 
Last edited:

⚙️ Step 3 – The Script - part 1​


Save this to /usr/local/bin/qbportupdater.sh:

##NB: The forum prevented me from pasting the correct curl commands in the script below. Note that you should include the -s flag immediately after curl

Code:
#!/bin/bash
: '
qbportupdater.sh

Continuously updates qBittorrent’s listening port to match the
ProtonVPN-assigned NAT-PMP port when using WireGuard.

Requires:
- natpmpc
- qBittorrent WebUI enabled
- /etc/qbportupdater.conf with credentials and gateway
'

set -euo pipefail
set +H

CONF_FILE="/etc/qbportupdater.conf"
STATE_FILE="/tmp/qb_current_port"

# Load config
if [[ ! -f "$CONF_FILE" ]]; then
  echo "Config file not found: $CONF_FILE"
  exit 1
fi
source "$CONF_FILE"

while true; do
  TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
 
  # Request NAT-PMP TCP port from ProtonVPN gateway
  OUT=$(natpmpc -a 1 0 tcp 60 -g "$GATEWAY" 2>/dev/null || true)
  PORT=$(echo "$OUT" | grep "Mapped public port" | awk '{print $4}' || true)

  if [[ -z "$PORT" ]]; then
    echo "[$TIMESTAMP] ERROR: Could not obtain port"
    sleep 60
    continue
  fi

  # Check previous port
  PREV_PORT=$(cat "$STATE_FILE" 2>/dev/null || echo "none")

  if [[ "$PORT" == "$PREV_PORT" ]]; then
    # Quiet log – only report when it changes
    sleep 45
    continue
  fi

  echo "[$TIMESTAMP] Port changed to $PORT, updating qBittorrent"

  # Log in and update qBittorrent
  COOKIE_JAR=$(mktemp)
  trap 'rm -f "$COOKIE_JAR"' EXIT
 #NB INSERT -s after the word curl below - this forum does not allow me to paste the line with the -s flag!
  curl --cookie-jar "$COOKIE_JAR" \
    --data "username=${QBIT_USER}&password=${QBIT_PASS}" \
    "http://${QBIT_HOST}/api/v2/auth/login" >/dev/null


 #NB INSERT -s after the word curl below - this forum does not allow me to paste the line with the -s flag!
  curl --cookie "$COOKIE_JAR" \
    --data "json={\"listen_port\":${PORT}}" \
    "http://${QBIT_HOST}/api/v2/app/setPreferences" >/dev/null

  echo "$PORT" > "$STATE_FILE"

  echo "[$TIMESTAMP] qBittorrent listen port updated successfully"
  sleep 45
done


Make it executable:
Code:
sudo chmod 755 /usr/local/bin/qbportupdater.sh
sudo chown qbittorrent:qbittorrent /usr/local/bin/qbportupdater.sh

 
Last edited:

⚙️ Step 4 – Systemd Service​


Create /etc/systemd/system/qbportupdater.service:

Code:
[Unit]
Description=ProtonVPN NAT-PMP Port Updater for qBittorrent
After=network-online.target qbittorrent-nox.service
Wants=network-online.target

[Service]
User=qbittorrent
Group=qbittorrent
ExecStart=/usr/local/bin/qbportupdater.sh
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Enable and start:

Code:
sudo systemctl daemon-reload
sudo systemctl enable --now qbportupdater.service



⚙️ Step 5 – Verify​


Check logs:
Code:
journalctl -u qbportupdater -f

You should see:

Code:
[2025-09-25 12:07:51] Port changed to 55090, updating qBittorrent
[2025-09-25 12:07:51] qBittorrent listen port updated successfully



📌 Notes & Gotchas​


  • The script logs only when the port changes → keeps journal quiet.
  • Ports rotate roughly every 60 minutes; ProtonVPN requires refreshing every 15–60s, hence the loop.
  • Don’t run this as root. Running under qbittorrent user keeps things tighter.
  • If you change WebUI credentials or port, update /etc/qbportupdater.conf.
  • I tested with UDP, I haven't confirmed if it works with TCP.



That’s it — you now have hands-free ProtonVPN port forwarding with qBittorrent behind Asuswrt-Merlin.
 
Last edited:
mods - Please can you edit the curl commands for me in Step 3. When I try and paste curl with a -s flag, it refuses to post!
1758815672217.png
 
Last edited:

Support SNBForums w/ Amazon

If you'd like to support SNBForums, just use this link and buy anything on Amazon. Thanks!

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Back
Top
âś–