ServerShelf 1.6.0 for macOS is out. Until now the checks ran while the app was open. Close it, and the uptime polls, the sensor readings, the TLS expiry watch and the notifications stopped with it. That is fine on a laptop and wrong on the Mac mini in the cupboard that is on anyway. This release adds a mode for that machine.
The service
servershelf --headless starts the same binary with no window and no Dock icon. It unlocks the vault by itself and then runs everything the desktop app runs in the background: uptime checks, hardware sensors, TLS expiry, patch schedules, the heartbeat ping, every notification channel and the companion server for the phone. The menu bar icon is still there, and its "Open" item builds the window when you want to look.
On macOS that is a LaunchAgent. Replace YOU with your login name, because launchd expands neither ~ nor $HOME, and create the log directory first: launchd will not do that either.
mkdir -p ~/Library/Logs/ServerShelf
cat > ~/Library/LaunchAgents/app.servershelf.headless.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>app.servershelf.headless</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/ServerShelf.app/Contents/MacOS/servershelf</string>
<string>--headless</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<dict><key>Crashed</key><true/></dict>
<key>StandardOutPath</key>
<string>/Users/YOU/Library/Logs/ServerShelf/headless.log</string>
<key>StandardErrorPath</key>
<string>/Users/YOU/Library/Logs/ServerShelf/headless.log</string>
<key>ProcessType</key>
<string>Background</string>
</dict>
</plist>
PLIST
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/app.servershelf.headless.plist
tail -f ~/Library/Logs/ServerShelf/headless.log
One line per start lands in that log: the version, the number of uptime checks, the poll interval, and that the other loops are running. A vault with a passphrase needs two more entries in ProgramArguments: --passphrase-file and the path. A LaunchAgent needs a logged-in user; for a machine that should watch before anyone logs in, switch on automatic login for that account.
On Linux it is a user unit with ExecStart=/usr/bin/servershelf --headless, wrapped in xvfb-run -a on a box without a display. Both templates ship in the repository under tools/headless/, together with the longer write-up.
Which vault the service can open
A quick-start vault needs nothing: the session key sits next to the database. A vault with a passphrase reads it from the file behind --passphrase-file or from SERVERSHELF_PASSPHRASE. The file has to be a regular file that belongs to the service user, is unreadable for everyone else and stays small. Anything else is refused instead of quietly accepted. The environment variable is read once at start and removed from the environment, so none of the programs ServerShelf runs later inherits it.
There is no third way in. Nobody is at the keyboard, so a wrong passphrase does not open a dialog: the service says what is wrong and exits with status 2, which launchd and systemd report as a failed start. Touch ID and the idle auto-lock stay out of a headless run for the same reason.
One process per machine
Two ServerShelf processes on one database would keep two encrypted connections open and run every check twice. So a second start now hands over instead: open the app while the service runs and you get the service's own window, close it again and the checks keep going. A servershelf:// link behaves the same way.
Stopping
A service stop sends SIGTERM. ServerShelf catches it, writes the backup outside the app folder that a normal quit writes, and exits after that — so the copy you would want after a crash is there.
Compatibility
Nothing changes for the desktop app: same database, same encryption, same window. Headless needs a vault that was set up once with a window, because that setup asks questions a service cannot answer. Windows and Linux builds follow through the usual pipeline; the templates and the handover are written for them, but this release was tested on macOS.