docs(installer): add the operator install guide (Phase 0.4)

Closes the last Phase 0 item. INSTALL.md is written before the installer
binary on purpose: everything it installs is already released (0.1-0.3), so
the guide is not speculation about a tool that might exist - it is the
specification of what the run asks, where it writes, what it prints, and what
the operator does next.

It is useful today. Appendix A is the same deployment done by hand - bundle
fetch, tarball verify and overlay copy, the optional patch tier,
--print-config provisioning, systemd unit / sc create - composed from the
released artifacts' actual contents and the sidecar's config and CLI source.
That appendix doubles as Phase 1's acceptance test.

Writing it settled four things the plan had left implicit, now recorded in
PLAN.md:

- The installer does not install itself; day-two commands run from the
  downloaded binary.
- The flag surface: --servuo, --patches/--no-patches, --host, --site-url and
  --yes join the --verify/--bundle/--purge the plan already named, so every
  prompt has a non-interactive equivalent.
- A modified Config/Bridge.cfg is reported, not overwritten - one deliberate
  deviation from deploy.ps1, whose overwrite-on-hash-differs rule is right for
  a developer and would silently revert an operator's whole shard config on
  update. install.json's recorded hashes are what make the distinction
  possible.
- Remote-website deployments: widen [web] bind, firewall it to the site's
  address, front it with TLS or a VPN off a trusted network. [shard] bind
  stays on loopback because that socket carries commands into the game.

Also adds the missing installer/ section to the docs index, and refreshes two
stale examples in PLAN.md (overlay file count, sidecar version).

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-04 11:39:02 -05:00
parent fc79bb6ed0
commit 5c8585fe75
3 changed files with 753 additions and 17 deletions

View File

@@ -1,19 +1,19 @@
# Runic Gateway Installer — plan
Status: **Phase 0 all but complete** — every prerequisite in another repo has landed, and the
installer repo now publishes the bundle manifest, so *what* the installer will install is already
released and composed ahead of the binary that installs it. No installer code exists yet; `0.4`
(`INSTALL.md`) is the remaining item, then Phase 1. This document is the design of record;
it supersedes the informal overview it grew out of, which described a ServUO integration that does
not match how `servuo-plugins` actually ships (see
Status: **Phase 0 complete.** Every prerequisite in another repo has landed, the installer repo
publishes the bundle manifest, and [`INSTALL.md`](INSTALL.md) now specifies the operator-facing run
— so *what* the installer installs and *what using it looks like* both exist ahead of the binary.
No installer code exists yet; **Phase 1 is next.** This document is the design of record; it
supersedes the informal overview it grew out of, which described a ServUO integration that does not
match how `servuo-plugins` actually ships (see
[Corrections](#corrections-to-the-original-overview)).
| Phase 0 item | State |
|---|---|
| 0.1 `servuo-plugins` release workflow | ✅ Merged — [servuo-plugins#7](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins/pulls/7) + [#8](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins/pulls/8); first overlay release is [`v0.1.1`](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins/releases/tag/v0.1.1) |
| 0.2 `link` installable (data paths + `--print-config`) | ✅ Merged — [link#24](https://gitea.whitlocktech.com/RunicGateway/link/pulls/24) (docs half [docs#84](https://gitea.whitlocktech.com/RunicGateway/docs/pulls/84)); released as [`v1.1.0`](https://gitea.whitlocktech.com/RunicGateway/link/releases/tag/v1.1.0) |
| 0.3 Bundle CI in the installer repo | 🟨 In review — [installer#3](https://gitea.whitlocktech.com/RunicGateway/installer/pulls/3), plus the dispatch step in each component ([link#25](https://gitea.whitlocktech.com/RunicGateway/link/pulls/25), [servuo-plugins#9](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins/pulls/9)). First bundle: `2026.08.04` |
| 0.4 This file + `INSTALL.md` | 🟦 This file exists; `INSTALL.md` is **next** the shape has now settled |
| 0.3 Bundle CI in the installer repo | ✅ Merged — [installer#3](https://gitea.whitlocktech.com/RunicGateway/installer/pulls/3), plus the dispatch step in each component ([link#25](https://gitea.whitlocktech.com/RunicGateway/link/pulls/25), [servuo-plugins#9](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins/pulls/9)). First bundle: [`2026.08.04`](https://gitea.whitlocktech.com/RunicGateway/installer/src/branch/main/bundles/current.json) |
| 0.4 This file + `INSTALL.md` | ✅ [`INSTALL.md`](INSTALL.md) — the operator guide, written before the binary because it *is* the specification of the run |
| — Repo bootstrap (governance + CI) | ✅ [`RunicGateway/installer`](https://gitea.whitlocktech.com/RunicGateway/installer) created; workflows merged ([installer#1](https://gitea.whitlocktech.com/RunicGateway/installer/pulls/1), [#2](https://gitea.whitlocktech.com/RunicGateway/installer/pulls/2)) |
---
@@ -180,7 +180,7 @@ Runic Gateway Installer v1.0.0
├── runicgateway-installer-linux-x86_64
└── SHA256SUMS
uo-link v0.x.y (existing release, extended)
uo-link v1.1.0 (existing release, extended)
├── uo-link-sidecar-windows-x86_64.exe
├── uo-link-sidecar-linux-x86_64
├── runicgateway-link_<ver>_amd64.deb (Phase 5)
@@ -337,12 +337,48 @@ Repo work that must land before an installer can exist.
4. **`docs`: this file, plus `docs/installer/INSTALL.md`** (the operator-facing guide) once the
shape is settled.
As built ([`INSTALL.md`](INSTALL.md)) — written *before* the binary on purpose. Everything it
installs is already released (items 13), so the guide is not speculation about a tool that
might exist; it is the specification of what the run asks, where it writes, what it prints, and
what the operator does next. Phase 14 implement it.
- **It is useful before the installer exists.** Appendix A is the same deployment done by hand —
bundle fetch, tarball verify + overlay copy, the optional patch tier, `--print-config`
provisioning, and a systemd unit / `sc create` service — composed from the released artifacts'
actual contents and the sidecar's config and CLI source rather than from memory. That appendix
doubles as **Phase 1's acceptance test**: walking it end to end on a real shard is what proves
the automated path has nothing left to discover.
- **The installer does not install itself.** §5's `runicgateway doctor` sketch implied a name on
`PATH`; nothing places one there, and adding self-installation would give the tool a second
lifecycle to manage. The guide names the downloaded artifact, says to keep it, and shortens it
in later examples.
- **The flag surface got fixed here**, because a guide cannot describe a run in the abstract:
`--verify`, `--bundle`, `--purge` were already named by §5/§7; `--servuo`, `--patches` /
`--no-patches`, `--host`, `--site-url` and `--yes` are the remainder, chosen so every prompt
in §6's handoff has a non-interactive equivalent and an unattended install is expressible.
- **A modified `Bridge.cfg` must survive an update** — see Phase 1, where this changes the sync
rule inherited from `deploy.ps1`.
- **Remote-website deployments needed an answer.** `[web] bind` defaults to `127.0.0.1`, which
only works when the site runs on the shard host. The guide says to widen it, firewall it to
the website's address, and front it with TLS or a VPN off a trusted network — because the
token is always required but travels as a plain bearer token over HTTP. `[shard] bind` stays
on loopback, since that socket carries inbound commands *into* the game.
### Phase 1 — installer core
- ServUO root detection and validation (`ServUO.exe`, `Scripts/`, `Config/`), with version detection
and an explicit refusal when the ServUO process is running.
- Overlay sync: fetch tarball → verify SHA256 → hash-compare against the server tree → add/change,
**never delete**. Port of `deploy.ps1` semantics including its `-Verify` dry run (`--verify`).
- **One deviation from `deploy.ps1`: an operator-modified `Config/Bridge.cfg` is reported, not
overwritten.** `deploy.ps1` overwrites every file whose hash differs, which is right for a
developer redeploying their own tree and wrong for an operator who has set `LinkUrl`,
`PublicConnectAddress` and sweep intervals — an `update` would silently revert the shard's entire
configuration. `install.json` records the hash deployed, so the installer can distinguish "the
operator edited this" from "the overlay moved on" (§7.0) and act only on the second. The rule is
specific to `Bridge.cfg`: it is the only file in the overlay that is *meant* to be edited in
place, and it carries no code, so a stale copy cannot break the build. Every `.cs` file and
`Scripts.csproj` still overwrite unconditionally.
- Write `install.json`: component, version, source commit, per-file hashes, applied patches,
timestamp.
- Idempotent re-runs; a second run with no upstream change reports "unchanged" and writes nothing.
@@ -370,9 +406,9 @@ degrade loudly rather than silently.
```
✓ ServUO found /opt/ServUO (57.4)
✓ Overlay in sync 30 files, all hashes match install.json
✓ Overlay in sync 24 files, all hashes match install.json
⚠ Patch tier 1 of 3 applied — vendor.sale unavailable
✓ uo-link installed 0.3.0
✓ uo-link installed 1.1.0
✓ Service running, enabled
✓ Sidecar reachable 127.0.0.1:8080 /health ok
✓ Protocol sidecar 3 = overlay manifest 3
@@ -393,8 +429,9 @@ deliberately:
- **uo-link**: compare the bundle's version against what is installed → download → verify checksum →
replace binary → restart service.
- **plugin overlay**: download the bundle's overlay tarball → verify → re-sync → record commit →
tell the operator ServUO must restart (the installer does not restart the shard).
- **plugin overlay**: download the bundle's overlay tarball → verify → re-sync (leaving a modified
`Bridge.cfg` alone — Phase 1) → record commit → tell the operator ServUO must restart (the
installer does not restart the shard).
Because both come from one bundle, an update always moves to a combination whose protocol versions
were checked together, rather than to two independently-latest artifacts that may disagree.