migrate
This commit is contained in:
@@ -0,0 +1,431 @@
|
||||
---
|
||||
tags:
|
||||
- Docker
|
||||
- Media
|
||||
---
|
||||
Directory Structure
|
||||
cd docker
|
||||
mkdir -p ~/arr-stack/{config/{gluetun,qbittorrent,prowlarr,radarr,sonarr},data/{torrents,media/{movies,tv}}}
|
||||
cd ~/arr-stack
|
||||
touch docker-compose.yml .env
|
||||
|
||||
|
||||
```
|
||||
# Tom Spark's ARR Stack — Automated Media Server
|
||||
# https://github.com/loponai/arrstack
|
||||
#
|
||||
# Usage:
|
||||
# 1. Copy .env.example to .env and fill in your VPN credentials
|
||||
# 2. Run: bash setup-folders.sh
|
||||
# 3. Run: docker compose up -d
|
||||
#
|
||||
# All VPN-protected services (qBittorrent, Prowlarr, FlareSolverr) run
|
||||
# through Gluetun. If the VPN drops, traffic stops. Zero leaks.
|
||||
#
|
||||
# Radarr, Sonarr, Lidarr, Bazarr, Jellyfin, and Seerr do NOT run through
|
||||
# the VPN — they need direct network access for speed and local connectivity.
|
||||
|
||||
networks:
|
||||
arrnetwork:
|
||||
name: arrnetwork
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.39.0.0/24
|
||||
|
||||
services:
|
||||
|
||||
# ============================================================
|
||||
# GLUETUN — VPN Container (kill switch + tunnel)
|
||||
# All VPN-protected services route through this container.
|
||||
# Ports for those services are mapped HERE, not on the services themselves.
|
||||
# Docs: https://github.com/qdm12/gluetun-wiki
|
||||
# ============================================================
|
||||
gluetun:
|
||||
image: qmcgaw/gluetun:latest
|
||||
container_name: gluetun
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
networks:
|
||||
arrnetwork:
|
||||
ipv4_address: ${IP_GLUETUN}
|
||||
ports:
|
||||
- 8000:8000 # Gluetun Control Server
|
||||
- 8080:8080 # qBittorrent WebUI
|
||||
- 6881:6881 # qBittorrent torrenting port
|
||||
- 6881:6881/udp
|
||||
- 9696:9696 # Prowlarr
|
||||
- 8191:8191 # FlareSolverr
|
||||
volumes:
|
||||
- ./gluetun:/gluetun
|
||||
environment:
|
||||
- VPN_SERVICE_PROVIDER=${VPN_SERVICE_PROVIDER}
|
||||
- VPN_TYPE=${VPN_TYPE}
|
||||
# --- WireGuard credentials (most providers) ---
|
||||
- WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
|
||||
- WIREGUARD_ADDRESSES=${WIREGUARD_ADDRESSES}
|
||||
# - WIREGUARD_PUBLIC_KEY=${WIREGUARD_PUBLIC_KEY}
|
||||
- WIREGUARD_PRESHARED_KEY=${WIREGUARD_PRESHARED_KEY}
|
||||
# --- OpenVPN credentials (if using OpenVPN instead) ---
|
||||
# - OPENVPN_USER=${OPENVPN_USER}
|
||||
# - OPENVPN_PASSWORD=${OPENVPN_PASSWORD}
|
||||
# --- Server selection ---
|
||||
- SERVER_COUNTRIES=${SERVER_COUNTRIES}
|
||||
# --- Port forwarding (ProtonVPN, AirVPN, PIA) ---
|
||||
# - VPN_PORT_FORWARDING=${VPN_PORT_FORWARDING}
|
||||
- FIREWALL_VPN_INPUT_PORTS=${FIREWALL_VPN_INPUT_PORTS}
|
||||
# --- General ---
|
||||
- TZ=${TZ}
|
||||
- BLOCK_MALICIOUS=off
|
||||
- HTTP_CONTROL_SERVER_ADDRESS=:8000
|
||||
- HTTP_CONTROL_SERVER_LOG=on
|
||||
- HTTP_CONTROL_SERVER_AUTH_DEFAULT_ROLE={"auth":"none"}
|
||||
healthcheck:
|
||||
test: wget -qO /dev/null http://127.0.0.1:9999 || exit 1
|
||||
interval: 20s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================================
|
||||
# QBITTORRENT — Torrent Client (runs through Gluetun VPN)
|
||||
# ALL traffic goes through the VPN tunnel. No direct internet.
|
||||
# ============================================================
|
||||
qbittorrent:
|
||||
image: lscr.io/linuxserver/qbittorrent:latest
|
||||
container_name: qbittorrent
|
||||
network_mode: service:gluetun
|
||||
depends_on:
|
||||
gluetun:
|
||||
condition: service_healthy
|
||||
restart: true
|
||||
labels:
|
||||
- deunhealth.restart.on.unhealthy=true
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- UMASK=002
|
||||
- TZ=${TZ}
|
||||
- WEBUI_PORT=8080
|
||||
- TORRENTING_PORT=${FIREWALL_VPN_INPUT_PORTS}
|
||||
volumes:
|
||||
- ./qbittorrent:/config
|
||||
- /data:/data
|
||||
healthcheck:
|
||||
test: wget -q --spider http://localhost:8080 || exit 1
|
||||
interval: 60s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 20s
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================================
|
||||
# DEUNHEALTH — Auto-restarts unhealthy containers
|
||||
# If qBittorrent loses VPN connection, this restarts it automatically.
|
||||
# ============================================================
|
||||
deunhealth:
|
||||
image: qmcgaw/deunhealth
|
||||
container_name: deunhealth
|
||||
network_mode: none
|
||||
environment:
|
||||
- LOG_LEVEL=info
|
||||
- HEALTH_SERVER_ADDRESS=127.0.0.1:9999
|
||||
- TZ=${TZ}
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
restart: always
|
||||
# ============================================================
|
||||
# PROWLARR — Indexer Manager (runs through Gluetun VPN)
|
||||
# Manages torrent/usenet indexers. Syncs to Radarr/Sonarr/Lidarr.
|
||||
# ============================================================
|
||||
prowlarr:
|
||||
image: lscr.io/linuxserver/prowlarr:latest
|
||||
container_name: prowlarr
|
||||
network_mode: service:gluetun
|
||||
depends_on:
|
||||
gluetun:
|
||||
condition: service_healthy
|
||||
restart: true
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- UMASK=002
|
||||
- TZ=${TZ}
|
||||
volumes:
|
||||
- ./prowlarr:/config
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================================
|
||||
# FLARESOLVERR — Cloudflare Bypass (runs through Gluetun VPN)
|
||||
# Some indexers use Cloudflare protection. This gets around it.
|
||||
# ============================================================
|
||||
flaresolverr:
|
||||
image: ghcr.io/flaresolverr/flaresolverr:latest
|
||||
container_name: flaresolverr
|
||||
network_mode: service:gluetun
|
||||
depends_on:
|
||||
gluetun:
|
||||
condition: service_healthy
|
||||
restart: true
|
||||
environment:
|
||||
- LOG_LEVEL=info
|
||||
- TZ=${TZ}
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================================
|
||||
# RADARR — Movie Manager (NOT behind VPN)
|
||||
# Searches via Prowlarr, sends downloads to qBittorrent,
|
||||
# renames and hard-links completed files to media folder.
|
||||
# ============================================================
|
||||
radarr:
|
||||
image: lscr.io/linuxserver/radarr:latest
|
||||
container_name: radarr
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- UMASK=002
|
||||
- TZ=${TZ}
|
||||
volumes:
|
||||
- ./radarr:/config
|
||||
- /data:/data
|
||||
ports:
|
||||
- 7878:7878
|
||||
networks:
|
||||
arrnetwork:
|
||||
ipv4_address: ${IP_RADARR}
|
||||
restart: unless-stopped
|
||||
# ============================================================
|
||||
# SONARR — TV Show Manager (NOT behind VPN)
|
||||
# Same pattern as Radarr but for TV series.
|
||||
# ============================================================
|
||||
sonarr:
|
||||
image: lscr.io/linuxserver/sonarr:latest
|
||||
container_name: sonarr
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- UMASK=002
|
||||
- TZ=${TZ}
|
||||
volumes:
|
||||
- ./sonarr:/config
|
||||
- /data:/data
|
||||
ports:
|
||||
- 8989:8989
|
||||
networks:
|
||||
arrnetwork:
|
||||
ipv4_address: ${IP_SONARR}
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================================
|
||||
# LIDARR — Music Manager (NOT behind VPN)
|
||||
# Optional. Comment out if you don't need music automation.
|
||||
# ============================================================
|
||||
lidarr:
|
||||
image: lscr.io/linuxserver/lidarr:latest
|
||||
container_name: lidarr
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- UMASK=002
|
||||
- TZ=${TZ}
|
||||
volumes:
|
||||
- ./lidarr:/config
|
||||
- /data:/data
|
||||
ports:
|
||||
- 8686:8686
|
||||
networks:
|
||||
arrnetwork:
|
||||
ipv4_address: ${IP_LIDARR}
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================================
|
||||
# BAZARR — Subtitle Manager (NOT behind VPN)
|
||||
# Automatically downloads subtitles for movies and TV shows.
|
||||
# ============================================================
|
||||
bazarr:
|
||||
image: lscr.io/linuxserver/bazarr:latest
|
||||
container_name: bazarr
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- UMASK=002
|
||||
- TZ=${TZ}
|
||||
volumes:
|
||||
- ./bazarr:/config
|
||||
- /data:/data
|
||||
ports:
|
||||
- 6767:6767
|
||||
networks:
|
||||
arrnetwork:
|
||||
ipv4_address: ${IP_BAZARR}
|
||||
restart: unless-stopped
|
||||
# ============================================================
|
||||
# JELLYFIN — Media Server (NOT behind VPN)
|
||||
# Your personal streaming service. Plays movies, TV, music.
|
||||
# Needs full bandwidth — never put this behind the VPN.
|
||||
# ============================================================
|
||||
jellyfin:
|
||||
image: lscr.io/linuxserver/jellyfin:latest
|
||||
container_name: jellyfin
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- UMASK=002
|
||||
- TZ=${TZ}
|
||||
volumes:
|
||||
- ./jellyfin:/config
|
||||
- /data/media:/data/media
|
||||
ports:
|
||||
- 8096:8096
|
||||
# Uncomment the lines below to enable hardware transcoding (Intel Quick Sync / VAAPI).
|
||||
# Only works if your system has Intel/AMD integrated graphics (/dev/dri must exist).
|
||||
# If you get an error about /dev/dri not found, leave these commented out.
|
||||
# devices:
|
||||
# - /dev/dri:/dev/dri
|
||||
networks:
|
||||
arrnetwork:
|
||||
ipv4_address: ${IP_JELLYFIN}
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================================
|
||||
# SEERR — Request System (NOT behind VPN)
|
||||
# Netflix-like UI for requesting movies and TV shows.
|
||||
# Share this with family — they never need to touch Radarr.
|
||||
#
|
||||
# Seerr is the unified successor to Overseerr and Jellyseerr
|
||||
# (merged under seerr-team). Supports Plex, Jellyfin, and Emby.
|
||||
#
|
||||
# Config uses a NAMED Docker volume (not a bind mount). This is
|
||||
# required: Seerr runs as the `node` user (UID 1000) and a
|
||||
# bind-mounted host folder is created root-owned, causing a
|
||||
# permission-denied crash loop. On Windows/WSL, bind mounts also
|
||||
# corrupt the SQLite DB over SMB. Named volumes fix both cases
|
||||
# (matches upstream Seerr docs).
|
||||
#
|
||||
# Migrating from ./jellyseerr or ./seerr bind mount? See README
|
||||
# troubleshooting "Migrating Seerr config to a named volume".
|
||||
# ============================================================
|
||||
seerr:
|
||||
image: ghcr.io/seerr-team/seerr:v3.0.1
|
||||
init: true
|
||||
container_name: seerr
|
||||
environment:
|
||||
- LOG_LEVEL=info
|
||||
- TZ=${TZ}
|
||||
- PORT=5055
|
||||
volumes:
|
||||
- seerr_config:/app/config
|
||||
ports:
|
||||
- 5055:5055
|
||||
healthcheck:
|
||||
test: wget --no-verbose --tries=1 --spider http://localhost:5055/api/v1/settings/public || exit 1
|
||||
start_period: 20s
|
||||
timeout: 3s
|
||||
interval: 15s
|
||||
retries: 3
|
||||
networks:
|
||||
arrnetwork:
|
||||
ipv4_address: ${IP_SEERR}
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================================
|
||||
# AUDIO BookShelf — Server (NOT behind VPN)
|
||||
# Your personal streaming service. Plays all audiobooks.
|
||||
# Needs full bandwidth — never put this behind the VPN.
|
||||
# ============================================================
|
||||
audiobookshelf:
|
||||
image: ghcr.io/advplyr/audiobookshelf:latest
|
||||
container_name: audiobookshelf
|
||||
ports:
|
||||
- 13378:80
|
||||
volumes:
|
||||
- /data/media/audiobookshelf/books:/audiobooks
|
||||
- /data/media/audiobookshelf/podcasts:/podcasts
|
||||
- /data/media/audiobookshelf/metadata:/metadata
|
||||
- ./audiobookshelf/config:/config
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
arrnetwork:
|
||||
ipv4_address: ${IP_AUDIO}
|
||||
|
||||
# ============================================================
|
||||
# NAVIDROME — Music Media Server (NOT behind VPN)
|
||||
# Your personal streaming service. Plays music.
|
||||
# Needs full bandwidth — never put this behind the VPN.
|
||||
# ============================================================
|
||||
navidrome:
|
||||
image: deluan/navidrome:latest
|
||||
user: 1000:1000
|
||||
container_name: navidrome
|
||||
ports:
|
||||
- 4533:4533
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
ND_SCANSCHEDULE: "1h"
|
||||
ND_LOGLEVEL: info
|
||||
ND_SESSIONTIMEOUT: "24h"
|
||||
volumes:
|
||||
- ./navi/data:/data
|
||||
- /data/media/music:/music:ro
|
||||
networks:
|
||||
arrnetwork:
|
||||
ipv4_address: ${IP_NAVI}
|
||||
|
||||
volumes:
|
||||
seerr_config:
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 2. Step-by-Step qBittorrent Configuration
|
||||
|
||||
Once your stack is running via `docker compose up -d`, navigate to your qBittorrent interface at `http://localhost:8118` or your server's IP address (e.g., `[http://192.168.1.50:8118](http://192.168.1.50:8118)`).
|
||||
|
||||
### Step 2a: Log In and Find Credentials
|
||||
|
||||
- Look at your container logs (`docker logs qbittorrent`) to locate the **temporary password** generated automatically by linuxserver/qbittorrent for security.
|
||||
|
||||
- Use `admin` as the username and paste that password.
|
||||
|
||||
- _Recommended:_ Instantly go to **Tools > Options > Web UI** to change the password to a permanent one.
|
||||
|
||||
|
||||
### Step 2b: Configure Connection & Port Forwarding
|
||||
|
||||
This ensures your traffic efficiently routes through AirVPN's system:
|
||||
|
||||
**1.Open Connection Settings:**Inside Web UI.
|
||||
|
||||
Go to **Tools** in the top navigation bar and select **Options**. In the sidebar menu that pops up, click on **Connection**.
|
||||
|
||||
**2.Set the Torrenting Port:**Match Gluetun mapping.
|
||||
|
||||
Locate **Port used for incoming connections** and type in exactly: `29261`.
|
||||
|
||||
**3.Disable UPnP / NAT-PMP:**Security step.
|
||||
|
||||
**Uncheck** the box next to _Use UPnP / NAT-PMP port forwarding from my router_. Your VPN handles port assignment, so your local router shouldn't intervene.
|
||||
|
||||
### Step 2c: Bind to the VPN Interface (The Hard Kill Switch)
|
||||
|
||||
Binding ensures that if Gluetun ever collapses, leaks, or drops connection, qBittorrent immediately stops downloading or seeding instead of trying to pass data via an unprotected network.
|
||||
|
||||
**1.Open Advanced Panel:**Scroll down sidebar.
|
||||
|
||||
While still in the Options menu, scroll down the left sidebar panel and select **Advanced**.
|
||||
|
||||
**2.Bind Network Interface:**Target VPN tunnel.
|
||||
|
||||
Look for **Network interface** near the top of the list. Change the dropdown menu from _Any interface_ to exactly **`tun0`**.
|
||||
|
||||
**3.Bind IP Address:**Optional but safer.
|
||||
|
||||
Look right underneath at the **Optional IP address to bind to** setting. Change it from _All addresses_ to **`All IPv4 addresses`**.
|
||||
|
||||
**4.Save and Restart:**Apply changes.
|
||||
|
||||
Click **Save / Apply** at the bottom right. Restart your container with `docker compose restart qbittorrent` to guarantee the network interfaces lock into place cleanly.
|
||||
Reference in New Issue
Block a user