jd

rosbackup-ng (0.8.1)

Published 2026-06-23 06:55:54 +00:00 by jd in jd/rosbackup-ng

Installation

pip install --index-url  rosbackup-ng

About this package

Automated, resilient RouterOS backup utility (binary + plaintext, parallel, tmpfs-staged)

RouterOS Backup NG

CI License: MIT Python 3.9+ Code style: ruff Types: mypy

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.

rosbackup-ng web dashboard

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 (and s3 via 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, 0600 files, and log redaction.

See doc/FEATURES.md for the full (non-exhaustive) feature list.

Documentation

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

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Run the checks above (they must all pass)
  4. 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.

Requirements

Requires Python: >=3.9
Details
PyPI
2026-06-23 06:55:54 +00:00
1
rosbackup-ng contributors
MIT License Copyright (c) 2025 JD Bungart <me@jdneer.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
542 KiB
Assets (2)
Versions (2) View all
0.8.1 2026-06-23
0.8.0.dev2 2026-06-23