Keeps qBittorrent's port synced to Proton VPN
Proton VPN hands out a new forwarded port on most reconnects, and peers can't reach qBittorrent until it listens there. port-sync reads the port from Proton's log every 15 seconds and sets it through qBittorrent's Web UI.
Install, in a normal PowerShell window
irm https://raw.githubusercontent.com/Real-Fruit-Snacks/port-sync/main/install.ps1 | iexRun it as the Windows account you torrent with. It makes a Web UI password and tells you where to paste it in qBittorrent, does one test sync, then registers a task that starts at sign-in. One UAC prompt, for the task.
Proton VPN forwarded port
qBittorrent listening port
In syncOut of sync
2026-10-26 09:02:17 [port-sync] listening port already correct: 48213
Why it exists
On Linux the Proton app writes the forwarded port to a file. On Windows it only writes it to its own log, as Port pair 48213->48213. Without port-sync, every reconnect means opening qBittorrent's settings by hand, or a slow torrent until you notice.
port-sync assumes the VPN and qBittorrent are already set up so torrent traffic can't leave outside the tunnel. The setup guide is that setup, step by step: the kill switch, binding qBittorrent to the adapter, port forwarding and a leak test.
The loop
In: Proton VPN's client-logs.txt
Port pair 48213->48213
The newest line wins. A later Disconnected clears it.
port-sync, every 15 s
- Checks the
ProtonVPNadapter is up. - Reads the newest
Port pairline. - Logs in to the Web UI and reads qBittorrent's port: when Proton's changes, and once a minute anyway.
- If they differ, sets it, reads it back, logs out.
Out: qBittorrent's Web UI on 127.0.0.1
POST /api/v2/app/setPreferences
{"listen_port":48213,
"random_port":false,"upnp":false}
The same call turns off qBittorrent's random port and UPnP.
The Web UI password is generated by the installer, encrypted with DPAPI to your Windows account, and only ever sent to 127.0.0.1. After a rejected login, port-sync waits for the password file to change, or 30 minutes, because qBittorrent bans an address after 5 failed logins in a row.
What sync.log tells you
One line per change, in %LOCALAPPDATA%\port-sync\sync.log. A condition that repeats is written once.
| Line | Means |
|---|---|
listening port updated: 49160 -> 48213 | Fixed. qBittorrent now listens on Proton's port. |
listening port already correct: 48213 | Checked. Nothing to change. |
VPN adapter 'ProtonVPN' is not up - waiting | Waiting for the VPN to connect. |
no forwarded port in the Proton VPN log yet - waiting | Waiting. Port forwarding is off, or a Proton update changed the log line. Nothing else breaks. |
qBittorrent Web UI not reachable (not running?) - will retry | Retrying. Start qBittorrent; the port lands within 60 s. |
Web UI login rejected (wrong password, or address banned) | Stopped for 30 minutes, or until the password file changes. Fix the password, then quit and reopen qBittorrent. |
can't decrypt …\qbit-pass.txt | Wrong account. The file opens only for the Windows account that made it. Re-run the installer as the account you torrent with. |
Day to day
Watch it
Get-Content "$env:LOCALAPPDATA\port-sync\sync.log" -Wait -Tail 20One cycle: exit 0 if qBittorrent has the forwarded port, 1 if not
powershell -NoProfile -ExecutionPolicy Bypass -File "$env:LOCALAPPDATA\port-sync\port-sync.ps1" -OnceRestart the task
Stop-ScheduledTask port-sync; Start-ScheduledTask port-syncUninstall: removes the task and %LOCALAPPDATA%\port-sync; qBittorrent keeps its last port
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/Real-Fruit-Snacks/port-sync/main/install.ps1))) -UninstallComing from proton-qbit-port-sync 1.x: run the same install line. It keeps your password file, replaces the old task, and moves to %LOCALAPPDATA%\port-sync.
Parameters
The defaults fit the setup guide. To change one for the task, add it to the task's arguments in an admin PowerShell. Re-running the installer resets them.
$t = Get-ScheduledTask port-sync
$t.Actions[0].Arguments += " -Adapter 'ProtonVPN TUN'"
Set-ScheduledTask -InputObject $t
Stop-ScheduledTask port-sync; Start-ScheduledTask port-sync
| Parameter | Default |
|---|---|
-QbitUrl | http://127.0.0.1:8080 |
-QbitUser | admin |
-ProtonLogs | %LOCALAPPDATA%\Proton\Proton VPN\Logs |
-Adapter | ProtonVPN. ProtonVPN TUN for OpenVPN, '' to skip the check |
-StateDir | %LOCALAPPDATA%\port-sync: the password file and sync.log |
-IntervalSec | 15: how often to read the Proton log |
-RecheckSec | 60: how often to re-read qBittorrent's port when Proton's hasn't changed |
Tested on
- Ubuntu 24.04, PowerShell 7.4.6, qbittorrent-nox 4.6.3: the Pester suite, including the sync against a real Web UI, with simulated Proton log lines.
- Windows Server 2022 (GitHub's
windows-latest), Windows PowerShell 5.1 and PowerShell 7: the unit tests, and the installer against a real Task Scheduler. - Not tested: the Proton VPN app's real log on a Windows 10 or 11 desktop, and qBittorrent 5.x. If you run either, an issue saying which versions worked is the most useful thing you can send.
Known issues
- Proton doesn't document the
Port pairline. If an update changes it,sync.logsays so and nothing else breaks. - A console window can flash at sign-in:
-WindowStyle Hiddenhides it only after PowerShell has started. - qBittorrent has to be running to receive the port. A change made while it's closed lands within 60 s of opening it.