Automatically syncs the qBittorrent listening port with the VPN-assigned forwarded port from Gluetun
4.2K
qb-port-sync is a lightweight Python-based sidecar container that automatically updates your qBittorrent listening port to match the VPN-assigned forwarded port from Gluetun.
Perfect for setups where qBittorrent runs through Gluetun (network_mode: service:gluetun) with VPN providers that support port forwarding such as ProtonVPN, Mullvad, and others.
✅ Syncs qBittorrent’s listening port with the latest Gluetun-forwarded port
✅ Detects Gluetun VPN reconnections and updates automatically
✅ Optional firewall monitor — restarts qBittorrent if it becomes firewalled
✅ Optional webhook notifications (Discord, Slack, ntfy, Gotify, etc.)
✅ Built for Docker — minimal footprint (~15MB)
✅ Works with WireGuard and OpenVPN connections
services:
gluetun:
image: qmcgaw/gluetun:latest
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- 8888:8888/tcp # HTTP proxy
- 8388:8388/tcp # Shadowsocks
- 8388:8388/udp # Shadowsocks
- 8000:8000 # required for Gluetun API access
# Other services
# qBittorrent
- 9092:9092 # qBittorrent Web UI
#- 6881:6881 #torrenting port Not needed if using qBittorrent with network_mode: "service:gluetun"
#- 6881:6881/udp #torrenting port Mpt needed if using qBittorrent with network_mode: "service:gluetun"
# Other containers that are being routed via the container where you still want access the resources like web ui on local network
networks:
internal:
web:
volumes:
- /configs/gluetun:/gluetun
environment:
# I specify the PUID and PGID but this is optional (default is 1000,1000), description from Wiki "User ID/Group ID to run as non root and for ownership of files written"
- PUID=1001
- PGID=100
- UMASK=002
- TZ=America/New_York
# See https://github.com/qdm12/gluetun-wiki/tree/main/setup#setup
#- VPN_SERVICE_PROVIDER=custom
- VPN_SERVICE_PROVIDER=protonvpn
- VPN_TYPE=wireguard
# OpenVPN:
#- OPENVPN_USER=
#- OPENVPN_PASSWORD=
# Wireguard:
#- WIREGUARD_PUBLIC_KEY="XXXXXXXXXXXXXXXX"
#- WIREGUARD_PRIVATE_KEY="XXXXXXXXXXXXXXXXXX"
- WIREGUARD_PRIVATE_KEY=XXXXXXXXXXXXXXXXXX
- SERVER_COUNTRIES=United States
- PORT_FORWARD_ONLY=on
#- WIREGUARD_ADDRESSES=10.2.0.2/32
#- VPN_ENDPOINT_IP=146.70.202.130 # "Endpoint" under [Peer] in WG Config
#- VPN_ENDPOINT_PORT=51820 # should be the default 51820 but can confirm by seeing the port after IP in "Endpoint"
#- VPN_DNS_ADDRESS=DNS = 10.2.0.1 # "DNS" under [Interface] in WG Config
- VPN_PORT_FORWARDING=on
- VPN_PORT_FORWARDING_PROVIDER=protonvpn
# Server list updater
# See https://github.com/qdm12/gluetun-wiki/blob/main/setup/servers.md#update-the-vpn-servers-list
- UPDATER_PERIOD=24h
- HTTP_CONTROL_SERVER_USER=admin
- HTTP_CONTROL_SERVER_PASSWORD=password
labels:
- "com.centurylinklabs.watchtower.enable=True"
restart: unless-stopped
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
network_mode: "service:gluetun"
depends_on:
gluetun:
condition: service_healthy
environment:
- PUID=1001
- PGID=100
- UMASK=002
- TZ=America/New_York
- WEBUI_PORT=9092
#- TORRENTING_PORT=6881
volumes:
- /configs/qbittorrent:/config
- /downloads:/downloads #optional
- /media:/media #optional for uploading
labels:
- "com.centurylinklabs.watchtower.enable=True"
healthcheck:
test: curl --fail http://ifconfig.me/ || exit 1
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
#test: "ifconfig | grep -q eth0"
#interval: 1m
#timeout: 30s
#retries: 0
restart: unless-stopped
qb-port-sync:
#build: ./qb-port-sync
image: adxglock/qb-port-sync:latest
container_name: qb-port-sync
network_mode: "service:gluetun"
depends_on:
gluetun:
condition: service_healthy
qbittorrent:
condition: service_healthy
environment:
- GLUETUN_API=http://localhost:8000/v1/openvpn/portforwarded
- GLUETUN_USER=admin
- GLUETUN_PASS=password
- QBITTORRENT_HOST=http://localhost:9092
- QBITTORRENT_USER=admin
- QBITTORRENT_PASS=adminadmin
volumes:
- /var/run/docker.sock:/var/run/docker.sock
labels:
- "com.centurylinklabs.watchtower.enable=True"
# healthcheck: #HEALTHCHECK ADDED INTO DOCKERFILE
# test: curl --fail http://ifconfig.me/ || exit 1
# interval: 30s
# timeout: 10s
# retries: 3
# start_period: 60s
restart: unless-stopped
networks:
internal:
external: true
name: internal
web:
external: true
name: web
📝 Tip:
Make sure qbittorrent and qb-port-sync share the same network namespace as Gluetun by using
network_mode: "service:gluetun".
This allows API access via localhost inside the shared namespace.
| Variable | Default | Description |
|---|---|---|
GLUETUN_API | http://localhost:8000/v1/openvpn/portforwarded | Gluetun API endpoint |
GLUETUN_USER | admin | Gluetun control server username |
GLUETUN_PASS | password | Gluetun control server password |
QBITTORRENT_HOST | http://localhost:9092 | qBittorrent WebUI base URL |
QBITTORRENT_USER | admin | qBittorrent WebUI username |
QBITTORRENT_PASS | adminadmin | qBittorrent WebUI password |
CHECK_INTERVAL | 300 | Poll interval in seconds |
MONITOR_FIREWALL | true | If enabled, restarts qBittorrent when firewalled |
QBT_CONTAINER_NAME | qbittorrent | Container name to restart |
WEBHOOK_URL | (optional) | Webhook URL for notifications |
/v1/openvpn/portforwarded) every few minuteslisten_port dynamicallydocker run --rm \
-e GLUETUN_API=http://localhost:8000/v1/openvpn/portforwarded \
-e GLUETUN_USER=admin \
-e GLUETUN_PASS=password \
-e QBITTORRENT_HOST=http://localhost:9092 \
-e QBITTORRENT_USER=admin \
-e QBITTORRENT_PASS=yourpass \
-v /var/run/docker.sock:/var/run/docker.sock \
adxglock/qb-port-sync:latest
Author: ADXGlock
GitHub: ADXGlock
DockerHub: adxglock
This project is licensed under the MIT License — see the LICENSE file for details.
If you find this project helpful:
If you set WEBHOOK_URL=https://ntfy.sh/qb-port-sync, you’ll receive:
🔁 Updated qBittorrent port to 42311
⚠️ qBittorrent is firewalled. Restarting container...
By ADXGlock For Gluetun + qBittorrent power users.
Content type
Image
Digest
sha256:fe45a4b38…
Size
47.3 MB
Last updated
8 months ago
docker pull adxglock/qb-port-sync