Backups on the static filesystem
A backup of a native-symlinked site can be large: the backup tar follows the
files/private symlinks (dereferences the store), so the
tarball holds the full file data. Those backups land in
/data/disk/<account>/backups on the root partition — a disk-full risk for a
big account whose files live on attached storage.
For such accounts the nightly per-account maintenance relocates backups and
backup-exports onto the static filesystem and replaces them with symlinks:
/data/disk/<account>/backups -> /data/disk/<account>/static/files/.backups
/data/disk/<account>/backup-exports -> /data/disk/<account>/static/files/.backup-exports
The Aegir paths are unchanged — backup_path and aegir_backup_export_path
keep working through the symlinks (the same nightly run re-asserts the export
path to <account>/backup-exports in its hostmaster settings block). Both
targets live under static/files, so they share one filesystem and the
backup-download hardlinks between backups and backup-exports keep
working (hardlinks cannot cross filesystems). The leading-dot names are skipped
by the site/orphan scan, like static/files/.archived — they can never be
mistaken for site stores. The nightly local purges glob through the symlinks
unchanged (-mtime +_PURGE_BACKUPS on backups, -mtime +_PURGE_TMP on
backup-exports).
When it acts
The relocation is gated on static/files resolving (symlinks followed) to a
different device than the account root — a stat -c '%d' comparison. On a
default single-filesystem box static/files sits on the root device, there is
nowhere better to put backups, and the run is a deliberate no-op. It only
acts once an account's static/files is on attached storage — typically after a
migratefs relocation.
A backup directory that does not exist yet is left alone: Aegir creates it on first use and a later nightly run relocates it. Once both paths are symlinks the nightly pass just re-verifies the targets and creates a missing store directory — no lock, no queue pause (the steady-state fast path). A symlink pointing at an unexpected target is never touched; it is logged for operator review.
One-time migration safety
Moving existing backups is the only destructive-looking step, and it is built to never lose one:
- Incremental, low-space.
rsync --remove-source-filescopies file by file and removes each source only after it is copied — peak extra space on the tight root filesystem is roughly one file, not a full second copy. - Fail-open. On any failure the real directory stays in place and no symlink is created; the directory is replaced only after it emptied cleanly. A non-empty leftover is logged and left for review. A backup is never deleted.
- Ownership preserved. The source's
owner:groupis captured first and applied to the store directory and (withchown -h) to the symlink itself. - Serialised. One account migrates at a time, guarded by a real
flockon/run/.boa_backups_relocate.flock— the kernel releases it if the process dies, so there is no stale-lock guessing.
Task-queue interlock
So that no backup task writes into a directory being moved, the migration holds
the Aegir task queue with the dedicated stop file /run/boa_queue_stop.pid
(its own PID; an existing hold is respected, never overwritten):
runner.shhonours it twice — the parent exits immediately, and each per-account child dispatch skips too, so a pause set after a runner started still holds every dispatch.- Any already-running task is drained first (bounded wait, ~60 s); if one is still active the relocation defers to the next night rather than move a backup mid-write, and the interlock is re-checked once more right before each move.
- The mechanism is self-healing by design: the run removes the stop file only if
it created it and still owns it (recorded PID verified),
clear.shpurges a leaked one as soon as its owner PID is gone, and/runclears on reboot — so it cannot freeze the queue. The same generic stop file is used by the nightly symlink automation; the queue side is described on Task queue.
Verification
readlink /data/disk/<account>/backups
readlink /data/disk/<account>/backup-exports
On a relocated account both print the static/files/.backups /
.backup-exports targets; on a single-filesystem box both remain real
directories. The per-account nightly log records the outcome with
backups-on-static: lines — relocated <dir> -> <target> (static filesystem)
on success, move failed / not empty after move / could not symlink when a
step was skipped fail-open (the data is then still in place, or safe in the
store awaiting a manual relink).
Kill-switches
On by default where the filesystem gate applies; disable without a code change:
| Control file | Scope |
|---|---|
/data/conf/disable_backups_on_static_fs.cnf |
box-wide — all accounts on this host |
/data/disk/<account>/static/control/no_backups_on_static_fs.info |
one Octopus account |
While present the nightly pass returns before doing anything — it stops future relocation but never moves already-relocated data back; undoing a relocation is a manual operation. The full control-file catalogue is on the Configuration leaf.
Known caveat
Pre-existing backups↔backup-exports hardlink pairs are de-linked by the
one-time move — the two directories migrate in separate rsync runs (no -H),
so old tarballs briefly cost double space, on the static filesystem (the target),
not the tight root one. The duplication ages out with the normal purge sweeps —
_PURGE_TMP clears the backup-exports copy, _PURGE_BACKUPS the backups
copy. Backups taken after relocation hardlink normally,
since both directories are then co-located on one filesystem.
Related pages
- Overview & safety model — the symlink layout whose dereferenced backups this page is about.
- Configuration — every control file and cnf variable of the symlinking subsystem.
- Backups overview — per-account backup directories may be symlinks; what that means for off-site include/exclude sets.
- Task queue — how the runner dispatches tasks and honours queue pauses.
- migratefs storage relocation
— how
static/filesends up on a separate filesystem in the first place.