From 603c938ac108dc469eaa7f2565a81beddc35df91 Mon Sep 17 00:00:00 2001 From: EdyTheCow Date: Fri, 7 Apr 2023 21:10:53 +0000 Subject: [PATCH] Finish docs and configs --- README.md | 81 +++++++++++----- _base/compose/.env | 16 ++++ _base/compose/docker-compose.yml | 25 +++++ _base/data/traefik/.htpasswd | 0 _base/data/traefik/acme.json | 0 _base/data/traefik/traefik.toml | 24 +++++ dmc/compose/.env | 26 ++++++ dmc/compose/docker-compose.yml | 152 +++++++++++++++++++++++++++++++ dmc/data/.gitkeep | 0 dmc/services/.gitkeep | 0 10 files changed, 303 insertions(+), 21 deletions(-) create mode 100644 _base/compose/.env create mode 100644 _base/compose/docker-compose.yml create mode 100644 _base/data/traefik/.htpasswd create mode 100644 _base/data/traefik/acme.json create mode 100644 _base/data/traefik/traefik.toml create mode 100644 dmc/compose/.env create mode 100644 dmc/compose/docker-compose.yml create mode 100644 dmc/data/.gitkeep create mode 100644 dmc/services/.gitkeep diff --git a/README.md b/README.md index 3febf91..8e088dc 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ # 📚 About -Docker Media Center is a fully automated media set-up using Jellyfin and a bunch of other services to achieve full automation. All of the services listed below are running behind Traefik reverse proxy with proper certificates and basic auth. Most other similar set-up were either lacking some sort of reverse proxy and were rather exposing ports or were poorly documented. This guide aims for the quickest way to set-up a secure and production ready media center set-up. +Docker Media Center is a fully automated media set-up using Jellyfin and a bunch of other services to achieve full automation. All of the services listed below are running behind Traefik reverse proxy with proper certificates and basic auth. Most other similar setups were either lacking a reverse proxy and exposing ports or were poorly documented. This guide aims for the quickest way to set-up a secure and production ready media center. + +Furthermore, the guide is set up with volume paths in a way to allow hardlinks of media files rather than making copies. This means once a media file is downloaded, it is hardlinked to the Jellyfin media directory rather than copied. Such a method is faster and saves storage on your server. ### Services - Jellyfin @@ -15,7 +17,7 @@ Docker Media Center is a fully automated media set-up using Jellyfin and a bunch - Jellyseerr # 🧰 Getting Started -This guide assumes you have a basic knowledge of linux and Docker / Docker Compose. +This guide assumes you have a basic knowledge of linux and Docker / Docker Compose. ### Requirements - Domain @@ -34,7 +36,8 @@ Navigate to `dmc/compose/.env/` and edit these variables. |---|---|---| | COMPOSE_PROJECT_NAME | dmc | The prefix for all of containers when started from the compose file | | DOMAIN | domain.com | The domain that's going to be used to access Jellyfin and rest of the other services | -| DATA_DIR | ../data | The location where all of configs, media and downloads are going to be stored. By default it's stored in the data folder | +| DATA_DIR | ../data | The location where all of media and downloads are going to be stored | +| SERVICES_DIR | ../data | The location where all of services configs are stored | | TIMEZONE | Europe/Oslo | Your timezone, you can find all of the valid timezones here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List | | ENV_PUID | 1000 | Your user ID, used for file permissions. You can find it by running command: id | | ENV_PGUID | 1000 | Your group ID, used for file permissions. You can find it by running command: id | | @@ -57,7 +60,7 @@ If you're using Cloudflare, make sure to enable the proxying by enabling the clo | sonarr.domain.com | CNAME | dmc.domain.com | | prowlarr.domain.com | CNAME | dmc.domain.com | -## Setting up Traefik +## Traefik Clone repository
``` git clone https://github.com/EdyTheCow/docker-media-center.git @@ -71,7 +74,7 @@ sudo chmod 600 acme.json ``` Basic auth
-Navigate to `_base/data/traefik/.htpasswd` and paste your generated user/pass in MD5 format. This will be your basic auth user/pass for most services we're going to set up. +Navigate to `_base/data/traefik/.htpasswd` and paste your generated user/pass in MD5 format. This will be your basic auth user/pass for most services we're going to set up. If unsure, google how to generate htpasswd. Start docker compose
Inside of `_base/compose` run @@ -89,48 +92,84 @@ Navigate to `jellyfin.domain.com` in your browser and follow the instructions. W | Library | Path | |---|---| -| Movies | /data/media/local/movies | -| TV Shows | /data/media/local/tvshows | +| Movies | /data/media/movies | +| TV Shows | /data/media/tvshows | -Jellyfin only has one volume pointing at `/data/media` this allows us to add whatever media type we want without having to define extra volumes in docker. The reason why it's under `local` directory is in case we wanted to mount google drive or similar in the future, we could add media under `gdrive` instead of `local` for example. +Jellyfin only has one volume pointing at `/data/media` this allows us to add whatever media type we want without having to define extra volumes in docker for future media types. ## Transmission -Start service +Inside of `dmc/compose` run ``` docker-compose up -d transmission ``` Configuration
-Navigate to `transmission.domain.com` in your browser, you should be asked to login using the credentials for basic auth you set-up earlier. Make sure everything works, other than that there's no further configuration. - -## Prowlarr +Navigate to `transmission.domain.com` in your browser, you should be asked to login using the credentials for basic auth you set-up earlier. Under `Preferences -> Torrents` make sure your download paths look like this: `/data/downloads/complete` and `/data/downloads/incomplete`. This will be important later on for hardlinks. ## Radarr -Start service +Inside of `dmc/compose` run + ``` docker-compose up -d radarr ``` +Configuration
+Navigate to `radarr.domain.com` in your browser, in the panel under `Media Management` section and add the root folder by simply selecting `/data/media/movies` directory. - Configuration
-In the panel, navigate to `Media Management` section and add root folder by simply selecting `/movies` directory. +Under `Download Clients` add a new client by selecting Transmission. Change these settings: + +| Setting | Value | +|---|---| +| Name | Transmission | +| Host | transmission | +| Category | movies | + +Host `transmission` will resolve the local IP of the container, do not use a domain or public IP. It's more convenient and secure to connect services locally. Since the connection is local, you do not need to insert any other credentials. Click `Test` to make sure it works and add the client. ## Sonarr -Start service +Inside of `dmc/compose` run ``` docker-compose up -d sonarr ``` Configuration
-In the panel, navigate to `Media Management` section and add root folder by simply selecting `/tv` directory. +Navigate to `sonarr.domain.com` in your browser, in the panel under `Media Management` section and add the root folder by simply selecting `/data/media/tvshows` directory. +Under `Download Clients` add new client by selecting Transmission. Change these settings: + +| Setting | Value | +|---|---| +| Name | Transmission | +| Host | transmission | +| Category | tvshows | + +Host `transmission` will resolve the local IP of the container, do not use a domain or public IP. It's more convenient and secure to connect services locally. Since the connection is local, you do not need to insert any other credentials. Click `Test` to make sure it works and add the client. + +## Prowlarr +Inside of `dmc/compose` run + ``` +docker-compose up -d prowlarr + ``` +Configuration
+Navigate to `prowlarr.domain.com` in your browser, under `Settings -> Apps` add Sonarr and Radarr. + +| Setting | Value | +|---|---| +| Name | Radarr | +| Sync Level | Full Sync | +| Prowlarr Server | http://prowlarr:9696 | +| Radarr Server | http://radarr:7878 | + +Instructions for adding Sonarr are exactly the same, just change the name to `Sonarr` and use `http://sonarr:8989` for `Sonarr Server`. You'll find API keys for both under `Settings -> General` in their respective panels. + +Navigate to `Indexers` and click `Add Indexer` to add public or private indexers. Once added, these will automatically sync with Sonarr and Radarr. ## Jellyseerr -Start service +Inside of `dmc/compose` run ``` docker-compose up -d jellyseerr ``` Configuration
- Select option to use `Jellyfin account` and proceed by providing url and account details for your jellyfin installation. Scan and enable libraries. + Navigate to `jellyseerr.domain.com` in your browser, select option to use `Jellyfin account` and proceed by providing url and account details for your jellyfin installation. Scan and enable libraries. Adding radarr / sonarr
Most importantly, do not use the actual url or IP of radarr / sonarr. Simply use `radarr` or `sonarr` for the hostname. This will resolve the local IP of the container rather than the public one. Since we're running everything on the same server, it's more secure and convenient to connect these services locally. Make sure to uncheck `Use SSL` option too for the local connection to work. @@ -140,10 +179,10 @@ Below are the important settings you should edit, the instructions for sonarr ar | Setting | Value | |---|---| | Default Server | Checked | -| Server Name | Radarr (can be something else too) | +| Server Name | Radarr | | Hostname or IP Address | radarr | | Use SSL | Unchecked | -| API Key | Can be found under General section in radarr panel | +| API Key | Can be found under General section in radarr / sonarr panel | # 📋 TODO diff --git a/_base/compose/.env b/_base/compose/.env new file mode 100644 index 0000000..415e4f1 --- /dev/null +++ b/_base/compose/.env @@ -0,0 +1,16 @@ +## +# General Variables +## + +COMPOSE_PROJECT_NAME=base +DATA_DIR=../data + +## +# Container: traefik -- Traefik variables +## + +## Only used if Cloudflare is selected in labels +# Cloudflare account email +CF_API_EMAIL= +# Cloudflare global api key +CF_API_KEY= \ No newline at end of file diff --git a/_base/compose/docker-compose.yml b/_base/compose/docker-compose.yml new file mode 100644 index 0000000..758c473 --- /dev/null +++ b/_base/compose/docker-compose.yml @@ -0,0 +1,25 @@ +version: '3.7' + +networks: + global: + external: true + +services: + + traefik: + image: traefik:v2.9 + env_file: + - .env + networks: + - global + restart: always + ports: + - "80:80" + - "443:443" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ${DATA_DIR}/traefik/traefik.toml:/etc/traefik/traefik.toml + - ${DATA_DIR}/traefik/acme.json:/acme.json + - ${DATA_DIR}/traefik/.htpasswd:/.htpasswd + labels: + - "traefik.http.middlewares.dmc-auth.basicauth.usersfile=/.htpasswd" \ No newline at end of file diff --git a/_base/data/traefik/.htpasswd b/_base/data/traefik/.htpasswd new file mode 100644 index 0000000..e69de29 diff --git a/_base/data/traefik/acme.json b/_base/data/traefik/acme.json new file mode 100644 index 0000000..e69de29 diff --git a/_base/data/traefik/traefik.toml b/_base/data/traefik/traefik.toml new file mode 100644 index 0000000..16c9871 --- /dev/null +++ b/_base/data/traefik/traefik.toml @@ -0,0 +1,24 @@ +[global] + checkNewVersion = false + sendAnonymousUsage = false + +[entryPoints] + [entryPoints.web] + address = ":80" + + [entryPoints.websecure] + address = ":443" + +[providers.docker] + +[certificatesResolvers.cloudflare.acme] + email = "admin@domain.com" + [certificatesResolvers.cloudflare.acme.dnsChallenge] + provider = "cloudflare" + delayBeforeCheck = 0 + +[certificatesResolvers.letsencrypt.acme] + email = "admin@domain.com" + storage = "acme.json" + [certificatesResolvers.letsencrypt.acme.httpChallenge] + entryPoint = "web" \ No newline at end of file diff --git a/dmc/compose/.env b/dmc/compose/.env new file mode 100644 index 0000000..3096bbb --- /dev/null +++ b/dmc/compose/.env @@ -0,0 +1,26 @@ +# Containers prefix +COMPOSE_PROJECT_NAME=dmc + +# Data location for storing media, downloads and configs +DATA_DIR=../data +SERVICES_DIR=../services + +# Timezone +TIMEZONE=Europe/Oslo + +# Linux user/group ID for file permissions +## User ID +ENV_PUID=1000 +## Group ID +ENV_PGID=1000 + +# Domain +DOMAIN=domain.com + +# Subdomains for accessing services +SUB_DOMAIN_JELLYFIN=jellyfin +SUB_DOMAIN_TRANSMISSION=transmission +SUB_DOMAIN_SONARR=sonarr +SUB_DOMAIN_RADARR=radarr +SUB_DOMAIN_PROWLARR=prowlarr +SUB_DOMAIN_JELLYSEERR=jellyseerr \ No newline at end of file diff --git a/dmc/compose/docker-compose.yml b/dmc/compose/docker-compose.yml new file mode 100644 index 0000000..0dbb8c2 --- /dev/null +++ b/dmc/compose/docker-compose.yml @@ -0,0 +1,152 @@ +version: "3.7" + +networks: + global: + external: true + local: + external: false + +services: + + jellyfin: + image: lscr.io/linuxserver/jellyfin:latest + restart: unless-stopped + #security_opt: # Required for Docker versions below 20.10.10, update Docker for long term solution. Source: https://docs.linuxserver.io/faq#jammy + # - seccomp=unconfined + networks: + - global + - local + environment: + - PUID=${ENV_PUID} + - PGID=${ENV_PGID} + - TZ=${TIMEZONE} + volumes: + - ${SERVICES_DIR}/jellyfin:/config + - ${DATA_DIR}/media:/data/media + labels: + - "traefik.enable=true" + - "traefik.http.routers.dmc-jellyfin.rule=Host(`${SUB_DOMAIN_JELLYFIN}.${DOMAIN}`)" + - "traefik.http.routers.dmc-jellyfin.tls=true" + - "traefik.http.services.dmc-jellyfin.loadbalancer.server.port=8096" + - "traefik.http.routers.dmc-jellyfin.tls.certresolver=letsencrypt" + - "traefik.docker.network=global" + + transmission: + image: lscr.io/linuxserver/transmission:latest + restart: unless-stopped + networks: + - global + - local + environment: + - PUID=${ENV_PUID} + - PGID=${ENV_PGID} + - TZ={TIMEZONE} + volumes: + - ${SERVICES_DIR}/transmission:/config + - ${DATA_DIR}/downloads:/data/downloads + ports: + - 51413:51413 # Torrent port TCP + - 51413:51413/udp # Torrent port UDP + labels: + - "traefik.enable=true" + - "traefik.http.routers.dmc-transmission.rule=Host(`${SUB_DOMAIN_TRANSMISSION}.${DOMAIN}`)" + - "traefik.http.routers.dmc-transmission.tls=true" + - "traefik.http.services.dmc-transmission.loadbalancer.server.port=9091" + - "traefik.http.routers.dmc-transmission.tls.certresolver=letsencrypt" + - "traefik.docker.network=global" + # Basic auth + - "traefik.http.middlewares.dmc-auth.basicauth.usersfile=/.htpasswd" + - "traefik.http.routers.dmc-transmission.middlewares=dmc-auth" + + radarr: + image: lscr.io/linuxserver/radarr:latest + restart: unless-stopped + networks: + - global + - local + environment: + - PUID=${ENV_PUID} + - PGID=${ENV_PGID} + - TZ={TIMEZONE} + volumes: + - ${SERVICES_DIR}/radarr:/config + - ${DATA_DIR}:/data + labels: + - "traefik.enable=true" + - "traefik.http.routers.dmc-radarr.rule=Host(`${SUB_DOMAIN_RADARR}.${DOMAIN}`)" + - "traefik.http.routers.dmc-radarr.tls=true" + - "traefik.http.services.dmc-radarr.loadbalancer.server.port=7878" + - "traefik.http.routers.dmc-radarr.tls.certresolver=letsencrypt" + - "traefik.docker.network=global" + # Basic auth + - "traefik.http.middlewares.dmc-auth.basicauth.usersfile=/.htpasswd" + - "traefik.http.routers.dmc-radarr.middlewares=dmc-auth" + + sonarr: + image: lscr.io/linuxserver/sonarr:latest + restart: unless-stopped + #security_opt: # Required for Docker versions below 20.10.10, update Docker for long term solution. Source: https://docs.linuxserver.io/faq#jammy + # - seccomp=unconfined + networks: + - global + - local + environment: + - PUID=${ENV_PUID} + - PGID=${ENV_PGID} + - TZ={TIMEZONE} + volumes: + - ${SERVICES_DIR}/sonarr:/config + - ${DATA_DIR}:/data + labels: + - "traefik.enable=true" + - "traefik.http.routers.dmc-sonarr.rule=Host(`${SUB_DOMAIN_SONARR}.${DOMAIN}`)" + - "traefik.http.routers.dmc-sonarr.tls=true" + - "traefik.http.services.dmc-sonarr.loadbalancer.server.port=8989" + - "traefik.http.routers.dmc-sonarr.tls.certresolver=letsencrypt" + - "traefik.docker.network=global" + # Basic auth + - "traefik.http.middlewares.dmc-auth.basicauth.usersfile=/.htpasswd" + - "traefik.http.routers.dmc-sonarr.middlewares=dmc-auth" + + prowlarr: + image: lscr.io/linuxserver/prowlarr:latest + restart: unless-stopped + networks: + - global + - local + environment: + - PUID=${ENV_PUID} + - PGID=${ENV_PGID} + - TZ={TIMEZONE} + volumes: + - ${SERVICES_DIR}/prowlarr:/config + labels: + - "traefik.enable=true" + - "traefik.http.routers.dmc-prowlarr.rule=Host(`${SUB_DOMAIN_PROWLARR}.${DOMAIN}`)" + - "traefik.http.routers.dmc-prowlarr.tls=true" + - "traefik.http.services.dmc-prowlarr.loadbalancer.server.port=9696" + - "traefik.http.routers.dmc-prowlarr.tls.certresolver=letsencrypt" + - "traefik.docker.network=global" + # Basic auth + - "traefik.http.middlewares.dmc-auth.basicauth.usersfile=/.htpasswd" + - "traefik.http.routers.dmc-prowlarr.middlewares=dmc-auth" + + jellyseerr: + image: fallenbagel/jellyseerr:latest + restart: unless-stopped + networks: + - global + - local + environment: + - LOG_LEVEL=debug + - TZ={TIMEZONE} + volumes: + - ${SERVICES_DIR}/jellyseerr:/app/config + labels: + - "traefik.enable=true" + - "traefik.http.routers.dmc-jellyseerr.rule=Host(`${SUB_DOMAIN_JELLYSEERR}.${DOMAIN}`)" + - "traefik.http.routers.dmc-jellyseerr.tls=true" + - "traefik.http.services.dmc-jellyseerr.loadbalancer.server.port=5055" + - "traefik.http.routers.dmc-jellyseerr.tls.certresolver=letsencrypt" + - "traefik.docker.network=global" + diff --git a/dmc/data/.gitkeep b/dmc/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/dmc/services/.gitkeep b/dmc/services/.gitkeep new file mode 100644 index 0000000..e69de29