HiddenGit private Git · Tor v3 · SSH

Upgrade an older deployment without port drift

The configuration migration is intentionally separate from persistent-state migrations. Its job is to make old .env files converge to the current schema without rewriting repositories, the Soft Serve database, SSH identities, or the Tor onion identity.

Why migration exists

Older HiddenGit releases represented one network fact in several places:

SOFT_SERVE_SSH_PORT ─┬─ Soft Serve listener
                     ├─ host publication
                     └─ health check
ONION_TARGET_PORT ───── Tor target
SOFT_SERVE_SSH_PUBLIC_URL ─ clone hint

That created drift opportunities. Duplicate .env keys were worse: the shell reader and Docker Compose could choose different occurrences. Current schema validation rejects duplicates before Compose executes.

The target model is:

internal SSH = 23231  ← managed constant
       ↑          ↑
       │          └── Tor onion:<ONION_PUBLIC_PORT>
       └───────────── host 127.0.0.1:<LOCAL_SSH_PORT>

1. Stop and back up before upgrading software

A config-only migration does not need application-state mutation, but a software upgrade deserves a recovery point:

./run.sh down
./run.sh backup
./run.sh verify-backup backups/<archive>.tar.age /offline/identity.agekey

Keep the old checkout/tag available as rollback source.

2. Update the source without overwriting .env

Switch to the reviewed release/tag using your normal Git workflow. Never copy env.example on top of the existing deployment file.

3. Preview the config transformation

./run.sh config migrate

The preview:

Warnings about a formerly customized HTTP/Git/stats port mean the old deployment used a topology the new secure default intentionally removes. Decide whether to accept the reduced surface or maintain a reviewed extension; do not hide the warning by inventing a new .env knob.

4. Apply only after reviewing the plan

./run.sh config migrate --apply

If a change is needed, the command first creates a timestamped mode-0600 copy:

.env.pre-config-YYYYmmddTHHMMSSZ

The replacement is written atomically and fsynced. No rollback copy is created when the file is already canonical.

5. Prove convergence

sha256sum .env
./run.sh config migrate --apply
sha256sum .env

The second command should say:

Configuration migration: already canonical
No changes applied; no rollback copy created

The hashes must match. This is the operational definition of migration idempotency.

6. Validate and restart

./run.sh config check
./run.sh doctor
./run.sh up
./run.sh status

Verify local SSH on LOCAL_SSH_PORT and onion SSH on ONION_PUBLIC_PORT.

Rollback

If the declarative migration itself is wrong and services have not been started, restore the private pre-config copy to .env, preserving mode 0600, and use the prior source release. If application state has already been upgraded or changed, use the release-specific recovery procedure rather than assuming an .env rollback reverses database changes.

Unsupported legacy topology

The migration intentionally stops rather than guessing when an old deployment changed an internal invariant such as SOFT_SERVE_DATA_PATH. Capture the old Compose/config, back up state, and design an explicit migration. This is safer than turning every historical implementation detail into a permanent public API.