Ezarr sets up a Servarr media stack with Docker
Ezarr aims to make it as easy as possible to setup an entire Servarr/Jackett/BitTorrent/Usenet/PleX/Jellyfin mediacenter stack using Docker
At a glance
- What is it?
- Ezarr is a Python and shell toolkit that takes a fresh Ubuntu server and produces a running Sonarr, Radarr, Prowlarr, Plex or Jellyfin stack in Docker, handling the parts that are tedious rather than the parts that are hard: host user IDs, directory layout, permissions and a sample compose file. It is a deployment script, not a media server, and its own badge says the configuration only has to not crash.
- Who is it for?
- Ezarr suits a person standing in front of a blank Ubuntu server who wants the standard media stack running tonight rather than this weekend, and who is willing to edit a compose file afterwards. It is the wrong tool for someone who wants one container, for a media server other than the Servarr family, and for a machine that is not a dedicated Linux host.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 73 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A deployment script, not a media server
The project description says it plainly. Ezarr aims to make it as easy as possible to set up an entire Servarr, Jackett, BitTorrent, Usenet, Plex and Jellyfin media centre stack using Docker.
So the deliverable is a running stack, and the thing being packaged is the deployment. That is a narrower and more honest framing than most projects in this space, where a compose file and a wiki page are presented as a product. Here the repository contains a Python CLI, several shell scripts, a Python module describing the container configuration, an environment sample and a compose sample, and those scripts do the parts of the job that are repetitive.
The stack it assembles is large. On the automation side there is Sonarr for television, Radarr for films, Lidarr for music, Bazarr for subtitles, Mylar3 for comics, Audiobookshelf for audiobooks and podcasts, and Sportarr for sports broadcasts. On the indexer side there is Prowlarr and, as an alternative to it, Jackett, with qBittorrent for torrents and SABnzbd for Usenet. On the serving side there is Plex and, as an alternative, Jellyfin, plus Tautulli for Plex statistics. Homarr is a dashboard for all of it, and Overseerr and Jellyseerr handle user requests.
The configuration follows the TRaSH guidelines for hardlinks in Docker, which the README says means it should at least perform optimally. The hardlink layout is the reason a stack like this is worth automating properly, since a wrong layout means every file exists twice on disk.
The audience is someone setting up a home server, and the requirements are correspondingly narrow: Linux, Python 3, and Docker with docker-compose-v2.
The CLI guides a first install, the manual path gives control
There are two documented ways in, and the documentation is clear about which to use when.
The CLI is the recommended method for setting this up for the first time on a new system. You clone the repository into a directory of your choosing and run `python3 main.py`, and the CLI guides you through the process.
There is a warning attached to it that is worth reading twice. The script will create users for each container with IDs ranging from 13001 to 13015, and if you want to choose your own IDs, or some of them are already occupied, you have to go through the manual install instead. So the convenience of the guided path comes with a fixed opinion about your host's user database.
The manual path is seven steps. Clone with `git clone https://github.com/Luctia/ezarr.git`, copy `.env.sample` to `.env` with `cp .env.sample .env`, set the environment variables, run `setup.sh` as superuser, which sets up the users, the system of directories and the permissions, copy `docker-compose.yml.sample` to `docker-compose.yml`, review it, and then bring the stack up with `docker compose up -d`.
The two paths differ in who makes the decisions. The CLI asks. The manual path lets you set the variables, the IDs and the compose file yourself, and the scripts then do the mechanical work of creating the users and the directory tree with the right ownership.
If you are coming from an older version or reinstalling with different IDs, the documentation tells you to run `remove_old_users.sh` first to clean up the old users, and then follow the manual steps. There is a separate `update_containers.sh` for the ongoing case.
The dependency install on Ubuntu and other Debian-based distributions is a single command.
sudo apt-get install python3 docker.io docker-compose-v2The script only works on Linux. There is a chance the sample compose file will work on Windows, although it is untested.
Container user IDs are the real configuration
The `.env.sample` file is where the substance of this project is, and it is mostly about user IDs.
The reason is the hardlink model. Each container in a Servarr stack runs as its own user, and if those users are not mapped consistently across the containers and onto the host, a hardlink between the download folder and the media folder cannot be created, and the file exists twice. The ID plan exists to prevent that, and the documentation links to the TRaSH guidance for the reasoning.
The sample assigns a UID to each container that needs its own user, and the values are in the 13000 range with `MEDIACENTER_GID=13000` first, then `SONARR_UID=13001`, `RADARR_UID=13002`, `LIDARR_UID=13003`, `READARR_UID=13004` which is marked discontinued, `MYLAR_UID=13005`, `PROWLARR_UID=13006`, `QBITTORRENT_UID=13007`, `JACKETT_UID=13008`, `PLEX_UID=13010`, `SABNZBD_UID=13011`, `BAZARR_UID=13013`, `AUDIOBOOKSHELF_UID=13014` and `SPORTARR_UID=13015`.
Two entries carry their own warnings. The Seerr UID is commented out, with a note that Seerr does not recommend using a non-default UID and GID, and a pointer to the references in `setup.sh` and `docker-compose.yml.sample`. And the READARR UID is marked discontinued, so the numbering has gaps and retired slots in it.
Two more variables are worth understanding before you fill the file in. `ROOT_DIR` is where everything is stored and the path must be absolute, because if you leave it empty it installs in the directory the `.env` file happens to be in. And `UID` and `GID` are the user that runs Docker, which the documentation tells you to find with `id -u`.
There is also a `TIMEZONE` variable that has to be a TZ database name such as `Europe/Amsterdam`, and a `PLEX_CLAIM` token for connecting the server to an account, which is obtained from the Plex site and is valid for four minutes after it is generated.
The compose file is meant to be edited before it runs
The compose sample is a starting point rather than a finished configuration, and the documentation says so directly.
The instruction is to take a look at the `docker-compose.yml` file and comment out any services you would rather not run, by placing `#` in front of the lines, which ensures they are ignored by Docker Compose. The example given is running Plex and Jellyfin at the same time, which is a bit unusual, and the same logic applies to leaving out Sportarr, Mylar3 or any of the rest.
The README also notes a specific detail that is easy to miss. If you use Homarr, you need to add a newly generated encryption key to the Homarr section, and that key is not in the sample, so a stack that starts cleanly can still be misconfigured in that one place.
Then the stack is brought up.
docker compose up -dIf it complains about permissions, the documented fix adds the current user to the docker group and applies the change.
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp dockerwith a reboot if it still does not work.
That last instruction is a reminder that this project targets a dedicated machine. The `newgrp` approach opens a subshell for the group change, and the fallback is a reboot of the host, which is fine on a box whose only job is to run the stack and is not fine on a desktop.
Afterwards the documentation says the containers are up and the user can continue to set up the settings in them. That last part is the real work, and the project does not try to hide it. The scripts produce a running stack with the right layout, the right permissions and no collisions, and the per-application configuration, the indexers, the download clients and the quality profiles are all still yours to do.
The badge tells you what the CI actually checks
There is a workflow badge at the top of the README, and the explanation next to it is unusually honest for a project of this kind.
The badge means that the shell script and the docker-compose file in the repository at least do not crash. The README is quick to add that it does not necessarily mean it will run well on your system, with a smiley at the end of the sentence.
That is a small thing and it is worth appreciating, because the badge in question is a `check_running` workflow, and the honest description of it tells you what the test actually is. It brings the stack up, or at least starts it, and checks that it does not fall over. It does not check that Plex can reach the media directory, that the hardlinks work, that Sonarr can talk to qBittorrent, or that the indexers return anything.
The repository layout is consistent with that scope. There is `main.py` for the CLI, `setup.sh` for the privileged setup, `remove_old_users.sh` for cleaning up, `update_containers.sh` for upgrades, `container_configs.py` and `users_groups_setup.py` as the Python modules holding the container definitions, and the two sample files.
The project is not archived and the last push was on 2026-08-11. There are no GitHub releases, so there is no version history to point at, and the tool is a script you take a copy of and edit rather than a package you pin.
The licence is MIT, and the README notes that the Plex claim token is valid for four minutes, which is a small sign of how closely the setup is tied to the current behaviour of the applications it deploys.
Where this is the wrong tool
There are three clear boundaries, and none of them is about the script being badly written.
The first is scope. Ezarr exists to assemble the Servarr family with Plex or Jellyfin in front of it, and if you want one of those applications you do not need it, because each is a Docker image with its own documentation. The value of the script is entirely in the coordination, the user IDs, the directory tree and the hardlink layout, and if you do not need that coordination the script is overhead.
The second is that it is a script you run, not a package you install. There are no releases, so there is nothing to upgrade to, and when you change the compose file you are changing your installation rather than updating it. The `update_containers.sh` script exists for the containers, but the layout around them is yours to maintain. That is fine for a single home server and wrong for a fleet.
The third is the one that deserves the most attention. The stack includes indexers and download clients, and the components the project itself calls out are FlareSolverr, described as a proxy server to bypass Cloudflare and DDoS-GUARD protection, and Jackett, described as an alternative to Prowlarr. Whether the content you fetch is licensed for your use is determined by the indexers you configure and the sources behind them, and nothing in this repository makes that decision for you or grants permission to fetch anything. The project is a deployment convenience, and the responsibility for what you point it at stays with the operator.
The alternative approach, and the difference in approach is real, is to run each application from its own image and wire them by hand, which is a common approach. You get per-application control and the ability to use only the pieces you want, and you give up the shared directory layout, the consistent user IDs and the hardlink setup that the TRaSH guidance depends on. The choice is between a coordinated stack that is right the first time and a set of containers that you tune yourself.
Editorial conclusion
Ezarr suits a person standing in front of a blank Ubuntu server who wants the standard media stack running tonight rather than this weekend, and who is willing to edit a compose file afterwards. It is the wrong tool for someone who wants one container, for a media server other than the Servarr family, and for a machine that is not a dedicated Linux host. Check first the user ID plan in `.env.sample`, because the script creates host users for each container with IDs from 13001 to 13015 and changing them later means removing the old users and rerunning the setup, and read the TRaSH hardlink guidance before you start filling the disk with media.
Frequently asked questions
What does Ezarr actually install?
It is a toolkit for deploying a media centre stack with Docker, including Sonarr, Radarr, Lidarr, Bazarr, Mylar3, Audiobookshelf, Sportarr, Prowlarr or Jackett, qBittorrent, SABnzbd, Plex or Jellyfin, Tautulli, Homarr and Overseerr or Jellyseerr. The configuration is set up to follow the TRaSH guidelines for hardlinks in Docker.
How do I install Ezarr?
The only requirements are Linux, Python 3 and Docker with docker-compose-v2, which on Ubuntu and Debian-based distributions is `sudo apt-get install python3 docker.io docker-compose-v2`. Then clone the repository and either run `python3 main.py` for the guided CLI, or follow the manual steps of copying `.env.sample` to `.env`, running `setup.sh` as superuser, copying `docker-compose.yml.sample` to `docker-compose.yml` and running `docker compose up -d`.
Why do I need to set user IDs in the .env file?
Each container that needs its own user is given a UID in the 13000 range in `.env.sample`, and the values have to be consistent across containers and on the host so that hardlinks between the download folder and the media folder work. The README warns that the CLI path creates those users with IDs from 13001 to 13015, so choosing your own IDs means using the manual install, and that changing them later requires running `remove_old_users.sh` first.
What does the check_running badge actually verify?
The README says it means the shell script and the docker-compose file in the repository at least do not crash, and explicitly that it does not necessarily mean it will run well on your system. It is a smoke test of the deployment, not a check of the configured stack.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/luctia-ezarr)Was this useful?