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

5.3 KiB
Raw Permalink 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).