OBS recording archive
Updated July 30, 2026.
The Worship Mac records OBS services under:
/Users/worship/Movies/OBS/Main Recording
Storage pulls completed recordings into:
/mnt/bulk-storage/automated_recordings/obs-recordings
The old daily /root/obs-backup.sh cron mistook an open OBS application for an
active recording and had not archived successfully since June 18. It is
disabled. OBS may remain open with the replacement; eligibility is decided per
file.
Safety model
The storage-initiated archive accepts only direct-child mov, mkv, and mp4
regular files. Symlinks, unsupported extensions, open files, and files newer
than 30 minutes are excluded.
For every eligible recording:
- The Mac reports device, inode, size, modification time, and an encoded path constrained to the exact recording root.
- Storage streams without compression into a root-only
.incomingdirectory. Interrupted copies resume at the exact verified partial size. - The Mac and storage independently compute SHA-256.
- Storage atomically publishes the verified bytes on the same ZFS filesystem and writes a digest/source-identity manifest.
- The constrained Mac agent rechecks identity, stability, open state, and SHA-256 immediately before deleting only that source file.
Any transfer, capacity, digest, collision, manifest, SSH, or finalization failure retains the Mac source. If publication succeeded but the final SSH response was lost, the next run re-verifies the published object and retries only finalization instead of transferring the recording again.
The dedicated SSH public key is restricted to the archive agent's four bounded operations. Its private key remains root-only on storage and must never be printed, copied to documentation, or used for an interactive shell.
Scheduling and health
The Git-managed implementation is in the riveroaks/infra repository under
apps/obs-archive on branch feat/obs-recording-archive.
ro-obs-archive.timer checks every ten minutes. The one-shot service has a
single-run lock, requires the expected ZFS filesystem, and stops below 2 TiB
free. Health metrics are written to:
/var/lib/ro-obs-archive/health.prom
Useful checks:
systemctl status ro-obs-archive.service ro-obs-archive.timer --no-pager
journalctl -u ro-obs-archive.service --since "2 hours ago" --no-pager
grep -E '^ro_obs_archive_(run_success|discovered_files|archived_files|failed_files|capacity_low|backlog_stale) ' \
/var/lib/ro-obs-archive/health.prom
Logs identify files only by a short digest and byte count, not by recording filename. Optional telemetry is a separate service so an observability or cloud failure can never change local archive success.
Do not re-enable the legacy cron alongside the systemd timer. Full install, rollback, threat-model, and incident procedures live with the infra code.