Files
ezarr/README.md
dtoro 194edc4223
Some checks failed
Check running / run (push) Has been cancelled
Add services-and-ports reference table to README
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.
2026-04-17 10:43:53 +02:00

270 lines
21 KiB
Markdown

# Ezarr
[![Check running](https://github.com/Luctia/ezarr/actions/workflows/check_running.yml/badge.svg)](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.