Files
2026-07-20 09:23:17 -04:00
..
2026-07-20 09:23:17 -04:00
2026-07-20 09:23:17 -04:00
2026-07-20 09:23:17 -04:00
2026-07-20 09:23:17 -04:00
2026-07-20 09:23:17 -04:00
2026-07-20 09:23:17 -04:00

Want the easy, full version? → SparkBox

This is one of my original one-shot scripts. It still works — but these days everything I build goes into **[SparkBox](https://tomsparkbo>

👉 Get it free at tomsparkbox.com

Built by Tom Spark Reviews.


Tom Spark's ARR Stack

One-command automated media server with VPN protection. Sonarr, Radarr, Prowlarr, qBittorrent, Gluetun, Jellyfin, and more.

Full video tutorial: [YouTube Link Coming Soon]

What You Get

Service Port Purpose
Gluetun VPN tunnel with kill switch
qBittorrent 8080 Torrent client (VPN protected)
Prowlarr 9696 Indexer manager (VPN protected)
FlareSolverr 8191 Cloudflare bypass (VPN protected)
Radarr 7878 Movie automation
Sonarr 8989 TV show automation
Lidarr 8686 Music automation
Bazarr 6767 Subtitle automation
Jellyfin 8096 Media server / streaming
Seerr 5055 Netflix-like request UI (Overseerr/Jellyseerr successor)

All download traffic routes through Gluetun's VPN tunnel. If the VPN drops, all traffic stops — zero leaks. The deunhealth container auto-r>

Quick Start

1. Install Docker

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Log out and back in for group change to take effect

2. Clone this repo

git clone https://github.com/loponai/arrstack.git
cd arrstack

3. Create folder structure

sudo bash setup-folders.sh

This creates:

/data/
├── torrents/     ← qBittorrent downloads here
│   ├── movies/
│   ├── tv/
│   └── music/
└── media/        ← Radarr/Sonarr organize files here (Jellyfin reads from here)
    ├── movies/
    ├── tv/
    └── music/

Hard links: Both folders MUST be on the same drive/filesystem. Radarr and Sonarr create hard links (not copies) — the file appears in>

4. Configure your VPN

cp .env.example .env
nano .env

Fill in your VPN provider and credentials. See VPN Setup Guides below.

5. Launch

docker compose up -d

6. Verify everything is working

bash test-stack.sh

This runs a full health check — Docker status, VPN connection, IP leak test, service accessibility, hard link support, and folder permissio>

You can also check manually:

# Check Gluetun's IP (should be VPN, not your real IP)
docker exec gluetun wget -qO- ifconfig.me

# qBittorrent shares Gluetun's network, so the above proves both are tunneled.
docker exec qbittorrent wget -qO- ifconfig.me

# Check health status of all containers
docker ps --format "table {{.Names}}\t{{.Status}}"

7. Configure services

Open each service in your browser at http://YOUR-SERVER-IP:PORT and follow the video tutorial for step-by-step configuration.

Quick reference:

  • qBittorrent (:8080) — Get temp password: docker logs qbittorrent 2>&1 | grep "temporary password"
  • Prowlarr (:9696) — Add indexers, connect to Radarr/Sonarr. If an indexer is blocked by Cloudflare, set up FlareSolverr as a proxy: >
  • Radarr (:7878) — Root folder: /data/media/movies, download client category: movies
  • Sonarr (:8989) — Root folder: /data/media/tv, download client category: tv
  • Jellyfin (:8096) — Add libraries: /data/media/movies, /data/media/tv, /data/media/music. To watch, open `http://YOUR-SERVER-I>
  • Seerr (:5055) — Connect to Jellyfin, Radarr, and Sonarr. Seerr is the unified successor to Overseerr/Jellyseerr. If you previously >

Internal Docker IPs — use these when connecting services to each other (NOT localhost):

IP Service
172.39.0.2 Gluetun (also qBittorrent, Prowlarr, FlareSolverr)
172.39.0.3 Radarr
172.39.0.4 Sonarr
172.39.0.5 Lidarr
172.39.0.6 Bazarr
172.39.0.7 Jellyfin
172.39.0.8 Seerr

These IPs are the same for everyone — they're hardcoded in the docker-compose file. Common connections:

  • Radarr/Sonarr → Download Client → qBittorrent: host 172.39.0.2, port 8080
  • Prowlarr → Apps → Radarr: server http://172.39.0.3:7878
  • Prowlarr → Apps → Sonarr: server http://172.39.0.4:8989
  • Prowlarr → Apps → Prowlarr Server: http://172.39.0.2:9696
  • Seerr → Radarr: host 172.39.0.3, port 7878
  • Seerr → Sonarr: host 172.39.0.4, port 8989
  • Seerr → Jellyfin: host 172.39.0.7, port 8096

Important Radarr/Sonarr settings:

  • Media Management → Show Advanced → Use Hardlinks instead of Copy → must be ON
  • Media Management → Rename Movies/Episodes → recommended ON

Recommended quality profile (1080p baseline, 4K preferred):

Go to Settings → Profiles and edit or create a profile:

  1. Uncheck everything below 1080p (720p, 480p, etc.)
  2. Check/enable everything from HDTV-1080p up through Bluray-2160p
  3. Set Cutoff to Bluray-1080p — this is the minimum quality Radarr/Sonarr will be happy with
  4. Set Upgrade Until to Bluray-2160p — it will automatically upgrade to 4K if one becomes available

This means it grabs a 1080p release right away so you can start watching, then silently upgrades to 4K later if it finds one.

VPN Setup Guides

The best value for torrenting — cheapest long-term plans, fast WireGuard speeds, and easy setup with Gluetun. [Get Surfshark](https://get.s>

  1. Go to Surfshark Manual Setup
  2. Select WireGuard and get your credentials (private key + address)
  3. In your .env:
VPN_SERVICE_PROVIDER=surfshark
VPN_TYPE=wireguard
WIREGUARD_PRIVATE_KEY=your_key_here
WIREGUARD_ADDRESSES=10.14.0.2/16
SERVER_COUNTRIES=United States

The .env.example file is pre-configured for Surfshark. Just paste your private key and you're good to go.

NordVPN

  1. Go to NordVPN Manual Setup
  2. Select NordLynx (WireGuard) and generate a private key
  3. In your .env:
VPN_SERVICE_PROVIDER=nordvpn
VPN_TYPE=wireguard
WIREGUARD_PRIVATE_KEY=your_key_here
WIREGUARD_ADDRESSES=10.5.0.2/16
SERVER_COUNTRIES=United States

ProtonVPN

  1. Go to ProtonVPN WireGuard Config → Downloads → WireGuard
  2. Generate a config file, open it, copy PrivateKey and Address
  3. In your .env:
VPN_SERVICE_PROVIDER=protonvpn
VPN_TYPE=wireguard
WIREGUARD_PRIVATE_KEY=your_key_here
WIREGUARD_ADDRESSES=10.2.0.2/32
SERVER_COUNTRIES=United States
VPN_PORT_FORWARDING=on

AirVPN

  1. Go to AirVPN Config Generator → Client Area → Config Generator
  2. Select Linux → WireGuard → pick server → Generate
  3. In your .env:
VPN_SERVICE_PROVIDER=airvpn
VPN_TYPE=wireguard
WIREGUARD_PRIVATE_KEY=your_key_here
WIREGUARD_PUBLIC_KEY=server_public_key
WIREGUARD_PRESHARED_KEY=your_preshared_key
WIREGUARD_ADDRESSES=your_ip/32
FIREWALL_VPN_INPUT_PORTS=your_port
VPN_PORT_FORWARDING=on

Other Providers

Gluetun supports 30+ providers. Check the full provider list.

Starting and Stopping

Start the stack:

cd arrstack
docker compose up -d

Stop the stack:

cd arrstack
docker compose down

Check status:

docker ps --format "table {{.Names}}\t{{.Status}}"

Auto-Start After Reboot

All containers are set to restart: unless-stopped, which means they automatically come back once Docker is running. You just need to make>

Linux (dedicated server or VM):

Run this once and you're done:

sudo systemctl enable docker

Windows (running Docker inside WSL):

WSL (Windows Subsystem for Linux) doesn't start Docker automatically when your PC boots. Here's how to fix that:

Step 1: Open your WSL terminal and run this command to edit the WSL config file:

sudo nano /etc/wsl.conf

Step 2: Your file might already have some lines in it (like [boot] or [user]). Look for a [boot] section. If it exists, add the `>

[boot]
command=service docker start

Step 3: Save the file by pressing Ctrl+X, then Y, then Enter. Step 4 (optional): By default, WSL only starts when you open a terminal. If you want it to start automatically when Windows boots (so y>

  1. Press Win+R on your keyboard
  2. Type shell:startup and press Enter — this opens your Windows Startup folder
  3. Right-click in the folder → New → Text Document
  4. Name it wsl.vbs (make sure it ends in .vbs, not .vbs.txt — if you can't see file extensions, go to View → Show → File name extensi>
  5. Right-click the file → Edit (or Open with Notepad) and paste this:
Set ws = CreateObject("Wscript.Shell")
ws.Run "wsl -d Ubuntu -u root -- service docker start", 0
  1. Save and close

That's it — next time your PC restarts, WSL starts Docker automatically and all your containers come back up on their own. No commands need>

Updating

cd arrstack
docker compose pull
docker compose up -d

Remote Access with Tailscale (Optional)

Want to access Jellyfin, Seerr, or any service from outside your home? Tailscale creates a private network betwee>

On your server:

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

On your phone/laptop/TV:

  1. Install Tailscale from your app store
  2. Sign in with the same account

Access your services from anywhere:

http://YOUR-TAILSCALE-IP:8096    ← Jellyfin
http://YOUR-TAILSCALE-IP:5055    ← Seerr
http://YOUR-TAILSCALE-IP:7878    ← Radarr
http://YOUR-TAILSCALE-IP:8989    ← Sonarr

Find your Tailscale IP with tailscale ip -4 on the server.

Tailscale is free for personal use (up to 100 devices). Everything is encrypted with WireGuard — nobody can see your traffic, not even Tail>

Do NOT expose Jellyfin directly to the internet (no port forwarding on your router). Use Tailscale or a reverse proxy instead. Direct>

Sharing with Family and Friends

Your family and friends only need two things — Seerr to request movies/shows and Jellyfin to watch them. They never see Radarr, Son>

Step 1: Invite them to your Tailscale network

  1. Go to the Tailscale admin console
  2. Click Share on your server's machine
  3. Enter their email — they'll get an invite link

Step 2: They install Tailscale

  1. Download Tailscale on their phone, laptop, or TV from tailscale.com/download
  2. Accept your invite and sign in Step 3: They access your services

Give them these two links (replace with your Tailscale IP):

http://YOUR-TAILSCALE-IP:5055    ← Seerr (request movies and shows)
http://YOUR-TAILSCALE-IP:8096    ← Jellyfin (watch everything)

For TVs and phones, they can install the Jellyfin app (available on Roku, Fire TV, Apple TV, Android TV, iOS, Android) and enter yo>

That's it — they request, you automatically download, they watch. No technical knowledge needed on their end.

Troubleshooting

Gluetun unhealthy / won't connect:

  • Double-check VPN credentials in .env — these are NOT your login email/password
  • Try removing the gluetun folder and restarting: rm -rf gluetun && docker compose up -d
  • Check logs: docker logs gluetun

qBittorrent can't connect:

  • Make sure Gluetun is healthy: docker ps (should show "healthy")
  • Check qBit is using VPN: docker exec gluetun wget -qO- ifconfig.me
  • In qBittorrent settings → Advanced → set Network Interface to tun0

Movie or show not downloading:

  • Quality profile too strict — If Radarr/Sonarr can't find a release matching your quality profile, it won't download anything. Go to t>
  • Not enough indexers — Public indexers have limited catalogs. If you only have one or two indexers in Prowlarr, add more (1337x, The P>
  • Not enough seeders — Some torrents just don't have anyone sharing them, especially older or niche content. Check qBittorrent — if the>
  • Indexer blocked by Cloudflare — See the Prowlarr setup note above about setting up FlareSolverr with tags.

Hard links not working (files copying instead):

  • Both /data/torrents and /data/media must be on the same filesystem
  • Check Radarr/Sonarr → Settings → Media Management → "Use Hardlinks" is checked
  • Verify with: ls -i /data/torrents/movies/yourfile and ls -i /data/media/movies/YourMovie/yourfile — inode numbers should match

Permission errors:

  • Run id and make sure PUID/PGID in .env match your user
  • Re-run: sudo chown -R $(id -u):$(id -g) /data

Service won't start — "port already in use":

Another program on your system might be using the same port. This is common with port 5055 (Seerr) but can happen with any service.

  1. Find what's using the port (replace 5055 with the port number from the error):

    Linux:

    sudo ss -tlnp | grep 5055
    

    Windows (WSL users) — run in PowerShell:

    netstat -ano | findstr :5055
    

    This gives you a PID (process ID). Find the program name:

    Get-Process -Id <PID> | Select-Object ProcessName, Id, Path
    
  2. Either stop/disable that program, or change the port in docker-compose.yml to an unused one (e.g. 5056:5055).

  3. If it's a Windows service hogging the port, disable it in an admin PowerShell:

    Stop-Service <ServiceName> -Force
    Set-Service <ServiceName> -StartupType Disabled
    
  4. Then recreate the container:

    docker compose up -d --force-recreate <service-name>
    

Seerr stuck restarting / crash-looping:

The current docker-compose.yml uses a named volume (seerr_config) for Seerr's config, which fixes both causes of the crash loop. If you>

Root cause (for reference):

  • Linux/macOS: Seerr runs as the node user (UID 1000). A bind-mounted ./seerr folder is created root-owned on first `docker compose>
  • Windows/WSL: Bind mounts go through an SMB share inside Docker Desktop's VM, which doesn't support file locking. Seerr's SQLite DB co>

Named volumes sidestep both problems because Docker creates them with correct ownership inside its own managed storage.

If you still see it after pulling:

  • Check logs: docker logs seerr | tail -30
  • Nuke the volume and start fresh (you'll lose Seerr settings, not media):
    docker compose down seerr && docker volume rm arrstack_seerr_config && docker compose up -d seerr
    

Migrating Seerr config to a named volume (existing installs):

If you had Seerr working on an older version of this repo with a bind-mounted ./jellyseerr or ./seerr folder and want to keep your sett>

docker compose down seerr
# pick whichever folder you actually have
SRC=./seerr
[ -d ./jellyseerr ] && SRC=./jellyseerr
docker volume create arrstack_seerr_config
docker run --rm -v "$(pwd)/${SRC#./}":/src -v arrstack_seerr_config:/dest alpine sh -c "cp -a /src/. /dest/ && chown -R 1000:1000 /dest"
docker compose up -d seerr

If you don't care about preserving settings, just docker compose up -d seerr — Seerr will start fresh and walk you through setup again.

Can't log into qBittorrent:

  • qBittorrent generates a temporary password every time it starts. Get it with:
    docker logs qbittorrent 2>&1 | grep "temporary password"
    
  • Default username is admin. Once logged in, go to Tools → Options → Web UI and set a permanent password.

Services can't connect to each other (connection refused, timeout):

  • Don't use localhost when connecting services together — that won't work across Docker containers.
  • Use the internal Docker IPs instead:
    • qBittorrent/Prowlarr/FlareSolverr: 172.39.0.2
    • Radarr: 172.39.0.3
    • Sonarr: 172.39.0.4
    • Jellyfin: 172.39.0.7
  • The one exception: Prowlarr → FlareSolverr can use localhost:8191 because they both run through Gluetun and share the same network.

"Root folder does not exist" in Radarr/Sonarr:

  • Make sure you ran sudo bash setup-folders.sh to create the /data directory structure.
  • Double-check the root folder path — it should be /data/media/movies for Radarr and /data/media/tv for Sonarr (not /movies or `/data>

Downloads stuck at "importing" or "waiting to import":

  • This is almost always a permissions issue. Fix it with:
    sudo chown -R $(id -u):$(id -g) /data
    sudo chmod -R 775 /data
    
  • Make sure PUID/PGID in your .env match your user (check with id). Jellyfin library is empty after downloads finish:
  • Make sure your Jellyfin libraries point to the correct paths: /data/media/movies, /data/media/tv, /data/media/music
  • Jellyfin doesn't scan instantly. Go to Dashboard → Libraries → click the ... menu → Scan Library to force a refresh.
  • You can also set up scheduled scans in Dashboard → Scheduled Tasks.

Subtitles not downloading (Bazarr):

  • Bazarr needs to be connected to Radarr and Sonarr: Settings → Radarr / Sonarr → enter the IP (172.39.0.3 / 172.39.0.4) and API key.
  • You also need at least one subtitle provider: Settings → Providers → Add → OpenSubtitles.com is the most popular (free account requir>

Everything works but downloads are slow:

  • Your VPN server might be too far away. Change SERVER_COUNTRIES in your .env to a country closer to you, then restart:
    docker compose down && docker compose up -d
    
  • Check your VPN speed: docker exec gluetun wget -qO- https://speed.cloudflare.com/__down?measId=10000000 > /dev/null — if it's very slow>

Disk space filling up:

  • By default, qBittorrent keeps torrents after Radarr/Sonarr imports them. To auto-clean:
    • In Radarr/Sonarr → Settings → Download Clients → click on qBittorrent → enable Remove Completed
    • This deletes the torrent from qBittorrent after the file has been imported (the hard link in your media folder is kept, so you don't lo>

VPN IP leak — want to make sure your real IP isn't exposed:

# Check the VPN container's IP (should NOT be your real IP)
docker exec gluetun wget -qO- ifconfig.me

# Compare with your real IP (run this outside Docker)
curl -s ifconfig.me

If both IPs are the same, your VPN isn't working — check Gluetun logs with docker logs gluetun.

Credits

Built by Tom Spark following Trash Guides and [Servarr Wiki](https://wiki.se>

Uses Gluetun for VPN, LinuxServer.io container images, and [Seerr](https://gi>