Seagate Backup SSD

Overview

Secondary external SSD for weekly redundancy. Mirrors the primary Seagate drive for 2-copy USB protection. Uses simpler flat directory structure (no subvolumes) for straightforward recovery.

Property Value

Capacity

2TB USB-C

Encryption

LUKS2 (aes-xts-plain64, 256-bit)

Filesystem

btrfs with zstd compression (no subvolumes)

Mount Point

/mnt/seagate-backup/

Frequency

Weekly (sync from primary)

Passphrase

gopass show v3/domains/d000/storage/seagate/backup

Why Two Drives

Defense in Depth

Risk Mitigation

Drive failure

Second drive has identical data

Ransomware

Offline drive can’t be encrypted by malware

Theft

Off-site drive survives home break-in

User error

Weekly sync means max 7 days data loss

Fire/flood

Geographic separation (one off-site)

Primary vs Backup Differences

Aspect Primary Backup

Structure

btrfs subvolumes (@secrets, @configs, etc.)

Flat directories (secrets/, configs/, etc.)

Mount

4 separate mounts per subvolume

Single mount at root

Snapshots

Yes (@snapshots subvolume)

No (mirror only)

Use case

Daily incremental backup

Weekly full mirror

Recovery

Granular (mount individual subvols)

Simple (mount, copy)

Why flat on backup? Simplicity for disaster recovery. When panicking, mount + cp is easier than subvolume mounts.

Directory Structure

/mnt/seagate-backup/
├── secrets/      # Mirror of primary @secrets
│   ├── .secrets/
│   ├── gnupg/
│   ├── password-store/
│   ├── ssh/
│   └── pki/
├── configs/      # Mirror of primary @configs
│   ├── dotconfig/
│   ├── dotlocal/
│   ├── ansible/
│   ├── claude/
│   └── bin/
├── backups/      # Mirror of primary @backups
│   └── mozilla/
└── storage/      # Mirror of primary @storage
    ├── atelier/
    ├── Documents/
    └── Pictures/

Script Internals

seagate-backup-mount

Simpler than primary - single mount, no subvolumes:

#!/bin/bash
set -euo pipefail

DEVICE="${1:-/dev/sda1}"        # Default device (different from primary)
MAPPER_NAME="seagate-backup"    # Different mapper name
MOUNT_BASE="/mnt/seagate-backup"

# Idempotent check
if mountpoint -q "$MOUNT_BASE" 2>/dev/null; then
    echo "Already mounted at $MOUNT_BASE/"
    ls -la $MOUNT_BASE/
    exit 0
fi

# Open LUKS - prompts for passphrase
echo "Opening LUKS volume..."
sudo cryptsetup open "$DEVICE" "$MAPPER_NAME"

# Single mount at root (no subvolumes)
sudo mkdir -p "$MOUNT_BASE"
sudo mount /dev/mapper/$MAPPER_NAME $MOUNT_BASE

# Set ownership
sudo chown $USER:$USER $MOUNT_BASE
sudo chown -R $USER:$USER $MOUNT_BASE/* 2>/dev/null || true

echo "Mounted at $MOUNT_BASE/"
ls -la $MOUNT_BASE/

Key difference from primary: No -o subvol=@name. Mounts btrfs root directly.

seagate-sync-to-backup

Mirrors all 4 directories from primary to backup:

#!/bin/bash
set -euo pipefail

PRIMARY="/mnt/seagate"
BACKUP="/mnt/seagate-backup"

# Verify BOTH drives mounted
if ! mountpoint -q "$PRIMARY/secrets" 2>/dev/null; then
    echo "Primary not mounted. Run seagate-primary-mount first."
    exit 1
fi

if ! mountpoint -q "$BACKUP" 2>/dev/null; then
    echo "Backup not mounted. Run seagate-backup-mount first."
    exit 1
fi

echo "=== SEAGATE SYNC: PRIMARY → BACKUP ==="
echo "Started: $(date)"

# Mirror each directory
# rsync from primary subvolume mounts to backup flat dirs
echo ">>> Syncing secrets..."
rsync -av --delete $PRIMARY/secrets/ $BACKUP/secrets/

echo ">>> Syncing configs..."
rsync -av --delete $PRIMARY/configs/ $BACKUP/configs/

echo ">>> Syncing backups..."
rsync -av --delete $PRIMARY/backups/ $BACKUP/backups/

echo ">>> Syncing storage..."
rsync -av --delete $PRIMARY/storage/ $BACKUP/storage/

echo "=== SYNC COMPLETE ==="
echo "Finished: $(date)"

# Show sizes for verification
echo ""
echo "Primary:"
du -sh $PRIMARY/secrets $PRIMARY/configs $PRIMARY/backups $PRIMARY/storage
du -sh $PRIMARY/

echo ""
echo "Backup:"
du -sh $BACKUP/secrets $BACKUP/configs $BACKUP/backups $BACKUP/storage
du -sh $BACKUP/

Why sync instead of backup script?

  • Primary already has clean, --delete’d mirrors

  • Sync just copies those mirrors to second drive

  • Faster than re-running all rsync from source

  • Ensures backup matches primary exactly

seagate-backup-umount

#!/bin/bash
set -euo pipefail

MOUNT_BASE="/mnt/seagate-backup"
MAPPER_NAME="seagate-backup"

echo "Syncing..."
sync

echo "Unmounting..."
sudo umount $MOUNT_BASE

echo "Closing LUKS..."
sudo cryptsetup close $MAPPER_NAME

echo "Done. Safe to remove."

Weekly Workflow

Complete Sequence

# 1. Run daily backup to primary first
seagate-primary-mount
seagate-primary-backup

# 2. Mount backup drive
seagate-backup-mount

# 3. Sync primary → backup
seagate-sync-to-backup

# 4. Verify sizes match
# Primary and backup should show identical sizes

# 5. Unmount both
seagate-primary-umount
seagate-backup-umount

Expected Output

=== SEAGATE SYNC: PRIMARY → BACKUP ===
Started: Tue Feb 17 08:34:00 PM PST 2026

>>> Syncing secrets...
>>> Syncing configs...
>>> Syncing backups...
>>> Syncing storage...

=== SYNC COMPLETE ===
Finished: Tue Feb 17 08:36:00 PM PST 2026

Primary:
235M    /mnt/seagate/secrets
6.9G    /mnt/seagate/configs
692M    /mnt/seagate/backups
20G     /mnt/seagate/storage
28G     /mnt/seagate/

Backup:
235M    /mnt/seagate-backup/secrets
6.9G    /mnt/seagate-backup/configs
692M    /mnt/seagate-backup/backups
20G     /mnt/seagate-backup/storage
28G     /mnt/seagate-backup/

Off-Site Rotation Strategy

For true disaster protection, rotate one drive off-site:

Rotation Schedule

Week Primary Drive Backup Drive Action

Week 1

Home (daily use)

Off-site (bank/family)

Daily backups to primary only

Week 2

Home (daily use)

Bring home for sync

Sync primary → backup, return off-site

Week 3

Home (daily use)

Off-site

Daily backups continue

Week 4

Home (daily use)

Bring home for sync

Sync, return off-site

Off-Site Options

Location Pros Cons

Bank safe deposit box

Fire/flood/theft proof, secure

Limited access hours, monthly cost

Trusted family (different city)

Geographic separation, free

Requires trust, travel for rotation

Office desk drawer

Convenient access

Same metro area (shared disaster risk)

Label drives clearly: "SEAGATE-1 PRIMARY" and "SEAGATE-2 BACKUP". Use different colored labels or tape.

Initial Setup

One-time setup for the backup drive:

# 1. Create LUKS2 container
sudo cryptsetup luksFormat --type luks2 \
    --cipher aes-xts-plain64 \
    --key-size 512 \
    --hash sha256 \
    --iter-time 5000 \
    /dev/sdX1
# 2. Open and format (no subvolumes - flat btrfs)
sudo cryptsetup open /dev/sdX1 seagate-backup
sudo mkfs.btrfs -L seagate-backup /dev/mapper/seagate-backup
# 3. Mount and create directories
sudo mount /dev/mapper/seagate-backup /mnt/seagate-backup
sudo mkdir -p /mnt/seagate-backup/{secrets,configs,backups,storage}
sudo chown -R $USER:$USER /mnt/seagate-backup/*
# 4. Initial sync from primary (primary must be mounted)
seagate-sync-to-backup
# 5. Unmount
sudo umount /mnt/seagate-backup
sudo cryptsetup close seagate-backup

LUKS Header Backup

# Backup header
sudo cryptsetup luksHeaderBackup /dev/sdX1 \
    --header-backup-file seagate-ssd2-$(date +%Y%m%d).img
# Encrypt with age
age -e -R ~/.config/age/recipients.txt \
    -o ~/.secrets/luks-headers/seagate-ssd2-$(date +%Y%m%d).img.age \
    seagate-ssd2-$(date +%Y%m%d).img
# Shred plaintext
shred -vzn 3 seagate-ssd2-$(date +%Y%m%d).img

Recovery from Backup Drive

If primary is lost or primary workstation destroyed:

Mount Backup

# On new/recovered system
sudo cryptsetup open /dev/sdX1 seagate-backup
sudo mount /dev/mapper/seagate-backup /mnt/seagate-backup

Restore Critical Secrets

# 1. Restore dsec/age
mkdir -p ~/.secrets
rsync -av /mnt/seagate-backup/secrets/.secrets/ ~/.secrets/
chmod 700 ~/.secrets
chmod 600 ~/.secrets/.metadata/keys/*
# 2. Restore GPG
rsync -av /mnt/seagate-backup/secrets/gnupg/ ~/.gnupg/
chmod 700 ~/.gnupg
chmod 600 ~/.gnupg/*
# 3. Restore gopass
rsync -av /mnt/seagate-backup/secrets/password-store/ ~/.password-store/
mkdir -p ~/.local/share/gopass/stores
rsync -av /mnt/seagate-backup/secrets/password-store/ ~/.local/share/gopass/stores/root/
# 4. Restore SSH
rsync -av /mnt/seagate-backup/secrets/ssh/ ~/.ssh/
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_* ~/.ssh/config 2>/dev/null || true

Restore Configs (Optional)

rsync -av /mnt/seagate-backup/configs/dotconfig/ ~/.config/
rsync -av /mnt/seagate-backup/configs/dotlocal/ ~/.local/

Test Recovery

# Verify dsec works
dsec show d000 dev/network

# Verify gopass works
gopass ls

# Verify SSH works
ssh-add -l

Verification Checklist

After weekly sync:

  • Both drives show same total size (~28GB)

  • secrets/ sizes match

  • configs/ sizes match

  • backups/ sizes match

  • storage/ sizes match

  • Both drives unmount cleanly

  • Backup drive stored securely (safe or off-site)