Skip to content
ViaLicense
99.98% UPTIME
EN Language
Sign in Become a reseller
Backup

A backup strategy that survives contact with reality: 3-2-1, incrementals and JetBackup retention

RAID is not a backup and neither is a snapshot. A practical look at applying 3-2-1 on a production server, how JetBackup 5 builds incrementals from hardlinks, how retention actually works, and what a real restore drill looks like.

In most hosting companies, backups are "solved" like this: install JetBackup, define a nightly job, see a green tick in the panel, move on. Then one morning /home remounts read-only, or a customer wipes a database with the wrong plugin. That is the day you find out whether the 40 days of archives you have been paying to store actually open.

This is about moving backups from "configured" to "proven to work".

What 3-2-1 means on an actual server

Three copies, two different media, one offsite. Translated to a hosting box, most setups turn out to be 1-1-0:

  • Backups sit on the same machine under /backup
  • Same RAID array, same chassis, same rack
  • The remote copy is still on the "we'll add it soon" list

RAID is not a backup. It keeps you online through a dead disk and does exactly nothing against rm -rf. An LVM or ZFS snapshot is not a backup either, because it lives in the same storage pool as the source. When the pool goes, the snapshot goes with it.

A layout that actually works usually looks like this:

  • Copy 1, local disk: a separate physical disk or NVMe. This one exists for speed. Single file or single database restores in minutes.
  • Copy 2, storage box on your network: an SSH destination. This is the copy you reach for when the whole server is gone.
  • Copy 3, object storage at a different provider: an S3-compatible destination, for datacenter-level events and ransomware.

The modern phrasing is 3-2-1-1-0: one copy immutable or offline, zero errors after verification. Those two extra digits exist entirely because of ransomware, and they come back later in this article.

How incremental backups really work

Numbers help. Take 200 accounts averaging 3 GB each, so 600 GB of live data.

  • Compressed full backup every night: you read 600 GB and write 250-400 GB of archives depending on content. Keeping 7 days costs well over 2 TB, and the disk is busy for hours every night.
  • Uncompressed (snapshot) backup: 600 GB the first night, then only changed files. On shared hosting the daily change rate is typically 1-3%, so 6-18 GB.

JetBackup 5 achieves this with hardlinks. Every backup folder looks like a complete directory tree, but unchanged files are just a second name pointing at the inode from the previous backup. It is easy to confirm:

  • Run stat /backup/.../public_html/wp-includes/version.php. If Links: says 14, then 14 names point at that inode, the live file included, and it occupies disk space once.
  • Running du -sh on a single backup folder shows the full size and misleads you. Measure the parent in one call instead: du -h --max-depth=1 /backup/jetbackup5/
  • Do not add -s to that command: du refuses to run when -s and --max-depth are combined. And because a single call counts each inode only once, the first folder looks huge and the later ones tiny. The number that means anything is the total at the bottom.

The payoff shows up during restores. To recover one file a customer deleted, you do not extract a 300 GB archive. You cp it.

The cost is inodes. A hardlink itself consumes no new inode, but every backup rebuilds the directory tree, so every folder takes a fresh inode, and so does every changed or newly created file. 200 accounts × ~60,000 files is already 12 million file inodes in the first copy alone, before you add the directories of 30 retention points and each day's changed files. If you are not watching df -i on the backup volume, you will meet this error while the disk is 40% full:

No space left on device

Plenty of space, no inodes left. Formatting the backup volume with a denser inode ratio (mkfs.ext4 -i 8192, one inode per 8 KB) or choosing XFS, which allocates inodes dynamically, makes a real difference here. It is also the decision that is most expensive to revisit two years later, because revisiting it means reformatting the volume.

What happens on destinations without hardlinks

This one usually gets discovered late. The incremental trick depends on hardlinks at the filesystem level, which means the incremental structure only works on destinations that support them: local disk and SSH. Object storage, Google Drive and Dropbox have no such concept, so writing there falls back to archive-style behaviour, and you should not expect the efficiency you see on local disk.

The practical consequence: do not copy your local policy to the remote destination. Thirty daily copies locally may be perfectly reasonable; the same policy pointed at S3 will surprise you on both storage and transfer. Weekly × 8 plus monthly × 6 is a sane starting point offsite.

Why the remote destination is not optional

The part that derails projects is the first upload. 600 GB over a 100 Mbit/s uplink takes about 13 hours in theory (600,000 MB ÷ 12.5 MB/s ≈ 48,000 seconds), and longer in practice, because real throughput never reaches the theoretical ceiling and the same link is usually carrying customer traffic. Schedule the initial seed for a weekend or a quiet window; every night after that is far smaller.

Choosing a destination type:

  • SSH/SFTP: hardlinks work, incremental efficiency is preserved, traffic is encrypted. The best option if you run your own storage box.
  • S3-compatible: high durability, plus versioning and object lock. Remember that restores generate egress charges, including the restores you do for testing.
  • FTP: still supported, but plain FTP puts both credentials and data on the wire in clear text. Make SSH/SFTP your default for offsite copies and keep FTP for the cases where nothing else is available.

There is a subtle point on the ransomware side. JetBackup needs delete permission on the destination in order to enforce retention at all. Which means that if the server is compromised, those same credentials can wipe the remote copy. The fix is not to remove the permission, it is to compensate on the destination side:

  • Turn on versioning and object lock on the bucket, so a deleted object stays recoverable for a defined window.
  • Or make the third copy a pull: the storage box connects and fetches, rather than the production server pushing.

Retention in JetBackup lives on the schedule, not the job

This is the most commonly misread part of JetBackup 5. Retention is attached to the schedule, not to the backup job. You add several schedules to one job, and each carries its own retain value:

  • Daily, retain 14
  • Weekly, retain 8
  • Monthly, retain 6

Combine those three on a single job and you have a classic GFS rotation: daily granularity for two weeks, weekly for two months, monthly for half a year. Admins coming from JetBackup 4 keep looking for retention on the job itself and end up with far shorter history than they think.

The second setting people conflate with it is retention for removed accounts. When an account is deleted from the server, its backups do not disappear at that moment; a separate rule governs how long they survive. That number is the only thing that saves you when an annual customer cancels and comes back 40 days later. Set it deliberately instead of inheriting the default.

Third: if you do not set reserved space (Reserved Space) on the destination, the volume can fill before retention gets a chance to prune anything, and the queue starts throwing errors. Never make the entire backup volume available to the backups themselves; always keep a margin.

A backup you have never restored is not a backup

The line is a cliché, and in most companies it is also the one task nobody has ever performed. A real drill looks like this:

  • Once a month, pick a random account. Not the smallest one.
  • Restore it to a test server, or under a different username on the same box.
  • Compare file counts: find /home/username -type f | wc -l
  • Check row counts on tables that matter. For WordPress, SELECT COUNT(*) FROM wp_posts; is a decent first look.
  • Point your own hosts file at the test server and confirm the site genuinely loads.
  • Time it. "Restoring 600 GB takes 5 hours 20 minutes" is the single most useful number you will have, both when writing contracts and when the room is on fire.

Write down two figures: RPO, how much data loss is acceptable (if you back up at 03:00, your worst case is roughly 24 hours), and RTO, how long it takes to be serving again.

The most common surprise in a drill comes from what the job actually includes. If the backup job was scoped to the home directory only, a restore brings back files but not DNS zones, SSL certificates, cron entries, email filters or FTP accounts. The site loads and nobody receives mail. Far cheaper to learn that in a drill than during an incident.

If you enable encryption, the same discipline applies to the key: lose it and the backups are unrecoverable. Keep it off the server being backed up, and include it in the drill.

Practical notes on cPanel and DirectAdmin

  • Once the JetApps repository is in place, installation is a single package: jetbackup5-cpanel or jetbackup5-directadmin. The interface and the concepts are largely identical across both panels.
  • JetBackup 5 keeps its own data in MongoDB. Logs live under /usr/local/jetapps/var/log/jetbackup5/, which is the first place to look when the queue stalls.
  • You can drive it from the shell: jetbackup5api -F listBackupJobs and jetbackup5api -F listQueueItems are enough to feed a monitoring script.
  • Letting end users run their own restores cuts support load noticeably. Most "please roll me back to yesterday" tickets never reach you.
  • To be fair about the weak spots: during the first full backup, MongoDB and the queue workers put real pressure on low-memory servers. On a 2 GB box, expect I/O and memory strain that first night. And if you are migrating from JetBackup 4, the interface and terminology differ enough that you should not attempt it on a busy day.

Licensing is the simple part. A JetBackup license binds to the server's IP address, not to a key file, so when you move the backup server you change the IP yourself in the panel and the old address stops immediately. Activating a JetBackup license draws from a prepaid balance with no approval step, and installation is a single command on the server, with the script finding the license by IP. The cPanel or DirectAdmin license on the same machine is managed from the same place, alongside the rest of the backup licenses.

But the license is not the interesting part. If you only take one action from this article today, restore a random account onto a test server and time it. The result will tell you more about your backup strategy than every green tick in the panel.

Every licence in this article is one you can order from the panel, bound to your server's IP and working within a minute.