Skip to content

Powered by Grav

Automated codename upgrades

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); autoexcalibur enforces 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:

SH
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

SH
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

SH
# 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:

SH
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

SH
# 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), then barracuda up-lts system percona-8.4 (8.0 → 8.4). There is no direct 5.7 → 8.4 jump.
  • Excalibur requires Percona 8.4. autoexcalibur runs _check_mysql_compatibility up front and refuses to proceed (exit 1) on anything but 8.4, telling you exactly what to run first:
    • on Percona 8.0barracuda up-lts system percona-8.4 once;
    • on Percona 5.7barracuda up-lts system percona-8.4 twice (5.7 → 8.0, then 8.0 → 8.4).

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+ builds intl against any ICU and is rebuilt against 76 automatically. PHP below 8.1 is the catch: PHP 7.4 and 8.0 cannot build intl against ICU 76+ (only against ICU ≤ 73), so their intl must stay on an older ICU, pinned with _ICU_FORCE_VRN in /root/.barracuda.cnf. In practice 7.4 is the one that matters — it is the version still hosting legacy Drupal 7 sites that need intl. Where weekly auto-updates are enabled the SELFUPGRADE weekly run self-heals 7.4 intl after a system ICU bump; without auto-updates the pin is the operator's responsibility. The _ICU_FORCE_VRN / _ICU_NEWER_VRN variables are catalogued in barracuda.cnf reference.
  • resolvconf purged. No longer needed on these releases; BOA writes /etc/resolv.conf directly.
  • /root/.top-daedalus.cnf retired on the Excalibur hop. On either hop into Excalibur (_TRIXIE_TO_EXCALIBUR or _DAEDALUS_TO_EXCALIBUR) the old Daedalus marker is renamed to /root/.old-top-daedalus.cnf and a .top-excalibur.cnf marker 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>-security but 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) then archive.debian.org for the release, security.debian.org then 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>/updates on the archive).
  • A host with neither curl nor wget available 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:

SH
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.

© 2026 BOA Documentation. All rights reserved.