> This page is for NeMo Relay, version v0.10.4.
> For other versions, use one of these documentation indexes:
> - Latest (v0.10.4) (default): https://docs.nvidia.com/nemo/relay/latest/llms.txt
> - dev: https://docs.nvidia.com/nemo/relay/dev/llms.txt
> - v0.10.4: https://docs.nvidia.com/nemo/relay/v0.10.4/llms.txt
> - v0.9.4: https://docs.nvidia.com/nemo/relay/v0.9.4/llms.txt
> - v0.8.4: https://docs.nvidia.com/nemo/relay/v0.8.4/llms.txt
> - v0.7.3: https://docs.nvidia.com/nemo/relay/v0.7.3/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nemo/relay/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/nemo/relay/_mcp/server.

# macOS Deployment

> Run a local daemon with a user LaunchAgent or system LaunchDaemon.

Use a LaunchAgent for a daemon that runs while one user is logged in. Use a
LaunchDaemon for a shared daemon that starts at boot. These examples use the
supported Apple Silicon binary and require administrator access for shared files.

## Prepare the Mac

Install a verified binary using [Installation](/getting-started/installation),
then copy it to a fixed administrator-owned path:

```bash
sudo install -d -m 0755 /opt/nvidia/bin
sudo install -m 0755 "$(command -v nemo-relay)" /opt/nvidia/bin/nemo-relay
/opt/nvidia/bin/nemo-relay daemon --help
```

Complete [Configuration and Managed Clients](/daemon/configuration). Use
`/opt/nvidia/bin/nemo-relay` as the dispatcher and `http://127.0.0.1:47632` as the
bundle endpoint. Choose one of the two launchd jobs below.

## User LaunchAgent

Create directories as the target user:

```bash
mkdir -p "$HOME/Library/LaunchAgents" "$HOME/Library/Logs/NeMoRelay"
mkdir -p "$HOME/.config/nemo-relay/daemon"
chmod 700 "$HOME/.config/nemo-relay/daemon" "$HOME/Library/Logs/NeMoRelay"
```

Save the following as
`~/Library/LaunchAgents/com.nvidia.nemo-relay.daemon.plist`.
Replace `/Users/alex` with the user's absolute home path in all three locations.
launchd does not expand `~` or shell variables inside a plist.

```xml
<?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.nvidia.nemo-relay.daemon</string>
  <key>ProgramArguments</key>
  <array>
    <string>/opt/nvidia/bin/nemo-relay</string><string>daemon</string>
    <string>--bind</string><string>127.0.0.1</string>
    <string>--port</string><string>47632</string>
  </array>
  <key>EnvironmentVariables</key>
  <dict><key>XDG_CONFIG_HOME</key><string>/Users/alex/.config</string></dict>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>ThrottleInterval</key><integer>5</integer>
  <key>ExitTimeOut</key><integer>150</integer>
  <key>Umask</key><integer>63</integer>
  <key>StandardOutPath</key><string>/Users/alex/Library/Logs/NeMoRelay/daemon.out.log</string>
  <key>StandardErrorPath</key><string>/Users/alex/Library/Logs/NeMoRelay/daemon.err.log</string>
</dict>
</plist>
```

Load and inspect the job from that user's desktop login session:

```bash
chmod 644 "$HOME/Library/LaunchAgents/com.nvidia.nemo-relay.daemon.plist"
plutil -lint "$HOME/Library/LaunchAgents/com.nvidia.nemo-relay.daemon.plist"
launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.nvidia.nemo-relay.daemon.plist"
launchctl print "gui/$(id -u)/com.nvidia.nemo-relay.daemon"
tail -n 50 "$HOME/Library/Logs/NeMoRelay/daemon.err.log"
```

The job starts again at login. It is not a boot-time service for logged-out users.
For multiple simultaneous user daemons, assign separate ports and bundles.

## System LaunchDaemon

Use a dedicated hidden service account called `_nemo-relay`. Check that the name
is unused and select an unused numeric ID. The following example uses `499`;
check both listings before using it and replace it if occupied:

```bash
dscl . -list /Users UniqueID
dscl . -list /Groups PrimaryGroupID
```

As an administrator, create the account and its private home:

```bash
sudo dscl . -create /Groups/_nemo-relay
sudo dscl . -create /Groups/_nemo-relay PrimaryGroupID 499
sudo dscl . -create /Users/_nemo-relay
sudo dscl . -create /Users/_nemo-relay UniqueID 499
sudo dscl . -create /Users/_nemo-relay PrimaryGroupID 499
sudo dscl . -create /Users/_nemo-relay UserShell /usr/bin/false
sudo dscl . -create /Users/_nemo-relay NFSHomeDirectory /var/lib/nemo-relay
sudo dscl . -create /Users/_nemo-relay IsHidden 1
sudo dscl . -create /Users/_nemo-relay Password '*'
sudo install -d -o _nemo-relay -g _nemo-relay -m 0700 /var/lib/nemo-relay
sudo install -d -o _nemo-relay -g _nemo-relay -m 0700 /var/lib/nemo-relay/.config
sudo install -d -o _nemo-relay -g _nemo-relay -m 0700 /Library/Logs/NeMoRelay
```

Save `/Library/LaunchDaemons/com.nvidia.nemo-relay.daemon.plist`:

```xml
<?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.nvidia.nemo-relay.daemon</string>
  <key>UserName</key><string>_nemo-relay</string>
  <key>GroupName</key><string>_nemo-relay</string>
  <key>WorkingDirectory</key><string>/var/lib/nemo-relay</string>
  <key>ProgramArguments</key>
  <array>
    <string>/opt/nvidia/bin/nemo-relay</string><string>daemon</string>
    <string>--bind</string><string>127.0.0.1</string>
    <string>--port</string><string>47632</string>
  </array>
  <key>EnvironmentVariables</key>
  <dict><key>XDG_CONFIG_HOME</key><string>/var/lib/nemo-relay/.config</string></dict>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>ThrottleInterval</key><integer>5</integer>
  <key>ExitTimeOut</key><integer>150</integer>
  <key>Umask</key><integer>63</integer>
  <key>StandardOutPath</key><string>/Library/Logs/NeMoRelay/daemon.out.log</string>
  <key>StandardErrorPath</key><string>/Library/Logs/NeMoRelay/daemon.err.log</string>
</dict>
</plist>
```

Set ownership and start it:

```bash
sudo chown root:wheel /Library/LaunchDaemons/com.nvidia.nemo-relay.daemon.plist
sudo chmod 644 /Library/LaunchDaemons/com.nvidia.nemo-relay.daemon.plist
plutil -lint /Library/LaunchDaemons/com.nvidia.nemo-relay.daemon.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.nvidia.nemo-relay.daemon.plist
sudo launchctl print system/com.nvidia.nemo-relay.daemon
sudo tail -n 50 /Library/Logs/NeMoRelay/daemon.err.log
```

Hooks run as each user and check the daemon's TLS certificate before they send
anything. They cannot read the service account's files, so publish the
certificate, never the key, in the system configuration directory. Export it
as the service account with the service's environment:

```bash
sudo install -d -o root -g wheel -m 0755 /etc/nemo-relay
sudo -u _nemo-relay env HOME=/var/lib/nemo-relay XDG_CONFIG_HOME=/var/lib/nemo-relay/.config \
  /opt/nvidia/bin/nemo-relay daemon tls-certificate \
  | sudo tee /etc/nemo-relay/hook-tls-certificate.pem > /dev/null
sudo chown root:wheel /etc/nemo-relay/hook-tls-certificate.pem
sudo chmod 644 /etc/nemo-relay/hook-tls-certificate.pem
```

The certificate stays the same across restarts and upgrades. Publish it again
only if the service identity under
`/var/lib/nemo-relay/.config/nemo-relay/bootstrap` is removed.

The service identity lives under `/var/lib/nemo-relay/.config/nemo-relay/daemon`.
Keep it across upgrades. User workers still load `/etc/nemo-relay`, and their
identities remain in each user's config directory.

## Verify, Restart, and Remove

Check daemon health and assigned workers, then complete
[worker-backed verification](/daemon/operations#verify-worker-backed-operation):

```bash
curl -f http://127.0.0.1:47632/healthz
curl -f http://127.0.0.1:47632/_nemo_relay/v1/workers/status
lsof -nP -iTCP:47632 -sTCP:LISTEN
```

Restart after a binary update with the command for your job:

```bash
launchctl kickstart -k "gui/$(id -u)/com.nvidia.nemo-relay.daemon"
# For the system job instead:
sudo launchctl kickstart -k system/com.nvidia.nemo-relay.daemon
```

Close harness sessions before restarting. For plist changes, unload the job with
`bootout`, then run its `bootstrap` command again. Test a planned logout/login
or reboot. Configure your log rotation tool for the two log files; launchd's
file redirection does not itself bound their size.

To remove a user job:

```bash
launchctl bootout "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.nvidia.nemo-relay.daemon.plist"
rm "$HOME/Library/LaunchAgents/com.nvidia.nemo-relay.daemon.plist"
```

To remove a system job:

```bash
sudo launchctl bootout system /Library/LaunchDaemons/com.nvidia.nemo-relay.daemon.plist
sudo rm /Library/LaunchDaemons/com.nvidia.nemo-relay.daemon.plist
```

Retain the identity directory and service account for rollback. Follow
[Operations](/daemon/operations) for upgrades and complete removal.
Apple's [launchd guide](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html)
explains the LaunchAgent and LaunchDaemon file layout.