Docs / Where to run it

Where to run it

The daemon runs wherever it can reach what it backs up. Each way below runs the same safegrd daemon with the same config, so you can start with one and move to another by copying ~/.safegrd.

WhereUse it when
A service on the hostThe database or files are on a VM or a server you can SSH into.
Docker ComposeThe database runs in Compose, or you want the client tools without installing them on the host.
Kubernetes CronJobYou run on Kubernetes and an hourly pass is often enough.
Kubernetes with HelmYou run on Kubernetes and want the daemon resident, so a "Back up now" or a drill from the console starts within a minute.
GitHub ActionsThere is no server of yours to run it on, and a scheduled workflow can reach the database.
On SafeGrdNothing of yours should run it. SafeGrd starts a machine for each backup, where your plan includes it.

Every way needs the host enrolled once (Install and enroll), which writes ~/.safegrd/config.yaml and, with a customer-managed key, the key beside it. In a container, that directory lives in a volume or a Secret.

A service on the host

safegrd daemon install writes a systemd unit on Linux or a launchd agent on macOS and starts it. Daemon covers the unit, its environment and its logs.

Docker Compose

The image ghcr.io/safegrd/cli carries pg_dump 18, the MariaDB client, the MongoDB tools and a PostgreSQL 18 server for sandbox drills, and runs as its own user. compose.yaml runs it beside a PostgreSQL service with its config and key in the safegrd-home volume.

# 1. Enroll once: writes the config and key into the volume
docker compose run --rm safegrd enroll --token sg_pat_... --claim <code>
# 2. Start the daemon
docker compose up -d
# 3. Check it
docker compose exec safegrd safegrd doctor
docker compose exec safegrd safegrd list

The claim code is the one the console shows when you add a host, and it writes the surfaces into the config. A surface whose credential is {from: env, name: APP_DATABASE_URL} reads its connection string from the service's environment, so the password stays out of the config. Give the volume room for the largest database you back up: a sandbox drill restores into a throwaway cluster there. With a customer-managed key, keep a copy of the key somewhere safe outside the volume.

Kubernetes CronJob

cronjob.yaml runs one safegrd daemon run --once pass each hour: it backs up every surface that is due, runs a drill when SafeGrd's server asks for one, and exits. Enroll on any machine, then put the config and the key in a Secret:

kubectl create secret generic safegrd \
  --from-file=config.yaml=$HOME/.safegrd/config.yaml \
  --from-file=daemon.key=$HOME/.safegrd/keys/daemon.key
kubectl apply -f cronjob.yaml

Leave daemon.key out when SafeGrd holds the key for you. The CLI refuses a config or key that others can read, and a Secret volume cannot be both 0600 and owned by the container's user, so an init container copies both into an in-memory volume at 0600. The daemon's state (the last backup of each surface, the weekly and monthly slots) is on a small PersistentVolumeClaim, so a pod that restarts does not take an extra backup. concurrencyPolicy: Forbid stops two passes backing up the same surface at once.

A "Back up now" or "Drill now" from the console waits for the next pass. For an hour's wait or less, change schedule; to start them within a minute, run the daemon resident with the chart below.

Kubernetes with Helm

The Helm chart runs safegrd daemon run as a Deployment, from the same Secret as the CronJob. From a clone of safegrd/cli:

helm install safegrd ./packaging/helm/safegrd

existingSecret names the Secret (safegrd by default), and env adds the variables your surfaces read their credentials from. The state volume (persistence.size, 2 Gi by default) holds the throwaway cluster a sandbox drill restores into: size it for the largest database plus a quarter. A drill that would leave less than 5% of the volume free runs in memory instead, and the console says so.

GitHub Actions

The GitHub Action backs up from a scheduled workflow and drills into a database it creates on the runner. Back up Supabase with GitHub Actions walks through it.

On SafeGrd

Back up on SafeGrd under Surfaces in the console takes a connection string, and a machine SafeGrd starts for each backup does the rest. SafeGrd keeps the connection string encrypted and uses it only on that machine. How it works.