There is an old saying that people fall into two groups: those who make backups and those who are about to start. They usually start the day after a disk failure, a ransomware attack or an unfortunate “DROP TABLE” at 4:59 pm on a Friday. In this article we go beyond the saying: we show what a sensible backup strategy looks like for a company website, an online store and a server, from the classic 3-2-1 rule to the things almost everyone forgets.
Backups without illusions: the 3-2-1 rule in practice for websites, online stores and servers
15.10.2026 | Author: Marcin Wiercioch
The 3-2-1 rule (and its newer extensions)
The foundation of every backup strategy fits in three digits:
- 3: keep at least three copies of your data (production plus two backups),
- 2: on two different media or systems (for example the server disk and object storage),
- 1: including at least one copy outside the main location (another data centre, another cloud).
Modern practice extends this to 3-2-1-1-0: the extra one is an offline or immutable copy, one that neither ransomware nor an attacker with a stolen password can delete, and the zero means “zero errors in a test restore”. More on that zero in a moment, because it is the most often ignored part of the whole puzzle.
What exactly needs to be backed up for a website?
“I back up the files” is not enough. A complete website backup has at least four layers:
- the database: in WordPress and online stores this is where everything most valuable lives: content, orders, customers,
- application files: the theme, plugins and above all the uploads directory with media, which cannot be recreated from a repository,
- configuration: nginx/Apache virtual hosts, PHP, crontab, certificates, environment variables; without them, restoring a server is archaeology,
- things “next to” the server: the DNS zone, CDN/WAF configuration, API keys. Exporting a DNS zone takes a minute, and when taking over a project after an outage it can be worth its weight in gold.
If you keep your code in a git repository (as we do), you can restore the theme files from the repo, but the database and uploads always need their own backup.
Company website: a sensible minimum
For a business card website or a WordPress blog, a simple rhythm is enough: the database daily, files weekly, plus an extra copy before every plugin and core update. There are two practical requirements: backups must leave the server (more on that below) and they must be created automatically, because a backup “made manually when there is a spare moment” statistically does not exist. Treat your hosting provider’s backup as a nice extra, not a strategy: it is sometimes on the same machine, sometimes unavailable exactly when the whole server is down, and its retention rarely exceeds a few days.
Online store: every hour counts
In an online store, the database is literally money: losing a day of orders means real losses and chaos in the warehouse. That is why in e-commerce it is worth knowing two abbreviations that administrators use:
- RPO (Recovery Point Objective): how much data you can afford to lose. For a store, a sensible RPO is minutes or a few hours, not a day,
- RTO (Recovery Time Objective): how quickly you need to be back up. What good is a backup if restoring it takes three days?
In practice this means: a database dump every hour (or continuous archiving of MySQL binlogs), files once a day and, at a larger scale, a database replica in a second location. Watch out for a classic trap: replication is not a backup. A replica will dutifully repeat an accidental deletion of data too. And then there is GDPR: backups contain customers’ personal data, so the same rules apply to them as to production: encryption, access control and retention.
Server: an automation that runs by itself
At the VPS level it is worth combining two worlds: snapshots of the whole machine at the provider (fast recovery after a total failure) and application backups (database plus files), which let you restore a single item without restoring everything. Here is the skeleton of a script that handles the second part and sends the backup off the server, to Cloudflare R2, which we wrote about recently:
#!/bin/bash
set -euo pipefail
STAMP=$(date +%Y-%m-%d_%H-%M)
BACKUP_DIR=/var/backups/site
mysqldump --single-transaction --quick shop_db | gzip > "$BACKUP_DIR/db_$STAMP.sql.gz"
tar -czf "$BACKUP_DIR/files_$STAMP.tar.gz" -C /var/www/site wp-content/uploads
rclone copy "$BACKUP_DIR" r2:backups/site --include "*_$STAMP*"
# lokalnie trzymamy tylko 7 dni
find "$BACKUP_DIR" -type f -mtime +7 -delete
Add a cron entry and an error notification, and you are done. It is worth encrypting sensitive backups before uploading them (with age or gpg), so that even a leak from the bucket is not a disaster. Just remember that the decryption key must not live only… on the server being backed up.
Where to keep backups?
The shortest answer: not where production is. A backup on the same disk dies with the disk, and a backup on the same hosting account dies with a compromised account. Good options are object storage (R2, S3, Backblaze B2) in a different location, with two additions:
- multi-level retention: for example 7 daily, 4 weekly and 12 monthly copies. This protects you from the scenario “the error was spotted after three weeks, and all backups have already been overwritten”,
- immutability (object lock / versioning): a copy that nobody, not even an administrator, can delete for a set period. It is the best insurance against ransomware and stolen API keys. A separate account and credentials used only for backups is standard practice, not paranoia.
A backup you have not tested does not exist
Back to the zero in the 3-2-1-1-0 formula. Backups can be empty, cut off halfway, encrypted with a key nobody has, or taken from a stopped database. The only way not to find this out on the day of an outage is a regular test restore: once a quarter, bring the website up from a backup in a test environment and click around for 10 minutes. Add monitoring of the process itself: you need to check not only “whether the backup succeeded” but above all whether it ran at all. A job that quietly stopped starting two months ago is a classic. Health checks work great for this (for example a ping after a successful script run), or Zabbix, which we described recently, with a trigger such as “no fresh backup file for 26 hours”.
Seven deadly sins
- a backup on the same server as production,
- backing up files without the database (or the other way round),
- treating replication or RAID as a backup,
- no backup before updates and deployments,
- an encrypted archive whose password only one person knows (or nobody),
- a retention of “the last 3 days”, while errors come to light after weeks,
- zero restore tests, in other words faith instead of knowledge.
Summary
A good backup is boring: it runs by itself, it is stored in several places, including one that cannot be touched, and every now and then someone checks that you can actually restore from it. All this “boredom” costs a fraction of what a single serious failure without a backup does. As part of our ongoing technical support, we set up exactly this kind of system for our clients, with automation, off-server copies and monitoring that will flag a missing backup before anyone needs it. Not sure whether your backups really work? Let’s check together, ideally before you need them.



