docs: Client Setup operator guide; update Client-Connection wiki

Point operators at openfsd-client with honest Phase 0 limits
(12-char JWT host default, A8 short paths, -novoice fallback).
This commit is contained in:
Reese Norris
2026-07-28 23:12:22 -04:00
parent 6621fc5c9b
commit 26dde88213
3 changed files with 341 additions and 8 deletions

View File

@@ -146,7 +146,7 @@ docker compose up -d # pull/build single image; FSD + web
1. Open `http://localhost:8000`
2. Log in with the default admin credentials (printed in container logs on first startup)
3. **Configure Server** — see the [Configuration](https://github.com/renorris/openfsd/wiki/Configuration) wiki
4. Connect a client — [Client Connection Wiki](https://github.com/renorris/openfsd/wiki/Client-Connection)
4. Connect a client — [Client Connection Wiki](https://github.com/renorris/openfsd/wiki/Client-Connection). For modern pilot clients (vPilot first), use **openfsd Client Setup** (`openfsd-client`): operator guide [docs/client-injector/README.md](docs/client-injector/README.md) (Phase 0 = on-disk apply; honest JWT host limits).
### Service selection
@@ -213,3 +213,5 @@ mkdocs serve
## Operator wiki
Tracked source for the GitHub wiki is under [`wiki/`](wiki/) (Deployment, Configuration, Client Connection, Postgres migration).
**Client Setup:** configure user-installed third-party clients for private openfsd networks with auxiliary binary `openfsd-client` — see [docs/client-injector/README.md](docs/client-injector/README.md) and [wiki/Client-Connection.md](wiki/Client-Connection.md).

View File

@@ -0,0 +1,267 @@
# openfsd Client Setup — operator guide
**Product name:** openfsd Client Setup
**Binary:** `openfsd-client`
**Audience:** operators of a private openfsd network who need third-party pilot/ATC clients to connect to that network.
This guide is the operator-facing summary. Design detail lives in
[docs/design/client-runtime-injector.md](../design/client-runtime-injector.md).
Version-pinned reverse-engineering notes live under
[docs/client-injector/research/](research/).
---
## What it is (and is not)
openfsd Client Setup configures **user-installed** third-party FSD/AFV clients
(vPilot first; more adapters later) so they talk to **your** openfsd deployment
instead of the public VATSIM endpoints they ship with.
| Phase 0 (shipped intent) | Not Phase 0 |
|--------------------------|-------------|
| On-disk PE string / config **apply** with reversible backups | In-memory process inject |
| Config rewrite (status URL, cached servers) | Shadow / ephemeral launch (later) |
| Reversible **Revert** + **Health** | PE AFV `ret` disable (research gate **R2**) |
| Launch with client CLI flags (`-novoice`, server override) | Redistributing client installers |
**Honest naming:** Phase 0 is an **on-disk apply + config** tool. Do not market it as
a “runtime-only injector.” Runtime strategies are later roadmap phases only.
---
## Legal
- **Never redistribute** vPilot, xPilot, Euroscope, vatSys, or any other
proprietary client binary, installer, or patched derivative.
- Users must install the client **themselves** from the vendor (e.g.
[vpilot.rosscarlson.dev](https://vpilot.rosscarlson.dev/Download)).
- openfsd tracks **hashes, YAML profiles, research notes, and our code**
never third-party binaries (local extracts go under gitignored `.research/`).
- Product framing: **private openfsd networks you are authorized to operate**.
Do not use Client Setup to deceptively connect patched clients to the public
VATSIM network.
---
## Prerequisites
1. A running openfsd deployment with web (JWT + status feed) and FSD TCP.
2. Optional: openfsd started with **`-afv`** if you want voice retarget (see AFV below).
3. A **user-owned** install of a supported client version (today: **vPilot 3.12.1**,
hash-pinned in the profile).
4. **Quit the client completely** before **Apply** or **Revert**. The tool refuses
when the primary PE is locked / the process is running.
### Build (when the binary is in-tree)
```bash
go build -o openfsd-client ./cmd/openfsd-client
```
`openfsd-client` is an **auxiliary** cmd (like `openfsd-migrate-*`). It is **not**
a flag on the main `openfsd` server binary.
---
## Phase 0 limits (read this before production hostnames)
vPilot 3.12.1 embeds stock JWT and AFV base URLs in the managed PE (`#US` heap).
In-place overwrite has a **fixed UTF-16 payload budget**. That implies hard caps
on how long your public URLs can be **until** free-slot remap (research gate **R1**)
or server short JWT paths (**A8**) are available.
### JWT host length
| JWT path used in the PE | Max **host** (in-place) | Notes |
|-------------------------|------------------------:|-------|
| Default `https://{host}/api/v1/fsd-jwt` | **12** chars | Lab / very short hosts only |
| Prefer short path → fixed `POST /j` | **25** chars | Requires server A8: `/j` must be **getFsdJwt**, not a bare 302 |
| Prefer short path → `/api/fsd-jwt` (if exposed) | **15** chars | A8 readable alias |
| Prefer short path → `/fsd-jwt` (if exposed) | **19** chars | Optional A8 alias |
**Default without `--prefer-short-jwt`:** max host **12** characters for the
canonical `/api/v1/fsd-jwt` path.
**With `--prefer-short-jwt`:** planner prefers short paths (order typically
`/j`, then other A8 aliases) so max host can reach **25** when the servers
`POST /j` invokes the JWT handler **directly**.
| Research / server work | Status (honest) |
|------------------------|-----------------|
| **R1** free-slot `#US` + ldstr remap | **OPEN** — production-length hosts without A8 need this |
| **A8** short JWT paths (fix `/j` + aliases) | Optional companion web change; high leverage for long hosts |
| **R2** PE AFV `ret` disable site | **OPEN** — not used in Phase 0 |
**R1 free-slot remap is still OPEN.** For production long hostnames today, plan on
**A8 short JWT paths** (especially fixed `/j`) and/or short public DNS. Without R1
or working A8, Phase 0 JWT patching is a **short-host lab** path only.
Example hosts that fit default path (≤12): `fsd.ex.co` (9).
Typical FQDNs like `openfsd.example.com` (19) need **`--prefer-short-jwt`** + server
`/j` (or R1).
### AFV (voice)
| Situation | Phase 0 behavior |
|-----------|------------------|
| AFV base URL length **≤ 25** chars total | Prefer **retarget** `#US` to your `AFV_API_PUBLIC_BASE_URL` |
| AFV base URL **> 25** chars | Plan **`-novoice`** launch flag (no voice) |
| Operator chooses no voice | `--force-disable-afv` → launch with **`-novoice`** |
| PE connect-handler `ret` disable | **Not until R2** — do not claim Phase 0 does this |
Examples: `https://v.ex.co` (15) fits; `https://voice.example.com` (25) is at
budget; `https://voice1.example.com` (26) does **not** fit in-place.
openfsd must be running with **`-afv`** (and correct advertise/public base URL)
for retargeted voice to work. Without AFV on the server, use Discord/etc. and
launch with voice disabled.
### status.txt (VATSIM-shaped subset)
Client Setup points the clients network status URL at openfsd:
```text
GET {web-base}/api/v1/data/status.txt
```
That feed is a **VATSIM-shaped subset**, not a byte-identical VATSIM status file.
Operators should know it advertises (among other keys):
| Key | Role |
|-----|------|
| `json3` | JSON data feed URL |
| `url1` | Servers list URL |
| `servers.live` | Live servers list URL |
Exact template: `internal/web/data_templates/status.txt`. Cached server list is
usually also written directly into the client config so auto-download is less
critical after Apply.
---
## Safety: quit before Apply
1. Fully **quit** the client (not minimize).
2. Confirm Client Setup / CLI preflight is green (process not running, PE not locked).
3. Run **plan** (dry) and read blockers / constraints.
4. **apply** only when plan has no blockers you have not accepted.
5. **health** after apply; **revert** if something is wrong.
Half-applied installs should not happen if the engine auto-reverts on health
failure; keep the `.openfsd-bak` / manifest tree intact until you are sure.
---
## CLI examples
GUI (when no subcommand and GUI is built):
```bash
openfsd-client
```
List embedded client profiles:
```bash
openfsd-client list-profiles
```
Detect install / fingerprint:
```bash
openfsd-client detect --client vpilot
# or with explicit path:
openfsd-client detect --client vpilot --install "%LOCALAPPDATA%\vPilot"
```
Dry-run plan (always do this first on a new hostname):
```bash
openfsd-client plan \
--client vpilot \
--install "%LOCALAPPDATA%\vPilot" \
--web-base "https://fsd.ex.co" \
--fsd-host "fsd.ex.co" \
--fsd-port 6809 \
--afv-base "https://v.ex.co"
```
Production-style host with short JWT path preference (server must support A8 `/j`):
```bash
openfsd-client plan \
--client vpilot \
--install "%LOCALAPPDATA%\vPilot" \
--web-base "https://openfsd.example.com" \
--fsd-host "openfsd.example.com" \
--prefer-short-jwt \
--afv-base "https://voice.example.com"
```
Apply / revert / health (quit client first):
```bash
openfsd-client apply --client vpilot --install "%LOCALAPPDATA%\vPilot" \
--web-base "https://fsd.ex.co" --fsd-host "fsd.ex.co" \
--afv-base "https://v.ex.co"
openfsd-client health --client vpilot --install "%LOCALAPPDATA%\vPilot"
openfsd-client revert --client vpilot --install "%LOCALAPPDATA%\vPilot"
```
Launch (after a successful apply; may pass `-novoice` / server override as planned):
```bash
openfsd-client launch --client vpilot --install "%LOCALAPPDATA%\vPilot"
# Force no voice even if AFV URL would fit:
openfsd-client apply ... --force-disable-afv
openfsd-client launch --client vpilot --install "%LOCALAPPDATA%\vPilot"
```
Common flags (all mutate subcommands that need endpoints):
| Flag | Meaning |
|------|---------|
| `--client` | Adapter id (`vpilot`, …) |
| `--install` | Client install directory |
| `--web-base` | openfsd web base (`https://host`) |
| `--fsd-host` / `--fsd-port` | FSD TCP (default port **6809**) |
| `--afv-base` | AFV REST public base (must be ≤25 chars for retarget) |
| `--prefer-short-jwt` | Prefer server short JWT paths (`/j` → max host **25**) |
| `--force-disable-afv` | Plan launch with **`-novoice`**; skip AFV retarget |
Illustrative exit codes (design): `0` ok, `1` usage, `2` hash mismatch, `3` apply
failed (reverted), `4` revert failed, `5` client running / file locked, `6` plan
blockers.
---
## Operator checklist
- [ ] Client installed legally; version hash matches a known profile.
- [ ] Client **fully quit** before Apply / Revert.
- [ ] JWT host fits budget: ≤**12** default, or ≤**25** with `--prefer-short-jwt` + fixed server `/j`.
- [ ] If host is long and R1 is still OPEN: enable A8 short paths on the server **or** shorten DNS.
- [ ] AFV URL ≤**25** chars for retarget; else accept **`-novoice`**.
- [ ] Do not expect PE AFV disable until **R2**.
- [ ] Never ship or mirror vPilot binaries in git, Docker images, or operator dropboxes.
- [ ] After Apply: health check, then one real connect smoke test on the private network.
---
## Related documents
| Document | Role |
|----------|------|
| [docs/design/client-runtime-injector.md](../design/client-runtime-injector.md) | Full design (phases, budgets, A8, research gates) |
| [docs/client-injector/research/vpilot-3.12.1.md](research/vpilot-3.12.1.md) | vPilot 3.12.1 RE notes / fingerprints |
| [wiki/Client-Connection.md](../../wiki/Client-Connection.md) | Operator wiki: connect paths per client |
| [docs/authentication-token.md](../authentication-token.md) | FSD JWT request/response shape |
| [docs/design/afv-server.md](../design/afv-server.md) | openfsd AFV (`-afv`) |
External historical tools (superseded for openfsd docs by `openfsd-client`):
- [renorris/vpilot-patch-utility](https://github.com/renorris/vpilot-patch-utility) (archived)
- [renorris/openfsd-client-patch-utility](https://github.com/renorris/openfsd-client-patch-utility)

View File

@@ -1,6 +1,58 @@
# Client Connection
openfsd supports the modern VATSIM FSD protocol. **Clients using protocol revisions older than `100` (VatsimAuth) are *not* supported.** This includes clients designed to connect to the classic [Marty Bochane FSD2 server](https://github.com/kuroneko/fsd).
openfsd supports the modern VATSIM FSD protocol. **Clients using protocol revisions older than `100` (VatsimAuth) are *not* supported.** This includes clients designed to connect to the classic [Marty Bochane FSD2 server](https://github.com/kuroneko/fsd).
## Primary path: openfsd Client Setup
**Product:** openfsd Client Setup (`openfsd-client`) — monorepo auxiliary binary that configures **user-installed** third-party clients for a private openfsd network.
| | |
|--|--|
| **Operator guide** | [docs/client-injector/README.md](../docs/client-injector/README.md) |
| **Design** | [docs/design/client-runtime-injector.md](../docs/design/client-runtime-injector.md) |
| **vPilot research** | [docs/client-injector/research/vpilot-3.12.1.md](../docs/client-injector/research/vpilot-3.12.1.md) |
### Phase 0 (honest limits)
Phase 0 is **on-disk apply + config** (reversible backups) — **not** in-memory inject.
- **Default JWT path** (`/api/v1/fsd-jwt`): max public host length **12** characters for in-place PE patch.
- **`--prefer-short-jwt`** + server short path **`POST /j`** (A8: handler must be `getFsdJwt`, not a bare 302): max host **25**.
- **R1 free-slot `#US` remap** is still **OPEN** — production long hostnames need **A8 short paths** and/or short DNS until R1 lands.
- **AFV:** retarget voice base if URL **≤ 25** chars; otherwise plan **`-novoice`**. PE AFV disable is **not** until research gate **R2**.
- **Quit the client completely** before Apply / Revert.
- **Never redistribute** vPilot or other proprietary clients; users install from the vendor.
CLI sketch:
```bash
openfsd-client list-profiles
openfsd-client detect --client vpilot
openfsd-client plan --client vpilot --install DIR --web-base URL --fsd-host HOST [--prefer-short-jwt] [--afv-base URL]
openfsd-client apply --client vpilot --install DIR ... # client must be quit
openfsd-client health --client vpilot --install DIR
openfsd-client revert --client vpilot --install DIR
openfsd-client launch --client vpilot --install DIR
```
### status.txt (openfsd subset)
Clients that poll a VATSIM-style status URL should use:
```text
GET {web-base}/api/v1/data/status.txt
```
openfsd serves a **VATSIM-shaped subset** (not a full public VATSIM mirror). Keys of interest include **`json3`**, **`url1`**, and **`servers.live`** pointing at openfsd data/server list feeds. See `internal/web/data_templates/status.txt`.
### Historical external patch tools
Older CLI utilities remain historical references; prefer **`openfsd-client`** for openfsd:
- [vpilot-patch-utility](https://github.com/renorris/vpilot-patch-utility) (archived; vPilot 3.11.1-era)
- [openfsd-client-patch-utility](https://github.com/renorris/openfsd-client-patch-utility)
---
## VRC
@@ -14,19 +66,20 @@ You will need to add an entry to the `myservers.txt` file. See the following sni
>
> `sweatbox.vatsim.net Public Sweatbox`
Newer versions of VRC such as 1.3.0 use the new VATSIM fsd-jwt authentication system. The binary for these newer versions would need to be patched to call the openfsd fsd-jwt URL.
Newer versions of VRC such as 1.3.0 use the new VATSIM fsd-jwt authentication system. The binary for these newer versions would need to be patched to call the openfsd fsd-jwt URL (openfsd Client Setup may gain a VRC adapter later; until then use a versioned external tool carefully).
openfsd JWT endpoints (same VATSIM-shaped body; no redirect): canonical `POST /api/v1/fsd-jwt`, short aliases `POST /j` and `POST /api/fsd-jwt` for PE `#US` URL budgets. See [authentication-token.md](../docs/authentication-token.md) for the max_host table.
## Euroscope
See [here](https://github.com/renorris/openfsd-client-patch-utility).
Primary path when an Euroscope adapter lands: **openfsd Client Setup** (`openfsd-client`). Until then, historical reference:
Some additional 3rd party work can be found here: [github.com/Misaka-Nnnnq/openfsd-patch-for-es](https://github.com/Misaka-Nnnnq/openfsd-patch-for-es)
- [openfsd-client-patch-utility](https://github.com/renorris/openfsd-client-patch-utility)
- Third-party: [github.com/Misaka-Nnnnq/openfsd-patch-for-es](https://github.com/Misaka-Nnnnq/openfsd-patch-for-es)
## vatSys
TODO
TODO (future Client Setup adapter).
## Swift
@@ -41,11 +94,20 @@ TODO
## vPilot
See [vPilot Patch Utility](https://github.com/renorris/vpilot-patch-utility)
**Preferred:** [openfsd Client Setup](../docs/client-injector/README.md) (`openfsd-client`) with the **vPilot 3.12.1** profile.
- Phase 0: on-disk PE + config apply; quit vPilot before Apply.
- JWT host budget: **12** chars default path; **25** with `--prefer-short-jwt` and server `POST /j` (A8).
- R1 free-slot remap still **OPEN** — long production hosts need A8 and/or short DNS.
- AFV: retarget if voice base URL ≤ **25** chars; else launch with **`-novoice`**. PE disable not until R2.
- **Never redistribute** vPilot; install from [vpilot.rosscarlson.dev](https://vpilot.rosscarlson.dev/Download).
Historical: [vPilot Patch Utility](https://github.com/renorris/vpilot-patch-utility) (3.11.1-era; archived).
## xPilot
See [here](https://github.com/renorris/openfsd-client-patch-utility).
**Preferred when adapter lands:** openfsd Client Setup. Until then, historical reference:
[openfsd-client-patch-utility](https://github.com/renorris/openfsd-client-patch-utility).
## Voice (AFV)
@@ -59,3 +121,5 @@ Clients such as **TrackAudio**, **xPilot**, and **VectorAudio** (AFV-Native-deri
AFV authenticates against the same certificate database as FSD (CID + password). UDP voice endpoints are advertised in the AFV channel config from `AFV_UDP_ADVERTISE_IPV4` (must be reachable by clients, including through NAT).
Without `-afv`, use an external voice solution (Discord, etc.); FSD multiplayer still works independently of voice.
For **vPilot via Client Setup**: prefer retargeting the embedded AFV base when the full URL is ≤ **25** characters; otherwise Client Setup plans **`-novoice`** rather than PE-disabling the voice connect path (R2 still open).