Hostmaster frontend internals
Hostmaster is the Drupal 7 install profile that is Aegir's web UI — the
omega8cc fork ships it as its own repo on the public branch model
(5.x-dev / 5.x-pro / 5.x-lts plus their -base/-edge variants). A BOA
box runs it N+1 times: one Master frontend under /var/aegir (the
aegir user's controlling instance) and one Satellite frontend per
Octopus instance under /data/disk/<user> — each a complete, independent
Drupal 7 site with its own database, its own codebase generation and its own
Drush alias. This page is the profile's anatomy; the staged scripts that
run the build are on the
staged setup engine page.
The repo root is small and every file is load-bearing:
| File | Lines | Role |
|---|---|---|
hostmaster.info |
57 | Profile metadata + the module manifest Drupal enables at install |
hostmaster.install |
327 | hook_install() — builds the initial Aegir node graph and site config |
hostmaster.profile |
16 | One hook: un-hides the profile from update status |
hostmaster.make |
63 | BOA build entry — pins Aegir projects to /opt/tmp/make_local/* copies |
drupal-org.make |
158 | Shared include — placement rules + the full contrib/library list |
build-hostmaster.make |
11 | Standalone build entry (core tarball from files.aegir.cc) |
drupal-org-core.make |
12 | Historic drupal.org-packager core pin; inert in BOA builds |
hostmaster.info — the module manifest
Standard D7 install-profile metadata (core = 7.x,
distribution_name = "Hostmaster (Aegir)") with one structural switch:
exclusive = TRUE (hostmaster.info:6), which makes the D7 installer
auto-select the profile — no profile-picker step on a Hostmaster platform.
The dependencies[] list is the canonical "what is enabled at install"
manifest, 40 active entries in four commented tiers:
- Drupal core (
:10-20):block book color comment filter help menu node overlay system user. - Aegir core (
:23-37):hostingplus 14hosting_*submodules —alias client clone cron db_server le migrate package platform server site task tasks_extra web_server. These resolve from the monolithichostingrepo (which carries the submodule directories) and from the separately-bundledhosting_leandhosting_tasks_extraprojects. - Aegir golden contrib (
:40-41):hosting_platform_composer_git,hosting_platform_git. - Drupal contrib (
:44-55):actions_permissions admin_menu ctools environment_indicator fe_block features overlay_paths revision_deletion strongarm userprotect views views_bulk_operations.betterloginandr4032loginare present but commented out (:56-57) — still built into the platform by the make chain, not enabled at install.
Adding a bundled module is therefore always a two-file change minimum: the
.info line only tells Drupal to enable it; the make chain (below) is what
puts the code on disk. A module that should be enabled on existing
instances too also needs an enable call in the BOA upgrade path — see
what BOA layers on top.
hostmaster.install — the initial node graph
hostmaster_install() (hostmaster.install:8) runs once, inside the D7
installer that provision-install triggers for the @hostmaster site. Three
phases:
- Nginx wiring (
:13-17): if the platform's server context hashttp_service_type === 'nginx'— always true on BOA — it enableshosting_nginx,hosting_ssl,hosting_nginx_ssl. Note the context read:d()->platform->serverworks here because the installer runs under Provision with the backend contexts already saved. hostmaster_bootstrap()(:27) — creates the entire initial Aegir content graph as nodes, in order: default client (from--client_name, defaultadmin;hosting_default_client/hosting_admin_clientvariables), theserver_masterserver node with itshttpservice, the DB service on the same node — or a separateserver_<host>node when the DB host differs from the web host (:68-92) — theDrupalplatform package node, thehostmasterplatform node withpublish_path = d()->root(:112-125,hosting_own_platform), thehostmasterprofile package node with package-instance rows, and finally the@hostmastersite node itself (:164-182, nid saved asaegir_hostmaster_site_nid). It then enables the default hosting features (hosting_features_enable,:187-198), setssite_frontpage = hosting/sites(:200), disables open registration (user_register = 0,:203) and recordsinstall_url(:206). The frontend registering itself as platform + site is what lets Aegir manage its own future migrations.hostmaster_task_finalize()(:209) — theme switch to eldir (below), block placement, emptiesmenu_options_*for the four Aegir node types so they never offer menu placement (:223-226), andnode_access_rebuild().
hostmaster.install runs only at INIT. Anything you change here reaches
existing instances only through hostmaster-migrate update hooks or through
BOA's upgrade-path drush calls — never assume a .install edit is fleet-wide.
hostmaster.profile — one hook
The file exists mostly so Drupal recognises the profile; its single
substantive hook is hostmaster_update_projects_alter()
(hostmaster.profile:8-16), which clones the module-data entry, flips
info['hidden'] = FALSE and re-feeds it to _update_process_info_list() —
D7 hides install profiles from update-status by default, and this un-hides
Hostmaster so a new release shows up as an available update in the UI.
The make-file chain
drush hostmaster-install does not fetch anything from the network on a BOA
box. The chain, from the top:
- Provision's
install.hostmaster.incdefaults the platform root to<aegir_root>/hostmaster-<version>(install.hostmaster.inc:71) and the makefile toprovision/aegir.make(:89). aegir.makeis twocopyprojects: Drupal core from/opt/tmp/make_local/drupaland thehostmasterprofile from/opt/tmp/make_local/hostmaster.- Drush make recurses into the copied profile's own
hostmaster.make, whichincludes[hostmaster] = "drupal-org.make"(hostmaster.make:7) and pins the ten Aegir projects —eldir,hosting, then the golden tieraegir_objects hosting_civicrm hosting_deploy hosting_git hosting_le hosting_remote_import hosting_site_backup_manager hosting_tasks_extra— tocopydownloads from/opt/tmp/make_local/<project>(hostmaster.make:11-51). Commented git-mode blocks forhosting/eldirdev work sit at:53-63. drupal-org.makesets the placement rules —defaults[projects][subdir] = "contrib", with the Aegir tier overridden tosubdir "aegir"andeldirtyped as a theme (drupal-org.make:7-25) — and pins the whole contrib set ascopyprojects from/opt/tmp/make_local/*: the D7 contrib modules, the TFA stack (libraries+tfa+tfa_basic,:71-82), three raw JS libraries (qrcodejs,timeago/timeagojs,vuejs,:85-103), the BOA contrib tier (features features_extra idna_convert revision_deletion strongarm userprotect environment_indicator tag1_d7es,:107-137) and BOA's ownhosting_custom_settings(:142-143). The tail (:145-158) is a changelog of projects removed or folded into Aegir core — check it before re-adding anything.build-hostmaster.makeis the non-BOA entry point: it pulls a pinned Drupal core tarball fromfiles.aegir.cc/core/and includes the samedrupal-org.make(build-hostmaster.make:7-11).
The resulting platform tree keeps almost everything inside the profile:
profiles/hostmaster/modules/aegir/ (Aegir tier),
profiles/hostmaster/modules/contrib/ (everything else),
profiles/hostmaster/themes/aegir/eldir/, plus top-level libraries/ for
the JS payloads. BOA's build code re-asserts those two module dirs exist at
satellite.sh.inc:6127.
Who fills /opt/tmp/make_local
_master_download_for_local_build() (master.sh.inc:547) and
_satellite_download_for_local_build() (satellite.sh.inc:3125) are
deliberate master/satellite copies of the same logic. Presence test first —
the cache is complete when hostmaster/hostmaster.make,
hosting/hosting.module and drupal/modules/system/system.module all exist
(master.sh.inc:553-555) — then either:
_DL_MODE=BATCH(default): onemake_local.tar.gzfetched via_get_dev_ext(master.sh.inc:561-568), or- GIT mode: Drupal core tarball via
_get_core_ext, then${_gCb}=git clone --branch(OCTOPUS.sh.txt:183) ofhostmaster.git,hosting.git,eldir.gitand the golden repos at branch5.x-${_tRee}from${_gitHub}(master.sh.inc:576-588), plus every pinned contrib tarball via_get_dev_stc(:591-617) — the version pins in this fetch list must match the.makecomments.
Everything is normalized to 0755/0644 afterwards. Because the make chain and
the fetch functions both name every project, adding a bundled project
touches four places: hostmaster.make or drupal-org.make, both
_download_for_local_build copies, and the mirror-side make_local.tar.gz
build. The make files ride the whole-release transport (boa.tar.gz /
git tree), not a per-file serial — see the
serial & fetch pipeline.
The hostmaster-install sequence
drush hostmaster-install <domain> (Provision command,
install.hostmaster.inc) is the single entry point both instance types use:
provision-save @server_master (+ @server_<dbhost> if DB is remote)
provision-verify @server_master (:242-243)
provision-save @platform_hostmaster root + makefile (:260-266)
provision-verify @platform_hostmaster → drush make builds the tree (:275)
provision-save @hostmaster site context, drush_aliases: 'hm' (:288-302)
provision-install @hostmaster → D7 installer → hostmaster_install() (:305)
provision-verify @hostmaster (:306)
hosting-setup → queues/cron wiring, prints one-time login link (:318)
The 'drush_aliases' => 'hm' line (:296) is why the Master's canonical
alias file is /var/aegir/.drush/hm.alias.drushrc.php while the full
hostmaster.alias.drushrc.php name is what BOA parses on Satellites —
BOA extracts root', site_path' and uri' from these files with
grep|cut|awk|sed chains all over the codebase (master.sh.inc:795,
satellite.sh.inc:1380, AegirSetupC.sh.txt:265-269). Treat the alias
files as the runtime source of truth for "where is this frontend"; never
hardcode a generation path.
Per-host and per-Octopus instances
| Master | Satellite (one per Octopus instance) | |
|---|---|---|
| Unix user | aegir |
${_USER} (o1, o2, …) |
$HOME / aegir root |
/var/aegir |
/data/disk/${_USER} |
| Platform root (INIT) | /var/aegir/hostmaster-${_AEGIR_VERSION} (AegirSetupM.sh.txt:145) |
${_ROOT}/aegir/distro/001 |
| Platform root (upgrades) | /var/aegir/host_master/NNN (AegirUpgrade.sh.txt:478) |
${_ROOT}/aegir/distro/NNN (AegirSetupA.sh.txt:127) |
| Frontend domain | _THIS_FRONT = _MY_FRONT or the host FQDN (dns.sh.inc:728-732) |
_DOMAIN = ${_USER}.<hostname> default (OCTOPUS.sh.txt:167) |
| Alias parsed by BOA | /var/aegir/.drush/hm.alias.drushrc.php |
${_ROOT}/.drush/hostmaster.alias.drushrc.php |
| Installer stage | AegirSetupM via _aegir_master_install_upgrade() (master.sh.inc:981) |
AegirSetupB via _satellite_child_b_aegir_build() (satellite.sh.inc:5687) |
| DB user | ${_AEGIR_DB_USER} (aegir) |
${_USER}, or aegir_root for remote DB hosts (satellite.sh.inc:5711-5714) |
_AEGIR_VERSION defaults to AUTO in the settings files
(barracuda.sh.cnf:1311, octopus.sh.cnf:801) and is rewritten to the tree
name by the wrappers (sed -i "s/^_AEGIR_VERSION.*/_AEGIR_VERSION=${_tRee}/g",
barracuda:874, boa:977) — so a Master INIT root looks like
hostmaster-lts, never an upstream-style hostmaster-7.x-3.x; that naming
does not exist anywhere in BOA.
Generation numbering. Satellite frontends live in numbered codebase
generations under ${_ROOT}/aegir/distro/. _HM_DISTRO=001 is the INIT
default (OCTOPUS.sh.txt:307); on upgrades _satellite_if_init_or_upgrade
globs the existing dirs and sets _HM_DISTRO to zero-padded last+1
(satellite.sh.inc:4853-4867), and _satellite_make() exports it into the
per-instance settings snapshot (:4290) that AegirSetup{A,B,C} re-derive
_HM_ROOT="${_ROOT}/aegir/distro/${_HM_DISTRO}" from
(AegirSetupA.sh.txt:127, AegirSetupB.sh.txt:127-129,
AegirSetupC.sh.txt:130-132). Stage B's UPGRADE path additionally detects
"zombie" generations — a previous root without
sites/${_DOMAIN}/settings.php — moves them to
backups/system/empty-host-master-* and re-numbers (satellite.sh.inc: 5817-5860). The Master analog is the host_master/NNN scheme managed by
the hostmaster upgrade orchestrator,
seeded with a 000 placeholder (AegirUpgrade.sh.txt:392-396).
After a Satellite install the active generation is symlinked twice:
${_ROOT}/u/${_DOMAIN} → ${_HM_ROOT} and /data/u/${_DOMAIN} → ${_HM_ROOT}
(satellite.sh.inc:5768-5773) — stable paths that survive re-numbering.
Each Satellite also gets its own queue driver: stage B writes
${_ROOT}/aegir.sh (a drush @hostmaster hosting-dispatch wrapper,
satellite.sh.inc:5466-5474) and stage A installs the per-instance runner
at /var/xdrago/run-${_USER} (satellite.sh.inc:4371-4374). The frontends
never share state — same code lineage, disjoint databases, users, queues
and vhosts.
The eldir theme
eldir is Aegir's admin theme, maintained as its own omega8cc fork and pulled
into the build like any other project: staged at /opt/tmp/make_local/eldir
(GIT mode clones eldir.git at 5.x-${_tRee} — master.sh.inc:578,
satellite.sh.inc:3157), typed as a theme and placed under the profile by
drupal-org.make:12-13 → profiles/hostmaster/themes/aegir/eldir/.
hostmaster_task_finalize() makes it the site: theme_enable(array('eldir')),
theme_default = eldir, Bartik disabled (hostmaster.install:213-217), then
hostmaster_place_blocks('eldir') (:220, defined :235-327) inserts seven
Views blocks — the task list into sidebar_first, and the
site/platform/package listing blocks into content_bottom — via a direct
db_insert('block') (:320-325), not the block API. Two consequences for
maintainers: the region names hard-couple .install to eldir's region set,
and the placement happens exactly once at INIT — a theme swap or region
rename on a live instance means re-placing blocks yourself. The stock D7
themes are stripped from the platform after install
(bluemarine chameleon pushbutton, satellite.sh.inc:3349-3351), so eldir
plus the D7 admin theme is the entire theme surface.
What BOA layers on top after hostmaster-install
A stock Aegir frontend and a BOA frontend diverge immediately after the
profile install, via two stage-B functions (Satellite side; the Master gets
the equivalent treatment in _aegir_master_install_upgrade()):
_satellite_child_b_aegir_build() (satellite.sh.inc:5687) resolves the
DB topology — localhost / 127.0.0.1 / ProxySQL / the host's own FQDN keep
_USE_DB_USER=${_USER}, a genuinely remote DB host switches it to
aegir_root (:5697-5715) — writes the instance credential snippet
${_ROOT}/.${_USER}.pass.php (0600, :5720-5728), runs hostmaster-install
with the full BOA flag set — --aegir_root=${_ROOT} --root=${_HM_ROOT} --script_user=${_USER} --web_group=${_WEBG} --http_service_type=nginx
(:5734-5762) — then strips the stock profiles
(rm -rf ${_HM_ROOT}/profiles/{default,standard,minimal,testing}, :5764),
creates the (kept-empty) sites/all/{modules,themes,libraries} scaffolding,
sets up sites/${_DOMAIN}/files with 02775/${_WEBG}, plants the u/
symlinks and drains the first task backlog with forced
hosting-dispatch/hosting-tasks rounds (:5778-5791).
_satellite_child_b_aegir_ui_enhance() (satellite.sh.inc:6120) is the
BOA-policy pass, all through ${_DRUSHCMD} @hostmaster:
- enables ~20 modules beyond the
.infomanifest (:6139-6160):aegir_objects,fix_ownership,fix_permissions,hosting_http_basic_auth(those three ship inside thehosting_tasks_extraproject tree),hosting_civicrm(_cron),hosting_deploy,hosting_platform_composer(_git),hosting_platform_git,hosting_site_backup_manager,environment_indicator,overlay(_paths),revision_deletion,timeago,userprotect,libraries, …; laterhosting_le,hosting_le_vhostandhosting_custom_settings(+features-revert) (:6283-6300); - sets the operating policy via
_vSet=variable-set --always-set(AegirSetupB.sh.txt:51): queue frequencies andhosting_queue_tasks_items 1, cron interval, platform/upload base paths under${_ROOT}/static, backup-export path,hosting_alias_automatic_*(:6161-6202); - rewrites UI state directly in SQL where no API exists: deletes the
hosting/platforms+hosting/sitesmenu links, hides the user menu, truncates the filter tables, resets the task-log display map viavariable_setindrush ev(:6203-6224,:6276-6296); - brands the instance (
site_name "Octopus System powered by Barracuda") and builds the welcome content and client records with throwaway helper scriptsmake_home.php/make_client.phpcopied from/opt/tmp/boa/aegir/helpers/*.php.txt, executed withdrush php-script, then deleted (:6227-6253); - on UPGRADE, re-points platform-node status so only the current
aegir/distro/generation stays active (status=-2for old roots,:6255-6263); - one-time SSL flip: sets the
httpservice type tonginx_ssland force-verifies@server_master, witnessed by${_ROOT}/log/hosting_le_enable.txt(:6330-6337).
The same platform-registration trick is used by stage C for the other
platforms: make_platform.php from the same helpers dir creates platform
nodes in this frontend (AegirSetupC.sh.txt:289-351).
How this differs from a plain Drupal 7 site
- Profile-centric layout. Effectively all modules and the theme live
under
profiles/hostmaster/;sites/all/*exists but is intentionally empty. Extending the frontend means changing the profile/make chain, not dropping code intosites/all. - Built offline, from pinned copies. No drupal.org fetches at build
time; every component
copy-resolves from/opt/tmp/make_local, itself a mirror artifact or a set of5.x-<tree>git clones. - Self-registered. The site's own platform and site nodes exist in its
own database (
hosting_own_platform,aegir_hostmaster_site_nid) — the frontend is a managed Aegir citizen, which is what makeshostmaster-migrateupgrades possible. - Generation-numbered roots, alias-resolved. The docroot moves on every
upgrade (
aegir/distro/NNN,host_master/NNN); nothing may assume a stable path except the drush alias files and theu/symlinks. - Trimmed and policy-locked. Stock
profiles/default, the D7 themes, thescriptsdir and root*.txtremoved (satellite.sh.inc:3348-3354,:5764); registration closed; admin protected via a rawuserprotectseed (:6308-6327); permissions normalized to 0755/0644 with 0711 traverse-only parents. - Unprivileged, per-instance runtime. Each frontend runs and executes Drush as its own system user, and all of its PHP must stay parse- and runtime-safe on the PHP 5.6 floor that applies to the whole Aegir layer (see the topic chapter).
Maintainer contract
- New bundled module =
.infodependencies[]line + make-chain entry (hostmaster.makefor Aegir-tier,drupal-org.makefor contrib) + both_download_for_local_build()copies + the mirrormake_localartifact. For existing instances, add theencall to_satellite_child_b_aegir_ui_enhance()(and the Master path) — the.infomanifest only fires at INIT. hostmaster.installedits touch new installs only. Fleet-wide behaviour changes belong in the upgrade path or in the modules themselves, not in the profile installer.- Never hardcode a frontend path. Parse the alias file
(
hm.alias.drushrc.phpon the Master,hostmaster.alias.drushrc.phpon Satellites) or use theu/symlinks; generation numbers advance on every upgrade and zombie-recovery can skip numbers. - Block/theme coupling.
hostmaster_place_blocks()writes raw block rows against eldir's region names once; changing eldir regions or the default theme requires a matching block strategy. - Master/satellite duplication is deliberate. The build/staging logic
exists twice (
master.sh.inc/satellite.sh.inc); fix both copies, don't DRY them — see code style & conventions. - Transport awareness. The hostmaster repo, make files and helper scripts all ride the whole-release transport; there is no per-file serial for any of this — plan release timing per the serial & fetch pipeline.
Related
- Aegir backend APIs (topic chapter) — the task round-trip this frontend sits on top of.
- Staged setup engine (AegirSetup*)
— the scripts that stage
make_localand runhostmaster-install. - Hostmaster upgrade orchestrator
— the Master's
host_master/NNNlifecycle andhostmaster-migrate. - The serial & fetch pipeline — which transport a hostmaster change rides.
- Variables and
Commands —
_DL_MODE,_AEGIR_VERSION,_HM_DISTROand the wrapper verbs referenced above.