Skip to content

Command reference

Every command an administrator needs on the server, in one place. The pages linked from each section explain the background.

Where to run them. The install script puts the stack into /opt/restow, owned by root. Run the commands there (cd /opt/restow) with sudo. For an installation by hand, run them in the directory of its docker-compose.yml. The services of the stack are postgres, api, worker, scheduler, caddy (the edge with the web interface) and, only if you started it, updater.

Recommended: download the script, check it, run it (Get started):

Terminal window
curl -fsSLO https://github.com/restow-backup/restow/releases/download/v0.1.0/install.sh
curl -fsSLO https://github.com/restow-backup/restow/releases/download/v0.1.0/install.sh.sha256
sha256sum -c install.sh.sha256
sudo bash install.sh

The one-liner for the newest release, interactive or unattended. It runs the script without checking it first (why the path above is better):

Terminal window
curl -fsSL https://github.com/restow-backup/restow/releases/latest/download/install.sh | sudo bash
curl -fsSL https://github.com/restow-backup/restow/releases/latest/download/install.sh | sudo bash -s -- --non-interactive --domain backup.example.com --edition full

Unattended, the script does not show the master key: copy it from /opt/restow/.env right away (see Master key and database).

Command What it does
sudo bash install.sh --dry-run Runs the checks and prints what it would do; changes nothing.
sudo bash install.sh --local An evaluation without a public domain, with a certificate of Caddy’s own authority. Not for production.
sudo bash install.sh --with-updater Also starts the opt-in updater. Read Updates first.
bash install.sh --help Every option and the exit codes.
bash install.sh --upgrade Prints how to update; the script itself never updates.

The install log is /var/log/restow-install.log, without secrets.

Terminal window
sudo docker compose ps
curl -fsS http://127.0.0.1:3000/healthz
curl -fsS http://127.0.0.1:3000/readyz

/healthz says that the api process is up. /readyz answers 503 not_ready until the database answers and the worker and the scheduler have reported in; its body names what is missing. The running version is shown at the bottom of the web interface’s sidebar.

Terminal window
sudo docker compose logs -f api # follow; Ctrl+C ends the log, not the service
sudo docker compose logs --tail 200 worker # the last 200 lines
sudo docker compose logs --since 1h scheduler # the last hour
sudo docker compose logs caddy # the edge: certificates, requests
Terminal window
sudo docker compose up -d # start, and apply a changed .env or new images
sudo docker compose restart api # restart a service with its current image and environment
sudo docker compose stop # stop everything; all data stays

docker compose restart does not pick up a changed .env or a new image; docker compose up -d does.

The setup wizard asks for a one-time setup token. Until the setup is complete, the api prints it at every start; use the one printed last:

Terminal window
sudo docker compose logs api | grep 'SETUP TOKEN'

See Setup wizard.

When the last owner has lost their passkey, authenticator app or password:

Terminal window
sudo docker compose exec api restow admin list
sudo docker compose exec api restow admin recover --email owner@example.com
sudo docker compose exec api restow help

admin recover works for owners only, asks for confirmation and a new password, and is recorded in the audit log. See Recovering administrator access.

Keep an offline copy of RESTOW_MASTER_KEY. Without it no backup can be read, and there is no recovery path. This prints it, so copy it to an offline place:

Terminal window
sudo grep '^RESTOW_MASTER_KEY=' /opt/restow/.env

A database dump, written by root and readable only by root (before every update, and regularly):

Terminal window
sudo sh -c 'umask 077; docker compose exec -T postgres pg_dump -U restow -Fc restow > restow-$(date +%F).dump'

What else to back up, and how to read backups without a running server (restow-restore), is in Backing up Restow itself.

Read the release notes of every version in between first. In short, for version X.Y.Z:

Terminal window
cd /opt/restow
sudo sh -c 'umask 077; docker compose exec -T postgres pg_dump -U restow -Fc restow > restow-$(date +%F).dump'
NEW=X.Y.Z
sudo cp -p .env .env.before-update
sudo sed -i -E 's#^(RESTOW_(WEB_)?IMAGE=ghcr\.io/restow-backup/restow(-web)?(-community)?):.*$#\1:'"$NEW"'#' .env
sudo docker compose pull
sudo docker compose up -d
sudo docker compose logs -f api

The steps one by one, checking the images first and going back: Updates, step by step.

An image, with the identity of exactly its release (here 0.1.0; the same for restow-web, restow-community and restow-web-community):

Terminal window
cosign verify ghcr.io/restow-backup/restow:0.1.0 \
--certificate-identity https://github.com/restow-backup/restow/.github/workflows/release.yml@refs/tags/v0.1.0 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com

The signed checksum list of the release files (install.sh, docker-compose.yml, env.example and the rest), downloaded next to them:

Terminal window
cosign verify-blob SHA256SUMS --bundle SHA256SUMS.sigstore.json \
--certificate-identity https://github.com/restow-backup/restow/.github/workflows/release.yml@refs/tags/v0.1.0 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
sha256sum -c --ignore-missing SHA256SUMS

The agent’s own signature, the SBOM and what the release checks covered: Verifying a release.

Terminal window
sudo docker compose --profile updater up -d # start it (after setting it up)
sudo docker compose --profile updater ps updater # is it running?
sudo docker compose --profile updater logs --tail 100 updater
sudo docker compose --profile updater up -d updater # recreate it, e.g. after changing RESTOW_UPDATER_IMAGE
sudo docker compose --profile updater rm -sf updater # remove it again

Whether it is ready, or what blocks it, the Install card under Settings → Updates says. Before you start it, read The opt-in updater: it mounts the Docker socket.

On the machine itself. restow-agent is a link in /usr/local/bin where that folder belongs to root; otherwise use the full path, /opt/restow-agent/bin/restow-agent (Linux) or '/Library/Application Support/Restow/bin/restow-agent' (macOS).

Terminal window
restow-agent status # local state; no root needed (--json for scripts)
sudo restow-agent status # also the hook policy
sudo restow-agent service status # the system service
sudo restow-agent service restart
sudo restow-agent backup-now # one backup in the foreground (add --debug for details)
sudo restow-agent hooks status # whether hooks from the server may run here
restow-agent version
journalctl -u restow-agent # Linux: the agent's log in the journal
sudo tail -f /var/log/restow-agent/agent.log
sudo restow-agent uninstall # remove the agent (asks first; --yes skips the question)

More in Install on Linux and macOS, Troubleshooting and Uninstall.

The install script has no uninstall, on purpose: removing an installation can destroy backups. This stops and removes the containers; the database, the local chunk store, Caddy’s certificates, the updater’s dumps and .env stay:

Terminal window
cd /opt/restow
sudo docker compose --profile updater down

Only when you are sure that no backup in them is still needed:

Terminal window
sudo docker compose --profile updater down --volumes # deletes the database and the local chunk store
cd / && sudo rm -r /opt/restow # .env holds RESTOW_MASTER_KEY

Keep an offline copy of RESTOW_MASTER_KEY as long as backups on other storage (S3, NFS, SMB) may still be needed: restow-restore reads them with the key alone. Those backups are not deleted by the steps above; remove them in the storage itself. Docker stays installed.