Docker Compose configuration for an OSS self-hosted media-management and playback stack.
Details
| Service | Purpose | Network placement |
|---|---|---|
| Jellyfin | Media playback and library browsing | Standard media-stack network |
| Seerr | Media discovery and requests | Standard media-stack network |
| Sonarr | TV library management | Standard media-stack network |
| Radarr | Movie library management | Standard media-stack network |
| Bazarr | Subtitle management | Standard media-stack network |
| Prowlarr | Indexer management | Shares Gluetun's protected network namespace |
| qBittorrent | Download client | Shares Gluetun's protected namespace and binds to tun0 |
| FlareSolverr | Compatibility support for applicable indexers | Shares Gluetun's protected network namespace |
| Gluetun | VPN gateway, firewall, and fail-closed network namespace | VPN-connected gateway for protected services |
| Homarr | Dashboard with links to the stack's web interfaces | Separate Compose project |
Details
- A Linux host with Docker Engine and the Docker Compose plugin
- A VPN subscription supported by Gluetun
/dev/net/tunavailable to Docker- Host directories for media, service configuration, and Homarr data
The example Docker subnet is 172.30.39.0/24. Change it if it overlaps another network on your system.
Details
Clone the repository and create the local environment files, preferably on a dedicated machine or VM:
git clone https://github.com/BlaiseMoses01/media-server.git
cd media-server
cp media-stack/.env.example media-stack/.env
cp homarr/.env.example homarr/.envEdit media-stack/.env with your user IDs, timezone, VPN provider, WireGuard private key, preferred server country, storage locations, and any necessary network changes. Never commit this file.
The host paths are configured without editing Compose YAML:
| Environment file | Variable | Purpose |
|---|---|---|
media-stack/.env |
CONFIG_ROOT |
Parent directory for service configuration |
media-stack/.env |
MEDIA_ROOT |
Parent directory for downloads and organized media |
homarr/.env |
HOMARR_APPDATA |
Homarr database and configuration directory |
Generate Homarr's required encryption key and place the output in homarr/.env:
openssl rand -hex 32Prepare the host directories. Replace these example values with the same paths selected in the two .env files:
CONFIG_ROOT=/your/config/path
MEDIA_ROOT=/your/media/path
HOMARR_APPDATA=/your/homarr/path
sudo mkdir -p \
"${CONFIG_ROOT}"/{gluetun,qbittorrent,prowlarr,radarr,sonarr,bazarr,jellyfin} \
"${MEDIA_ROOT}"/{downloads,media/movies,media/tv} \
"${HOMARR_APPDATA}"Start both projects:
docker compose --env-file media-stack/.env -f media-stack/compose.yaml up -d
docker compose --env-file homarr/.env -f homarr/compose.yaml up -dUseful local endpoints include:
| Service | URL |
|---|---|
| Homarr | http://HOST_IP:7575 |
| Jellyfin | http://HOST_IP:8096 |
| Seerr | http://HOST_IP:5055 |
| Sonarr | http://HOST_IP:8989 |
| Radarr | http://HOST_IP:7878 |
| Bazarr | http://HOST_IP:6767 |
| Prowlarr | http://HOST_IP:9696 |
| qBittorrent | http://HOST_IP:8080 |
Complete each application's first-run setup in its web interface. Inside the media-stack network, services sharing Gluetun's network namespace can be reached through the gluetun hostname and their respective ports.
Details
- Follow the VPN fail-closed design and test guide to configure and verify the two-layer qBittorrent kill switch.
- Do not expose the application ports directly to the public internet. Use a firewall and, when remote access is needed, an authenticated VPN or carefully configured reverse proxy.
- Keep
.envfiles, VPN credentials, API keys, databases, logs, download history, and application-data directories out of Git. - Homarr's Docker-socket mount is optional. Remove it if Docker integration is not needed. Even a read-only socket mount provides powerful access to information about the Docker host.
- A VPN can provide privacy and network isolation, but it does not authorize access to content or make otherwise unlawful activity lawful.
- Back up application data and media-library metadata before upgrades.
The stack presented in this repo is intended for lawful uses such as organizing and playing media you created, own, are licensed to access, have permission to copy or distribute, or that is in the public domain. I do not support the download, upload, reproduction, or distribution of copyrighted material without authorization from the rights holder.
You, and you alone, are responsible for how you configure and use these tools and for complying with copyright law, service terms, and other rules applicable in your jurisdiction. This repository is not legal advice. For United States guidance, see the U.S. Copyright Office FAQ on copyright and digital files.
The original configuration and documentation in this repository are available under the MIT License. Referenced applications and container images remain subject to their respective licenses. This license does not grant rights to any media or override the legal-use disclaimer above.