86 lines
4.9 KiB
Markdown
86 lines
4.9 KiB
Markdown
# Deployment
|
|
|
|
## Runtime and configuration
|
|
|
|
The production executable is the Rust server, built with `cargo build --locked
|
|
--release`. SQLite is bundled into the executable. The Go implementation remains
|
|
in `cmd/balance-server` and `internal/` as a compatibility reference and rollback
|
|
option; build it with `go build -o balance-server-go ./cmd/balance-server`.
|
|
|
|
The Dockerfile uses a Rust 1.90 Debian Bookworm builder and a Debian Bookworm slim
|
|
runtime, running as the unprivileged `balance` user. The image embeds the existing
|
|
web client and uses no separate frontend process. Build dependencies and SQLite
|
|
are compiled at image build time.
|
|
The numeric identity remains UID 100 / GID 101, matching the original Alpine Go
|
|
image, so existing volume permissions are preserved across the switch.
|
|
|
|
`docker compose up -d --build` publishes **http://localhost:8123** (host 8123,
|
|
container 8080). `GET /health` is the liveness endpoint. Direct binary execution
|
|
uses `:8080` by default. Place a TLS reverse proxy in front of the published port
|
|
for remote access; pass `X-Forwarded-Proto: https` to enable Secure session cookies.
|
|
|
|
| Variable | Default | Purpose |
|
|
| --- | --- | --- |
|
|
| `BALANCE_ADDR` | `:8080` | HTTP listen address |
|
|
| `BALANCE_DB_PATH` | `./data/balance.db` | SQLite file; Docker uses `/data/balance.db` |
|
|
| `BALANCE_JWT_SECRET` | required | At least 32 characters; retain across migration |
|
|
| `BALANCE_ACCESS_TTL` | `15m` | Go-style duration for access tokens |
|
|
| `BALANCE_REFRESH_TTL` | `720h` | Go-style duration for refresh tokens |
|
|
| `BALANCE_ALLOW_REGISTRATION` | `true` | Enable creation of accounts |
|
|
| `BALANCE_CORS_ORIGINS` | empty | Comma-separated allowed browser origins |
|
|
|
|
Inject secrets through the deployment environment or `.env`; never put them in
|
|
images or source control. Compose preserves the existing named `balance-data`
|
|
volume mounted at `/data`. Keep that volume and its project name when upgrading.
|
|
|
|
## Go to Rust migration
|
|
|
|
1. Build and validate the Rust binary/image before stopping production. Retain the
|
|
previous Go executable/image and exact environment for rollback.
|
|
2. Stop the Go service and confirm no other process writes its SQLite database.
|
|
3. Back up the entire database directory, including `balance.db` and any
|
|
`balance.db-wal`/`balance.db-shm` files. Protect the backup as financial data.
|
|
Record the existing environment securely, especially `BALANCE_JWT_SECRET`.
|
|
4. Start Rust with the **same database path/volume and JWT secret**. The schema is
|
|
unchanged: startup creates missing tables and indexes without rewriting
|
|
existing accounts, records, change sequences or refresh-token hashes.
|
|
5. Check `/health`, login with an existing account, refresh an existing session,
|
|
and sync a device with its saved cursor. Verify another device receives edits
|
|
and tombstones. Inspect error rates without logging credentials or tokens.
|
|
|
|
The existing Argon2id password hashes, HS256 JWT claims, hashed refresh tokens,
|
|
RFC3339 timestamps, entity versions and global change sequences are shared with
|
|
Go. No export/import, cursor reset, account recreation or forced sign-out is
|
|
required. Do not start both implementations against the same database at once.
|
|
|
|
## Rollback
|
|
|
|
Stop Rust first. Start the retained Go executable/image with the same current
|
|
database directory and secret. Rust-written accounts, password hashes, refresh
|
|
sessions, records, tombstones and cursors remain readable by Go. Check health,
|
|
login, refresh and sync again. The compatibility suite exercises both directions,
|
|
including a second takeover back to the original implementation.
|
|
|
|
For database corruption or an unrelated failed migration, stop all writers before
|
|
restoring the complete backup directory. Restoring an older backup discards
|
|
changes after that backup and may require clients to resynchronize; prefer normal
|
|
binary rollback against the current database when it is healthy. Never overwrite
|
|
an active database or delete a Compose volume as part of an upgrade.
|
|
|
|
## Validation and operations
|
|
|
|
Before release run `cargo test --locked`, `cargo build --locked --release`,
|
|
`python3 tools/compatibility.py --rust-binary target/release/balance-server`, and
|
|
the retained reference checks `go test ./...`, `go vet ./...`, `go build ./...`.
|
|
The differential suite uses temporary databases and loopback listeners, compares
|
|
API/errors/security headers/assets, tests browser cookies, pagination, LWW,
|
|
tombstones, concurrent pushes, token expiration, refresh rotation, rate limiting,
|
|
and shared-database takeover/rollback in both directions.
|
|
|
|
Keep regular encrypted backups with retention and restore drills. Monitor HTTP
|
|
5xx, sync errors, authentication failures, latency, database/change-log growth
|
|
and free disk space. The in-memory limiter allows 30 registration/login/refresh
|
|
attempts per remote IP per minute and resets on restart; use proxy controls when
|
|
operating a public service. Application logs must never include passwords,
|
|
Authorization headers or tokens.
|