- Notifications
You must be signed in to change notification settings - Fork42
ghostserverd/mediaserver-docker
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
- Automated Media Server 👻
_ _ __ _| |__ ___ ___| |_ / _` | '_ \ / _ \/ __| __/ | (_| | | | | (_) \__ \ |_ \__, |_| |_|\___/|___/\__| |___/ / _ \ (¯\| o (@) |/¯) \_ .___. _/ / !_! \ /_.--._.--._\This is an automated media server set up in docker containers via docker-compose. The goal of this project is to automate as much of the installation and configuration as possible while maintaining simplicity of the setup (no ansible playbooks or fancy bash scripts) to avoid making it a complete black box.
The end result of this setup is a media server with the following components
plexfilebot- with a web interface for triggering
amcscript
- with a web interface for triggering
transmission- configured to call
filebotcontainer on torrent completion - with
combustionweb UI
- configured to call
nzbget- configured to call
filebotcontainer on nzb completion
- configured to call
sonarrradarrjackettbazarrtautulli- configured to look at plex server logs
portainerwatchtowernginx + letsencrypt- for reverse proxying to reach your services at *.domain.tld
heimdall
The high-level steps for setup are as follows
- Install docker and docker-compose
docker-compose up- add an indexer to
jackett - configure
sonarr/radarrto use thejackettindexer - configure
sonarr/radarrto use annzbindexer - configure
sonarr/radarrto usetransmissionas their download client - configure
sonarr/radarrto usenzbgetas their nzb client - configure
nzbgetwith your newsgroup provider - add libraries to
plex
Once these steps have been completed, it is possible to add a TV Show or Movie tosonarr /radarr, have it automatically download them when available, and then it will be automatically copied into yourplex libraries. Post-installation, this should be a fully-automated media server. Thetransmission container will automatically clean any files older than 30 days (configurable).
📓 This has only been tested on Ubuntu 18.04 LTS but it should work just fine on other linux distros. MacOS and Windows are unsupported. If you test it on MacOS or Windows and it works, let me know!
I've removed the cofiguration forqbittorrent. If you want to keep using it, feel free to search through git history to recover the configuration, but it's no longer supported and has not been updated to use the newfilebot container.
Each service is available on its own ports:
| Service | Port |
|---|---|
| transmission | 5656 |
| nzbget | 6789 |
| filebot | 7676 |
| sonarr | 8989 |
| radarr | 7878 |
| bazarr | 6767 |
| jackett | 9117 |
| plex | 32400 |
| portainer | 9000 |
| heimdall | 8888 |
| netdata | 19999 |
📓To reachplex, append/web to the address e.g.192.168.1.11:32400/web
All of the services are running in the default docker-compose network. From within services, they can access each other via their<service_name>:<port> as defined indocker-compose.yml. These areNOT the ports you've configured in your.env file. Those ports are mapped to the host device's network, but the services are operating within the network that docker-compose sets up, so they will not respect the rules forwarding ports to the host network.
| Service | Port |
|---|---|
| transmission | 5656 |
| nzbget | 6789 |
| filebot | 7676 |
| sonarr | 8989 |
| radarr | 7878 |
| bazarr | 6767 |
| jackett | 9117 |
| plex | 32400 |
| tautulli | 8181 |
| heimdall | 80 |
| netdata | 19999 |
git clone https://github.com/ghostserverd/mediaserver-docker.gitcd mediaserver-dockercp .env_sample .envid$USER# save the result of this for building your .env file below
Modify the.env file to specify the directory configurations. Note that these directories are for the host machine. They are mapped to various locations inside of their container by thedocker-compose file.
The.env_sample file has some notes about the various configuration options. There are additional descriptions of each service's configuration below.
A good directory setup looks something like this
CONFIG_DIR=/some/directory/media_server/configDOWNLOAD_DIR=/some/directory/media_server/downloadsMEDIA_DIR=/some/directory/media_server/mediaTV_DIR=/some/directory/media_server/media/TV ShowsMOVIES_DIR=/some/directory/media_server/media/MoviesBASE_DIR=/some/directory/media_server
Note that there is a base volume mount that holds bothmedia anddownloads
/some/directory/media_server
Configuring a single mount that contains bothdownloads andmedia allowsfilebot to take advantage ofhardlinks when renaming and moving files. Hardlinks are much quicker than actually copying the file, but they require that the source and destination be on the same volume in order to work.
| variable | description |
|---|---|
| CONFIG_DIR | where configuration for each of the services will live. You'll end up with multiple directories in here, one for each service. If you move this directory to a different volume with a different instance of the whole media server, it should retain your various configurations. |
| DOWNLOAD_DIR | where various services will download files to. |
| MEDIA_DIR | where your media will be copied to. |
| TV_DIR | where your TV shows will be placed byfilebot on download completion. It should be a subdirectory ofMEDIA_DIR |
| MOVIES_DIR | where your TV shows will be placed byfilebot on download completion. It should be a subdirectory ofMEDIA_DIR |
| BASE_DIR | a shared directory that housesmedia anddownloads directories to be used for hardlinks |
| variable | description |
|---|---|
| PUID | the unixUID that will be passed to the various services. It can be discovered by runningid $USER on the host machine. |
| PGID | is the unixGID that will be passed to the various services. It can be discovered by runningid $USER on the host machine. |
Fill out the rest of the configuration options before deploying. See each individual service's section for configuration details.
docker-compose up
Append-d to run in detached mode. The first time you run a service, it is probably a good idea to not run in dettached mode (i.e. DON'T append-d) so you can watch all of the logs for issues.
| variable | description |
|---|---|
| JACKETT_PORT | the port that jacket will listen on |
<server-ip>:9117
jackett should be configurable the same as any other installation of it. Feel free to skip these steps if you know how to configurejackett already.
- Add an Indexer
- Click
+ Add Indexer - Search for your desired tracker
- Click on the 🔧icon next to your desired tracker
- Sign in with your account information
- Click
Okay
- Click
- You should see
Successfully configured <tracker>and a new entry for your tracker - Copy the
API Keyfrom the top right corner and save it somewhere - Click the
Copy Torznab Feedon the tracker you just added and paste it somewhere to save it
| variable | description |
|---|---|
| SONARR_PORT | the port that sonarr will listen on |
<server-ip>:8989
sonarr should be configurable the same as any other installation of it. Feel free to skip these steps if you know how to configuresonarr already.
transmission instead of the IP address when configuring the download client, as well asjackett instead of the IP when setting up your indexer. This is because this uses docker-compose networking which means each service is accessible at the name of the service, rather than the host or even local IP address.
Step-by-step for those who need it
Add an Indexer
- Click on the
Settingsbutton at the top - Click on the
Indexerstab - Click the big
+symbol - Click the
Custombutton in theTorznabsection - Configure your
TorznabfeedName: the name of this indexer (doesn't matter, just name it the name of your tracker)URL: theCopy Torznab Feedurl fromjackettthat you saved earlier⚠️ It is necessary to replace the IP withjacketthttp://jackett:9117/api/v2.0/indexers/<indexer>/results/torznab/instead ofhttp://192.168.1.11:9117/api/v2.0/indexers/<indexer>/results/torznab/
API Key: theAPI Keyfromjackettthat you saved earlier
- Click
Testto verify that it is configured properly - Click
Save
- Click on the
Add a Download Client
- Click on the
Settingsbutton at the top - Click on the
Download Clienttab - Under
Completed Download HandlingtoggleEnablefrom Yes to No- We'll be using
filebotto handle our completed downloads
- We'll be using
- Click the
Savebutton at the top right - Click the large
+button - Click on
transmission - Configure your Download Client
Name: whatever you want; probablytransmissionHost:transmissionPort:5656or whatever you have set forTRANS_WEBUI_PORTin your.envfileUsername:adminor whatever you have set forTRANS_WEBUI_USERin your.envfilePassword:adminadminor whatever you have set forTRANS_WEBUI_PASSin your.envfileCategory:sonarr- this allows transmission GC to properly remove torrents after seed limits exceeds
- Click
Testto verify that it is configured properly - Click
Save
- Click on the
Add Some TV Shows
- Click on the
Seriesbutton at the top - Click
+ Add Series - Start typing in the search bar. It will search automatically when you stop typing
- Configure the download path (you should only have to do this on the first show you add)
- Click the dropdown that says
Select Path - Click
Add a different path - Click the 📁button on the right of the modal
- Click
tv# final path should be/tv/ - Click
Ok - Click the green ✔️that is now visible
- Click the
+sign
- Click the dropdown that says
- Click on the
There are many other configuration options for
sonarrthat are not covered here.sonarr's webpage ishere
| variable | description |
|---|---|
| RADARR_PORT | the port that radarr will listen on |
<server-ip>:7878
radarr should be configurable the same as any other installation of it. Feel free to skip these steps if you know how to configureradarr already.
transmission instead of the IP address when configuring the download client, as well asjackett instead of the IP when setting up your indexer. This is because this uses docker-compose networking which means each service is accessible at the name of the service, rather than the host or even local IP address.
Step-by-step for those who need it
Add an Indexer
- Click on the
Settingsbutton at the top - Click on the
Indexerstab - Click the big
+symbol - Click the
Custombutton in theTorznabsection - Configure your
TorznabfeedName: the name of this indexer (doesn't matter, just name it the name of your tracker)URL: theCopy Torznab Feedurl fromjackettthat you saved earlier⚠️ It is necessary to replace the IP withjacketthttp://jackett:9117/api/v2.0/indexers/<indexer>/results/torznab/instead ofhttp://192.168.1.11:9117/api/v2.0/indexers/<indexer>/results/torznab/
API Key: theAPI KeyfromJackettthat you saved earlier
- Click
Testto verify that it is configured properly - Click
Save
- Click on the
Add a Download Client
- Click on the
Settingsbutton at the top - Click on the
Download Clienttab - Under
Completed Download HandlingtoggleEnablefrom Yes to No- We'll be using
filebotto handle our completed downloads
- We'll be using
- Click the
Savebutton at the top right - Click the large
+button - Click on
transmission - Configure your Download Client
Name: whatever you want; probablytransmissionHost:transmissionPort:5656or whatever you have set forTRANS_WEBUI_PORTin your.envfileUsername:adminor whatever you have set forTRANS_WEBUI_USERin your.envfilePassword:adminadminor whatever you have set forTRANS_WEBUI_PASSin your.envfileCategory:radarr- this allows transmission GC to properly remove torrents after seed limits exceeds
- Click
Testto verify that it is configured properly - Click
Save
- Click on the
Add Some Movies
- Click on the
Add Moviesbutton at the top - Start typing in the search bar. It will search automatically when you stop typing
- Configure the download path (you should only have to do this on the first movie you add)
- Click the dropdown that says
Select Path - Click
Add a different path - Click the 📁button on the right of the modal
- Click
movies# final path should be/movies/ - Click
Ok - Click the green ✔️that is now visible
- Click the
+sign
- Click the dropdown that says
- Click on the
There are many other configuration options for
radarrthat are not covered here.radarr's webpage ishere
| variable | description |
|---|---|
| BAZARR_PORT | the port that bazar will listen on |
<server-ip>:6767
bazarr should be configurable the same as any other installation of it. Feel free to skip these steps if you know how to configurebazarr already.
Step-by-step for those who need it
Configure connection settings for Sonarr:
Hostname or IP Address:sonarrListening Port:8989or whatever you have set forSONARR_PORTin your.envfileAPI Key: theAPI KeyfromSonarr
Configure connection settings for Radarr:
Hostname or IP Address:radarrListening Port:7878or whatever you have set forRADARR_PORTin your.envfileAPI Key: theAPI KeyfromRadarr
<server-ip>:7676
| variable | description |
|---|---|
| FILEBOT_PORT | the web interface port for the filebot container |
| FILEBOT_FORMAT | the filebotformat expression to use |
| FILEBOT_ACTION | theaction for filebot to take when renaming files |
| FILEBOT_CONFLICT | what filebot does when it sees a conflicting filename |
| FILEBOT_SERIES_DB | the database to use for TV metadata lookup |
| FILEBOT_ANIME_DB | the database to use for anime metadata lookup |
| FILEBOT_MOVIE_DB | the database to use for movie metadata lookup |
| FILEBOT_MUSIC_DB | the database to use for music metadata lookup |
| OPEN_SUB_USER | the opensubtitles username for filebot to use when downloading subtitles [NOT FUNCTIONAL] |
| OPEN_SUB_PASS | the opensubtitles password for filebot to use when downloading subtitles [NOT FUNCTIONAL] |
The opensubtitles configuration is called by the container startup script, but opensubtitles still fails when filebot is actually run. Until I figure out how to make this work, stick tobazarr.
You can navigate to<server-ip>:7676 to see the filebot command that will be run when a download is completed. Do NOT expose this port to the internet as it is not password protected.
These are thefilebot CLI options:https://www.filebot.net/cli.html. If there are additional options you want to be able to configure, open an issue.
4.9.x version offilebot by default. In order to properly register after you have purchased a license, copy yourlicense.psm file to the filebot config directory on your host machine. The container will automatically registerfilebot with that license.
| variable | description |
|---|---|
| TRANS_WEBUI_USER | the username with which to log into transmission |
| TRANS_WEBUI_PASS | the password with which to log into transmission |
| TRANS_WEBUI_PORT | the port for transmission's web interface |
| TRANS_CONNECTION_PORT | the connection port for tranmission to use |
| TRANS_MAX_RETENTION | the time in seconds before a torrent is automatically removed |
| TRANS_MAX_RATIO | the ratio at which a torrent is automatically removed |
<server-ip>:5656
It should not be necessary to configure transmission beyond the default configuration. The container writes a config with reasonable defaults. If you need access to additional transmission settings, feel free to open an issue.
The container is already automatically configured to callfilebot to post-process a download.
<server-ip:7890
| variable | description |
|---|---|
| NZBGET_PORT | the web interface port for nzbget |
The container is already automatically configured to callfilebot to post-process a download.
These are the automatic configurations innzbget now:
- The
MainDirwill automatically be set to/downloads/nzb - The
ScriptDirwill automatically be set to/usr/local/bin - The
Extensionswill automatically be set tonzbget-postprocess.sh - The
ControlUsernamewill automatically be set to whatever is configured inNZBGET_WEB_USERiff it is set - The
ControlPasswordwill automatically be set to whatever is configured inNZBGET_WEB_PASSiff it is set
The paths are configured that way to support callingfilebot with the post-process script.
Seethe documentation for instructions on setting up the rest ofnzbget.
The first time that you set up your plex server, you will need to claim the server to associate it with your plex account. You need to access the server vialocalhost or127.0.0.1 in order to claim it. The easiest way to accomplish this is to create an SSH tunnel to your server so you can access plex on port 32400 on localhost.
ssh <server-ip> -L 32400:localhost:32400Once you do this, you can now log into plex vialocalhost:32400/web or127.0.0.1:32400/web and claim the server. Once the server has been claimed, you can log into it directly via the server's IP address.
| variable | description |
|---|---|
| PLUGIN_LIST | a list of plugins to install. supported plugins aretrakt andsubzero. leave empty to install no plugins |
| PLEX_WEB_PORT | the port for the plex web interface |
<server-ip>:32400/web
- Add some libraries
- TV Shows will be at
/data/TV Showsassuming you followed the/media/TV Showsconvention forTV_DIR - Movies will be at
/data/Moviesassuming you followed the/media/Moviesconvention forMOVIES_DIR
- TV Shows will be at
⚠️ If you don't useBazarrset up your media agents to not use local files (hopefully this will be fixed in the future)- There is a problem that I have not been able to fix yet where local TV Series art is not available. It appears the artwork downloaded by
filebotis not readable byplexfor an unkown reason (I don't believe it's permissions related, but if you have ideas, please open an issue). - To get around this, uncheck
Local Media Assetsfor all Agents underSettings>Server>Agents. Artwork will be downloaded by plex and accessible.
- There is a problem that I have not been able to fix yet where local TV Series art is not available. It appears the artwork downloaded by
- Kill and restart the containers after logging in to Plex if you have Plexpass
docker stop plexdocker-compose up -d plex
The compose file includes a letsencrypt container which you can use to set up a reverse proxy to various services which will automatically provision an SSL certificate for you to use. If you do not want to use a reverse proxy, simply delete that entry from the compose file.
I recommend that you launch the full mediaserver once without the reverse proxy enabled so you can set up authentication forsonarr,radarr,bazarr,nzbget,tautulli,netdata, andheimdall
The reverse proxy is configured to use subdomain routing by default. It copies in appropriate configurations for each service with these names
| service | config name |
|---|---|
| sonarr | s.subdomain.conf |
| radarr | r.subdomain.conf |
| transmission | t.subdomain.conf |
| nzbget | n.subdomain.conf |
| plex | p.subdomain.conf |
| tautulli | u.subdomain.conf |
| netdata | m.subdomain.conf |
| heimdall | h.subdomain.conf |
| bazarr | b.subdomain.conf |
Config files for each subdomain will be present in theconfig directory on your host machine if you wish to change the configurations. The directory isconfig/letsencrypt/nginx/proxy-confs. If you wish to use different subdomains (e.g.plex.domain.tld instead ofp.domain.tld) you need to change the configuration for the subdomain in that directory, and update theLE_SUBDOMAINS to include the new subdomain.
Note that the first time you run the letsencrypt container, it can take some time for it to register an SSL cert.
| variable | description |
|---|---|
| LE_HOSTNAME | the hostname you are using to host the reverse proxy |
| LE_EMAIL | the email for which your letsencrypt SSL cert will be registered |
| LE_SUBDOMAINS | the subdomains for which to register the SSL cert |
I have built a wireguard container following the principles describedhere and have successfully tested using docker-compose to force all traffic fornzbget through the wireguard VPN using a config fromhttp://mullvad.net/.
Download or build a wireguard config file from your VPN provider. For example, mullvad has a wireguard config generator athttps://mullvad.net/en/download/wireguard-config/. Once you have the config file (e.g. mine is calledwgnet0.conf, copy that file into your config/wireguard directory. The container will automatically find the config file and build the VPN network for you.
wireguard config file. This will disallow traffic from the docker network which will make it inaccessible from the reverse proxy container. There is a rudimentary killswitch implemented in thewireguard container already. I may improve this over time.
docker-compose.yml has been updated with a commented out wireguard service. There is also a commented outnzbget service configured to use the wireguard container's network as an example. This will forcenzbget to proxy all traffic through thewireguard container, and thus through the VPN. You can follow the same pattern with thetransmission container, or evensonarr andradarr if you want all queries to torrent trackers to go through the VPN.
To proxy an additional container through thewireguard container's network, add the service name (e.g.transmission) to the list of network aliases defined in thewireguard service.
networks:default:aliases: -nzbget -transmission
Then update the new service's definition (e.g.transmission) to remove the port mapping list, and add
network_mode:"service:wireguard"depends_on: -wireguard
Because thewireguard has an alias totransmission, it is now accessible ontransmission:5656 just like it was before. You will also want to add the port mapping that were originally in thetransmission service definition to thewireguard service definition.
Thewireguard container now has a proper route back to the local network overeth0 so services that are using thewireguard network should now be accessible via your local subnet. You need to specify this subnet in theLOCAL_NETWORK environment variable. Thanks tohtilly andcmulk who's containers I shamelessly copied and modified. Once you have set up the route back to the local subnet, you can properly port foward through the VPN. Seehttps://mullvad.net/en/help/port-forwarding-and-mullvad/ for details on port forwarding withmullvad.
Mountingdocker.sock is normally an anti-pattern for containers. However, when thewireguard container is started,wg-quick rewrites/etc/resolv.conf with the DNS address specified in the interface's.conf file. This breaks DNS resolution for docker services from within any container that is using thewireguard container as its network. In practice, this means that from within e.g. thetransmission ornzbget containers,curl filebot:7676 will fail DNS resolution. This breaks the auto-config between downlaoders andfilebot.
To work around this issue, thewireguard container now inspects the network (docker network inspect mediaserver-docker_default) and writes/etc/hosts entries for each service it finds in the network. This means that if one of your service IPs changes for any reason, you'll need to restart thewireguard container in order to be able to properly resolve DNS for docker services again.
I believe it is possible to fix this issue usingdnsmasq instead of writing/etc/hosts which would remove the requirement to read fromdocker.sock, but I have not been able to get it to work, so I'm leaving this hack in place for now.
If you do not mountdocker.sock, thewireguard container will still run, but any containers in thewireguard network will be unable to resolve DNS for other docker services. If that's fine with you, you don't need to mountdocker.sock.
Thewireguard container has been updated to usednsmasq to conditionally route DNS requests.
The container also now scrapes the wireguard interface file for its DNS server and write /etc/dnsmasq.conf with that as the final fallback DNS address.
There are now three options for enabling docker DNS resolution from within the wireguard container:
If
docker.sockis mounted, write/etc/hostswith any service in the network (this is really just for backwards comptability and is the same behavior as described above.)If
LOCAL_TLDis set (e.g. to local) write/etc/dnsmasq.confto use127.0.0.11for that TLD. Also, write/etc/resolv.confto searchLOCAL_TLDso that containers can access the addresses of the services without having to know to append.localto match the rule in/etc/dnsmasq.conf. This will require aliases with the TLD in each of the containers that need to be accessible from within the wireguard network. An alias should look something like this (e.g. forLOCAL_TLD=ghost).filebot:image:ghostserverd/filebot:4.9.xcontainer_name:filebotrestart:alwaysnetworks:default:aliases: -filebot.ghost
which will result in
filebotbeing accessible from containers within thewireguardnetwork.If
SERVICE_NAMESis set (a list of services to make available from within the wireguard network), write each service name individually to/etc/dnsmasq.confto force127.0.0.11as the DNS server for each service address. This is nice because you don't have to write an alias for each service to make available, but you do need to list out all of the services. A sampleSERVICE_NAMESvariable is set in thedocker-compose.ymlfile. It shouldn't need to be modified, but if there is a reason to, open an issue and I can make it pull from the.envfile.
The last three settings are mutually exclusive. Only one of the mechanisms should be used. Of the last two, I'm not really sure which one I prefer, but they're both better than mounting docker.sock in my opinion.
Most of these containers are config wrappers aroundLinuxServer.io containers. Without their amazing linuxserver containers, none of this would have been possible. If you find this automated media server useful, go donate to them! They probably deserve it more than I do.
- forum.linuxserver.io
- IRC on freenode at
#linuxserver.io - Podcast covers everything to do with getting the most from your Linux Server plus a focus on all things Docker and containerisation!
- Donate
This would also not be possible without filebot. This has been updated to use the latest4.9.x version of filebot. It supports automatic registration as long as you provide a license file.
Thanks to patorjk for hisascii text generator
Thanks tosecretmapper for thecombustion UI fortransmission
If you really want to donate to me, you can do that here
- Consider switching from
nginxtotraefik - Auto-configuration for linking
radarrandsonarrtotransmission - Auto-configuration for linking
radarrandsonarrtonzbget - Auto-configuration for
plexlibraries - Improve documentation (maybe blog post with pictures)
Better configuration options fornzbgetWireguard as a network container for downloadersAdditional containers (tautulli,muximux,portainer)Add reverse proxy support (traefik?)Upgradefilebotto4.8.2and make it easy to license
About
Docker compose for comprehensive autonomous media server
Resources
Uh oh!
There was an error while loading.Please reload this page.
