A self-hosted home media server built on Ubuntu Server 24.04 LTS and Docker. Streams movies, TV shows, anime, music, and photos to any device on your local network with no cloud accounts, no telemetry, and no data leaving your home.
Designed for local network use only. No port forwarding or external access required.
| Service | Purpose | Default Port |
|---|---|---|
| Jellyfin | Media server — stream everything | :8096 |
| Jellyseerr | Discovery, recommendations, and requests | :5055 |
| Sonarr | TV show and anime library manager | :8989 |
| Radarr | Movie library manager | :7878 |
| Prowlarr | Indexer manager — syncs sources to Sonarr and Radarr | :9696 |
| qBittorrent | Torrent download client | :8081 |
| Bazarr | Automatic subtitle downloader | :6767 |
All ports are configurable in .env.
No service in this stack sends personal data, usage habits, or identifiable information to any external party.
| Service | Telemetry | External Calls | Notes |
|---|---|---|---|
| Jellyfin | None | None | Disable usage stats on first launch |
| Sonarr / Radarr | None | TVDB / TMDB title lookups | IP + title name only |
| Prowlarr | None | Indexer sites for search results | IP + search terms only |
| qBittorrent | None | Torrent peers and trackers | Standard torrent traffic |
| Jellyseerr | None | TMDB for discovery browsing | IP + search terms only |
| Bazarr | None | OpenSubtitles / Animetosho | IP + title name only |
- A machine running Ubuntu Server 24.04 LTS (bare metal, no desktop environment)
- Static IP assigned to the server — via DHCP reservation on your router or set directly on the machine
- Sufficient storage for your media library
curlandjqinstalled:sudo apt install -y curl jq
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USERLog out and back in for the group change to take effect.
cp .env.example .envOpen .env and fill in:
| Variable | What to set | How to find it |
|---|---|---|
PUID / PGID |
Your user and group ID | Run id in terminal |
TZ |
Your timezone | Timezone list |
MEDIA_ROOT |
Where your media storage is mounted | e.g. /mnt/storage or /srv/media |
SERVER_IP |
This machine's local IP address | Run hostname -I |
All other values (ports, config paths) have sensible defaults and can be left as-is unless you have conflicts.
chmod +x setup.sh
sudo ./setup.shThis creates all required directories with correct ownership, starts all containers, and waits until every service is ready. It prints URLs and next steps when complete.
Open Jellyfin in your browser at http://<server-ip>:8096 and follow the setup wizard. Create your admin account and add your media libraries. Note the password you set.
Then add your credentials to .env:
JELLYFIN_USER=yourusername
JELLYFIN_PASS=yourpassword
Open Jellyseerr at http://<server-ip>:5055/setup and sign in with your Jellyfin credentials. You can skip the Sonarr and Radarr steps — the wiring script handles those automatically.
chmod +x config.sh
./config.shThis authenticates with every service and wires them together automatically:
- Connects qBittorrent to Sonarr and Radarr as the download client
- Registers Prowlarr with Sonarr and Radarr for indexer syncing
- Configures root media folders in Sonarr and Radarr
- Links Jellyseerr to Sonarr, Radarr, and Jellyfin
docker compose psAll services should show running. To view logs for a specific service:
docker compose logs jellyfinThe wiring script connects Prowlarr to Sonarr and Radarr, but you still need to add your indexers. Go to Indexers > Add Indexer, search by name, and use the test button before saving. Once saved, Prowlarr pushes them to Sonarr and Radarr automatically — do not add indexers directly in either app.
| Indexer | Best for |
|---|---|
| YTS | Movies — very clean releases |
| EZTV | TV shows |
| The Pirate Bay | Broad coverage of everything |
| 1337x | General — movies, TV, anime |
| Nyaa | Anime — the standard, essentially required |
| TokyoTosho | Anime — secondary source, good for niche titles |
| Tracker | Best for |
|---|---|
| BTN (BroadcasTheNet) | TV shows — invite only, considered the best TV tracker |
| PTP (PassThePopcorn) | Movies — invite only, extremely high quality |
| AnimeBytes | Anime — better than Nyaa for older or niche titles, invite only |
| MAM (MyAnonamouse) | Books and audiobooks |
On first startup, qBittorrent generates a temporary password that changes on every restart. After the wiring script runs:
- Open qBittorrent at
http://<server-ip>:8081 - Go to Tools > Options > Web UI and set a permanent password
- Add it to
.env:QBIT_PASS=yourpassword
The wiring script connects Bazarr to Sonarr and Radarr, but subtitle providers require your account credentials and must be added manually.
- Open Bazarr at
http://<server-ip>:6767 - Go to Settings > Providers and add at least one provider:
- OpenSubtitles.com — free account required at opensubtitles.com
- Animetosho — no account needed, recommended for anime
- Go to Settings > Languages, create a language profile containing English, and set it as the default for both Series and Movies
- Go to Movies and Series, select all existing content, and bulk edit to assign the English profile — this covers content added before the profile was set
- Go to System > Tasks and run Search for Missing Subtitles to trigger an immediate download across your library
Users browse and request content through Jellyseerr. Requests flow automatically into Sonarr or Radarr without users needing access to any other service.
Before requesting or downloading anything, verify the full pipeline is correctly wired. Work through this once after config.sh completes.
- Confirm at least one indexer is listed under Indexers
- Click the test icon on each indexer to confirm it is reachable
- Go to Settings > Apps and confirm Sonarr and Radarr both show green
- Go to Settings > Media Management > Root Folders and confirm
/media/tvshowsand/media/animeare listed - Go to Settings > Download Clients and confirm qBittorrent shows green
- Go to Settings > Indexers and confirm your Prowlarr indexers have synced through
- Go to Settings > Media Management > Root Folders and confirm
/media/moviesis listed - Go to Settings > Download Clients and confirm qBittorrent shows green
- Go to Settings > Indexers and confirm your Prowlarr indexers have synced through
- Confirm you can log in with your permanent password
- Go to Tools > Options > Downloads and confirm the default save path is
/downloads - Go to Tools > Options > Connection — a red port status means port
6881is not forwarded on your router, which will significantly reduce download speeds. Forward6881TCP and UDP to your server's LAN IP in your router's admin panel.
- Go to Settings > Sonarr and Settings > Radarr and click Test on both — should return a version number
- Confirm at least one subtitle provider is listed under Settings > Providers
- Confirm a language profile is assigned under Settings > Languages with defaults set for both Series and Movies
- Confirm your library is populated under Movies and Series
- Confirm all libraries exist and point to the correct folders under Dashboard > Libraries
- Run a scan on each library to pick up any existing content
- Go to your profile Settings > Playback and set:
- Preferred audio language: Japanese
- Preferred subtitle language: English
- Subtitle mode: Always
- Go to Settings > Services and confirm both Sonarr and Radarr show green
- Go to Settings > Users and configure request permissions for household members
Run through this once before giving others access:
- Request a movie in Jellyseerr
- Confirm it appears in Radarr as Monitored
- Confirm a download starts in qBittorrent within a few minutes
- Confirm the file is imported in Radarr once downloaded
- Confirm the movie appears in Jellyfin
- Confirm subtitles were downloaded in Bazarr
- Play the movie in Jellyfin and confirm subtitles appear
If every step passes the full pipeline is working correctly.
Paths below reflect the defaults in .env.example. They can be changed to any location by editing .env.
/srv/
├── media/
│ ├── movies/ # Radarr output → Jellyfin source
│ ├── tvshows/ # Sonarr output → Jellyfin source
│ ├── anime/ # Sonarr output → Jellyfin source
│ ├── music/ # Jellyfin music library
│ └── photos/ # Jellyfin photo library
├── downloads/ # qBittorrent download folder
├── jellyfin/
│ ├── config/ # Jellyfin config and database
│ └── cache/ # Transcoding cache
├── sonarr/config/
├── radarr/config/
├── prowlarr/config/
├── qbittorrent/config/
├── bazarr/config/
└── jellyseerr/config/
This stack runs well on modest hardware. Reference build:
- CPU: AMD Ryzen 5 5500 (6-core, 12-thread, 4.2GHz boost)
- RAM: 16GB DDR4-3200
- OS Drive: Any SSD (NVMe recommended)
- Media Storage: Any HDD or SSD with sufficient capacity
The Ryzen 5 5500 has no integrated GPU. The devices: /dev/dri lines in the Jellyfin section of docker-compose.yaml are commented out by default for this reason. The 6-core processor handles software transcoding adequately, and most modern clients on a local network will direct play without triggering transcoding at all.
For machines with an Intel integrated GPU, enable hardware transcoding after starting the stack:
sudo apt install -y intel-media-va-driver-non-free
sudo usermod -aG render $USERThen in Jellyfin go to Dashboard > Playback and enable Intel QSV. Uncomment the devices section in docker-compose.yaml and restart the Jellyfin container.
# Start all services
docker compose up -d
# Stop all services
docker compose down
# Restart a single service
docker compose restart jellyfin
# View live logs for a service
docker compose logs -f sonarr
# Pull latest images and restart
docker compose pull && docker compose up -d
# Check resource usage across containers
docker statsThis project is licensed under the GNU General Public License v3.0.
You are free to use, modify, and distribute this project, but any derivative work must also be distributed under the same license terms.