Site cloning & in-host migration
Two Aegir tasks duplicate or relocate a site without leaving the host:
- Clone — create a new site as a copy of an existing one (same host, often same platform, new machine-name).
- Migrate — move a site from one platform to another on the same host. The classic
Drupal-version-upgrade path: add
drupal-10.5-proviaoctopus up-lts platforms, then migrate the site onto it.
Both are Provision backup/restore operations under the hood — a full site backup followed by a restore on the new platform or machine-name, plus a Hostmaster node rewrite. BOA layers two control files on top that trade safety for speed when you trust the source.
The two accelerators
| Control file | Path | Effect | Scope |
|---|---|---|---|
FastTrack.info |
~/static/control/FastTrack.info |
skip the pre-clone/pre-migrate verify tasks | clone + migrate |
MyQuick.info |
~/static/control/MyQuick.info |
per-table parallel mydumper/myloader instead of single-stream dump |
backup, clone, migrate, delete |
They are independent — either, both, or neither. Both are empty control files in the
Octopus instance's ~/static/control/ directory (their presence is the switch; contents
are irrelevant), so an instance owner without root can toggle them.
Mind the BOA defaults — these are not a neutral opt-in. A periodic barracuda pass
maintains the default state per instance, and it is not "off for both":
- MyQuick is ON by default. Each pass writes
MyQuick.info(unless aMyClassic.infoopt-out file exists), so parallel dump/restore — and its Restore-task caveat below — is the default behaviour, not something you opt into. - FastTrack is OFF by default. The same pass deletes any
FastTrack.infoonce and writesClassicTrack.info, so the defensive verifies run by default.
FastTrack — skip the defensive verifies
By default Clone and Migrate queue a set of verify tasks first: verify source platform,
verify target platform, verify source site. With FastTrack.info present:
- Both source and target platforms are no longer verified.
- The site is no longer verified before clone or migrate.
Those verifies normally catch ownership drift, missing modules, and broken
settings.php — issues that, if uncaught, surface mid-clone and can leave the new site
in a state that is hard to recover without root. The legitimate reason to skip them is
mass migration: verifying every platform and site for each clone in a batch of 200
is duplicated work once you have verified at the start of the batch.
Restore the default (verifying) behaviour:
touch ~/static/control/ClassicTrack.info
rm ~/static/control/FastTrack.info
ClassicTrack.info is the explicit opt-back-in — create it and delete FastTrack.info
to force classic Aegir behaviour.
MyQuick — parallel dump/restore
With MyQuick.info present, the DB phase of backup, clone, migrate and delete tasks
switches to a per-table parallel mydumper dump and myloader import, collapsing the
hours-long single-stream dump of a large database to minutes (BOA's own figure: tasks
that normally take 1–2 hours down to 3–6 minutes).
The trade-off — restore task breaks. With MyQuick active, Aegir does not leave a
conventional complete .sql dump inside the site archive tarball. The split per-table
dump is not what Aegir's Restore task expects, so Restore will not work for any site
whose last archive was produced under MyQuick. Because MyQuick is on by default (see
above), this caveat applies on a stock BOA host unless you have deliberately turned it
off.
Mitigations:
- The system still maintains nightly backups of every site using the split-dump format. You can find the per-table SQL dump in the backups directory under a timestamped subdirectory and reconstruct/restore manually.
- If you specifically need Aegir's Restore task to work, opt out of MyQuick by
creating
~/static/control/MyClassic.infoand removing~/static/control/MyQuick.info.MyClassic.infostops the periodicbarracudapass from re-writingMyQuick.info, so the slower single-stream dump (which Restore can read) becomes the default again.
Where the speed difference comes from
| Phase | Default | FastTrack | MyQuick |
|---|---|---|---|
| Verify source platform | queued | skipped | n/a |
| Verify target platform | queued | skipped | n/a |
| Verify source site | queued | skipped | n/a |
| Backup source DB | single-stream (slow) | (no change) | parallel (fast) |
| Copy site files | unchanged | (no change) | (no change) |
| Restore DB on new name/platform | single-stream (slow) | (no change) | parallel (fast) |
| Install / verify new site | unchanged | (no change) | (no change) |
FastTrack removes the verify overhead; MyQuick parallelises the two DB phases. Combined on a large DB-heavy site they are transformative; on a small site FastTrack alone is the bigger win.
Clone — Provision backend
The Aegir Clone task wraps Provision's provision-clone. Its first argument is the
Drush alias of the new site as generated by provision-save, not a bare domain:
# provision-save the new site first, then:
drush @site provision-clone @new_site @platform_name
Passing a bare domain as the first argument fails — the new site must already have a
saved Drush alias. The Hostmaster-side task that registers the clone in the front-end DB
takes positional name=value task arguments (the clone task reads new_uri and
target_platform):
drush @hostmaster hosting-task @source-site clone \
new_uri=clone-of-foo.example.com target_platform=@target-platform-alias
In practice operators drive one-offs from the Aegir UI (source site node → Tasks → Clone) and use Drush only for scripted bulk operations.
Migrate — Provision backend
The Aegir Migrate task wraps Provision's provision-migrate:
drush @site-alias provision-migrate @target-platform-alias
The task verifies the target platform supports the site's modules, briefly disables the
site, moves sites/<domain>/ from the old platform to the new, updates the codebase
references, runs drush updatedb -y on the new platform, rewrites the nginx vhost to the new
platform path, and re-enables the site. Total downtime is typically 30 s to a few
minutes depending on DB size.
hosting_migrate also ships hosting_migrate.batch.inc for migrating many sites in one
job — the common shape during a Drupal-version upgrade, where every site on the old
platform moves to the new one. The Hostmaster-side hosting-task uses the same
positional new_uri= / target_platform= argument form as Clone.
A Migrate can also cross installation profiles when the target platform uses a
different profile — moving a site from, say, a distribution profile to plain drupal.
Site Verify must run clean first
Migrate (and Clone, without FastTrack) depend on the source site verifying cleanly. A site that fails Verify on the source will fail the relocation; fix the verify error before relocating, or accept the FastTrack risk knowingly.
Upgrade safety: how a target platform is judged
Migrate and Clone are the Aegir-preferred way to apply core and module updates —
build a new platform with the newer code, then move sites onto it — and the front
end will not let you move a site somewhere that would corrupt it. When you open
the Migrate or Clone form, each candidate target platform is classified from a
per-package comparison of the site's current platform against the target,
and the result is shown under each target as Upgrades / Warnings / Errors
(hosting_package_comparison(), hosting_package.instance.inc:334-395).
The comparison keys every module and theme by its installed schema version and a computed version code, and sorts each into:
- Error — an enabled package whose schema on the current platform is newer
than on the target. Moving there would be a schema downgrade, which Drupal
cannot do. A target with any Error count is disabled on the form — you
cannot select it (
hosting_migrate.module:204-206). - Warning — a package missing from the target (it would be disabled by Drupal's update logic), or a straight downgrade of a non-blocking package.
- Upgrade — the target has a newer version/schema; the move runs the module's updates.
The Compare platforms link on the form (hosting/migrate/compare/…) opens a
per-package table tagging each module downgrade / missing / upgrade / same, so you
can see exactly why a target is flagged before committing.
Because the comparison reads each platform's package registry, it is only as current as the last Verify of the platforms involved: if you have just added modules to a target platform, re-Verify it so the newly available versions are registered before you rely on the Migrate form's judgement.
Drupal 10+ / Composer platforms. This registry is not a Drupal-7-only relic —
Provision populates each package's schema version from
\Drupal::service('update.update_hook_registry')->getInstalledVersion() on D10+
(and drupal_get_installed_schema_version() below that), so the upgrade/warning/
error gating and the Compare view keep working for Composer-built platforms. The
one difference is that module/theme detection reads *.info.yml on modern cores,
so the exact set of packages compared is core-version dependent.
TLS / Encryption auto-disable
Neither a clone nor a name-changing migrate carries the source's TLS certificate. The key and certificate are bound to the source machine-name and must never be reused by the new node, so BOA auto-disables Encryption on the new node before it is saved.
On clone — hosting_clone resets the new node unconditionally (guarded only by
HOSTING_SSL_DISABLED being defined):
$clone->ssl_enabled = HOSTING_SSL_DISABLED;
$clone->ssl_key = 0;
This mirrors the existing safety where a clone also starts with cron disabled.
On migrate — only when the machine-name actually changes. hosting_migrate compares
the source domain against new_uri; if they differ (and the node is not the
Hostmaster site), it sets ssl_enabled = HOSTING_SSL_DISABLED and ssl_key = 0 on the
front end, and the Provision backend forces ssl_enabled = 0 / unsets ssl_key before
the final verify. Stale per-site Let's Encrypt control/pid files are unlinked
automatically; the immutable manual-cert flag is preserved. A same-name
platform-to-platform migrate (machine-name unchanged) leaves Encryption enabled in its
persisted end-state, but the Provision backend still transiently disables SSL
(ssl_enabled = 0 / unset ssl_key) around the migrate to avoid vhost/key race edge
cases, then re-enables it afterwards from the saved encryption_was_enabled state — so
the certificate is not carried across a name change but is not permanently dropped on a
same-name move. The Hostmaster site is exempt.
In every case the operator re-enables Encryption deliberately for the new hostname — issue a fresh Let's Encrypt certificate for the clone's real domain rather than carrying the source's over.
Files symlinking on clone and migrate/rename
Both tasks deploy the new site from a backup that preserves symlinks, and on a
native-symlinked BOA host a site's files/private dirs are symlinks into the
per-account store. Left alone, the freshly deployed copy would keep pointing at the
source site's store. Provision re-homes it automatically:
- Clone — after the clone's post-deploy verify, the clone task runs the hardened
NOPASSWD sudo wrapper
/usr/local/bin/fix-drupal-site-symlinks.sh, which drivesautosymlink's narrow single-site--force-unshareapply mode: the source's files are copied into the clone's own/data/disk/<account>/static/files/<clone>/store and the in-site symlinks repointed.--force-unsharebreaks the inherited link even when astatic/control/share.files.<site>.infosharing file exists — a fresh clone never opted into sharing. - Migrate / rename — the Migrate task (also the RENAME path, e.g. promoting staging
to live) mirrors the clone flow right after the target verify: the inherited old-name
link is broken, the data copied into the target's own
static/files/<uri>store, and the symlinks repointed. A store already sitting at the target name is archived aside first. The old-name store then becomes a normal reported orphan, archived to.archived/by the nightly sweep — never auto-deleted. A same-name platform-to-platform migrate simply re-verifies idempotently.
Warn-not-fail. The symlink step never fails the clone or migrate. Operator signals:
| Outcome | Where you see it |
|---|---|
| Success | Aegir task log: [native-symlink] <site>: files/private moved into the per-account store and symlinked |
| Wrapper run failed / returned non-zero | Aegir task log: [native-symlink] <site>: could not move files into the store (non-fatal); left as plain dirs - manual review if symlinking was expected — the task still succeeds |
Unshare not completed — deferred by the nightly maintenance pause (/etc/boa/.pause_tasks_maint.cnf), per-site dry-run not clean, or the unshare could not be applied (missing source / no space / rsync fail) |
/var/log/boa/autosymlink.log: [ALERT] Clone unshare for <site> not completed ...; files may still be shared with the source - manual review required |
Wrapper absent, kill-switch control file present, or account not under /data/disk |
Silent skip — no warning, no ALERT |
Recovery once space is available (or the pause has lifted):
sudo /usr/local/bin/fix-drupal-site-symlinks.sh --site=<clone> --force-unshare
Caveat: a cross-account clone under low disk may keep a link into the source store until the manual rerun; a same-account shared link is harmless. See Files symlinking for the subsystem overview, kill-switches and store layout, and Orphans & archiving for how the old-name store is archived.
Backups produced by these tasks
Provision writes its task backups to the server's flat backup directory (~/backups,
i.e. aegir_root/backups) as a single hyphenated tarball per archive:
~/backups/<uri>-<timestamp>.tar.gz
for example ~/backups/foo.example.com-20260623.143501.tar.gz. There is no per-site
subdirectory — the file is flat in ~/backups, named <uri>-<date>. Under MyQuick, the
split per-table SQL dump for the same archive sits in a timestamped directory alongside
(<uri>_sql_dump_backup_<timestamp>), which is the dump you reconstruct from when the
Aegir Restore task cannot read a MyQuick archive.
Clone vs cross-host move
Clone and Migrate stay on one host. To duplicate or relocate an account onto a different
BOA host, use the root-side toolchain — xcopy to duplicate, xoct to move a single
account, xmass for the whole server. See
Cross-host migration.
Related
- Cross-host migration — moving accounts between hosts
(
xoct/xcopy/xmass); within-host clone is the related but distinct concept. - Aliases & redirects — a clone with a new machine-name often needs its alias set rebuilt.
- Files symlinking — the native per-account files store that clone/migrate re-home into; tools, kill-switches, orphan archiving.
- Database (MySQL/Percona) — the
mydumper/myloaderlayer MyQuick drives. - Backups internals & operations — the host-level off-site backup suite, separate from these per-task Provision backups.
- See the Reference appendix for the consolidated control-file and command tables.