37 lines
1.7 KiB
Markdown
37 lines
1.7 KiB
Markdown
# Harbor state recovery
|
|
|
|
Harbor keeps the existing data paths and volumes. `state.json` now uses `schemaVersion: 1`; subscription cache, generated sing-box config and HWID keep their existing filenames.
|
|
|
|
## Atomic writes
|
|
|
|
Persistent files are written to a unique temporary file in the same directory, flushed with `fsync`, closed and atomically renamed over the target. A failure before rename leaves the previous target untouched and removes the temporary file.
|
|
|
|
## Migration
|
|
|
|
On startup, a legacy `state.json` without `schemaVersion` is normalized and migrated to v1. Before replacement Harbor saves the original beside it:
|
|
|
|
```text
|
|
state.json.backup-v0-2026-07-11T12-00-00-000Z
|
|
```
|
|
|
|
The v1 migration preserves existing fields, adds normalized revision, selection and server fields, and does not rename the volume. Older Harbor builds ignore the additional `schemaVersion` field, but the backup is the safest rollback source.
|
|
|
|
## Corrupt JSON
|
|
|
|
If `state.json` cannot be parsed, Harbor renames the exact damaged bytes to:
|
|
|
|
```text
|
|
state.json.corrupt-2026-07-11T12-00-00-000Z
|
|
```
|
|
|
|
It then creates a valid empty v1 state and reports `storage-recovery` through `snapshot.operation`. A corrupt subscription cache is preserved with the same suffix and reported in control logs.
|
|
|
|
Recovery should be performed while Harbor is stopped:
|
|
|
|
1. Copy the whole data directory before changing anything.
|
|
2. Inspect a backup with `jq . <backup-file>`.
|
|
3. Restore only a valid JSON backup to the original filename.
|
|
4. Start Harbor and verify `GET /api/state` before applying or importing anything.
|
|
|
|
Generated config rollback also uses the atomic writer. No automatic recovery tries to guess missing subscription credentials or repair semantically invalid sing-box configuration.
|