CHG-0061: The Core Router Restored From Its Vaulted Backup

CHG-0061: The Core Router Restored From Its Vaulted Backup #

Date2026-11-11
Change typeConfiguration
ClassificationDisruptive
StatusComplete, 2026-11-11. The vaulted backup, decrypted from a fresh GitHub clone, restored onto dv02cor002p01; the site matched its baseline and the firewall plan showed no drift
Window2026-11-11, from the 12:16 baseline to the 12:47 firewall plan, with the operator at the router’s web UI. One router reboot: no routing, DNS or DHCP for the site for a few minutes
Sitemobile
Systemsdv02cor002p01 (core router)
Automationansible-inventory-deevnet backups/mobile/dv02cor002p01/config.xml.vault, written by make backup-router in deevnet.net; ansible-vault decrypt
RiskMedium. Most likely to go wrong: the router reboots into a configuration that does not bring the management segment up, which leaves only the console
Related changesCHG-0007 (the firewall role’s pre-apply snapshot)
Related incidentsNone
Related runbooksRebuild the Core Router, Console Recovery: Core Router

Summary #

The core router’s configuration is backed up vault-encrypted into the inventory, at backups/mobile/dv02cor002p01/config.xml.vault. The first backup was taken on 2026-11-11 at 12:12. No restore has been done from it yet, so nobody knows whether it would bring the router back.

This change restores that backup onto the running router, following steps 2–5 of Rebuild the Core Router. The backup is decrypted from a fresh clone of the inventory taken from GitHub, not from the Builder. Step 1, the OPNsense reinstall, is left out: the router keeps its install, and only its configuration is replaced. The backup is minutes old, so the router should come back as it was.

Goal #

  • The backup decrypts from a fresh GitHub clone, with the vault password alone.
  • The router accepts it, reboots, and comes back on 10.20.99.1 and every VLAN.
  • The network checks match the baseline taken before the change.
  • The plaintext the decrypt produced is deleted, as are the older plaintext copies in migration-logs/.

Scope #

In scope: decrypting the backup, the restore from the web UI, and the reboot and checks. Out of scope: reinstalling OPNsense. That path’s own steps are unchanged, and the reinstall itself stays unrehearsed.

Risk and impact #

RiskWhereGuard
The restored configuration does not bring management upthe routerThe configuration in use before the restore stays in the router’s own history (/conf/backup). Console Recovery restores it with Restore a backup; its file name is noted in Step 1
The router changed after the backup, and the restore undoes itthe routerStep 1 checks that the newest revision in the router’s history is the one from before the backup. If a newer one exists, take a new backup first
The decrypted config.xml outlives the changethe operator’s computerStep 5 deletes it and the clone. It holds the router’s private keys
The site is offline during the rebootevery segmentExpected, and the reason this change is Disruptive. Nothing is mid-deploy

Prerequisites #

  • The backup on GitHub: router-config-backup branch of ansible-inventory-deevnet (PR #97)
  • Console cable and a terminal ready for the router, in case management does not come back
  • On the computer whose browser does the restore: git, ansible-vault, and the vault password
  • Baseline from the Builder, taken 2026-11-11 12:16: the web UI answers; dv02hyp001p01 and api resolve through 10.20.99.1; 10.20.25.20 and 1.1.1.1 answer ping; HTTPS to GitHub works. Already failing before the change: a ping to 10.20.30.11, and tdemo-1.tdemo returns no address

Procedure #

Step 1: Note the revision to undo to #

Run: in the web UI, open System β†’ Configuration β†’ History.

Verify:

  1. Note the newest revision’s date and file name: that is the configuration running now, and the one to pick at the console if the restore needs undoing.
  2. It is no newer than the backup (2026-11-11 12:12). If it is, stop and take a fresh make backup-router first.

Undo: nothing to undo.

Step 2: Decrypt the backup from GitHub #

Not disruptive.

Run:

git clone -b router-config-backup https://github.com/deevnet/ansible-inventory-deevnet.git ~/rehearsal
cd ~/rehearsal
ansible-vault decrypt --output ~/rehearsal/config.xml backups/mobile/dv02cor002p01/config.xml.vault

Verify:

  1. grep -c '<opnsense>' ~/rehearsal/config.xml prints 1.

Undo: rm -rf ~/rehearsal.

Step 3: Restore it #

Disruptive: the router reboots.

Run: in the web UI, open System β†’ Configuration β†’ Backups. Under Restore, choose All as the area, pick ~/rehearsal/config.xml, keep Reboot after a successful restore selected, and restore.

Verify:

  1. The page reports the restore succeeded before the router reboots.

Undo: Undo Step 3.

Step 4: Check the site #

Run: from the Builder, the baseline checks again, once the web UI answers.

Verify:

  1. Every check that passed in the baseline passes again.

  2. The firewall role’s plan shows no drift. It reports and writes nothing without firewall_apply=true:

    cd ansible-collection-deevnet.net
    ANSIBLE_ASK_VAULT_PASS=true make migration-opnsense-firewall
    

Undo: Undo Step 3.

Step 5: Delete the plaintext #

Run:

rm -rf ~/rehearsal                                            # the operator's computer
rm /srv/dvnt/migration-logs/*-pre-firewall-*.xml              # the Builder
rm /srv/dvnt/ansible-collection-deevnet.net/migration-logs/*-pre-firewall-*.xml

Verify:

  1. No *.xml is left in either migration-logs/ directory.

Undo: no undo. The vaulted backup replaces them, and Step 4 proves it restores.

Verification #

The router came back from the vaulted backup alone, and the site matches the baseline.

Undo #

Undo Step 3 #

If the web UI answers, restore the revision noted in Step 1 from System β†’ Configuration β†’ History. If it does not, follow Console Recovery: Core Router: Restore a backup at the console, choosing that revision.

To close #

This change closes when every item below is done.

  • Step 1: the revision to undo to noted, and no newer than the backup
  • Step 2: the backup decrypted from a fresh GitHub clone
  • Step 3: the backup restored, the router rebooted
  • Step 4: the baseline checks pass again, the firewall plan shows no drift
  • Step 5: the decrypted copy and the old plaintext copies deleted

Outcome #

Completed after the change has run.

WhenStepsWhat happened
12:16BaselineTaken from the Builder; recorded under Prerequisites
Before 12:421–2Backup decrypted on the operator’s Mac from the inventory on GitHub, after PR #97 merged. It was decrypted with --output to ~/rehearsal/config.xml, outside the checkout
Before 12:423Restored from the web UI with a reboot; the router came back on 10.20.99.1
12:424The baseline checks again, identical line for line: the web UI answers, dv02hyp001p01 and api resolve through the router, 10.20.25.20 and 1.1.1.1 answer ping, HTTPS to GitHub works. The 10.20.30.11 ping and tdemo-1.tdemo lookup failed, as they did before the change
12:474Firewall plan: 0 to add, 0 of 71 to update, 0 to delete; the deevnet_private alias matches inventory
After 12:475~/rehearsal deleted on the Mac; seven plaintext router configs deleted from the Builder’s two migration-logs/ directories

Departures from the plan #

  • Decrypted from main, not a fresh clone of the branch. PR #97 merged first, so the operator pulled main into an existing checkout on a Mac and decrypted from it. The copy still came from GitHub, and the Builder was not involved.
  • Seven plaintext copies deleted, not six. Besides the six *-pre-firewall-*.xml, the Builder held dv02cor002p01-pre-chg0032-20261002T180721Z.xml, the snapshot taken before CHG-0032. It was deleted with them.
  • The reboot was not confirmed from the router’s uptime. The Builder has no saved host key for the router’s SSH, and one was not accepted just for this check. The operator watched the reboot.

Follow-ups #

  • The checks that already failed in the baseline, a ping to 10.20.30.11 and the tdemo-1.tdemo lookup, are unexplained and outside this change
Page last modified: November 11, 2026