Questions#
The questions a network engineer asks before putting something on the path between their network and everything else. Several of the answers are unsatisfying.
Is this just VyOS with a skin on it?#
It is VyOS with an agent and a web interface on top. The kernel, nftables, FRR, Kea,
pdns-recursor, strongSwan, OpenVPN, Suricata and Podman are all upstream and
unmodified. What Wheelhouse adds is the
control-plane agent, the interface, the installer, the app catalogue and the packaging.
"A skin" would be a fair description of a product that hid the model underneath. This one
is built on it: every change is reviewed as a sentence before it is applied, applied as one
transaction and archived as a revision you can roll back to, and Advanced mode shows the
set lines behind each change and the whole configuration tree as commands.
Where the base ends and Wheelhouse begins.
Why VyOS, and not FreeBSD like everything else in this category?#
Two reasons, and one bill that comes with them.
The configuration model. VyOS has a transactional configuration tree: set builds a
candidate, compare shows the diff, commit applies it as one transaction,
commit-confirm puts it back if nobody confirms, and every commit is archived as a
numbered revision you can diff and return to. That is the product's whole thesis, and it
is not something a web interface can add to a system that does not have it. It had to be
underneath.
The kernel. nftables, tc and CAKE, in-kernel WireGuard, network namespaces, Podman
containers as configuration objects, FRR for BGP and OSPF, and a Debian base where the
agent is an ordinary .deb and the drivers are Linux drivers. A FreeBSD appliance is
structurally locked out of that list, which is a fact about kernels rather than a
criticism of anyone's engineering.
The bill. What that choice costs:
- No UPnP or NAT-PMP anywhere in the base, and no credible published miniupnpd image to fall back on. The agent answers both itself: each mapping is a port forward and a firewall rule, applied like any other change. It is off until an administrator turns it on, and it opens IPv4 ports only.
- No wildcard DNS in the configuration tree, no per-host DHCP option overrides in Kea, and a PXE boot file that cannot be conditioned on client architecture. dnsmasq is in the catalogue as the workaround.
- CAKE cannot attach to
ingress— that node takes a limiter and nothing else, so the QoS page shapes a CAKE download through an IFB device the agent chooses and reuses — and there is no DOCSIS or ATM overhead compensation anywhere in the tree. - Committing
nat static— one-to-one NAT — through this build's HTTP API has been seen to stop the API process, while the CLI accepts the same lines. So Wheelhouse does not write it: a one-to-one mapping is a destination and a source NAT rule that the agent plans and the API commits like any other, and the agent refusesnat staticat every staging and configure route. Seen 2026-09-02; not reproduced on 0.6.2, 2026-09-04. - The base is a rolling release, so node names move under you.
mac-addressbecomingmachas already cost a day. Images are built from a pinned source tree for that reason.
If those trades look wrong for your network, that is a real conclusion and this page would rather you reached it here than three weeks in.
Can I still use the CLI?#
Yes, and nothing objects. configure, set, compare, commit, commit-confirm,
rollback and show configuration commands all work exactly as they did. The agent
drives the router through VyOS' own documented HTTP API as a separate program; it stores
its state under /config/wheelhouse and touches nothing else in the tree.
A change you make from the console is read back by the interface like any other, because the interface has no private copy of the configuration — it reads the router. Where live state and configured intent disagree, the pages that can tell say so rather than smoothing it over. With Advanced mode on, the interface shows the commands behind every pending change, so the two can be checked against each other.
There are several things the interface cannot do where the console is the answer, and each page says which. Compared with the VyOS CLI.
Will it run on my hardware?#
There is no compatibility list.
- One machine's worth of evidence. The image installs to a disk and reboots into itself, and that has been done on one physical machine as well as in VMs. No other board, appliance or network card has ever run it.
- amd64 only. The build produces one image and it is amd64; UEFI and legacy BIOS both
boot. The arm64
.debexists for running the agent off-router against an arm64 router, and will not give you an image. - Secure Boot is untested. No signing key exists in the build, so assume you have to turn it off.
- Two network ports, two cores, 2 GB of RAM and 16 GB of disk is the floor; four cores, 4 GB and 32 GB is comfortable, more if you run containers. Those numbers are reasoned from what the software does — two images on disk after an upgrade, 64 MiB allocated per password check for Argon2id — and not measured on a bench.
- No CPU, memory or throughput figure has been measured on any hardware, in CI or out of it. The agent's budget of under 150 MB resident is a target.
Boot the live image on the box and look at ip -br link before you install anything. If
the ports are there, the drivers are there. Hardware.
Can I try it without touching my router?#
Three ways, in order of how much evidence stands behind them.
- Install it in a virtual machine. This is the path with the record: installs to disk
in a VM followed by a reboot into the installed system are verified for 0.4.5 by hand
and for 0.5.0 from a seed carrying a real router's 214-command configuration. There is
now a script for that run —
tools/install-smoke.sh, by hand on a libvirt host: install from a seed, take the medium away, boot the disk, and check that the machine which comes back is the one the seed asked for. It exercises the same installer, the same units and the same first boot as metal. One caveat, with dates on it: an unattended install did not work in 0.6.0, 0.6.1 or 0.6.2. The script the installer hands the router ended withexit 0, which VyOS' own script template redefines to something else, so a commit and a save that had both succeeded came back as a refusal — the live system took the seed's configuration and the disk was never written. It is fixed in the tree, with a test that runs the shipped script under those aliases. On 2026-09-03 a machine was installed unattended with the patched installer, from the 0.6.2 image, and that machine is the router every screenshot on this site was taken from. It is not fixed in any image you can download today. - Run the agent off-router, pointed at a VyOS router you already have. Everything that reads works; the few things that need the router's own filesystem say so. Suricata's alert log is the clearest example — off-router, the IDS page tells you it cannot read it.
wheelhouse-agent --demostarts with no router credentials, so the interface loads and the API answers with nothing behind them. Be clear about what that is: there is no fixture data, so every router read fails until you supply--api-urland--api-key. It shows you the shape of the product and it is the right way to attach a reproducible case to a bug report. It is not a demonstration of the product working.
How do upgrades work?#
Three different operations, and only the first is the customer path.
The whole system is VyOS' add system image: a second complete image installed
alongside the running one. Both stay on disk. Give the interface the URL of a release ISO,
wait for the download and install, and reboot when you choose — the running image does not
change until you do. If the new one misbehaves, set the old image as the default boot and
reboot, or pick it from the GRUB menu, which is the path that works when the new image
will not bring the network up at all.
/config is carried across, so your configuration, your accounts and password hashes,
your TOTP secrets, the unused recovery codes that go with them, your API tokens, the audit
log and its hash chain, the agent's TLS certificate, the VyOS API key and the numbered
revision archive all survive.
The agent and interface alone can be replaced with a new .deb on a running router
without a reboot. The off-router agent has its own installer script. Neither is the
supported customer path today.
What is the release cadence?#
There is no schedule.
One version number covers the whole product — agent, interface, installer, packaging and image are built and released from one tag. Versioning is semantic and the changelog follows Keep a Changelog, with security fixes called out in their own section. The first release in that changelog is 0.3.0, dated 2026-09-01, and the newest tag is 1.0.2. Read that as what it is: a project shipping quickly because it is new, not a cadence anyone has committed to.
There is no long-term-support branch, no published support window for an old version, and no advisory feed separate from the changelog.
The router now says when it is out of date. The download host publishes a
machine-readable channel index — stable.json, and beta.json for pre-release tags —
naming the newest version, its notes, its checksum file and whether the checksums are
signed. The agent reads it 45 seconds after it starts and once a day after that, checks it
against the SHA256SUMS published beside it, and the System page then says a newer version
exists and what changed in it. Three things it deliberately does not do: it installs
nothing, because add system image stays an action a person starts and confirms; it sends
nothing, not the licence key, not the fingerprint, not the host name, not even a version in
the user agent; and it does not treat the index as proof, because both files come from the
same host and releases are not signed yet. Turn it off on the System page and no request is
ever made. If you would rather watch from outside anyway, the index is a URL:
watching for releases.
What happens when the licence server is down?#
Nothing, for a long time, and then reads keep working.
A licence key is a signed statement — plan, features, router limit, expiry, grace period — that the agent verifies offline against a public key compiled into its binary. A router that has never reached the licence server and never will still knows what it holds. The refresh runs about 20 seconds after the agent starts, then once every 24 hours, and retries hourly after a failure. A failed refresh changes nothing: the error is recorded so the Licence page can show it, and the current token stays good until its expiry plus the grace period the key itself carries — seven days on the plans issued today, read out of the signed key rather than hardcoded.
So an outage at the licence server is invisible unless it lasts longer than your token's remaining life. If it does, the write plane closes and everything readable stays readable.
Two consequences. A revoked licence keeps working while
the server is unreachable, because revocation only arrives on a refresh. And a router
whose clock reads earlier than the licence was issued reports clock-unverified and
stays writable — closing the write plane there would lock set service ntp behind the
very fault you need to fix.
You can also switch the refresh off entirely with --license-server '', in which case no
request is ever made and the key runs to its own expiry. Privacy,
the licence gate.
What happens if I stop paying?#
The router keeps routing, and you keep seeing it.
A lapsed agent signs you in and shows every page, every counter, every log line, the configuration tree and the whole audit trail. What it refuses is the write plane: staging, commit, commit-confirm, discard, direct configure, rollback, save, load, reconcile, capture and the app-store actions. Each refusal is an HTTP 402 with a sentence naming the fix rather than a blank failure.
The administration plane is outside the gate as well: you can still manage accounts and API tokens, install a system image, reboot the box and paste in a new licence key with no licence at all.
A card that expires costs you the ability to change the router, not the ability to see it. Pricing.
What if I lock myself out?#
Three different accidents with three different answers. The one that used to end in a hand-edited state file no longer does.
You applied the change that cut you off. This is what auto-revert is for, and Apply with auto-revert is offered every time rather than only for a risky change. With a risky change pending the bar also says so: it recognises the changes that strand operators — firewall rules, NAT, an interface's own addresses, the default route, failover, load balancing and policy routing, router accounts, certificates, the SSH, HTTPS and API services, and anything on an interface the router is currently leaving through — marks them, opens the list with a sentence saying they could cut off your connection, and styles Apply changes in the danger colour. You can still press it. Let the window run out and the router restarts with its saved configuration; that is the configuration backend's own mechanism, so nothing in your browser or in the agent is holding it. How auto-revert works.
You lost the password or the phone. Enrolling a second factor issues ten single-use
recovery codes, shown exactly once. One of them signs you in at the login prompt in place
of a code from the app, and Account reissues the set on proof of a current code or one
of the remaining ones. If the codes went with the phone,
another administrator clears that account's second factor from Admin → Users;
that revokes the account's sessions, does not turn the two-factor requirement off, and
cannot be pointed at the administrator's own account. If nobody can sign in at all, the
console has wheelhouse-rescue, which resets a web UI password or clears a second factor
and writes what it did into the audit log. A break-glass token (--admin-token-file;
nothing creates one for you, so most installs have none) still authenticates as admin
against the API. Nothing here recovers a lost TOTP secret — it removes it, so the account
enrols again — and nothing here revokes API tokens.
You cannot reach the box at all. The console. An install creates a wheelhouse
account, and the base system's own vyos account is kept beside it with the same
password, because the base's login and sudo handling depend on it existing. It is your
recovery account, and whatever you do to one you should do to the other.
Does it phone home?#
Two things reach out, to two hosts, and only one of them says anything about you. Neither is exactly one request a day: both retry hourly when they fail, and the update check makes up to three requests when it finds something newer.
The licence refresh, once every 24 hours, carries four fields: the licence key, a
fingerprint of the installation, the router's host name and the agent version. The
fingerprint is 16 hexadecimal characters derived from /etc/machine-id by a one-way hash;
it exists so the plan's router limit can count. It is one flag to turn off, with the
consequence stated — a renewal will not reach the router on its own, and a revoked key
will not stop working.
The update check, once a day, is a plain GET of a static file on the download host,
and it sends nothing: no licence key, no fingerprint, no host name, not even a version in
the user agent. When that file names something newer it fetches two more static files, the
checksums and the release notes, so a router sitting on an available update makes three
requests a day rather than one; a router that cannot reach the host retries hourly. It is
what lets the System page say a newer release exists, and it installs nothing. One toggle
on that page stops it, and then no request is made.
There is no telemetry, no analytics, no crash reporting and no usage metrics. Nothing counts your rules, your interfaces, your clients or your traffic and sends the number anywhere. Either connection reveals what any HTTPS request reveals: your public address and the time. Privacy.
Is my configuration portable, or am I trapped?#
It is a VyOS configuration, which is the answer to both halves.
show configuration commands on the console prints the whole running configuration as
set lines. So does GET /api/config/commands through the API. Download config on
the System page saves the running configuration as <hostname>-config.boot. Every commit
is archived as a numbered revision under /config/archive, which is VyOS' own mechanism
and not something the agent invented.
Remove the agent and you have a VyOS router with your configuration on it. There is no proprietary configuration format, because the configuration model is the base's.
Coming the other way, wheelhouse-opnsense-import reads an OPNsense config.xml and writes
VyOS commands plus a report of what came across, what came across differently and what
could not; --check-against then compares a running router with the configuration it
should have. It is not one click — it writes commands and a report a person reads.
Migrating from OPNsense.
What if you disappear?#
Three parts, and the third one is bad.
The router does not stop. The agent is a self-hosted binary with no dependency on any server except to renew a licence, and a key verifies offline. If the licence server vanished tomorrow, a licensed router would keep accepting changes until its token expired plus its grace period, would keep showing you everything after that, and the console would keep working regardless.
The base is GPL and its source ships with every release. SOURCES-<version>-amd64.txt names
the exact vyos-build commit and every installed package, and the patch to that build
tooling is published beside it. Both files are also on the installed system under
/usr/share/doc/wheelhouse/, so a customer holding only the box can find them. You could
rebuild the operating system underneath.
The agent and the interface are proprietary, and there is no source escrow and no published continuity commitment. Neither has been decided on, and until one is, the honest position is that you would be left with a GPL router you can rebuild and a proprietary management plane you cannot. That is a real risk.
Is it open source?#
No. The agent and the interface are proprietary programs that drive GPL components as separate processes, over a documented API. The base is GPL and its corresponding source is published with every release. Neither half of that sentence should be softened in either direction. Dependency licences and the boundary.
What does it cost?#
Three plans, priced: Homelab for one router, Lab for three, Business for ten with commercial use. The same software on each, no support in any of them, and the image goes to subscribers rather than to a public download. Nothing is for sale yet, because neither the licence agreement nor the terms of service has been written. Pricing.
Can my team use it without sharing one password?#
Yes. Local accounts with Argon2id and TOTP, four roles enforced server-side on every route, API tokens that carry a role and an expiry and are stored only as a hash, and OIDC single sign-on with group-to-role mapping. Every change records who made it, with what role, from which address, and the commands it ran.
Two-factor has a way back: ten single-use recovery codes at enrolment, and an
administrator who can clear another account's factor. The audit log is tamper-evident from
the version that introduced the chain onwards — every entry written since then carries a
sequence number and the hash of the entry before it, and GET /api/audit/verify walks the
chain and names the first entry that does not fit. Entries written by an older agent have
no hash of their own; they are sealed as a block, counted, and reported as what they are.
A syslog collector can be given a copy of each entry as it is written.
The limits, in the same breath: no per-object permissions and no hardware-key second factor. The off-box copy is off until you configure a collector, and it is best-effort rather than a spooler — an entry the collector cannot take is dropped and counted, not queued to disk, and the default transport is UDP, which nothing acknowledges. Root on the router can still rewrite the file: a hash chain proves a break, it does not prevent one. So the chain tells you something was changed and the off-box copy is what might tell you what it said, when it was reachable. Accounts and access control.
Where do I report a bug or a vulnerability?#
A vulnerability goes through the disclosure process; a bug goes to support. Both need an address, and neither address is published yet. The forge is private, so there is no public issue tracker, no forum and no chat channel. That is a real gap, not an oversight in this page. Support.
What is the catch?#
That it is young, and that youth shows in specific places rather than in general.
The image has only ever run on one physical machine, so there is no compatibility list —
and no VM image and no arm64 image either. One add system image upgrade has been done
end to end, in a VM, and none on hardware. Releases are not signed. There is no alerting
and no device inventory. The uplink model and the neighbour table are IPv4 only. The
audit log can be copied off the box, but nothing copies it until you configure a collector.
The interface's tests render nearly every page, but in jsdom rather than a browser, and
five pages have none; the agent has over a thousand test functions. The prices are set; there are no
terms to buy under them yet, and no published support mailbox.
All of it is on one page: what is finished, and what is not.