VyOS burn-in period
Context: a pair of HA firewalls on VyOS, upgraded in place from 1.2.9 in early 2023 to the 2026.02 stream release. Never rebuilt from scratch. Hostnames and addresses below are genericized; versions, errors and commands are as they happened.
The trail
| Version | When | Note |
|---|---|---|
| 1.2.9 | 2023 start | where the pair came from |
| 1.4-rolling-202302150317 | 2023-02 | first rolling jump |
| 1.4-rolling-202305091511 | 2023-05 | self-baked image |
| 1.5-rolling-202405270829 | 2024-05 | config-error-on-boot bug below |
| 1.5-rolling-202505061352 | 2025-05 | container SNAT bug, own entry |
| 1.5-rolling-202509150723 | 2025-09 | |
| 2025.11 → 2026.02 | 2025–2026 | stream releases, minisign-verified |
Image management
add system image https://s3-us.vyos.io/rolling/current/vyos-rolling-latest.iso
set system image default-boot 1.5-rolling-202405270829
Two things the S3 mirror does: signature download 403s (...iso.minisig, ...iso.asc) — answer "yes" to continue, but verify stream ISOs yourself with minisign and the published key:
minisign -Vm vyos-2026.02-generic-amd64.iso -P RWTR1ty93Oyontk6caB9WqmiQC4fgeyd/ejgRxCRGd2MQej7nqebHneP
Signature and comment signature verified
Self-baked images
The Docker build flow is not repeated here; it lives in the Evergreen firewall page. The same flow built every image on this trail: the current stream, --build-type release for sagitta, and the equuleus branch with ./configure --version 1.3.2 when a customer-of-one needed a pinned release.
Bugs the trail hit
-
1.4 lost the default route on DHCP interfaces. Workaround:
set protocols static route 0.0.0.0/0 dhcp-interface eth0— or stop using DHCP on a firewall WAN. -
Installer offers no RAID1 for NVMe. Workaround: build the mirror by hand, metadata 1.0 at the end of the disk so the UEFI partition lives in front:
mdadm --create /dev/md0 --level=1 --raid-devices=2 --metadata=1.0 /dev/nvme0n1p2 /dev/nvme1n1p2 mdadm --detail --scan >> /etc/mdadm/mdadm.conf -
After the 1.5 upgrade:
WARNING: There was a config error on bootand a horrifying moment when/config/config.bootlooked empty. The migration errors are in/tmp/vyos-configd-script-stdout; the fix is to zero the status flag so configd proceeds:echo 0 > /tmp/vyos-config-status -
BFD config crashed on a source-address check — a genuine source bug in
/usr/libexec/vyos/conf_mode/protocols_bfd.py(len(peer_config['source']) < 2). Fixed it the VyOS way: fork, adjust, Phabricator task, commit with the task reference, pull request. The workflow costs an evening; do it — rolling releases only improve if the people running them in production report. -
A static route was in the config but not in the kernel. Delete the exact line, set the exact line again, commit. Mundane, but first check the kernel (
ip route) — not the config — when traffic takes a wrong turn. -
snmpd kept reporting pre-rename interface names. Restart snmpd after renaming interfaces.
Migration mechanics (2025.11 → 2026.02)
The upgrade keeps the pre-migration config; diff it, read the migrate log:
diff /config/config.boot.20260811-155514.pre-migration /config/config.boot
cat /config/vyos-migrate.log
Habits that paid off
-
Compare and count firewall rules between the pair before believing an upgrade:
run show configuration commands | grep -v eth0 | sort > fw-a # scp it over, then: diff fw-a fw-b -
BFD is downstream of OSPF: if OSPF is down, BFD is down — don't debug the wrong layer. A healthy peer shows
Status: up, sane timers; a broken one showsStatus: init,Diagnostics: neighbor signaled session down. -
iperf3, twenty parallel streams, one average number:
b=<src>;s=<dst>; for i in {1..20};do iperf3 -t 30 -T t${i} -c $s -B $b -p 510${i} & done \ | awk '/sender/ {sum+=$8; cnt+=1} END {print sum/cnt}' -
sflow-rt for flow visibility (in docker, on a hypervisor): install, pull the browse-flows / prometheus / particle apps, then export flows in Prometheus format:
curl "http://<sflow-rt>/app/prometheus/scripts/export.js/flows/ALL/txt?metric=sflow_flows_bps&key=ipsource,ipdestination,vlan,agent,tcpsourceport,tcpdestinationport&label=src,dst,vlan,agent,sport,dport&value=bytes&scale=8&maxFlows=100"
This saved you a night? I do this for a living: info@wirt.ee.