Files
2026-10-28 09:16:54 +01:00

180 lines
5.5 KiB
Markdown

# MikroTik Backup System
Version **0.0.1** is the initial Rust rewrite of the previous Python/TypeScript application. It is a single self-hosted service with an embedded web UI, SQLite storage, RouterOS/SwOS backup workflows, scheduling, retention, notifications, and local OpenAPI documentation.
## Quick start
### Docker Compose
```bash
docker compose build app
docker compose up -d
```
The default published address is `127.0.0.1:5581`. Persistent application data is stored in the `data` volume.
The image uses `rust:1.99.1-alpine3.24` for the build stage and `alpine:3.24` for runtime. The service runs as UID/GID `10001` with a read-only root filesystem.
### Native build
Requires Rust 1.99.1 or compatible toolchain and the native dependencies needed by the crates in `Cargo.lock`.
```bash
cargo build --release --locked
./target/release/mikrotik-backup serve
```
Or use the launcher:
```bash
./start.sh
```
## First account
Registration is disabled by default. Set `DEFAULT_ADMIN_PASSWORD` before first startup, or let the application create the initial administrator password file under `DATA_DIR/secrets/initial-admin-password`.
New installations and new accounts default to **English**. Imported accounts preserve their saved language preference. The UI also supports Polish, Spanish, and Norwegian.
## Main configuration
| Variable | Default | Purpose |
| --- | --- | --- |
| `DATA_DIR` | `./storage` | Database, backups, secrets, SSH known hosts |
| `DATABASE_PATH` | `<DATA_DIR>/routeros_backup_next.db` | SQLite database path |
| `LISTEN_ADDR` | `127.0.0.1:5581` | HTTP listener |
| `API_PREFIX` | `/api` | API base path |
| `TIMEZONE` | `Europe/Warsaw` | Scheduler timezone |
| `SECRET_KEY` | generated/persisted when absent | JWT signing secret |
| `ALLOW_REGISTRATION` | `false` | Allow account registration |
| `DEFAULT_ADMIN_USERNAME` | `admin` | Initial administrator name |
| `DEFAULT_ADMIN_PASSWORD` | empty | Initial administrator password |
| `SSH_HOST_KEY_POLICY` | `accept-new` | `accept-new` or `strict` |
| `SSH_TIMEOUT_SECONDS` | `30` | Device SSH timeout |
| `MAX_PARALLEL_BACKUPS` | `4` | Concurrent backup limit |
| `CORS_ORIGINS` | `[]` | Explicit allowed HTTP(S) origins |
Run configuration validation without starting the server:
```bash
./target/release/mikrotik-backup check-config
```
## Data layout
```text
DATA_DIR/
├── routeros_backup_next.db
├── backups/
│ ├── exports/<device-id>/
│ └── binary/<device-id>/
├── secrets/
└── ssh/
```
RouterOS text exports are stored under `backups/exports`; binary RouterOS backups and SwOS `.swb` files are stored under `backups/binary`.
## Legacy Python/TypeScript import
The importer is explicit and never runs during normal startup. Stop the old application first and import into a **new** Rust destination.
```bash
./import-python.sh /srv/mikrotik-backup-old
```
Docker Compose example:
```bash
docker compose run --rm \
-v /srv/mikrotik-backup-old:/legacy:ro \
app import-python --source /legacy
```
The importer copies accounts, devices, settings, logs, backup metadata, and every referenced backup file. It validates existing backup checksums when present and refuses to publish an incomplete destination. See [docs/migration.md](docs/migration.md).
## RouterOS and SwOS
RouterOS uses SSH-based export/backup operations. SwOS uses its web interface and downloads `/backup.swb`, with Digest authentication first and Basic as fallback. Connection testing distinguishes general web reachability from backup-endpoint availability.
SwOS details and troubleshooting are in [docs/switchos.md](docs/switchos.md).
## Configuration comparison
`.rsc` files support:
- side-by-side and unified diff;
- changed-lines-only mode and search;
- paged browser rendering to limit DOM size;
- semantic RouterOS analysis that groups changes by configuration section and identifies added, removed, and modified commands/fields;
- masking of sensitive values in semantic summaries.
Binary backups are not diffed.
## Embedded web assets and caching
`build.rs` combines the UI sources listed in `web/assets.list`. Each compiled CSS/JavaScript bundle receives a content hash in its filename, for example:
```text
/assets/app.<hash>.js
/assets/app.<hash>.css
/assets/docs.<hash>.js
/assets/docs.<hash>.css
```
The HTML shell is generated with those exact filenames. Hashed assets use:
```text
Cache-Control: public, max-age=31536000, immutable
```
HTML and API responses remain non-cacheable by default. `/favicon.ico` intentionally returns `204 No Content`.
## API documentation
Interactive local documentation:
```text
/docs
```
OpenAPI JSON:
```text
/openapi.json
```
Swagger UI is embedded locally and does not require a CDN.
## Validation
Frontend unit tests:
```bash
node web/tests/core.test.cjs
```
JavaScript syntax:
```bash
node --check web/js/i18n.js
node --check web/js/core.js
node --check web/js/views.js
node --check web/js/app.js
```
Rust checks when a toolchain is available:
```bash
cargo fmt --check
cargo test --locked
cargo clippy --locked --all-targets -- -D warnings
```
The browser smoke tests under `web/tests/` require Playwright.
## Security and dependencies
The service uses request size/time limits, JWT validation, password hashing, SSH host-key verification, secret redaction, restricted filesystem permissions, and a non-root container runtime. Dependency audit notes and the local `libssh2-sys` patch provenance are summarized in [docs/security.md](docs/security.md).
Third-party license notices are in `docs/THIRD_PARTY_NOTICES.txt`.