DB-VPS backup tier
Current layout
DB-VPS has a dedicated mirrored backup tier on two 12 TB HDDs:
| Layer | Value |
|---|---|
| Disks | /dev/sdb ST12000NM000J-2T serial ZRT0E14W; /dev/sdc ST12000NM000J-2T serial ZRT0E14H |
| RAID | Linux mdadm RAID1, /dev/md/backup12t (/dev/md127 at runtime) |
| RAID UUID | 5b951241:335d55e2:31e43f2c:1b6222a0 |
| Filesystem | ext4, label BACKUP_RAID, UUID e63b9568-f717-47cb-a9b4-4c0b0b1be4fc |
| Mount | /backup-raid via /etc/fstab |
| Backup tool | BorgBackup, unencrypted local repositories under /backup-raid/borg |
| Monitoring | mdmonitor.service and smartmontools.service |
The old 1 TB /backup disk is still mounted separately and remains the live
storage for Mailcow and container registries. Do not repoint /backup to
/backup-raid without a separate migration plan because Docker bind mounts
currently reference directories below /backup.
Daily backup framework
The generic runner is:
/usr/local/sbin/tracium-backup-run /etc/tracium-backup/sources.d/<source>.confEach source config defines:
SOURCE_NAMEBORG_REPOPATHSEXCLUDES- optional
PRE_HOOKandPOST_HOOK - retention values:
RETENTION_DAILY,RETENTION_WEEKLY,RETENTION_MONTHLY,RETENTION_YEARLY
Systemd units:
systemctl list-timers --all 'tracium-backup@*.timer'
systemctl status 'tracium-backup@host-ssd.timer'
systemctl status 'tracium-backup@host-ssd.service'
journalctl -u 'tracium-backup@host-ssd.service' -n 200 --no-pagerActive sources:
/etc/tracium-backup/sources.d/host-ssd.conf
/etc/tracium-backup/sources.d/tracium-postgres.confThis source backs up SSD-host configuration and deploy state:
/etc/root/home/srv/opt/usr/local/var/spool/cron
It intentionally does not copy active database files or Docker runtime storage. Databases must be backed up through a dedicated source with a dump/quiesce hook.
Tracium PostgreSQL source
The tracium-postgres source creates a logical PostgreSQL backup from the
tracium-postgres-1 container:
- config:
/etc/tracium-backup/sources.d/tracium-postgres.conf - pre-hook:
/etc/tracium-backup/hooks.d/tracium-postgres-dump - post-hook:
/etc/tracium-backup/hooks.d/tracium-postgres-cleanup - repository:
/backup-raid/borg/tracium-postgres - timer:
tracium-backup@tracium-postgres.timer - schedule: daily at
00:30 UTCplus up to20mrandomized delay (override intracium-backup@tracium-postgres.timer.d/schedule.conf; staggered ~4h before host-ssd’s04:30 UTCso the two backups do not contend on I/O) - retention: 7 daily, 4 weekly, 6 monthly, 1 yearly
Default mode is a full custom-format pg_dump plus pg_dumpall --globals-only. The dump is written into /backup-raid/staging/tracium-postgres
and then archived by Borg. The post-hook removes the staging directory after the
archive is created.
As of 2026-07-12, the tracium database is about 297 GB. The first full run was
initially scheduled for 12:30 UTC (midday) so it would not compete with the
initial 12 TB RAID resync. That accommodation was reverted to 00:30 UTC
(night) on 2026-07-14: the ~2.5h daytime pg_dump saturated I/O on the busy
DB (assignment-worker ticks 16-56s → 86-102s) and held ACCESS SHARE on every
table, which blocked a DROP INDEX CONCURRENTLY migration and hung an
api-server boot-goose → failed deploy. Rule: run heavy DB dumps only in the
night window, away from ingestion load and deploy migrations.
A schema-only smoke archive was created successfully:
sudo env TRACIUM_POSTGRES_DUMP_MODE=schema \
/usr/local/sbin/tracium-backup-run \
/etc/tracium-backup/sources.d/tracium-postgres.confSmoke archive:
tracium-postgres-20260712T182004ZRun the full PostgreSQL backup manually only when the RAID is not doing heavy rebuild work:
sudo systemctl start 'tracium-backup@tracium-postgres.service'
journalctl -u 'tracium-backup@tracium-postgres.service' -fCheck PostgreSQL backup integrity:
sudo BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes \
borg list /backup-raid/borg/tracium-postgres
sudo BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes \
borg check --archives-only --last 1 /backup-raid/borg/tracium-postgresAdd a new source
Create a config:
sudo cp /etc/tracium-backup/sources.d/1c-filebase.conf.example \
/etc/tracium-backup/sources.d/1c-filebase.conf
sudoedit /etc/tracium-backup/sources.d/1c-filebase.conf
sudo systemctl enable --now 'tracium-backup@1c-filebase.timer'Run once manually:
sudo systemctl start 'tracium-backup@1c-filebase.service'
journalctl -u 'tracium-backup@1c-filebase.service' -n 200 --no-pagerFor 1C:
- file-base mode: stop/quiesce 1C in
PRE_HOOK, copy files, start inPOST_HOOK; - SQL-backed mode: use a dump/export hook and back up the dump staging directory, not live database files.
Inspect backups
source=host-ssd
sudo BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes \
borg list "/backup-raid/borg/$source"
latest=$(sudo BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes \
borg list --short "/backup-raid/borg/$source" | tail -1)
sudo BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes \
borg info "/backup-raid/borg/$source::$latest"Check the latest archive:
source=host-ssd
sudo BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes \
borg check --archives-only --last 1 "/backup-raid/borg/$source"Restore probe:
latest=$(sudo BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes \
borg list --short /backup-raid/borg/host-ssd | tail -1)
sudo rm -rf /backup-raid/restore-test/host-ssd-latest
sudo mkdir -p /backup-raid/restore-test/host-ssd-latest
sudo env latest="$latest" BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes \
bash -c 'cd /backup-raid/restore-test/host-ssd-latest && borg extract "/backup-raid/borg/host-ssd::$latest" etc/hostname'
sudo cmp -s /etc/hostname /backup-raid/restore-test/host-ssd-latest/etc/hostnameRAID operations
Status:
cat /proc/mdstat
sudo mdadm --detail /dev/md/backup12t
findmnt /backup-raid
df -hT /backup-raidDisk health:
sudo smartctl -H /dev/sdb
sudo smartctl -H /dev/sdc
sudo smartctl -H /dev/sda
sudo smartctl -H /dev/nvme0n1If a disk fails, replace only the failed member. Identify by serial before any destructive command:
lsblk -e7 -o NAME,SIZE,MODEL,SERIAL,FSTYPE,MOUNTPOINTS
sudo mdadm --detail /dev/md/backup12tAfter replacing a failed disk, partition it like the healthy member, then add it:
sudo sfdisk -d /dev/sdX | sudo sfdisk /dev/sdY
sudo partprobe /dev/sdY
sudo mdadm --add /dev/md/backup12t /dev/sdY1
watch cat /proc/mdstatUse the actual device names from mdadm --detail; do not assume sdX/sdY.
Important caveats
- Borg repositories are local and unencrypted. This is intentional for unattended local restore, but physical access to the disks is equivalent to access to the backup contents.
- RAID1 is not a backup by itself; it protects against one HDD failure. Borg archives provide historical restore points.
- The current
/backup1 TB disk is still live storage. The examplelegacy-backup-1tb.conf.examplecan snapshot it into Borg, but enabling it should be a separate operator decision because the first run may copy hundreds of GB. - Active DB files must not be backed up by plain file copy. Add dedicated dump sources for Postgres, 1C SQL, or other databases.