Skip to main content
RunBook Academy

← All runbooks in VyOS

medium riskservice affecting~35 min

Runbook: Add a Static Route

1 · Prerequisites

Confirm every item is in place before any state change.

2 · Pre-checks

Read-only diagnostic commands. If any of these don't match expected output, stop and investigate further.

  • · show ip route 10.20.0.0/16 run BEFORE the change — whatever it answers today is exactly what a rollback restores, and if it answers with a route, this static will displace it
  • · show ip route 192.0.2.99 for the intended next-hop: an indirect route whose next-hop does not resolve is installed inactive and never reaches the FIB
  • · Checked for more-specific prefixes already in the table. Longest-prefix-match beats administrative distance: a /24 from OSPF wins over your /16 static for everything inside the /24.
  • · The distance is decided and written in the ticket: 1 for a primary, 210 for a floating backup that must sit behind OSPF, BGP and IS-IS
  • · show configuration commands checked for redistribute static. If the estate redistributes statics, the blast radius is every router that accepts the advertisement, not this one.
  • · The return path is confirmed by the far end's owner or by a test from that end — a static route fixes one direction only
  • · Baseline captured: show ip route, show ip route static, show configuration protocols static, ip route show
  • · Out-of-band console open, peer reviewer named for the compare diff, change window end time agreed

3 · Procedure

Execute each step in order. Verify the expected output of a step before moving to the next.

  1. 1Capture the baseline, and specifically the two "before" answers: show ip route 10.20.0.0/16 and show ip route 192.0.2.99. The first is the rollback expectation; the second decides whether the route can install at all.
  2. 2Check for more-specific prefixes from any source that already cover part of your prefix, and for a redistribute static statement in the routing configuration.
  3. 3Choose the form: next-hop plus interface on a shared Ethernet segment, next-hop alone on a transit link where the next-hop resolves recursively, interface alone only on a point-to-point link.
  4. 4Choose the distance before typing it. 1 is a primary and beats every dynamic protocol; 210 is a floating backup that activates only when the preferred source withdraws.
  5. 5Enter configure and set the route, with a description that carries the change reference and the reason. The description is stored in the VyOS tree only, and it is the single piece of documentation that outlives you.
  6. 6Run compare and have the named reviewer read the diff. A transposed octet in a next-hop produces a route that installs cleanly and forwards into nothing.
  7. 7Apply with commit-confirm 10 if you reach this router over the network, or commit from the console.
  8. 8Cross-check three views: show configuration protocols static is what you typed, show ip route static is what FRR accepted, ip route show is what the kernel will actually forward on. All three must agree.
  9. 9Confirm the route is selected and installed: show ip route 10.20.0.0/16 must show S>*. Bare S, or inactive, means the route is in the RIB and forwarding nothing.
  10. 10Test the forward path with traceroute, and use traceroute -s with the source address production traffic will really use — the router's own source selection is not the same thing.
  11. 11Test the return path from the far end. Forward-only success is the commonest way this change appears to have failed when it has half succeeded.
  12. 12Confirm inside the timer, save, and close the ticket with the before and after show ip route 10.20.0.0/16 side by side.

4 · Verification

Confirm the procedure actually fixed the problem.

  • show ip route 10.20.0.0/16 shows S>*: S for static, > for selected, * for present in the FIB
  • The reported next-hop and the resolved egress interface are both the ones you intended
  • ip route show contains the prefix with proto static. The kernel FIB is the only view that forwards packets; FRR's RIB is a statement of intent.
  • The FRR view and the kernel view agree. A route in show ip route and absent from ip route show does nothing, and traffic falls through to a less-specific route.
  • Every other prefix in show ip route is unchanged from the baseline capture
  • traceroute from the router leaves by the intended path, and traceroute -s from the production source address takes the same path
  • Traffic completes in both directions, verified from the far end and not only from this router
  • If the route is redistributed, a downstream router shows it arriving with the attributes the policy was supposed to stamp
  • save has run, so the route survives a reboot

5 · Rollback

If verification fails, undo the procedure in reverse order.

  • Before any commit, exit discard throws the candidate away and leaves the running configuration untouched
  • After the commit and before confirm, do nothing — the commit-confirm timer restores the previous configuration by itself
  • After confirm: delete protocols static route 10.20.0.0/16, compare, commit, save
  • Removing the route does not restore "nothing" — it restores whatever the baseline showed. If that was a default route, traffic keeps flowing to the wrong place and fails somewhere downstream where nobody is watching this change.
  • A middle state exists and is often the right one: set protocols static route 10.20.0.0/16 disable keeps the route in the configuration but stops it being rendered to FRR, so the intent stays reviewable while the forwarding reverts
  • If the route was redistributed, removing it withdraws it from every router that accepted it, and that convergence is not instantaneous
  • A whole-tree rollback 1 reverts everything else in the candidate too. Run compare between rollback and commit, every time.

6 · Escalation

When the runbook isn't enough, contact:

  • · Escalate to network engineering when the prefix is already carried by OSPF or BGP. A distance-1 static overrides them and never withdraws, so the route outlives the topology it was written for.
  • · Escalate rather than reach for on-link when the next-hop does not resolve. That flag makes the kernel install the route regardless of reachability; if the next-hop is wrong, traffic is handed to the wrong segment and dropped there silently.
  • · Escalate to the far end's owner when the forward path works and the return path does not — that is their change, not another route on this router
  • · Escalate to network engineering before committing if the router redistributes static routes into BGP: a local operational fix becomes an estate-wide, and possibly an external, advertisement
  • · Escalate when two static routes for the same prefix are proposed at the same distance. That is ECMP load sharing, not a primary and a backup, and the difference only becomes visible when one path fails.
  • · Hold rather than force: commit the route with disable set, name the owner of the blocking item, agree an end time, and leave the forwarding table as it was

A static route is not added to the routing table. It competes for it, and at the default administrative distance of 1 it beats every dynamic source in the table except a connected route. Whatever OSPF or BGP has to say about the prefix stops mattering on this router the moment you commit.

That is usually the point. What makes it a production change rather than a one-liner is the other half of the same property: a static route has no mechanism for noticing that it has become wrong. A dynamic route withdraws when the path behind it fails. A static route does not. It keeps pointing at the same next-hop through the outage, the maintenance, the re-addressing project and the decommission, because nothing in the router’s model of the world can tell it otherwise.

So this runbook front-loads two questions that take about a minute each and prevent most of the ways this goes wrong: what carries this prefix today, and does the next-hop actually resolve.

When to use this runbook

  • A prefix has to be reachable from this router and no dynamic protocol carries it here.
  • A floating backup path is being installed behind a dynamic primary.
  • Traffic for a specific destination is being pinned during a migration, with an end date recorded in the ticket.

When not to use it

  • To work around a dynamic protocol that is not converging. A distance-1 static will make the symptom disappear, which is exactly the problem: the cause stays, the static outlives the incident, and the next person finds a routing table that contradicts the design with no record of why.
  • For the default route. Same tree, same syntax, entirely different blast radius — the default route is every destination the router does not otherwise know, and it deserves its own change.
  • For blackhole or reject routes. Same configuration tree, opposite intent, and the verification is inverted: success is traffic not arriving.
  • For source-based decisions. A static route matches on destination only. Choosing a path by source, by port or by mark is policy-based routing.

Blast radius

Locally: every packet this router forwards toward the prefix, for as long as the route exists.

Beyond this router: it depends entirely on whether the estate redistributes statics. redistribute static in an IGP or in BGP turns a local operational fix into an advertisement, and the routers that accept it will forward toward this one on the strength of it. Read the redistribution policy, not just the redistribute statement — a prefix-list and a route-map usually decide which statics actually leave, and “my prefix is not in the list” is a fact to verify rather than assume.

Inputs

  • The prefix, in the exact form it will be written.
  • The next-hop, and whether it sits on a connected subnet of this router.
  • The form: next-hop with interface, next-hop alone, or interface alone.
  • The distance, decided in advance: 1 or 210.
  • A description carrying the change reference and the reason.
  • Whether the estate redistributes static routes.
  • The owner of the far end, for the return path.

Step 1: Find out what carries the prefix today

Read-only / Safethe two questions
show ip route 10.20.0.0/16
show ip route 192.0.2.99
show configuration commands | match redistribute

Three answers to the first command, and each one changes the change:

  • Nothing carries it. The static is additive here, and the rollback restores nothing. That sounds safe and is worth thinking about: after a rollback, traffic for the prefix falls to the default route and leaves the building instead of failing locally, which is harder to notice.
  • Something carries it at a higher distance. Your static will win. Confirm that displacing it is the intent, in the ticket, with the person who owns the dynamic path.
  • Something carries a more specific prefix. This is the one that catches people out.

Step 2: Confirm the next-hop resolves

An indirect static route — a next-hop with no interface — does not carry its own egress. The kernel performs a second lookup on the next-hop address, finds a route that reaches it, and uses that route’s interface. If that lookup fails, the route is installed inactive and never enters the FIB.

The show ip route output for the next-hop is what tells you which form to use:

  • The next-hop is on a connected subnet of this router: use the direct form, next-hop plus interface. The interface is explicit and the route stops depending on another route staying correct.
  • The next-hop is reachable through another route: the indirect form is appropriate, and you accept that this route’s health is now tied to that other route’s.
  • The next-hop does not resolve at all: stop. This is not a route you can add yet.

Step 3: Choose the distance before you type it

Distance 1 is a primary: it wins against everything except connected routes. Distance 210 is a floating backup: it sits behind eBGP at 20, OSPF at 110, IS-IS at 115 and iBGP at 200, stays inactive while any of them carries the prefix, and becomes active the moment they withdraw.

The failure mode is quiet in both directions. A backup committed at distance 1 is permanently active and the intended primary is permanently ignored — and everything works, so nobody finds out until the day the static path is the one that breaks. A primary committed at 210 is permanently inactive, and traffic keeps using a path somebody had decided to move off.

And two statics for the same prefix at the same distance are not a primary and a backup at all: they are equal-cost candidates, and the router load-shares between them. If you want a backup, the distances must differ.

Step 4: Commit, with a description

Service impact possibleadd the route
configure
set protocols static route 10.20.0.0/16 next-hop 192.0.2.99 interface eth0
set protocols static route 10.20.0.0/16 description 'CR-1231 dc01-eu transit, review 2026-11-01'
compare
commit-confirm 10
exit

The description is not exported to FRR. It lives in the VyOS configuration tree and appears in show configuration protocols static, which is precisely where the next operator will be looking when they find a route nobody remembers. A change reference, the destination in words, and a review date cost one line and are the only documentation that reliably survives.

Read the compare output for the next-hop especially. A transposed octet produces a route that commits cleanly, installs cleanly, and forwards into nothing — there is no validation step anywhere in the stack that knows what you meant.

Point of no return. After the commit this router’s forwarding decision for the prefix has changed, and if the route is redistributed, so has every downstream router’s.

Step 5: Cross-check three views

Read-only / Safethe three characters that matter
vyos@vyos:~$ show ip route 10.20.0.0/16
S>* 10.20.0.0/16 [1/0] via 192.0.2.99, eth0, 00:00:07

Illustrative output

S on its own means FRR has the route and has not selected it. The word inactive means the recursive lookup for the next-hop failed. Neither forwards a packet.

Then confirm the kernel agrees:

Read-only / Safethe other two views
show configuration protocols static
show ip route static
ip route show

Three views of one route, and they answer different questions. show configuration protocols static is what you typed. show ip route static is what FRR accepted into its RIB. ip route show is the kernel FIB — the only one of the three that forwards a packet, where the entry should carry proto static.

Step 6: Test both directions, from a real source

Read-only / Safeforward path
traceroute 10.20.0.5
traceroute -s 192.0.2.1 10.20.0.5

The first traceroute leaves with whichever source address the router chooses for itself. That is often not the address production traffic carries, and on a router with several interfaces or a bound management path it can take a different route entirely. The second form pins the source, which is the test that matches reality.

Then test the return path from the far end, or have its owner do it. A static route is one-directional: it tells this router how to reach the destination and says nothing about how the destination reaches back. Forward success with return failure is the commonest way this change appears to have failed when it has in fact half succeeded, and the remaining half is somebody else’s routing table.

Asymmetry is not automatically a fault — return paths differ from forward paths all over the internet. It becomes a fault when something stateful sits in the path and only sees one direction of the conversation, which on a routed estate with firewalls is most of the time.

Only when both directions are proven:

Configuration changeconfirm and persist
configure
confirm
save
exit

Rollback

Service impact possibleremove the route
configure
delete protocols static route 10.20.0.0/16
compare
commit
save

The rollback restores the baseline, and the baseline is the thing to have written down. Removing the route does not return the prefix to a neutral state; it returns it to whatever show ip route 10.20.0.0/16 answered before the change. If that was a default route, traffic still leaves the router — just not where anyone intends, and it fails somewhere downstream where nobody connects the failure to this change.

There is a middle state worth knowing about. set protocols static route 10.20.0.0/16 disable keeps the route in the configuration but stops it being rendered to FRR, so forwarding reverts while the intent stays visible and reviewable. For a change that is contested rather than wrong, that is a better place to stop than deletion.

If the route was redistributed, deletion withdraws it from every router that accepted the advertisement. That convergence takes time and is worth watching rather than assuming.

Common patterns

SymptomLikely causeNext check
Route shows S with no > or *Another source wins the prefix, or a more specific route existsshow ip route for the exact prefix and its supernet
Route shows inactiveThe recursive next-hop lookup failedshow ip route for the next-hop address
Route in FRR, absent from the kernelIt never reached the FIBip route show, then escalate
Route installed, traffic still failsA more specific route from another source covers the destinationTrace the exact destination, not the prefix
Works from the router, fails from hostsSource address selection differstraceroute -s with the production source
Forward works, nothing comes backNo return route at the far endThe far end’s routing table, via its owner
Backup path never activatesBoth routes committed at the same distance, so they load-shareshow ip route static and compare the distances
Route survives a topology change it should not haveStatic routes never withdrawThe description and the review date in the ticket
Route disappears after a rebootsave never ranCompare running against the boot configuration

Escalation

Escalate rather than commit when:

  • The prefix is already carried by OSPF or BGP. Overriding a dynamic protocol with a static is a design decision with a long tail, not a routing fix.
  • The next-hop does not resolve and on-link is being suggested as the way through.
  • The forward path works and the return path does not. Adding a second route on this router will not fix somebody else’s table.
  • The router redistributes static routes into BGP. A local fix becoming an external advertisement is a different conversation with a different set of people in it.

Holding is a real option: commit the route with disable, name the owner of the blocker, agree an end time, and leave the forwarding table exactly as you found it.

References

  1. VyOS — Static routes
  2. VyOS — Routing overview
  3. VyOS — CLI, commit and rollback
  4. ip-route(8)