initial commit
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
---
|
||||
name: self-hosted-torrent-client
|
||||
description: |-
|
||||
Deploy and troubleshoot a Dockerized torrent client (qBittorrent) behind a VPN
|
||||
(Gluetun) with private tracker support, including dynamic IP registration via
|
||||
Mousehole for trackers like MyAnonaMouse (MAM).
|
||||
version: 1.0.0
|
||||
platforms: [linux]
|
||||
metadata:
|
||||
hermes:
|
||||
tags: [torrent, seedbox, vpn, gluetun, qbittorrent, private-tracker, mam]
|
||||
category: self-hosting
|
||||
---
|
||||
|
||||
# Self-Hosted Torrent Client (qBittorrent + Gluetun + Private Trackers)
|
||||
|
||||
Deploy and maintain a Dockerized qBittorrent behind a VPN tunnel (Gluetun)
|
||||
with support for private trackers that require IP registration (MAM, etc.).
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
qBittorrent ──┤ │
|
||||
│ network_mode: │
|
||||
Mousehole ───┤ service:gluetun │── tun0 (VPN) ── Internet
|
||||
│ │
|
||||
Gluetun ──────┤ VPN client │── enp2s0 (host network)
|
||||
```
|
||||
|
||||
All three containers share Gluetun's network namespace. Only Gluetun declares
|
||||
port mappings — qBittorrent and Mousehole inherit them.
|
||||
|
||||
## Quickstart
|
||||
|
||||
### 1. Docker Compose
|
||||
|
||||
Use a single compose file with three services:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
gluetun:
|
||||
image: qmcgaw/gluetun:latest
|
||||
container_name: gluetun
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
ports:
|
||||
- "8080:8080" # qBittorrent WebUI
|
||||
- "5010:5010" # Mousehole WebUI (use 0.0.0.0:5010 if accessing from LAN)
|
||||
environment:
|
||||
VPN_SERVICE_PROVIDER: "private internet access"
|
||||
VPN_TYPE: "openvpn"
|
||||
OPENVPN_PROTOCOL: "tcp"
|
||||
OPENVPN_USER: "<your-username>"
|
||||
OPENVPN_PASSWORD: "<your-password>"
|
||||
SERVER_HOSTNAMES: "nl-amsterdam.privacy.network"
|
||||
VPN_PORT_FORWARDING: "on"
|
||||
PORT_FORWARD_ONLY: "true"
|
||||
FIREWALL_VPN_INPUT_PORTS: "8080,5010"
|
||||
restart: unless-stopped
|
||||
|
||||
qbittorrent:
|
||||
image: lscr.io/linuxserver/qbittorrent:latest
|
||||
container_name: qbittorrent
|
||||
network_mode: "service:gluetun"
|
||||
depends_on:
|
||||
gluetun:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ./qbittorrent:/config
|
||||
- /path/to/downloads:/downloads
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/Chicago
|
||||
- WEBUI_PORT=8080
|
||||
restart: unless-stopped
|
||||
|
||||
mousehole:
|
||||
image: tmmrtn/mousehole:latest
|
||||
container_name: mousehole
|
||||
network_mode: "service:gluetun"
|
||||
depends_on:
|
||||
gluetun:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
TZ: America/Chicago
|
||||
MOUSEHOLE_AUTH_PASSWORD: <strong-password>
|
||||
MOUSEHOLE_ALLOWED_HOSTS: localhost,127.0.0.1,[::1],192.168.50.98
|
||||
volumes:
|
||||
- mousehole:/var/lib/mousehole
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
mousehole:
|
||||
```
|
||||
|
||||
### 2. Set up qBittorrent
|
||||
|
||||
- Access WebUI at `http://<host-ip>:8080`
|
||||
- Go to Settings → Connection
|
||||
- Set **Listening Port** to match Gluetun's forwarded port
|
||||
- Disable UPnP/NAT-PMP
|
||||
- The port is stored in `Session\Port` in `qBittorrent.conf`
|
||||
- Verify the forwarded port from Gluetun: `docker exec gluetun cat /tmp/gluetun/forwarded_port`
|
||||
|
||||
### 3. Set up Mousehole (for private trackers needing dynamic IP)
|
||||
|
||||
- Access Mousehole WebUI at `http://<host-ip>:5010`
|
||||
- Log in with the `MOUSEHOLE_AUTH_PASSWORD`
|
||||
- On MAM, go to **Preferences → Security** and create a session:
|
||||
- IP: Use the IP Mousehole shows you
|
||||
- IP vs ASN locked: **ASN**
|
||||
- Allow Session to set Dynamic Seedbox: **Yes**
|
||||
- Label: `mousehole`
|
||||
- Copy the cookie MAM gives you
|
||||
- Paste it into Mousehole and click **Set**
|
||||
|
||||
## Common Private Tracker Issues
|
||||
|
||||
| Symptom | Likely Cause | Fix |
|
||||
|---|---|---|
|
||||
| "Unrecognized host/PassKey" | Browser IP ≠ VPN IP (private tracker mismatch) | Set up Mousehole with MAM Dynamic Seedbox API |
|
||||
| "Non-Whitelisted client or version" | Client not on tracker's allowed list | Check tracker's allowed clients page; may need to downgrade/pin a version |
|
||||
| Stalled torrent, no peers | Tracker not being contacted or port not reachable | Verify QBT port matches forwarded port, check tracker reachability: `curl -s -o /dev/null -w "%{http_code}" "<tracker-announce-url>"` |
|
||||
| Port mismatch | Gluetun forwarded port ≠ QBT listening port | After Gluetun restart, check `docker exec gluetun cat /tmp/gluetun/forwarded_port` and update QBT config |
|
||||
|
||||
## Pitfalls & Gotchas
|
||||
|
||||
### qBittorrent WebUI: IPv6-Only Binding on linuxserver.io Images
|
||||
|
||||
**Symptom:** qBittorrent logs "WebUI: Now listening on IP: *, port: 8080" but the
|
||||
WebUI is unreachable from the Docker host via IPv4. Connection gets "Connection refused"
|
||||
on the container's Docker IP, even though qBittorrent is running and healthy.
|
||||
|
||||
**Root cause:** On linuxserver.io qBittorrent images (v5.2.x), the start script changes
|
||||
`WebUI\Address=*` to `WebUI\Address=localhost` before launch. qBittorrent 5.2.x then
|
||||
binds the WebUI **only to IPv6** (`[::]:8080`). The Docker proxy connects via IPv4
|
||||
(the container's Docker IP), which fails because nothing is listening on IPv4:8080.
|
||||
|
||||
**Diagnosis:**
|
||||
```
|
||||
docker exec qbittorrent sh -c 'cat /proc/net/tcp /proc/net/tcp6' | grep -i "1F90"
|
||||
```
|
||||
- `/proc/net/tcp` (IPv4) — port 8080 (0x1F90) ABSENT
|
||||
- `/proc/net/tcp6` (IPv6) — port 8080 PRESENT on `[::]:1F90`
|
||||
|
||||
**Fix:** Set `WebUI\Address=0.0.0.0` in qBittorrent.conf (instead of `*`).
|
||||
The start script's localhost override only triggers on empty or `*` values.
|
||||
Then restart qBittorrent.
|
||||
|
||||
### Port Binding
|
||||
- `127.0.0.1:5010:5010` binds to localhost ONLY — not accessible from LAN or other containers
|
||||
- Use `0.0.0.0:5010:5010` or just `5010:5010` for LAN access
|
||||
- Default `docker compose restart` does NOT pick up port binding changes — use `docker compose up -d --force-recreate <service>` instead
|
||||
|
||||
### Mousehole Host Header
|
||||
- Default `MOUSEHOLE_ALLOWED_HOSTS` only allows `localhost`, `127.0.0.1`, `[::1]`
|
||||
- Add your LAN IP or hostname when accessing from another machine
|
||||
|
||||
### Gluetun Recreates
|
||||
- When Gluetun is recreated, qBittorrent may auto-detach if using `network_mode: service:gluetun`
|
||||
- Docker Compose handles this correctly via container name, not container ID
|
||||
- The PIA VPN IP WILL change on restart — Mousehole handles re-registration
|
||||
|
||||
### Gluetun VPN IP Changes
|
||||
- PIA and other VPN providers assign different IPs on reconnect
|
||||
- This perfectly normal — Mousehole re-registers the new IP with the tracker
|
||||
- Check current VPN IP: `docker exec gluetun cat /tmp/gluetun/ip`
|
||||
|
||||
### Stale Containers
|
||||
- Old, unhealthy gluetun instances (e.g., `vigorous_lewin`) can sit around after config changes
|
||||
- Check for them with `docker ps -a` and clean up: `docker rm <container>`
|
||||
|
||||
### Port Forwarding Verification
|
||||
1. Check forwarded port: `docker exec gluetun cat /tmp/gluetun/forwarded_port`
|
||||
2. Check what port QBT is listening on from its logs or config
|
||||
3. Test port is open on VPN interface: `docker exec qbittorrent python3 -c "import socket; s=socket.socket(); s.settimeout(3); print(s.connect_ex(('10.26.x.x', 36590)))"` (use actual tun0 IP from QBT logs)
|
||||
|
||||
### Tracker Connectivity Test
|
||||
- From inside the container: `docker exec qbittorrent curl -s -o /dev/null -w "%{http_code} (%{time_total}s)" --connect-timeout 15 "<tracker-url>"`
|
||||
- A 404 on the announce URL is expected (missing required params) — means the tracker is reachable
|
||||
- A 200 with "failure reason" means tracker is rejecting the announce specifically — check the reason text
|
||||
|
||||
## Verification
|
||||
|
||||
After setup, confirm:
|
||||
1. Gluetun is healthy: `docker ps --filter name=gluetun --format '{{.Status}}'`
|
||||
2. Port forwarding is active: `docker exec gluetun cat /tmp/gluetun/forwarded_port`
|
||||
3. qBittorrent is using the forwarded port from its config
|
||||
4. Mousehole shows OK status after cookie is set
|
||||
5. Add a public tracker torrent to qBittorrent to verify general connectivity
|
||||
6. Add the private tracker torrent and check tracker status via MAM's tracker detail page
|
||||
@@ -0,0 +1,41 @@
|
||||
# Getting a MAM Session Cookie for Mousehole
|
||||
|
||||
These are the exact steps to create a MAM API session and get the cookie for Mousehole.
|
||||
|
||||
## Step 1: Go to MAM Security Settings
|
||||
|
||||
Make sure you are logged into MAM on your browser.
|
||||
Navigate to: https://www.myanonamouse.net/preferences/index.php?view=security
|
||||
|
||||
## Step 2: Create a New Session
|
||||
|
||||
In the "Create session" section at the bottom of the page, enter:
|
||||
|
||||
| Field | Value | Why |
|
||||
|---|---|---|
|
||||
| IP | Use the IP shown on Mousehole's own page (it knows its own IP since it shares the VPN network) | Must be the VPN IP, not your browser IP |
|
||||
| IP vs ASN locked session | **ASN** | Allows the PIA VPN IP to change without breaking the session |
|
||||
| Allow Session to set Dynamic Seedbox | **Yes** | This is what lets Mousehole register the VPN IP via the API |
|
||||
| Session Label | `mousehole` | Any text, just for identification |
|
||||
|
||||
Then click **Submit Changes!**
|
||||
|
||||
## Step 3: Copy the Cookie
|
||||
|
||||
MAM will show you a cookie value after creating the session.
|
||||
Copy it to your clipboard — this is a one-time display.
|
||||
|
||||
## Step 4: Paste into Mousehole
|
||||
|
||||
1. Open Mousehole at http://192.168.50.98:5010 (or your host's LAN IP)
|
||||
2. Log in with the MOUSEHOLE_AUTH_PASSWORD
|
||||
3. Paste the cookie into the text box
|
||||
4. Click **Set**
|
||||
|
||||
You should see an OK status after that.
|
||||
|
||||
## Important
|
||||
|
||||
- Do NOT share this cookie with any other service (Prowlarr, Jackett, etc.)
|
||||
- MAM rotates the cookie value on each API call, so any other client sharing this cookie will break
|
||||
- If the cookie stops working (failed API calls), create a new session on MAM and update Mousehole
|
||||
Reference in New Issue
Block a user