Runbook: Backup All Infrastructure

Last Updated

2026-02-21

Owner

evanusmodestus

Frequency

Daily (automated) / Weekly (verified)


1. Overview

This runbook covers backup and recovery procedures for all infrastructure systems. Follows the 3-2-1 backup strategy: 3 copies, 2 media types, 1 offsite.

1.1. Architecture Overview

Backup Infrastructure Architecture

1.2. Detailed Backup Flows

Infrastructure Backup Flows
Solid lines = active backups. Dashed lines = pending implementation. Animated lines = automated backup flows.

2. Backup Coverage Summary

System Status Method NAS Path Retention

ISE 3.4

✓ Active

netapi ise backup

/ise_backups

30 days

9800-CL WLC

✓ Active

netapi wlc backup

/wlc_backups

30 days

VyOS

✓ Active

netapi vyos backup

/firewall_backups

30 days

IOS Switches

✓ Active

netapi ios backup

/switch_backups

30 days

KVM VM Definitions

✓ Active

netapi kvm backup

/kvm_backups

30 days

Keycloak

✓ Active

netapi keycloak backup

/Backups/keycloak

30 days

Vault

✓ Automated

systemd timer (02:00)

/vault_backups

30 days

Workstations

✓ Active

Borg Backup

/Backups/borg

90 days

BIND DNS

○ Pending

TBD

/dns_backups

-

FreeIPA

○ Pending

TBD

/ipa_backups

-

Windows AD

○ Pending

TBD

/ad_backups

-

iPSK Manager

○ Pending

TBD

/ipsk_backups

-

k3s Cluster

✓ Active

Manual / cron

/k3s_backups

7 days

3. NAS Directory Structure

NAS Backup Structure
Figure 1. NAS Backup Structure

4. NAS Share Setup

Create missing backup shares on nas-01 using the synoshare CLI (no OTP required).

4.1. Required Shares

Share Purpose Status

/ise_backups

ISE configuration exports

✓ Exists

/wlc_backups

WLC configuration

✓ Exists

/firewall_backups

VyOS configs

✓ Exists

/switch_backups

IOS switch configs

✓ Exists

/kvm_backups

VM XML definitions

✓ Exists

/k3s_backups

etcd snapshots, manifests

✓ Exists

/vault_backups

Vault snapshots

✓ Exists

/bind_backups

BIND zone files

○ Create

/keycloak_backups

Realm exports

○ Create

/ipa_backups

FreeIPA backups

○ Create

4.2. Create Shares via SSH

SSH to NAS and use synoshare CLI (bypasses 2FA/OTP requirement):

ssh nas-01

CRITICAL: Do NOT create directories first. synoshare --add creates the directory automatically. If directory exists, synoshare fails with 0xE700.

# Create DSM shares (synoshare creates the directories)
sudo synoshare --add bind_backups "BIND DNS backups" /volume1/bind_backups "" administrators "" 1 1

sudo synoshare --add keycloak_backups "Keycloak realm exports" /volume1/keycloak_backups "" administrators "" 1 1

sudo synoshare --add ipa_backups "FreeIPA backups" /volume1/ipa_backups "" administrators "" 1 1

# Verify
sudo synoshare --enum ALL | grep -E 'bind|keycloak|ipa'
synoshare --add syntax
synoshare --add <name> <desc> <path> <na> <rw> <ro> <browsable 0|1> <adv_privilege 0-7>
Table 1. Positional arguments
Position Value Description

1

bind_backups

Share name

2

"BIND DNS backups"

Description (quote if spaces)

3

/volume1/bind_backups

Filesystem path (synoshare creates this)

4

""

No access users (empty = none)

5

administrators

Read-write users (no @ prefix)

6

""

Read-only users (empty = none)

7

1

Browseable (1=yes, 0=no)

8

1

Advanced privileges (0-7)

If directory already exists, delete it first: sudo rm -rf /volume1/<sharename> then run synoshare.
For netapi API method (requires OTP), see Synology Commands - Share Management.

5. Prerequisites

5.1. Secrets Required

Secret Set Command Systems

Network

dsource d000 dev/network

ISE, WLC, VyOS, switches, NAS

Identity

dsource d000 dev/identity

Keycloak, FreeIPA

Vault

dsource d000 dev/vault

Vault (if manual backup needed)

5.2. Connectivity Pre-Check

Run before starting backups:

# Load secrets
dsource d000 dev/network

# Pre-flight connectivity check
echo "=== Pre-flight Connectivity Check ==="
for host in ise-01 wlc-01 vyos-01 nas-01 keycloak-01 vault-01; do
  if ping -c1 -W2 $host &>/dev/null; then
    echo "✓ $host reachable"
  else
    echo "✗ $host UNREACHABLE"
  fi
done

6. Backup Procedures

6.1. Quick Backup (All Active Systems)

Run all backups in sequence. Script located at examples/backup-all.sh.

#!/bin/bash
# Full Infrastructure Backup - All Systems
# Runbook: backup-all-infrastructure.adoc

set -e

echo "=== Infrastructure Backup $(date +%Y-%m-%d) ==="

# =============================================================================
# PREREQUISITES
# =============================================================================
# 1. Vault SSH cert with ALL principals:
#      ssh-keygen -Lf ~/.ssh/id_ed25519_vault-cert.pub | grep -A6 "Principals:"
#    Required: admin, adminerosado, ansible, evanusmodestus, root
#    If missing, run: vault-ssh-sign
#
# 2. SSH agent has cert loaded:
#      ssh-add -l | grep vault
#
# 3. netapi dependencies installed:
#      cd ~/atelier/_projects/personal/netapi && uv sync --extra all
#
# =============================================================================
# TROUBLESHOOTING
# =============================================================================
# "netmiko not installed" error:
#   cd ~/atelier/_projects/personal/netapi && uv sync --extra all
#
# YubiKey passphrase prompt (missing principal):
#   vault-ssh-sign
#   # Verify: ssh-keygen -Lf ~/.ssh/id_ed25519_vault-cert.pub | grep -A6 "Principals:"
#
# NAS upload fails:
#   dsource d000 dev/storage
#
# =============================================================================

# Pre-flight connectivity check
echo "[0/8] Connectivity check..."
for host in ise-01 wlc-01 vyos-01 nas-01 vault-01 kvm-01 k3s-master-01; do
  ping -c1 -W2 "$host" &>/dev/null && echo "  ✓ $host" || echo "  ✗ $host UNREACHABLE"
done

# Load secrets (network for device access, storage for NAS upload)
dsource d000 dev/network
dsource d000 dev/storage

# Network devices
echo "[1/8] Backing up VyOS..."
netapi vyos backup --upload-nas

echo "[2/8] Backing up WLC..."
netapi wlc backup --upload-nas

echo "[3/8] Backing up IOS Switches..."
netapi ios backup --all --upload-nas

echo "[4/8] Backing up KVM definitions..."
netapi kvm backup --all --upload-nas

# Security
echo "[5/8] Backing up ISE..."
netapi ise backup --upload-nas

echo "[6/8] Triggering Vault backup..."
ssh vault-01 "sudo systemctl start vault-backup.service"

# Identity (different secrets)
echo "[7/8] Backing up Keycloak..."
dsource d000 dev/identity
netapi keycloak backup --upload-nas 2>/dev/null || echo "  (keycloak backup pending)"

# Kubernetes
echo "[8/8] Backing up k3s..."
ssh k3s-master-01 "sudo /usr/local/bin/k3s-backup.sh" 2>/dev/null || echo "  (k3s cron handles this)"

echo ""
echo "=== Backup Complete ==="
echo "Verify: netapi synology backup-status --detailed"

6.2. Individual System Backups

Each backup script is in examples/ for reuse. View source with include::example$backup-<system>.sh[].

6.2.1. Vault Backup

What’s backed up:
  • File storage backend (/opt/vault/data)

  • PKI certificates

  • KV secrets

  • Auth configurations

#!/bin/bash
# Vault Backup - Verification & Manual trigger
# Runbook: backup-all-infrastructure.adoc
# Detailed: vault-backup.adoc

# Prerequisites
# - SSH access to vault-01 (or run directly on vault-01)
# - systemd timer configured (see vault-backup.adoc)

# =============================================================================
# 1. Check timer status
# =============================================================================
systemctl list-timers vault-backup.timer --no-pager

# Expected output:
# NEXT                        LEFT   LAST                        PASSED       UNIT               ACTIVATES
# Tue 2026-02-24 02:28:20 UTC 23h    Mon 2026-02-23 02:13:58 UTC 38min ago    vault-backup.timer vault-backup.service

# =============================================================================
# 2. Check last backup log
# =============================================================================
sudo journalctl -u vault-backup.service -n 10 --no-pager

# Expected output (successful):
# Feb 23 02:13:58 vault-01... systemd[1]: Starting vault-backup.service - Vault Backup to NAS...
# Feb 23 02:13:59 vault-01... bash[55856]: sending incremental file list
# Feb 23 02:13:59 vault-01... bash[55856]: vault-backup-20260223-021358.tar.gz
# Feb 23 02:13:59 vault-01... bash[55856]: sent 117,703 bytes  received 35 bytes  235,476.00 bytes/sec
# Feb 23 02:13:59 vault-01... bash[55856]: total size is 149,853  speedup is 1.27
# Feb 23 02:13:59 vault-01... systemd[1]: vault-backup.service: Deactivated successfully.
# Feb 23 02:13:59 vault-01... systemd[1]: Finished vault-backup.service - Vault Backup to NAS.

# =============================================================================
# 3. Verify backups on NAS
# =============================================================================
ssh nas-01 "ls -lh /volume1/vault_backups/*.tar.gz | tail -3"

# Expected output:
# -rw-r--r-- 1 hashi-backups users 137K Feb 20 18:04 vault-backup-20260221-020458.tar.gz
# -rw-r--r-- 1 hashi-backups users 143K Feb 21 18:18 vault-backup-20260222-021858.tar.gz
# -rw-r--r-- 1 hashi-backups users 147K Feb 22 18:13 vault-backup-20260223-021358.tar.gz

# =============================================================================
# 4. Manual backup (if needed)
# =============================================================================
# sudo systemctl start vault-backup.service
# sudo systemctl status vault-backup.service

# =============================================================================
# TROUBLESHOOTING: SSH falls back to YubiKey instead of Vault cert
# =============================================================================
# If prompted for YubiKey passphrase, your Vault cert may be missing a principal.
#
# CRITICAL: Vault SSH roles do NOT support 'default_principals' - it's silently
# ignored. You MUST specify valid_principals on EVERY sign request.
#
# Check current principals:
#   ssh-keygen -Lf ~/.ssh/id_ed25519_vault-cert.pub | grep -A6 "Principals:"
#
# Required principals by host:
#   - adminerosado: Synology NAS
#   - admin: VyOS, network devices
#   - ansible: automation
#   - evanusmodestus: Linux workstations
#   - root: emergency access
#
# Fix: Update vault-ssh-sign script then re-sign:
#   sed -i 's/valid_principals="\([^"]*\)"/valid_principals="adminerosado,admin,ansible,evanusmodestus,root"/' ~/.local/bin/vault-ssh-sign
#   vault-ssh-sign
#
# Or manual re-sign (not recommended):
#   dsource d000 dev/vault
#   vault write -field=signed_key ssh/sign/domus-client \
#     public_key=@$HOME/.ssh/id_ed25519_vault.pub \
#     valid_principals="adminerosado,admin,ansible,evanusmodestus,root" \
#     >| ~/.ssh/id_ed25519_vault-cert.pub
#   ssh-add -d ~/.ssh/id_ed25519_vault 2>/dev/null
#   ssh-add ~/.ssh/id_ed25519_vault

6.2.2. ISE Backup

What’s backed up:
  • Configuration database

  • Certificates and keys

  • Policy sets and rules

  • Network devices

  • Endpoint groups

#!/bin/bash
# ISE Backup
# Runbook: backup-all-infrastructure.adoc

# Prerequisites
dsource d000 dev/network

# Trigger ISE config backup (async - takes several minutes)
netapi ise backup --upload-nas

# Check backup status
netapi ise api-call openapi GET '/api/v1/backup-restore/config/last-backup-status' | jq .

# Verify on NAS (after backup completes)
ssh nas-01 "ls -lh /volume1/ise_backups/*.tar.gpg | tail -3"

# Manual: Check ISE repository
netapi ise api-call openapi GET '/api/v1/repository' | jq -r '.response[].name'

6.2.3. VyOS Backup

What’s backed up:
  • Full configuration (show configuration commands)

  • Firewall rules

  • NAT rules

  • DHCP configuration

  • DNS forwarding

  • Zone policies

#!/bin/bash
# VyOS Backup
# Runbook: backup-all-infrastructure.adoc

# Prerequisites
dsource d000 dev/network

# Backup VyOS configuration (both nodes for HA)
for node in vyos-01 vyos-02; do
    echo "=== Backing up $node ==="
    ssh $node "source /opt/vyatta/etc/functions/script-template && run show configuration commands" > /tmp/${node}-$(date +%Y%m%d).cfg
done

# Upload to NAS
scp /tmp/vyos-*.cfg nas-01:/volume1/firewall_backups/

# Verify on NAS
ssh nas-01 "ls -lh /volume1/firewall_backups/vyos*.cfg | tail -5"

# Cleanup local files
rm -f /tmp/vyos-*.cfg

# Alternative: netapi (when implemented)
# netapi vyos backup --upload-nas

6.2.4. WLC Backup

What’s backed up:
  • Running configuration

  • WLAN profiles

  • AP join profiles

  • Policy tags

  • RF profiles

#!/bin/bash
# 9800-CL WLC Backup
# Runbook: backup-all-infrastructure.adoc

# Prerequisites
dsource d000 dev/network

# Backup (exports running config and uploads to NAS)
netapi wlc backup --upload-nas

# Verify on NAS
ssh nas-01 "ls -lh /volume1/wlc_backups/*.json | tail -3"

# Manual alternative (no netapi)
# ssh wlc-01 "show running-config" > /tmp/wlc-$(date +%Y%m%d).cfg
# scp /tmp/wlc-*.cfg nas-01:/volume1/wlc_backups/

6.2.5. IOS Switches Backup

What’s backed up:
  • Running configuration

  • VLAN database

  • 802.1X configuration

  • Interface settings

#!/bin/bash
# IOS Switch Backup
# Runbook: backup-all-infrastructure.adoc

# Prerequisites
dsource d000 dev/network

# Backup all switches
netapi ios backup --all --upload-nas

# Backup single switch
# netapi ios backup --host 10.50.1.10 --upload-nas

# Verify on NAS
ssh nas-01 "ls -lh /volume1/switch_backups/*.cfg | tail -5"

# Manual alternative (no netapi)
# ssh admin@10.50.1.10 "show running-config" > /tmp/switch-$(date +%Y%m%d).cfg
# scp /tmp/switch-*.cfg nas-01:/volume1/switch_backups/

6.2.6. KVM Backup

What’s backed up:
  • VM XML definitions

  • Network XML definitions

  • Storage pool definitions

VM disk images are NOT backed up here. Those are backed up via Borg on the host.
#!/bin/bash
# KVM VM Definitions Backup
# Runbook: backup-all-infrastructure.adoc
# Note: This backs up XML definitions, NOT disk images

# Prerequisites
dsource d000 dev/network

# Backup all VM definitions
netapi kvm backup --all --upload-nas

# Verify on NAS
ssh nas-01 "ls -lh /volume1/kvm_backups/*.xml | tail -5"

# Manual alternative (no netapi)
ssh kvm-01 'for vm in $(virsh list --all --name); do
  virsh dumpxml "$vm" > /tmp/"$vm".xml
done'
scp kvm-01:/tmp/*.xml nas-01:/volume1/kvm_backups/

# Note: Disk images backed up separately via Borg

6.2.7. k3s Backup

What’s backed up:
  • SQLite state database (single-node)

  • Static manifests

  • TLS certificates

  • Node join token

Single-node k3s uses SQLite, NOT etcd. Use cp -rv directory not cp directory/*.
#!/bin/bash
# k3s Backup (Single-node SQLite)
# Runbook: backup-all-infrastructure.adoc, k3s-operations.adoc
# Note: Single-node k3s uses SQLite, NOT etcd

# Run on k3s-master-01
ssh k3s-master-01 << 'EOF'
sudo mkdir -p /mnt/k3s_backups
sudo mount -t nfs nas-01:/volume1/k3s_backups /mnt/k3s_backups

# Backup SQLite database
sudo cp -v /var/lib/rancher/k3s/server/db/state.db \
  /mnt/k3s_backups/etcd/state.db.$(date +%Y%m%d)

# Backup manifests, TLS, token (use -rv directory, NOT *)
sudo cp -rv /var/lib/rancher/k3s/server/manifests /mnt/k3s_backups/
sudo cp -rv /var/lib/rancher/k3s/server/tls /mnt/k3s_backups/
sudo cp -v /var/lib/rancher/k3s/server/token /mnt/k3s_backups/

# Verify
ls -la /mnt/k3s_backups/

sudo umount /mnt/k3s_backups
EOF

6.2.8. Keycloak Backup (Pending)

What’s backed up:
  • Realm export (JSON)

  • Users and groups

  • Clients and roles

  • Identity providers

#!/bin/bash
# Keycloak Backup
# Runbook: backup-all-infrastructure.adoc
# Status: PENDING - needs keycloak_backups share on NAS

# Prerequisites
dsource d000 dev/identity

# Backup realm export
netapi keycloak backup --upload-nas

# Manual alternative
ssh keycloak-01 "/opt/keycloak/bin/kc.sh export \
  --dir /tmp/keycloak-export \
  --realm domus"
scp -r keycloak-01:/tmp/keycloak-export/* nas-01:/volume1/keycloak_backups/

# Verify on NAS
ssh nas-01 "ls -lh /volume1/keycloak_backups/*.json | tail -3"

6.2.9. BIND DNS Backup (Pending)

What’s backed up:
  • Zone files

  • named.conf

  • Configuration directory

#!/bin/bash
# BIND DNS Backup
# Runbook: backup-all-infrastructure.adoc
# Status: PENDING - needs bind_backups share on NAS

# Run on bind-01
ssh bind-01 << 'EOF'
DATE=$(date +%Y%m%d)
BACKUP_DIR="/tmp/bind-backup-$DATE"
mkdir -p "$BACKUP_DIR"

# Backup zone files
cp -rv /var/named/*.zone "$BACKUP_DIR/"
cp -rv /var/named/*.db "$BACKUP_DIR/"

# Backup config
cp -v /etc/named.conf "$BACKUP_DIR/"
cp -rv /etc/named/ "$BACKUP_DIR/named-conf.d/"

# Create tarball
tar -czf "/tmp/bind-backup-$DATE.tar.gz" -C /tmp "bind-backup-$DATE"
rm -rf "$BACKUP_DIR"
EOF

# Copy to NAS
scp bind-01:/tmp/bind-backup-*.tar.gz nas-01:/volume1/bind_backups/

# Verify
ssh nas-01 "ls -lh /volume1/bind_backups/*.tar.gz | tail -3"

6.2.10. FreeIPA Backup (Pending)

What’s backed up:
  • LDAP database

  • Kerberos keytabs

  • Certificates

  • Configuration

#!/bin/bash
# FreeIPA Backup
# Runbook: backup-all-infrastructure.adoc
# Status: PENDING - needs ipa_backups share on NAS

# Run on ipa-01 (as root)
ssh ipa-01 << 'EOF'
# Full backup (LDAP + files)
sudo ipa-backup

# Or data-only backup (faster)
# sudo ipa-backup --data

# Find latest backup
LATEST=$(ls -td /var/lib/ipa/backup/ipa-full-* | head -1)
echo "Latest backup: $LATEST"
EOF

# Copy to NAS
LATEST=$(ssh ipa-01 "ls -td /var/lib/ipa/backup/ipa-full-* | head -1")
scp -r ipa-01:"$LATEST" nas-01:/volume1/ipa_backups/

# Verify
ssh nas-01 "ls -lh /volume1/ipa_backups/"

7. Recovery Procedures

Recovery Order Matters!

Systems have dependencies. Recover in this order:

  1. VyOS (network connectivity)

  2. BIND / DNS (name resolution)

  3. Windows AD (authentication source)

  4. Vault (secrets and certificates)

  5. ISE (network access control)

  6. Everything else (WLC, Keycloak, etc.)

7.1. Recovery Priority Matrix

Priority System RTO Dependencies

P0

VyOS

15 min

None (restore first)

P0

Windows AD

30 min

Network (VyOS)

P1

Vault

30 min

Network, DNS

P1

ISE

1 hour

Network, AD, Vault certs

P2

WLC

1 hour

Network, ISE

P2

Keycloak

1 hour

Network, DNS

P3

Switches

2 hours

Network (basic config works)

P3

KVM

2 hours

Network

7.2. ISE Recovery

# 1. List available backups
dsource d000 dev/network
netapi synology list-files /ise_backups --sort-time

# 2. Download backup file
netapi synology download /ise_backups/ise-01_config_YYYYMMDD.tar.gpg /tmp/

# 3. Restore via ISE CLI or GUI
# GUI: Administration > System > Backup and Restore > Restore
# CLI: application restore <backup-file> repository <repo-name>

7.3. WLC Recovery

# 1. Download backup
netapi synology download /wlc_backups/wlc-01_config_YYYYMMDD.xml /tmp/

# 2. SCP to WLC
scp /tmp/wlc-01_config_*.xml admin@wlc-01:/

# 3. Restore on WLC
# copy flash:wlc-01_config_*.xml startup-config
# reload

7.4. VyOS Recovery

# 1. Download backup
netapi synology download /firewall_backups/vyos-01_config_YYYYMMDD.txt /tmp/

# 2. SSH to VyOS and load configuration
ssh vyos-01
configure
load /tmp/vyos-01_config_YYYYMMDD.txt
commit
save

7.5. Switch Recovery

# 1. Download config
netapi synology download /switch_backups/sw-core-01_config_YYYYMMDD.txt /tmp/

# 2. SCP to switch
scp /tmp/sw-core-01_config_*.txt admin@sw-core-01:/

# 3. Restore
# copy flash:sw-core-01_config_*.txt running-config
# write memory

7.6. Keycloak Recovery

# 1. Download realm export
netapi synology download /Backups/keycloak/keycloak-01_export_YYYYMMDD.json /tmp/

# 2. Import via CLI
ssh keycloak-01 "/opt/keycloak/bin/kc.sh import --file /tmp/keycloak-01_export_*.json"

# Or via Admin Console:
# Realm Settings > Action > Partial Import

7.7. Vault Recovery

# 1. Download snapshot
netapi synology download /Backups/vault/vault-01_snapshot_YYYYMMDD.snap /tmp/

# 2. Restore (requires root token)
vault operator raft snapshot restore /tmp/vault-01_snapshot_*.snap

See Vault Backup for detailed procedures.

8. Verification

8.1. Post-Backup Verification

dsource d000 dev/network
netapi synology backup-status --detailed
Expected output:
                                    Backup Status
┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━┓
┃ System   ┃ Folder            ┃ Files ┃ Devices ┃     Latest ┃  Age ┃ Status ┃
┡━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━┩
│ ISE      │ /ise_backups      │     7 │       1 │ 2026-02-21 │   0d │  ✓ OK  │
│ WLC      │ /wlc_backups      │     4 │       1 │ 2026-02-21 │   0d │  ✓ OK  │
│ VyOS     │ /firewall_backups │     3 │       2 │ 2026-02-21 │   0d │  ✓ OK  │
│ Switches │ /switch_backups   │     3 │       2 │ 2026-02-21 │   0d │  ✓ OK  │
│ KVM VMs  │ /kvm_backups      │    16 │       8 │ 2026-02-21 │   0d │  ✓ OK  │
│ Keycloak │ /Backups/keycloak │     2 │       2 │ 2026-02-21 │   0d │  ✓ OK  │
│ Vault    │ /Backups/vault    │     5 │       1 │ 2026-02-21 │   0d │  ✓ OK  │
└──────────┴───────────────────┴───────┴─────────┴────────────┴──────┴────────┘

✓ All 7 backup sets current (< 24 hours)

8.2. Backup Age Alerting

Age Status Action

< 24 hours

✓ OK (green)

None

24-72 hours

⚠ Warning (yellow)

Investigate

> 72 hours

✗ Critical (red)

Immediate action required

8.3. Restore Test (Monthly)

Monthly, perform a test restore to verify backups are valid:

# 1. Download random backup
netapi synology download /firewall_backups/$(netapi synology list-files /firewall_backups --sort-time | head -1) /tmp/test-restore/

# 2. Validate XML structure
xmllint --noout /tmp/test-restore/*.xml && echo "✓ XML valid"

# 3. Check file size (not empty/truncated)
ls -lh /tmp/test-restore/

# 4. Clean up
rm -rf /tmp/test-restore/

9. Automation

9.1. Active Systemd Timers

System Timer Schedule Status

vault-01

vault-backup.timer

Daily 02:00

✓ Active

Workstations

borg-backup.timer

Daily 03:00

✓ Active

9.2. Planned Automation

# /etc/systemd/system/infra-backup.timer
[Unit]
Description=Daily Infrastructure Backup

[Timer]
OnCalendar=*-*-* 01:00:00
Persistent=true

[Install]
WantedBy=timers.target
# /etc/systemd/system/infra-backup.service
[Unit]
Description=Infrastructure Backup Service
After=network-online.target

[Service]
Type=oneshot
ExecStart=/home/evanusmodestus/.local/bin/infra-backup.sh
User=evanusmodestus
Environment="PATH=/home/evanusmodestus/.local/bin:/usr/bin"

[Install]
WantedBy=multi-user.target

10. Troubleshooting

10.1. Common Failures

Symptom Cause Resolution

Connection timeout

Host unreachable

Check network, verify host is up

Authentication failed

Bad credentials

Re-run dsource d000 dev/network

Error 408 on NAS upload

Target folder missing

Create folder: netapi synology mkdir /path

Backup in progress

Previous backup still running

Wait or check ISE backup status

Insufficient space

NAS full

Clean old backups, expand volume

Certificate error

Expired/invalid cert

Update certificate on target system

10.2. ISE Backup Specific

# Check ISE backup status
netapi ise api-call openapi GET '/api/v1/backup-restore/config/last-backup-status'

# Check ISE repository
netapi ise api-call openapi GET '/api/v1/repository'

10.3. NAS Connectivity

# Test NAS access
netapi synology list-files /

# Check NAS disk space
netapi synology disk-usage

11. Cold Storage Sync

11.1. Weekly: NAS → Seagate SSD

# Mount Seagate
sudo cryptsetup open /dev/sda1 seagate-backup
sudo mount /dev/mapper/seagate-backup /mnt/seagate

# Sync critical backups
rsync -avz --delete \
  /mnt/nas/ise_backups/ \
  /mnt/nas/firewall_backups/ \
  /mnt/nas/Backups/vault/ \
  /mnt/seagate/infra-backups/

# Unmount
sudo umount /mnt/seagate
sudo cryptsetup close seagate-backup

11.2. Quarterly: M-Disc Archive

See M-Disc Verbatim for burn procedures.

12. TODO: Pending Implementations

  • k3s-master-01 - SQLite backup to NAS (completed 2026-02-22)

  • bind-01 - Zone file export script

  • ipa-01 - ipa-backup integration

  • keycloak-01 - Realm export automation

  • home-dc01 - Windows Server Backup or wbadmin

  • ipsk-manager - MySQL dump + Apache config