Skip to navigation

macOS Deployment

View as Markdown

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, then copy it to a fixed administrator-owned path:

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. 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:

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 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:

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:

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

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

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 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:

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:

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:

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:

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:

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:

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 for upgrades and complete removal. Apple’s launchd guide explains the LaunchAgent and LaunchDaemon file layout.