A personal media server that automatically finds, downloads, and organizes movies and TV shows. You browse a Netflix-like interface, click what you want, and it handles the rest.
What you'll have when done:
- Seerr: Netflix-style browsing and request UI (this is what you'll use day-to-day)
- Plex: Plays your media on any device (TV, phone, laptop)
- Everything else runs in the background automatically
Time to complete: About 20 minutes
If you already have OrbStack (or Docker Desktop) and Plex installed, you can run a single command that handles everything:
curl -fsSL https://raw.githubusercontent.com/liamvibecodes/mac-media-stack/main/bootstrap.sh | bashIt will prompt you for VPN keys and walk you through the Seerr login. If you'd rather do each step yourself, continue with the manual guide below.
You can also run it locally with custom paths:
bash bootstrap.sh --media-dir /Volumes/T9/Media --install-dir ~/mac-media-stackTo use Jellyfin instead of Plex:
bash bootstrap.sh --jellyfinAlready on an older clone and want the newest release tag:
bash <(curl -fsSL https://raw.githubusercontent.com/liamvibecodes/mac-media-stack/main/scripts/update-to-latest-release.sh)This stack supports two media servers. Pick one:
| Plex (default) | Jellyfin | |
|---|---|---|
| Setup | Install natively on macOS | Runs in Docker automatically |
| Account | Requires a free Plex account | No account needed |
| Cost | Free (Plex Pass optional) | Completely free and open source |
| Remote streaming | Built-in (Plex Pass for some features) | Requires manual reverse proxy |
| Client apps | Polished apps on every platform | Good apps, fewer platforms |
Plex is the default. Everything works out of the box with no changes.
Jellyfin is a fully open-source alternative. To use it, add the --jellyfin flag:
bash bootstrap.sh --jellyfinOr for manual setup, set MEDIA_SERVER=jellyfin in your .env file.
- A Mac (any recent macOS)
- An internet connection
- At least 50GB free disk space (media libraries will need more)
- Your VPN keys (two values: a private key and an address)
- A free Plex account (create one at https://plex.tv if you don't have one), OR use Jellyfin (no account needed)
You need a container runtime to run the behind-the-scenes services. Pick one:
OrbStack is faster and lighter than Docker Desktop (~2s startup, ~1GB RAM).
brew install --cask orbstackOr download from https://orbstack.dev. Open it once after installing.
- Go to https://www.docker.com/products/docker-desktop/
- Click "Download for Mac"
- If you have an M-series Mac (M1, M2, M3, M4): choose "Apple Silicon"
- If you're not sure, click the Apple icon top-left of your screen > "About This Mac" and check the chip
- Open the downloaded
.dmgfile - Drag Docker to your Applications folder
- Open Docker Desktop from Applications
- It will ask for your password to install components. Enter it.
- Wait for it to finish starting (the whale icon in your menu bar will stop animating)
- In Docker Desktop settings (gear icon), go to "General" and make sure "Start Docker Desktop when you sign in" is checked
Both options use the same docker and docker compose commands. Everything in this guide works identically with either one.
Plex is the app that actually plays your media on your TV, phone, etc.
- Go to https://www.plex.tv/media-server-downloads/
- Under "Plex Media Server", choose macOS
- Open the downloaded file and drag Plex to Applications
- Open Plex Media Server from Applications
- It will appear as an icon in your menu bar (an orange arrow)
- In Plex's menu bar icon, click "Open Plex" to open the web interface
- Sign in with your Plex account
- Skip the initial library setup for now (we'll point it at the right folders later)
No separate install needed. Jellyfin runs as a Docker container alongside the rest of the stack. Just make sure MEDIA_SERVER=jellyfin is set in your .env file (the --jellyfin flag does this automatically).
- Open Terminal (search "Terminal" in Spotlight, or find it in Applications > Utilities)
- Run these commands one at a time (copy and paste each line, then press Enter):
cd ~
git clone https://github.com/liamvibecodes/mac-media-stack.git
cd mac-media-stackIf you don't have git installed, your Mac will prompt you to install Command Line Tools. Click "Install" and wait, then run the commands again.
This creates all the folders and prepares your configuration file.
bash scripts/setup.shYou should see "Setup complete!" at the end.
You need two values from your ProtonVPN account: a WireGuard Private Key and a WireGuard Address. Get your WireGuard private key from https://account.protonvpn.com/downloads#wireguard-configuration, or use the ones provided to you.
- Open the
.envfile in TextEdit:
open -a TextEdit .env- Find these two lines near the bottom:
WIREGUARD_PRIVATE_KEY=your_wireguard_private_key_here
WIREGUARD_ADDRESSES=your_wireguard_address_here
- Replace the placeholder text with your actual values. For example:
WIREGUARD_PRIVATE_KEY=aBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890abcdefg=
WIREGUARD_ADDRESSES=10.2.0.2/32
- Save and close TextEdit (Cmd+S, then Cmd+Q)
Run preflight checks before first startup:
bash scripts/doctor.shThen start services:
docker compose up -dIf using Jellyfin, include the profile:
docker compose --profile jellyfin up -dThis will download everything it needs (about 2-3 GB, may take a few minutes on the first run). You'll see each service being created. After it starts, run the health check:
bash scripts/health-check.shEverything should show OK. If VPN shows FAIL, double-check your WireGuard keys in Step 5.
- Open Plex in your browser: http://localhost:32400/web
- Go to Settings (wrench icon) > Libraries > Add Library
- Add a Movies library:
- Type: Movies
- Add folder: click "Browse" and navigate to your home folder > Media > Movies
- Add a TV Shows library:
- Type: TV Shows
- Add folder: click "Browse" and navigate to your home folder > Media > TV Shows
- That's it. Plex will automatically scan these folders whenever new media appears.
Important: Always access Plex at http://localhost:32400/web from the server Mac itself. This avoids the "Plex Pass" paywall for remote streaming setup.
- Open Jellyfin in your browser: http://localhost:8096
- Complete the initial setup wizard (language, create admin account)
- Add a Movies library:
- Content type: Movies
- Folder:
/data/movies
- Add a TV Shows library:
- Content type: Shows
- Folder:
/data/tvshows
- Finish the wizard. Jellyfin will scan these folders automatically.
This script automatically sets up all the connections between services. It configures the download client, indexers, and search providers so you don't have to touch any of that manually.
bash scripts/configure.shThe script will:
- Configure the download client (qBittorrent) with the right settings
- Set up all the search indexers (where to find movies/shows)
- Connect everything together (Prowlarr, Radarr, Sonarr, Seerr)
- Ask you to sign in to Seerr with Plex or Jellyfin (one browser step)
At the end it will print your qBittorrent password and save credentials/API keys to <MEDIA_DIR>/state/first-run-credentials.txt (mode 600, default path ~/Media/state/first-run-credentials.txt).
This installs a background job that checks your stack every hour. If the VPN goes down or a container stops, it automatically restarts it. Set it and forget it.
bash scripts/install-auto-heal.shLogs go to <MEDIA_DIR>/logs/auto-heal.log (default ~/Media/logs/auto-heal.log) if you ever want to check what it's been doing.
To remove it later:
launchctl unload ~/Library/LaunchAgents/com.media-stack.auto-heal.plist
rm ~/Library/LaunchAgents/com.media-stack.auto-heal.plistDay-to-day usage:
- Open http://localhost:5055 (Seerr) to browse and request movies/shows
- Open http://localhost:32400/web (Plex) or http://localhost:8096 (Jellyfin) to watch your media
- Everything else is automatic
Bookmarks to save:
| What | URL |
|---|---|
| Seerr (browse/request) | http://localhost:5055 |
| Plex (watch) | http://localhost:32400/web |
| Jellyfin (watch) | http://localhost:8096 |
You probably won't need these, but just in case:
| What | URL |
|---|---|
| Radarr (movies admin) | http://localhost:7878 |
| Sonarr (TV admin) | http://localhost:8989 |
| qBittorrent (downloads) | http://localhost:8080 |
What happens automatically:
- New requests in Seerr get searched and downloaded
- Downloads are automatically imported into Plex
- Subtitles are auto-fetched (English)
- If enabled, container updates happen at 4am daily (Watchtower)
- Everything survives reboots (OrbStack or Docker Desktop + Plex auto-start)
Nothing is working after reboot:
Open OrbStack (or Docker Desktop). Wait 30 seconds. Run bash scripts/health-check.sh.
VPN health check fails:
Double-check your WireGuard keys in .env. Make sure there are no extra spaces. Then restart:
docker compose restart gluetunDownloads are stuck or slow: Open qBittorrent (http://localhost:8080) and check if torrents are active. If everything shows "stalled", the VPN tunnel may be down. Restart gluetun:
docker compose restart gluetunPlex doesn't see new movies: Plex scans periodically. To force a scan, open Plex, go to your library, and click the refresh icon. Or make sure the library folder paths are correct (Step 7).
"Permission denied" errors:
Make sure your PUID/PGID in .env match your Mac user. Run id -u in Terminal to check.
Want to stop everything:
cd ~/mac-media-stack
docker compose downWant to start everything again:
cd ~/mac-media-stack
docker compose up -d
# If using Jellyfin:
docker compose --profile jellyfin up -dNeed help? Run the health check and share a screenshot with whoever set this up for you:
bash scripts/health-check.sh