macOS Tutorial
One-line option
The optional sponsor bootstrap installs macFUSE when needed, downloads the correct Intel or Apple silicon build and runs the provider chooser and diagnostics:
curl -fsSL https://raw.githubusercontent.com/debridmediamanager/zurg-site/main/public/install.sh | bash
It uses GitHub browser sign-in. macOS may still require approval under System Settings > Privacy & Security and a reboot. Existing binaries and configs are preserved. Continue below for the manual route.
Step 1: Install macFUSE
macFUSE lets rclone mount zurg's virtual filesystem as a real directory on your Mac.
- Download the latest
.dmgfrom macfuse.io - Open the
.dmgand run the installer - During installation, macOS will block the system extension. Go to System Settings > Privacy & Security, scroll down, and click Allow
- Reboot your Mac (required for the kernel extension to load)
After rebooting, open Terminal (press Cmd + Space, type "Terminal", press Enter) and verify:
kextstat | grep macfuse
# Should output a line containing: io.macfuse.filesystems.macfuse
Step 2: Download Zurg
Open GitHub Releases in a browser where you are signed in to the GitHub account that has zurg access. Take the newest nightly. It is the pre-release at the top of the list. Grab its darwin-arm64 zip or darwin-amd64 on an Intel Mac. Do not take the release GitHub marks Latest. That is v1.0.0. It is older than zurg setup and answers it with unknown command.
Nightlies are for sponsors. Until your GitHub account has access that page answers 404. The free public build is v1.0.0 from zurg-public. It has no zurg setup. Set it up by hand as its README explains instead of following the steps below.
Then unpack it.
mkdir -p ~/zurg && cd ~/zurg
unzip -o ~/Downloads/zurg-*-darwin-arm64.zip
chmod +x zurg
Verify:
./zurg version
Recommended: let zurg finish the setup
From the extracted directory, run:
./zurg setup
./zurg doctor
setup asks which providers to configure. Choose one or several of Real-Debrid, TorBox, AllDebrid and Usenet in priority order. For example enter 2,4 for TorBox followed by Usenet. It asks only for the selected credentials, creates config.yml with mode 0600, downloads rclone and ffprobe, prepares /Volumes/Zurg and installs auto-start.
It chooses a LaunchAgent when the current user has a GUI launchd domain. On a headless Mac with no logged-in GUI user it installs a system LaunchDaemon that still runs zurg as the current user. That path does not require auto-login.
The prerequisite check distinguishes an installed macFUSE package from an extension macOS can actually load. On Apple silicon the first macFUSE install may still require a one-time Recovery security change, approval under System Settings > Privacy & Security and a reboot. No installer can bypass those confirmations.
Setup is safe to run again. It updates the generated launchd service but does not replace an existing config.yml.
Before streaming through the mount, open config.yml or the Dashboard at http://localhost:9999/config/ and set both --vfs-cache-max-size and --vfs-cache-min-free-space under rclone_extra_args. Keep the maximum below half of the currently free disk space and reserve at least 20G with the minimum-free-space setting. Then run ./zurg service restart.
The rest of this page explains the config and Plex setup. Steps 3, 4, 5 and 7 are the manual alternative and can be skipped after zurg setup succeeds.
Step 3: Configure zurg manually
Create a config file with your Real-Debrid API token:
cd ~/zurg
cat > config.yml << 'EOF'
# Minimal config - use Dashboard at http://localhost:9999/config/ for more settings
zurg: v1
providers:
- type: realdebrid
token: YOUR_RD_API_TOKEN_HERE
rclone_enabled: true
mount_path: /Volumes/Zurg
rclone_extra_args:
- "--vfs-cache-max-size"
- "100G"
- "--vfs-cache-min-free-space"
- "20G"
directories:
shows:
group: media
group_order: 10
filters:
- has_episodes: true
movies:
group: media
group_order: 20
only_show_the_biggest_file: true
EOF
Replace the placeholder token with your actual token from real-debrid.com/apitoken:
sed -i '' "s|YOUR_RD_API_TOKEN_HERE|PASTE_YOUR_TOKEN_HERE|g" ~/zurg/config.yml
Do not drop
mount_path. rclone would fall back to/Volumes/Zurgon macOS without it, but media-server scanning is only enabled whenmount_pathis set explicitly — leave it out and Plex never gets told to refresh (Step 6).
Cache sizing is critical. The VFS cache stores chunks of streamed files on your local disk. If it fills your drive, macOS performance will degrade severely — Spotlight, Plex, and even the OS itself can become unresponsive. Always set both limits:
--vfs-cache-max-size— hard cap on total cache size. Set this to no more than 50% of your free disk space. Check withdf -h /.--vfs-cache-min-free-space— stops caching when free space drops below this. Keep at 20G or higher as a safety net.For example, on a 256GB drive with 100GB free, use
50Gmax size and20Gmin free space.
Step 4: Download dependencies manually
Zurg has a built-in command that downloads rclone and ffprobe and updates config.yml with their paths:
cd ~/zurg
./zurg download-requirements
Create the mount point and the log directory. /Volumes is owned by root, so zurg cannot create /Volumes/Zurg itself; the log directory has to exist before launchd opens its output files in Step 7:
sudo mkdir -p /Volumes/Zurg
sudo chown "$(whoami)" /Volumes/Zurg
mkdir -p ~/zurg/logs
See the configuration reference for all available options, or use the web Dashboard at http://localhost:9999/config/ after starting zurg.
Step 5: Test zurg manually
Before setting up auto-start, verify everything works:
cd ~/zurg && ./zurg
You should see log output showing zurg starting up, connecting to Real-Debrid, and mounting via rclone. In another terminal window, check:
# Check the HTTP endpoint
curl -s http://localhost:9999/http/version.txt
# Check the mount
ls /Volumes/Zurg/
# Expected: __all__ __downloads__ __realdebrid__ __unplayable__ movies shows version.txt
If everything looks good, stop zurg with Ctrl+C.
Step 6: Install Plex Media Server
- Download from plex.tv/media-server-downloads — select macOS (Universal)
- Open the
.dmgand drag Plex Media Server into/Applications - Launch Plex Media Server from Applications (or Spotlight:
Cmd + Space→ "Plex Media Server") - Your browser should open to the Plex setup wizard — follow it to claim your server
- Enable auto-start: Right-click the Plex icon in the menu bar and check Launch at Login
- Get your Plex token — the easiest way:
- Open any media item in Plex Web
- Click Get Info (or ... → Get Info)
- Click View XML
- Look for
X-Plex-Token=in the URL bar
Add the Plex token to your zurg config by editing config.yml:
plex_server_url: http://localhost:32400
plex_token: YOUR_PLEX_TOKEN
Step 7: Set up zurg auto-start manually
macOS LaunchAgents start services automatically when you log in. Plex already handles its own auto-start (Step 6), so we only need a LaunchAgent for zurg.
Zurg LaunchAgent
cat > ~/Library/LaunchAgents/com.zurg.plist << PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.zurg</string>
<key>ProgramArguments</key>
<array>
<string>${HOME}/zurg/zurg</string>
</array>
<key>WorkingDirectory</key>
<string>${HOME}/zurg</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>StandardOutPath</key>
<string>${HOME}/zurg/logs/launchd-stdout.log</string>
<key>StandardErrorPath</key>
<string>${HOME}/zurg/logs/launchd-stderr.log</string>
<key>ThrottleInterval</key>
<integer>10</integer>
</dict>
</plist>
PLIST
Key settings:
- RunAtLoad — starts zurg when you log in
- KeepAlive / SuccessfulExit: false — if zurg crashes, launchd automatically restarts it
- ThrottleInterval: 10 — waits 10 seconds between restart attempts
Load the LaunchAgent
launchctl load ~/Library/LaunchAgents/com.zurg.plist
Verify it is registered:
launchctl list | grep zurg
# Should show com.zurg with a PID
Step 8: Configure Plex Libraries
Now that zurg is running and the mount is active:
- Open http://localhost:32400/web
- Go to Settings (wrench icon) → Manage → Libraries
- Click Add Library
Add Movies library:
- Type: Movies
- Click Browse for media folder
- Navigate to
/Volumes/Zurg/movies - Click Add Library
Add TV Shows library:
- Type: TV Shows
- Click Browse for media folder
- Navigate to
/Volumes/Zurg/shows - Click Add Library
Recommended library settings (under each library's Edit → Advanced):
- Uncheck Empty trash automatically after every scan — zurg manages content lifecycle
- Uncheck Generate video preview thumbnails — saves bandwidth since files are streamed from Real-Debrid
Step 9: Verify Everything Works
# 1. Zurg is running
curl -s http://localhost:9999/http/version.txt && echo " - Zurg is up"
# 2. Mount is active
ls /Volumes/Zurg/movies > /dev/null 2>&1 && echo "Mount is active"
# 3. Plex is running
curl -s -o /dev/null -w "%{http_code}" http://localhost:32400/identity && echo " - Plex is up"
# 4. Processes
ps -eo pid,command | grep -E "[z]urg|[r]clone.*mount|[P]lex Media Server" | head -5
# 5. Zurg service
cd ~/zurg && ./zurg service status
Step 10: Enable Auto-Login (Optional)
This is only needed for the manual LaunchAgent path. A LaunchAgent requires a user to log in after each reboot. The built-in installer uses a LaunchDaemon on a headless Mac instead.
If you deliberately use the manual LaunchAgent on a headless server, enable auto-login so it starts unattended:
- Open System Settings
- Go to Users & Groups
- Click Automatic login and select your user
- Enter your password
Security note: Auto-login means anyone with physical access to the Mac can access your account. Only use this on machines in a trusted location.
Managing the Services
For an install created by zurg setup, use the same commands on every platform:
cd ~/zurg
./zurg service status
./zurg service restart
./zurg service stop
./zurg service start
./zurg service uninstall
uninstall removes auto-start only. It leaves the binary, config, data, logs and cache in place. The launchctl commands below are the manual equivalents.
Start / Stop / Restart
# Stop zurg (and its rclone child process)
launchctl stop com.zurg
# Start zurg
launchctl start com.zurg
# Restart zurg
launchctl stop com.zurg && sleep 2 && launchctl start com.zurg
View Logs
# Zurg logs
tail -50 ~/zurg/logs/launchd-stdout.log
# Rclone logs
tail -50 ~/zurg/logs/rclone.log
Reload After Config Change
If you edit a .plist file:
launchctl unload ~/Library/LaunchAgents/com.zurg.plist
launchctl load ~/Library/LaunchAgents/com.zurg.plist
If you edit config.yml, just restart zurg:
cd ~/zurg && ./zurg service restart
Update Zurg
A sponsor build replaces itself:
cd ~/zurg
./zurg update
./zurg service restart
update takes the newest nightly. It downloads it, checks the new binary reports the version it expected, and only then swaps it in by rename, so the running process is never overwritten. When the installed build is already the newest it says so and changes nothing.
update signs in to GitHub with the account you used for the install. The installer keeps the GitHub CLI in ~/zurg/bin for that. If update says it found no GitHub credential then your install is older than that change. Run the installer's update once and every zurg update after it works. The same command also updates a build too old to have zurg update.
curl -fsSL https://raw.githubusercontent.com/debridmediamanager/zurg-site/main/public/install.sh | bash -s update
You can also set GITHUB_TOKEN instead. Use a classic token with the repo scope from the GitHub account that has zurg access.
By hand, download the new darwin-arm64 zip from Releases the same way as in Step 2, then:
cd ~/zurg
./zurg service stop && sleep 2
rm -f zurg
unzip -o ~/Downloads/zurg-*-darwin-arm64.zip
chmod +x zurg
./zurg service start
Delete the old binary rather than overwriting it in place. Rewriting the file keeps the same inode and invalidates its ad-hoc code signature, and macOS then kills the new build on exec — the symptom is an immediate exit with no output at all. zurg update swaps by rename for exactly this reason.
Troubleshooting
"Operation not permitted" when mounting
macFUSE needs to be approved in System Settings:
- Go to System Settings > Privacy & Security
- Scroll down and look for a blocked system extension message
- Click Allow, then reboot
Mount shows as "not a directory" or hangs
The mount point may be stale from a previous crash:
umount -f /Volumes/Zurg 2>/dev/null
diskutil unmount force /Volumes/Zurg 2>/dev/null
launchctl stop com.zurg && sleep 2 && launchctl start com.zurg
Zurg keeps restarting (crash loop)
Check the logs for the error:
tail -100 ~/zurg/logs/launchd-stderr.log
Common causes:
- Invalid
config.ymlsyntax — validate withcd ~/zurg && ./zurgmanually - Expired Real-Debrid token — get a new one from real-debrid.com/apitoken
/Volumes/Zurgmissing or not owned by your user — zurg cannot create it and fails withensure mount path: permission denied(Step 4)- Port 9999 already in use — check with
lsof -i :9999
macFUSE breaks after macOS update
Major macOS updates sometimes invalidate the kernel extension. Reinstall macFUSE:
- Download the latest version from macfuse.io
- Install it
- Approve the extension in System Settings > Privacy & Security
- Reboot
Everything was working but stopped after reboot
If you installed the manual LaunchAgent and auto-login is not enabled, you must log in before it starts. Either:
- Enable auto-login (see Step 10)
- SSH in — the LaunchAgents will already be loaded once the user session exists
- Use VNC/Screen Sharing to log in remotely
An install created by zurg setup on a headless Mac uses a LaunchDaemon and does not need a GUI login. Check it with cd ~/zurg && ./zurg service status.
Architecture Overview
launchd (PID 1)
com.zurg LaunchAgent
└── ./zurg
├── HTTP/WebDAV server (:9999)
├── Dashboard UI (:9999/config/)
├── Real-Debrid API client
└── rclone mount (child process)
└── /Volumes/Zurg/
├── movies/
└── shows/
Plex Media Server (:32400) — Launch at Login via menu bar
├── Movies library → /Volumes/Zurg/movies
└── Shows library → /Volumes/Zurg/shows
macFUSE kernel extension
└── Enables FUSE mounts for rclone