Skip to content

Powered by Grav

Native files symlinking

Native files symlinking

How BOA keeps each site's writable files and private directories in the account's static store, symlinked back into the platform, with a warn-not-fail safety model.

BOA keeps each site's writable files and private directories outside the platform docroot, in the owning Octopus account's static store, and links them back into the site:

TXT
sites/<url>/files    ->  /data/disk/<account>/static/files/<url>/files
sites/<url>/private  ->  /data/disk/<account>/static/files/<url>/private

Only a symlink lives in the platform, so:

  • a site's uploads survive platform rebuilds and code redeploys untouched;
  • every site's data has one per-account home under static/files/;
  • because the store is a single directory tree, the whole store can be relocated onto attached /mnt storage with migratefs while the per-site links keep working through it.

Where the subsystem acts

The subsystem acts at three points:

  • New-site install: Provision's post-install hook has the just-created real files/private moved into the store and symlinked, before the first verify writes the vhost.
  • Clone and Migrate/rename: after the target verify, the new site is re-homed into its own store with --force-unshare, which breaks the inherited link into the source name's data even when a sharing control file exists — a fresh clone or renamed site never opted into the share.
  • The gated nightly batch: converts pre-existing plain-directory sites and archives deleted-site orphan stores — opt-in everywhere except the omega8.cc-hosted (.aegir.cc) fleet, where it is seeded on by default.

Existing unconverted sites are deliberately not touched by a normal install or verify; only the nightly auto-fix or a manual run moves data at a time an operator chose.

Safety model

The safety model is uniform across all of it:

  • Every path is warn-not-fail: low disk, a missing tool, or any non-zero step logs a warning and the task still succeeds — a conversion falls back to plain real directories, and a clone unshare that cannot complete leaves a still-shared link flagged with an operator-actionable [ALERT] for a manual re-run once space allows; never a dangling link, never an aborted install or clone.
  • Moves are crash-safe and rc-checked: a symlink is never created over a failed or partial move, and an interrupted run is self-healed on the next pass.
  • Stale and orphaned stores are archived, never deleted — moved into static/files/.archived/<stamp>/, with pruning left strictly to the operator.
  • Root-managed conversion: because the store is root-managed while Provision tasks run unprivileged, the conversion always runs as root through a hardened NOPASSWD sudo wrapper (/usr/local/bin/fix-drupal-site-symlinks.sh) that fail-closed validates its arguments and can reach only the narrow single-site apply — never the global batch/live modes.

Scope is /data/disk/<account> Octopus accounts only; the master hostmaster account keeps plain directories.

Kill-switches and file sharing

Two kill-switch tiers disable native symlinking without a code change:

  • box-wide /data/conf/disable_native_files_symlink.cnf;
  • per-account /data/disk/<account>/static/control/no_native_files_symlink.info.

Deliberate cross-site file sharing remains possible via static/control/share.files.<site>.info, honoured everywhere except cloning.

Cross-cutting

  • The Clone and Migrate tasks whose logs now carry the [native-symlink] success line (and, on low disk, an operator-actionable [ALERT]) are in Migration & cloning; relocating the account-level static/files store itself onto attached storage is migratefs.
  • The nightly window the automation shares — cadence, heavy-task skips, and the other night workers — is in the monitor stack; the task-queue pause mechanism it holds is the task queue.
  • The sudoers entry for the wrapper and the AppArmor mrix exec edges added to every PHP profile are in Security & isolation (AppArmor).
  • The backup subsystem whose per-account backups directories the nightly relocation moves is Backups.
  • The _AUTOSYMLINK_* / _ORPHAN_FILES_REPORT variables are catalogued in the host control-file reference and the Reference appendix.

Native files symlinking — overview & safety model

The store layout and event model for native files symlinking, plus the privilege and account scope, the warn-not-fail safety properties, kill-switches and file sharing.

Files-symlink tools — autosymlink, sudo wrapper, symlinkinfo

The three executables behind the subsystem: the autosymlink worker and its modes, the hardened sudo wrapper, and the read-only symlinkinfo history query, with logs.

Nightly automation — updatesymlinks

The updatesymlinks scheduler around autosymlink: the auto-fix and orphan-report sub-modes, the nightly cron line, the task-queue pause and grace, and the heavy-task skips.

Files-symlinking configuration reference

The three barracuda.cnf variables that govern the nightly automation, how Barracuda persists them, the defaults by system class, and the full kill-switch control-file catalogue.

Orphan stores & the .archived archive

How a deleted site's leftover store is detected by the strict alias-and-vhost test, archived into a dated .archived directory rather than deleted, and pruned only by you.

Backups on the static filesystem

The nightly relocation of an account's backups and backup-exports onto its static filesystem, gated on a different-device test, with its no-op default and kill-switches.

Why a dry run is NOT CLEAN — the EXPLAINED section

Why one anomaly marks a whole dry run NOT CLEAN and blocks batch conversion, and how the read-only EXPLAINED section re-probes each finding with its diagnosis and fix.

© 2026 BOA Documentation. All rights reserved.