rosbackup-ng (0.8.1)
Installation
pip install --index-url rosbackup-ngAbout this package
Automated, resilient RouterOS backup utility (binary + plaintext, parallel, tmpfs-staged)
RouterOS Backup NG
Automated, resilient backup utility for MikroTik RouterOS devices. It creates, downloads,
and stores both binary (.backup) and plaintext (.rsc) backups — in parallel, with
encryption, tmpfs staging, tag/group targeting, pluggable storage destinations, and
connectivity built to survive flaky overlay links (e.g. ZeroTier). An optional self-hosted
web platform adds a dashboard, HTTP API, schedules, and push-restore.
It runs as a lean CLI (rosbackup) or as a long-running web service (rosbackup-web). The web
platform deploys as a Docker stack (see Deploy with Docker); pip, a single-file
zipapp, and from-source installs live in doc/INSTALLATION-METHODS.md.
The optional self-hosted web platform — fleet dashboard with reachability, backup health, latency, and recent runs. See Web platform.
At a glance
rosbackup --compose-style renders a live, scale-aware view. At fleet scale it switches
from per-row output to an aggregate dashboard — a progress bar, success/failure/running
counts, throughput-based ETA, the active window, and a failures tail:
[+] Backing up 5000 targets
██████████░░░░░░░░░░░░░░░░░░░░ 1640/5000 33% ✔ 1628 ✘ 12 ⠹ 48 running 2m14s eta 4m31s
Active:
⠹ router-1641 Backing Up 1.2s
⠼ router-1642 Getting Info 0.4s
… and 46 more running
Recent failures:
router-0044, router-0210
(See Compose-style output for the per-row view used by smaller fleets.)
Highlights
- Both backup formats — binary (
.backup) + plaintext (.rsc), in parallel, with encryption and tmpfs staging to spare router flash. - Resilient connectivity — retry-within-a-window, TCP keepalives, and operation-level reconnect, built to survive flaky overlay links (e.g. ZeroTier).
- Fleet at scale — tags/groups, scoped runs (
--group/--tag), and a compose-style live view that scales from 4 routers to 5,000. - Pluggable storage — mirror to
local/sftp/nextcloud(ands3via an extra), with per-destination retention and group/tag routing. - Optional web platform — self-hosted UI +
/api/v1: dashboard, schedules, push-restore, firmware upgrades, an encrypted Vault for keys/passwords, API tokens, and an audit log. - Secure by default — SSH key auth, self-contained host-key verification, encrypted
backups,
0600files, and log redaction.
See doc/FEATURES.md for the full (non-exhaustive) feature list.
Documentation
doc/FEATURES.md— Full (non-exhaustive) feature listdoc/BOOTSTRAP.md— Preparing RouterOS devices for automated backups with the bootstrap utilitydoc/COMMAND_REFERENCE.md— Complete reference of all command-line optionsdoc/CONFIG_REFERENCE.md— Detailed reference of allglobal.yaml/targets.yamlparametersdoc/FILESYSTEM_STRUCTURE.md— Project directory structure and organizationdoc/BACKUP_STRUCTURE.md— Backup file formats, naming conventions, and info filesdoc/BACKUP-AND-RESTORE.md— What backups contain and how to restore a device (binary-only, with safety steps)doc/TMPFS_FEATURES.md— tmpfs staging feature documentationdoc/WEB_PLATFORM.md— Self-hosted web UI / API (rosbackup-web), reverse-proxy TLS, and the HTTP APIdoc/NETWORKING.md— Container network profiles (bridge/NAT66 vs macvlan native address) with diagramsdoc/DEPLOY.md— Docker Compose deploy (registry pull + local build), TLS, profilesdoc/INSTALLATION-METHODS.md— Non-Docker installs: pip (registry), single-file zipapp, from sourcedoc/WEB_STYLE_GUIDE.md— Web UI design system (tokens, components; repo-only, not served)doc/DESIGN_REFERENCE.md— Architecture and developer documentationtestlab/README.md— Self-contained libvirt RouterOS test lab (dual-stack virtual routers)
Prerequisites
- Docker Engine + Compose v2 — or Python 3.9+ for the other install methods
- RouterOS devices with SSH access enabled
- An SSH key pair for the backup user (see BOOTSTRAP)
- RouterOS v7.7 or later for tmpfs staging (falls back to flash on older versions)
Deploy with Docker
The supported way to run the web platform is the Docker Compose stack under deploy/ — it
pulls a pre-built image from the registry, with a local build as fallback:
git clone https://git.jdneer.com/jd/rosbackup-ng /opt/rosbackup-ng && cd /opt/rosbackup-ng/deploy
sudo ./deploy.sh up # first run scaffolds .env + ./config, pulls the image
$EDITOR config/global.yaml config/targets.yaml
sudo ./deploy.sh set-password # set the admin password once
sudo ./deploy.sh up # idempotent — re-run anytime
TLS (DNS-01 / manual cert), the two network profiles (bridge/NAT66 vs macvlan), updates, and the full
deploy.sh command reference are in doc/DEPLOY.md and
doc/NETWORKING.md.
Prefer not to use Docker? pip (from the package registry), a single-file zipapp, and from-source installs are in
doc/INSTALLATION-METHODS.md.
Configuration
See doc/CONFIG_REFERENCE.md for the full reference. A minimal
global.yaml:
# Parent directory for storing backups (required)
backup_path_parent: backups
# Days to keep backups; omit or null to disable pruning (optional)
#backup_retention_days: 90
# Global backup password (optional; used when a target sets `encrypted: true`)
backup_password: your-global-backup-password
ssh:
user: rosbackup # default SSH username
#known_hosts_file: null # default: <config-dir>/known_hosts
#add_target_host_key: true # true = trust-on-first-use; false = strict
# Resilient connect for flaky / overlay links (e.g. ZeroTier). On by default.
connect_retry:
total_timeout: 180 # retry window in seconds (0 = fail fast)
#initial_delay: 5
#max_delay: 30
args:
keepalive_interval: 60 # keep long backups alive across NAT/overlay timeouts
tmpfs:
enabled: true # stage binary backups in RAM to reduce flash wear
fallback_enabled: true # fall back to flash if tmpfs can't be used
# Email notifications (nested schema). Additional channels plug in under notifications.*
#notifications:
# enabled: true
# notify_on_failed_backups: true
# smtp:
# enabled: true
# host: smtp.example.com
# port: 587
# use_tls: true
# from_email: backups@example.com
# to_emails: [ops@example.com]
# Named groups for scoped runs (-g/--group) and storage routing
#groups:
# - name: critical
# match_tags: [critical] # dynamic: any target tagged "critical"
# - name: hq
# members: [ROUTER-1] # explicit member list
# Mirror backups to additional destinations (local kept by default)
#storage:
# - name: dr-sftp
# type: sftp
# host: sftp.example.com
# user: rosbackup
# private_key: ./ssh-keys/private/id_offsite
# remote_path: /srv/backups/routeros
# groups: [critical] # route by group name or tag
# Web platform capability toggles (only affect rosbackup-web; both default true)
#web:
# allow_download: true
# allow_restore: true
A minimal targets.yaml:
targets:
- name: ROUTER-1
enabled: true
host: 192.168.88.1
description: "HQ core router, rack A03" # free-text metadata (optional)
tags: [site-hq, core, critical] # labels for groups/--tag (optional)
ssh:
private_key: ./ssh-keys/private/id_rosbackup
See doc/CONFIG_REFERENCE.md for per-target overrides
(encryption, retention, tmpfs, per-target connect_retry, keeping backups on the router,
storage routing, web capability overrides, etc.).
Usage
# Back up all enabled targets
rosbackup
# A specific target only
rosbackup --target ROUTER-1
# A named group or a tag (selectors are mutually exclusive with --target)
rosbackup --group critical
rosbackup --tag site-hq
# Discover configured groups/tags with device counts
rosbackup --list
# Scale-aware compose-style output
rosbackup --compose-style
# Validate connectivity/access without writing anything
rosbackup --dry-run
Compose-style output
--compose-style (-x) renders a live view that scales from a handful of routers to
thousands. Small fleets get a per-row view:
[+] Executing backup for 4 targets ...
✔ ROUTER1 Finished 3.8s
✔ ROUTER2 Finished 3.8s
⠹ ROUTER3 Backing Up 2.1s
⠹ ROUTER4 Connecting 0.6s
Summary:
Total time: 3.9s
Total size: 107.0KB
Success: 4 | Failed: 0 | Total: 4
Large fleets automatically switch to an aggregate dashboard — a live progress bar, success/failure/running counts, throughput-based ETA, the currently-running window, and a failures tail:
[+] Backing up 5000 targets
██████████░░░░░░░░░░░░░░░░░░░░ 1640/5000 33% ✔ 1628 ✘ 12 ⠹ 48 running 2m14s eta 4m31s
Active:
⠹ router-1641 Backing Up 1.2s
⠼ router-1642 Getting Info 0.4s
… and 46 more running
Recent failures:
router-0044, router-0210
State updates are O(1) and rendering is O(visible rows), so the view stays responsive regardless of fleet size.
Other examples
rosbackup --no-parallel # sequential
rosbackup --max-parallel 10 # cap concurrency
rosbackup --log-level DEBUG # verbose
rosbackup --no-tmpfs # disable tmpfs staging for this run
rosbackup --tmpfs-size-mb 25 # override tmpfs size for this run
rosbackup --log-file backups.log # also write a 0600 log file
Bootstrap (provisioning a router)
Create the backup user and install its key on a device (see doc/BOOTSTRAP.md):
# Generate a key pair for the backup user
ssh-keygen -t ed25519 -f ssh-keys/private/id_rosbackup
# Provision a router (prompts for the existing admin password)
rosbackup-bootstrap -H 192.168.88.1 -k ssh-keys/private/id_rosbackup.pub
# See exactly what it would do, without changing anything
rosbackup-bootstrap -H 192.168.88.1 -k ssh-keys/private/id_rosbackup.pub --dry-run
Web platform
rosbackup-web is a self-hosted UI + HTTP API that reads the same config directory as the CLI
(dashboard pictured above). Deploy it with the Docker stack
(doc/DEPLOY.md); to run it without Docker, see
doc/INSTALLATION-METHODS.md. Once it's installed:
rosbackup-web -c /etc/rosbackup --set-password # set the admin password once
rosbackup-web -c /etc/rosbackup # serve on 127.0.0.1:8474
It gives you a dashboard, targets inventory (table + cards), run-now with live progress,
schedules, a backup browser with download + push-restore, firmware upgrades, an encrypted
Vault for SSH keys and passwords, API tokens, and an audit log. Bind it to localhost and
terminate TLS at a reverse proxy (sample Caddyfile + systemd unit under
doc/examples/).
Full details — auth, the Vault, schedules, push-restore, capability toggles, the API, and the
single-file build — are in doc/WEB_PLATFORM.md.
Command completion
Enable bash completion for the current shell session:
source scripts/rosbackup-ng-completion.bash
It provides option, file-path, and target-name completion (from targets.yaml) for the
rosbackup and rosbackup-bootstrap commands.
Logging
Console logging is colored via rich. With --log-file, logs are also written to a file
(created 0600) including backup status, connection details, retries, and errors. Format:
MM-DD-YYYY HH:MM:SS [LEVEL] [target] message.
Development
pip install -e ".[dev,web]"
ruff check src tests && ruff format --check src tests
mypy src
bandit -q -r src
pytest -q
CI runs this same battery on every push via self-hosted Forgejo
Actions (.forgejo/workflows/ci.yml),
deliberately using no external/marketplace actions — every step is hand-written shell.
Before pushing, run the whole gate in one shot with a venv that matches CI's resolved
dependencies — this catches the failures a pytest-only check misses (ruff/format/bandit, and
runner-environment flakes):
scripts/ci-local.sh # ruff -> format -> mypy -> bandit -> pytest -> shiv build + smoke
scripts/ci-local.sh --fresh # rebuild the .civenv from scratch first
It runs every gate (not just the first failure) and exits non-zero if any fails. The .civenv
it creates is gitignored and reused across runs.
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Run the checks above (they must all pass)
- Commit and open a Pull Request
License
This project is licensed under the MIT License — see the LICENSE file for details.
Support
Open an issue or send a PR.
