From 1f43072ad978145807b70fa49b4674fd56fc9c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Lafarge?= Date: Thu, 1 Jun 2017 01:20:27 +0200 Subject: [PATCH] Integrate Traefik (2.0) to our stack I'm sorry, this commit contains a compilation of what I've added to our Plex & co setup over the last two years, without commiting anything. So... it actually contains multiple changes :/ I thought these changes would be beneficial to our pet project Essentially, they are meant to make setup and maintainance easier than ever before, which I think is essential if we want more people to enjoy this stuff :D Here's the list: - Traefik has been integrated to our stack. It makes the setup easier for everyone who just wants a working setup on a fresh new server. Using this integrated traefik to route traffic to containers that aren't part of this stack is still possible of course. As a result, using custom networks is not necessary any more, it simplifies our `docker-compose.yaml` file a bit. - I've updated to Traefik 2, which completely breaks the vast majority of its APIs. Docker annotations had to be rewritten. - I removed the traefik.toml file and entirely moved the configuration to CLI flags. Removing this "moving part" that had to be edited and could be commited by accident (with our credentials in it...) will make "git pulls" much much easier... and therefore encourage contributions I hope :) - Basic auth is handled using Traefik's middleware feature (new in 2.0). It's not necessary to setup auth on radarr, sonarr, etc. individually Also, it's now possible to have multiple users instead of sharing the same credentials with your family and friends. - The configuration just boils down to env. variables, which the README suggests should be put in the user's `.bashrc/.zshrc` (using `docker-compose` commands is therefore way simpler, no need to constantly use Ctrl-R any more). - The plex token is no more passed as an env. var. It has to be entered on the UI on first setup. - Only the HTTPs port is exposed, most browsers use https by default when typing URLs in the navigation bar. As a result, we now use the tlsChallenge (instead of http challenge): it doesn't require the server to listen on port 80. Only 443 is used during the ACME challenge. - Some additional folders are mounted onto plex, they are targeted at manual uploads from other machines (I used that to RSync music from my multiple computers, as well as my Pictures, which I think is a rather valuable feature). --- .gitignore | 10 +- README.md | 158 ++++++++++++++++++++++----- README.old.md | 48 +++++++++ docker-compose.yaml | 258 ++++++++++++++++++++++++++------------------ 4 files changed, 337 insertions(+), 137 deletions(-) create mode 100755 README.old.md mode change 100644 => 100755 docker-compose.yaml 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