Build a fully automated media server with Docker — movies, TV shows, music, and subtitles discovered, downloaded, organized, and served automatically.
A mediastack is a collection of self-hosted applications that work together to:
All of this happens automatically. You (or your family) request a movie, and it appears in Plex within minutes — downloaded, renamed, moved to the right folder, with subtitles.
| App | Role | One-sentence summary |
|---|---|---|
| Gluetun | VPN container | Runs a VPN tunnel that other containers route traffic through |
| qBittorrent | Download client | Downloads torrents through the VPN |
| Prowlarr | Indexer manager | Connects to torrent sites and shares them with Sonarr/Radarr/Lidarr |
| Sonarr | TV show manager | Monitors TV shows, searches for new episodes, sends them to qBittorrent |
| Radarr | Movie manager | Same as Sonarr but for movies |
| Lidarr | Music manager | Same as Sonarr but for music albums |
| Bazarr | Subtitle manager | Automatically downloads subtitles for everything Sonarr and Radarr grab |
| Plex | Media server | Serves your library to TVs, phones, and browsers |
| Seerr | Request manager | Pretty UI where users can browse and request movies/shows |
| Recyclarr | Quality sync | Automatically applies community-recommended quality profiles |
| FlareSolverr | CAPTCHA solver | Helps Prowlarr access indexers that use Cloudflare protection |
Here's the flow when someone requests a movie:
All torrent traffic goes through Gluetun. The *arr apps (Sonarr, Radarr, etc.) and qBittorrent all run on a Docker network that routes through Gluetun's VPN tunnel. If the VPN drops, traffic stops — nothing leaks to your real IP.
Gluetun exposes ports for all the services behind it. When you access Sonarr at http://your-server:8989, the request goes: your browser → Gluetun (port 8989) → Sonarr container. But when Sonarr searches indexers, the traffic goes: Sonarr → Gluetun → VPN tunnel → internet.
Every container needs to run with the same user and group IDs so file permissions work. Find yours:
id
# Output: uid=1000(youruser) gid=1000(youruser) groups=...
Note your uid (PUID) and gid (PGID). You'll use these in every container.
Many guides mount /downloads and /media as separate volumes in each container. This breaks hardlinks. When Sonarr "moves" a completed download to your library, it should create a hardlink (same file, two paths, zero extra disk space). But hardlinks only work within the same filesystem/mount. Separate mounts = separate filesystems = no hardlinks = files get copied instead, using double the disk space.
All containers get the same top-level /data mount. Inside it, downloads and media are subdirectories:
# Create the directory tree
sudo mkdir -p /data/media_stack/qbittorrent/{movies,tv,music}
sudo mkdir -p /data/media/{movies,tv,music}
# Set ownership to your PUID:PGID
sudo chown -R 1000:1000 /data
Every container mounts the same /data directory:
volumes:
- /path/to/your/storage:/data # Same mount in EVERY container
| Container | What it uses inside /data |
|---|---|
| qBittorrent | Downloads to /data/media_stack/qbittorrent/{movies,tv,music} |
| Sonarr | Sees downloads at /data/media_stack/qbittorrent/tv, library at /data/media/tv |
| Radarr | Sees downloads at /data/media_stack/qbittorrent/movies, library at /data/media/movies |
| Lidarr | Sees downloads at /data/media_stack/qbittorrent/music, library at /data/media/music |
| Plex | Reads from /data/media/{movies,tv,music} |
Because they all share the same mount, hardlinks work. When Radarr imports a completed movie, it creates a hardlink from the download folder to the library folder — instant, zero extra disk space. The original stays in the download folder for seeding.
Gluetun is a lightweight container that establishes a VPN tunnel. Other containers connect to the internet through Gluetun by using Docker's network_mode: service:gluetun.
tun0)Without port forwarding, you can download but can't seed properly. Other peers can't initiate connections to you, so your upload speed (and ratio on private trackers) suffers. PIA, Mullvad, and AirVPN support port forwarding through Gluetun.
gluetun:
image: qmcgaw/gluetun:latest
container_name: gluetun
restart: unless-stopped
cap_add:
- NET_ADMIN # Required — Gluetun creates network interfaces
environment:
- VPN_SERVICE_PROVIDER=private internet access
- OPENVPN_USER=your-vpn-username
- OPENVPN_PASSWORD=your-vpn-password
- SERVER_REGIONS=Netherlands # Pick a region close to you
- PORT_FORWARD_ONLY=true # Only connect to servers that support port forwarding
- VPN_PORT_FORWARDING=on # Enable port forwarding
- UPDATER_PERIOD=24h # Update server list daily
- TZ=Europe/Copenhagen
volumes:
- /srv/docker/gluetun:/gluetun
ports:
# Gluetun exposes ports for ALL services behind the VPN.
# These services don't have their own ports: section.
- "8090:8090" # qBittorrent Web UI
- "6881:6881" # qBittorrent torrent port
- "8989:8989" # Sonarr
- "7878:7878" # Radarr
- "8686:8686" # Lidarr
- "9696:9696" # Prowlarr
- "6767:6767" # Bazarr
- "7474:7474" # Autobrr
- "8191:8191" # FlareSolverr
networks:
vpn:
ipv4_address: 172.21.0.2
When your VPN provider assigns a forwarded port, qBittorrent needs to know about it. This script syncs the port from Gluetun's control API to qBittorrent:
#!/bin/bash
# port-sync.sh — run every 5 minutes via cron or as a sidecar container
GLUETUN_API="http://localhost:8000"
QBIT_API="http://localhost:8090"
QBIT_USER="admin"
QBIT_PASS="your-qbit-password"
# Get forwarded port from Gluetun
PORT=$(curl -sf "${GLUETUN_API}/v1/openvpn/portforwarded" | jq -r '.port')
if [ -z "$PORT" ] || [ "$PORT" = "0" ]; then
echo "No forwarded port available"
exit 1
fi
# Log into qBittorrent
COOKIE=$(curl -sf -c - "${QBIT_API}/api/v2/auth/login" \
--data "username=${QBIT_USER}&password=${QBIT_PASS}" | grep SID | awk '{print $NF}')
# Set the listening port
curl -sf "${QBIT_API}/api/v2/app/setPreferences" \
--cookie "SID=${COOKIE}" \
--data "json={\"listen_port\":${PORT}}"
echo "Set qBittorrent listening port to ${PORT}"
qBittorrent does the actual downloading. It runs behind Gluetun so all torrent traffic goes through the VPN.
compose.yaml (qbittorrent service)qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
restart: unless-stopped
network_mode: service:gluetun # Route ALL traffic through Gluetun
depends_on:
gluetun:
condition: service_healthy
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Copenhagen
- UMASK=022
- WEBUI_PORT=8090
volumes:
- /srv/docker/qbittorrent:/config
- /data:/data
Notice: no ports: section. qBittorrent's ports are exposed on the Gluetun container instead.
network_mode: service:gluetun means qBittorrent shares Gluetun's network stack. When qBittorrent connects to a peer, it goes through the VPN tunnel. When you access http://your-server:8090, the request goes to Gluetun's port 8090, which routes to qBittorrent.
http://your-server:8090docker logs qbittorrent 2>&1 | grep "temporary password"/data/media_stack/qbittorrent/Set up download categories so Sonarr/Radarr downloads go to the right subfolder:
| Category | Save Path |
|---|---|
tv | /data/media_stack/qbittorrent/tv |
movies | /data/media_stack/qbittorrent/movies |
music | /data/media_stack/qbittorrent/music |
Create these in qBittorrent: right-click in the left sidebar → "New Category".
Prowlarr is the central place where you configure your torrent indexers. Instead of adding each indexer separately to Sonarr, Radarr, and Lidarr, you add them once in Prowlarr and it syncs them to all the *arr apps.
compose.yaml (prowlarr service)prowlarr:
image: lscr.io/linuxserver/prowlarr:latest
container_name: prowlarr
restart: unless-stopped
network_mode: service:gluetun
depends_on:
gluetun:
condition: service_healthy
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Copenhagen
volumes:
- /srv/docker/prowlarr/config:/config
http://your-server:9696http://localhost:8989, API key from Sonarrhttp://localhost:7878, API key from Radarrhttp://localhost:8686, API key from Lidarrnetwork_mode: service:gluetun. From Prowlarr's perspective, Sonarr is on the same host (localhost), just a different port.
Some indexers use Cloudflare protection. FlareSolverr solves CAPTCHAs for Prowlarr:
flaresolverr:
image: ghcr.io/flaresolverr/flaresolverr:latest
container_name: flaresolverr
restart: unless-stopped
network_mode: service:gluetun
environment:
- TZ=Europe/Copenhagen
In Prowlarr: Settings → Indexers → Add → FlareSolverr → URL: http://localhost:8191
Sonarr manages your TV show library. You tell it which shows you want, and it monitors indexers for new episodes, downloads them, renames them, and moves them to your library.
compose.yaml (sonarr service)sonarr:
image: lscr.io/linuxserver/sonarr:latest
container_name: sonarr
restart: unless-stopped
network_mode: service:gluetun
depends_on:
gluetun:
condition: service_healthy
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Copenhagen
- UMASK=022
volumes:
- sonarr_config:/config # Local volume (see note below)
- /data:/data
sonarr_config). If your storage is local (SSD, HDD), a bind mount (/srv/docker/sonarr:/config) is fine.
http://your-server:8989/data/media/tvlocalhost, Port: 8090, Category: tv/data/media_stack/qbittorrent/tv//data/media/tv/Show Name/Season XX/Radarr is Sonarr but for movies. The setup is nearly identical.
compose.yaml (radarr service)radarr:
image: lscr.io/linuxserver/radarr:latest
container_name: radarr
restart: unless-stopped
network_mode: service:gluetun
depends_on:
gluetun:
condition: service_healthy
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Copenhagen
- UMASK=022
volumes:
- radarr_config:/config
- /data:/data
http://your-server:7878/data/media/movieslocalhost:8090, category moviesQuality profiles determine which releases to grab (Bluray 1080p vs WEB-DL, etc.). The defaults are okay, but Recyclarr (section 14) syncs much better community profiles.
Lidarr manages your music library. Same pattern as Sonarr/Radarr.
compose.yaml (lidarr service)lidarr:
image: lscr.io/linuxserver/lidarr:latest
container_name: lidarr
restart: unless-stopped
network_mode: service:gluetun
depends_on:
gluetun:
condition: service_healthy
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Copenhagen
- UMASK=022
volumes:
- /srv/docker/lidarr/config:/config
- /data:/data
http://your-server:8686/data/media/musiclocalhost:8090, category musicBazarr automatically downloads subtitles for your movies and TV shows. It integrates with Sonarr and Radarr — when a new file is imported, Bazarr checks for subtitles.
compose.yaml (bazarr service)bazarr:
image: lscr.io/linuxserver/bazarr:latest
container_name: bazarr
restart: unless-stopped
network_mode: service:gluetun
depends_on:
gluetun:
condition: service_healthy
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Copenhagen
- UMASK=022
volumes:
- /srv/docker/bazarr/config:/config
- /data:/data
http://your-server:6767http://localhost:8989, API keyhttp://localhost:7878, API keyBazarr scores subtitle matches and picks the best one. It can also upgrade subtitles if a better match appears later.
Plex serves your media library to your devices. It runs on the host network for best performance and DLNA support.
compose.yaml (plex service)plex:
image: lscr.io/linuxserver/plex:latest
container_name: plex
restart: unless-stopped
network_mode: host # Direct access to network (no Docker NAT)
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Copenhagen
- VERSION=docker
- PLEX_CLAIM=claim-xxxxxxxxxxxx # Get from https://plex.tv/claim
volumes:
- /srv/docker/plex/config:/config
- /data/media:/data/media
devices:
- /dev/dri:/dev/dri # GPU for hardware transcoding
network_mode: host — Plex runs directly on the host network. Recommended for discovery (DLNA, GDM) and avoids Docker NAT issues. Port 32400.PLEX_CLAIM — Get a claim token from plex.tv/claim. It expires after 4 minutes, so paste it and start the container quickly./dev/dri — Passes through the GPU for hardware transcoding (Intel Quick Sync, AMD, or NVIDIA). Without this, Plex uses CPU transcoding which is much slower. Requires Plex Pass.http://your-server:32400/web/data/media/movies), TV Shows (/data/media/tv), Music (/data/media/music)Seerr (formerly Overseerr/Jellyseerr) is a user-friendly request interface. Instead of telling your family "go to Radarr and add a movie", you give them a Netflix-like UI where they can browse trending content and click "Request".
compose.yaml (seerr service)seerr:
image: ghcr.io/fallenbagel/jellyseerr:latest
container_name: seerr
restart: unless-stopped
environment:
- TZ=Europe/Copenhagen
volumes:
- /srv/docker/jellyseerr:/app/config
ports:
- "5055:5055"
http://your-server:5055http://your-server-ip:7878, API key, root folder /data/media/movieshttp://your-server-ip:8989, API key, root folder /data/media/tvlocalhost to reach Sonarr/Radarr. Use your server's LAN IP instead (e.g., http://192.168.1.100:8989). These ports are exposed on the Gluetun container.
The default quality profiles in Sonarr/Radarr are basic. The community has spent years building TRaSH Guides — optimized quality profiles with custom formats that prefer proper releases, avoid bad encoders, and score releases intelligently.
Recyclarr syncs these profiles to your Sonarr/Radarr automatically.
compose.yaml (recyclarr service)recyclarr:
image: ghcr.io/recyclarr/recyclarr:latest
container_name: recyclarr
restart: unless-stopped
network_mode: service:gluetun
user: 1000:1000
volumes:
- /srv/docker/recyclarr:/config
/srv/docker/recyclarr/recyclarr.ymlsonarr:
main:
base_url: http://localhost:8989
api_key: your-sonarr-api-key
quality_definition:
type: series
quality_profiles:
- name: WEB-1080p
radarr:
main:
base_url: http://localhost:7878
api_key: your-radarr-api-key
quality_definition:
type: movie
quality_profiles:
- name: HD Bluray + WEB
docker exec recyclarr recyclarr syncThese are optional but useful tools that improve the stack.
Monitors IRC announce channels from your private trackers and grabs releases the instant they're uploaded — before they even appear in RSS feeds. This is how you get the best speeds and build ratio.
autobrr:
image: ghcr.io/autobrr/autobrr:latest
container_name: autobrr
restart: unless-stopped
network_mode: service:gluetun
user: 1000:1000
volumes:
- /srv/docker/autobrr:/config
Setup: http://your-server:7474 → connect to qBittorrent, add tracker IRC channels, create filters.
Automatically tags, categorizes, and cleans up torrents in qBittorrent. Removes unregistered torrents, enforces share ratios, organizes by tracker, maintains a recycle bin.
qbit_manage:
image: bobokun/qbit_manage:latest
container_name: qbit_manage
restart: unless-stopped
network_mode: service:gluetun
environment:
- QBT_RUN=false # Run as daemon (not one-shot)
- QBT_SCHEDULE=30 # Run every 30 minutes
volumes:
- /srv/docker/qbit_manage:/config
- /data:/data
QBT_RUN=true means "run once and exit", which causes a restart loop with restart: unless-stopped. Set it to false and use QBT_SCHEDULE=30 for the daemon to run every 30 minutes.
Scans your existing downloads and finds the same content on other trackers. Seed the same file on multiple trackers without downloading again — free ratio.
cross-seed:
image: crossseed/cross-seed:latest
container_name: cross-seed
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Copenhagen
volumes:
- /srv/docker/cross-seed:/config
- /srv/docker/cross-seed/cross-seeds:/cross-seeds
- /data:/data
ports:
- "2468:2468"
Some trackers upload releases as RAR archives. Unpackerr watches for completed downloads and automatically extracts them so Sonarr/Radarr can import the media files.
unpackerr:
image: golift/unpackerr:latest
container_name: unpackerr
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Copenhagen
volumes:
- /srv/docker/unpackerr:/config
- /data:/data
security_opt:
- no-new-privileges:true
# Check Gluetun is connected
docker exec gluetun curl -sf https://ipinfo.io
# Should show your VPN IP, NOT your real IP
# Check port forwarding
curl -sf http://localhost:8000/v1/openvpn/portforwarded
# Should show {"port":12345}
Set download paths and categories (section 6). Port-sync script handles the forwarded port.
Add indexers, connect to Sonarr/Radarr/Lidarr. Prowlarr auto-syncs indexers to all apps.
For each (Sonarr, Radarr, Lidarr): add root folder, add qBittorrent as download client, note the API key.
Connect to Sonarr/Radarr using their API keys. Add subtitle providers.
Add media libraries pointing to /data/media/{movies,tv,music}.
Connect to Plex, Sonarr, and Radarr.
Here's a minimal but complete compose file for the core stack. Copy this, adjust the paths and credentials, and docker compose up -d.
PUID=1000
PGID=1000
TZ=Europe/Copenhagen
UMASK=022
# VPN credentials
OPENVPN_USER=your-vpn-username
OPENVPN_PASSWORD=your-vpn-password
SERVER_REGIONS=Netherlands
/opt/stacks/mediastack/compose.yaml
services:
# === VPN GATEWAY ===
gluetun:
image: qmcgaw/gluetun:latest
container_name: gluetun
restart: unless-stopped
cap_add:
- NET_ADMIN
environment:
- VPN_SERVICE_PROVIDER=private internet access
- OPENVPN_USER=${OPENVPN_USER}
- OPENVPN_PASSWORD=${OPENVPN_PASSWORD}
- SERVER_REGIONS=${SERVER_REGIONS}
- PORT_FORWARD_ONLY=true
- VPN_PORT_FORWARDING=on
- UPDATER_PERIOD=24h
- TZ=${TZ}
volumes:
- /srv/docker/gluetun:/gluetun
ports:
- "8090:8090" - "8989:8989" - "7878:7878"
- "8686:8686" - "9696:9696" - "6767:6767"
- "7474:7474" - "8191:8191"
networks:
vpn: { ipv4_address: 172.21.0.2 }
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8000/v1/openvpn/status"]
interval: 30s
timeout: 10s
retries: 5
# === DOWNLOAD CLIENT ===
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
restart: unless-stopped
network_mode: service:gluetun
depends_on: { gluetun: { condition: service_healthy } }
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- UMASK=${UMASK}
- WEBUI_PORT=8090
volumes:
- /srv/docker/qbittorrent:/config
- /data:/data
# === INDEXER MANAGER ===
prowlarr:
image: lscr.io/linuxserver/prowlarr:latest
container_name: prowlarr
restart: unless-stopped
network_mode: service:gluetun
depends_on: { gluetun: { condition: service_healthy } }
environment: [PUID=${PUID}, PGID=${PGID}, TZ=${TZ}]
volumes: [/srv/docker/prowlarr/config:/config]
# === TV SHOWS ===
sonarr:
image: lscr.io/linuxserver/sonarr:latest
container_name: sonarr
restart: unless-stopped
network_mode: service:gluetun
depends_on: { gluetun: { condition: service_healthy } }
environment: [PUID=${PUID}, PGID=${PGID}, TZ=${TZ}, UMASK=${UMASK}]
volumes: [sonarr_config:/config, /data:/data]
# === MOVIES ===
radarr:
image: lscr.io/linuxserver/radarr:latest
container_name: radarr
restart: unless-stopped
network_mode: service:gluetun
depends_on: { gluetun: { condition: service_healthy } }
environment: [PUID=${PUID}, PGID=${PGID}, TZ=${TZ}, UMASK=${UMASK}]
volumes: [radarr_config:/config, /data:/data]
# === MUSIC ===
lidarr:
image: lscr.io/linuxserver/lidarr:latest
container_name: lidarr
restart: unless-stopped
network_mode: service:gluetun
depends_on: { gluetun: { condition: service_healthy } }
environment: [PUID=${PUID}, PGID=${PGID}, TZ=${TZ}, UMASK=${UMASK}]
volumes: [/srv/docker/lidarr/config:/config, /data:/data]
# === SUBTITLES ===
bazarr:
image: lscr.io/linuxserver/bazarr:latest
container_name: bazarr
restart: unless-stopped
network_mode: service:gluetun
depends_on: { gluetun: { condition: service_healthy } }
environment: [PUID=${PUID}, PGID=${PGID}, TZ=${TZ}, UMASK=${UMASK}]
volumes: [/srv/docker/bazarr/config:/config, /data:/data]
# === CAPTCHA SOLVER ===
flaresolverr:
image: ghcr.io/flaresolverr/flaresolverr:latest
container_name: flaresolverr
restart: unless-stopped
network_mode: service:gluetun
environment: [TZ=${TZ}]
# === QUALITY PROFILES ===
recyclarr:
image: ghcr.io/recyclarr/recyclarr:latest
container_name: recyclarr
restart: unless-stopped
network_mode: service:gluetun
user: ${PUID}:${PGID}
volumes: [/srv/docker/recyclarr:/config]
volumes:
sonarr_config: { driver: local }
radarr_config: { driver: local }
networks:
vpn:
driver: bridge
ipam:
config:
- subnet: 172.21.0.0/16
Here's the exact order to configure everything after docker compose up -d:
docker compose logs -f gluetun — wait for "healthy" status:8090, check logs for temp password (docker logs qbittorrent 2>&1 | grep "temporary password"), change it, set download paths, create categories (tv, movies, music):8989, set auth, add root folder /data/media/tv, add qBittorrent (localhost:8090, category tv), copy API key:7878, same as Sonarr but root folder /data/media/movies, category movies, copy API key:8686, root folder /data/media/music, category music, copy API key:9696, set auth, add indexers, connect to Sonarr/Radarr/Lidarr via Settings → Apps using localhost URLs + API keys, hit Sync:6767, connect to Sonarr (localhost:8989) and Radarr (localhost:7878) with API keys, add subtitle providers, set languages:32400/web, sign in, add libraries: /data/media/movies, /data/media/tv, /data/media/music:5055, connect to Plex, add Radarr (http://your-LAN-ip:7878) and Sonarr (http://your-LAN-ip:8989) with API keys| Problem | Fix |
|---|---|
| Gluetun won't connect | Check VPN credentials. Check docker logs gluetun. Try a different SERVER_REGIONS. |
| "All connections failed" | Server list outdated. Delete /srv/docker/gluetun/servers.json and restart. |
| qBittorrent can't reach the internet | Gluetun not healthy. Check docker compose ps. |
| Real IP showing in qBittorrent | network_mode: service:gluetun is missing. Verify: docker exec qbittorrent curl -sf https://ipinfo.io |
| Problem | Fix |
|---|---|
| "Unable to connect to indexer" | Prowlarr indexers not synced. Go to Prowlarr → Settings → Apps → Sync. |
| "Download client unavailable" | Use localhost:8090 (not server IP) since both are on network_mode: service:gluetun. |
| "Import failed: destination exists" | Duplicate file. Check if already imported. May need to clear the download queue. |
| "Database is locked" | Config is on NFS. Move to a local Docker volume (see section 8). |
| Sonarr/Radarr can't find downloads | Wrong download path. Both must share the same /data mount. |
| Problem | Fix |
|---|---|
| Can't find media | Library path wrong. Must match: /data/media/movies, /data/media/tv. |
| Claim token expired | Tokens last 4 minutes. Generate new at plex.tv/claim, update compose, recreate. |
| Hardware transcoding not working | Check /dev/dri exists. Add user to video group. Requires Plex Pass. |
/data:/data)df -h /data)ls -li — hardlinked files have the same inode number| From → To | URL to use | Why |
|---|---|---|
| Sonarr → qBittorrent | localhost:8090 | Both on network_mode: service:gluetun |
| Prowlarr → Sonarr | localhost:8989 | Same reason |
| Bazarr → Sonarr | localhost:8989 | Same reason |
| Seerr → Sonarr | http://192.168.x.x:8989 | Seerr is NOT behind VPN — use host IP |
| Plex → media | Direct filesystem | Host network, reads files directly |
| Term | Meaning |
|---|---|
| Hardlink | A second filename pointing to the same data on disk. Two paths, one file, one set of disk space. Only works within the same filesystem. |
| Seed/Seeding | Uploading a file to other torrent users after downloading it. Required by most private trackers. |
| Ratio | Upload divided by download. Private trackers often require 1.0+ (upload as much as you download). |
| Indexer | A torrent site/tracker that lists available torrents. Prowlarr connects to these. |
| Custom Format | A scoring rule in Sonarr/Radarr that gives points to releases matching criteria (e.g., +10 for Bluray, -50 for CAM). |
| Quality Profile | Rules defining which quality levels are acceptable and in what order to prefer them. |
| Port Forwarding (VPN) | Your VPN provider assigns you a port that external peers can connect to. Without it, seeding is slow. |
| TRaSH Guides | Community-maintained guides for optimal *arr configuration. The gold standard for quality profiles. |
| network_mode: service:X | Docker feature that makes a container share another container's network. Used to route traffic through Gluetun. |