Skip to main content

Backup & Restore

Kuploy can back up and restore the whole instance — its own database and configuration, which hold every organization on this deployment. This is an operator-level disaster-recovery tool, separate from any per-app database backups your developers configure.

Everything here lives under Settings → Maintenance and is available to instance admins only.

On Kuploy Cloud

This is an operator tool, so on Kuploy Cloud it lives under Platform Admin → Maintenance and is restricted to platform admins — the people who run the deployment. Regular organization owners and admins (tenants) can't reach it: it acts on the shared platform database that holds every organization, never a single tenant's data. Everything below applies identically; only the location (Platform Admin → Maintenance instead of Settings → Maintenance) differs.

Whole-instance scope

An instance backup captures everything — all organizations, users, projects and settings. Restoring one rolls the whole instance back to that point in time, not a single organization. Treat it accordingly.

Prerequisites

  • You must be signed in as an instance admin (the first user created on a fresh instance is an admin).
  • At least one S3 destination (a bucket kuploy can upload backups to). If you don't have one yet, follow Configure an AWS S3 bucket below.

Configure an AWS S3 bucket

You only need to do this once. These steps use Amazon S3; any S3-compatible provider (Cloudflare R2, Wasabi, MinIO, DigitalOcean Spaces, …) works the same way — only the Endpoint differs.

1. Create the bucket

  1. In the top-right Region selector of the AWS console, pick the region the bucket should live in, e.g. US East (Ohio) us-east-2. Note the region code — you'll need it below. (The Create bucket form shows this region under General configuration; it isn't a separate field there.)
  2. Open S3 → Buckets → Create bucket.
  3. Bucket type — leave General purpose.
  4. Bucket namespace — leave Global namespace (the default).
  5. Bucket name — a globally-unique name, e.g. my-kuploy-backups.
  6. Object Ownership — leave ACLs disabled (recommended).
  7. Block Public Access — keep Block all public access ticked; backups must stay private.
  8. Bucket Versioning — optionally set to Enable so an overwritten or deleted backup object can still be recovered.
  9. Leave the remaining defaults (encryption, tags) and click Create bucket.

2. Create a scoped IAM policy

Give kuploy access to only this bucket. In IAM → Policies → Create policy, switch to the JSON editor and paste (replace my-kuploy-backups with your bucket name):

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "KuployBackupsBucket",
"Effect": "Allow",
"Action": ["s3:ListBucket", "s3:GetBucketLocation"],
"Resource": "arn:aws:s3:::my-kuploy-backups"
},
{
"Sid": "KuployBackupsObjects",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": "arn:aws:s3:::my-kuploy-backups/*"
}
]
}

Name it e.g. kuploy-backups and create it.

3. Create the IAM user

  1. In IAM → Users → Create user, name it e.g. kuploy-backups, and leave Provide user access to the AWS Management Console unchecked.
  2. On Set permissions, choose Attach policies directly, search for kuploy-backups, tick it, and finish creating the user.

Creating the user does not generate an access key — that's a separate step below.

4. Create an access key

  1. Open the user (IAM → Users → kuploy-backups) → Security credentials tab → Create access key.
  2. For Use case, choose Application running outside AWSNext.
  3. Skip the optional description tag → Create access key.
  4. On Retrieve access keys, copy the Access key ID and Secret access key now — the secret is shown only once (or Download .csv).

5. Add the destination in kuploy

Go to Settings → S3 Destinations → Add Destination and fill in:

FieldValue
NameA label you choose, e.g. AWS backups
ProviderAmazon Web Services (AWS) S3
Access Key IdThe Access key ID from step 4
Secret Access KeyThe Secret access key from step 4
BucketYour bucket name, e.g. my-kuploy-backups
RegionYour bucket's region, e.g. us-east-2
Endpointhttps://s3.<region>.amazonaws.com, e.g. https://s3.us-east-2.amazonaws.com
Where to find these

Open the bucket in S3 → Buckets → my-kuploy-backups → Properties → Bucket overview: it shows the AWS Region (e.g. us-east-2) and the bucket ARN (arn:aws:s3:::my-kuploy-backups). The Bucket field above is just the name, and the Endpoint is https://s3. + that region + .amazonaws.com.

Click Test connection to confirm the credentials, then Create.

Back up the instance

  1. Go to Settings → Maintenance → Backups → Create Backup.
  2. Pick your Destination, a Schedule (cron) and an optional Prefix (a folder inside the bucket).
  3. Keep the latest — optionally cap how many backups are retained; older ones are pruned automatically. Leave it empty to keep every backup (no pruning — the default).
  4. Save. Use the Run (▶) action on a backup to take one immediately, or let the schedule run it. The checklist icon on a backup lists its recent runs (status + logs).

Each backup is a single archive in your bucket containing the instance database and its configuration files.

Restore

Restore is reached from Settings → Maintenance → Backups → Restore Backup. Pick the destination and the backup file, then choose where to restore to.

Restores the backup's database into a separate, empty database you provide — the running instance's database and filesystem are never touched. Use it to validate a backup, stand up a clone, or migrate to fresh infrastructure. It's safe and ungated because nothing on the live instance changes.

  1. Prepare an empty target database on your Postgres server. It must already exist (the restore populates it) and should be empty:

    CREATE DATABASE kuploy_restore;
  2. In Restore Backup, choose your Destination and the backup file (instance-backup-<timestamp>.zip).

  3. Under Restore to, select New / external database.

  4. In Target database URL, enter the connection string of that empty database, e.g. postgresql://user:password@host:5432/kuploy_restore.

  5. Click Restore and watch the log until "Restore completed successfully!" (you'll also get a success toast).

  6. Verify the copy by connecting to the target and checking your data landed:

    SELECT name FROM organization;
    SELECT name FROM project;
  7. To actually run on the restored copy, point a fresh kuploy instance at that database (its DATABASE_URL). On first boot it re-applies any newer migrations (see the note below).

"Ignored, non-fatal errors"

The restore log may end with pg_restore reported ignored, non-fatal errors. That's normal when the backup was taken with a newer Postgres than the target (e.g. a SET transaction_timeout the older server doesn't recognise) — the restore still completes. Use matching Postgres major versions if you want a clean log.

In-place restore (destructive)

Overwrites the running instance's own database and configuration, rolling every organization back to the backup. Use only for genuine disaster recovery.

Because it's irreversible, kuploy requires you to type the instance name to confirm, and it automatically takes a fresh pre-restore backup first so you can recover the current state if needed.

After restoring an older backup

Restoring a whole-database backup also resets the instance's schema to that backup's version. On the next start, kuploy re-applies its forward migrations to catch the schema back up. Let migrations finish converging before trusting the instance, and consider running Clean Redis afterward to drop cache and sessions that reference the pre-restore state.

Restore history

Every restore is recorded and listed under Settings → Maintenance → Restore history, newest first — its status (running / done / error), whether it was in-place or restore-to-new, the backup file and destination, when it ran, and any error. Use it as an audit trail of what was restored and whether it succeeded.

Other maintenance actions

  • Reload Server — restarts the web server process. The panel is briefly unavailable while it comes back up.
  • Clean Redis — flushes the instance's Redis, clearing cached state and sessions for every organization on it. Requires a typed confirmation. Users stay signed up but will need to sign in again.