A complete, opinionated Plex Media Server stack delivered as a single Docker Compose file — bootstrap streaming, request handling, library automation, downloads, and monitoring with one command.
- One command, full stack — Plex, request handling (Seerr), library automation (Radarr/Sonarr), downloads, monitoring, and metadata curation all wired together.
docker compose up -dand you're done. - Pre-built Kometa config included — IMDb Top 250 / Trakt / streaming-service collections, daily rotating playlists, and resolution/HDR overlays are ready to run, not a blank YAML you fill in over weeks.
- Network-isolated by design — four separate Docker networks split streaming, request flow, downloading, and monitoring so a misbehaving service can't talk to the rest.
- Stream analytics in the box — Tracearr ships built-in for concurrent-stream monitoring, geolocation, and account-sharing detection alongside Tautulli's usage reporting.
- Docker and Docker Compose (v2+)
- A Plex account and a claim token — generate this immediately before your first
docker compose up; claim tokens expire roughly 4 minutes after they're issued - Values for
DB_PASSWORD,JWT_SECRET, andCOOKIE_SECRETin.env— Tracearr refuses to start without them and will fail the whole stack'supcommand - OpenVPN credentials from a supported VPN provider (
OPENVPN_PROVIDER,OPENVPN_CONFIG,OPENVPN_USERNAME,OPENVPN_PASSWORD) — Transmission tunnels all traffic through OpenVPN and won't start without them. See Transmission VPN setup for details
-
Clone the repository:
git clone https://github.com/joshdev8/AutoPlexx.git cd AutoPlexx -
Copy
.env.exampleto.envand fill in your values:cp .env.example .env
-
Set
USERDIRin.envto the parent directory where configs and media should live. All services bind-mount under${USERDIR}/<service>, so this one variable controls where everything lands — you don't normally need to editdocker-compose.ymlitself. -
Start all services:
docker compose up -d
docker compose ps # show running services
docker compose logs -f <service> # tail one service's logs
docker compose restart <service> # restart one service after editing its config
docker compose pull && docker compose up -d # update images (Watchtower also does this on a schedule)
docker compose down # stop everything (named volumes preserved)
docker compose config # validate YAML + env interpolation without starting anythingflowchart LR
User([User])
Watchlist[Plex Watchlist]
User -->|streams from| Plex
User -->|requests via| Seerr
Watchlist -->|synced by| Watchlistarr
Seerr -->|submits to| Radarr
Seerr -->|submits to| Sonarr
Watchlistarr -->|drives| Radarr
Watchlistarr -->|drives| Sonarr
Prowlarr -->|provides indexers to| Radarr
Prowlarr -->|provides indexers to| Sonarr
Radarr -->|sends torrents| Transmission
Sonarr -->|sends torrents| Transmission
Transmission -->|completed files| Plex
Bazarr -->|fetches subtitles for| Plex
Plex -->|stream activity| Tautulli
Plex -->|stream activity| Tracearr
Tracearr --> TimescaleDB[(TimescaleDB)]
Tracearr --> Redis[(Redis)]
Telegraf -->|host + container metrics| Grafana
Tautulli -->|usage data| Grafana
cAdvisor -->|container metrics| Prometheus
NodeExporter[node-exporter] -->|host metrics| Prometheus
Prometheus -->|scraped time-series| Grafana
See Network Architecture below for the exact network membership of each service.
Screenshots of the running stack — Plex, Seerr, Tautulli, Grafana, and Tracearr — coming soon. Contributions welcome via PR.
| Service | Description | Port |
|---|---|---|
| Plex | Central media server | 32400 (host network) |
A ready-to-use Kometa (Plex Meta Manager) configuration is included for automated collections and overlays, but Kometa itself is not part of docker-compose.yml — see Kometa Configuration for how to run it.
| Service | Description | Port |
|---|---|---|
| Seerr | Content request and management interface | 5055 |
| Radarr | Movie management and downloading | 7878 |
| Sonarr | TV show management and downloading | 8989 |
| Prowlarr | Indexer manager that feeds Radarr/Sonarr | 9696 |
| Bazarr | Subtitle management for Radarr/Sonarr libraries | 6767 |
| FlareSolverr | Cloudflare bypass proxy for Prowlarr indexers | 8191 |
| Maintainerr | Rule-based Plex library cleanup (auto-remove watched/aged items) | 6246 |
| Watchlistarr | Syncs Plex watchlist to Radarr/Sonarr | N/A |
| Decluttarr | Removes stalled / failed downloads from *arr queues | N/A |
| Checkrr | Scans media files for codec / corruption issues | 8585 |
| Cleanarr | Finds and removes duplicate content | N/A |
| Requestrr | Discord bot for content requests | 4545 |
| Service | Description | Port |
|---|---|---|
| Transmission (VPN) | Torrent client with OpenVPN tunnel — setup notes | 9091 |
| Service | Description | Port |
|---|---|---|
| Tautulli | Plex usage monitoring | 8181 |
| Grafana | Metrics visualization | 3000 |
| Prometheus | Time-series metrics database — scrapes cAdvisor + node-exporter | 9090 |
| cAdvisor | Per-container CPU / memory / network metrics | 8080 |
| node-exporter | Host (CPU / disk / network) metrics | 9100 |
| Telegraf | Metrics collection agent | N/A |
| Tracearr | Stream tracking and account sharing detection | 3001 |
| Portainer | Docker management UI (note on socket access) | 9000 |
| Service | Description | Port |
|---|---|---|
| Watchtower | Automated container updates | N/A |
| TimescaleDB | Time-series database (used by Tracearr) | N/A (internal) |
| Redis | Cache/queue (used by Tracearr) | N/A (internal) |
These services pair well with this stack but are not included in the default docker-compose.yml. See their respective docs to add them:
- Lidarr - Music management and downloading
- Jackett - Torrent indexer aggregator (Prowlarr covers most use cases)
Services are isolated into separate Docker networks:
monitoring_network- Tautulli, Grafana, Telegraf, Watchtower, Portainer, Prometheus, cAdvisor, node-exportermedia_network- Seerr, Radarr, Sonarr, Prowlarr, Bazarr, FlareSolverr, Maintainerr, Checkrrdownload_network- Transmission, Watchlistarr, Cleanarr, Requestrr, Decluttarr, Radarr, Sonarrtracearr-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).
Portainer mounts the host's Docker socket (/var/run/docker.sock) so it can manage every container. This grants the Portainer UI root-equivalent access to the host — anyone who logs in can stop, restart, or exec into any container, including those handling secrets. Set a strong admin password on first launch and don't expose port 9000 to the public internet.
Transmission uses the haugene/transmission-openvpn image, which runs an OpenVPN client inside the container and tunnels all torrent traffic through it. The container fails to start without valid VPN credentials.
Required .env values:
| Variable | What it is |
|---|---|
OPENVPN_PROVIDER |
Provider name from the supported list (e.g. MULLVAD, PIA, NORDVPN) |
OPENVPN_CONFIG |
Server / region config name — provider-specific, see your provider's section in the linked docs |
OPENVPN_USERNAME |
VPN account username (the one you use to log into the VPN, not the provider portal) |
OPENVPN_PASSWORD |
VPN account password |
LOCAL_NETWORK |
CIDR of your LAN (default 192.168.0.0/16) — traffic to these subnets bypasses the tunnel so the web UI stays reachable |
Optional:
TRANSMISSION_RPC_USERNAME/TRANSMISSION_RPC_PASSWORD— auth for the Transmission web UI. Leave blank for no auth.
Required compose capabilities (already configured in docker-compose.yml, mentioned here in case you fork):
cap_add: [NET_ADMIN]devices: [/dev/net/tun]
Verifying the tunnel works:
docker compose exec transmission curl -s https://ipinfo.io | grep -E '"(ip|country)"'The IP and country in the response should match your VPN exit, not your home connection. If they match your home IP, the tunnel is not active — check docker compose logs transmission for OpenVPN errors.
If the web UI on :9091 is unreachable: LOCAL_NETWORK probably doesn't cover the subnet your machine is on. Add your subnet (e.g. 192.168.1.0/24) to LOCAL_NETWORK, comma-separated if you need multiple ranges, and restart the container.
The plex-meta-manager/config/ directory contains a ready-to-use Kometa configuration. Kometa itself is not in docker-compose.yml — run it as a one-shot container on whatever schedule you prefer (cron, systemd timer, or a separate compose file):
docker run --rm \
-v "$(pwd)/plex-meta-manager/config:/config" \
--env-file .env \
kometateam/kometaThe bundled config drives:
- Movies - IMDb Top 250, TMDb trending, Trakt lists, Oscar categories, genre collections, streaming service collections, holiday collections, and more
- TV Shows - Popular/trending, streaming networks, genres, studios (Marvel, DC), year-based collections
- Playlists - Daily rotating playlists by genre (Action, Comedy, Animated, Family)
- Overlays - Resolution badges (4K, 1080p, 720p), HDR/Dolby Vision, IMDb Top 250, streaming service badges, show status (Airing/Ended/Canceled)
