Skip to content

Powered by Grav

Prebuilt package builder

Prebuilt package builder

The heavy stack components — Modern and Legacy OpenSSL, ICU, cURL, Valkey, Nginx, Unbound, Pure-FTPd (where the FTP xtra is selected), and every selected PHP version — reach the fleet as prebuilt .deb packages, so a box installs them in seconds instead of recompiling each from source. The self-hosting Prebuilt stack packages page covers that from the consuming box's side: the _USE_PREBUILT_PKGS switch, the automatic per-component fallback to a source build, and reading the report log. This page is the producer side — how those packages are actually built and published.

Packages are produced by stackbuild (aegir/tools/bin/stackbuild) on dedicated builder-mirror VMs, one per supported release. The load-bearing property is that the builder re-implements no build logic: it runs after a real barracuda up-<tree> on a real BOA box of the target release, and only snapshots, packages, and publishes what the unmodified installer already built. The _*_VRN version pins in BARRACUDA.sh.txt stay the single source of truthstackbuild never sets a version, it detects each installed version from the tree on disk, so a pin bump is packaged on the next run with no edit to the builder. And because a package can only exist once the real upgrade succeeded on a real box of that release, the builder doubles as a standing upgrade canary ahead of the fleet.

Builder-box invariants

A builder is an ordinary BOA box of its release, pinned into three states:

  • _USE_PREBUILT_PKGS=NO, set explicitly and permanently in /root/.barracuda.cnf. A builder must always compile from source — if it installed its own packages it would repackage them in a circle. stackbuild enforces this and refuses to run the moment it finds _USE_PREBUILT_PKGS=YES.
  • The full PHP matrix (php-max), every build-shape toggle at shipped defaults. An empty _PHP_EXTRA_CONF and no _ICU_FORCE_VRN pin, so the packages carry the default build shape — the only shape a consuming box is ever offered a package for. php-max guarantees every PHP version is present on disk to snapshot.
  • _XTRAS_LIST carries FTP. Pure-FTPd is the only packaged component gated on an xtra rather than installed unconditionally, and stackbuild only packages what the real upgrade actually installed — so a builder without the FTP xtra never publishes boa-pure-ftpd, and every box then source-builds Pure-FTPd for as long as no package exists. That is the ordinary per-component fallback rather than an error, which is exactly why the omission is silent. Unlike _USE_PREBUILT_PKGS, this invariant is not enforced — nothing refuses to run. Hosted boxes (those carrying /root/.host8.cnf, or whose hostname ends .aegir.cc) add the token themselves: seeded into the generated cnf on a PUBLIC easy-setup install, and re-added in memory on every upgrade run, so an existing hosted builder converges even when its cnf does not yet list FTP. On any other builder, set it explicitly.

The daily cycle

Each builder runs one cron line: barracuda up-<tree> then stackbuild all. Both are cheap no-ops when nothing changed. When a pin bump lands, the next upgrade compiles the new version from source on the builder, and the following stackbuild all packages and publishes it — so any pin bump is packaged within about 24 hours. Boxes that upgrade inside that window find no package for the new version yet and fall back to a source build by design: this is just the normal per-component fallback, not an error.

A pin bump can also invalidate packages whose own versions did not change: an OpenSSL bump makes the real upgrade rebuild PHP and Nginx on the builder (their own probes force it), while their published filenames stay the same. stackbuild treats a published package as stale when the installed tree was rebuilt after the package was published — the component's probe binary is newer than the published file — and stackbuild all repackages and republishes it under the same filename. No dependency map is re-implemented in the tool: it trusts the real upgrade's own rebuild decisions, which is also why components the upgrade does not rebuild on such a bump (the dynamically linked Unbound and cURL simply follow the upgraded library in place) correctly keep their published packages.

stackbuild verbs

All verbs require root and re-assert the builder invariant first. package, publish, all, and force take a lock (/run/stackbuild.lock) and refuse to run concurrently.

Verb Action
check Report installed versions against published packages, flagging stale ones
package Build the missing or stale (or explicitly named) packages
publish gzip each built package plus a sha256 sidecar into the mirror /dev/ tree
sync Cross-sync fresh packages to the peer active mirror
all package the missing and stale set, then publish, then sync
force Rebuild the named (default: every installed) components regardless of published state, then publish and sync

Naming and integrity

Every package is published as a compressed .deb with a checksum sidecar:

TXT
boa-<component>_<version>.<codename>_amd64.deb.gz
boa-<component>_<version>.<codename>_amd64.deb.gz.sha256

The installer constructs each filename from its own version pins (_install_boa_deb in lib/functions/helper.sh.inc), fetches the sidecar first as a cheap published-or-not probe, and verifies the checksum before unpacking anything. The sidecar hashes the compressed file, so verification happens before gunzip. Because the filename carries the exact version, a mirror safely holds many versions side by side, and publish never deletes an older package — slower trees and older pins keep resolving to their exact filename.

Dependency policy

Each package's Depends: carries distro libraries only, resolved on the builder for its exact release (dpkg-shlibdeps over the staged ELF objects, so per-release sonames come out right by construction). The BOA-to-BOA ordering — PHP needs the BOA OpenSSL, ICU, and cURL trees present first — is enforced by the installer itself, not by dpkg. A published package deliberately carries no inter-BOA Depends:, so a box whose companion component fell back to a source build (correct tree on disk, no dpkg record) keeps working, and the installer's apt-get -f install pass never drags a companion back to source.

Adding a builder mirror for a new release

To bring up the next release's builder — for example Excalibur alongside Daedalus:

  1. Create and install the VM on the target release the normal way, e.g. boa in-lts public <fqdn> <email> o1. On a Debian base the installer converts it to Devuan via the matching auto* tool automatically.
  2. Set the builder invariants: _USE_PREBUILT_PKGS=NO explicitly in /root/.barracuda.cnf, select php-max so all PHP versions build, and make sure _XTRAS_LIST carries FTP so the xtra-gated boa-pure-ftpd is built too.
  3. Create /root/.stackbuild.cnf — an empty file is enough. Its presence is what marks a build box: _update_agents deploys stackbuild (and staticbuild, the test-codebase builder) to /opt/local/bin/ only on boxes carrying it, refreshed by the serial-gated fetch on every barracuda run. stackbuild auto-detects _PUB_DIR from the existing prebuilt packages under /var/www; on a fresh mirror where that detection does not apply yet, set _PUB_DIR in the cnf — never by editing the script, which the fetch resets.
  4. Set _PEER_MIRROR in /root/.stackbuild.cnf on BOTH active builders so each pushes its release's fresh packages to the other — both then hold the complete package tree. Passive mirrors keep syncing from the authoritative Daedalus mirror exactly as before.
  5. Add the daily cron: barracuda up-<tree> then stackbuild all.
  6. Flip the shipped default last. Only after the new release's package set is published and propagated does the shipped default for that release flip to YES in a BOA update — never before the packages exist.

Reference

  • Commands — the consolidated CLI index, including stackbuild and its verbs.
  • Variables_USE_PREBUILT_PKGS and the rest of the _VAR catalogue.
  • Build & test — the other "prebuilt" path a box fetches: the Ægir make_local.tar.gz bundle and the versioned Drush 8 tarball, distinct from these stack .deb packages.

© 2026 BOA Documentation. All rights reserved.