Skip to content

Instantly share code, notes, and snippets.

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/45a47852be6d36f534ef13ccb5576845 to your computer and use it in GitHub Desktop.
Save altendorfme/45a47852be6d36f534ef13ccb5576845 to your computer and use it in GitHub Desktop.
Docker Automatic Media Server - Setup Guide

Introduction

This guide is focused on building a completely autonomous request-based media server using individual docker containers.

Most of the images we will be using are maintiained by linuxserver.io. They maintain many up-to-date versions of the most popular tools used for media servers.

Our full stack includes:

  • Plex Media Server - Plex Media Server is the back-end component to Plex, a self-hosted media platform.
  • Transmission - A lightweight torrent downloading client.
  • Radarr - Web application and tool that integrates directly with most torrent clients for monitoring downloading movies.
  • Sonarr - Web application and tool that integrates directly with most torrent clients for monitoring and downloading TV shows.
  • Jackett - An indexing tool to be used in conjunction with Sonarr/Radarr.
  • Ombi - Web application that automatically gives your shared Plex users the ability to request content.
  • Tautulli - A Python based monitoring and tracking tool for Plex Media Server.
  • Heimdall - A dashboard to organize and view the status of all your apps.
  • LetsEncrypt - For generating SSL certs and reverse proxy to subdomain all our apps on our domain.

Requirements

  1. Docker and docker-compose installed on your machine.
  2. A domain with DNS management.
  3. A VPN provider supported by OpenVPN.
  4. A storage device to keep your large files.

Initial Setup

These are the instructions on setting up your server and DNS records.

DNS Management

You will need to set up your DNS records to point to your server and enable subdomains.

A Record

You will need to create an A record to point to your server.

In the name field, you will put your domain name (alternatively, most DNS providers support using the @ character).

In the IPv4 field, you will put your global IP address. If you don't have a static IP, you will have to use your dynamically assigned one given to you by your ISP. There are a couple methods to find this (make sure you don't have any VPN services running, or your IP address will be different):

  • From your network on any internet-accessible device, navigate to ipv4.icanhazip.com
  • From the command line, run curl ipv4.icanhazip.com

CNAME Records

These records are important since they allow your domain to have subdomains, i.e. sonarr.mydomain.com. If your DNS provider supports wildcard CNAME records, you will only need to create one. Otherwise, you will have to create a CNAME record for each app you want to be able to access. LetsEncrypt doesn't have a web interface, and you can access your Plex server from app.plex.tv, so you can exclude those.

Creating mediaman

The first thing we want to do is create a user that will be able to read and write the contents of our docker volumes.

Create the user mediaman with a user ID of your choosing.

Note: ID's from 0-999 are reserved, use any number above that.

sudo useradd -u 2020 --create-home mediaman

Set mediaman's password.

sudo passwd mediaman

And log in to mediaman's bash.

su mediaman

Next, you will want to give mediaman access to the directories we will be using. In my case, I have a hard drive mounted under /mnt/disk1. We don't want to give access to the entire disk as we may end up putting more data on there in the future, so we create subdirectories in it just for this setup. Let's create folders for our media and torrent files.

sudo mkdir /mnt/disk1/media

sudo mkdir /mnt/disk1/torrents

Before we go ahead and give mediaman access to these directories, we need to create the folders our services will need to use since the chown -R command does not apply to directories created after you run the command.

People typically divide their Plex libraries into a directory each. So, let's create directories for movies and tv. You can create more based on your needs.

sudo mkdir /mnt/disk1/media/movies

sudo mkdir /mnt/disk1/media/tv

Transmission's default structure has downloads and watch (watch is if you want to manually place torrent files in the directory, which Transmission will recognize and begin torrenting).

sudo mkdir /mnt/disk1/torrents/downloads

sudo mkdir /mnt/disk1/torrents/watch

Give mediaman access to directories media and torrents, recursively:

sudo chown -R mediaman:mediaman /mnt/disk1/media

sudo chown -R mediaman:mediaman /mnt/disk1/torrents

App Structure

My directory structure is set up as such: /home/mediaman/docker-automatic-media-server/[service name]. I have a subfolder inside the docker-automatic-media-server/ folder with each app's name, i.e. /home/mediaman/docker-automatic-media-server/sonarr. In our case, every single one of our apps use a config folder, which we want to be accessible from the same directory for simplicity's sake, so in each one of those subfolders, create another folder called config/.


Docker Setup

Now we will be writing our docker-compose files and starting the docker containers. I will leave out most info on how to setup the actual application from the web interfaces to keep this guide as short as possible. Refer to the Docker Hub link under each section.

Note: Remember to change any volume paths to work on your machine!

Plex

docker-compose.yml

version: '2'

services:
        plex:
                image: linuxserver/plex
                container_name: plex
                network_mode: host
                environment:
                         - PUID=2020
                         - PGID=2020
                         - VERSION=docker
                volumes:
                        - /home/mediaman/docker-automatic-media-server/plex/config:/config
                        - /mnt/disk1/media/movies:/movies
                        - /mnt/disk1/media/tv:/tv
                restart: unless-stopped

Transmission

if you have a different VPN provider, you can use a different image as opposed to the qmcgaw/private-internet-access image and update the docker-compose file with it. The important thing is that the Transmission service uses the same network as the VPN service, which is done with the following line: network_mode: service:[name of service]. If you update the docker-compose file, remember to expose the Transmission service's ports in the VPN service ports section.

docker-compose.yml

version: '3.7'

services:
        pia:
                build: https://github.com/qdm12/private-internet-access-docker.git
                image: qmcgaw/private-internet-access
                container_name: pia
                init: true
                cap_add:
                        - NET_ADMIN
                devices:
                        - /dev/net/tun
                environment:
                        - USER=[USERNAME]
                        - PASSWORD=[PASSWORD]
                        - ENCRYPTION=strong
                        - PROTOCOL=udp
                        - REGION=US Chicago
                        - NONROOT=no
                        - DOT=on
                        - BLOCK_MALICIOUS=on
                        - BLOCK_NSA=off
                        - UNBLOCK=
                        - FIREWALL=on
                        - EXTRA_SUBNETS=
                        - TINYPROXY=on
                        - TINYPROXY_LOG=Critical
                        - TINYPROXY_USER=[TINYPROXY_USERNAME]
                        - TINYPROXY_PASSWORD=[TINYPROXY_PASSWORD]
                        - SHADOWSOCKS=on
                        - SHADOWSOCKS_LOG=on
                        - SHADOWSOCKS_PASSWORD=[SHADOWSOCKS_PASSWORD]
                network_mode: bridge
                ports:
                        # pia
                        - 8888:8888/tcp
                        - 8388:8388/tcp
                        - 8388:8388/udp

                        # transmission
                        - 9091:9091
                        - 51413:51413
                        - 51413:51413/udp
                restart: unless-stopped
        transmission:
                image: linuxserver/transmission
                container_name: transmission
                depends_on:
                        - pia
                network_mode: service:pia
                environment:
                        - PUID=2020
                        - PGID=2020
                        - TZ=America/Chicago
                        - USER=[USERNAME]
                        - PASS=[PASSWORD]
                volumes:
                        - /home/mediaman/docker-automatic-media-server/transmission/config:/config
                        - /mnt/disk1/torrents/downloads:/downloads
                        - /mnt/disk1/torrents/watch:/watch
                restart: unless-stopped

Radarr

docker-compose.yml

version: '2'

services:
        radarr:
                image: linuxserver/radarr
                container_name: radarr
                environment:
                        - PUID=2020
                        - PGID=2020
                        - TZ=America/Chicago
                volumes:
                        - /home/mediaman/docker-automatic-media-server/radarr/config:/config
                        - /mnt/disk1/media/movies:/movies
                        - /mnt/disk1/downloads:/downloads
                network_mode: bridge
                ports:
                        - 7878:7878
                restart: unless-stopped

Sonarr

docker-compose.yml

version: '2'

services:
        sonarr:
                image: linuxserver/sonarr
                container_name: sonarr
                environment:
                        - PUID=2020
                        - PGID=2020
                        - TZ=America/Chicago
                volumes:
                        - /home/mediaman/docker-automatic-media-server/sonarr/config:/config
                        - /mnt/disk1/media/tv:/tv
                        - /mnt/disk1/torrents/downloads:/downloads
                network_mode: bridge
                ports:
                        - 8989:8989
                restart: unless-stopped

Jackett

docker-compose.yml

version: '2'

services:
        jackett:
                image: linuxserver/jackett
                container_name: jackett
                environment:
                        - PUID=2020
                        - PGID=2020
                        - TZ=America/Chicago
                volumes:
                        - /home/mediaman/docker-automatic-media-server/jackett/config:/config
                        - /mnt/disk1/downloads:/downloads
                network_mode: bridge
                ports:
                        - 9117:9117
                restart: unless-stopped

Ombi

docker-compose.yml

version: '2'

services:
        ombi:
                image: linuxserver/ombi
                container_name: ombi
                environment:
                        - PUID=2020
                        - PGID=2020
                        - TZ=America/Chicago
                        - BASE_URL=/
                volumes:
                        - /home/mediaman/docker-automatic-media-server/ombi/config:/config
                network_mode: bridge
                ports:
                        - 3579:3579
                restart: unless-stopped

Tautulli

docker-compose.yml

version: '2'

services:
        tautulli:
                image: linuxserver/tautulli
                container_name: tautulli
                environment:
                        - PUID=2020
                        - PGID=2020
                        - TZ=America/Chicago
                volumes:
                        - /home/mediaman/docker-automatic-media-server/tautulli/config:/config
                        - /home/mediaman/docker-automatic-media-server/plex/config/Library/Application Support/Plex Media Server/Logs:/logs
                network_mode: bridge
                ports:
                        - 8181:8181
                restart: unless-stopped

Heimdall

docker-compose.yml

version: '2'

services:
        heimdall:
                image: linuxserver/heimdall
                container_name: heimdall
                environment:
                        - PUID=2020
                        - PGID=2020
                        - TZ=America/Chicago
                volumes:
                        - /home/mediaman/docker-automatic-media-server/heimdall/config:/config
                network_mode: bridge
                ports:
                        - 81:80
                        - 444:443
                restart: unless-stopped

LetsEncrypt

For my case, I only wanted the subdomains to get an SSL certificate since I will eventually be hosting my own website through my main URL from a different machine

docker-compose.yml

version: '2'

services:
        letsencrypt:
                image: linuxserver/letsencrypt
                container_name: letsencrypt
                cap_add:
                        - NET_ADMIN
                environment:
                        - PUID=2020
                        - PGID=2020
                        - TZ=America/Chicago
                        - URL=[YOUR_DOMAIN]
                        - SUBDOMAINS=heimdall,jackett,ombi,plex,radarr,raneto,sonarr,tautulli,transmission
                        - VALIDATION=http
                        - EMAIL=[YOUR_EMAIL]
                        - ONLY_SUBDOMAINS=true
                volumes:
                        - /home/mediaman/docker-automatic-media-server/letsencrypt/config:/config
                network_mode: bridge
                ports:
                        - 80:80
                        - 443:443
                restart: unless-stopped

If you want the same thing as me (only using subdomains), you can leave the /home/mediaman/docker-automatic-media-server/letsencrypt/config/nginx/site-confs/default file as-is.

To configure your server with subdomains, head to /home/mediaman/docker-automatic-media-server/letsencrypt/config/nginx/proxy-confs/. You will see a bunch of sample files that are already written up for you to use. However, they are pre-configured for docker containers using host networking. Since we are using bridge networking, we will need to update these subdomain files. Here's an example of sonarr.subdomain.conf:

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name sonarr.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    location / {
        include /config/nginx/proxy.conf;
        proxy_pass http://127.0.0.1:8989;
    }

    location ~ (/sonarr)?/api {
        include /config/nginx/proxy.conf;
        proxy_pass http://127.0.0.1:8989;
   }
}

Wrapping Up

After you set up all your applications to communicate with eachother, you now have a completely automatic flow. From an Ombi movie request by a shared Plex user, to Sonarr/Radarr, to Jackett for indexing, back to Sonarr/Radarr, to Transmission for downloading, and straight into your library folders. You also have an awesome dashboard with Heimdall, you can set up the API key so that you can see an overview of your apps (Transmission leeching/seeding speed, Sonarr/Radarr queued movies) and direct links to those apps. Tautulli gives you analytics and live data on who's watching what, and also lets you send out weekly newsletters automatically of the recently added movies and TV shows.

Enjoy!

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