Resistro Cloud Documentation

Resistro Cloud is a managed backup baseline for small self-managed PostgreSQL databases. EU-hosted, E2E encrypted, starting at 9€/month.

Quick Start

Get your first backup running in under 5 minutes:

# 1. Install the cloud agent (installs the binary and the systemd unit)
curl -fsSL https://cloud.resistro.org/install-agent.sh | sudo sh

# 2. Put your credentials in the environment file (mode 0600, never on the command line)
sudo $EDITOR /etc/resistro-agent/env
#   RESISTRO_API_KEY=...         from the dashboard, "API Key"
#   RESISTRO_ENCRYPTION_KEY=...  generate once: openssl rand -hex 32

# 3. Start the agent
sudo systemctl enable --now resistro-agent
sudo journalctl -u resistro-agent -f

# That's it. The agent asks for work hourly; how often a backup actually
# runs depends on your plan - daily on Solo and Starter, hourly from
# Business upward.
Both variables are mandatory. The agent uploads by default (--upload=true) and refuses to start without an encryption key — it will not silently fall back to storing your data unencrypted.

Install the Agent

The agent is a single static binary (Linux amd64 and arm64) with no runtime dependencies of its own. It talks to your database with the engine's own tools (pg_dump, mysqldump), connects to cloud.resistro.org, reports backup status, and uploads encrypted backups.

The recommended way is the installer — it detects your architecture, pins the expected SHA-256 of the release build, verifies the download against it, creates /etc/resistro-agent/env with mode 0600, and installs the systemd unit:

curl -fsSL https://cloud.resistro.org/install-agent.sh | sudo sh

Manual download — the block below performs the same checksum verification the installer does, by reading the expected SHA-256 out of the installer instead of asking you to compare two hex strings by eye. Run it as written; the || branch aborts before the binary is made executable:

# Download (Linux amd64 — for arm64 replace both occurrences of amd64 with arm64)
wget https://cloud.resistro.org/download/resistro-agent_linux_amd64

# Expected checksum, taken from the installer — the same value the installer pins
EXPECTED=$(curl -fsSL https://cloud.resistro.org/install-agent.sh \
  | sed -n 's/^EXPECTED_SHA256_AMD64="\(.*\)"$/\1/p')
[ -n "$EXPECTED" ] || { echo "could not read expected checksum - aborting"; exit 1; }

# Verify. On systems without sha256sum (e.g. macOS) use: shasum -a 256 -c -
echo "$EXPECTED  resistro-agent_linux_amd64" | sha256sum -c - \
  || { echo "CHECKSUM MISMATCH - do not run this binary"; exit 1; }

chmod +x resistro-agent_linux_amd64
mv resistro-agent_linux_amd64 /usr/local/bin/resistro-cloud-agent
What this check does and does not do: it detects a corrupted or swapped download, because binary and checksum come from two different requests and the checksum is the one the installer itself enforces. It does not protect you against a compromised cloud.resistro.org — that is the same trust boundary the curl | sh installer sits on. If you need provenance independent of this host, verify the release checksum against the one published with the release before you install.

Connect to Cloud

Find your API key in the dashboard under "API Key".

Pass the API key and the encryption key through the environment, never as command-line flags — process arguments are world-readable via ps and /proc/<pid>/cmdline. The agent warns when you use --api-key for exactly this reason.

# Credentials file — the installer already creates this. Only run the block below
# on a host that has no /etc/resistro-agent/env yet: it overwrites the file and
# would replace an existing encryption key, making earlier backups unrecoverable.
cat > /etc/resistro-agent/env <<EOF
RESISTRO_API_KEY=rst_your_key_here
RESISTRO_ENCRYPTION_KEY=$(openssl rand -hex 32)
EOF
chmod 600 /etc/resistro-agent/env

# Run interactively (same variables, same process)
set -a; . /etc/resistro-agent/env; set +a
resistro-cloud-agent --backup-interval 1h

# Run as systemd service
cat > /etc/systemd/system/resistro-agent.service <<EOF
[Unit]
Description=resistro-agent — backup daemon for resistro.org SaaS
Documentation=https://cloud.resistro.org/docs
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
EnvironmentFile=/etc/resistro-agent/env
ExecStart=/usr/local/bin/resistro-cloud-agent --heartbeat-interval 60s --backup-interval 1h
Restart=on-failure
RestartSec=30

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now resistro-agent

Agent Options

FlagEnvDefaultDescription
--api-keyRESISTRO_API_KEYrequiredYour API key from the dashboard. Prefer the env variable or --api-key-file; passed as a flag the secret is visible in ps//proc and the agent logs a warning.
--api-key-fileRead the API key from a file instead of the command line
--serverRESISTRO_SERVERhttps://cloud.resistro.orgServer URL
--heartbeat-intervalRESISTRO_HEARTBEAT_INTERVAL1mAgent heartbeat interval
--backup-intervalRESISTRO_BACKUP_INTERVAL1hHow often the agent asks for backup work; set 0 to disable the daemon backup loop. The server decides whether a run is due: on Solo and Starter a new backup is accepted once the previous one is at least 20 hours old (about one per day), Business and Pro have no spacing. A request inside your plan's window is answered with a clean skip (tier_backup_frequency), not an error.
--backup-engineRESISTRO_BACKUP_ENGINEtoolsDeprecated; the agent selects direct database tools per engine (pg_dump for PostgreSQL, mysqldump for MySQL/MariaDB).
--intervalDeprecated alias for --backup-interval
--encryption-keyRESISTRO_ENCRYPTION_KEYrequired while --upload is trueHex-encoded 256-bit AES key. Prefer the env variable or --encryption-key-file; passed as a flag the secret is visible in ps//proc.
--encryption-key-fileRESISTRO_ENCRYPTION_KEY_FILERead the encryption key from a file instead of the command line
--uploadtrueUpload backups to cloud storage. While true the agent exits at startup if no encryption key is set.
--include-system-dbsRESISTRO_INCLUDE_SYSTEM_DBSfalseAlso back up engine-internal DBs (postgres, template0, mysql, information_schema, ...)
Important: Generate your encryption key once with openssl rand -hex 32 and put it in /etc/resistro-agent/env. Save it somewhere safe. Without the key, your backups are unrecoverable — we cannot help you recover them.

Register / Login

Create an account at cloud.resistro.org or via API:

# Register
curl -X POST https://cloud.resistro.org/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","password":"secret","name":"Your Name"}'

# Login
curl -X POST https://cloud.resistro.org/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","password":"secret"}'

Both return a JWT token and your API key.

Manage Databases

# Add a database
curl -X POST https://cloud.resistro.org/api/v1/databases \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"myapp_prod","engine":"postgresql"}'

# List databases
curl https://cloud.resistro.org/api/v1/databases \
  -H "Authorization: Bearer YOUR_TOKEN"

View Backups

# List all backups
curl https://cloud.resistro.org/api/v1/backups \
  -H "Authorization: Bearer YOUR_TOKEN"

# Filter by database
curl "https://cloud.resistro.org/api/v1/backups?database_id=UUID" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Dashboard overview
curl https://cloud.resistro.org/api/v1/dashboard \
  -H "Authorization: Bearer YOUR_TOKEN"

Configure Alerts

# Add email alert (on failure + anomaly)
curl -X POST https://cloud.resistro.org/api/v1/alerts \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"channel":"email","target":"ops@example.com"}'

# Add Slack webhook
curl -X POST https://cloud.resistro.org/api/v1/alerts \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"channel":"slack","target":"https://hooks.slack.com/services/xxx","on_success":true}'

# List alerts
curl https://cloud.resistro.org/api/v1/alerts \
  -H "Authorization: Bearer YOUR_TOKEN"

# Delete alert
curl -X DELETE https://cloud.resistro.org/api/v1/alerts/ALERT_ID \
  -H "Authorization: Bearer YOUR_TOKEN"

Alert channels: email, slack, teams, webhook

Toggles: on_failure (default: true), on_success (default: false), on_anomaly (default: true)

API Reference: Authentication

EndpointAuthDescription
POST/api/v1/auth/registerNoneCreate account
POST/api/v1/auth/loginNoneLogin, get JWT

API Reference: Databases

EndpointAuthDescription
GET/api/v1/databasesJWTList databases
POST/api/v1/databasesJWTAdd database
PATCH/api/v1/databases/{id}JWTUpdate database settings

API Reference: Backups

EndpointAuthDescription
GET/api/v1/backupsJWTList backups (?database_id= filter)
GET/api/v1/dashboardJWTStats overview

API Reference: Alerts

EndpointAuthDescription
GET/api/v1/alertsJWTList alert configs
POST/api/v1/alertsJWTCreate alert config
DELETE/api/v1/alerts/{id}JWTDelete alert config

API Reference: Agent

EndpointAuthDescription
POST/api/v1/agent/heartbeatAPI KeyAgent heartbeat
POST/api/v1/agent/backup/startAPI KeyStart backup record
POST/api/v1/agent/backup/completeAPI KeyComplete backup record
PUT/api/v1/agent/backup/{id}/uploadAPI KeyUpload encrypted backup data

Agent endpoints use X-API-Key header. Dashboard endpoints use Authorization: Bearer TOKEN.

Encryption

All backups uploaded to Resistro Cloud are encrypted before leaving your server using AES-256-GCM with a random nonce per backup. The encryption key never leaves your machine.

# Generate your key once, put it in /etc/resistro-agent/env:
openssl rand -hex 32
RESISTRO_ENCRYPTION_KEY=a1b2c3d4...hex...

# Save it somewhere safe (password manager, hardware token).
# Without this key, your backups are unrecoverable.
# We cannot decrypt your backups — by design.

Restore

Two steps: download the encrypted backup, then decrypt and pg_restore.

1. List backups

curl -H "Authorization: Bearer $TOKEN" \
     https://cloud.resistro.org/api/v1/backups

2. Download + decrypt

Use the customer-restore.sh helper or do it by hand:

# Download ciphertext
curl -o backup.enc -H "Authorization: Bearer $TOKEN" \
     https://cloud.resistro.org/api/v1/backups/<BACKUP_ID>/download

# Decrypt locally (build decrypt-backup from the resistro-cloud repo)
decrypt-backup -key $RESISTRO_ENCRYPTION_KEY -in backup.enc -out backup.dump

# Restore into your target Postgres
pg_restore -h <host> -U <user> -d <target_db> --no-owner backup.dump

The download endpoint streams raw ciphertext — the server cannot decrypt it. Keep the encryption key.

Storage Backends

Resistro Cloud supports multiple storage backends:

BackendDescriptionPlan
localHetzner Storage Box (default)All plans
s3S3-compatible (AWS, MinIO, Wasabi)Business+
sftpSFTP server (bring your own)Business+

© 2026 Resistro · resistro.org · Dashboard