Backup strategies: snapshots vs backups and the 3-2-1 rule

The 3-2-1 rule means keeping 3 copies of your data on 2 different types of media, with 1 copy offsite. Platform snapshots help, but they count as a single layer.

Updated 6 min read

Learning objectives

After reading this article you will be able to:

  • Apply the 3-2-1 rule to an app and its database
  • Tell backups, snapshots and replicas apart
  • Set up a scheduled backup with an offsite copy and a restore test
On this page

Almost everyone who hosts an app has lost data, or knows someone who has: a DROP TABLE in the wrong environment, a dying disk, a locked account, ransomware. What separates a scare from a disaster is having a recent copy, somewhere else, that you already know how to restore.

The 3-2-1 rule is the simplest way to organize that. For an app with a database, it tells you how many copies to keep, where each one goes and what role platform snapshots play.

3copies2media types1offsitesamesiteProductionthe live databasedaily dumpAnother diskdump or snapshotencryptedAnother providerobject storagesurvives alost account
Three copies, on two media types, with one offsite: only that one survives if you lose the whole account.

What is the 3-2-1 backup rule?#

The paper "Data Backup Options", written for US-CERT (now part of CISA), sums it up like this:

  • 3 copies of any important file: 1 primary and 2 backups.
  • 2 different media types, to protect against different hazards.
  • 1 copy stored offsite.

The idea is that each kind of failure takes down at most one copy. A broken disk hits one medium. A fire, an account mistake or a break-in hits everything in the same place, which is why one copy must be far away. The paper cites Peter Krogh's book The DAM Book as the source of the rule.

Today "different media" is read more broadly: a local disk plus object storage, or two independent providers. The principle stays the same: pick places that don't fail together.

How do you apply it to an app and its database?#

Start by listing what you would lose and couldn't recreate. For a bot, API or website, that's usually four things:

What Where it lives How to protect it
Code Git repository The remote repository is already an offsite copy. Clone it on another machine for one more.
Database Database server Scheduled dump (pg_dump, mysqldump, mongodump) sent offsite. See how to back up a database.
Uploaded files Disk or object storage Periodic copy to another destination.
Environment variables Platform dashboard Keep the .env in a password vault, never in Git. See what is a .env file.

A typical setup looks like this:

  1. Copy 1: the production database.
  2. Copy 2: the daily dump on the same server, or a platform snapshot. Cheap and fast to restore.
  3. Copy 3: the encrypted dump in object storage at another provider. This is the offsite copy.

Copy 3 is the only one that survives if the whole account is lost, which is why it matters more than the other two.

What is the difference between a backup, a snapshot and a replica?#

  • Backup: a point-in-time copy you control, stored apart from the source and restorable anywhere. This is what the 3-2-1 rule counts.
  • Snapshot: a copy taken by the platform your app or database runs on, restored from its dashboard. It's quick and convenient, but it stays inside the same platform. For the rule, it counts as a good layer, but only one.
  • Replica: a second instance that follows the first in real time. It helps availability, but it copies mistakes too. A DELETE without WHERE reaches the replica within seconds, so it doesn't protect you from human error.

Snapshots and dumps complement each other. A snapshot handles "undo yesterday's mistake" in minutes. A dump at another provider handles "I lost the account".

How do you set up an automated backup with an offsite copy?#

The example uses PostgreSQL and restic, an open source tool that encrypts your data, deduplicates it and uploads it to S3 destinations. Swap the dump for mysqldump or mongodump if you use another database.

Prerequisites: pg_dump and restic installed, an S3 bucket at another provider, and credentials in environment variables. Create the repository once:

bash
export AWS_ACCESS_KEY_ID="..."           # keys for the destination bucket
export AWS_SECRET_ACCESS_KEY="..."
export RESTIC_PASSWORD="a-long-passphrase" # encrypts the repository
export RESTIC_REPOSITORY="s3:https://endpoint.example.com/my-bucket"

restic init

If you lose RESTIC_PASSWORD, the repository can no longer be opened. Keep it in a password vault, off the server. Then the daily script:

bash
#!/usr/bin/env bash
set -euo pipefail
set -a; source /etc/backup.env; set +a  # load and export DB_*, PGPASSWORD, AWS_* and RESTIC_*

DIR=/var/backups/app
mkdir -p "$DIR"

pg_dump -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -Fc -f "$DIR/db.dump"  # 1. dump the database (custom format, already compressed)

restic backup "$DIR" /srv/app/uploads  # 2. send the dump and user uploads offsite

restic forget --keep-daily 7 --keep-weekly 4 --prune  # 3. keep 7 daily and 4 weekly, drop the rest

restic check  # 4. verify the repository integrity

The script reads DB_HOST, DB_USER and DB_NAME from the environment, and pg_dump reads the password from PGPASSWORD or ~/.pgpass, so it never shows up in shell history. Cron doesn't inherit your shell, so the top of the script loads all of these, plus AWS_* and RESTIC_*, from /etc/backup.env (with 600 permissions). set -a exports them to pg_dump and restic, which a plain source doesn't do. Schedule it with cron at 3 a.m.: 0 3 * * * /opt/backup.sh >> /var/log/backup.log 2>&1. If cron is new to you, see what is a cron job.

restic also calls its restore points "snapshots", but they live in your bucket and have nothing to do with a platform's snapshots. prune locks the repository while it runs, so don't schedule it at the same time as another backup. To choose the offsite destination, see backups to object storage.

How do you know the backup works?#

A backup that has never been restored is just a hope. Test it for real, at least once a quarter, with the same RESTIC_* and AWS_* variables exported:

bash
restic restore latest --target /tmp/restore-test
createdb restore_test
pg_restore -d restore_test --no-owner /tmp/restore-test/var/backups/app/db.dump
psql -d restore_test -c "SELECT count(*) FROM orders;"

Replace orders with one of your tables. Compare the count with production and note how long the restore took: that is your real recovery time. If the restore fails, the script needs fixing, and it's better to learn that now than on the day of the incident.

What are common backup mistakes?#

  • Backing up only to the same server or account. Lose the server, lose everything. The offsite copy is not optional.
  • Never testing a restore. The error shows up when you need the backup most.
  • A script that fails silently. Use set -euo pipefail and alert when the job does not run (an external monitor that expects a "ping" at the end covers this).
  • Forgetting uploads and the .env. The database is safe, but the app won't start without its secrets.
  • Keeping the encryption passphrase only on the server. If the server disappears, the copy becomes unreadable.
  • Retention that is too short. If a mistake goes unnoticed for ten days and you keep seven, every copy is already contaminated.

How to do this on Square Cloud#

On Square Cloud, snapshots fill the fast-recovery layer, copy 2 in the setup above. Databases get an automatic daily snapshot on every plan that includes them, and applications from the Pro plan. Each is kept for 7 days, with the most recent kept for up to 30 days. On any plan you can take manual snapshots before a risky change.

An application snapshot restores in full to the same application or another one, including a new application, in one click in the dashboard. A database snapshot restores to the same database, another one of the same engine or a new database. You can also download a database snapshot as a .zip, and that download is the starting point for your offsite copy: store the file outside the platform, next to the scheduled dump from the example above.

Also keep the code on GitHub and the environment variables saved somewhere safe: the dashboard imports and exports the .env in KEY=VALUE format. Retention and restore details are on the snapshots page.

Deploy

Push from GitHub, the CLI or a ZIP and go live in seconds

Learn more

FAQs

What does the 3-2-1 backup rule mean?

Keep 3 copies of your data (1 primary and 2 backups) on 2 different types of media, with 1 copy offsite. US-CERT describes it in 'Data Backup Options' and credits the rule to Peter Krogh.

Are snapshots and backups the same thing?

No. A snapshot is a copy taken by the platform your app runs on and restored from its dashboard. A backup, in the 3-2-1 sense, is a copy you control and store elsewhere, so it survives even if the account or platform fails.

Do I need to back up my code if it is on GitHub?

The repository is already an offsite copy, but only of the code. Environment variables, user uploads and the database are not in it and need their own backup.

How often should I back up?

It depends on how much data you can afford to lose. If losing up to a day is acceptable, a daily backup is enough. If not, back up every hour.

Is a replica a backup?

No. A replica copies mistakes too: a DELETE without WHERE reaches it within seconds. A backup keeps old states, while a replica only holds the current one.

Next articleDeploy failed: how to read build errorsA failed build prints dozens of lines, but only one matters. Learn to find the first real error, match it to its cause and fix npm, pip and TypeScript failures.

More in Deploy

See all 33 articles