Hook scripts

A hook is your own script, run by Nyx Backup at a point in the backup run. Typical uses: quiesce a database or stop a service so its files are consistent before the backup reads them, kick off something downstream afterwards, or send a failure alert somewhere the desktop notification cannot reach.

Each backup set can use three hooks, and all three are optional:

HookWhen it runsIf it exits non-zero
Pre-backupBefore the run startsThe run is aborted
Post-backupAfter a successful run, once the manifest is writtenLogged as a warning; the run still counts as successful
FailureAfter a run fails, including a run a pre-hook abortedLogged as a warning; it cannot re-fail an already-failed run

The pre-backup hook is the one with teeth. If your script cannot put the system into a safe state, exit non-zero and no backup is taken, rather than one that captures a half-written database.

Where scripts live

Hooks are chosen by filename from an administrator-controlled directory - not typed in as a command line:

PlatformDirectory
WindowsC:\ProgramData\NyxBackup\hooks\
Linux/etc/nyxbackup/hooks/
macOS/Library/Application Support/NyxBackup/hooks/

A backup set stores only the name of a script in that directory, and the service refuses anything that does not resolve inside it.

This is deliberate, and it is the security boundary of the feature. The backup service runs with full privileges - as SYSTEM on Windows, as root on Linux and macOS - so a hook runs with those privileges too. If any user could point a backup set at any executable, configuring a backup would be a way to run arbitrary code as SYSTEM. Instead the directory is writable only by Administrators (Windows) or root (Unix), so placing a script there is already an administrative act.

On Windows the directory is created with an explicit access list rather than inheriting from ProgramData, whose defaults would otherwise let a standard user drop files in.

What people use them for

Before a backup: make the data safe to copy

The main use, and the reason pre-backup hooks can abort a run.

A live database cannot be backed up by copying its files. The data files are being written while you read them, so a file-level copy is crash-consistent at best and frequently will not restore at all. The fix is to export a clean copy first, into a folder your backup set includes, and let the backup capture that:

  • Dump a database. mysqldump --single-transaction and equivalents take a consistent read view without locking the database, producing an export that restores anywhere.
  • Quiesce an application. Stop a service, flush its state, or put it into a maintenance mode for the duration of the run.
  • Export from something with no files at all - a device, an API, an appliance - into the backup source.

Two things to set up alongside the hook: add the dump directory to the set’s included paths, and exclude the live data directory, or you will back up both the good export and the unusable raw files.

If the export fails, exit non-zero. The run is aborted, and you get a failed backup you can see rather than a successful one containing a database that will not restore.

After a backup: tell someone, or tidy up

Post-backup hooks run once the manifest is written, so the snapshot exists and NYX_SNAPSHOT_ID identifies it:

  • Send a notification somewhere the desktop cannot reach - email, SMS, or a chat webhook. Wire the same script as both the post and failure hook and let it branch on NYX_STATUS; that is how the examples are written.
  • Clean up the dump the pre-hook created, so it is not left on disk.
  • Trigger something downstream - kick off a second job, update a dashboard, record the snapshot id.

A non-zero exit from a post hook is logged and does not fail the run, which is usually what you want: a failed notification should not turn a good backup into a bad one.

Examples to start from

The service seeds an examples subdirectory on first run with working, commented scripts. Copy one up a level into the hooks directory, edit the settings at the top, and select it by name in the backup set.

ExamplePhaseWhat it does
mysqldumpPreConsistent MySQL / MariaDB dump
pg_dumpPrePostgreSQL dump
mongodumpPreMongoDB dump
sqlite-backupPreSQLite online backup (Linux, macOS)
mssql-exportPreSQL Server export (Windows)
quiesce-appPreStop or pause a service around the run (Linux, macOS)
notify-emailPost + failureEmail via an HTTP API, no local mail server
notify-smsPost + failureSMS
notify-webhookPost + failurePOST to a chat or automation webhook

Shell scripts ship for Linux and macOS, PowerShell for Windows. Each carries install instructions and an explanation of why it is written the way it is.

Nothing in examples is live: a script is only offered as a hook once you move it up into the hooks directory itself, which requires administrator rights.

Environment variables

Your script is told which set it is running for, and what happened, through environment variables. Three are set for every hook:

VariableValue
NYX_SET_NAMEThe backup set’s name, as shown in the app
NYX_SET_IDThe set’s stable identifier (a UUID) - use this rather than the name if your script keys off a particular set, since names can be edited
NYX_PHASEpre, post, or failure - so one script can serve all three roles

The post-backup hook additionally receives the outcome:

VariableValue
NYX_STATUSsuccess
NYX_SNAPSHOT_IDIdentifier of the snapshot just written
NYX_FILESNumber of files uploaded in this run
NYX_BYTESBytes uploaded in this run

The failure hook receives what went wrong instead:

VariableValue
NYX_STATUSfailure
NYX_ERRORThe error text, suitable for putting in an alert
NYX_ERROR_CODEA stable category such as storage_missing_object - test this rather than matching on the message, which is written for humans and may change

The pre-backup hook gets only the three common variables. There is no snapshot or outcome yet - that is the point of running before.

Note that NYX_FILES and NYX_BYTES count what was uploaded, not what was examined. An incremental run where nothing changed reports zero for both and is still a success.

Output

Anything your script writes to stdout or stderr is copied into the service log, tagged with the hook phase. That is the simplest way to see what a hook actually did, without turning on debug logging.

If the script is missing

A hook naming a script that is not in the directory is skipped with a warning - not treated as a failure. A renamed or deleted script therefore does not start breaking backups; it stops doing whatever it was doing, and says so in the log.

Timeout

Every hook is subject to a timeout, 300 seconds by default, so a script that hangs cannot stall backups indefinitely. It is configurable per set.

Current limits

Pre- and post-backup hooks are configurable in the app. The failure hook is set in config.toml; it is not yet exposed in the interface.