Plex Media Server, Sonarr, Radarr, Bazarr, Jackett, qBittorrent, Tdarr, Samba (Share), Duplicati (Backup), Scrutiny (S.M.A.R.T) and WatchTower
This is an HTPC option for a private network, we will not have any direct external access, the remote access will be done by TailScale installed on an EdgeRouter-X.
You can install TailScale via Docker as well.
The only open port will be from Plex, 32400 to keep remote access easier for apps and TVs.
Alternatives:
- Plex Media Server to Jellyfin: I have a lifetime license for Plex, and I still think it’s the best and most complete solution, if you want to install both it won’t be difficult to adjust it in Docker.
- qBittorrent to Deluge, Transmission, rTorrent: qBittorrent has the largest number of options with no need for addons, its configuration is fast and has a good performance.
Debian 12+
Debian is a safe choice, everything should work on versions 10 and 11, but Kernel upgrade from version 12 Bookworm works better with Intel Quick Sync for HW Transcode on Plex, Jellyfin or Emby.
sudo nano /etc/ssh/sshd_config
PermitRootLogin yes
Reboot and reconnect with root user
deluser debian rm -rf /home/debian apt-get update; apt-get upgrade -y; apt-get autoremove; apt install apt-transport-https ca-certificates curl gnupg2 software-properties-common htop ncdu nano net-tools zip fdisk sl -y timedatectl set-timezone Etc/UTC
List of tz database time zones
Swap
fallocate -l 1G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile
echo '/swapfile none swap sw 0 0' | tee -a /etc/fstab
sysctl vm.swappiness=10 sysctl vm.vfs_cache_pressure=50
echo 'vm.swappiness=10' | tee -a /etc/sysctl.conf echo 'vm.vfs_cache_pressure=50' | tee -a /etc/sysctl.conf
Install Docker:
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update; apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
systemctl status docker
You should see a green status.
Mount disks
If you’re starting now, you probably have a disk with a large amount of space, after formatting this process is easier to mount.
Each disk has its own UUID.
You can find out the UUID of your disk by running blkid
, the result will be like this:
/dev/sda1: UUID="648c6531-4d62-4d3c-a0d9-074f651cdbfb" TYPE="ext4" PARTUUID="6e301172-01" /dev/sda5: UUID="5e1b25a1-498b-4bce-af47-d30aa9ea31b5" TYPE="swap" PARTUUID="6e301172-05" /dev/sdb1: LABEL="HD" UUID="CA8261F08261E205" TYPE="ntfs" PARTLABEL="HD" PARTUUID="deb852d4-a496-4b8c-9065-bec8d9c5d7e4"
If not show any addition disk, try:
fdisk -l | grep "Disk /"
The result will be like this:
Disk /dev/sdb: 20 GiB, 21474836480 bytes, 41943040 sectors Disk /dev/sda: 20 GiB, 21474836480 bytes, 41943040 sectors
fdisk /dev/sdb
n p 1 w
mkfs -t ext4 /dev/sdb1
blkid
and get UUID
nano /etc/fstab
UUID=UUID /mnt/storage auto defaults 0 0
You also need an empty folder where it will be mounted:
mkdir -p /mnt/storage
systemctl daemon-reload
Run mount -a
. If you can access your partitions and no errors appear then everything is fine.
mkdir -p /mnt/storage/{transcode,media/{tv-shows,movies},downloads/{radarr,sonarr,aria2}}/
Install containers
Environment
nano .env
STORAGE_DIR=/mnt/storage DOCKER_DIR=/opt TZ=Etc/UTC PUID=0 PGID=0 PLEX_CLAIM=CLAIM_CODE
You can obtain a claim token from https://plex.tv/claim and input here. Keep in mind that the claim tokens expire within 4 minutes.
Pre configuration
Scrutiny
mkdir -p /opt/scrutiny/config/
nano /opt/scrutiny/config/scrutiny.yaml
Notification “urls” look like the following. For more information about service specific configuration see shoutrrr’s documentation.
version: 1
web:
listen:
port: 8081
host: 0.0.0.0
#notify:
# urls:
# - "discord://token@channel"
# - "telegram://token@telegram?channels=channel-1[,channel-2,...]"
# - "pushover://shoutrrr:apiToken@userKey/?priority=1&devices=device1[,device2, ...]"
# - "slack://[botname@]token-a/token-b/token-c"
# - "smtp://username:password@host:port/?fromAddress=fromAddress&toAddresses=recipient1[,recipient2,...]"
# - "teams://token-a/token-b/token-c"
# - "gotify://gotify-host/token"
# - "pushbullet://api-token[/device/#channel/email]"
# - "ifttt://key/?events=event1[,event2,...]&value1=value1&value2=value2&value3=value3"
# - "mattermost://[username@]mattermost-host/token[/channel]"
# - "ntfy://username:password@host:port/topic"
# - "hangouts://chat.googleapis.com/v1/spaces/FOO/messages?key=bar&token=baz"
# - "zulip://bot-mail:bot-key@zulip-domain/?stream=name-or-id&topic=name"
# - "join://shoutrrr:api-key@join/?devices=device1[,device2, ...][&icon=icon][&title=title]"
# - "script:///file/path/on/disk"
# - "https://www.example.com/path"
Deploy
nano docker-compose.yml
version: "3.3"
services:
# Watchtower
watchtower:
container_name: watchtower
image: containrrr/watchtower:latest
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-Etc/UTC}
- WATCHTOWER_CLEANUP=true
- WATCHTOWER_INCLUDE_RESTARTING=true
- WATCHTOWER_REVIVE_STOPPED=true
- WATCHTOWER_SCHEDULE=0 5 * * * *
- WATCHTOWER_ROLLING_RESTART=true
- WATCHTOWER_INCLUDE_STOPPED=true
# Plex
plex:
container_name: plex
ports:
- 32400:32400 # WebUI
# - 1900:1900/udp # Plex DLNA Server
# - 3005:3005 # Plex Companion
# - 5353:5353/udp # Bonjour/Avahi network discovery
# - 8324:8324 # Plex for Roku via Plex Companion
# - 32410:32410/udp # GDM network discovery
# - 32412:32412/udp # GDM network discovery
# - 32413:32413/udp # GDM network discovery
# - 32414:32414/udp # GDM network discovery
# - 32469:32469 # Plex DLNA Server
image: linuxserver/plex:latest
restart: always
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-Etc/UTC}
- VERSION=docker
- PLEX_CLAIM=${PLEX_CLAIM}
volumes:
- ${DOCKER_DIR:-/opt}/plex:/config
- ${STORAGE_DIR:-/mnt/storage}/media:/media
devices:
- /dev/dri:/dev/dri
# Radarr
radarr:
container_name: radarr
ports:
- 7878:7878 # WebUI
image: linuxserver/radarr:latest
restart: always
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-Etc/UTC}
volumes:
- ${DOCKER_DIR:-/opt}/radarr:/config
- ${STORAGE_DIR:-/mnt/storage}:/storage
# Sonarr
sonarr:
container_name: sonarr
ports:
- 8989:8989 # WebUI
image: linuxserver/sonarr:latest
restart: always
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-Etc/UTC}
volumes:
- ${DOCKER_DIR:-/opt}/sonarr:/config
- ${STORAGE_DIR:-/mnt/storage}:/storage
# Bazarr
bazarr:
container_name: bazarr
ports:
- 6767:6767 # WebUI
image: linuxserver/bazarr:latest
restart: always
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-Etc/UTC}
volumes:
- ${DOCKER_DIR:-/opt}/bazarr:/config
- ${STORAGE_DIR:-/mnt/storage}:/storage
# Jackett
jackett:
container_name: jackett
ports:
- 9117:9117 # WebUI
image: linuxserver/jackett:latest
restart: always
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-Etc/UTC}
volumes:
- ${DOCKER_DIR:-/opt}/jackett:/config
# Tdarr
tdarr:
container_name: tdarr
ports:
- 8265:8265 # WebUI
# - 8266:8266 # Server port
# - 8267:8267 # Internal node port
# - 8268:8268 # Example extra node port
image: haveagitgat/tdarr:latest
restart: always
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-Etc/UTC}
- serverIP=0.0.0.0
- serverPort=8266
- webUIPort=8265
- internalNode=true
- nodeName=Tdarr
volumes:
- ${DOCKER_DIR:-/opt}/tdarr/server:/app/server
- ${DOCKER_DIR:-/opt}/tdarr/configs:/app/configs
- ${DOCKER_DIR:-/opt}/tdarr/logs:/app/logs
- ${STORAGE_DIR:-/mnt/storage}:/storage
devices:
- /dev/dri:/dev/dri
# Scrutiny
scrutiny:
container_name: scrutiny
ports:
- 8081:8081
# - 8086:8086 # InfluxDB
volumes:
- /run/udev:/run/udev:ro
- ${DOCKER_DIR:-/opt}/scrutiny/config:/opt/scrutiny/config
- ${DOCKER_DIR:-/opt}/scrutiny/influxdb:/opt/scrutiny/influxdb
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-Etc/UTC}
- COLLECTOR_CRON_SCHEDULE="0 0 * * 0"
image: ghcr.io/analogj/scrutiny:master-omnibus
cap_add:
- SYS_RAWIO
- SYS_ADMIN # NVMe
restart: always
devices:
- /dev/sda:/dev/sda
- /dev/sdb:/dev/sdb
# qBittorrent
qbittorrent:
container_name: qbittorrent
ports:
- 8080:8080 # WebUI
- 6881:6881 # Torrent
- 6881:6881/udp # Torrent
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-Etc/UTC}
image: linuxserver/qbittorrent:latest
restart: always
volumes:
- ${DOCKER_DIR:-/opt}/qbittorrent:/config
- ${STORAGE_DIR:-/mnt/storage}:/storage
# Samba
samba:
container_name: samba
ports:
- 139:139 # NetBIOS
- 445:445 # TCP Stack
image: dperson/samba
restart: always
environment:
- PUID=${PUID:-0}
- PGID=${PGID:-0}
- TZ=${TZ:-Etc/UTC}
volumes:
- ${STORAGE_DIR:-/mnt/storage}:/storage
command: '-s "storage;/storage;yes;no;yes;all" -p'
# Duplicati
duplicati:
image: linuxserver/duplicati:latest
container_name: duplicati
ports:
- 8200:8200 # WebUI
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-Etc/UTC}
volumes:
- ${DOCKER_DIR:-/opt}/duplicati:/config
- ${DOCKER_DIR:-/opt}:/docker
restart: always
docker compose up -d
Wait for the complete installation of all applications, it may take several minutes.
First apps configuration
Sonarr
Settings > Media Management > Importing - Check Use Hardlinks when trying to copy files from torrents that are still being seeded
Settings > Media Management > Root Folders - /storage/media/tv-shows/
Radarr
Settings > Media Management > Importing - Check Use Hardlinks when trying to copy files from torrents that are still being seeded
Settings > Media Management > Root Folders - /storage/media/movies/
qBittorrent
Options > Downloads - Default Save Path: /downloads/
If use a public trackers:
Options > BitTorrent > Enable Automatically add these trackers to new downloads:b>
Add content tracker best list from ngosang repository
Bazarr
Plex
Ports
- Plex: 32400
- 1900:1900/udp # Plex DLNA Server
- 3005:3005 # Plex Companion
- 5353:5353/udp # Bonjour/Avahi network discovery
- 8324:8324 # Plex for Roku via Plex Companion
- 32410:32410/udp # GDM network discovery
- 32412:32412/udp # GDM network discovery
- 32413:32413/udp # GDM network discovery
- 32414:32414/udp # GDM network discovery
- 32469:32469 # Plex DLNA Server
- qBittorrent: 8080
- 6881:6881 # Torrent
- 6881:6881/udp # Torrent
- Sonarr: 8989
- Radarr: 7878
- Bazarr: 6767
- Jackett: 9117
- Tdarr: 8265
- 8266:8266 # Server port
- 8267:8267 # Internal node port
- 8268:8268 # Example extra node port
- Duplicati: 8200
- Samba: 8200
- Scrutiny: 8200
- 8266:8266 # Server port
References and credits
- https://plex.tv
- https://github.com/Sonarr/Sonarr
- https://github.com/Radarr/Radarr
- GitHub - morpheus65535/bazarr: Bazarr is a companion application to Sonarr and Radarr. It manages and downloads subtitles based on your requirements. You define your preferences by TV show or movie and Bazarr takes care of everything for you.
- GitHub - Jackett/Jackett: API Support for your favorite torrent trackers
- GitHub - containrrr/watchtower: A process for automating Docker container base image updates.
- GitHub - ngosang/trackerslist: Updated list of public BitTorrent trackers
- https://www.qbittorrent.org
- https://www.linuxserver.io
- https://trash-guides.info
- GitHub - dperson/samba: Samba docker container