VyOSVI · Commit and Rollback SafetySafe changes
commit semantics — what the commit engine actually does
What you'll learn
- Walk a commit from candidate to running and name what runs at each step
- Distinguish a set-time constraint failure, a verify() failure, and a backend rejection
- Use show system commit and its diff to find what a change actually did
- Recognise the commit failure modes that leave a router partly configured
Prerequisites
Verified against VyOS 1.5.x LTS (circinus) · VyOS 1.4.x (sagitta) — legacy · FRRouting 10.x (VyOS 1.5) · Linux kernel 6.6 LTS (VyOS 1.5 base) · strongSwan 5.9.x (IPsec) · WireGuard 1.0.x (kernel module + userspace tooling)
commit semantics — what the commit engine actually does
The commit command takes the candidate configuration and turns
it into runtime state. Almost every operator carries a mental
model of this that is slightly wrong, and the wrong part is always
the same: they believe a failed commit changes nothing. It is a
comfortable belief and it is why half-configured routers surprise
people.
This lesson walks what actually runs, in what order, and what is left behind when one step of it fails.
Where the checks actually happen
The first thing to unlearn is that commit is where your
configuration gets checked. Some of it is checked much earlier,
and knowing which is which is most of the diagnostic skill.
flowchart TB
A["set / delete<br/>(you type it)"] --> B{"Value constraint<br/>from the interface definition"}
B -->|fails| B1["rejected here<br/>nothing enters the candidate"]
B -->|passes| C["candidate configuration"]
C --> D["commit"]
D --> E["priority-ordered conf_mode scripts"]
E --> F["get_config()"]
F --> G["verify()"]
G -->|ConfigError| G1["this script fails<br/>commit reports failure"]
G -->|ok| H["generate()<br/>render FRR / nftables / systemd files"]
H --> I["apply()<br/>reload the backend"]
I --> J["next script, same four steps"]
J --> K["archive revision"]
Where commits fail, and how the message tells you
| Where | What it catches | What it looks like |
|---|---|---|
set-time constraint | Format, range, enumeration | rejected as you type; nothing enters the candidate |
verify() | Cross-node references and required combinations | a hand-written sentence naming the node |
generate() / apply() | The backend refusing what VyOS rendered | a template or daemon error, often after other scripts already applied |
The message shape tells you which one you are in, and each one
implies a different next move. A set-time rejection needs a
different value. A verify() failure needs a different
combination — usually a node you have not created yet. A failure
in apply() means the box is already partly changed and the
question is no longer “what did I type wrong” but “what state is
this router in right now”.
“All or nothing” is not what a commit promises
Because the engine runs one script after another, a commit that
fails in the middle has already run the scripts before it. The
interfaces script applied; the BGP script then raised
ConfigError and stopped. Nothing rolls the interfaces back.
That is the honest model, and it is the one to keep in your head at 03:00: a failed commit does not restore the router to the state it was in before you typed it. It stops. Where it stopped depends on priority order, which is why the same typo produces a harmless failure in one subtree and a half-configured router in another.
The candidate configuration, on the other hand, is untouched by a failure — your changes are all still there in the session, which is what lets you fix the one bad node and commit again rather than retyping. The confusion the phrase “atomic commit” causes is exactly this: the session is safe, the box may not be.
The revision archive
Every successful commit archives the configuration. The revisions
live in /config/archive/ as gzipped files, and how many are kept
is a configured number:
set system config-management commit-revisions '200'
set system config-management commit-archive location 'scp://user:pass@backup.example.net/vyos'
The second line is the one that survives losing the router: on every successful commit the configuration is also copied to a remote location over SCP, SFTP, FTP or TFTP, named after the host and the timestamp. A router whose disk you cannot read is not a router whose configuration you have lost. Note that the credentials live in the URI, so this node is one of the few places a password ends up in the configuration — which is an argument for a dedicated, write-only account on the archive host.
Read the history with show system commit:
vyos@vyos:~$ show system commit0 2026-08-15 14:01:12 by vyos via cli
1 2026-08-15 11:42:03 by vyos via cli
2 2026-08-14 14:23:00 by ansible via cli
3 2026-08-14 09:15:41 by vyos via boot-config-loaderIllustrative output
Revision 0 is the current configuration, so “the change before this one” is revision 1. Two commands turn that list into evidence:
show system commit diff 1
show system commit file 1
diff shows what changed relative to the running configuration —
the fastest way to answer “what did the last change actually do”.
file prints the whole configuration as it was at that revision,
which is what you want when the question is “what did this router
look like on Thursday”.
How it fails
The production failure modes the engineer must recognise:
- A value the CLI rejects as you type it. Format, range or enumeration. It never reaches the candidate, and no commit is involved. Fix the value.
- A
verify()failure naming a node that does not exist. The classic is a reference: a neighbour pointing at a peer-group that was never created, a rule referencing an address-group that is not defined, an interface named in a policy that is not configured. The message names both ends. Create the missing node in the same session and commit once. - A backend that refuses what VyOS rendered. The VyOS syntax
was fine, and FRR or nftables rejected the result. The commit
reports a failure from the
apply()of that one script, and the scripts before it have already run. - Commits from two sessions at once. VyOS serialises them —
the second operator’s
commitwaits rather than interleaving. What this looks like from the outside is a commit that hangs, and the correct response is to find the other session, not to interrupt yours. - A commit that succeeds and breaks the service anyway. No
layer of the engine has an opinion about whether your routing
policy was a good idea. This is the failure mode
commit-confirmexists for.
Rollback
rollback 1— go back one revision. On VyOS this reboots the router to load the older configuration, so it is a maintenance action, not a quick undo; plan for the outage.compare 1— before rolling back, see exactly what rolling back would change.loadan archived file thencommit— list/config/archive/first and load the gzipped revision you want. This avoids the reboot, at the cost of re-running every script, so it can fail in the middle exactly like any other commit.discard— throw away an uncommitted candidate. Nothing on the box changes, because nothing had been applied.
Production discipline
Cross-course references
The Linux course’s V-Linux-NetConfig covers the underlying
netlink semantics. The OPNsense course’s
XXXVIII-OPNsense-Troubleshoot covers the equivalent failure
modes on the firewall side. The Ansible course’s
XLII-Ansible-BeyondLinux covers how to drive commits from
Ansible with the same review workflow.
Quiz
Knowledge check · 4 questions
Q1. An operator types `set protocols bgp system-as 4294967296` and the CLI rejects it immediately, without a commit. Which check rejected it?
Q2. A commit that fails leaves the router in the state it was in before the commit was typed.
Q3. A commit fails with `Specified peer-group "UPSTREAM" for neighbor "192.0.2.2" does not exist!`. What kind of failure is this, and what is the correct fix?
The operator is adding a peer to an existing BGP configuration and typed `set protocols bgp neighbor 192.0.2.2 peer-group UPSTREAM`. Every individual value was accepted as it was typed. The commit is refused.
Q4. A commit reported success, and BGP sessions dropped seconds later. Where does the operator look, and what does this say about the engine?
A change set touching several subtrees was committed during a maintenance window. VyOS reported no error. Within a minute, two eBGP sessions went from Established to Active.
Passing score: 75%. Answers are checked in this browser.