Files
obsidian-vault/200 projects/220 Web Host Migration/Backup Architecture — Offsite to AWS S3.md

5.3 KiB
Raw Blame History

created, modified, type, client, project, status, priority, tags, aliases, id
created modified type client project status priority tags aliases id
2026-08-28 2026-08-28 project sam web-host-migration active 1
backup
aws
s3
glacier
obsidian
backup-architecture
offsite-backup
1848129024-BAC

Backup Architecture — Offsite to AWS S3 (Disaster / "House burns down")

Part of Migration Plan — InMotion to Local + AWS Offsite, Phase 1. Status: bucket + lifecycle + pipeline built & validated. Seeding pending user go/no-go. Source-set refined from the Google-photos migration note (see "Source set" below).

Why

Protect the "house burns down" set off-machine so a total local loss doesn't destroy photos, site data, or Borg backups. Local copies alone (Borg/rsync/Kopia between .13/.35/.23) are all on-site — a fire takes them all. AWS is the off-site copy.

Tech stack (what we actually use)

  • AWS S3 bucket sam-offsite-backup — region ap-southeast-2 (Sydney)
    • Block all public access, Versioning Enabled, SSE-S3 server-side encryption at rest
    • Lifecycle rule archive-to-glacier: S3 Standard (first 90 days, fast restore) → Glacier Flexible @ 90d → Glacier Deep Archive @ 180d (cold/cheap)
  • IAM user backup-offsite — programmatic, least-privilege, only object-level S3 on this one bucket (ListBucket/PutObject/GetObject/DeleteObject). No bucket-management, no console, no other AWS services. Root keeps full power.
  • Tool: AWS CLI aws s3 sync (chosen over rclone — rclone fought S3 region discovery with the scoped IAM; AWS CLI works with object-only perms). Validated: full upload/list/readback/delete test succeeded.
  • Local driver: pending — will be a NixOS systemd timer (won't be in backup.nix to avoid disrupting existing Borg; separate service) running from .13, reading creds from /home/sam/.aws-credentials.local (0600).

Source set (what we back up)

From .13 (unless noted):

Source Path Size
Photo master (by_date) /mnt/ubuntu_storage_3TB/archive/03_photos/by_date 373 GB
Immich phone-only .35:/mnt/hd/immich/library (via SSH to .35) small
Projects / notes / docs /mnt/ubuntu_storage_3TB/archive/ (01_family…08_transfer, minus 03_photos) ~177 GB
.27 Borg repo /mnt/ubuntu_storage_3TB/backup/borg/.27 162 GB
Total ~712 GB

Explicitly SKIPPED (duplicates/transient/regenerable)

  • by_subject (69 GB) — duplicate of by_date (different folder order)
  • /mnt/data/takeout/ (269 GB) — transient Google-photos download, deleted after verification
  • Immich thumbs / encoded-video — regenerable
  • 14 zip archives — redundant
  • Immich library copies of by_date photos — duplicates

Proposed bucket layout (prefixes)

s3://sam-offsite-backup/
├── photos/by_date/       (373G)
├── photos/phone-only/    (small, from .35 Immich)
├── archive/rest/         (177G)
└── borg/.27/             (162G)

Procedure to run a seed / sync

On .13 (after tooling installed):

source /home/sam/.aws-offsite-env.sh          # sets AWS_* from creds file
AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
  aws s3 sync /mnt/ubuntu_storage_3TB/archive/03_photos/by_date \
  s3://sam-offsite-backup/photos/by_date/ --storage-class STANDARD
  • s3 sync is incremental — after the initial seed, re-runs upload only new/changed files.
  • Bandwidth: ~3.3 MB/s measured → ~62 h for full 712 GB seed.

Cost (AUD, honest — revised 2026-08-28)

Seeding everything in S3 Standard (fast restore) means the first 90 days cost the most:

  • Months 0–3 (all S3 Standard): 712 GB × $0.036 ≈ **$26/mo**
  • Months 3–6 (Glacier Flexible): $0.005/GB ≈ **$3.6/mo**
  • After month 6 (Deep Archive): $0.0015/GB ≈ **$1.1/mo**
  • One-time upload bytes: free (AWS ingress is free) ✓

Cheaper option: send cold data straight to Glacier Deep Archive

If photos + archive are genuinely cold (only needed in disaster), upload them with --storage-class DEEP_ARCHIVE directly → no 90-day Standard wait, $1/mo immediately for the cold set. Only recent/active data (Borg .27 repo + phone-only) stays in Standard. Downside: Deep Archive restore takes hours (acceptable for disaster recovery). This could reduce peak to **$5–8/mo** total.

The two choices are a small cost-vs-restore-speed tradeoff; both are well under the 20–50 AUD/mo budget and ~75%+ cheaper than the retired $100 VPS.

Pending / Open

  • User confirms go/no-go on seed scope + storage class (Standard vs Deep Archive for cold set)
  • Install AWS CLI declaratively on .13 + systemd timer (managed NixOS service) — but not in existing backup.nix (protect current Borg jobs); separate config
  • Begin first seed (run overnight / across days given ~62 h)
  • Verify a test restore from S3 after seed (critical)
  • Decide optional "delete noncurrent versions" lifecycle to cap version bloat
  • Security: rotate access key after seeding (it was shared in chat); root MFA now enabled

*See Migration Work Log for live track record; Migration Plan — InMotion to Local + AWS Offsite §9 for the master cost model. ➡ Restore procedures: Restore Runbook (how to bring back each machine, local or S3).