Some checks failed
Check running / run (push) Has been cancelled
Quick-lookup table grouping each service by category (-arr, indexers, downloaders, media servers, requests, dashboard, audiobooks) with the host-side port(s) mapped in the compose sample. Linked service names mirror the feature list above. Plex is called out as host-networked.
270 lines
21 KiB
Markdown
270 lines
21 KiB
Markdown
# Ezarr
|
|
[](https://github.com/Luctia/ezarr/actions/workflows/check_running.yml)
|
|
|
|
Ezarr is a project built to make it EZ to deploy a Servarr mediacenter on an Ubuntu server. The
|
|
badge above means that the shell script and docker-compose file in this repository at least *don't
|
|
crash*. It doesn't necessarily mean it will run well on your system ;)
|
|
It's set up to follow the [TRaSH guidelines](https://trash-guides.info/Hardlinks/How-to-setup-for/Docker/) so it should at least perform optimally. It features:
|
|
- [Sonarr](https://sonarr.tv/) is an application to manage TV shows. It is capable of keeping track
|
|
of what you'd like to watch, at what quality, in which language and more, and can find a place to
|
|
download this if connected to Prowlarr and qBittorrent. It can also reorganize the media you
|
|
already own in order to create a more uniformly formatted collection.
|
|
- [Radarr](https://radarr.video/) is like Sonarr, but for movies.
|
|
- [Bazarr](https://www.bazarr.media/) is a companion application to Sonarr and Radarr that manages
|
|
and downloads subtitles based on your requirements.
|
|
- [Lidarr](https://lidarr.audio/) is like Sonarr, but for music.
|
|
- [Mylar3](https://github.com/mylar3/mylar3) is like Sonarr, but for comic books. This one is a bit
|
|
tricky to set up, so do so at your own risk. In order to connect this to your Prowlarr container,
|
|
the process within Prowlarr is the same as for the other containers (add app). You'll have to add
|
|
an API key within Mylar3, yourself.
|
|
- [Audiobookshelf](https://www.audiobookshelf.org/) is a self-hosted audiobook and podcast server.
|
|
- [Homarr](https://homarr.dev/) is _a sleek, modern dashboard that puts all of your apps and services at your fingertips._
|
|
- [Prowlarr](https://wiki.servarr.com/prowlarr) can keep track of indexers, which are services that
|
|
keep track of Torrent or UseNet links. One can search an indexer for certain content and find a
|
|
where to download this. **Note**: when adding an indexer, please do not set the "seed ratio" to
|
|
less than 1. Less than 1 means that you upload less than you download. Not only is this
|
|
unfriendly towards your fellow users, but it can also get you banned from certain indexers.
|
|
- [Jackett](https://github.com/Jackett/Jackett) is an alternative to Prowlarr.
|
|
- [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr) is a proxy server to bypass Cloudflare and DDoS-GUARD protection.
|
|
- [qBittorrent](https://www.qbittorrent.org/) can download torrents and provides a bunch more
|
|
features for management.
|
|
- [SABnzbd](https://sabnzbd.org/) can download nzb's
|
|
features for management.
|
|
- [PleX](https://www.plex.tv/) is a mediaserver. Using this, you get access to a Netflix-like
|
|
interface across many devices like your laptop or computer, your phone, your TV and more. For
|
|
some features, you need a [PleX pass](https://www.plex.tv/nl/plex-pass/).
|
|
- [Tautulli](https://tautulli.com/) is a monitoring application for PleX which can keep track of
|
|
what has been watched, who watched it, when and where they watched it, and how it was watched.
|
|
- [Jellyfin](https://jellyfin.org/) is an alternative for PleX. Which you'd like to use is a matter
|
|
of preference, and you *could* even use both, although this is probably a waste of resources.
|
|
- [Overseerr](https://overseerr.dev/) is a show and movie request management and media discovery
|
|
tool.
|
|
- [Jellyseerr](https://github.com/Fallenbagel/jellyseerr) is like Overseerr, but for Jellyfin.
|
|
|
|
## Services and ports
|
|
Quick reference for the Web UIs exposed by each service. All ports are on your Docker host (reach them at `http://<your-host>:<port>`).
|
|
|
|
| Category | Service | Host port(s) | Notes |
|
|
| --------------- | ------------------------------------------- | ------------------------------------- | ------------------------------------------------- |
|
|
| -arr / manage | [Sonarr](https://sonarr.tv/) | `8989` | TV |
|
|
| -arr / manage | [Radarr](https://radarr.video/) | `7878` | Movies |
|
|
| -arr / manage | [Lidarr](https://lidarr.audio/) | `8686` | Music |
|
|
| -arr / manage | [Mylar3](https://github.com/mylar3/mylar3) | `8090` | Comics |
|
|
| -arr / manage | [Bazarr](https://www.bazarr.media/) | `6767` | Subtitles |
|
|
| -arr / manage | [Prowlarr](https://wiki.servarr.com/prowlarr) | `9696` | Indexer manager |
|
|
| Indexers | [Jackett](https://github.com/Jackett/Jackett) | `9117` | Alternative indexer manager |
|
|
| Cloudflare | [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr) | `8191` | Proxy for Cloudflare/DDoS-GUARD |
|
|
| Download | [qBittorrent](https://www.qbittorrent.org/) | `8080` (Web UI), `6881` TCP+UDP (BT) | Default save path: `/data/torrents` |
|
|
| Download | [SABnzbd](https://sabnzbd.org/) | `8081` → `8080` | See the SABnzbd note below about `inet_exposure` |
|
|
| Media server | [Plex](https://www.plex.tv/) | `32400` (host network) | Runs with `network_mode: host` |
|
|
| Media server | [Jellyfin](https://jellyfin.org/) | `8096` | |
|
|
| Monitoring | [Tautulli](https://tautulli.com/) | `8181` | Plex stats/monitoring |
|
|
| Requests | [Overseerr](https://overseerr.dev/) | `5055` | For Plex |
|
|
| Requests | [Jellyseerr](https://github.com/Fallenbagel/jellyseerr) | `5056` → `5055` | For Jellyfin |
|
|
| Dashboard | [Homarr](https://homarr.dev/) | `7575` | Dashboard for all of the above |
|
|
| Audiobooks | [Audiobookshelf](https://www.audiobookshelf.org/) | `13378` → `80` | Audiobooks + podcasts |
|
|
|
|
Adjust the left side of each `hostport:containerport` mapping in `docker-compose.yml` if any of these clash with something else on your host.
|
|
|
|
## Requirements
|
|
Currently, this script only works on Linux. There is a chance that the sample docker compose file will work on Windows,
|
|
although untested. The only requirements other than that are **Python 3** and **docker** with **docker-compose-v2**.
|
|
While this script _may_ work on docker-compose-v1 it's made to be and highly recommended to be run using v2.
|
|
The easiest way to install these dependencies on Ubuntu and other Debian-based distors is by running:
|
|
```
|
|
sudo apt-get install python3 docker.io docker-compose-v2
|
|
```
|
|
For other Linux distros you may have to use a different package manager or download directly from docker's website.
|
|
|
|
## Using
|
|
### Using the CLI
|
|
To make things easier, a CLI has been developed. First, clone the repository in a directory of your
|
|
choosing. You can run it by entering `python3 main.py` and the CLI will guide you through the
|
|
process. It will ask which services to enable, your timezone, your root directory, and — if you
|
|
want — independent absolute paths for your configs, downloads and media trees (press enter at each
|
|
prompt to keep the `ROOT_DIR`-based default). See [Storage layouts](#storage-layouts) below for the
|
|
trade-offs when splitting those.
|
|
This is the recommended method if you're setting this up for the first time on a new system.
|
|
Please take a look at [important notes](#important-notes) before you continue.
|
|
**NOTE: This script will create users for each container with IDs ranging from 13001 to 13014.
|
|
If you want to choose your own IDs (or some of them are occupied) you have to go through the manual install.**
|
|
|
|
### Manually
|
|
If you're installing this for the first time simply follow these steps.
|
|
If you're coming from an older version or reinstalling with different IDs, run `remove_old_users.sh` to clean up old users and then follow these steps.
|
|
1. To get started, clone the repository in a directory of your choosing. `git clone https://github.com/Luctia/ezarr.git`
|
|
2. Copy `.env.sample` to a real `.env` by running `$ cp .env.sample .env`.
|
|
3. Set the environment variables to your liking. Pay special attention `ROOT_DIR` as this is where everything is going to be stored in.
|
|
The path in this value needs to be **absolute**. If you leave it empty it's going to install in the directory the .env file is currently in.
|
|
`UID` should be set to the ID of the user that you want to run docker with. You can find this by running `id -u` from that user's shell.
|
|
If you want to spread configs, downloads and media across different locations (e.g. SSD for configs, bulk HDD for media), set `CONFIG_DIR`, `DOWNLOADS_DIR` and/or `MEDIA_DIR` to absolute paths. Any of them left empty fall back to `${ROOT_DIR}/config`, `${ROOT_DIR}/data` and `${ROOT_DIR}/data/media` respectively. **Note:** hardlinks/atomic moves between downloads and media only work when `DOWNLOADS_DIR` and `MEDIA_DIR` live on the same filesystem — split them only if you understand that you'll be copying instead of hardlinking.
|
|
|
|
The generated folder structure on the host looks like this (the three top-level trees can live under one `ROOT_DIR` or be spread across different drives via the `*_DIR` overrides):
|
|
```
|
|
${CONFIG_DIR}/ # default: ${ROOT_DIR}/config
|
|
├── sonarr-config/
|
|
├── radarr-config/
|
|
├── lidarr-config/
|
|
├── mylar-config/
|
|
├── prowlarr-config/
|
|
├── jackett-config/
|
|
├── qbittorrent-config/
|
|
├── sabnzbd-config/
|
|
├── bazarr-config/
|
|
├── overseerr-config/
|
|
├── jellyseerr-config/
|
|
├── plex-config/
|
|
├── jellyfin-config/
|
|
├── tautulli-config/
|
|
└── audiobookshelf-config/
|
|
|
|
${DOWNLOADS_DIR}/ # default: ${ROOT_DIR}/data
|
|
├── torrents/ # qBittorrent save path
|
|
│ ├── tv/
|
|
│ ├── movies/
|
|
│ ├── music/
|
|
│ ├── comics/
|
|
│ └── ...
|
|
└── usenet/ # SABnzbd complete/incomplete
|
|
├── tv/
|
|
├── movies/
|
|
├── music/
|
|
├── comics/
|
|
└── ...
|
|
|
|
${MEDIA_DIR}/ # default: ${ROOT_DIR}/data/media
|
|
├── tv/ # Sonarr
|
|
├── movies/ # Radarr
|
|
├── music/ # Lidarr
|
|
├── comics/ # Mylar3
|
|
├── books/
|
|
├── audiobooks/ # Audiobookshelf
|
|
├── podcasts/ # Audiobookshelf
|
|
└── audiobookshelf-metadata/
|
|
```
|
|
Inside the -arr containers these are always exposed under a single `/data` tree — `/data/torrents`, `/data/usenet`, `/data/media/{tv,movies,...}` — regardless of how the host paths are split. This preserves the TRaSH single-`/data`-mount pattern and keeps hardlinks working as long as `DOWNLOADS_DIR` and `MEDIA_DIR` share a filesystem. The compose file achieves this by binding `${DOWNLOADS_DIR}:/data` as the parent and overlaying `${MEDIA_DIR}:/data/media` on top.
|
|
4. Run `setup.sh` as superuser. This will set up your users, a system of directories and ensure permissions are set correctly.
|
|
5. Copy `docker-compose.yml.sample` to a real `docker-compose.yml` by running `$ cp docker-compose.yml.sample docker-compose.yml`.
|
|
6. Take a look at the `docker-compose.yml` file. If there are services you would like to ignore
|
|
(for example, running PleX and Jellyfin at the same time is a bit unusual), you can comment them
|
|
out by placing `#` in front of the lines. This ensures they are ignored by Docker compose.
|
|
Double check that your .env file is set up properly. Also make sure to add a newly generated encryption key to the
|
|
Homarr section, if you want to use it.
|
|
7. Run `docker compose up -d` to start the containers. If it complains about permissions run the following commands to add your current user to the docker group and apply changes:
|
|
```
|
|
sudo groupadd docker
|
|
sudo usermod -aG docker $USER
|
|
newgrp docker
|
|
```
|
|
If it still doesn't work reboot your system.
|
|
|
|
That's it! Your containers are now up and you can continue to set up the settings in them. Please
|
|
take a look at [important notes](#important-notes) before you continue.
|
|
|
|
## Storage layouts
|
|
The -arr services use **hardlinks** to move downloaded files from `torrents/` or `usenet/` into the
|
|
media library without duplicating bytes. Hardlinks only work within a single filesystem — so
|
|
`DOWNLOADS_DIR` and `MEDIA_DIR` must resolve to paths on the same filesystem for this to work. If
|
|
they don't, Sonarr/Radarr/Lidarr/Mylar will silently fall back to copying, which uses twice the
|
|
disk space and a lot more I/O on every import. `CONFIG_DIR` has no such constraint and can live
|
|
anywhere.
|
|
|
|
Some layouts that work well:
|
|
|
|
- **Single-drive / single-filesystem (simplest).** Set `ROOT_DIR` and leave `CONFIG_DIR`,
|
|
`DOWNLOADS_DIR`, `MEDIA_DIR` empty. Everything lives under one tree, hardlinks just work.
|
|
- **SSD for configs, HDD for everything else.** Set `CONFIG_DIR=/ssd/ezarr/config` and leave the
|
|
other two empty (they default under `ROOT_DIR`, which you point at the HDD). Config databases
|
|
benefit from the faster disk; downloads + media stay together so hardlinks work.
|
|
- **Pooled storage with [mergerfs](https://github.com/trapexit/mergerfs).** Combine multiple
|
|
HDDs into one mount point (e.g. `/pool`) and point `ROOT_DIR` or `DOWNLOADS_DIR`+`MEDIA_DIR` at
|
|
it. With `category.create=epmfs` and `moveonenospc=true`, mergerfs keeps a torrent and its
|
|
hardlinked media file on the same underlying disk, so `link(2)` succeeds inside the pool.
|
|
- **CoW filesystems (btrfs / xfs with reflink / bcachefs / ZFS).** Same-filesystem rule still
|
|
applies, but you also get reflinks (instant, space-sharing copies) as a fallback when hardlinks
|
|
aren't appropriate.
|
|
|
|
Layouts that will **break hardlinks** (they will still run, just less efficiently):
|
|
- `DOWNLOADS_DIR` on one drive/mount and `MEDIA_DIR` on a different drive/mount.
|
|
- Downloads on local disk, media on a remote NFS/SMB share (or vice versa).
|
|
- Either path going through a union filesystem that doesn't co-locate related files.
|
|
|
|
If you genuinely need split storage and can't pool it, set "Use Hardlinks" to `false` in each -arr
|
|
and accept the copy overhead.
|
|
|
|
Regardless of how you split the host paths, the compose file always exposes a single `/data` tree
|
|
inside the -arr containers — `/data/torrents`, `/data/usenet`, `/data/media/{tv,movies,...}` — so
|
|
the root-folder paths you configure in Sonarr/Radarr/etc. never need to change.
|
|
|
|
## Important notes
|
|
- You probably shouldn't run the python script as root. Ideally you should create a brand new user that's just for these services, but any regular user will do.
|
|
It will need your password for `sudo` to set up the permissions and folder structures, but you shouldn't run it *as* root.
|
|
- If you already used this script previously and want to clean up old users, run `remove_old_users.sh`.
|
|
This is also recommended if you are updating from an earlier version of this script, since there were previously some conflicts in user IDs.
|
|
- It is recommended to restart your system after script completion, so that newly created users and groups can be loaded properly.
|
|
- When linking one service to another, remember to use the container name instead of `localhost`.
|
|
- Please set the settings of the -arr containers as soon as possible to the following (use
|
|
advanced):
|
|
- Media management:
|
|
- Use hardlinks instead of Copy: `true`
|
|
- Root folder: `/data/media/` and then tv, movies or music depending on service
|
|
- qBittorrent ships with a default username `admin` and a one-time password that can be viewed by running `docker logs qbittorrent`.
|
|
- Make sure to set a username and password for all servarr services and qBittorrent!
|
|
- In qBittorrent, after connecting it to the -arr services, you can indicate it should move
|
|
torrents in certain categories to certain directories, like torrents in the `radarr` category
|
|
to `/data/torrents/movies`. You should do this. Also set the `Default Save Path` to
|
|
`/data/torrents`. Set "Run external program on torrent completion" to true and enter this in the
|
|
field: `chmod -R 775 "%F/"`.
|
|
- You'll have to add indexers in Prowlarr by hand. Use Prowlarrs settings to connect it to the
|
|
other -arr apps.
|
|
|
|
### IMPORTANT IF USING NFS SHARES
|
|
- NFS shares' permissions are mapped by user IDs. If you want to access a file as a client, your user ID needs to match the user ID of the owner (or group) of that file on the NFS server.
|
|
Note that if you are a group member (and not the owner), having matching group IDs won't be enough, there also needs to be a corresponding user on the NFS server. The easiest way to make sure
|
|
the users and groups are set up on both sides correctly is to run `setup.sh` on both your NFS server and your client.
|
|
On your server:
|
|
- Copy `.env` and `setup.sh` to your NFS server.
|
|
- You may have to adjust `.env` so that `ROOT_DIR` (and `CONFIG_DIR` / `DOWNLOADS_DIR` / `MEDIA_DIR`, if you've set any of them) reflect where each tree will be stored on your server, which is most likely different from the mapped location on the client.
|
|
- Make sure that the `.env` file is not a .sample. Run `setup.sh`.
|
|
- Now follow all the same steps but on your client machine. Always double-check that `.env` is set correctly, especially the path variables above.
|
|
You don't have to do this on your server first but it's recommended. If you are running this script on the client **make sure that you temporarily enable -no-root-squash on your NFS server**,
|
|
as the script needs superuser privileges to run and by default on NFS the root user is mapped to nowhere to prevent abuse.
|
|
|
|
**Heads-up on hardlinks over NFS:** if your downloads live on the local disk but media lives on an NFS mount (or vice versa), that's two different filesystems and hardlinks will break — see [Storage layouts](#storage-layouts) for the options. Keeping `DOWNLOADS_DIR` and `MEDIA_DIR` both on the NFS mount is fine, as long as they share the same share/filesystem.
|
|
|
|
### SABnzbd External internet access denied message
|
|
When you're trying to access SABnzbd the first time you'll come across the message `External
|
|
internet access denied`. To fix this simple modify the `sabnzbd.ini` and change `inet_exposure` to
|
|
`4`, restart the docker container for sabnzbd (`docker restart sabnzbd`) and now you can access the
|
|
UI of SABnzbd (note: you may get a `Access denied - Hostname verification failed`, to fix this,
|
|
simply go to the IP of your server directly instead of the hostname). After accessing the UI don't
|
|
forget to set a username and password (https://sabnzbd.org/wiki/configuration/3.7/general,
|
|
section Security).
|
|
|
|
For more instructions or help see also https://sabnzbd.org/wiki/extra/access-denied.html on the
|
|
official SABnzbd website.
|
|
|
|
## FAQ
|
|
|
|
### How to update containers
|
|
There is an `update_containers.sh` script that takes care of this. Simply run it and it updates
|
|
all containers and removes old images. If you want to keep them, simply comment out the last line of the script.
|
|
It's essentially the following steps but automated:
|
|
If you'd like to it manually, go to the directory of your `docker-compose.yml` file
|
|
and run `(sudo) docker compose pull`. This pulls the newest versions of all images (blueprints for
|
|
containers) listed in the `docker-compose.yml` file. Then, you can run `(sudo) docker compose up
|
|
-d`. This will deploy the new versions without losing uptime. Afterwards, you can run `(sudo)
|
|
docker image prune` to remove the old images, freeing up space.
|
|
|
|
### Why do I need to set some settings myself, can that be added?
|
|
Some settings, particularly for the Servarr suite, are set in databases. While it *might* be
|
|
possible to interact with this database after creation, I'd rather not touch these. It's not
|
|
that difficult to set them yourself, and quite difficult to do it automatically. For other
|
|
containers, configuration files are automatically generated, so these are more easily edited,
|
|
but I currently don't believe this is worth the effort.
|
|
|
|
On top of the above, connecting the containers above would mean setting a password and creating an
|
|
API key for all of them. This would lead to everyone using Ezarr having the same API key and user/
|
|
password combination. Personally, I'd rather trust users to figure this out on their own rather
|
|
than trusting them to change these passwords and keys.
|