The ISO#
wheelhouse-<version>-amd64.iso is the base platform built from source with the
Wheelhouse package baked in, its identity replaced, and its
corresponding-source record written beside it. The build is
packaging/iso/build-iso.sh: it clones vyos-build,
renders an image flavor, stages a branding overlay, drops the .deb into
vyos-build/packages/ — live-build installs every package found there — and runs the
upstream builder inside the upstream build container.
It takes 30 to 60 minutes and needs a privileged container, because live-build mounts filesystems.
DEB=dist/wheelhouse-agent_1.2.3_amd64.deb VERSION=1.2.3 bash packaging/iso/build-iso.shWhat it produces#
Everything lands in $BUILD_DIR/out, and the release workflow publishes all of it
together:
| File | What |
|---|---|
wheelhouse-<version>-amd64.iso | The image. |
wheelhouse-<version>-amd64.iso.sha256 | Its checksum. |
wheelhouse-<version>-build-source.tar.gz | The complete source of the GPL build tooling this image was built with, with the Wheelhouse changes already applied. |
vyos-build-wheelhouse-<version>.patch | Those changes, as a readable diff. |
SOURCES-<version>.txt | The vyos-build commit, the build container's digest, and every installed package with its exact version. |
The last three are the corresponding-source record. Compliance is GPLv2 §3(a) — the source is published beside the binary. There is no §3(b) written offer, so nothing that ships may promise one, and the branding hook fails the build if the wording creeps back in.
Environment#
| Variable | Default | Meaning |
|---|---|---|
DEB | (required) | The agent package to bake in. |
VERSION | dev | The image version string. |
BUILD_DIR | /srv/wheelhouse-build | Where the checkout and the output go. Must be a host path, because docker -v needs one even when this script itself runs inside a job container. |
VYOS_COMMIT | the pin in the script | The vyos-build commit to build from. head follows the branch instead, prints a warning, and must not be shipped. |
VYOS_BRANCH | rolling | The branch and the container tag. Upstream renamed current to rolling in 2026. |
VYOS_BUILD_REPO | upstream's GitHub repository | Where the checkout comes from. |
VYOS_BUILD_IMAGE | vyos/vyos-build:$VYOS_BRANCH | The build container. |
BUILD_BY | a string in the script | The builder identity recorded in the image. |
The base is pinned to a commit, in the source tree rather than in CI, so the base is a property of the tree. There is no tag to pin to: the newest tag upstream belongs to a branch marked unmaintained, and the maintained rolling branch has no tags at all.
The flavor#
packaging/iso/wheelhouse.toml is a template —
@VERSION@ and @VYOS_BASE@ are substituted, and the build fails if any @…@
marker survives. It declares two things.
default_config#
The configuration the image boots with when there is no config.boot yet: a live boot,
and the first boot after an install. It is upstream's own default with three changes,
kept otherwise verbatim so the syntax stays upstream's:
| Change | Why |
|---|---|
host-name wheelhouse | This is the live login prompt, the banner's header, the DHCP client identity the upstream router logs, and the common name of the certificate the agent generates on first boot. |
NTP off pool.ntp.org | A router we sold should not ask the upstream project for the time forever, and a customer should not see an upstream host on the System page. |
| A login banner of our own | Without banner post-login, upstream renders its own template into /etc/motd: a welcome line, a logo and a support portal, on the console and — through pam_motd — over SSH. Setting the node replaces that template wholesale. The upstream credit stays, one line, at the bottom. |
\n in a banner value becomes a real newline, so agetty's own escapes cannot be used
there.
/etc/os-release#
An [[includes_chroot]] entry, and it is deliberately the only place that file is
owned. See Identifying the system.
The branding overlay#
Three things are staged into the checkout: the splash image, two live-build hooks, and the licence documents.
The splash#
It replaces both copies of upstream's own. That artwork is copyrighted by its author with all rights reserved, and their licence permits redistributing a self-built image only if the artwork is replaced — so this is a licence condition, not a preference. Both copies ship because the ISOLINUX one is what both bootloaders draw, and live-build copies the GRUB directory regardless.
50-wheelhouse-brand.chroot#
Runs inside the chroot, after every include is in place. It asserts rather than assumes, and any failure fails the build:
| Check | Why |
|---|---|
The four documents exist under /usr/share/doc/wheelhouse | They are the licence and source answer a customer gets. |
None of them contains <TODO | An unfilled placeholder in one of these is a compliance defect, not a typo. |
SOURCE-OFFER.txt does not read like a §3(b) written offer | A written offer needs a real address behind it for three years, and there is none. |
/etc/os-release says ID=wheelhouse | If the flavor's override ever stops winning, the image would silently report itself as the base to hostnamectl, monitoring agents and Ansible facts. |
It also does three things:
- Replaces
/usr/share/vyos/EULAwith a symlink to../doc/wheelhouse/TERMS.txt. Upstream's release build type installs a commercial end-user licence agreement there that no flavor entry can outrank, and nothing in the GPL requires shipping another company's commercial terms. Replaced rather than deleted, because the operational CLI'sshow licensepages that exact path — and now it shows the Wheelhouse terms, which is what it should have shown all along. - Round-trips
/etc/os-releaseinto/usr/lib/os-release, because Debian normally makes the former a symlink to the latter and the include may have left the two disagreeing. - Removes upstream's Secure Boot MOK certificate from
/var/lib/shim-signed/mok. It is a public certificate, not a key, and it is not enrolled in firmware, so this is hygiene rather than a hole — but it is a leftover, not a required notice.
50-wheelhouse-brand.binary#
Runs against the built image directory, and is what labels the boot menu entries.
The upstream patches#
Three literal strings in upstream's build script cannot be reached by any flavor key, so the build patches them — and verifies both that the literal was there and that it is gone afterwards, failing loudly if upstream has moved on:
| Patched | To | Why |
|---|---|---|
--iso-application "VyOS" | "Wheelhouse" | A Wheelhouse stick otherwise mounts under the base's name. |
--iso-volume "VyOS" | "WHEELHOUSE" | And blkid -L otherwise sees the base's name. Uppercase because ISO 9660 wants it that way. |
hostname=vyos username=live | hostname=wheelhouse quiet username=live | The live kernel command line sets the host name before any configuration is loaded, so the first console prompt otherwise names the base. quiet stops fourteen upstream unit descriptions printing between the splash and the banner. |
quiet raises the console log level to KERN_ERR and tells systemd not to print unit
status. Panics, oopses and units that actually fail still reach the screen, so a
broken boot still says so. There are two escape hatches, and the build protects the
first: the fail-safe menu entry boots without quiet, and the build fails if upstream
ever adds quiet to that line. Failing that, both bootloaders let an operator edit the
command line before booting — Tab in ISOLINUX, e in GRUB.
Because upstream's builder is GPL-2, those changes are published: the diff is written to
out/vyos-build-wheelhouse-<version>.patch and named in SOURCES.
What ships in /usr/share/doc/wheelhouse/#
| File | What |
|---|---|
TERMS.txt | The product's terms. Also what /usr/share/vyos/EULA resolves to. |
THIRD-PARTY.txt | Third-party notices. |
SOURCE-OFFER.txt | Where the corresponding source is published. |
SOURCES.txt | The base commit, the container, and every installed package with its version. Written into the chroot before the build, so this copy points at dpkg for the package list; the copy beside the ISO carries the list itself. |
What has actually been booted#
The live image has been booted in a virtual machine and on physical hardware. A
complete install to disk followed by a reboot into the installed system is
not recorded on hardware; every end-to-end verification names a virtual machine. An
add system image upgrade of a Wheelhouse box is not recorded at all.
There is no compatibility list, and this documentation will not invent one. The image's
driver packages can be listed from SOURCES-<version>.txt; that is not a compatibility
claim.
amd64 UEFI only#
There is no arm64 image and no virtual-machine image — no qcow2, no OVA. The arm64
.deb exists for running the agent off-router against an arm64 router.
See also#
- The
.deb— what gets baked in. - Identifying the system — what a built image calls itself.
- Channel index format — where the artefacts are published.
- What first boot does — what happens the first time it boots.
- About Wheelhouse — the licence boundary and the attribution.
- The image and the image flavor
- Built on VyOS and the source offer
- Upgrade the image
Checked against#
packaging/iso/build-iso.sh,
packaging/iso/wheelhouse.toml,
packaging/iso/branding/50-wheelhouse-brand.chroot,
packaging/iso/branding/50-wheelhouse-brand.binary,
packaging/iso/branding/doc/TERMS.txt,
packaging/iso/branding/doc/SOURCE-OFFER.txt,
packaging/iso/branding/doc/THIRD-PARTY.txt,
.forgejo/workflows/iso.yml,
docs/hardware.md,
packaging/README.md.