Backing Up to a NAS Every Night — tar+ssh (and Why Not rsync)
Self-Hosting Build Guide, Part 12. We secured the server (Part 11). Now: how to save the data even when the server dies.
← Previous: Part 11 — Free WordPress Defense (Wordfence)
→ Next: Part 13 — My Notes on My Server (Obsidian LiveSync)
TL;DR
- Self-hosting without backups is a time bomb — one dead disk and your posts, photos, and database vanish at once
- Every night a cron job tars the important folders and ships them to a NAS over
ssh - We deliberately skipped
rsync(which needs its own daemon on port 873) — ssh is already open, so zero extra ports - The DB dump must finish before the file backup runs, so that dump is included in the same bundle — order creates consistency
- “The backup ran” and “the backup succeeded” are different — a 0-byte file is a failure
1. No Backups = a Time Bomb
Putting a blog on your own computer means the backups the cloud used to handle are now your job. One SSD reaches end of life, or one mistyped command, and months of posts, photos, and databases disappear in an instant.
The rule is simple: back up to a different physical device, automatically, every day. Manual backups always get forgotten.
2. Why tar + ssh Instead of rsync
For backups, most people reach for rsync — fast, with incremental sync. But to use rsync properly with a NAS (here, a Synology) you have to turn on its rsync daemon (port 873). That’s one more open port.
| Item | rsync daemon | tar + ssh |
|---|---|---|
| Extra ports to open | needs 873 | 0 (reuses existing ssh) |
| Incremental transfer | yes | full each time |
| Setup complexity | service + permissions | one line |
| Attack surface | grows | unchanged |
Our data is small, so bundling it whole every day costs nothing. In that case there’s no reason to pay the price of another open port. Shrinking attack surface is almost always the right call in self-hosting.
3. A One-Line Backup
tar czf - /important/data/folder | ssh -p <port> [email protected] "cat > /backup/site-$(date +%F).tgz"
tar czf - bundles the folder and streams it to stdout, and ssh catches that stream and drops it as a file on the NAS. No temp file in the middle, so it uses less disk too. The date ($(date +%F)) in the filename means each day stacks under a different name.
4. Order Creates Consistency — DB First
You can’t just copy a database’s folder. Copy it mid-write and you back up a half-written state. So first dump the DB safely to a file, and the file backup must run after that dump finishes.
flowchart LR
A[04:30 DB dump] --> B[dump file created]
B --> C[05:00 file backup
bundles the dump]
C --> D[ship to NAS]
That’s why the two are staggered. The order of the two cron jobs is the consistency of the backup.
5. Verify “Success”
The most common illusion: if cron fired on schedule, you assume the backup happened. But running is not succeeding. If the disk was full or the NAS briefly went down, you’re left with an empty 0-byte file.
- After the backup, check the size of the file that was created
- If it’s below a threshold, treat it as failed and send an alert
- Auto-delete old backups (rotate) so the disk doesn’t fill up
Add those three lines and your backup escapes the classic trap of “I thought it was there, but it was empty.”
In One Line
Back up to another device, automatically, every day. tar czf - … | ssh ships to a NAS without opening one more port. DB dump first, then the file backup. And check the size to verify “success” — an empty backup is not a backup.

Leave a Reply