| name | mac-mini-as-headless-server |
| description | Use when setting up a Mac (especially Mac Mini or Apple Silicon Mac Studio) for unattended 24/7 server operation, headless use, or remote-only access. Covers sleep prevention, screen saver, Wake-on-LAN, auto-restart, App Nap, SSH enablement, and โ on Apple Silicon โ a caffeinate LaunchDaemon that stops the headless display from parking (physical panel and VNC/screen-share going black even with displaysleep=0). Targets macOS 15 (Sequoia) and later. |
Configure macOS for Server Use
Overview
Configures macOS for unattended 24/7 server operation by disabling sleep, screen saver, and App Nap, while enabling Wake-on-LAN, auto-restart after power failure, and SSH remote login. The screen lock lives in the user keybag and changing it requires the user's account password (root alone can't), so the script verifies it, offers to turn it off when run interactively (you type the user's password once), and prints the exact CLI/GUI fix on unattended runs.
Requires sudo. Targets macOS 15 (Sequoia) and later. Target hardware: Mac Mini, Mac Studio, or any Mac used as a headless server.
Apple Silicon caveat: on an Apple Silicon Mac with no local keyboard/mouse, pmset displaysleep 0 is not enough. WindowServer still parks the physical display (DPMS off ~30s after each wake), which turns the panel black and makes RealVNC / screen-capture sessions show black, because they capture the physical display. The only reliable fix is to hold a PreventUserIdleDisplaySleep assertion continuously โ this skill installs a caffeinate -d LaunchDaemon (step 7) for that.
When to Use
- Setting up a Mac as a home server, CI runner, or always-on machine
- Preparing a Mac Mini for headless/remote-only operation
- Troubleshooting a Mac that keeps sleeping, locking, or becoming unreachable
- Fixing a headless Apple Silicon Mac whose physical display or VNC/screen-share session goes black despite
displaysleep 0
Quick Reference
| Setting | Command | Effect |
|---|
| Screen saver off | defaults -currentHost write com.apple.screensaver idleTime -int 0 | Disables screen saver activation |
| System sleep off | pmset -c sleep 0 | Never sleep |
| Display sleep off | pmset -c displaysleep 0 | Never turn off display |
| Disk sleep off | pmset -c disksleep 0 | Never spin down disks |
| Dim before sleep off | pmset -c halfdim 0 | No pre-sleep dimming (absent/no-op on some modern Macs โ not listed in their pmset -g custom) |
| Wake-on-LAN | pmset -c womp 1 | Wake on network access |
| Auto-restart | pmset -c autorestart 1 | Restart after power loss |
| App Nap off | defaults write NSGlobalDomain NSAppSleepDisabled -bool YES | Prevents app throttling |
| SSH on | systemsetup -setremotelogin on | Enables Remote Login โ needs Full Disk Access; confirm with -getremotelogin |
| Keep display awake (Apple Silicon) | caffeinate -d via LaunchDaemon | Holds PreventUserIdleDisplaySleep โ stops the headless display park that displaysleep 0 does not prevent (panel + VNC go black) |
| Screen lock status | sysadminctl -screenLock status | Reports lock state โ no sudo needed |
| Screen lock off | sysadminctl -screenLock off -password - | Needs the user's account password (user keybag) โ root/sudo alone can't change it. Scriptable form: -password 'pw'. Step 8 runs the interactive form for you on TTY runs |
Implementation
Run the bundled script as root, via sudo from the target user's account (it refuses to run from a bare root shell so per-user defaults land in the right account):
sudo bash scripts/setup.sh
What it does, in order:
- Screen saver off โ
idleTime 0, per-user
- All sleep off โ
pmset -c sleep/displaysleep/disksleep/halfdim 0
- Wake-on-LAN โ
womp 1
- Auto-restart after power failure โ
autorestart 1
- App Nap off โ per-user global default
- SSH on โ
systemsetup -setremotelogin on; needs Full Disk Access and can fail while exiting 0, so trust the verify output, not this step
- Keep-display-awake LaunchDaemon โ writes
/Library/LaunchDaemons/com.local.keepdisplayawake.plist running caffeinate -d (RunAtLoad + KeepAlive, survives reboots), loads it, then fires caffeinate -u -t 2 to wake an already-parked panel. Follows with a verification dump: pmset -g, daemon state (want a PID), display assertion (want caffeinate listed), and systemsetup -getremotelogin (want On)
- Screen lock โ checks
sysadminctl -screenLock status (no sudo needed). On an interactive (TTY) run it prompts once for the user's account password and turns the lock off in place; unattended runs get the manual GUI/CLI instructions instead
Common Mistakes
- Running without sudo โ
pmset and systemsetup require root; defaults commands must run as the real user via sudo -u
- Omitting the power-source flag โ
pmset defines -a (all), -b (battery), -c (charger), -u (UPS); the man page doesn't say which profile a flagless write targets, so be explicit โ -c (or -a) on a desktop
- Expecting immediate effect โ Screen saver and lock-screen changes may require logout/restart
- FileVault blocking auto-login โ Auto-login (System Settings > Users & Groups > Login Options) requires FileVault off
- Trusting
systemsetup -setremotelogin on โ it requires Full Disk Access (per man systemsetup) and historically exits 0 even on failure, so a plain run can silently do nothing. Always confirm with systemsetup -getremotelogin (the script prints it in the verify block)
- Relying on
pmset displaysleep 0 alone on Apple Silicon โ it does not stop the headless display park; you need the caffeinate -d LaunchDaemon (step 7). Symptom: the physical panel and/or VNC session is black even though pmset -g shows displaysleep 0.
- Expecting
caffeinate -d to wake a black screen โ -d only prevents sleep; it won't wake an already-parked panel. Fire a one-shot caffeinate -u -t 2 to wake it (step 7 does this after loading the daemon).
- Running a bare
caffeinate -d instead of the LaunchDaemon โ an orphaned/nohup'd caffeinate holds the assertion until the next reboot, then silently dies and the display parks again. Use the LaunchDaemon (step 7) so it comes back at boot.
- Trying to disable the screen lock with
defaults write com.apple.screensaver askForPassword -int 0 โ ignored since macOS 10.13 High Sierra, though old blog posts still recommend it. The setting lives in the user keybag (MobileKeyBag) and changing it needs the user's account password โ root/sudo alone can't do it, but it is scriptable if you supply the password: sysadminctl -screenLock off -password 'pw' (or -password - to be prompted). Verify with sysadminctl -screenLock status โ no sudo needed (step 8). For fleets, an MDM configuration profile with the com.apple.screensaver payload is the hands-off alternative.
Reverting
To restore display sleep later:
sudo pmset -c displaysleep 10
To remove the keep-display-awake LaunchDaemon (step 7):
sudo launchctl bootout system /Library/LaunchDaemons/com.local.keepdisplayawake.plist
sudo rm /Library/LaunchDaemons/com.local.keepdisplayawake.plist
To re-enable the screen lock (as the user, no sudo; prompts for the account password):
sysadminctl -screenLock immediate -password -