Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ TRANSMISSION_RPC_PASSWORD=
# Host port to expose Grafana on. Defaults to 3000 if unset.
GRAFANA_PORT=3000

# ============ Decluttarr (queue cleanup for Radarr/Sonarr) ============
# These keys come from Radarr's Settings -> General -> API Key (and Sonarr's
# equivalent) AFTER the stack is running. Decluttarr starts fine with them
# blank — it just skips any service whose key isn't set.
RADARR_API_KEY=
SONARR_API_KEY=

# ============ Tracearr (required — stack will refuse to start if blank) ============
# Use strong random strings, e.g. `openssl rand -base64 32`
DB_PASSWORD=
Expand Down
7 changes: 4 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ There is no test suite. After changing `docker-compose.yml`, always run `docker
**Network isolation matters.** Services are split across four bridge networks and one host-mode service. A service can only reach another if they share a network — adding a new service requires picking the right one (or declaring multiple):

- `monitoring_network` — tautulli, grafana, telegraf, watchtower, portainer, prometheus, cadvisor, node-exporter
- `media_network` — seerr, radarr, sonarr, prowlarr, bazarr
- `download_network` — transmission, watchlistarr, cleanarr, requestrr, radarr, sonarr
- `media_network` — seerr, radarr, sonarr, prowlarr, bazarr, flaresolverr, maintainerr, checkrr
- `download_network` — transmission, watchlistarr, cleanarr, requestrr, decluttarr, radarr, sonarr
- `tracearr-network` — tracearr, timescale (PostgreSQL), redis
- **host network** — plex only (required for proper streaming/discovery)

Expand Down Expand Up @@ -62,5 +62,6 @@ The mounted config directory is `plex-meta-manager/config/`. Its structure is re

1. **Hard-required** (stack won't start): `DB_PASSWORD`, `JWT_SECRET`, `COOKIE_SECRET` (Tracearr); `OPENVPN_PROVIDER`, `OPENVPN_CONFIG`, `OPENVPN_USERNAME`, `OPENVPN_PASSWORD` (Transmission VPN). All use the `${VAR:?must be set}` fail-fast form.
2. **Effectively required for the feature to work**: `PUID`/`PGID`/`TZ`/`USERDIR` (everything), `PLEX_CLAIM` (first-boot only), `GRAFANA_PORT` (defaults to 3000 if unset), `LOCAL_NETWORK` (Transmission, defaults to `192.168.0.0/16`), `PMM_*` (Kometa), `TRANSMISSION_RPC_USERNAME`/`TRANSMISSION_RPC_PASSWORD` (optional web UI auth).
3. **Populated after first boot**: `RADARR_API_KEY`, `SONARR_API_KEY` (Decluttarr). These come from the Radarr/Sonarr UIs after the stack is up — Decluttarr starts fine with them blank and skips any service whose key isn't set. **Note:** this is a real exception to the "every var in `.env.example` is consumed by compose" rule above — flag this chicken-and-egg to users on first-boot questions, since the *arr API keys are only obtainable post-`up`.

If a user mentions an env var not in this list (e.g. `RADARR_API_KEY`, `DOCKER_INFLUXDB_*`, `PLEX_TOKEN`), it's from an older version of the stack — not consumed today.
If a user mentions an env var not in this list (e.g. `DOCKER_INFLUXDB_*`, `PLEX_TOKEN`, `EMAIL`/`PASSWORD`), it's from an older version of the stack — not consumed today.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,11 @@ A ready-to-use [Kometa](https://kometa.wiki/) (Plex Meta Manager) configuration
| [Sonarr](https://sonarr.tv/) | TV show management and downloading | `8989` |
| [Prowlarr](https://prowlarr.com/) | Indexer manager that feeds Radarr/Sonarr | `9696` |
| [Bazarr](https://www.bazarr.media/) | Subtitle management for Radarr/Sonarr libraries | `6767` |
| [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr) | Cloudflare bypass proxy for Prowlarr indexers | `8191` |
| [Maintainerr](https://github.com/jorenn92/Maintainerr) | Rule-based Plex library cleanup (auto-remove watched/aged items) | `6246` |
| [Watchlistarr](https://github.com/nylonee/watchlistarr) | Syncs Plex watchlist to Radarr/Sonarr | N/A |
| [Decluttarr](https://github.com/ManiMatter/decluttarr) | Removes stalled / failed downloads from \*arr queues | N/A |
| [Checkrr](https://github.com/aetaric/checkrr) | Scans media files for codec / corruption issues | `8585` |
| [Cleanarr](https://github.com/se1exin/Cleanarr) | Finds and removes duplicate content | N/A |
| [Requestrr](https://github.com/darkalfx/requestrr) | Discord bot for content requests | `4545` |

Expand Down Expand Up @@ -174,8 +178,8 @@ These services pair well with this stack but are not included in the default `do
Services are isolated into separate Docker networks:

- **`monitoring_network`** - Tautulli, Grafana, Telegraf, Watchtower, Portainer, Prometheus, cAdvisor, node-exporter
- **`media_network`** - Seerr, Radarr, Sonarr, Prowlarr, Bazarr
- **`download_network`** - Transmission, Watchlistarr, Cleanarr, Requestrr, Radarr, Sonarr
- **`media_network`** - Seerr, Radarr, Sonarr, Prowlarr, Bazarr, FlareSolverr, Maintainerr, Checkrr
- **`download_network`** - Transmission, Watchlistarr, Cleanarr, Requestrr, Decluttarr, Radarr, Sonarr
- **`tracearr-network`** - Tracearr, TimescaleDB, Redis

Plex runs in host network mode for optimal streaming performance. Radarr and Sonarr are attached to both `media_network` (so Seerr, Prowlarr, and Bazarr can reach them) and `download_network` (so Watchlistarr and Transmission can reach them).
Expand Down
73 changes: 72 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,36 @@ services:
- ${USERDIR}/plex/media:/media
restart: unless-stopped

# Cloudflare bypass proxy. Prowlarr (and any other indexer client)
# routes requests through this to reach indexer sites behind Cloudflare.
flaresolverr:
container_name: flaresolverr
image: ghcr.io/flaresolverr/flaresolverr:latest
networks:
- media_network
ports:
- "8191:8191"
environment:
- LOG_LEVEL=info
- TZ=${TZ}
restart: unless-stopped

# Rule-based Plex library maintenance (auto-remove watched / aged items).
maintainerr:
container_name: maintainerr
image: ghcr.io/jorenn92/maintainerr:latest
networks:
- media_network
ports:
- "6246:6246"
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- ${USERDIR}/maintainerr/data:/opt/data
restart: unless-stopped

# ============ MEDIA CENTER ============
watchlistarr:
container_name: watchlistarr
Expand Down Expand Up @@ -268,7 +298,48 @@ services:
- ${USERDIR}/transmission/data:/data
restart: unless-stopped

# ============ ERROR MONITORING ============
# ============ LIBRARY MAINTENANCE ============
# Cleans stalled/failed downloads out of Radarr/Sonarr queues. Skips any
# service whose API key is blank, so it's safe to leave keys empty on
# first boot and fill them in after the *arrs are running.
# Pinned to v1: v2 (Nov 2025) requires both base_url and api_key in
# structured RADARR/SONARR blocks, which breaks the blank-keys-on-first-boot
# workflow this service is configured around. Re-evaluate if v2 ever
# gains a "skip instances with empty api_key" behavior.
decluttarr:
container_name: decluttarr
image: ghcr.io/manimatter/decluttarr:v1.50.2
networks:
- download_network
environment:
- TZ=${TZ}
- LOG_LEVEL=INFO
- RADARR_URL=http://radarr:7878
- RADARR_KEY=${RADARR_API_KEY:-}
- SONARR_URL=http://sonarr:8989
- SONARR_KEY=${SONARR_API_KEY:-}
- REMOVE_TIMER=10
- REMOVE_FAILED=True
- REMOVE_STALLED=True
- REMOVE_MISSING_FILES=True
- REMOVE_ORPHANS=True
restart: unless-stopped
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# Scans media files for codec / corruption issues. Web UI on :8585.
checkrr:
container_name: checkrr
image: ghcr.io/aetaric/checkrr:latest
networks:
- media_network
ports:
- "8585:8585"
environment:
- TZ=${TZ}
volumes:
- ${USERDIR}/checkrr/config:/etc/checkrr
- ${USERDIR}/plex/media:/media:ro
restart: unless-stopped

cleanarr:
container_name: cleanarr
image: cleanarr/cleanarr
Expand Down
Loading