v1.0 stable, linux x86_64 and arm64

12 services.
One binary. 90 seconds.

The arr stack, pre-wired. Installs qBittorrent, Prowlarr, Sonarr, Radarr, Bazarr+, Jellyfin, and Jellyseerr on a clean Linux host. No YAML to copy-paste, no wizard tour, no forum threads about Cloudflare tags.

lavx@homelab: ~
$ curl -fsSL https://lavx.github.io/arrstack/install.sh | bash
Terminal showing twelve services booting and admin credentials written to disk in 87 seconds.
the thing nobody writes on the repo

A working arr stack is roughly 400 clicks.

$ history | grep -E 'prowlarr|bazarr|jellyseerr' | wc -l → ~400

You pull the images. You open Prowlarr, generate an API key, paste it into Sonarr, paste it again into Radarr. You add eight indexers, forget to tag FlareSolverr at create-time, and every Cloudflare-gated search 403s until you delete and recreate each one. You open Bazarr+, hit its KeyError on audio_exclude, edit the language profile fields, then edit them again for every language. You click through the Jellyfin Startup Wizard. You click through /setup on Jellyseerr, paste a third API key, link libraries by hand. You hand-craft a Caddyfile, guess at the DNS-01 block, watch the cert fail, fix the block.

By the time you request a movie, the evening is gone. arrstack is this weekend, compressed into one binary.

what the installer actually does

Three guarantees.

01 /

One command

A TUI wizard asks the three questions it cannot guess (storage root, remote access mode, optional extras), then runs unattended.

02 /

Twelve services

Download, indexers, arr apps, subtitles, media, requests, proxy, trailers, quality sync. Wired to each other at create-time, not via post-hoc scripts.

03 /

Ninety seconds

From bash to a Jellyseerr tab where the setup wizard has already been bypassed and your account logs in with the admin password in admin.txt.

manifest

The twelve services, grouped by role.

Each one tracks its upstream :latest image, runs under a stable docker service name on the internal network, and gets credentials handed in at bootstrap so nothing prompts you on first load. Run arrstack update to pull the current tags.

qBittorrent :8080
required

download Client with tv/movies/music/books categories pre-matched to TRaSH paths.

Gluetun network
optional

vpn Wraps the download client in a killswitched VPN tunnel. Enabled when you pick a provider (Mullvad, Proton, or custom) and provide WireGuard credentials in the wizard.

Prowlarr :9696
required

indexer Unified indexer manager, eight public indexers pre-added and app-synced to Sonarr and Radarr.

FlareSolverr :8191
required

indexer Headless browser that solves Cloudflare challenges, tagged onto gated indexers at create-time.

Sonarr :8989
required

arr TV manager. Root folder, download client, quality profile wired on first boot.

Radarr :7878
required

arr Movie manager, same wiring as Sonarr, pointed at /data/media/movies.

Bazarr+ :6767
required

subtitles LavX fork, shipped in place of upstream Bazarr, with OpenSubtitles scraper and OpenRouter translator. Language profiles ship with the fields it needs.

Jellyfin :8096
required

media server Intel, AMD, or NVIDIA hardware transcoding wired from lspci -nn, /dev/dri/renderD128, and nvidia-ctk.

Jellyseerr :5055
required

requests Request portal. The four-step bootstrap pre-links Jellyfin so no /setup wizard appears.

Caddy :80 :443
required

reverse proxy Virtual hosts generated per mode (LAN, DuckDNS, Cloudflare) with optional local DNS block.

Trailarr :7889
required

trailers Pre-roll trailer fetcher linked to Radarr and Sonarr libraries.

Recyclarr one-shot
required

quality profiles One-shot container that syncs TRaSH-Guides profiles and custom formats into Sonarr and Radarr, run on a schedule.

the small things that break homelabs

What the installer handles so you do not.

FlareSolverr at create-time

Prowlarr gets the FlareSolverr tag when each indexer is created, not retroactively. Cloudflare-gated sites route on the first search.

Bazarr+ language profiles

Every profile ships with audio_exclude, audio_only_include, hi, and forced. Bazarr+ does not crash on a KeyError the first time it scans a library.

Jellyseerr 4-step bootstrap

Four POSTs to Jellyseerr’s internal API: admin + Jellyfin auth (serverType: 2), library sync, library enable, initialize. The /setup wizard never appears.

Jellyfin hardware transcode

Intel VA-API, AMD VA-API, or NVIDIA NVENC auto-detected by parsing lspci -nn, checking /dev/dri/renderD128, and probing nvidia-ctk --version, then wired into the Jellyfin transcoding config.

TRaSH-aligned /data mount

One shared /data mount across qBittorrent and the arr services, so hardlinks work and seeding torrents do not duplicate disk.

Caddy vhosts per mode

LAN (plain http), DuckDNS (Let’s Encrypt DNS-01 via the DuckDNS plugin), or Cloudflare (wildcard Let’s Encrypt DNS-01 via the Cloudflare plugin, against your domain) with an optional local DNS block. Remote-access modes require a Caddy image that carries the matching DNS plugin.

remote access

Three modes. Pick the one that matches what you own.

Remote access comparison across LAN, DuckDNS, and Cloudflare modes. Cloudflare mode uses Cloudflare DNS plus Caddy wildcard Let’s Encrypt via DNS-01, not Cloudflare Tunnel.
LAN only DuckDNS Cloudflare
Who it is for You never leave the house, or you VPN in. You want real HTTPS without buying a domain. You already own a domain and want pretty URLs.
Prereqs None. Free DuckDNS account + token, Caddy image with the DuckDNS plugin. Your domain + Cloudflare API token (Zone:DNS:Edit and Zone:Zone:Read), Caddy image with the Cloudflare plugin.
What you get http://host-ip:port
e.g. http://192.168.1.20:8096
https://sub.duckdns.org
e.g. jellyfin.myhome.duckdns.org
https://sub.yourdomain.tld
e.g. jellyfin.yourdomain.net
TLS None (plain HTTP). Let’s Encrypt via DNS-01 (DuckDNS plugin). Wildcard Let’s Encrypt via DNS-01 (Cloudflare plugin).
Cost Free. Free. Domain registration only.
pretty LAN urls, three options

Typing :8096 forever, or not.

none (default)

Reach services by host IP and port. Zero setup, zero magic.

http://192.168.1.20:8096
http://192.168.1.20:5055
# boring, but never breaks

dnsmasq

The installer runs a dnsmasq container that serves your LAN, so every device resolves *.<your TLD> (wizard default arrstack.local).

address=/arrstack.local/192.168.1.20
address=/jellyfin.arrstack.local/192.168.1.20
# rendered to <install-dir>/config/dnsmasq/dnsmasq.conf

hosts-file

No router access? The installer emits a hosts block in FIRST-RUN.md that you paste into each client machine.

192.168.1.20  jellyfin.arrstack.local
192.168.1.20  sonarr.arrstack.local
# /etc/hosts or C:\Windows\System32\drivers\etc\hosts
requirements

What the host machine needs.

  • Linux: Ubuntu 22.04+, Debian 12+, Fedora 43+
  • Docker + Docker Compose v2
  • 10 GB free disk, plus your media storage
faq

Honest answers.

Is this a fork of the linuxserver stack?
No. arrstack uses the same upstream images (linuxserver.io and vendor images for Jellyfin, Jellyseerr, Caddy), but adds the TUI, the cross-wiring, and the opinionated defaults. The heavy lifting of container maintenance is still done by those teams, and we thank them for it.
Does it work on ARM?
Yes. An arrstack-linux-arm64 binary is shipped alongside x86_64. Tested on Raspberry Pi 5 (8 GB) and a handful of small-form-factor ARM boxes.
Will it run on my Synology or Unraid?
Not a supported target. arrstack assumes a Linux host where it owns docker-compose.yml generation. On Synology or Unraid you should keep using their app stores, or SSH into a Linux VM running on the NAS.
Where does media go?
Under your chosen storage root, at /data/media/tv, /data/media/movies, and /data/media/music. The layout follows TRaSH-Guides so hardlinks between /data/torrents and /data/media work, without doubling disk usage.
Can I bring my existing Jellyfin config?
Not yet. A clean install is recommended. Importing an existing Jellyfin database is on the roadmap but the edge cases (user IDs, device IDs, orphaned metadata) are not trivial to migrate safely.
Is the admin password stored on disk?
Yes, in two places with mode 0600: plain text in ${installDir}/admin.txt for arrstack show-password to read, and in ${installDir}/.env so containers can pick it up on restart. state.json does not contain the password; it only holds API keys, paths, and wizard settings. If the tradeoff is unacceptable, delete admin.txt after first login and store the password in your password manager. Services keep working because their config files already hold the hashed form.
Does Cloudflare mode use Cloudflare Tunnel?
No. Cloudflare mode uses Cloudflare as your authoritative DNS and a Cloudflare API token scoped to Zone:DNS:Edit and Zone:Zone:Read on the single zone. Caddy then issues a wildcard Let’s Encrypt certificate via the DNS-01 challenge. No tunnel daemon, no cloudflared container, no WARP. Port 443 on your box faces the internet directly. For the Caddy caddy-dns/cloudflare plugin to be available, the image is swapped to a build that includes it (the stock caddy:latest image does not).
How do I update?
arrstack update runs docker compose pull then docker compose up -d against <install-dir>/docker-compose.yml. Configs, media, and state.json are all untouched. Pass --install-dir if you used a non-default path; otherwise it looks under ~/arrstack.