diff --git a/.gitignore b/.gitignore index 1a16b1b..86b806a 100644 --- a/.gitignore +++ b/.gitignore @@ -101,5 +101,11 @@ Session.vim # auto-generated tag files tags -# Media (oooops...) -media/ +# We do not want to commit user data +media + +# and even more, we don't want to commit TLS Certs :o +acme/ + +# or htpasswd files +htpasswd diff --git a/README.md b/README.md index 075ee12..ce0b5c4 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,152 @@ -# Media Server +Dockyard +======== -A media server configuration to run Plex, Sonarr, Radarr, and Transmission in Docker and behind Traefik. +TL;DR +----- +Each subdirectory contains a docker-compose setup. Setups can be combined, for +instance, you can spawn Traefik to act as a router to server-compents in other +setups. -## First run +## Requirements +NOTE: All the following should be applied on the machine you want to setup our +Plex stack on. + +- install Apache `htpasswd` - install [Docker](https://www.docker.com/) - install [Docker Compose](https://docs.docker.com/compose/) -- create a [Plex accout](https://www.plex.tv/) -- clone this repository -- clone and setup [the reverse proxy](https://github.com/hkaj/reverse_proxy) -- create a user for your media server, export its `$USER_ID` and `$GROUP_ID`. -- create a folder named `media` in this folder (`dockyard`) owned by $USER_ID:$GROUP_ID from your `media` user. -- get your Plex claim token at https://www.plex.tv/claim/ -- create a `web` docker network with `docker network create web` -- run `DOMAIN_NAME="..." PLEX_TOKEN="..." USER_ID="$USER_ID" GROUP_ID="$GROUP_ID" docker-compose up -d` -- profit :) +- clone this repository in a folder of your choice, where you want all your + media to be stored +- a domain (or subdomain) name with A records pointing to your server IP +``` +# Replace example.com with your (sub)domain here +example.COM A +*.example.com A +``` + +- Export these env vars in your `.bashrc/.zshrc`: +```shell +export TRAEFIK_ADMIN_PORT=8080 +# Change example.com with your domain name +export DOMAIN_NAME=fsociety.tel +# Change me@example.com with your domain name +export ACME_EMAIL=me@example.com +export USER_ID=${UID} +export GROUP_ID=${GID} +``` + +- then resource .zshrc/.bashrc, or simply log out of your server and connect again +``` +# Bash +source ~/.bashrc + +# ZSH +source ~/.zshrc +``` + +- protect your server with authentication (enabled on all services, no need to + log-in on all of them) +``` +# Jump into the repo you just cloned +cd dockyard + +htpasswd -c htpasswd +# you will then be prompted for your password +# an htaccess file will be created +``` + + +- finally bring up your stack (you can use [ctop](https://ctop.sh) to monitor + your stack) +```shell +# Bring up the stack ! +docker-compose up -d +``` + +## Configuration + +## Plex + +Plex won't be opened to the web when you start it for the first time. For that +reason, you'll need to create an SSH tunnel to perform the initial configuration + +```shell +ssh -L 32400:127.0.0.1:32400 +# Don't close the SSH session or your terminal until you finish the setup +``` + +Then, you can reach `http://127.0.0.1:32400` in your browser and follow the +instructions. You will then be able to access your Plex server on +[https://app.plex.tv](https://app.plex.tv). + +TODO: recommend TLS setup on the Plex server itself + +## Transmission + +TODO: protect via password using Traefik + +## Radarr + +TODO: protect via password using Traefik + +## Sonarr + +TODO: protect via password using Traefik + +## Ombi + +TODO: protect via password using Traefik + +## PlexPy + +TODO: protect via password using Traefik + +## Jackett + +TODO: protect via password using Traefik -## Config +## Where to find your media ? +In the `dockyard` (our repo) folder, a `media` subfolder will be created. +This is where all your content will be stored. This is the folder to +backup up and relocate to another server in case you need to migrate your +data from one machine to another. -### Transmission +## Troubleshooting -We use [Transmission](https://transmissionbt.com/) as the downloader. +### Docker-Compose commands -- stop transmission's container -- configure basic auth at `media/transmission/config/settings.json` (you will need to touch `rpc-authentication-required`, `rpc-username` and `rpc-password`) -- start transmission's container +All these commands must be run at the root of the repo you cloned +- getting logs from your container: +```shell +docker-compose logs -### Sonarr +# Only logs for a given set of services +docker-compose logs plex proxy +``` -We use [Sonarr](https://sonarr.tv/) to track and manage TV shows. +### Accessing Traefik's user interface -- setup auto-update and authentication -- connect transmission as a downloader +Traefik's user interface is not exposed publicly. To connect to it, you can use +SSH-tunneling on port `8080`: +```shell +ssh -L 8080:127.0.0.1:8080 +# don't close the SSH session +``` +The interface will be accessible under `http://localhost:8080` on your local +machine. -### Radarr +## Disclaimer -We use [Radarr](https://radarr.video/) (a clone of Sonarr) to track and manage movies. +We can't be held responsible for what you'll do with the setups (don't download +stuff illegally, etc. etc.) -- setup auto-update and authentication -- connect transmission as a downloader +## Maintainers +* [hkaj](/hkaj) +* [elafarge](/elafarge) -### Jackett -We use [Jackett](https://github.com/Jackett/Jackett) as a proxy between private trackers and our other components. diff --git a/README.old.md b/README.old.md new file mode 100755 index 0000000..8237dd4 --- /dev/null +++ b/README.old.md @@ -0,0 +1,48 @@ +# Media Server + +A media server configuration to run Plex, Sonarr, Radarr, and Transmission in Docker and behind Traefik. + + +## First run + +- install [Docker](https://www.docker.com/) +- create a [Plex accout](https://www.plex.tv/) +- clone this repository +- clone and setup [a reverse proxy](../traefik/) +- create a user for your media server, export its `$USER_ID` and `$GROUP_ID`. +- create a media folder in docker-compose's folder with $USER_ID:$GROUP_ID ownership +- get your Plex claim token at https://www.plex.tv/claim/ +- run `DOMAIN_NAME="..." PLEX_TOKEN="..." IP_ADDRESS="..." USER_ID="$USER_ID" GROUP_ID="$GROUP_ID" docker-compose up -d` +- profit :) + +## Config + + +### Transmission + +We use [Transmission](https://transmissionbt.com/) as the downloader. + +- stop transmission's container +- configure basic auth at `media/transmission/config/settings.json` (you will need to touch `rpc-authentication-required`, `rpc-username` and `rpc-password`) +- start transmission's container + + +### Sonarr + +We use [Sonarr](https://sonarr.tv/) to track and manage TV shows. + +- setup auto-update and authentication +- connect transmission as a downloader + + +### Radarr + +We use [Radarr](https://radarr.video/) (a clone of Sonarr) to track and manage movies. + +- setup auto-update and authentication +- connect transmission as a downloader + + +### Jackett + +We use [Jackett](https://github.com/Jackett/Jackett) as a proxy between private trackers and our other components. diff --git a/docker-compose.yaml b/docker-compose.yaml old mode 100644 new mode 100755 index 3a2674a..17075e9 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,156 +1,200 @@ version: '2.1' services: + # Our reverse proxy, handling host-based routing, TLS termination, Let's Encrypt... + proxy: + image: traefik:latest + container_name: traefik + restart: unless-stopped + command: + - --accesslog + - --api.insecure + - --global.sendanonymoususage=false + + # Certificate resolution + - --certificatesresolvers.letsencrypt.acme + - --certificatesresolvers.letsencrypt.acme.tlschallenge=true + - --certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL} + - --certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/acme.json + + # Providers + - --providers.docker=true + - --providers.docker.exposedbydefault=false + + # Entrypoint + - --entrypoints.websecure.address=:443 + + ports: + + # Just for the HTTP -> HTTPs redirection + - "443:443" + + # Traefik's admin port's only available via localhost or using + # SSH tunelling: ssh -L YOUR_PORT:127.0.0.1:YOUR_PORT + - "127.0.0.1:8080:8080" + + labels: + - "traefik.http.middlewares.auth.basicauth.usersfile=/etc/traefik/htpasswd" + - "traefik.http.middlewares.auth.basicauth.realm=Authenticate for ${DOMAIN_NAME}" + + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./acme/:/etc/traefik/acme + - ./htpasswd:/etc/traefik/htpasswd:ro + + # Plex, the actual media server organizing and streaming video files to all + # your devices plex: image: plexinc/pms-docker:latest + restart: unless-stopped container_name: plex - networks: - - web environment: - - PLEX_CLAIM="${PLEX_TOKEN}" - - ADVERTISE_IP="https://plex.${DOMAIN_NAME}/" - - PLEX_UID=${USER_ID} - - PLEX_GID=${GROUP_ID} + - PLEX_UID=${USER_ID} + - PLEX_GID=${GROUP_ID} + ports: + - 32400:32400 volumes: - - /etc/localtime:/etc/localtime:ro - - ./media/radarr/movies:/data/movies - - ./media/sonarr/series:/data/tvshows - - ./media/plex/config/:/config - - /tmp/transcode/:/transcode - labels: - - "traefik.enable=true" - - "traefik.backend=plex" - - "traefik.docker.network=web" - - "traefik.frontend.rule=Host:plex.${DOMAIN_NAME}" - - "traefik.port=32400" - depends_on: - - transmission - - sonarr - - radarr + - /etc/localtime:/etc/localtime:ro + - ./media/radarr/movies:/data/movies + - ./media/sonarr/series:/data/tvshows + - ./media/manual/music:/data/music + - ./media/manual/pictures:/data/pictures + - ./media/manual/videos:/data/videos + - ./media/plex/config/:/config + - /tmp/transcode/:/transcode + # An activity monitoring tool for plex, based on plex logs plexpy: image: linuxserver/plexpy:latest + restart: unless-stopped container_name: plexpy - networks: - - web environment: - - PUID=${USER_ID} - - PGID=${GROUP_ID} + - PUID=${USER_ID} + - PGID=${GROUP_ID} volumes: - - ./media/plexpy:/config - - ./media/plex/config/Library/Application\ Support/Plex\ Media\ Server/Logs:/logs:ro + - ./media/plexpy:/config + - ./media/plex/config/Library/Application\ Support/Plex\ Media\ Server/Logs:/logs:ro labels: - - "traefik.enable=true" - - "traefik.backend=plexpy" - - "traefik.frontend.rule=Host:plexpy.${DOMAIN_NAME}" - - "traefik.port=8181" - - "traefik.docker.network=web" - depends_on: - - plex + - "traefik.enable=true" + - "traefik.http.routers.plexpy.rule=Host(`plexpy.${DOMAIN_NAME}`)" + - "traefik.http.routers.plexpy.entrypoints=websecure" + - "traefik.http.routers.plexpy.tls=true" + - "traefik.http.routers.plexpy.tls.certresolver=letsencrypt" + - "traefik.http.routers.plexpy.middlewares=auth@docker" + expose: + - 8181 + # Our web-based BitTorrent client transmission: image: linuxserver/transmission:latest + restart: unless-stopped container_name: transmission - networks: - - web environment: - - PUID=${USER_ID} - - PGID=${GROUP_ID} + - PUID=${USER_ID} + - PGID=${GROUP_ID} volumes: - - /etc/localtime:/etc/localtime:ro - - ./media/transmission/config/:/config - - ./media/transmission/downloads/:/downloads + - /etc/localtime:/etc/localtime:ro + - ./media/transmission/config/:/config + - ./media/transmission/downloads/:/downloads + ports: + - 51413:51413 labels: - - "traefik.enable=true" - - "traefik.backend=transmission" - - "traefik.frontend.rule=Host:transmission.${DOMAIN_NAME}" - - "traefik.port=9091" - - "traefik.docker.network=web" + - "traefik.enable=true" + - "traefik.http.routers.transmission.rule=Host(`transmission.${DOMAIN_NAME}`)" + - "traefik.http.routers.transmission.entrypoints=websecure" + - "traefik.http.routers.transmission.tls=true" + - "traefik.http.routers.transmission.tls.certresolver=letsencrypt" + - "traefik.http.routers.transmission.middlewares=auth@docker" + expose: + - 9091 + # Scrapes TV shows metadata and finds matching torrents... automatically + # after episodes are released sonarr: image: linuxserver/sonarr:latest + restart: unless-stopped container_name: sonarr - networks: - - web volumes: - - /etc/localtime:/etc/localtime:ro - - /dev/rtc:/dev/rtc:ro - - ./media/sonarr/series:/tv - - ./media/sonarr/config:/config - - ./media/transmission/downloads/:/downloads + - /etc/localtime:/etc/localtime:ro + - /dev/rtc:/dev/rtc:ro + - ./media/sonarr/series:/tv + - ./media/sonarr/config:/config + - ./media/transmission/downloads/:/downloads environment: - - PUID=${USER_ID} - - PGID=${GROUP_ID} + - PUID=${USER_ID} + - PGID=${GROUP_ID} labels: - - "traefik.enable=true" - - "traefik.backend=sonarr" - - "traefik.frontend.rule=Host:sonarr.${DOMAIN_NAME}" - - "traefik.port=8989" - - "traefik.docker.network=web" - depends_on: - - transmission + - "traefik.enable=true" + - "traefik.http.routers.sonarr.rule=Host(`sonarr.${DOMAIN_NAME}`)" + - "traefik.http.routers.sonarr.entrypoints=websecure" + - "traefik.http.routers.sonarr.tls=true" + - "traefik.http.routers.sonarr.tls.certresolver=letsencrypt" + - "traefik.http.routers.sonarr.middlewares=auth@docker" + expose: + - 8989 + # Scrapes film metadata and finds matching torrents radarr: image: linuxserver/radarr:latest + restart: unless-stopped container_name: radarr - networks: - - web volumes: - - /etc/localtime:/etc/localtime:ro - - /dev/rtc:/dev/rtc:ro - - ./media/radarr/movies:/movies - - ./media/radarr/config:/config - - ./media/transmission/downloads/:/downloads + - /etc/localtime:/etc/localtime:ro + - /dev/rtc:/dev/rtc:ro + - ./media/radarr/movies:/movies + - ./media/radarr/config:/config + - ./media/transmission/downloads/:/downloads environment: - - PUID=${USER_ID} - - PGID=${GROUP_ID} + - PUID=${USER_ID} + - PGID=${GROUP_ID} labels: - - "traefik.enable=true" - - "traefik.backend=radarr" - - "traefik.frontend.rule=Host:radarr.${DOMAIN_NAME}" - - "traefik.port=7878" - - "traefik.docker.network=web" - depends_on: - - transmission - - # Proxy to a bunch of public trackers + - "traefik.enable=true" + - "traefik.http.routers.radarr.rule=Host(`radarr.${DOMAIN_NAME}`)" + - "traefik.http.routers.radarr.entrypoints=websecure" + - "traefik.http.routers.radarr.tls=true" + - "traefik.http.routers.radarr.tls.certresolver=letsencrypt" + - "traefik.http.routers.radarr.middlewares=auth@docker" + expose: + - 7878 + + # A Tornzab proxy to many many torrent tracker websites (public and private) jackett: image: linuxserver/jackett:latest + restart: unless-stopped container_name: jackett - networks: - - web volumes: - - ./media/jackett/config/:/config - - ./media/transmission/downloads/:/downloads + - ./media/jackett/config/:/config + - ./media/transmission/downloads/:/downloads environment: - - PUID=${USER_ID} - - PGID=${GROUP_ID} + - PUID=${USER_ID} + - PGID=${GROUP_ID} labels: - - "traefik.enable=true" - - "traefik.backend=jackett" - - "traefik.frontend.rule=Host:jackett.${DOMAIN_NAME}" - - "traefik.port=9117" - - "traefik.docker.network=web" + - "traefik.enable=true" + - "traefik.http.routers.jackett.rule=Host(`jackett.${DOMAIN_NAME}`)" + - "traefik.http.routers.jackett.entrypoints=websecure" + - "traefik.http.routers.jackett.tls=true" + - "traefik.http.routers.jackett.tls.certresolver=letsencrypt" + - "traefik.http.routers.jackett.middlewares=auth@docker" + expose: + - 9117 + # Makes it possible for your plex users to request new content on your Plex ombi: image: linuxserver/ombi + restart: unless-stopped container_name: ombi - restart: always - networks: - - web environment: - - PUID=${USER_ID} - - PGID=${GROUP_ID} + - PUID=${USER_ID} + - PGID=${GROUP_ID} volumes: - - /etc/localtime:/etc/localtime:ro - - ./media/ombi/config:/config + - /etc/localtime:/etc/localtime:ro + - ./media/ombi/config:/config labels: - - "traefik.enable=true" - - "traefik.backend=ombi" - - "traefik.frontend.rule=Host:ombi.${DOMAIN_NAME}" - - "traefik.port=3579" - - "traefik.docker.network=web" - -networks: - web: - external: true + - "traefik.enable=true" + - "traefik.http.routers.ombi.rule=Host(`ombi.${DOMAIN_NAME}`)" + - "traefik.http.routers.ombi.entrypoints=websecure" + - "traefik.http.routers.ombi.tls=true" + - "traefik.http.routers.ombi.tls.certresolver=letsencrypt" + - "traefik.http.routers.ombi.middlewares=auth@docker" + expose: + - 3579