Network Config Backup with Oxidized: Setup Guide - 夜莺博客

Network Config Backup with Oxidized: Setup Guide

Configuration backups fail for the same reason every time: they are a manual task performed on a good day. Oxidized turns them into a service - it polls every device on a schedule, pulls the running configuration over SSH, and commits a change to a Git repository only when the configuration actually changed, giving you a version history and a diff per device. This guide covers installation, the YAML configuration model, the node inventory backends, Git output, stripping secrets, and the API hook that triggers an immediate backup when something else in your environment detects a change.

Why Oxidized rather than a script

A collection of expect scripts handles the happy path and fails on everything else: a device that requires an enable password, a platform whose output includes a timestamp that changes on every fetch, a device that is down for maintenance. Oxidized ships model definitions per platform, uses libssh2 for transport, and applies a per-model normalisation step before deciding whether the configuration changed. That last point matters - without it, a Cisco IOS device creates a new revision every time someone exits configuration mode, and the history becomes noise.

Install

# Debian 12 / Ubuntu 22.04+
apt install -y ruby ruby-dev libmysqlclient-dev libssl-dev \\
  libsqlite3-dev pkg-config cmake libssh2-1-dev
apt install -y ruby-dev gcc make
gem install oxidized
gem install oxidized-script oxidized-web   # optional extras

useradd -m -s /bin/bash oxidized
mkdir -p /run/oxidized && chown oxidized:oxidized /run/oxidized

Run Oxidized as its own unprivileged user. The credentials that reach every network device should not belong to an interactive account, and the backup repository should be writable only by the service account.

Configuration

Config is YAML, loaded from /etc/oxidized/config and then ~/.config/oxidized/config, with the hashes merged so that shared settings can live system-wide and credentials per user.

username: backup
password: <secret>
model: ios
interval: 3600
rest: 127.0.0.1:8888
next_adds_job: true

vars:
  remove_secret: true
  output_store_mode: on_significant

source:
  default: csv
  csv:
    file: ~/.config/oxidized/router.db
    delimiter: !ruby/regexp /:/
    map:
      name: 0
      model: 1
      username: 2
      password: 3

output:
  default: git
  git:
    user: Oxidized
    email: oxidized@example.net
    repo: ~/.config/oxidized/configs.git

Node inventory

# ~/.config/oxidized/router.db  (RANCID-compatible)
core-sw01.example.net:ios
edge-rtr01.example.net:ios
wan-fw01.example.net:juniper
acc-sw02.example.net:procurve

CSV is fine to start; SQLite, MySQL and an HTTP endpoint are all supported sources, and the HTTP backend is what most teams eventually use, because device inventory already lives in an IPAM or CMDB. Feeding Oxidized from the same inventory you feed monitoring from removes an entire class of drift.

Store secrets, but not passwords

output_store_mode: on_significant plus a model's significant_changes filter stops timestamp-only revisions. remove_secret: true strips secrets before storage - which makes the repository safe to share, at the price of no longer being a full configuration backup. Decide deliberately: most regulated environments keep the secret-bearing version in a separate, access-controlled repository.

Trigger, schedule and verify

mkdir -p /run/oxidized && chown oxidized:oxidized /run/oxidized
sudo cp extra/oxidized.service /etc/systemd/system/
sudo systemctl enable --now oxidized
systemctl status oxidized

curl http://127.0.0.1:8888/nodes
curl -X PUT http://127.0.0.1:8888/node/next/core-sw01.example.net

The REST endpoint is the useful operational feature: when a syslog alert reports a configuration change on a device, pushing that node to the head of the queue means the change is captured in seconds rather than at the next hourly cycle. Set next_adds_job: true so the move creates a job immediately instead of waiting for a free worker.

Verify the history is real

git -C ~/.config/oxidized/configs.git log --oneline | head
git -C ~/.config/oxidized/configs.git log -p -1 -- core-sw01.example.net

An empty log after an hour means the source inventory did not match the device name the collector is using, or the model is wrong for the platform. Check oxidized logs for the fetched node list first - authentication failures appear per device, not as a service failure, which is why the service looking healthy proves very little.

Related: Ansible Jinja2 templating for network device configs for the push side of the same estate, and Ansible AWX job templates if you want scheduled runs with audit trails.

原文链接:https://github.com/ytti/oxidized/blob/master/README.md