4.2 KiB
4.2 KiB
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
- Cloned
HangmanLab.Server.T1to/root/HangmanLab.Server.T1onvps.lab. - Authored site-local
.env(not committed). SetCOMPOSE_PROJECT_NAME=hangmanlabso the new project resolves named volumes tohangmanlab_mysql_dataandhangmanlab_backend_dump, matching the volumes created by the old deployment. Added HarborForge vars (HF_*) andWIZARD_PORT=18080. - Verified volume resolution with
docker compose configbefore touching anything live. docker compose pullon the new project to pre-pull all images.docker compose downin the old project directory — without-v, so named volumes were preserved.docker compose up -din the new project directory. All services came up:mysqlhealthy,hf_db_initexited successfully (created theharborforgedatabase idempotently),hf_backendinitially blocked onConfig not readyas expected.- Confirmed data preservation: 13 tables still present in the
hangmanlabdatabase;harborforgedatabase 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 -tclean (pre-existing warnings about conflicting server names are unrelated).- Certbot
--nginx --expandrun over HTTP-01 to add the two new domains to the existing Let's Encrypt certificate coveringhangman-lab.topandapi.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 duplicateserver_namewarnings on reload; moved it out to/root/and re-reloaded.
Frontend / setup flow
- The setup wizard page in
HarborForge.Frontendwas rewritten to ask for the AbstractWizard port at step 1 (via SSH tunnel), test/health, and persist the chosen port inlocalStorage. NoVITE_WIZARD_PORTbuild-time env var is used anymore. - Backend URL is collected at step 3 and written to
localStorageasHF_BACKEND_BASE_URL. For this deployment the browser was pointed athttps://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-wizardimage runs asnonroot(uid/gid65532), but Docker creates thewizard_confignamed volume withroot:rootownership on first use, so the container process had no write permission inside/config. - Hot fix on vps.lab:
chown -R 65532:65532on the host-side volume path. Setup then completed successfully. - Permanent fix (this commit's predecessor
5e601b1): added awizard_initone-shot service usingbusybox, running as root, that chowns/configto65532:65532every time the project comes up. Thewizardservice nowdepends_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.topandhttps://api.hangman-lab.topunchanged and still serving the legacy stack from the same MySQL data.https://hf.hangman-lab.topandhttps://hf-api.hangman-lab.topserving 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
*_initsidecar pattern (busybox+chown) to avoid repeating this incident.