rapid-mlx serviceRun at boot on a headless Mac
One command registers Rapid-MLX as a system LaunchDaemon, so a Mac used as an inference appliance serves your model after every boot — before anyone logs in — and restarts the server if it exits.
$ sudo rapid-mlx service install --service-user serveuser \ --model qwen3.5-4b-4bit --host 127.0.0.1 --port 8000 $ rapid-mlx service status
serveuser is a dedicated, non-administrator account that
already has Rapid-MLX installed and the model downloaded — set that up
first (step 1 below). Rehearse with --dry-run to print every
step without changing anything.
Before you begin
- An Apple Silicon Mac on macOS 14 (Sonoma) or later, and administrator access.
- A dedicated, non-administrator local account for the service.
service installrefuses root and admin accounts and does not create users. - Physical or out-of-band access while you set it up.
FileVault matters. A LaunchDaemon starts without a GUI login only after the data volume is unlocked. After a cold boot, a FileVault-protected Mac can wait at the preboot unlock screen, where neither SSH nor Rapid-MLX can start. Decide your encryption and unattended-recovery policy deliberately.
Multi-interface Macs. If the Mac also has a private Ethernet or
Thunderbolt link, check that the internet default route is still the
one you expect (route -n get default) before installing or
upgrading — otherwise downloads fail while SSH still works.
1. Prepare the service account
Log in as the service account (with a display attached) and run, without sudo:
$ curl -fsSL https://rapidmlx.com/install.sh | bash $ export PATH="$HOME/.local/bin:$PATH" $ rapid-mlx doctor $ rapid-mlx serve qwen3.5-4b-4bit --host 127.0.0.1 --port 8000
Let the first download finish, check that the server answers, then stop
it. The daemon runs as this account, so its HOME, virtual
environment and ~/.cache/huggingface/hub are the ones you
just prepared.
2. Install the service
From an administrator session:
$ sudo rapid-mlx service install --service-user serveuser \ --model qwen3.5-4b-4bit --host 127.0.0.1 --port 8000 --dry-run $ sudo rapid-mlx service install --service-user serveuser \ --model qwen3.5-4b-4bit --host 127.0.0.1 --port 8000
install validates the account, writes a root-owned plist to
/Library/LaunchDaemons/com.rapidmlx.server.plist and
bootstraps it into the system domain. The plist only runs a stable
service run --config … command; the real definition is a
versioned, root-owned JSON file under
/Library/Application Support/Rapid-MLX/Services/, outside
the Python environment, so rebuilding the venv leaves it untouched. It
refuses to embed a secret, and refuses to install if a server already
answers on the target port.
Pass extra non-secret serve flags after --, for
example -- --max-num-seqs 4. Use the service's own
--host and --port for binding.
Day-to-day
$ rapid-mlx service status # registration, pid, health, model residency $ rapid-mlx service status --json # the same, machine-readable $ rapid-mlx service logs --follow # stream logs across restarts $ sudo rapid-mlx service restart # kickstart and wait until healthy
Logs rotate automatically: 100 MiB per stream, five backups and
seven days by default (change them with service configure
--log-max-mb, --log-backup-count and
--log-retention-days).
Change the model or flags
Changes are a two-step transaction. configure validates and
stages a candidate without touching the running server;
apply starts it, requires /readyz to report the
configured model loaded, and restores the previous definition if
anything fails.
$ sudo rapid-mlx service configure --model qwen3.5-9b-4bit --port 9000 -- --max-num-seqs 8 $ sudo rapid-mlx service apply --dry-run $ sudo rapid-mlx service apply $ rapid-mlx service config # active and pending definitions
configure --clear-serve-args removes all extra serve flags.
Changing the service account or executable needs
uninstall + install.
Keep the endpoint up without pinning memory. Pass the standby
policy through to serve; the first request reloads the
configured model:
$ sudo rapid-mlx service configure --model qwen3.5-9b-4bit -- \ --lazy-load --idle-unload-seconds 1800 $ sudo rapid-mlx service apply
In standby /readyz stays green; /health and
service status show whether the weights are loaded. A
request can only wake the model fixed in the service definition — it
cannot pick another repository or start a download.
Keep the endpoint private
The service binds to 127.0.0.1. Reach it from another
computer through an SSH tunnel:
$ ssh -L 8000:127.0.0.1:8000 serveuser@your-mac
To require an API key, send it over stdin into a mode-600 credential file — it never appears in arguments, the plist, shell history or status output:
$ security find-generic-password -w -s rapid-mlx-api-key | \ sudo rapid-mlx service credential set $ sudo rapid-mlx service restart $ rapid-mlx service credential status
sudo rapid-mlx service credential unset plus a restart turns
authentication off. For LAN or internet access, keep Rapid-MLX on
loopback behind a separately managed TLS-terminating, authenticating
reverse proxy. Have the proxy send a loopback Host header to Rapid-MLX,
or allow its forwarded Host with --trusted-hosts. If a
browser frontend uses a different origin, allow that origin with
--cors-origins.
Upgrade with automatic rollback
$ sudo rapid-mlx service upgrade --dry-run $ sudo rapid-mlx service upgrade --extras vision,embeddings
upgrade freezes the working environment, upgrades as the
service account, runs doctor, and accepts the new version
only when launchd's /readyz reports the configured model
loaded. Otherwise it restores the frozen environment and restarts the
previous service. --extras re-asserts the optional extras
the appliance needs; --version pins an exact release.
Verify recovery
$ curl -fsSLo headless_service_smoke.sh \ https://raw.githubusercontent.com/raullenchai/Rapid-MLX/main/scripts/headless_service_smoke.sh $ chmod +x headless_service_smoke.sh $ export RAPID_MLX_SERVICE_USER=serveuser $ export RAPID_MLX_SMOKE_MODEL=default $ ./headless_service_smoke.sh
The smoke test checks the system-domain job, process owner, liveness,
readiness, model inventory and a real one-token completion, waiting up
to 120 seconds for readiness. For an authenticated service, export
RAPID_MLX_API_KEY first. Then turn automatic login off,
reboot with recovery access available, leave the Mac at the login
window, and run it again remotely.
For desktop Macs that must come back after a power cut:
$ pmset -g custom $ sudo pmset -a sleep 0 autorestart 1
This requests a restart when AC power returns; it does not bypass FileVault. If outage recovery is a hard requirement, run a controlled power-loss test at the site.
Remove the service
$ rapid-mlx service uninstall --dry-run $ sudo rapid-mlx service uninstall
uninstall boots the daemon out and removes the plist. The
service account, model cache, Python environment and logs stay.
The engine's headless service guide also documents the manual LaunchDaemon setup the CLI automates, for recovery or custom deployments.