Skip to content
Rowsafe
Docs

Agent configuration

Every agent and installer setting, the files it installs, and its commands.

The agent reads environment variables. On a server, systemd loads them from /etc/rowsafe/agent.env (owned by postgres, mode 0600). In Docker, from the agent service's env_file.

In agent.env, values are single-quoted, with no single quotes or newlines inside. After a change, run the installer again (it self-tests first) or sudo systemctl restart rowsafe-agent.

Where backups go

VariableDefault
ROWSAFE_STORAGEownown: your bucket. rowsafe: Rowsafe Storage; Rowsafe gives the location and short-lived credentials, so the ROWSAFE_REPO_S3_* settings are unused (ROWSAFE_REPO_CIPHER_PASS still applies).

Bucket (repository)

For your own bucket. The installer fills these in from the bucket URL and keys you paste; set them yourself for installs without questions.

VariableDefault
ROWSAFE_REPO_S3_ENDPOINTrequiredHost name without https://, e.g. <account-id>.eu.r2.cloudflarestorage.com.
ROWSAFE_REPO_S3_BUCKETrequiredA private bucket.
ROWSAFE_REPO_S3_KEYrequiredAccess key ID of a token that can read and write only this bucket.
ROWSAFE_REPO_S3_KEY_SECRETrequiredIts secret.
ROWSAFE_REPO_CIPHER_PASSrequiredEncryption passphrase, 20+ characters. Store it in your secret manager before the first backup.
ROWSAFE_REPO_S3_REGIONautoauto for R2.
ROWSAFE_REPO_S3_URI_STYLEpathpath or host.
ROWSAFE_REPO_PATH_PREFIX/rowsafeEach database lives under <prefix>/<name>.
ROWSAFE_REPO_S3_PORT443For other S3-compatible stores.
ROWSAFE_REPO_S3_CA_FILEsystem storeAbsolute path to a PEM bundle to trust instead (e.g. a private MinIO).
ROWSAFE_REPO_S3_VERIFY_TLStruefalse skips certificate checks. Tests only.

Never change the passphrase, bucket or prefix of a repository that holds backups. See Change the configuration.

Second copy

Optional second bucket for the backups and change log, set up with --add-storage (guide). Every bucket setting above exists as ROWSAFE_REPO2_*, same defaults. Required: ROWSAFE_REPO2_S3_ENDPOINT, _S3_BUCKET, _S3_KEY, _S3_KEY_SECRET, _CIPHER_PASS. Optional: _S3_REGION, _S3_URI_STYLE, _PATH_PREFIX, _S3_PORT, _S3_CA_FILE, _S3_VERIFY_TLS.

VariableDefault
ROWSAFE_REPO2_CIPHER_PASSIts own passphrase, 20+ characters. Not the first bucket's.
ROWSAFE_REPO2_QUEUE_DIR/var/lib/rowsafe/copy2-queueWhere change log files wait for the second bucket (at most 256 per database).

If some are missing, the agent keeps using the first bucket only and says what's missing in its log and on the Storage page. Its pgBackRest configuration: /etc/rowsafe/pgbackrest/<name>.copy2.conf.

Connection to Rowsafe

VariableDefault
ROWSAFE_ENROLL_TOKENOne-time enrollment token (rse_...). Needed only until the first start; delete it after.
ROWSAFE_URLhttps://api.rowsafe.shThe API URL. Leave it unset.
ROWSAFE_AUTO_UPDATEtruefalse (or 0, no, off) turns self-update off. Any other value stops the agent from starting. Always off in Docker.
ROWSAFE_POLL_INTERVAL5sHow often an idle agent asks for work.
ROWSAFE_HEARTBEAT_INTERVAL30sHow often it reports in.

Metrics (a server on its own)

Prometheus metrics for a server running Rowsafe on its own: see Prometheus and Grafana.

VariableDefault
ROWSAFE_METRICS_LISTEN(off)Address to serve GET /metrics on, e.g. 127.0.0.1:9188. An address other than loopback needs ROWSAFE_METRICS_TOKEN.
ROWSAFE_METRICS_TOKENBearer token every scrape must send; at least 16 characters.

PostgreSQL and the server

VariableDefault
ROWSAFE_PG_USERpostgresRole the agent connects as, over the Unix socket. Must be a superuser.
ROWSAFE_PG_BIN_DIR/usr/lib/postgresql/%d/binPostgreSQL server binaries, for Proof. %d is the major version.
ROWSAFE_PGBACKREST_BIN/usr/bin/pgbackrestpgBackRest, also used in archive_command.
ROWSAFE_DRILL_DIR/var/lib/rowsafe/drillsScratch space for Proof (internally a drill).
ROWSAFE_DRILL_PORT55432Names the Unix socket of Proof's scratch cluster and of Rewind copies. They never listen on TCP.
ROWSAFE_REWIND_DIR/var/lib/rowsafe/rewindWhere Rewind restores copies. Needs about 1.3 × database size + 1 GiB free per copy. A short absolute path.
ROWSAFE_DRILL_PRELOADautoauto: start Proof's scratch cluster without production's shared_preload_libraries, retry with them if needed. production: always load them.
ROWSAFE_COPIES_DIR/var/lib/rowsafe/copiesWhere migration previews and safe copies are restored, one directory each.
ROWSAFE_COPY_PORTS55440-55539TCP ports safe copies listen on. Open them in your firewall for the addresses that connect.
ROWSAFE_COPY_TLS_CERT, ROWSAFE_COPY_TLS_KEYCertificate and key for safe copies, readable by the agent's user. Without them, each copy makes a self-signed one.
ROWSAFE_PREVIEW_KEEP1hHow long a preview copy is kept so the next preview starts fast (0: delete at once; at most 24h).
ROWSAFE_RESTORE_POINT_TIMEOUT90sHow long to wait for a Mark to be archived, up to 4m.
ROWSAFE_MONITORINGtruefalse turns metrics off.
ROWSAFE_COLLECT_QUERY_TEXTtruefalse sends long-running queries without their text.
ROWSAFE_LOGStruefalse: the agent never reads PostgreSQL's log (Logs).
ROWSAFE_STANDBYonStandbys. on: pairs with servers a person confirms in the dashboard. pinned: only with the fingerprints in ROWSAFE_STANDBY_PEERS, so even a compromised Rowsafe can't pair its own server. off: no standbys.
ROWSAFE_STANDBY_PEERSWith pinned: comma-separated key fingerprints (sudo -u postgres rowsafe-agent key on each server) this server may exchange bucket settings with.
ROWSAFE_CREATE_CLUSTER_ALLOW_FILE/etc/rowsafe/create-cluster-allowedForks: ports (ports 5440-5499) where root allowed new PostgreSQL clusters. Written by the installer (--allow-create-cluster).
ROWSAFE_CREATED_CLUSTERS_FILE/etc/rowsafe/created-clustersClusters created for forks (PORT UNIT per line), which Rowsafe may stop and start like those allowed with --allow-restart. Written by root.

MongoDB

Protect MongoDB.

VariableDefault
ROWSAFE_MONGODB_URIA full connection string (mongodb://user:password@host:port/?authSource=admin) instead of the installer's saved login. For a single server; Docker sidecars usually use ROWSAFE_MONGODB_HOST and rowsafe-agent mongodb login.
ROWSAFE_MONGODB_HOST127.0.0.1Where MongoDB listens (in Docker, the mongo service's name).
ROWSAFE_MONGODB_ARCHIVE_INTERVAL1mHow often new oplog entries go to your bucket (1s to 10m).
ROWSAFE_MONGODB_BIN_DIRPATH, then /usr/binWhere mongodump, mongorestore and mongod are.

ClickHouse

Protect ClickHouse.

VariableDefault
ROWSAFE_CLICKHOUSE_URLhttp://127.0.0.1:PORTClickHouse's HTTP interface. Docker sidecars: e.g. http://clickhouse:8123.
ROWSAFE_CLICKHOUSE_GATEWAY_LISTEN127.0.0.1:0 (a free port)Where the agent listens, only during a backup or restore, for ClickHouse to write and read the backup. The agent encrypts every file before it goes to your bucket. The Docker image sets 0.0.0.0:9010.
ROWSAFE_CLICKHOUSE_GATEWAY_URLthe listen addressHow ClickHouse reaches that address. Docker sidecars: e.g. http://rowsafe-agent:9010.
ROWSAFE_CLICKHOUSE_DATA_PATHClickHouse's own pathWhere the agent reads ClickHouse's data folder (read-only) to copy each new part, if it's not at the server's path. Not needed for Docker sidecars (data volume at /var/lib/clickhouse).
ROWSAFE_CLICKHOUSE_ARCHIVE_INTERVAL15sHow often the agent looks for new parts (1s to 5m). Changes how soon a change reaches your bucket, not restore precision (change times come from ClickHouse).

Redis and Valkey

Protect Redis or Valkey.

VariableDefault
ROWSAFE_REDIS_HOST127.0.0.1Where Redis or Valkey is. Docker sidecars: e.g. redis.
ROWSAFE_REDIS_DATA_DIRRedis's own data folderWhere the agent reads the snapshot file (read-only), only when Rowsafe can't follow the server. Docker sidecars: the data volume's mount in the agent, e.g. /srv/redis-data.

Files

VariableDefault
ROWSAFE_RESTIC_BIN/usr/local/lib/rowsafe/resticrestic, for Files. Falls back to restic on the PATH.
ROWSAFE_FILES_CACHE_DIR<state dir>/files-cacherestic's cache.
ROWSAFE_FILES_STAGING_DIR<state dir>/files-stagingWhere restores are staged before going in place. The root helper expects the default.
ROWSAFE_FILES_ALLOW_FILE/etc/rowsafe/files-allowedThe exact folders root allowed Rowsafe to read and restore into, with their owner (PATH UID lines; --files PATH --allow-files). The agent only reads it.
ROWSAFE_FILES_MOUNT_DIR/rowsafe-filesDocker: where volumes to back up are mounted.

The installer, systemd unit and update guard assume the default directories (ROWSAFE_STATE_DIR, ROWSAFE_CONFIG_DIR, ROWSAFE_LOG_DIR, ROWSAFE_INSTALL_DIR). Don't change them on a server.

Connection pooling

For Connection pooling (PgBouncer). All optional. On a server, leave all but the first two unset: the root helper and its units use the default paths. Paths must be absolute.

VariableDefault
ROWSAFE_POOLER_STATS_URLA PgBouncer Rowsafe doesn't manage, to monitor: its admin console as a postgres:// URL (e.g. postgres://stats:PASSWORD@pgbouncer:6432/pgbouncer in Docker). Rowsafe reads its stats and never changes it.
ROWSAFE_POOLER_DATABASEWith ROWSAFE_POOLER_STATS_URL: the Rowsafe name of the database it serves. Only if the agent has several databases.
ROWSAFE_POOLER_ALLOW_FILE/etc/rowsafe/pooler-allowedPostgreSQL ports where root allowed PgBouncer in front. Written by the installer (--allow-pooler).
ROWSAFE_POOLER_DIR<ROWSAFE_STATE_DIR>/poolerWhere the agent writes requests for the root helper.
ROWSAFE_POOLER_RESULT_DIR/run/rowsafe-poolerWhere the root helper writes answers.
ROWSAFE_POOLER_SOCKET_DIR/var/run/postgresqlPgBouncer's Unix socket directory, for its admin console.
ROWSAFE_POOLER_USERLIST/etc/pgbouncer/userlist.txtPgBouncer's user list, where the agent reads rowsafe_pgbouncer's password.

MySQL and MariaDB

Protect MySQL or MariaDB.

VariableDefault
ROWSAFE_MYSQL_USER, ROWSAFE_MYSQL_PASSWORD_FILEnot setAn account to use instead of Rowsafe's own (rowsafe@localhost). Needs the same privileges.
ROWSAFE_MYSQL_ADMIN_USER, ROWSAFE_MYSQL_ADMIN_PASSWORD_FILEroot, not setDocker: an administrator the agent logs in as once, to create its account.
ROWSAFE_MYSQL_BIN_DIRnot setWhere to look first for xtrabackup, mariadb-backup, mysqlbinlog, mysqld...; then PATH, /usr/sbin, /usr/bin.
ROWSAFE_MYSQL_CONF_FILE/etc/rowsafe/mysql/server.cnfRowsafe's option file for binary log settings (none: Rowsafe can't change the configuration). Not used in Docker.
ROWSAFE_MYSQL_SCRATCH_MEMORY256MInnoDB buffer pool of Proof's and Rewind's private servers.
ROWSAFE_MYSQL_PART_SIZE_MB64Upload part size. Covers backups up to about 600 GiB; raise it for larger (16 to 2048).

Docker

Run the agent in Docker. The agent images (ghcr.io/rowsafe/agent:pg<major>[-alpine] is the newest release; :<version>-pg<major>[-alpine] pins one) set:

VariableImage default
ROWSAFE_MODEdocker-sidecarnative outside the image.
ROWSAFE_SPOOL_DIR/rowsafe-spoolSpool volume shared with PostgreSQL. Each database uses <dir>/<name>.
ROWSAFE_SPOOL_STALL_AFTER5mHow long the oldest spooled file may wait before it counts as an archiving failure (at least 1m).
ROWSAFE_STATE_DIR/var/lib/rowsafeIdentity and state: the rowsafe-state volume.
ROWSAFE_CONFIG_DIR/var/lib/rowsafe/pgbackrestGenerated pgBackRest configuration, in the state volume.
ROWSAFE_DRILL_DIR/var/lib/rowsafe/drillsProof's scratch space: about 1.3 × database size + 1 GiB free.
ROWSAFE_AUTO_UPDATEfalseAlways off in Docker.
ROWSAFE_RESTIC_BIN/usr/local/bin/resticrestic 0.19.1, checked against its release's SHA-256 at image build.
ROWSAFE_FILES_MOUNT_DIR/rowsafe-filesMount volumes to back up with the database here (read-only is enough).
ROWSAFE_FORK_TARGET_DIRMakes this sidecar a fork target: absolute path of the empty data directory (the postgres container's PGDATA) a fork is restored into.
ROWSAFE_DOCKER_CONTROL_SOCKET/run/rowsafe-control/control.sockWhere the optional container control service listens (rowsafe-control volume).
ROWSAFE_IMAGE_VARIANTthe image's tag, e.g. pg17Which agent image this is; Update now picks the same one from the new release. ClickHouse images (clickhouse26.8...) run with ROWSAFE_MODE=native; this tells the agent it's in Docker, so it never updates itself.

The container control service (ghcr.io/rowsafe/docker-control:latest, or :<version>) reads:

VariableDefault
ROWSAFE_CONTROL_SERVICEpostgresThe compose service (in its own project) it may stop, start and restart.
ROWSAFE_CONTROL_CONTAINERInstead: one container name (without compose).
ROWSAFE_CONTROL_ALLOW_UIDS999,70Users allowed to connect: the agent's.
ROWSAFE_CONTROL_STOP_TIMEOUT2mHow long PostgreSQL may take to shut down before Docker kills it (at most 10m).
ROWSAFE_CONTROL_SOCKET/run/rowsafe-control/control.sockWhere it listens.
ROWSAFE_CONTROL_ALLOW_AGENT_UPDATE01: also let Rowsafe replace the agent's container with a newer signed image when someone clicks Update now (how).
ROWSAFE_CONTROL_UPDATE_ONLY01: only update the agent's container; stopping, starting or restarting the database container is refused. Turns agent updates on. Used for ClickHouse.
ROWSAFE_CONTROL_AGENT_SERVICErowsafe-agentThe agent's compose service, for agent updates.
ROWSAFE_CONTROL_AGENT_CONTAINERInstead: the agent container's name (without compose).

Installer

curl -fsSL https://rowsafe.sh | sudo sh                              # install, on its own (no dashboard; sudo rowsafe login later)
curl -fsSL https://rowsafe.sh | sudo sh -s -- --account         # install and connect: approve the server in your browser
curl -fsSL https://rowsafe.sh | sudo sh -s rse_...                   # the same with an enrollment token: nothing to approve
curl -fsSL https://rowsafe.sh | sudo sh -s rse_... --protect app     # without questions (automation)
curl -fsSL https://rowsafe.sh | sudo sh                              # run again: update, re-test, start
curl -fsSL https://rowsafe.sh | sudo sh -s -- --uninstall            # options alone go after `sh -s --`

https://rowsafe.sh/install serves the same script.

Permissions. The --allow-NAME options answer the permission questions: --allow-NAME says yes, --no-allow-NAME says no. Without a terminal or an option, what touches only the database is allowed (restart, create-cluster, updates, pooler, tuning, sqlite-modes, files); the server's security updates, reboot, firewall and public pooler aren't. Some need another: create-cluster, updates and security-updates need restart; reboot needs security-updates; pooler-public needs pooler. Without it they're refused, and turning one off turns off what needs it. Change them later with sudo rowsafe-allow.

Option
rse_...The enrollment token (or ROWSAFE_ENROLL_TOKEN=rse_...). Without one, on a terminal, you approve the server in your browser from a printed link.
--protect NAMESet up the database without questions: register as NAME, plan, apply. Never restarts the database. Storage settings must be in the environment (ROWSAFE_REPO_*).
--no-setupInstall the agent and storage only. Add the database later from the dashboard or with rowsafe adopt.
--install-postgres VERSIONFresh Debian or Ubuntu: install and start PostgreSQL VERSION (13 to 18) from apt.postgresql.org (signing key checked). Refused if PostgreSQL is installed; re-runs keep the one it installed. With --protect, restarts that new PostgreSQL once if backups need it. Used by Create a server for me.
--listen-publicMake PostgreSQL reachable from the network: every address, TLS (self-signed certificate in /etc/ssl/rowsafe-postgresql) and scram-sha-256 for every network login; local rules unchanged. Put a firewall in front: it decides who can connect. Restarts PostgreSQL only if --install-postgres installed it or you say yes; otherwise it applies at the next restart.
--files PATHBack up the folder PATH (uploads, media) with the database, without asking; repeatable. Gives the agent's user read-only access (ACL) if needed. Files.
--allow-filesDefault for folders named with --files. Let Rowsafe put restored files back into those folders only (as the folder's owner), listed in /etc/rowsafe/files-allowed. A folder added later in the dashboard needs --files with that folder once more. Only when someone asks and confirms.
--no-allow-filesDon't allow it, without asking.
--no-filesDon't ask about upload folders.
--allow-poolerDefault on. Let Rowsafe install and manage the connection pooler (PgBouncer; ProxySQL for MySQL and MariaDB; chproxy for ClickHouse). Nothing is installed until someone turns pooling on and confirms.
--no-allow-poolerDon't allow it. A PgBouncer Rowsafe set up keeps running, but Rowsafe can't change it.
--allow-pooler-publicWith --allow-pooler: also let PgBouncer listen on every address when someone picks "public". Otherwise only this server and its private network.
--no-allow-pooler-publicPgBouncer back to this server and its private network only.
--allow-pooler-target ADDRESS:PORTMySQL and MariaDB: let ProxySQL send connections to that server (the new primary after a standby's promotion). --no-allow-pooler-target ADDRESS:PORT stops it.
--allow-restartDefault on. Let Rowsafe restart or stop the database: Restart and Rewind the whole database in the dashboard, only when someone clicks and confirms. Installs the root helper rowsafe-pg-restart.
--no-allow-restartDon't allow it, and remove the helper. Also turns off updates, security updates, reboots and new clusters for forks.
--allow-updatesDefault on. Let Rowsafe install minor updates and upgrade the database, only when someone clicks Update or Upgrade and confirms. Needs --allow-restart. Updates.
--no-allow-updatesDon't allow it.
--allow-security-updatesDefault off. Let Rowsafe install the server's security updates. Needs --allow-restart.
--no-allow-security-updatesDon't allow it.
--allow-rebootDefault off. Let Rowsafe reboot the server. Needs --allow-security-updates.
--no-allow-rebootDon't allow it. --no-allow-security-updates turns it off too.
--allow-firewallDefault off. Let Rowsafe limit who reaches the database's port with nftables: only that port, never SSH, only when someone picks the addresses under Security and confirms.
--no-allow-firewallDon't allow it; removes Rowsafe's firewall rule and helper.
--allow-tuningDefault on. MongoDB, ClickHouse, Redis and Valkey: let Rowsafe write settings changed under Tuning into its own settings file. --no-allow-tuning turns it off.
--mysql-standbyMySQL and MariaDB: allow standbys with this server. Its account gets administrator rights, used only when someone adds, promotes or removes a standby, forks to an empty server or moves a database in, and confirms. --no-mysql-standby: don't.
--mongodb-standbyMongoDB: allow standbys. Its user gets clusterManager; root's helper may hand out the replica set's key file and add Rowsafe's lines to mongod.conf (a copy kept). Needs --allow-restart.
--mongodb-clonesMongoDB: keep an empty server ready for forks and move-ins (Rowsafe's user gets restore and readWriteAnyDatabase).
--clickhouse-clonesClickHouse: keep an empty server ready for forks and move-ins (Rowsafe's user may create and drop databases).
--mongodb-replica-setMongoDB: turn a standalone server into a one-member replica set without asking (one MongoDB restart). Needed to restore to any second.
--no-mongodb-replica-setMongoDB: never do that.
--allow-create-clusterDefault on where restarts are. Let Rowsafe create a PostgreSQL cluster (free port in 5440-5499) when someone forks a database here and confirms. Debian and Ubuntu (pg_createcluster).
--no-allow-create-clusterDon't allow it. Clusters created earlier stay.
--setup-storageSet up (or change) backup storage, even if configured.
--storage PROVIDERSkip the "where" question: rowsafe (Rowsafe Storage; also works without a terminal), or r2, b2, s3, wasabi, spaces, s3-compatible.
--no-promptNever ask, even on a terminal.
--check-storageTest the storage in agent.env (your bucket, or Rowsafe Storage through the agent, plus any second copy). Changes nothing.
--add-storageAdd a second copy in another bucket (questions like the first), or move it. Without a terminal, takes ROWSAFE_REPO2_* from the environment and tests it before saving.
--remove-second-copyStop sending backups to the second copy. Its bucket is left as is.
--download-only DIRDownload and verify the agent into DIR; install nothing. No root needed.
--permissionsWhere Rowsafe is installed: change only what it may do (--allow-NAME, --no-allow-NAME, --no-allow-files), offline, then print what it may do. What sudo rowsafe-allow runs. Exits 0 done, 2 refused and nothing changed (a needed permission is off, or not possible here), 1 a change failed.
--uninstallStop and remove the service and /opt/rowsafe. Keeps configuration, state and logs.
--uninstall --purgeAlso delete /etc/rowsafe, /var/lib/rowsafe, /var/log/rowsafe and the logrotate file. Refused while PostgreSQL still archives with Rowsafe's configuration.
-h, --helpHelp.
Environment variable
ROWSAFE_VERSION=1.2.3Install exactly this version, not the channel's latest.
ROWSAFE_CHANNEL=stableChannel to install from. Later updates follow the host's channel in Rowsafe.
ROWSAFE_ALLOW_DOWNGRADE=1Allow ROWSAFE_VERSION older than the installed one.
ROWSAFE_ALLOW_UNSUPPORTED_OS=1Try an OS other than Debian 12/13 or Ubuntu 22.04/24.04.
ROWSAFE_MONGODB_ADMIN_USER, ROWSAFE_MONGODB_ADMIN_PASSWORDWithout a terminal: a MongoDB admin, to create Rowsafe's MongoDB user. Used once, never saved.
ROWSAFE_CLICKHOUSE_ADMIN_USER, ROWSAFE_CLICKHOUSE_ADMIN_PASSWORDWithout a terminal: a ClickHouse admin, to create Rowsafe's ClickHouse user when a users file can't be used. Used once, never saved.

The installer copies these from its environment into agent.env, without printing them: ROWSAFE_URL, ROWSAFE_ENROLL_TOKEN, ROWSAFE_STORAGE, every ROWSAFE_REPO_* and ROWSAFE_REPO2_*, ROWSAFE_AUTO_UPDATE, ROWSAFE_PG_USER, ROWSAFE_PG_BIN_DIR, ROWSAFE_PGBACKREST_BIN, ROWSAFE_DRILL_DIR, ROWSAFE_DRILL_PORT, ROWSAFE_POLL_INTERVAL, ROWSAFE_HEARTBEAT_INTERVAL. Set anything else by editing the file.

What the installer does:

  1. Checks the system: root, Debian 12/13 or Ubuntu 22.04/24.04, amd64 or arm64, a postgres user and PostgreSQL server binaries, OpenSSL 3.
  2. Downloads the release manifest and signature, verifies the Ed25519 signature with its built-in key, then the binary's size and SHA-256. Any failure: nothing changes.
  3. Installs pgBackRest if missing (apt.postgresql.org if configured, else your distribution). Installs restic 0.19.1 for Files from GitHub into /usr/local/lib/rowsafe/restic, checked against its published SHA-256 (a mismatch installs nothing; falls back to your distribution's restic 0.17+ if GitHub is unreachable).
  4. Installs the agent, the systemd unit and a logrotate file.
  5. Sets up storage if needed and writes agent.env, keeping existing settings.
  6. If settings are missing, enables the service without starting it and lists what's missing. Otherwise self-tests the new agent, then starts or restarts it.
  7. Unless --no-setup, finds the database (PostgreSQL, MySQL, MariaDB, MongoDB, ClickHouse, Redis or Valkey) and protects it (questions below, or --protect NAME).

The questions it asks

A first install on a terminal asks these. Shown for PostgreSQL; other databases name themselves and skip what doesn't apply (by database).

Question
Where should backups go?Only when Rowsafe Storage is offered. 1 (default): Rowsafe Storage, bucket questions skipped. 2: your own bucket.
Paste your bucket URLE.g. Cloudflare R2's "S3 API" URL, https://<account-id>.r2.cloudflarestorage.com/<bucket>. Provider, endpoint, region and bucket are detected from it. Set up backup storage.
Access key ID, secretTyped hidden. Then it tests the bucket: writes, reads back and deletes a small file.
Encryption passphraseGenerated and shown once (or your own). You type its last 4 characters to confirm you saved it.
Name it in Rowsafe [app]:After Found PostgreSQL 18 on port 5432 (1.2 GB; databases: app). Enter accepts.
Turn on backups for app now? [Y/n]After the plan, in plain words. Nothing changes until yes.
Allow restarting PostgreSQL from the Rowsafe dashboard? [Y/n]Only when someone clicks Restart and confirms.
Allow Rowsafe to install and manage PgBouncer? ... [Y/n]Nothing installed now: only when someone turns connection pooling on and confirms.
Allow Rowsafe to install PostgreSQL updates when you click Update? [Y/n]Only if restarts are allowed. Minor updates and major upgrades, only when someone confirms; a Mark first.
Allow Rowsafe to install this server's security updates when you click Install? [y/N]Only if restarts are allowed.
Allow Rowsafe to reboot this server when you click Reboot? [y/N]Only after yes to security updates.
Allow Rowsafe to limit who can reach PostgreSQL's port with the firewall? [y/N]Only if nftables is installed. Only PostgreSQL's port, never SSH; only when someone picks the addresses and confirms. The firewall.
Allow Rowsafe to create a new PostgreSQL cluster here when you fork a database to this server? [Y/n]For forks, only when someone confirms, on ports 5440-5499. Debian and Ubuntu, only if restarts are allowed.
Restart PostgreSQL now? [y/N]Only if a setting needs it. Yes: restarts, checks changes reach the bucket, starts the first full backup. No: restart when it suits you; Rowsafe notices.
Does this app store uploads on this server? Rowsafe found /srv/app/storage/app (2.3 GiB, ...). Back it up with app, so a restore brings back both? [Y/n]For up to three folders that look like uploads. Files.
Allow Rowsafe to put restored files back into /srv/app/storage/app, as the folder's owner? [Y/n]Once a folder is protected; names exactly the folders it allows. Only when someone asks and confirms.

Secrets are never printed. Nothing is saved until the storage questions are answered. Without a terminal, or with --no-prompt, it asks nothing: put storage settings in the environment and use --protect NAME. Installer changes appear in the audit log as installer on <hostname>.

Files on the server

/opt/rowsafe/                          postgres 0755
  rowsafe-agent -> versions/<v>/...    the binary systemd runs; swapped on update
  versions/<v>/rowsafe-agent           current and previous version
  bin/rowsafe-agent-guard              root 0755; rolls back an update that keeps crashing
/etc/rowsafe/                          root:postgres 0750
  agent.env                            postgres 0600; settings and secrets
  pgbackrest/<name>.conf               postgres 0600; generated, local edits are overwritten
/var/lib/rowsafe/                      postgres 0700; identity, state, running Proof copies
  files.json                           the protected folders' settings and state (Files)
  files-cache/, files-staging/         restic's cache; restores staged before they are put in place
  files-restored/<id>/                 restored files Rowsafe could not put back into their folder
  storage-credentials.json             postgres 0600; Rowsafe Storage only: the current short-lived credentials
/var/log/rowsafe/                      postgres 0700; pgBackRest logs, rotated daily, 14 kept
/usr/local/lib/rowsafe/restic          root 0755; restic, for Files
/etc/rowsafe/files-allowed             root 0644; "PATH UID" per folder Rowsafe may read and restore into (--allow-files)
/etc/systemd/system/rowsafe-agent.service
/etc/logrotate.d/rowsafe
/usr/local/sbin/rowsafe-allow          root 0755; see and change what Rowsafe may do (sudo rowsafe-allow)
/usr/local/lib/rowsafe/install.sh      root 0755; root's copy of the installer, checked against the signed manifest

Only when you allowed restarts, updates, security updates or reboots:
/etc/rowsafe/restart-allowed           root 0644; "PORT UNIT" per cluster Rowsafe may restart or stop
/etc/rowsafe/updates-allowed           root 0644; postgresql, security, reboot: what Rowsafe may do
/usr/local/lib/rowsafe/rowsafe-pg-restart   root 0755; the root helper
/etc/systemd/system/rowsafe-pg-restart.{service,path}   restarts, stops, starts
/etc/systemd/system/rowsafe-pg-update.{service,path}    updates, upgrades, reboots
/var/lib/rowsafe-pg-restart/           root 0700; what an upgrade keeps for undo
  • Pooler (--allow-pooler): /etc/rowsafe/pooler-allowed and the rowsafe-pooler systemd units. PgBouncer's files: Connection pooling.
  • Logs: journalctl -u rowsafe-agent (JSON lines) and /var/log/rowsafe/<name>-<command>.log. Each task's log, with pgBackRest's output, is also in rowsafe task ID.
  • The systemd unit runs the agent as postgres with NoNewPrivileges, a read-only system, a private /dev, no capabilities and restricted address families. The installer rewrites it: put local changes in a drop-in (sudo systemctl edit rowsafe-agent).
  • The files helper (--allow-files): rowsafe-files-helper.{service,path} in /etc/systemd/system, with a drop-in (rowsafe-files-helper.service.d/folders.conf) that lets it write only into the folders in /etc/rowsafe/files-allowed. Same script as the root helper, in its own sandbox; private copy and cooldowns in /var/lib/rowsafe-files-helper. Files.
  • The firewall helper (--allow-firewall): /usr/local/lib/rowsafe/rowsafe-firewall (root 0755), started by rowsafe-firewall.path when the agent asks, loaded at boot by rowsafe-firewall-restore.service. Changes only its own nftables table (inet rowsafe), only for ports in /etc/rowsafe/firewall-allowed (root 0644); rules kept in /var/lib/rowsafe-firewall.

Agent commands

rowsafe-agent run         enroll if needed, then run tasks (what systemd runs)
rowsafe-agent inspect     print what the agent sees in PostgreSQL (read-only)
                          [--port 5432] [--socket-dir /var/run/postgresql] [--user postgres]
rowsafe-agent selftest    check the configuration, pgBackRest, Rowsafe and every database
rowsafe-agent storage test [--wait 60s]
                          write, read back and delete a test file in the backup storage
rowsafe-agent health      container health check (Docker)
rowsafe-agent files discover|access|list|add
                          the folders that go with a database (used by the installer)
rowsafe-agent mongodb status|login|initiate|save-uri --port 27017 [--admin-user NAME]
                          MongoDB: what the installer needs to know; create Rowsafe's
                          MongoDB user; start a replica set of one; save a login you made
rowsafe-agent clickhouse status|login|save-login --port 8123 [--users-xml | --admin-user NAME]
                          ClickHouse: what the installer needs to know; create Rowsafe's
                          ClickHouse user (--users-xml prints a users.d file for root to
                          install; --admin-user creates it with SQL, password on stdin);
                          save a login you made (user:password on stdin)
rowsafe-agent clickhouse download-backup --stanza FOLDER [--label LABEL --to DIR]
                          ClickHouse: list a database's backups, or decrypt one (and the full
                          backup it builds on) into DIR for RESTORE ... FROM File(...)
rowsafe-agent unseal      decrypt a file Rowsafe wrote to your bucket (stdin to stdout)
rowsafe-agent version

Run the self-test exactly as the service would:

sudo systemd-run --quiet --wait --pipe --collect -p User=postgres \
  -p EnvironmentFile=/etc/rowsafe/agent.env /opt/rowsafe/rowsafe-agent selftest
Edit on GitHub