Managing Aegir from the command line
The Aegir control panel is a thin front end over Drush. Every task you click
in the UI spawns a backend provision-* command against a Drush alias
(@server_master, @platform_…, @site-uri) — the same commands you can run
by hand. This page is the operator reference for driving the back end directly:
the verb set, what Verify actually checks per context type, and how to read a
failing task with --debug. For the alias/context model these verbs resolve
against, see the Entity & service model and, for the
developer-level internals, Provision backend.
It also walks the full lifecycle end to end — standing up a platform and a site — the node-first way that actually produces a serving site, with the hard rules and the two "what's good, what's bad" truths that BOA's own install testing surfaced on a live instance.
Run backend commands as the instance owner
BOA runs the hosting back end as the Octopus instance user oN (control-plane
tasks run as aegir on the Master), never as root — see
Multi-Octopus model. Drive a backend verb either as that
user or through the front end:
# As root: become the instance user, then call the backend directly
su - o1 -c 'drush @foo.example.com provision-verify'
# Or queue it through Hostmaster so the front end stays in sync (preferred)
drush @hostmaster hosting-task @foo.example.com verify
Guard-rail — keep the front end in sync. A raw provision-* command changes
the site/platform on disk but does not tell Hostmaster it happened, so the
control panel's recorded state can drift. Prefer hosting-task (which runs the
same backend verb and records the result as a task node), or run a front-end
Verify afterwards to reconcile. Reach for raw provision-* for diagnostics and
scripted bulk work, not for routine state changes.
The verb set
| Command | What it does | BOA notes |
|---|---|---|
provision-save @alias … |
Create/update a context (server / platform / site) as a Drush alias file; --delete removes it |
The alias must exist before install/clone; a bare domain will not work |
provision-verify |
Re-check and re-sync a context (see the checklists below) | Safe to re-run; the first tool to reach for when a context looks wrong |
provision-install |
Install the site the context describes (DB + user, run the profile, write vhost) | Creating the context does not install the site — this does |
provision-migrate @target-platform |
Move a site to another platform (upgrade path) | Runs drush updatedb; target is gated by the package comparison |
provision-clone @new @target-platform |
Copy a site to a new alias, source left in place | @new must be a provision-saved alias, not a bare domain |
provision-backup / provision-restore |
Tarball the site (files + DB dump) / restore from one | Backups are flat <uri>-<timestamp>.tar.gz under ~/backups |
provision-deploy |
Unpack a backup tarball into a platform as a site | The primitive behind restore, clone, migrate and import |
provision-import |
Register an on-disk site the context points at into the back end | See Importing & exporting sites |
provision-delete |
Remove the site (DB, user, files, vhost, alias) | Front-end Delete adds the disable-first safety; the raw verb does not |
hosting-task <nid|@alias> <task> |
Run a task through Hostmaster and record it | The front-end-synced way to run any of the above |
hosting-import @alias |
Pull a back-end context into the front end as a node | How platform Verify auto-registers untracked sites |
hosting-tasks |
The queue worker the dispatcher forks | Not run by hand — see Task queue engine |
hosting-task takes positional name=value arguments for the tasks that need
them, e.g. a clone: drush @hostmaster hosting-task @source clone new_uri=copy.example.com target_platform=@target.
Standing up a platform and a site from the command line
This is the sequence the frontend's Add platform and Add site forms run, and
the one to replicate for headless automation. The single most important rule is
node-first: create the Hostmaster node and let the dispatcher run the task
chain. Do not drive the raw provision-* verbs and expect a site that serves —
the two truths at the end of this section are why. This flow is not theory: it was
reverse-engineered from real BOA task logs and validated end to end on a live
instance, installing seven different Drupal distributions.
1 — Create the platform, and let its Verify register the profile. Creating a
hosting_platform node (the Add platform form, or a drush @hostmaster php-script helper that inserts the node) auto-queues the platform Verify.
That Verify does two things: it runs the backend provision-verify (scan
profiles, apply BOA core patches, symlink o_contrib, lock site-local Drush)
and it registers each install profile on the platform as a package. That
registration is load-bearing — a site's profile field is that package's node id,
not a machine name — so the platform must be created and verified before any
site is placed on it, or the site fails with Could not find the Profile <name> for Platform ID <nid>.
2 — Create the site, and let its Install auto-chain. Creating a hosting_site
node (the Add site form, or a helper inserting the node with the platform nid +
the resolved profile package + a client + a db server) auto-queues the Install
task. Running Install through the hosting task auto-chains Verify → Flush
caches and marks the site Enabled. Install creates the DB and user, writes
settings.php (with literal creds) and the nginx vhost, and on D10+ unlocks the
site-local Drush to run site-install <profile> then re-locks it.
3 — Wait for the dispatcher. Do not launch the follow-up tasks yourself and do not force the queue. The cron dispatcher runs the queued chain; poll the site until it serves. See Task queue engine.
Under the hood — the backend verbs each step runs
Useful for understanding and diagnostics (this is what the tasks above execute):
# Platform: save the context at the REAL docroot (…/web or …/docroot for Composer
# layouts), no --makefile for a pre-built codebase; backend verify; then the
# FRONTEND verify that registers the install-profile package.
drush --root=/data/disk/o1/static/…/web provision-save '@platform_mysite' --context_type=platform
drush @platform_mysite provision-verify
drush @hostmaster hosting-task @platform_mysite verify
# Site: save the context (profile = the distribution's machine name, or `standard`
# for a bare core), then install.
drush provision-save '@site.example.com' --context_type=site --uri=site.example.com \
--platform=@platform_mysite --server=@server_master --db_server=@server_localhost \
--profile=commerce_kickstart --client_name=admin
drush @site.example.com provision-install
The install profile is the crux for distributions. A bare Drupal core installs
standard; a distribution passes its own profile machine name —
commerce_kickstart, thunder, localgov, farm, openculturas,
drupal_cms_installer, and so on — both on the site --profile= and as the first
argument to the underlying site-install.
The hard rules
Each of these came from a real breakage during BOA install testing — do not "simplify" them away:
- Never force the queue.
hosting-tasks --force/ a hand-runhosting-dispatchruns other nodes' tasks too and races the dispatcher. Create the node and wait. - Never write the Hostmaster DB directly. Go through the provision/hosting API
(a node insert, a
hosting-task) — neversqlqinto thehosting_*tables. A direct write desyncs the front end and corrupts contexts. - Register each site exactly once. A platform Verify auto-imports any site in
its
sites/directory (automatic site import is on by default), so do not alsohosting-importthat same site — the double registration produces a mixed site/server context and a duplicate-key crash. - Platform verified before site — the profile-package rule above.
Two truths about driving it raw
What is genuinely good about the backend verbs, and where they stop:
- Raw
provision-verify/provision-saveare the right tool for diagnostics, scripted checks, and proving the installer itself. - Raw
provision-installinstalls Drupal but does not make it serve. A site built purely from the backend triad — with no Hostmaster node — has nosites.phpentry and returns HTTP 500. Only the node-first flow regeneratessites.php, rebuilds the container, and writes the vhost that makes the site reachable. Use raw provision to prove an install; use the node-first flow to run a site. - Backend
provision-verifyalone does not register the profile package — only the frontend platform Verify (the hosting-layer task) does. Skipping it is what triggers the "Could not find the Profile" error above.
What Verify checks, per context
provision-verify runs a pre → context verify (service fan-out) → post hook
chain, and does different work for each of the three context types. BOA is
Nginx-only, so every "reload the web server" step is nginx -s reload — there is
no Apache path.
Server verify (@server_master)
Scaffolds the config tree (config, config/includes, config/server_master,
per-service dirs; the Master also seeds an empty global.inc), verifies the
database service (connects to the master DB and probes can_create_database,
can_grant_privileges, and utf8mb4 support), caches the Nginx feature flags it
reads from nginx -V, and reloads Nginx. The master→remote config-sync and
include_path branches exist in the code but are inert on BOA: every box is
single-server, so remote_host is localhost. A server verify also cascades a
verify task to every enabled platform on that server
(hosting_platform.drush.inc:110-116).
Platform verify (@platform_…)
Fixes a Composer web root if present, optionally builds from a makefile/composer install, bootstraps DRUPAL_ROOT, corrects ownership, wires the per-core
o_contrib symlink, seeds boa_platform_control.ini, and — on D8+ — locks the
site-local Drush. Crucially it rebuilds the package registry: it enumerates
every module/theme/profile on the platform into package instances
(verify.provision.inc:167-169, via provision_drupal_find_sites() +
provision_find_packages()), which is what the migrate/clone
upgrade-safety comparison
reads. It then triggers the front-end half of automatic site import:
hosting_platform_post_hosting_verify_task() queues an import for any allowed
untracked site URL it discovers, because hosting_platform_automatic_site_import
is on by default (hosting.module:1331).
Site verify (@site-uri)
Rewrites settings.php — with literal DB credentials, because BOA's Nginx
service returns cloaked_db_creds() = FALSE, the opposite of the stock-Aegir
cloaked default (this is why site-local Drush works; see
settings.php wiring) —
re-renders the vhost and reloads Nginx, pushes the site to its server, rebuilds
caches, regenerates the cron key, seeds boa_site_control.ini, and re-locks the
site-local Drush on D8+.
Core-version split. Site post-verify rebuilds caches with
_provision_drupal_rebuild_d8plus() on D10+ (a site-local Drush call, because
Aegir's Drush 8 cannot full-bootstrap a D10+ site) versus
_provision_drupal_rebuild_caches() on older cores
(verify.provision.inc:491-501); site validate takes a full bootstrap below D12
but only a configuration bootstrap on D12+.
Diagnosing a failed task with --debug
When a task fails in the queue, re-run its backend verb by hand with Drush's
--debug flag — the command declares allow-additional-options => TRUE, so the
standard Drush verbosity flags pass straight through:
su - o1 -c 'drush @foo.example.com provision-verify --debug'
--debug surfaces the full per-service dispatch, every rsync/exec command it
runs, the bootstrap steps, and the drush_log('debug') traces the backend emits.
It is the fastest way to see which step of a Verify/Install/Migrate is actually
failing, rather than the summarised red task in the UI. For queue-level problems
(tasks stuck Processing, the dispatcher not firing) see
Aegir task failures.
Names and output you'll need
- Server aliases.
@server_masteris the web/HTTP server (always present);@server_localhostis the database server where a separate one is configured — use it for--db_server, otherwise fall back to@server_master. - Platform alias =
platform_+ the node title with every non-[A-Za-z0-9_]character stripped (underscore kept): a platform titledcommerce_kickstart-5.1.0-11.4.1resolves to@platform_commerce_kickstart5101141. - Site alias = the site's FQDN; the site's DB name is the first 16 characters of the sanitised URI.
- CLI verbosity hides
infolines. Run by hand, Drush suppresses theinfo-level lines (Found install profile,running drupal …) that the frontend task log captures. Add-vto see them — and do not read their absence as failure: aprovision-verifyexit code of 0 is the truth, not the quiet output.
Related
- Task queue engine — how these verbs get dispatched from cron.
- Entity & service model — the server/platform/site contexts and the package registry these verbs read and write.
- Site cloning & in-host migration — Clone/Migrate and the upgrade-safety comparison.
- Importing & exporting sites —
provision-import/hosting-importand taking a site off BOA. - Aegir task failures — recovering stuck and failed tasks.