Backup Script Manager
A single-administrator web application that runs ordered, typed backup steps on home-lab hosts over SSH and retrieves artifacts over SFTP.
Supported operations:
- Combine up to 50 Docker commands, remote host commands, database dumps, and directory archives in one job.
- Execute commands with zero or more declared outputs, allowing preparation and cleanup steps.
- Create compressed PostgreSQL or MySQL dumps using tools installed on the remote host.
- Archive a remote directory as
tar.gz. - Export restore-ready Backup Manager configuration with encrypted credential envelopes.
- Run jobs manually or with timezone-aware cron schedules.
- Retain a configured number of successful runs and notify by webhook or SMTP.
Run With Docker Compose
Create the deployment configuration and a permanent encryption key:
cp .env.example .env
openssl rand -base64 32
Set the generated value as MASTER_KEY and choose a strong ADMIN_PASSWORD in .env, then start the application:
docker compose up --build -d
Open http://localhost:3000. The default binds only to loopback. For network access, put the application behind an HTTPS reverse proxy, set BIND_ADDRESS as needed, and set SECURE_COOKIE=true; do not expose the HTTP login directly to the LAN.
Compose uses managed volumes by default. To use bind mounts, set DATA_PATH and BACKUP_PATH in .env; the process runs as UID/GID 10001, so those host directories must already exist and be writable by that identity. Keep MASTER_KEY in a password manager: losing or changing it makes stored SSH and database credentials unreadable.
Remote Host Requirements
- SSH must allow password or private-key authentication and the same account must support SFTP.
- Verify a probed SSH fingerprint against the host itself, for example with
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub -E sha256, before saving it. - The account needs write access to
/tmpand read access to backup sources. - Docker jobs require
docker,tar, andgzip; the SSH account must be permitted to run Docker without an interactive prompt. - Directory jobs require
tarandgzip. - PostgreSQL jobs require
pg_dumpandgzipon the SSH host. MySQL jobs requiremysqldumpandgzip.
Docker jobs execute in an existing container. Each configured output is a path inside that container. The manager copies it to a permission-restricted remote staging directory, downloads it, and deletes only that staging directory; it does not delete the original container output.
Job Steps
Every job targets one SSH host and runs its steps sequentially over one pinned connection. Use the step arrows in the job builder to control order. Available steps are:
- Docker command: runs an executable with explicit arguments inside an existing container. Declared container outputs are copied with
docker cp. - Remote command: runs an executable with explicit arguments on the SSH host. It can collect generated host files or archives.
- PostgreSQL/MySQL dump: creates a compressed dump using an encrypted password associated with that step.
- Directory archive: archives an absolute host path.
- Backup Manager configuration: creates a local, integrity-protected JSON artifact containing hosts, jobs, schedules, and notification settings. Credential values remain encrypted and restoration requires the original
MASTER_KEY; the key itself is never exported.
Command arguments are entered one per line and are passed as distinct shell-quoted values; shell pipelines and redirection are not interpreted. Add an explicit script on the remote system when more complex command logic is required.
By default, a failed step stops the job and no artifacts are published. Enable Continue if this step fails only for non-critical steps. The run then continues, skips outputs from the failed step, and finishes as succeeded_with_warnings if all required steps complete. Artifact names must be unique across the job, and every job must contain at least one artifact-producing step.
Schedules use five-field cron syntax. Jobs do not overlap: a scheduled occurrence is skipped if that job is already queued or running. Runs from different jobs are processed serially in this initial single-instance release.
Local Development
Node.js 22 or later is required.
npm install
export ADMIN_PASSWORD=development-only
export MASTER_KEY="$(openssl rand -base64 32)"
npm run dev
Vite serves the UI on http://localhost:5173 and proxies API requests to port 3000.
Verification commands:
npm run lint
npm run typecheck
npm test
npm run build
Run all checks in that order with npm run check.
Storage
data/app.dbcontains hosts, encrypted secrets, job definitions, schedules, and run history.backups/<job-id>/<run-id>/contains completed artifacts.backups/.staging/contains in-progress downloads and is cleaned when a run fails.
Configuration exports omit run history, artifact metadata, artifact files, the administrator password, runtime paths, and MASTER_KEY. Store the exported JSON and the key separately. For a complete storage-level backup, back up both the data and artifact volumes together.
Restore a configuration export from Settings > Restore configuration. Restores require the original MASTER_KEY, reject modified exports, update records with matching stable identities, add missing records, and leave unrelated local configuration and run history untouched. Numeric IDs and host references are remapped when necessary. A backup from another manager can initialize an empty installation but cannot merge into a populated installation. Restore is blocked while any job is queued or running, and conflicting names owned by unrelated local records must be resolved first.