Automated codename upgrades
Moving a BOA host between Devuan codenames (beowulf → chimaera → daedalus → excalibur) is driven by a family of auto* codename scripts in
/usr/local/bin/, triggered by a run-to-*.cnf marker and launched by the
clean-boa-env service.
Each script runs a chain of barracuda up-<tier> system passes and reboots,
advancing the OS one codename per pass until it reaches its named target.
This is the path to prefer for the supported targets; the explicit per-hop alternative is the classic major OS upgrade.
Backup, test the backup, then proceed. This is an unattended migration chain across multiple reboots. If it wedges mid-chain there is no in-place rescue — recovery is "restore the VM snapshot." Do not start without a tested backup. The provider boot caveats below are why Step 1 is non-negotiable.
The four codename drivers
| Target codename | Driver script | Trigger marker |
|---|---|---|
| Daedalus (recommended) | autodaedalus |
/root/.run-to-daedalus.cnf |
| Excalibur (latest) | autoexcalibur |
/root/.run-to-excalibur.cnf |
| Chimaera (deprecated, hop only) | autochimaera |
/root/.run-to-chimaera.cnf |
| Beowulf (deprecated, hop only) | autobeowulf |
/root/.run-to-beowulf.cnf |
Chimaera and Beowulf are deprecated: they are not tested in any context and exist here only as intermediate hops for a host still climbing to Daedalus.
All four share one template; they differ only in the named target and the
intermediate hops they walk through. Each driver carries the full
_${FROM}_TO_${TO}=YES pairing set for every codename below its target, so a
single trigger walks the whole chain.
autoexcalibur, for example, carries:
_BULLSEYE_TO_CHIMAERA_BEOWULF_TO_CHIMAERA_BOOKWORM_TO_DAEDALUS_CHIMAERA_TO_DAEDALUS_TRIXIE_TO_EXCALIBUR_DAEDALUS_TO_EXCALIBUR
Which target
- Daedalus is the recommended production target. Stable, well-tested, supports Percona 5.7, 8.0 and 8.4.
- Excalibur is the latest. Supported, but only with Percona 8.4 — there
is no 5.7 or 8.0 path on Excalibur. Stage the DB to 8.4 on Daedalus first
(see Percona sequencing below);
autoexcaliburenforces this with a hard pre-flight gate. - Chimaera is supported as a stepping stone; upgrade off it to Daedalus.
- Beowulf is a rescue target, not a destination: use it to get a very old Debian box onto Devuan, then chain forward to Daedalus.
Running the chain
The procedure is identical for all four targets — only the trigger marker changes.
Step 1 — Snapshot and verify the snapshot
Take a fresh VM snapshot, restore it to a throwaway VM, and confirm the restored VM boots and the BOA host works. Do not proceed until the backup is proven.
Step 2 — Pre-flight barracuda pass and clean reboot
A clean baseline first, so nothing is half-applied going in:
screen
barracuda up-lts system
boa reboot
If that reboot is not clean — boot fails, services don't come up, network is unreachable — fix it before triggering the chain. A major-OS chain on a host that already has boot problems guarantees a bad outcome.
Step 3 — Refresh the meta-installers
wget -qO- https://files.boa.io/BOA.sh.txt | bash
This installs the current auto* codename drivers and barracuda/octopus
shims into /usr/local/bin.
Step 4 — Drop exactly one trigger marker and launch
# Recommended production target
touch /root/.run-to-daedalus.cnf
# Or: latest (Excalibur — Percona 8.4 only, see below)
touch /root/.run-to-excalibur.cnf
# Or: intermediate stops
touch /root/.run-to-chimaera.cnf
touch /root/.run-to-beowulf.cnf
Then launch:
service clean-boa-env start
The driver walks barracuda up-<tier> system + reboot for each intermediate
codename until it reaches the target. The tier is the host's own (_tRee), not a
fixed lts — each driver runs barracuda up-${_tRee} system, so an LTS host
chains with up-lts, a PRO host with up-pro.
(_tRee is baked per release branch: the LTS-branch driver pins export _tRee=lts, the PRO-branch driver pro, the dev-branch driver dev; the host
fetches the copy matching its tier.)
Step 5 — Wait it out
A two-codename jump (e.g. Chimaera → Daedalus) is typically 30–60 minutes; a Debian-Buster → Devuan-Daedalus chain through several codenames can take 2–3 hours. The host reboots multiple times. Do not intervene unless a reboot fails to come back.
If the chain stops. Each driver expects every barracuda up-<tree> system
pass to leave its finale marker behind. A pass that ends without it (a mirror
that stopped answering, a resolver not yet up after a reboot) is retried once
after 60 seconds; when the second attempt ends the same way the driver stops
and writes two ERROR: lines into its log (/root/.auto<codename>.log)
naming the pass and the newest log under /var/backups/reports/up/barracuda/.
Fix the cause, then run the driver again, or reboot: the
/root/.run-to-<codename>.cnf trigger is still in place and clean-boa-env
relaunches the driver at boot. It starts over from the codename the box is on.
Step 6 — Verify
# Confirm the Devuan codename
lsb_release -ar 2>/dev/null
# Confirm BOA is back and on the expected DB series
boa info | grep -i db
mysql -e "SELECT VERSION();"
boa info | grep -c Percona returns 3 or more once the post-upgrade chain has
fully completed, including the cron-triggered background phase — a quick
confirmation that the DB layer has settled. A server that has been through
several upgrades reports 5, which is the cap, not an error. You can also check
the codename with lsb_release and the DB series with SELECT VERSION().
Starting from Debian
autoinit/automini carry the Debian→Devuan codename map and advance one step
per pass, with one mandatory consequence to know up front: the per-source-OS
target is not universally Daedalus.
| Starting OS | First Devuan hop |
|---|---|
| Debian Trixie (13) | Excalibur (touches /root/.top-excalibur.cnf) |
| Debian Bookworm (12) | Daedalus |
| Debian Bullseye (11) | Chimaera |
| Debian Buster (10) | Beowulf |
| Devuan Chimaera | Daedalus |
| Devuan Beowulf | Chimaera |
| Devuan Daedalus / Excalibur | (terminal — no further hop) |
A Trixie box therefore lands on Excalibur, not Daedalus, and so inherits the Excalibur Percona-8.4 requirement. Older Debian releases that cannot reach Daedalus in one hop walk an intermediate codename first; chain to the next target after the first chain completes and the host is stable.
Percona sequencing across the chain
The DB series the host carries constrains which OS targets are reachable:
- Daedalus defaults to Percona 5.7. You can stage forward in place:
barracuda up-lts system percona-8.0(5.7 → 8.0), thenbarracuda up-lts system percona-8.4(8.0 → 8.4). There is no direct5.7 → 8.4jump. - Excalibur requires Percona 8.4.
autoexcaliburruns_check_mysql_compatibilityup front and refuses to proceed (exit 1) on anything but 8.4, telling you exactly what to run first:- on Percona 8.0 —
barracuda up-lts system percona-8.4once; - on Percona 5.7 —
barracuda up-lts system percona-8.4twice (5.7 → 8.0, then 8.0 → 8.4).
- on Percona 8.0 —
Before the first Percona step, gate on readiness: the DB server is shared by
every account on the host, so its oldest codebase decides whether the box
can move — run codebasecheck --box --deep and read its verdicts first; an
account that cannot run on Percona 8 must move to a legacy 5.7 host before
the box upgrades (Percona 8 readiness).
The full staged-upgrade mechanics, recovery guards and the client-library soname ladder are in Percona install + tuning.
What the Daedalus/Excalibur path also changes
Beyond the Percona requirement, reaching the modern codenames applies:
- ICU bumped to 76.1. On excalibur/daedalus (and trixie/bookworm) the ICU
resolver targets
_ICU_NEWER_VRN=76-1. PHP 8.1+ buildsintlagainst any ICU and is rebuilt against 76 automatically. PHP below 8.1 is the catch: PHP 7.4 and 8.0 cannot buildintlagainst ICU 76+ (only against ICU ≤ 73), so theirintlmust stay on an older ICU, pinned with_ICU_FORCE_VRNin/root/.barracuda.cnf. In practice 7.4 is the one that matters — it is the version still hosting legacy Drupal 7 sites that needintl. Where weekly auto-updates are enabled the SELFUPGRADE weekly run self-heals 7.4intlafter a system ICU bump; without auto-updates the pin is the operator's responsibility. The_ICU_FORCE_VRN/_ICU_NEWER_VRNvariables are catalogued in barracuda.cnf reference. resolvconfpurged. No longer needed on these releases; BOA writes/etc/resolv.confdirectly./root/.top-daedalus.cnfretired on the Excalibur hop. On either hop into Excalibur (_TRIXIE_TO_EXCALIBURor_DAEDALUS_TO_EXCALIBUR) the old Daedalus marker is renamed to/root/.old-top-daedalus.cnfand a.top-excalibur.cnfmarker is created.- Brief, self-correcting PHP downtime. Because BOA's own PHP builds link against system libraries, a big codename jump (notably Daedalus to Excalibur) that bumps a system library's soname leaves the running PHP binaries linked against libraries that no longer exist. BOA detects this and rebuilds every active PHP version automatically — no operator action is required. Each version is offline only while its own rebuild runs: seconds when the prebuilt package path applies, or roughly 3 to 5 minutes when it compiles from sources.
Not every hop pays this PHP cost. BOA tags the same-generation Debian-to-Devuan
sidegrades — Debian Buster → Beowulf, Bullseye → Chimaera and Bookworm →
Daedalus — as small hops (/root/.small_hop_on_major_os_upgrade.info), and
every other jump as a big hop (/root/.big_hop_on_major_os_upgrade.info). The
full per-version PHP rebuild above runs only on big hops, so a small hop
does not reinstall and rebuild every installed PHP version, and the brief downtime
just described does not apply to it. The test is the source OS, not the
target — Debian Bookworm → Daedalus is a small hop even though it lands on
Daedalus, while a Devuan Chimaera → Daedalus or Daedalus → Excalibur advance (and
Debian Trixie → Excalibur) is a big hop that does rebuild.
cloud-init on the upgraded host
Every driver run begins by looking for cloud-init: the /etc/init.d/cloud-*
scripts, /etc/cloud/cloud.cfg.d, and on Linode/Akamai hosts the vendor's
akamai-linux-team.list source and 99linode-cloudinit apt preference. When
any of it is present, the driver removes cloud-init the way autoinit does on
a fresh conversion: the cloud-utils, cloud-init and cloud-image-utils
packages are purged, the sysvinit rc links and the exec bits of the init
scripts are stripped (the /etc/cloud/cloud-init.disabled kill-switch is a
systemd-generator mechanism and does nothing under sysvinit), and /etc/cloud
plus the two vendor apt files are parked in /var/backups. The reasons are
the same as on a fresh box: a live cloud-init slows every reboot of the chain,
and its per-instance modules re-run on every snapshot restore (the instance id
changes) with the stock disable_root/lock_passwd settings, locking the
root account while the key on disk is correct.
The removal is gated exactly as on a fresh conversion. It happens only when
classic networking is provably self-sufficient — the default-route interface
exists, it carries an iface … inet dhcp or inet static stanza in
/etc/network/interfaces or interfaces.d/, and /etc/resolv.conf names a
nameserver. Providers that hardwire boot networking to cloud-init fail that
probe and keep it, with cloud-init KEPT: classic networking not provably self-sufficient in the driver log (/root/.auto<codename>.log).
/root/.mode.selected.full.cnf removes it unconditionally, and
/root/.preserve.cloud.init.cnf keeps it regardless; both markers are
described on the
Debian to Devuan page. Amazon
EC2 hosts skip the block, as they are refused by the drivers anyway.
Archived releases and package mirrors
Each hop writes a fresh /etc/apt/sources.list for the target codename, and
the mirror in it is chosen against what actually serves that suite at that
moment. A release that has left support disappears from the live mirrors:
Debian moves it to archive.debian.org once its LTS ends (Buster is there;
Bullseye's LTS ended on 2026-08-31 and its move is under way), and Devuan moves
the counterpart to archive.devuan.org (Beowulf is there; Chimaera, Bullseye's
counterpart, will follow). A dead line in sources.list is not a stalled hop
but a box left mid-conversion with unusable APT, so BOA probes each suite's
Release file before writing:
- Devuan suites: the fast or configured mirror is probed; if it has dropped
the suite the other live mirrors are tried, then the archive. The archive
serves
<suite>-securitybut no-updates, so that stanza is written only when a live mirror was chosen. The chosen mirror's pool host is probed as well, because a mirror can serve its release files while the host its packages come from has an expired certificate — the shape that once stalled a migration's xtrabackup install. - Debian suites: the release pool and the security pool are resolved
separately —
deb.debian.org(or the configured local mirror) thenarchive.debian.orgfor the release,security.debian.orgthen the archive's security pool for<suite>-security. A security suite no host serves any more is left out of the file rather than written dead. Jessie, Stretch and Buster keep their long-archived shape (<suite>/updateson the archive). - A host with neither
curlnorwgetavailable at that moment keeps the preferred mirror, as before.
The same resolution runs whenever barracuda up-<tier> system rewrites the
sources.list of the codename the host is already on, so a host that sits on
a release while it is being archived keeps a working APT on its next upgrade.
Nothing needs editing when the next release is archived: the known-archived
lists in lib/functions/system.sh.inc only save the probe.
Chimaera's security suite, as of 2026-09-05. Devuan's merged
chimaera-security hands the Debian-built packages to
deb.debian.org/debian-security, which stopped serving the bullseye-security
pool when Debian 11 left LTS on 2026-08-31, before archive.debian.org picked
the suite up. Until it does, APT on a Chimaera box fails on every package whose
newest version sits in that suite, a fresh BOA install on Chimaera included, and
an apt-get dist-upgrade that meets those 404s aborts as a whole. A hop that
runs into it (Beowulf to Chimaera, or the pass on a Chimaera box before its move
to Daedalus) drops the dead -security stanza from sources.list, refreshes APT
and runs the upgrade again, logging NOTE: the chimaera-security pool is not served any more; the upgrade continues without it (in autoinit, a WARN line
ending in running apt-get dist-upgrade without it). Without that step the hop
upgraded nothing while the codename moved on, and the next hop jumped two
releases at once.
Provider boot caveats
Some providers (notably Linode/Akamai) have unreliable system-driven reboots.
The Lassie watchdog sometimes fails to remount the filesystem after a snapshot
restore, and an in-VM shutdown -r now does not always wake the VM.
Symptom: SSH stops responding mid-chain while the vendor panel shows the VM "running" but boot hung. Recovery: vendor-panel Power Off → Power On (sometimes several attempts), or restore the Step 1 snapshot. This is the failure mode that makes a tested snapshot mandatory.
Post-chain PHP-version cleanup
The chain deactivates every installed-but-unused PHP version (it applies
/root/.allow-php-multi-install-cleanup.cnf semantics automatically). Re-install
what you need afterwards:
barracuda php-idle enable # re-install previously-disabled versions
barracuda php-idle disable # disable unused again later
The per-site PHP-version mechanics are in PHP-FPM performance.
Related
- Classic major OS upgrade — the explicit
_${FROM}_TO_${TO}=YESpath with finer per-hop control. - Manual BOA upgrade reference — the
barracuda up-*/octopus up-*matrix the chain calls under the hood. - Percona install + tuning — the
staged
5.7 → 8.0 → 8.4upgrade and its recovery guards. - Reference appendix — consolidated
_VARtable (_ICU_FORCE_VRN,_ICU_NEWER_VRN). - Discontinued features — dropped codename targets and retired markers.