120 lines
5.0 KiB
Markdown
120 lines
5.0 KiB
Markdown
# Backup Tool v2
|
||
|
||
> A self-hosted, integrity-first backup appliance for local and hardened SSH sources.
|
||
|
||
Backup Tool creates signed, content-addressed backups, supports encrypted repositories and offline recovery, and runs as isolated web, scheduler, worker, migration, and admin roles. v2.0 supports **local** and **SSH** sources, local repositories, restore, encrypted recovery, email, and signed webhooks.
|
||
|
||
## What is supported
|
||
|
||
- Signed full and incremental backups, restore, retention, verification, and recovery.
|
||
- AES-256-GCM repository encryption with key epochs and offline Argon2id recovery bundles.
|
||
- Local sources and SSH sources using **private-key-only, pinned-host-key, forced-SFTP chroot** access.
|
||
- Durable, at-least-once webhook and STARTTLS SMTP notifications.
|
||
- A generated OpenAPI TypeScript client and operator UI.
|
||
|
||
Never use an SSH source with a shell, password, agent forwarding, remote commands, or an unchrooted account. See [SSH source requirements](docs/runbooks/ssh-sources.md).
|
||
|
||
## Quick local verification
|
||
|
||
Prerequisites: Docker Compose, Python 3.12–3.14, Node/npm, and a working virtual environment.
|
||
|
||
```sh
|
||
make setup
|
||
make check
|
||
make test-e2e
|
||
make test-ssh-integration
|
||
```
|
||
|
||
`make test-e2e` creates temporary test-only keys and source data, starts the complete Compose stack, checks readiness/metrics/restart behavior, and tears it down. `make test-ssh-integration` builds a separate forced-SFTP fixture and verifies key-authenticated SSH probe, backup, verification, and restore.
|
||
|
||
## Run locally with Docker Compose
|
||
|
||
The production Compose topology binds the proxy to `127.0.0.1:8080`; put a TLS reverse proxy in front of it for remote access.
|
||
|
||
```sh
|
||
mkdir -p secrets sources
|
||
head -c 32 /dev/urandom > secrets/master.key
|
||
chmod 600 secrets/master.key
|
||
# The container runs as UID 10001; grant that UID read access to the key.
|
||
chown 10001:10001 secrets/master.key
|
||
|
||
# Put test source data below ./sources, then start the isolated roles.
|
||
docker compose build --pull
|
||
docker compose run --rm migrate upgrade
|
||
docker compose up -d
|
||
curl -fsS http://127.0.0.1:8080/readyz
|
||
curl -fsS http://127.0.0.1:8080/metrics
|
||
```
|
||
|
||
On a fresh non-loopback deployment, set `BACKUP_TOOL_PUBLIC_BASE_URL` to the externally reachable HTTPS URL and set `BACKUP_TOOL_BOOTSTRAP_SECRET` before first setup. Never expose a fresh setup endpoint without bootstrap protection.
|
||
|
||
Stop the local stack with:
|
||
|
||
```sh
|
||
docker compose down
|
||
# Add --volumes only when intentionally discarding local metadata and repositories.
|
||
```
|
||
|
||
## Operator workflow
|
||
|
||
1. Open `http://127.0.0.1:8080` and create the first administrator.
|
||
2. Create a local or encrypted repository.
|
||
3. Create a local source, or configure a hardened SSH source as documented in [SSH sources](docs/runbooks/ssh-sources.md).
|
||
4. Create a job, run a probe, enqueue a backup, verify it, then perform a test restore.
|
||
5. Configure notification subscriptions and test them before relying on delivery.
|
||
6. Export and validate a recovery bundle after encrypted repository creation and each key rotation.
|
||
|
||
The browser exposes recovery status and the CLI procedure only; it never transfers recovery bundles or passphrases.
|
||
|
||
## Configuration
|
||
|
||
Compose supplies the core runtime variables. The important host paths are:
|
||
|
||
| Setting | Compose value | Purpose |
|
||
| --- | --- | --- |
|
||
| `BACKUP_TOOL_MASTER_KEY_FILE` | `/run/backup-tool-secrets/master.key` | Service-owned `0600` master key |
|
||
| `BACKUP_TOOL_SOURCES_DIR` | `./sources` | Read-only local-source bind mount |
|
||
| `BACKUP_TOOL_PUBLIC_BASE_URL` | `http://localhost:8080` | External URL and bootstrap policy |
|
||
| `BACKUP_TOOL_PORT` | `8080` | Loopback proxy port |
|
||
|
||
Use absolute, allowlisted paths for repositories, sources, and restores. The service rejects unsafe paths, symlinks where they violate the contract, missing key files, and non-current schemas.
|
||
|
||
## Operations and security
|
||
|
||
- [Observability](docs/runbooks/observability.md): readiness, liveness, metrics, and alert response.
|
||
- [Upgrade and rollback](docs/runbooks/upgrade.md)
|
||
- [Disaster recovery](docs/runbooks/disaster-recovery.md)
|
||
- [Recovery bundles](docs/runbooks/recovery-bundle.md)
|
||
- [Repository keys](docs/runbooks/keys.md)
|
||
- [Notifications](docs/runbooks/notifications.md)
|
||
- [SSH sources](docs/runbooks/ssh-sources.md)
|
||
- [Security policies](docs/README.md#security-boundaries)
|
||
|
||
## Development
|
||
|
||
```sh
|
||
make setup
|
||
make test-fast
|
||
make test-integration
|
||
make test-fault
|
||
make test-security
|
||
npm --prefix frontend test -- --run
|
||
npm --prefix frontend exec playwright test
|
||
```
|
||
|
||
OpenAPI and the generated browser client are committed artifacts:
|
||
|
||
```sh
|
||
.venv/bin/python tools/export_openapi.py --check openapi/v2.json
|
||
npm --prefix frontend run api:generate
|
||
git diff --exit-code -- openapi/v2.json frontend/src/api/generated
|
||
```
|
||
|
||
## Release evidence
|
||
|
||
Milestone evidence, the SBOM, provenance, and synthetic scale report live in [docs/release](docs/release/). M15 certification is synthetic metadata certification on the reference CI host; it does not claim a physical 10 TiB transfer.
|
||
|
||
## License
|
||
|
||
MIT — see [LICENSE](LICENSE).
|