From c5735f31297b55a3eae9d0983825b7031fef6b91 Mon Sep 17 00:00:00 2001 From: orion Date: Wed, 15 Apr 2026 15:46:53 +0000 Subject: [PATCH] docs: add deployment log with 2026-04-15 vps.lab migration entry --- docs/deployment-log.md | 96 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 docs/deployment-log.md diff --git a/docs/deployment-log.md b/docs/deployment-log.md new file mode 100644 index 0000000..6312b9f --- /dev/null +++ b/docs/deployment-log.md @@ -0,0 +1,96 @@ +# Deployment Log + +Running log of notable deployments, migrations, and incidents for +`HangmanLab.Server.T1`. Newest entries on top. Keep entries terse and +strictly non-sensitive (no secrets, tokens, passwords, or internal IPs). + +--- + +## 2026-04-15 — Migrate vps.lab from legacy `HangmanLab` compose to T1 + +**Goal:** replace the old `~/HangmanLab` docker-compose deployment on +`vps.lab` with `HangmanLab.Server.T1`, preserving existing MySQL data, +and expose the HarborForge stack under two new domains. + +**Steps taken** + +1. Cloned `HangmanLab.Server.T1` to `/root/HangmanLab.Server.T1` on + `vps.lab`. +2. Authored site-local `.env` (not committed). Set + `COMPOSE_PROJECT_NAME=hangmanlab` so the new project resolves + named volumes to `hangmanlab_mysql_data` and + `hangmanlab_backend_dump`, matching the volumes created by the old + deployment. Added HarborForge vars (`HF_*`) and + `WIZARD_PORT=18080`. +3. Verified volume resolution with `docker compose config` before + touching anything live. +4. `docker compose pull` on the new project to pre-pull all images. +5. `docker compose down` in the old project directory — **without** + `-v`, so named volumes were preserved. +6. `docker compose up -d` in the new project directory. All services + came up: `mysql` healthy, `hf_db_init` exited successfully + (created the `harborforge` database idempotently), `hf_backend` + initially blocked on `Config not ready` as expected. +7. Confirmed data preservation: 13 tables still present in the + `hangmanlab` database; `harborforge` database created fresh with + 0 tables. + +**Nginx** + +- Added two new server blocks to the existing site file: + - `hf.hangman-lab.top` → `127.0.0.1:${HF_FRONTEND_PORT}` + - `hf-api.hangman-lab.top` → `127.0.0.1:${HF_BACKEND_PORT}` +- `nginx -t` clean (pre-existing warnings about conflicting server + names are unrelated). +- Certbot `--nginx --expand` run over HTTP-01 to add the two new + domains to the existing Let's Encrypt certificate covering + `hangman-lab.top` and `api.hangman-lab.top`. Cloudflare proxy was + temporarily set to DNS-only on the new subdomains during validation, + then re-enabled. +- Certbot left a backup of the old site file in `sites-enabled/` which + caused duplicate `server_name` warnings on reload; moved it out to + `/root/` and re-reloaded. + +**Frontend / setup flow** + +- The setup wizard page in `HarborForge.Frontend` was rewritten to + ask for the AbstractWizard port at step 1 (via SSH tunnel), test + `/health`, and persist the chosen port in `localStorage`. No + `VITE_WIZARD_PORT` build-time env var is used anymore. +- Backend URL is collected at step 3 and written to `localStorage` as + `HF_BACKEND_BASE_URL`. For this deployment the browser was pointed + at `https://hf-api.hangman-lab.top`. + +**Incident: PUT /api/v1/config/harborforge.json → 500** + +- Symptom: during the "Finish setup" step the wizard returned HTTP + 500 on the config PUT. +- Root cause: the `abstract-wizard` image runs as `nonroot` + (uid/gid `65532`), but Docker creates the `wizard_config` named + volume with `root:root` ownership on first use, so the container + process had no write permission inside `/config`. +- Hot fix on vps.lab: `chown -R 65532:65532` on the host-side volume + path. Setup then completed successfully. +- Permanent fix (this commit's predecessor `5e601b1`): added a + `wizard_init` one-shot service using `busybox`, running as root, + that chowns `/config` to `65532:65532` every time the project comes + up. The `wizard` service now + `depends_on: { wizard_init: { condition: service_completed_successfully } }`. + The fix is idempotent and covers fresh installs on any host, not + just vps.lab. + +**Outcome** + +- `https://hangman-lab.top` and `https://api.hangman-lab.top` + unchanged and still serving the legacy stack from the same MySQL + data. +- `https://hf.hangman-lab.top` and `https://hf-api.hangman-lab.top` + serving the HarborForge stack from the same compose project. +- Setup wizard completed end-to-end; admin account created; backend + reachable from the frontend. + +**Follow-ups** + +- None blocking. If future deployments target a distroless service + that writes to a named volume, use the same `*_init` sidecar + pattern (`busybox` + `chown`) to avoid repeating this incident.