Quando um switch avaria numa sexta-feira e a substituição só chega na segunda, o novo equipamento chega vazio: a última configuração funcional estava no aparelho avariado e ninguém a guardou. O cenário é comum em PMEs — a configuração dos equipamentos de rede não entra no backup dos ficheiros, das bases de dados nem das VMs. O Oxidized resolve exactamente isto: um serviço que liga por SSH (ou telnet) a cada switch e router, guarda a configuração numa pasta e faz um commit num repositório Git a cada alteração — com data, autor do commit e diff linha a linha entre versões.
Suporta mais de 130 famílias de sistemas de rede (MikroTik RouterOS, Cisco IOS, Aruba, TP-Link, HP ProCurve, Fortinet, entre os mais comuns em PME), corre em Debian ou Ubuntu num VPS ou no LXC do Proxmox, e integra-se com o LibreNMS já monitorizado aqui no site — a partir desse momento, a configuração de cada equipamento fica visível na própria página do device.
⚠ Antes de produção: o serviço faz login em todos os equipamentos de rede — quem tiver essas credenciais tem a rede inteira nas mãos. Corre com utilizador próprio (nunca root), fica restrito à rede interna, e o repositório Git com as configurações deve ficar fora do acesso anónimo.
Neste artigo
Instalação no servidor Debian/Ubuntu
O Oxidized é uma gem de Ruby e pede Debian 12 ou Ubuntu 22.04 ou mais recentes. No Ubuntu, começa por activar o repositório universe (a libssh2-1-dev está nesse repositório), instalar as dependências de compilação e a gem:
add-apt-repository universe
apt install ruby ruby-dev libsqlite3-dev libssl-dev pkg-config cmake \
libssh2-1-dev libicu-dev zlib1g-dev g++ libyaml-dev libzstd-dev
gem install oxidized
A gem opcional oxidized-web acrescenta a interface web e a REST API (que o LibreNMS usa) — instala com gem install oxidized-web. O serviço corre com um utilizador próprio: o daemon não corre como root, e faz logins de rede — com useradd -s /bin/bash -m oxidized e su - oxidized antes de o arrancares.
Primeiro arranque e router.db
Na primeira execução, o Oxidized cria a configuração inicial em ~/.config/oxidized/config — basta correr oxidized uma vez e interromper. Um exemplo de configuração, com o intervalo de recolha, a origem dos equipamentos (source) e o destino das configurações (output):
username: backup
password: SenhaMuitoForte2026!
interval: 3600
log: ~/.config/oxidized/log
debug: false
threads: 30
timeout: 20
timelimit: 300
source:
default: csv
csv:
file: ~/.config/oxidized/router.db
delimiter: !ruby/regexp /:/
map:
name: 0
model: 1
output:
default: git
git:
user: Oxidized
email: [email protected]
repo: ~/.config/oxidized/backups.git
O router.db é o inventário no formato rancid — uma linha por equipamento com hostname:modelo e o delimiter do exemplo oficial (:). Credenciais por linha entram com o mapeamento completo da documentação (hostname:model:username:password e vars_map), e os grupos por zona entram no map ou nas credenciais do bloco groups::
# hostname:modelo (formato rancid; o delimiter do exemplo oficial é :)
sw-core:routeros
rt-filial:routeros
sw-cctv:procurve
A referência completa lista os campos de mapeamento e os grupos — os grupos valem ouro quando as credenciais diferem por zona (loja, filiais, CCTV). Para quem já mantém o inventário noutro sítio, o source pode ser SQLite, MySQL ou um URL HTTP — é aqui que a integração com o LibreNMS se encaixa mais abaixo.
Git: histórico e diff por alteração
O output git é o recomendado: cada versão da configuração é um commit no repositório (backups.git no exemplo), e os comandos do Git passam a ser a ferramenta de auditoria:
git -C ~/.config/oxidized/backups.git log --oneline # últimas alterações
git -C ~/.config/oxidized/backups.git diff HEAD~1 HEAD # o que mudou
Como bónus, o README documenta um exemplo de syslog UDP+ficheiro para IOS/JunOS que apanha os eventos de mudança de config e regista o autor da alteração no commit — um git blame em qualquer linha revela o utilizador e a data. O fluxo está documentado para IOS/JunOS: para modelos como o MikroTik, o histórico Git mostra quando as linhas mudaram, não quem as mexeu.
A interface web de consulta rápida
A gem oxidized-web abre a porta 8888 e expõe a lista de equipamentos com o estado da última recolha, a configuração completa de cada um, e as versões guardadas com diff entre elas. A REST API do mesmo serviço é o que o LibreNMS e scripts externos consomem: /nodes (inventário), /node/fetch/[NODE] (config), /node/version (versões) — e /node/next/[NODE] coloca um equipamento à cabeça da fila (a recolha é imediata com next_adds_job: true; sem ele, corre quando um worker fica livre).
A sintaxe actual usa o bloco extensions.oxidized-web: load é false por omissão (tem de ser true) e listen é 127.0.0.1 por omissão — a API fica em localhost, o que se quer quando quem consulta é só o LibreNMS na mesma máquina. A sintaxe antiga rest: está obsoleta (emite aviso e será removida), a extensão pede oxidized-web ≥ 0.16.0 e, se rest: estiver na configuração, o bloco novo é ignorado:
extensions:
oxidized-web:
load: true
listen: 127.0.0.1
port: 8888
vars: {}
A integração no LibreNMS
Com o LibreNMS no mesmo host (ou acessível por HTTP), dois passos ligam os dois. Primeiro, apontas o LibreNMS ao serviço e ligar a apresentação da config na página de cada device:
lnms config:set oxidized.enabled true
lnms config:set oxidized.url http://127.0.0.1:8888
lnms config:set oxidized.features.versioning true
lnms config:set oxidized.group_support true
Segundo, opcional mas recomendado: usar o próprio LibreNMS como inventário do Oxidized — o source HTTP do Oxidized lê a lista de devices directamente da API do LibreNMS (/api/v0/oxidized, com token de API), e a opção oxidized.reload_nodes true faz o LibreNMS reenviar a lista sempre que entra um device novo. Neste modo, o router.db deixa de ser mantido à mão. O LibreNMS não fornece credenciais — o inventário chega com hostname e grupo; o group_support faz o grupo do device no LibreNMS escolher o grupo do Oxidized, onde as credenciais ficam no bloco groups:.
source:
default: http
http:
url: https://librenms.empresa.pt/api/v0/oxidized
map:
name: hostname
model: os
group: group
headers:
X-Auth-Token: '0TOKEN_LONGO_DA_API'
Numa instalação com SELinux (RHEL/Alma/Rocky), a integração falha em silêncio sem setsebool -P httpd_can_network_connect 1. Com tudo activo, a página de cada switch no LibreNMS passa a ter o separador Config com a última configuração e o histórico — o diff num clique, sem consola.
Intervalo, eventos e hooks
O interval: 3600 define a recolha de hora em hora, com o serviço a ajustar automaticamente as threads para caber no prazo. O evento valioso é o contrário da recolha por agendamento: com o syslog do router ligado ao Oxidized, a mudança de config dispara a recolha. O fluxo documentado no README é para IOS/JunOS; no LibreNMS, o script syslog-notify-oxidized.php é quem chama /node/next no evento de syslog. Duas condições: next_adds_job: true na configuração (senão o nó só entra à cabeça da fila) e um listener a fazer a chamada. Com isso, a config muda às 14h32 e o backup entra de seguida, com commit e diff. Os hooks (exec no evento pós-store, GitHub repo, Slack Diff, XMPP) cobrem a notificação da alteração:
# hooks: notificar o canal Slack da equipa a cada alteração de config
# requer: gem install slack-ruby-client
hooks:
slack:
type: slackdiff
events: [post_store]
token: SLACK_BOT_TOKEN
channel: "C0123456789"
O hook usa um token de bot de Slack e o ID do canal (não um webhook e não o nome #redes) — os valores vêm do Hooks.md. Opcional: diff: false com message: para publicar um link ao commit em vez do snippet.
Onde guardar o repositório
O repositório Git com as configurações é um backup crítico — contém o estado de todo o parque de rede. Entra no ciclo de backup do servidor (o guia de backups do site cobre o resto), e a cópia de backups.git para um segundo destino (NAS, cloud) fecha o ciclo: o servidor perde-se, as configs sobrevivem num git clone.
Erros comuns
- Unknown model — o modelo no
router.dbnão corresponde ao nome certo (ex.mikrotikem vez derouteros). A página Supported OS Types do projecto lista os nomes válidos. - Device a falhar sempre — o
timeout(20 s por omissão) limita cada operação e otimelimit(300 s, por omissão) o total do job; para equipamentos lentos, aumenta-os na configuração, e umdebug: truetemporário mostra a fase exacta da falha. - Login failed — credenciais variam por zona: blocos
groups:na config comusername/passwordpor grupo. - LibreNMS sem separador Config — com SELinux activo,
httpd_can_network_connecté o primeiro suspeito (a falha é silenciosa). - oxidized-web sem API — a extensão não arranca por omissão: falta
load: trueno blocoextensions.oxidized-web, ou a gem não está no ambiente do utilizador do serviço (verifica comgem list oxidized-webnesse utilizador).
Veredicto
A partir de meia dúzia de equipamentos, o backup de rede deixa de ser luxo — é o que separa um restauro de dez minutos de um fim de semana a refazer configurações. O Oxidized é leve (gem Ruby, SQLite e Git — dimensiona consoante o tamanho do parque), e o Git dá auditoria sem custo, e a ligação ao LibreNMS põe a configuração no painel que a equipa já abre. O projecto, embora activo e amplamente usado em produção, tem o maintainer principal a pedir reforço — é um factor a saber, e o argumento extra para o backups.git ter cópia fora do servidor.
Artigos Relacionados
- LibreNMS: monitorização de rede open-source
- NetBox: inventário e documentação de rede (IPAM/DCIM)
- Backups fiáveis do MariaDB em servidores Linux
- MikroTik na fibra da MEO: substituir o FiberGateway
Fontes Oficiais
- Oxidized — GitHub (ytti/oxidized): instalação e configuração inicial
- Configuration — doc de referência (sources, outputs, timeout/timelimit)
- Hooks — referência dos hooks (exec, slackdiff, githubrepo)
- Supported OS Types — lista de modelos
- Oxidized Integration — LibreNMS docs