UniFi UNAS-Pro Master Backup Strategy: Native Rsync Daemon (Pull) Architecture#

This document defines the complete operational standard, architecture, schedule matrix, node-by-node configuration reference, and disaster recovery procedures for backing up all shared data from the master UniFi UNAS-Pro NAS (10.1.2.2) across the fleet of 5 TrueNAS SCALE storage nodes (HP1, HP2, HP3, HP7, HP8). It is designed to be sufficient to fully reconstruct the entire setup from scratch.

Antigravity Chat: agy –conversation=4c0c9b6d-2722-4fd6-a4aa-638c75ab46f4


1. Executive Summary & Architecture Overview#

Historically, backups were driven by UniFi Drive UI-managed SMB (Push) tasks that wrote into auto-generated wrapper folders (such as UNAS Pro_HP1).

The current production architecture shifts 100% of backups to a Native Rsync Daemon (Pull) model:

               ┌──────────────────────────────────────────────────────────┐
               │              UNAS-Pro Master NAS (10.1.2.2)              │
               │        Exposes 12 Shared Rsync Modules over SSH/TCP      │
               └────────────────────────────┬─────────────────────────────┘
         ┌──────────────────┬───────────────┼───────────────┬──────────────────┐
         │ (Min :00)        │ (Min :20)     │ (Min :50)     │ (Min :30)        │ (Min :15)
         ▼                  ▼               ▼               ▼                  ▼
  ┌──────────────┐   ┌──────────────┐┌──────────────┐┌──────────────┐   ┌──────────────┐
  │ HP1 TrueNAS  │   │ HP2 TrueNAS  ││ HP3 TrueNAS  ││ HP7 TrueNAS  │   │ HP8 TrueNAS  │
  │ 10.1.2.201   │   │ 10.1.2.212   ││ 10.1.2.213   ││ 10.1.1.17    │   │ 10.1.2.208   │
  └──────────────┘   └──────────────┘└──────────────┘└──────────────┘   └──────────────┘

Key Architectural Principles:#

  1. Pull Model: Remote TrueNAS nodes initiate SSH/Rsync pulls. UNAS-Pro operates purely as a read-only source, preventing unauthorized write modifications to master data.
  2. Dataset Root Landing: Backups land directly at the root of target ZFS datasets without nested SMB wrapper directories (UNAS Pro_HP*).
  3. Staggered 24/7 Hourly Schedules: Backups run every hour, 24 hours a day, 7 days a week. Each server is assigned a distinct minute offset to eliminate I/O and network saturation on the UNAS-Pro.
  4. Git-Managed Standalone Scripts: Backup logic is maintained in a central Git repository, auto-mirrored to UNAS-Pro via Git post-commit hook, and synced to each TrueNAS node via Rsync.
  5. Native GMail Notifications: Execution logs are stored locally, pruned automatically after 30 days, and emailed via TrueNAS SCALE’s native middleware GMail OAuth integration (sudo midclt call mail.send).

2. Fleet Production Schedule Matrix#

Node IP Address ZFS Pool Target Dataset Path Modules Pulled Cron Schedule Log Path
HP1 10.1.2.201 RaidZ1SSDPool8TB /mnt/RaidZ1SSDPool8TB/HP1UNASBackup/ Books, Photos, Nadine, [Immich](Immich.md), Musique, Software, HomesDSM, Documents, Downloads, GoogleCloudSync 0 * * * * /mnt/homes/unas_backup/
HP2 10.1.2.212 Raid0SSDPool3TB /mnt/Raid0SSDPool3TB/HP2UNASBackup/ Books, Immich, Nadine, Photos, Musique, Software, HomesDSM, Documents 20 * * * * /mnt/Homes/unas_backup/unas_backup/
HP3 10.1.2.213 Medias /mnt/Medias/HP3Medias/ Films, TVSeries 50 * * * * /mnt/Homes/unas_backup/unas_backup/
HP7 10.1.1.17 Stripe4TB /mnt/Stripe4TB/HP7UNASBackup/ Books, Photos, Nadine, Immich, Musique, Software, HomesDSM, Documents, GoogleCloudSync 30 * * * * /mnt/Stripe4TB/Homes/unas_backup/
HP8 10.1.2.208 RaidZ1SSDPool8TB /mnt/RaidZ1SSDPool8TB/HP8UNASBackup//mnt/Medias/HP8Medias/ Books, Photos, Nadine, Immich, Musique, Software, HomesDSM, Documents, GoogleCloudSync, Films, TVSeries 15 * * * * /mnt/homes/unas_backup/

3. UNAS-Pro Source Configuration#

The master UniFi UNAS-Pro (10.1.2.2) exposes shared folders as Rsync modules over SSH (TCP 22). The following must be configured in the UniFi Drive Web UI.

⚙️ Step 1 — Enable Rsync Server (UniFi Drive Web UI)#

  1. Open UniFi Drive Web UI at https://10.1.2.2.
  2. Navigate to Settings > Services / Rsync.
  3. Toggle Enable Rsync Server to ON.

⚙️ Step 2 — Expose Shared Folders as Rsync Modules#

  1. Navigate to UniFi Drive > Shared Folders / Drives.
  2. Edit each shared folder and enable Expose as Rsync Module.
  3. Exposed modules (12 total):
    • Core Data: Books, Documents, Downloads, GoogleCloudSync, HomesDSM, Immich, Musique, Nadine, Photos, Software
    • Media: Films, TVSeries

⚙️ Step 3 — Add TrueNAS SSH Public Keys to UNAS-Pro#

Each TrueNAS node authenticates to UNAS-Pro using passwordless SSH keypairs. No local OS user needs to be created on UNAS-Pro. Keys are added to /root/.ssh/authorized_keys.

SSH into UNAS-Pro as root:

ssh root@10.1.2.2

Append each TrueNAS node’s public key:

echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICa5Yy936hW6B/YvX9pU09jN unas_backup@HP1TrueNAS" >> /root/.ssh/authorized_keys
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOB37h2+l37HNm5Cykgb7jANgFTv7uzZpYSOA8CFXggy unas_backup@HP2TrueNAS" >> /root/.ssh/authorized_keys
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH6N9s11W7KkX0w4q5N+z7M9 unas_backup@HP3TrueNAS" >> /root/.ssh/authorized_keys
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAAtWUhNjo/n4Z9fye+5SX/EwaS/+ws9UPUIY8ATc8rQ unas_backup@HP7TrueNAS" >> /root/.ssh/authorized_keys
echo "sh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK9Xa/Eicgg+BOpXZoa1J1VLXHn4Mu+j4TA6H/EMPJiw unas_backup@HP8TrueNAS" >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys

✅ Step 4 — Verify Rsync Modules Are Visible from a TrueNAS Node#

From any TrueNAS node SSH session (as unas_backup), run:

sudo -u unas_backup rsync -e "ssh -i /mnt/homes/unas_backup/.ssh/id_ed25519 -o StrictHostKeyChecking=no" root@10.1.2.2::

Expected output: a list of all 12 exposed modules.


4. Git Repository & Script Management#

Backup scripts are version-controlled and automatically distributed to UNAS-Pro via a Git post-commit hook.

Repository Setup (Mac Studio Workstation)#

Repository location: /Users/marc/Scripts/
Remote: git@github.com:marcoue/Scripts.git

Clone on a new Mac Studio:

git clone git@github.com:marcoue/Scripts.git /Users/marc/Scripts

Script locations:

/Users/marc/Scripts/TrueNAS/
├── HP1_UNAS_Pull_Backup.sh
├── HP2_UNAS_Pull_Backup.sh
├── HP3_UNAS_Pull_Backup.sh
├── HP7_UNAS_Pull_Backup.sh
└── HP8_UNAS_Pull_Backup.sh

Git Post-Commit Hook (Auto-Mirror to UNAS-Pro)#

The hook is located at /Users/marc/Scripts/.git/hooks/post-commit. It automatically mirrors the TrueNAS/ scripts directory to UNAS-Pro after every commit.

To recreate the hook on a new workstation:

cat > /Users/marc/Scripts/.git/hooks/post-commit << 'EOF'
#!/bin/bash
rsync -av /Users/marc/Scripts/TrueNAS/ root@10.1.2.2:/Volume1/Software/Software/Scripts/TrueNAS/
EOF
chmod +x /Users/marc/Scripts/.git/hooks/post-commit

Scripts on UNAS-Pro (mirror destination):

/Volumes/Software/Software/Scripts/TrueNAS/
(Exposed via Rsync as: root@10.1.2.2::Software/Software/Scripts/TrueNAS/)
Node Script Path on Node Auto-Sync via Backup
HP1 /mnt/RaidZ1SSDPool8TB/HP1UNASBackup/Software/Software/Scripts/TrueNAS/HP1_UNAS_Pull_Backup.sh Yes (Pulls Software module)
HP2 /mnt/Raid0SSDPool3TB/HP2UNASBackup/Software/Software/Scripts/TrueNAS/HP2_UNAS_Pull_Backup.sh Yes (Pulls Software module)
HP3 /mnt/Homes/unas_backup/unas_backup/scripts/HP3_UNAS_Pull_Backup.sh Self-Updates at start of script
HP7 /mnt/Stripe4TB/HP7UNASBackup/Software/Software/Scripts/TrueNAS/HP7_UNAS_Pull_Backup.sh Yes (Pulls Software module)
HP8 /mnt/RaidZ1SSDPool8TB/HP8UNASBackup/Software/Software/Scripts/TrueNAS/HP8_UNAS_Pull_Backup.sh Yes (Pulls Software module)

HP3 Script Self-Sync Exception: Nodes HP1, HP2, HP7, and HP8 pull the Software module during their main backup payload, which automatically updates their copy of HPX_UNAS_Pull_Backup.sh from UNAS-Pro. Because HP3 only backs up media modules (Films and TVSeries), it does not pull the Software dataset as part of its backup payload. Instead, HP3_UNAS_Pull_Backup.sh includes a 1-line self-update command at the top of the script that explicitly pulls its latest version from root@10.1.2.2::Software/Software/Scripts/TrueNAS/HP3_UNAS_Pull_Backup.sh into /mnt/Homes/unas_backup/unas_backup/scripts/HP3_UNAS_Pull_Backup.sh before running the media sync.

Standard Backup Script Blueprint#

Every node’s backup script follows these standards:

#!/usr/bin/env bash
set -euo pipefail

KEY="/mnt/homes/unas_backup/.ssh/id_ed25519"       # SSH private key path
LOG_DIR="/mnt/homes/unas_backup"                    # Log directory
DEST_DIR="/mnt/<POOL>/<DATASET>"                    # Backup destination
TIMESTAMP="$(date +%Y-%m-%d_%H-%M)"
LOG_FILE="${LOG_DIR}/${TIMESTAMP}_unas_backup.log"
MODULES=("Module1" "Module2")                       # Rsync modules to pull

mkdir -p "${LOG_DIR}"

{
  echo "=== HPX UNAS Pull Backup Started: ${TIMESTAMP} ==="
  for mod in "${MODULES[@]}"; do
    echo "--> Pulling module: ${mod}"
    rsync -av --no-o --no-g --delete --backup \
      --backup-dir="${DEST_DIR}/$(date +%Y-%m-%d)_Rsync_deleted" \
      -e "ssh -i ${KEY} -o StrictHostKeyChecking=no" \
      "root@10.1.2.2::${mod}/" "${DEST_DIR}/${mod}/"
  done
  echo "=== Pruning logs older than 30 days ==="
  find "${LOG_DIR}" -maxdepth 1 -type f -name "*_unas_backup.log" -mtime +30 -delete
  echo "=== Backup Complete: $(date +%Y-%m-%d_%H-%M) ==="
} > "${LOG_FILE}" 2>&1

if [ $? -eq 0 ]; then
  sudo midclt call mail.send '{"subject": "SUCCESS: HPX UNAS Backup", "text": "HPX UNAS Backup completed successfully.", "to": ["proxmox.app@gmail.com"]}'
else
  sudo midclt call mail.send '{"subject": "FAILURE: HPX UNAS Backup", "text": "HPX UNAS Backup failed.", "to": ["proxmox.app@gmail.com"]}'
fi

5. Per-Node Configuration Reference#

Node IP SSH User Key Path Log Directory unas_backup User ID Symlink Requirement
HP1 10.1.2.201 /mnt/homes/unas_backup/.ssh/id_ed25519 /mnt/homes/unas_backup/ 84 Native ZFS /mnt/homes/
HP2 10.1.2.212 /mnt/Homes/unas_backup/unas_backup/.ssh/id_ed25519 /mnt/Homes/unas_backup/unas_backup/ 74 Native ZFS /mnt/Homes/
HP3 10.1.2.213 /mnt/Homes/unas_backup/unas_backup/.ssh/id_ed25519 /mnt/Homes/unas_backup/unas_backup/ 78 Native ZFS /mnt/Homes/
HP7 10.1.1.17 /mnt/homes/unas_backup/.ssh/id_ed25519 /mnt/Stripe4TB/Homes/unas_backup/ 76 ln -s /mnt/Stripe4TB/Homes /mnt/homes
HP8 10.1.2.208 /mnt/homes/unas_backup/.ssh/id_ed25519 /mnt/homes/unas_backup/ 78 ln -s "/mnt/Apps - Homes/Homes" /mnt/homes

Why Symlinks Are Required for HP7 and HP8:

  • HP1: HP1’s home directory pool is created at /mnt/homes/ without spaces or pool-name prefixes. No symlink is needed.
  • HP7: HP7’s home directory dataset is stored at /mnt/Stripe4TB/Homes/. A symlink (/mnt/homes -> /mnt/Stripe4TB/Homes) was created to standardize the path.
  • HP8: HP8’s home directory pool is named Apps - Homes (/mnt/Apps - Homes/Homes/). Because the pool name contains spaces, unquoted -e "ssh -i $KEY" commands inside rsync fail when parsing the path. The symlink /mnt/homes -> /mnt/Apps - Homes/Homes resolves the path cleanly without spaces.

Per-Node TrueNAS Cron Job Registry#

Node Cron Job ID Description User Schedule Command
HP1 6 UNAS-Pro HP1 Backup Pull (Script Method) unas_backup 0 * * * * bash /mnt/RaidZ1SSDPool8TB/HP1UNASBackup/Software/Software/Scripts/TrueNAS/HP1_UNAS_Pull_Backup.sh
HP2 1 UNAS-Pro HP2 Backup Pull (Script Method) unas_backup 20 * * * * bash /mnt/Raid0SSDPool3TB/HP2UNASBackup/Software/Software/Scripts/TrueNAS/HP2_UNAS_Pull_Backup.sh
HP3 2 UNAS-Pro HP3Medias Backup Pull (Script Method) unas_backup 50 * * * * bash /mnt/Homes/unas_backup/unas_backup/scripts/HP3_UNAS_Pull_Backup.sh
HP7 5 UNAS-Pro HP7 Backup Pull (Script Method) unas_backup 30 * * * * bash /mnt/Stripe4TB/HP7UNASBackup/Software/Software/Scripts/TrueNAS/HP7_UNAS_Pull_Backup.sh
HP8 UNAS-Pro HP8 Backup Pull (Script Method) unas_backup 15 * * * * bash /mnt/RaidZ1SSDPool8TB/HP8UNASBackup/Software/Software/Scripts/TrueNAS/HP8_UNAS_Pull_Backup.sh

6. Security & Permission Standard#

6.1 Service Account Setup (Per TrueNAS Node)#

  1. Create unas_backup user in TrueNAS Web UI (Credentials > Local Users > Add):

    • Username: unas_backup
    • Enable Create Home Directory
    • Leave all access toggles (SMB, TrueNAS, SSH) unchecked
  2. Generate SSH keypair on the node:

    sudo chown -R unas_backup:unas_backup /mnt/homes/unas_backup
    sudo -u unas_backup mkdir -p /mnt/homes/unas_backup/.ssh
    sudo -u unas_backup chmod 700 /mnt/homes/unas_backup/.ssh
    sudo -u unas_backup ssh-keygen -t ed25519 -N '' -f /mnt/homes/unas_backup/.ssh/id_ed25519
    sudo -u unas_backup cat /mnt/homes/unas_backup/.ssh/id_ed25519.pub
  3. Grant passwordless sudo via TrueNAS middleware (NOT via /etc/sudoers — TrueNAS resets it on updates):

    # First get the user ID
    sudo midclt call user.query '[["username", "=", "unas_backup"]]'
    # Then grant sudo
    sudo midclt call user.update <USER_ID> '{"sudo_commands_nopasswd": ["ALL"]}'
  4. Set ZFS dataset permissions:

    sudo zfs set aclmode=passthrough <POOL>/<DATASET>
    sudo chown -R unas_backup:unas_backup /mnt/<POOL>/<DATASET>/
    sudo chmod -R 777 /mnt/<POOL>/<DATASET>/

6.2 TrueNAS API Key Setup (for MCP / AI Agent Access)#

Each TrueNAS node requires an API key stored in 1Password for AI agent access via the MCP server fleet.

  1. Create API key in TrueNAS Web UI: System Settings > API Keys > Add.
    • Name: antigravity-cli
  2. Store in 1Password: Save in vault Homelab, item antigravity-cli, field HPX_TRUENAS_API_KEY.
  3. Add to MCP config: Update ~/.mcp-config/config.json with a truenas-hpX entry using https://10.1.X.X (always HTTPS — HTTP will auto-revoke the API key).
  4. Deploy: Run cd ~/.mcp-config && ./apply.py.

6.3 GMail OAuth Email Notification Setup#

Each TrueNAS node sends backup status emails via GMail OAuth to proxmox.app@gmail.com.

  1. In TrueNAS Web UI, navigate to System Settings > General > Email.
  2. Set Send Mail Method to GMail OAuth.
  3. Click Log In to GMail and authenticate with proxmox.app@gmail.com.
  4. Click Send Test Email to verify delivery.

GMail OAuth tokens expire periodically. If backup emails stop arriving, re-authenticate via TrueNAS Web UI > System Settings > General > Email.

6.4 ZFS Periodic Snapshot Protection#

Each node maintains automatic ZFS snapshots as a safety net against accidental deletions or ransomware:

Node Dataset Snapshot Schedule Retention
HP1 RaidZ1SSDPool8TB/HP1UNASBackup Daily at 00:00 4 weeks (28 days)
HP2 Raid0SSDPool3TB/HP2UNASBackup Daily at 18:29 2 days
HP3 Medias/HP3Medias Daily at 09:55 4 weeks (28 days)
HP7 Stripe4TB/HP7UNASBackup Daily 7 days
HP8 RaidZ1SSDPool8TB/HP8UNASBackup Daily 7 days

7. Log Monitoring Reference#

Logs are named YYYY-MM-DD_HH-MM_unas_backup.log and auto-pruned after 30 days.

Node SSH Command to View Latest Log
HP1 ssh marcoue@10.1.2.201 "sudo ls -t /mnt/homes/unas_backup/*_unas_backup.log | head -n 1 | xargs sudo tail -n 50"
HP2 ssh marcoue@10.1.2.212 "sudo ls -t /mnt/Homes/unas_backup/unas_backup/*_unas_backup.log | head -n 1 | xargs sudo tail -n 50"
HP3 ssh marcoue@10.1.2.213 "sudo ls -t /mnt/Homes/unas_backup/unas_backup/*_unas_backup.log | head -n 1 | xargs sudo tail -n 50"
HP7 ssh marcoue@10.1.1.17 "sudo ls -t /mnt/Stripe4TB/Homes/unas_backup/*_unas_backup.log | head -n 1 | xargs sudo tail -n 50"
HP8 ssh marcoue@10.1.2.208 "sudo ls -t /mnt/homes/unas_backup/*_unas_backup.log | head -n 1 | xargs sudo tail -n 50"

8. Disaster Recovery — Complete Rebuild Procedures#

8.1 Rebuild a Single TrueNAS Node from Scratch#

Follow these steps for any node. Replace HPX, 10.1.X.X, <POOL>, <DATASET>, <MINUTE> with node-specific values from the tables above.

Step 1 — Create unas_backup service account:

# Via TrueNAS Web UI: Credentials > Local Users > Add
# Username: unas_backup, Enable Home Directory, no other access

Step 2 — Grant passwordless sudo:

USER_ID=$(sudo midclt call user.query '[["username", "=", "unas_backup"]]' | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['id'])")
sudo midclt call user.update ${USER_ID} '{"sudo_commands_nopasswd": ["ALL"]}'

Step 3 — Generate SSH keypair:

sudo -u unas_backup ssh-keygen -t ed25519 -N '' -f /mnt/homes/unas_backup/.ssh/id_ed25519
sudo -u unas_backup cat /mnt/homes/unas_backup/.ssh/id_ed25519.pub
# Copy output — needed for Step 4

Step 4 — Register public key on UNAS-Pro:

ssh root@10.1.2.2 "echo '<PASTE_PUBLIC_KEY_HERE>' >> /root/.ssh/authorized_keys"

Step 5 — Verify SSH & Rsync connection:

sudo -u unas_backup rsync -e "ssh -i /mnt/homes/unas_backup/.ssh/id_ed25519 -o StrictHostKeyChecking=no" root@10.1.2.2::
# Should list all 12 modules

Step 6 — Set ZFS dataset permissions:

sudo zfs set aclmode=passthrough <POOL>/<DATASET>
sudo chown -R unas_backup:unas_backup /mnt/<POOL>/<DATASET>/
sudo chmod -R 777 /mnt/<POOL>/<DATASET>/

Step 7 — Sync backup script from UNAS-Pro:

sudo -u unas_backup rsync -av \
  -e "ssh -i /mnt/homes/unas_backup/.ssh/id_ed25519 -o StrictHostKeyChecking=no" \
  "root@10.1.2.2::Software/Software/Scripts/TrueNAS/HPX_UNAS_Pull_Backup.sh" \
  "/mnt/<POOL>/<DATASET>/Software/Software/Scripts/TrueNAS/HPX_UNAS_Pull_Backup.sh"
sudo chmod +x /mnt/<POOL>/<DATASET>/Software/Software/Scripts/TrueNAS/HPX_UNAS_Pull_Backup.sh

Step 8 — Register Cron Job via TrueNAS middleware:

sudo midclt call cronjob.create '{
  "description": "UNAS-Pro HPX Backup Pull (Script Method)",
  "user": "unas_backup",
  "command": "bash /mnt/<POOL>/<DATASET>/Software/Software/Scripts/TrueNAS/HPX_UNAS_Pull_Backup.sh",
  "schedule": {"minute": "<MINUTE>", "hour": "*", "dom": "*", "month": "*", "dow": "*"},
  "enabled": true,
  "stdout": true,
  "stderr": false
}'

Step 9 — Configure GMail OAuth:

  • Go to TrueNAS Web UI > System Settings > General > Email.
  • Set Send Mail Method to GMail OAuth, authenticate with proxmox.app@gmail.com.

Step 10 — Test run:

sudo midclt call cronjob.run <CRON_JOB_ID>
# Then verify log and email

8.2 Rebuild UNAS-Pro from Scratch#

If the UNAS-Pro itself is wiped or replaced:

  1. Enable Rsync Server: UniFi Drive Web UI > Settings > Services / Rsync > ON.
  2. Re-expose all 12 modules: UniFi Drive > Shared Folders — enable Expose as Rsync Module for all folders.
  3. Re-add all SSH public keys to /root/.ssh/authorized_keys (see Section 3, Step 3).
  4. Verify connectivity from each TrueNAS node using the test command in Section 3, Step 4.

All backup data resides safely on the TrueNAS nodes during a UNAS-Pro outage. The UNAS-Pro is the source, not the backup destination. A UNAS-Pro rebuild only requires restoring SSH keys and Rsync module configuration — no data recovery is needed from backups.


8.3 Rebuild Mac Studio Workstation (Script Management)#

If the Mac Studio workstation is replaced:

  1. Clone the scripts repository:
    git clone git@github.com:marcoue/Scripts.git /Users/marc/Scripts
  2. Recreate the Git post-commit hook:
    cat > /Users/marc/Scripts/.git/hooks/post-commit << 'EOF'
    #!/bin/bash
    rsync -av /Users/marc/Scripts/TrueNAS/ root@10.1.2.2:/Volume1/Software/Software/Scripts/TrueNAS/
    EOF
    chmod +x /Users/marc/Scripts/.git/hooks/post-commit
  3. Restore MCP configuration: Clone ~/.mcp-config from its Git repository, restore 1Password credentials, and run ./apply.py.