Skip to content

qBittorrent over Mullvad (Saltbox + Gluetun on saltierpoop)

Replace legacy binhex/qbittorrentvpn (PIA WireGuard in a restart loop) with the standard Saltbox qbittorrent role sharing the existing Gluetun instance used by JDownloader2.

Prerequisite: JDownloader2 over Mullvad — Gluetun already deployed with Mullvad WireGuard in Saltbox inventory.

Why Gluetun instead of qbittorrentvpn?

Approach Pros Cons
binhex qbittorrentvpn All-in-one image Separate VPN config (PIA WG file); not Saltbox-native; currently broken (missing WG Endpoint)
Saltbox qbittorrent + Gluetun One Mullvad config; same pattern as JD2; sb install lifecycle Must avoid port clashes inside Gluetun namespace; Traefik/DNS optional

Saltbox docs: Gluetun — route other containers, qBittorrent.

Port / collision notes

Multiple apps can share one Gluetun instance if listening ports do not clash inside the Gluetun network namespace. Saltbox publishes app ports through Gluetun.

  • qBittorrent web UI defaults to 8080 (qbittorrent_role_web_port).
  • JDownloader2 uses MyJDownloader (no Traefik hostname required); web UI ports differ.
  • Before install: docker exec gluetun wget -qO- https://ifconfig.me/ip — confirm Mullvad egress.

If you add Traefik hostnames for both apps, set distinct ports or use gluetun_firewall_input_ports per Saltbox Gluetun docs.

Migration steps

1. Inventory (sb edit inventory)

Add to /srv/git/saltbox/inventories/host_vars/localhost.yml:

# Route qBittorrent through existing Gluetun (same Mullvad session as JD2)
qbittorrent_docker_network_mode: "container:gluetun"
gluetun_firewall_input_ports: "8080,6881"

# Required on Gluetun — Cloudflare IPv6 DNS validation fails (same as JD2)
qbittorrent_role_dns_enabled: false

*arr apps reach qBittorrent at qbittorrent:8080 on the Docker network. Traefik hostname qbittorrent.realemail.app is not auto-provisioned when DNS role is disabled.

Validate:

sb validate-config

2. Stop legacy qbittorrentvpn

docker stop qbittorrentvpn
docker rm qbittorrentvpn   # after confirming no data you need in /opt/qbittorrentvpn

Legacy config (if any) under /opt/qbittorrentvpn/qBittorrent/ — import categories / qBittorrent.conf into Saltbox paths after sb install qbittorrent if you want to preserve state.

3. Install Saltbox qBittorrent

sb install qbittorrent

4. Point *arr stack at Gluetun (not qbittorrent)

With qbittorrent_docker_network_mode: "container:gluetun", the qBittorrent container shares Gluetun's network namespace. It is not registered as qbittorrent on the Saltbox Docker network, so Sonarr/Radarr cannot reach http://qbittorrent:8080.

Use internal Docker hostname gluetun, port 8080, HTTP (no TLS):

Field Value
Host gluetun
Port 8080
SSL off
Username / password Saltbox accounts.yml / qBittorrent Web UI

Verified from the Sonarr container: curl http://gluetun:8080 → qBittorrent UI.

Do not use https://qbittorrent.realemail.app for arr download clients — Traefik routes that hostname through Authentik forward-auth* (302 to login). Humans use the FQDN in a browser; API clients need the direct gluetun:8080 path.

Helper to bulk-update DB download clients (already pointed at legacy qbittorrentvpn / qfloodvpn):

python3 scripts/saltierpoop-arr-qbit-host.py   # from homelab repo on saltierpoop

Then docker restart sonarr radarr. Remove duplicate stale qBittorrent entries in each app's Settings → Download Clients if you only need one.

5. Verify VPN egress

# Mullvad IP from Gluetun namespace (same as JD2)
docker exec gluetun wget -qO- https://ifconfig.me/ip

# qBittorrent should match when adding a test torrent + checking peer IP in logs
# Kill switch: stop gluetun — qbit must not download
docker stop gluetun
docker exec qbittorrent wget -qO- --timeout=5 https://ifconfig.me || echo "blocked OK"
docker start gluetun

6. Remove sandbox qbittorrentvpn from Saltbox (optional)

If qbittorrentvpn was installed via sandbox:

sb remove qbittorrentvpn   # confirm Saltbox command for your install method

Rollback

Keep /opt/qbittorrentvpn backup until new qBittorrent is proven. Re-enable legacy container only if you restore a working PIA WireGuard wg0.conf with valid Endpoint.