Skip to content

Instantly share code, notes, and snippets.

@altendorfme
Created July 21, 2023 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save altendorfme/afd9ef88addcd7fb738b0da48202108e to your computer and use it in GitHub Desktop.
Save altendorfme/afd9ef88addcd7fb738b0da48202108e to your computer and use it in GitHub Desktop.
EasyArr: HTPC with Docker

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment