zm-api ships passive so that installing it cannot disturb a running ZoneMinder. That is a starting point, not a destination: takeover is where zm-api is meant to end up. Passive exists so you choose when to switch, on your own schedule, with a one-command way back.
daemon.enabled = false. zm-api serves the REST API. zoneminder.service keeps
supervising zmdc.pl, zmc, zmfilter and the rest, exactly as before zm-api
was installed. Installing the package changes nothing about how ZoneMinder
records, which is what makes it safe to drop onto a live box.
zm-api reads and controls ZoneMinder's daemons the way ZoneMinder's own web UI
does, through zmdc.pl's zmdc.sock:
GET /api/v3/daemons*andGET /api/v3/system/statuslist whatzmdc.plsupervises, with this host's load, memory and disk.POST /api/v3/daemons/{id}/start|stop|restart|reloadsend that command tozmdc.pl.- Creating, editing and deleting a monitor, and
PATCH /api/v3/monitors/{id}/state, start, restart and stop itszmc(andzmcontrol.plfor a controllable monitor) as ZoneMinder's API does.
/api/v3/system/startup, shutdown and restart still need takeover; in
passive mode zoneminder.service owns that.
daemon.enabled = true. zm-api supervises the ZoneMinder daemons itself,
replacing both zmdc.pl and zmwatch.pl with one native supervisor.
This is an upgrade, not a lateral move. What you gain:
- One supervisor instead of two processes. ZoneMinder runs
zmdc.plto start daemons andzmwatch.plto poll whether the capture daemons are still healthy. zm-api does both in its own health-check loop, so there is no second Perl daemon whose own death goes unnoticed. - Exponential backoff with recovery. A daemon that crashes repeatedly backs off between restarts rather than being restarted at a fixed interval forever, and the backoff resets once it has stayed up. A camera that is genuinely unreachable stops generating restart churn.
- Reconciliation against the database. A loop syncs running daemons with
what the
Monitorstable says should be running, so enabling or disabling a monitor through the API takes effect without a separate restart cycle. - Daemon control over the REST API. Start, stop, and query daemons through
/api/v3/daemons*instead of shelling out tozmdc.pl. - Structured logging. Supervision events go to the journal alongside everything else zm-api logs, rather than into ZoneMinder's own log tables and files.
The legacy zmdc.sock IPC shim is still bound, so tooling that talks to
zmdc.pl keeps working.
Exactly one supervisor may run. On startup in takeover mode zm-api runs
kill_orphan_daemons(), which pkill -9s zmc, zma, zmfilter.pl and
friends before starting its own. Leaving zoneminder.service enabled means two
supervisors killing and restarting each other's processes: daemons that restart
in a loop and events that record erratically. zm-api-takeover handles the
ordering for you — that is the whole reason it exists.
sudo zm-api-takeover # take over
sudo zm-api-takeover --revert # hand backThe script sequences both services correctly — disable and stop
zoneminder.service, flip the flag, restart zm-api; and the reverse on the way
back. Prefer it over editing APP_DAEMON__ENABLED by hand.
It also guards the switch on both sides:
- Before, it checks that zm-api is up in passive mode, runs as ZoneMinder's
account, can read
zm.conf, can write the events, socket and log directories, and can executezmc.sudo zm-api-takeover --checkruns only these checks and changes nothing. A failure stops the takeover unless you pass--force. - After, it waits for zm-api to stay up and, if
zmcwas capturing beforehand, for zm-api to have started it again. If either does not happen within 60 seconds it undoes the switch, startszoneminder.serviceagain and exits with status 3. A takeover that cannot record does not leave the host recording nothing.
Removing the zm-api package while in takeover mode hands control back the same way before the service is stopped.
- zm-api must already be working in passive mode. Takeover is not a way to fix a broken install: if the API cannot reach the database, taking over the capture daemons as well means nothing records.
- zm-api must run as the account ZoneMinder's daemons run as, with write access to the events and socket directories. The package sets that up; the script checks it.
- Nothing else may be starting the ZoneMinder daemons — no cron entry, no
zmpkg.plinvocation, no second host sharing the database with the same server ID.
systemctl is-active zm-api # active
systemctl is-enabled zoneminder # disabled (or not-found)
ps -o ppid=,cmd= -C zmc # one zmc per enabled monitor,
# parented by the zm-api process
journalctl -u zm-api -n 50Then confirm recording actually continues — watch the event count for an active
monitor rise over a few minutes. A clean systemctl status proves the
supervisor started, not that video is being captured.
sudo zm-api-takeover --revert is the first thing to try if capture misbehaves.
It restores the arrangement the host had before, and the REST API keeps working
throughout — passive is a fully supported mode, not a broken state.
Reverting is cheap and reversible in both directions, which is the point: you can take over on a Tuesday afternoon, watch it for a day, and go back with one command if anything looks wrong. Treat it as a rollback, not a defeat.
Full details: man 8 zm-api-takeover.