Self-hosted media automation stack built around Jackett, Radarr, Sonarr, FlareSolverr, and two small Node services:
bootstrap: one-shot provisioning for Radarr and Sonarruploader: webhook receiver + torrent watcher for the local blackhole flow
- Jackett
- Radarr
- Sonarr
bootstrap: one-shot job, run manuallyuploader: Node service inservices/uploader/index.ts, intended to listen on port3000
.
├── data/
│ ├── completed/ # blackhole watch folder
│ ├── files/ # Radarr/Sonarr root folder
│ └── torrents/ # blackhole torrent output
├── services/
│ ├── bootstrap/ # Radarr/Sonarr provisioning + config sync
│ └── uploader/ # webhook receiver + torrent watcher
└── docker-compose.yml
- Docker + Docker Compose
- an AllDebrid API key
- at least one configured Jackett indexer
Optional:
JACKETT_API_KEYif you want a fixed Jackett API key on first boot
The current setup expects only the API keys in .env. Paths, URLs, webhook target, and category defaults come from docker-compose.yml and the bootstrap service.
- Copy
.env.exempleto.env - Fill
.envwith:ALLDEBRID_API_KEY- optional
JACKETT_API_KEY
- Start the core services:
docker compose up -d --build- Open Jackett and configure at least one indexer
- Run the one-shot bootstrap job:
docker compose run --rm bootstrap --buildThe bootstrap service:
- waits for Jackett, Radarr, and Sonarr to become reachable
- resolves API keys from the live service config when possible
- ensures the Radarr/Sonarr root folder exists at
/data/files - ensures a
TorrentBlackholedownload client exists and points to:- torrent folder:
/data/torrents/ - watch folder:
/data/completed/
- torrent folder:
- ensures a webhook notification named
Notifierpoints tohttp://uploader:3000 - discovers all configured Jackett indexers
- creates or updates matching Torznab indexers in Radarr and Sonarr
- syncs shared quality profiles and custom formats from
services/bootstrap/config/config.json
Important: bootstrap does not create Jackett indexers for you. If Jackett has no configured indexer, bootstrap fails with No configured Jackett indexers found.
Shared bootstrap config lives in:
services/bootstrap/config/config.json
That file is applied to both Radarr and Sonarr.
Supported shape:
qualityProfiles[]nameallowedcutoffformatScores- optional:
upgradeAllowed,minFormatScore,cutoffFormatScore,minUpgradeFormatScore
customFormats[]nametype:regexorresolutionvalue- optional:
negate,required,includeCustomFormatWhenRenaming,specName
Bootstrap creates or updates resources by name. Extra resources already present in Radarr or Sonarr are left untouched.
services/uploader/index.ts implements the uploader flow:
- listens for
GrabandUpgradewebhooks from Radarr and Sonarr - watches
data/torrentsfor new.torrentfiles - uploads those torrent files to AllDebrid
- creates placeholder files under
data/filesso imports can resolve to the expected folder structure
Rerun bootstrap after changing .env or services/bootstrap/config/config.json:
docker compose run --rm bootstrap --build