{"id":14463535,"url":"https://github.com/navilg/media-stack","last_synced_at":"2026-01-25T10:19:01.714Z","repository":{"id":42498477,"uuid":"510783606","full_name":"navilg/media-stack","owner":"navilg","description":"A self-hosted stack for media management and streaming, with AI-powered movie and show recommendations. Includes Sonarr, Radarr, qBitTorrent, Prowlarr, Jellyfin, Jellyseerr, Recommendarr, and VPN support.","archived":false,"fork":false,"pushed_at":"2025-09-06T14:58:56.000Z","size":139,"stargazers_count":948,"open_issues_count":4,"forks_count":118,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-09-06T16:31:38.809Z","etag":null,"topics":["ai","ai-generated-content","docker","gluetun","homelab","jellyfin","jellyseerr","linux-shots","media","media-stack","mediaserver","opensource","prowlarr","qbittorrent","radarr","recommendarr","selfhosted","sonarr","vpn"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/navilg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"buy_me_a_coffee":"linuxshots"}},"created_at":"2022-07-05T15:00:50.000Z","updated_at":"2025-09-06T14:59:00.000Z","dependencies_parsed_at":"2024-01-14T10:34:08.442Z","dependency_job_id":"274cbee4-7b97-4021-928f-6cfcbcce3bbf","html_url":"https://github.com/navilg/media-stack","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/navilg/media-stack","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navilg%2Fmedia-stack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navilg%2Fmedia-stack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navilg%2Fmedia-stack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navilg%2Fmedia-stack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/navilg","download_url":"https://codeload.github.com/navilg/media-stack/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navilg%2Fmedia-stack/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28751393,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-25T09:58:17.166Z","status":"ssl_error","status_checked_at":"2026-01-25T09:55:56.104Z","response_time":113,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-generated-content","docker","gluetun","homelab","jellyfin","jellyseerr","linux-shots","media","media-stack","mediaserver","opensource","prowlarr","qbittorrent","radarr","recommendarr","selfhosted","sonarr","vpn"],"created_at":"2024-09-01T23:01:38.103Z","updated_at":"2026-01-25T10:19:01.688Z","avatar_url":"https://github.com/navilg.png","language":null,"funding_links":["https://buymeacoffee.com/linuxshots","https://www.buymeacoffee.com/linuxshots"],"categories":["Others"],"sub_categories":[],"readme":"[![\"Buy Me A Coffee\"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/linuxshots)\n\n# media-stack\n\nA self-hosted media ecosystem that combines media management, streaming, AI-powered recommendations, and VPN.\n\nThis stack includes:\n\n- **VPN:** For secure and private media downloading\n- **Radarr:** For movie management\n- **Sonarr:** For TV show management\n- **Prowlarr:** A torrent indexer manager for Radarr/Sonarr\n- **qBittorrent:** Torrent client for downloading media\n- **Jellyseerr:** To manage media requests\n- **Jellyfin:** Open-source media streamer\n- **Recommendarr:** For AI-powered movie and show recommendations\n\n## Requirements\n\n- Docker version 28.0.1 or later\n- Docker compose version v2.33.1 or later\n- Older versions may work, but they have not been tested.\n\n## Install media stack\n\n\u003e **⚠️ Warning for ARMv7 Users:**  \n\u003e Jellyseerr **v2.0.x** introduces breaking changes, dropping support for the **ARMv7** container image. However, **ARM64** support remains available. You will not be able to run Jellyseerr in ARMv7 CPU.\n\nThere are three ways to deploy this stack:\n\n1. **With a VPN** (Recommended)  \n2. **Without a VPN**  \n3. **With Recommendarr** (An optional tool for AI-generated movie and show recommendations)  \n\n\u003e **NOTE:** If you are installing this stack **without a VPN**, you **must** use the `no-vpn` profile.  \n\u003e This requirement prevents accidental or unintentional deployment of media-stack without VPN.  \n\u003e  \n\u003e Running the `docker compose` command without a profile **will not deploy anything**.  \n\u003e  \n\u003e Check the installation steps below. \n\n\nBefore deploying the stack, you must first create a Docker network:  \n\n```bash\ndocker network create --subnet 172.20.0.0/16 mynetwork\n# Update the CIDR range based on your available IP range\n```\n\nWhen VPN is enabled, **qBittorrent** and **Prowlarr** will run behind the VPN for added privacy.  \n\nBy default, **NordVPN** is used in `docker-compose.yml`, but you can switch to:\n\n- **ExpressVPN**  \n- **SurfShark**  \n- **ProtonVPN**  \n- **Custom OpenVPN**  \n- **WireGuard VPN**\n\nAll providers use the **OpenVPN** protocol.\n\n➡️ **Full list of supported VPN providers:** [VPN Providers](https://github.com/qdm12/gluetun-wiki/tree/main/setup/providers)\n\n### Configure Your VPN Provider  \n\nRefer to your VPN provider's documentation to generate an **OpenVPN username and password**.  \nFor setup instructions, check:  \n➡️ [Gluetun VPN Setup Guide](https://github.com/qdm12/gluetun-wiki/tree/main/setup/providers)\n\n### Enabling VPN in `docker-compose.yml`  \n\nBy default, **VPN is disabled** in `docker-compose.yml`. To enable it, simply **comment/uncomment** the required lines in the file.  \nThe `docker-compose.yml` file includes clear instructions in the comments to guide you through the process.  \n\nOnce updated, follow the steps below to deploy the stack with VPN.  \n\n### Deploying the Stack with VPN (NordVPN Example)  \n\n```bash\nVPN_SERVICE_PROVIDER=nordvpn OPENVPN_USER=openvpn-username OPENVPN_PASSWORD=openvpn-password SERVER_COUNTRIES=Switzerland RADARR_STATIC_CONTAINER_IP=radarr-container-static-ip SONARR_STATIC_CONTAINER_IP=sonarr-container-static-ip docker compose --profile vpn up -d\n\n# OPTIONAL: Use Nginx as a reverse proxy\n# docker compose -f docker-compose-nginx.yml up -d\n```  \n\n### Static Container IP Requirement  \n\nA **static container IP address** is needed when **Prowlarr** is behind a VPN.  \nSince Prowlarr can only communicate with **Radarr** and **Sonarr** using their **container IP addresses**,  \nthese must be **manually assigned** to avoid connection issues when containers restart.  \n\nUse the following environment variables to set static IPs:  \n\n- `RADARR_STATIC_CONTAINER_IP`  \n- `SONARR_STATIC_CONTAINER_IP`  \n\n## Deploy the Stack Without VPN  \n\n🚨 **Warning:** Deploying without a VPN is **highly discouraged** as it may expose your IP address when torrenting media.  \n\nTo proceed without VPN, run the following command:  \n\n```bash\ndocker compose --profile no-vpn up -d\n\n# OPTIONAL: Use Nginx as a reverse proxy\n# docker compose -f docker-compose-nginx.yml up -d\n```\n\n## Deploy the Stack with Recommendarr (Optional)  \n\n**Recommendarr** is a web application that uses AI to generate personalized TV show and movie recommendations based on your: \n\n- **Sonarr** library  \n- **Radarr** library \n- **Jellyfin** watchlist and library\n- **Trakt** watchlist (Optional)\n\n### Deploying with Recommendarr  \n\nRun the following command based on your setup:  \n\n```bash\nCOMPOSE_PROFILES=vpn,recommendarr docker compose up -d  # With VPN\n\n# COMPOSE_PROFILES=no-vpn,recommendarr docker compose up -d  # Without VPN\n```\n\n## Configure qBittorrent\n\n- Open qBitTorrent at http://localhost:5080. Default username is `admin`. Temporary password can be collected from container log `docker logs qbittorrent`\n- Go to Tools --\u003e Options --\u003e WebUI --\u003e Change password\n- Run below commands on the server\n\n```bash\ndocker exec -it qbittorrent bash # Get inside qBittorrent container\n\n# Above command will get you inside qBittorrent interactive terminal, Run below command in qbt terminal\nmkdir /downloads/movies /downloads/tvshows\nchown 1000:1000 /downloads/movies /downloads/tvshows\n```\n\n## Configure Radarr\n\n- Open Radarr at http://localhost:7878\n- Settings --\u003e Media Management --\u003e Check mark \"Movies deleted from disk are automatically unmonitored in Radarr\" under File management section --\u003e Save\n- Settings --\u003e Media Management --\u003e Scroll to bottom --\u003e Add Root Folder --\u003e Browse to /downloads/movies --\u003e OK\n- Settings --\u003e Download clients --\u003e qBittorrent --\u003e Add Host (qbittorrent) and port (5080) --\u003e Username and password --\u003e Test --\u003e Save **Note: If VPN is enabled, then qbittorrent is reachable on vpn's service name. In this case use `vpn` in Host field.**\n- Settings --\u003e General --\u003e Enable advance setting --\u003e Select Authentication and add username and password\n- Indexer will get automatically added during configuration of Prowlarr. See 'Configure Prowlarr' section.\n\nSonarr can also be configured in similar way.\n\n**Add a movie** (After Prowlarr is configured)\n\n- Movies --\u003e Search for a movie --\u003e Add Root folder (/downloads/movies) --\u003e Quality profile --\u003e Add movie\n- All queued movies download can be checked here, Activities --\u003e Queue \n- Go to qBittorrent (http://localhost:5080) and see if movie is getting downloaded (After movie is queued. This depends on availability of movie in indexers configured in Prowlarr.)\n\n## Configure Jellyfin\n\n- Open Jellyfin at http://localhost:8096\n- When you access the jellyfin for first time using browser, A guided configuration will guide you to configure jellyfin. Just follow the guide.\n- Add media library folder and choose /data/movies/\n\n## Configure Jellyseerr\n\n- Open Jellyfin at http://localhost:5055\n- When you access the jellyseerr for first time using browser, A guided configuration will guide you to configure jellyseerr. Just follow the guide and provide the required details about sonarr and Radarr.\n- Follow the Overseerr document (Jellyseerr is fork of overseerr) for detailed setup - https://docs.overseerr.dev/ \n\n## Configure Prowlarr\n\n- Open Prowlarr at http://localhost:9696\n- Settings --\u003e General --\u003e Authentications --\u003e Select Authentication and add username and password\n- Add Indexers, Indexers --\u003e Add Indexer --\u003e Search for indexer --\u003e Choose base URL --\u003e Test and Save\n- Add application, Settings --\u003e Apps --\u003e Add application --\u003e Choose Radarr --\u003e Prowlarr server (http://prowlarr:9696) --\u003e Radarr server (http://radarr:7878) --\u003e API Key --\u003e Test and Save\n- Add application, Settings --\u003e Apps --\u003e Add application --\u003e Choose Sonarr --\u003e Prowlarr server (http://prowlarr:9696) --\u003e Sonarr server (http://sonarr:8989) --\u003e API Key --\u003e Test and Save\n- This will add indexers in respective apps automatically.\n\n**Note: If VPN is enabled, then Prowlarr will not be able to reach radarr and sonarr with localhost or container service name. In that case use static IP for sonarr and radarr in radarr/sonarr server field (for e.g. http://172.19.0.5:8989). Prowlar will also be not reachable with its container/service name. Use `http://vpn:9696` instead in prowlar server field.**\n\n## Configure Recommendarr\n\nRecommendarr is an AI based movies/tvshows recommendation tool. To use this you will need any OpenAI API URL and API key with atleast one LLM model running. You can host your own OpenAI server with AI model using ollama or LM Studio. Or you can check `https://openrouter.ai` for limited-free LLMs.\n\n- Open Recommendarr at http://localhost:3000\n- Login with default username `admin` and password `1234`\n- Settings --\u003e Account --\u003e Change Password and change your admin password\n- Settings --\u003e AI service --\u003e API URL (Add OpenAI server API URL) --\u003e API Key (Add OpenAPI server API key) --\u003e Fetch available models --\u003e Set Max tokens (best to keep it under 2000) --\u003e Set Temperature (Best to keep at 0.8)\n- Settings --\u003e Sonarr --\u003e Sonarr URL (http://sonarr:8989) --\u003e API Keys (Sonarr API Key) --\u003e Test Connection --\u003e Save Sonarr setting\n- Settings --\u003e Radarr --\u003e Radarr URL (http://radarr:7878) --\u003e API Keys (Radarr API Key) --\u003e Test Connection --\u003e Save Radarr setting\n- Settings --\u003e Jellyfin --\u003e Jellyfin URL (http://jellyfin:8096) --\u003e API Keys (Jellyfin API Key) --\u003e User ID (Add your jellyfin user id) --\u003e Test Connection --\u003e Save Jellyfin settings\n- Test recommendarr: Recommendations --\u003e Choose LLM Model from drop down list --\u003e Enable Jellyfin Watch History toggle --\u003e Select language --\u003e Choose genres --\u003e Discover recommendations\n- You should be able to see recommendations based on your Jellyfin watch history\n\n## Configure Nginx\n\n- Get inside Nginx container\n- `cd /etc/nginx/conf.d`\n- Add proxies for all tools.\n\n`docker cp nginx.conf nginx:/etc/nginx/conf.d/default.conf \u0026\u0026 docker exec -it nginx nginx -s reload`\n- Close ports of other tools in firewall/security groups except port 80 and 443.\n\n\n## Apply SSL in Nginx\n\n- Open port 80 and 443.\n- Get inside Nginx container and install certbot and certbot-nginx `apk add certbot certbot-nginx`\n- Add URL in server block. e.g. `server_name  localhost mediastack.example.com;` in /etc/nginx/conf.d/default.conf\n- Run `certbot --nginx` and provide details asked.\n\n## Radarr Nginx reverse proxy\n\n- Settings --\u003e General --\u003e URL Base --\u003e Add base (/radarr)\n- Add below proxy in nginx configuration\n\n```\nlocation /radarr {\n    proxy_pass http://radarr:7878;\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_http_version 1.1;\n    proxy_set_header Upgrade $http_upgrade;\n    proxy_set_header Connection $http_connection;\n  }\n```\n\n- Restart containers.\n\n## Sonarr Nginx reverse proxy\n\n- Settings --\u003e General --\u003e URL Base --\u003e Add base (/sonarr)\n- Add below proxy in nginx configuration\n\n```\nlocation /sonarr {\n    proxy_pass http://sonarr:8989;\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_http_version 1.1;\n    proxy_set_header Upgrade $http_upgrade;\n    proxy_set_header Connection $http_connection;\n  }\n```\n\n## Prowlarr Nginx reverse proxy\n\n- Settings --\u003e General --\u003e URL Base --\u003e Add base (/prowlarr)\n- Add below proxy in nginx configuration\n\nThis may need to change configurations in indexers and base in URL.\n\n```\nlocation /prowlarr {\n    proxy_pass http://prowlarr:9696; # Comment this line if VPN is enabled.\n    # proxy_pass http://vpn:9696; # Uncomment this line if VPN is enabled.\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_http_version 1.1;\n    proxy_set_header Upgrade $http_upgrade;\n    proxy_set_header Connection $http_connection;\n  }\n```\n\n- Restart containers.\n\n**Note: If VPN is enabled, then Prowlarr is reachable on vpn's service name**\n\n## qBittorrent Nginx proxy\n\n```\nlocation /qbt/ {\n    proxy_pass         http://qbittorrent:5080/; # Comment this line if VPN is enabled.\n    # proxy_pass         http://vpn:5080/; # Uncomment this line if VPN is enabled.\n    proxy_http_version 1.1;\n\n    proxy_set_header   Host               http://qbittorrent:5080; # Comment this line if VPN is enabled.\n    # proxy_set_header   Host               http://vpn:5080; # Uncomment this line if VPN is enabled.\n    proxy_set_header   X-Forwarded-Host   $http_host;\n    proxy_set_header   X-Forwarded-For    $remote_addr;\n    proxy_cookie_path  /                  \"/; Secure\";\n}\n```\n\n**Note: If VPN is enabled, then qbittorrent is reachable on vpn's service name**\n\n## Jellyfin Nginx proxy\n\n- Add base URL, Admin Dashboard -\u003e Networking -\u003e Base URL (/jellyfin)\n- Add below config in Ngix config\n\n```\n location /jellyfin {\n        return 302 $scheme://$host/jellyfin/;\n    }\n\n    location /jellyfin/ {\n\n        proxy_pass http://jellyfin:8096/jellyfin/;\n\n        proxy_pass_request_headers on;\n\n        proxy_set_header Host $host;\n\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header X-Forwarded-Host $http_host;\n\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection $http_connection;\n\n        # Disable buffering when the nginx proxy gets very resource heavy upon streaming\n        proxy_buffering off;\n    }\n```\n\n## Jellyseerr Nginx proxy\n\n**Currently Jellyseerr/Overseerr doesnot officially support the subfolder/path reverse proxy. They have a workaround documented here without an official support. Find it [here](https://docs.overseerr.dev/extending-overseerr/reverse-proxy)**\n\n```\nlocation / {\n        proxy_pass http://127.0.0.1:5055;\n\n        proxy_set_header Referer $http_referer;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Real-Port $remote_port;\n        proxy_set_header X-Forwarded-Host $host:$remote_port;\n        proxy_set_header X-Forwarded-Server $host;\n        proxy_set_header X-Forwarded-Port $remote_port;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header X-Forwarded-Ssl on;\n    }\n```\n\n- Restart containers\n\n\n## Disclaimer  \n\n\u003e Neither the author nor the developers of the code in this repository **condone or encourage** downloading, sharing, seeding, or peering of **copyrighted material**.  \n\u003e Such activities are **illegal** under international laws.  \n\u003e\n\u003e This project is intended for **educational purposes only**.  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnavilg%2Fmedia-stack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnavilg%2Fmedia-stack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnavilg%2Fmedia-stack/lists"}