|
|
|
@@ -325,20 +325,68 @@ Saving restarts the site's ingest client, so the change takes effect immediately
|
|
|
|
AES-GCM encrypted at rest and **never returned to any client** — losing it means reading it back
|
|
|
|
AES-GCM encrypted at rest and **never returned to any client** — losing it means reading it back
|
|
|
|
from `sidecar.toml` on the shard host, not from the website.
|
|
|
|
from `sidecar.toml` on the shard host, not from the website.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
If the sidecar sits behind a reverse proxy, paste your **public** `https://` and `wss://` URLs
|
|
|
|
|
|
|
|
instead of the two the installer printed — it composes those from the sidecar's own bind address,
|
|
|
|
|
|
|
|
which knows nothing about what fronts it. Everything else on the page is unchanged.
|
|
|
|
|
|
|
|
|
|
|
|
### If your website is on a different machine
|
|
|
|
### If your website is on a different machine
|
|
|
|
|
|
|
|
|
|
|
|
The sidecar binds `127.0.0.1:8080` by default, which is reachable only from the shard host. If your
|
|
|
|
The sidecar binds `127.0.0.1:8080` by default, which is reachable only from the shard host. If your
|
|
|
|
website runs elsewhere, you must widen the bind — and then narrow the access:
|
|
|
|
website runs elsewhere, the recommended arrangement is a **TLS reverse proxy in front of the
|
|
|
|
|
|
|
|
sidecar** — this is a supported deployment and the one Runic Gateway itself runs, on a real domain
|
|
|
|
|
|
|
|
name.
|
|
|
|
|
|
|
|
|
|
|
|
1. Set `[web] bind` in `sidecar.toml` to `0.0.0.0:8080` (or a specific LAN address) and restart the
|
|
|
|
**Leave `[web] bind` on `127.0.0.1:8080`** and let the proxy be the only thing that talks to it.
|
|
|
|
service.
|
|
|
|
Widening the bind and firewalling the port is the alternative, not the default (see below).
|
|
|
|
2. **Firewall port 8080 to your website's address only.** The auth token is always on, but it
|
|
|
|
|
|
|
|
travels as a plain bearer token — the sidecar speaks HTTP, not HTTPS.
|
|
|
|
|
|
|
|
3. If the two hosts are not on a trusted network, put the sidecar behind a TLS reverse proxy or a
|
|
|
|
|
|
|
|
VPN/WireGuard link, and give the website the proxied `https://` / `wss://` URLs.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The `[shard] bind` line is a different matter: leave it on `127.0.0.1:7788`. That socket accepts
|
|
|
|
Give the website the **proxied** URLs — `https://link.example.com` and
|
|
|
|
*inbound commands* to the game, and being loopback-only is what makes that safe.
|
|
|
|
`wss://link.example.com/ws` — in place of the `http://` / `ws://` pair the installer prints. Those
|
|
|
|
|
|
|
|
values are the sidecar's own view of itself; the proxy is what the outside world sees.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
What the proxy must do:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Requirement | Why |
|
|
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
|
|
| **Forward the WebSocket upgrade** (`Upgrade` / `Connection` headers, HTTP/1.1 to the upstream) | `/ws` is the live event feed. Without it the site's REST calls work and events never arrive — a confusing half-working state. |
|
|
|
|
|
|
|
|
| **Pass request headers through unmodified** | Auth is `Authorization: Bearer` (or `X-Api-Key`), and the website sends `X-UOLink-Version`. A proxy that strips unknown headers turns into a `401`, and a stripped version header just silently skips the mismatch check. |
|
|
|
|
|
|
|
|
| **Do not buffer the WS connection, and allow long-lived ones** | The feed is idle between events. The sidecar sends a WebSocket **Ping every 30 s**, so a read timeout of 60 s or more is safe as it stands — but a proxy that buffers responses will hold events instead of streaming them. |
|
|
|
|
|
|
|
|
| **Do not log query strings** | The sidecar also accepts `?token=…` (for clients that cannot set headers). If anything in your stack uses that form, a default access-log format writes your auth token to disk on every request. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Nothing needs `X-Forwarded-For`: the sidecar never uses the client's IP for authorization, and the
|
|
|
|
|
|
|
|
browser IP that account provisioning cares about is supplied by the website in the request body.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
An nginx server block that satisfies all of the above:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```nginx
|
|
|
|
|
|
|
|
server {
|
|
|
|
|
|
|
|
listen 443 ssl;
|
|
|
|
|
|
|
|
server_name link.example.com;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# your certificate directives here
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
location / {
|
|
|
|
|
|
|
|
proxy_pass http://127.0.0.1:8080;
|
|
|
|
|
|
|
|
proxy_http_version 1.1;
|
|
|
|
|
|
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
|
|
|
|
|
|
proxy_set_header Connection $connection_upgrade; # "upgrade" for WS, "" otherwise
|
|
|
|
|
|
|
|
proxy_set_header Host $host;
|
|
|
|
|
|
|
|
proxy_buffering off;
|
|
|
|
|
|
|
|
proxy_read_timeout 300s;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(with the usual `map $http_upgrade $connection_upgrade { default upgrade; '' close; }` at `http`
|
|
|
|
|
|
|
|
level). Caddy and Traefik handle WebSocket upgrades automatically and need no equivalent stanza.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Without a proxy**, on a trusted network only: set `[web] bind` to `0.0.0.0:8080` or a specific LAN
|
|
|
|
|
|
|
|
address, restart the service, and **firewall the port to your website's address**. The auth token is
|
|
|
|
|
|
|
|
always required, but the sidecar speaks HTTP — on that path the token and every event cross the
|
|
|
|
|
|
|
|
network in the clear. Do not do this over the public internet.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The `[shard] bind` line is a different matter entirely: leave it on `127.0.0.1:7788` and never proxy
|
|
|
|
|
|
|
|
it. That socket accepts *inbound commands* to the game, and being loopback-only is what makes that
|
|
|
|
|
|
|
|
safe.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
@@ -451,7 +499,9 @@ The report is also written to a file, so it survives the scrollback.
|
|
|
|
| Shard boots clean but nothing reaches the site | The classic silent failure: ServUO ignores the script build's exit code and reloaded a **stale `Scripts.dll`**. Run `dotnet build Scripts/Scripts.csproj -c Release -p:Platform=x64` and read the errors it prints. |
|
|
|
|
| Shard boots clean but nothing reaches the site | The classic silent failure: ServUO ignores the script build's exit code and reloaded a **stale `Scripts.dll`**. Run `dotnet build Scripts/Scripts.csproj -c Release -p:Platform=x64` and read the errors it prints. |
|
|
|
|
| `[bridge status` says `connected=False` | The sidecar is not listening on `127.0.0.1:7788`. Check the service is running, and that `[shard] bind` in `sidecar.toml` matches `Host`/`Port` in `Bridge.cfg`. |
|
|
|
|
| `[bridge status` says `connected=False` | The sidecar is not listening on `127.0.0.1:7788`. Check the service is running, and that `[shard] bind` in `sidecar.toml` matches `Host`/`Port` in `Bridge.cfg`. |
|
|
|
|
| `[bridge` is not a command | The plugin did not compile, or `Bridge.cfg` has the bridge disabled. See the row above. |
|
|
|
|
| `[bridge` is not a command | The plugin did not compile, or `Bridge.cfg` has the bridge disabled. See the row above. |
|
|
|
|
| Website says the shard is offline; `/health` is fine locally | The website cannot reach port 8080 — bind address or firewall. See [§5](#if-your-website-is-on-a-different-machine). Note that the site is *designed* to render normally with the shard offline, so this fails quietly by design. |
|
|
|
|
| Website says the shard is offline; `/health` is fine locally | The website cannot reach the sidecar — bind address, firewall, or proxy. See [§5](#if-your-website-is-on-a-different-machine). Note that the site is *designed* to render normally with the shard offline, so this fails quietly by design. |
|
|
|
|
|
|
|
|
| REST reads work but **no live events arrive** | The classic reverse-proxy symptom: the WebSocket upgrade is not being forwarded. Confirm the proxy sets `Upgrade`/`Connection` and speaks HTTP/1.1 upstream, and that the site's WebSocket URL is `wss://…/ws` — not `https://`. |
|
|
|
|
|
|
|
|
| The event feed connects, then drops every minute or two | A proxy read timeout below the sidecar's 30 s WebSocket ping interval, or response buffering. Raise the timeout and turn buffering off. |
|
|
|
|
| Website logs `409` from the sidecar | Protocol mismatch: the number in Admin → Shard does not match the sidecar's. The sidecar rejects rather than mis-parsing. Set the field to what `/health` reports (`protocol`). If the *sidecar* and *overlay* disagree, you have a hand-assembled pair — reinstall from a bundle. |
|
|
|
|
| Website logs `409` from the sidecar | Protocol mismatch: the number in Admin → Shard does not match the sidecar's. The sidecar rejects rather than mis-parsing. Set the field to what `/health` reports (`protocol`). If the *sidecar* and *overlay* disagree, you have a hand-assembled pair — reinstall from a bundle. |
|
|
|
|
| `401` from the sidecar | Wrong or missing auth token. Read the live one back with `uo-link-sidecar --print-config --config <path>`; do not retype it from a screenshot. |
|
|
|
|
| `401` from the sidecar | Wrong or missing auth token. Read the live one back with `uo-link-sidecar --print-config --config <path>`; do not retype it from a screenshot. |
|
|
|
|
| A patch will not apply | Expected on a hand-modified shard. The base install is unaffected; you lose only the two features in [§4](#4-the-patch-tier-optional). Apply the hunks by hand if you want them. |
|
|
|
|
| A patch will not apply | Expected on a hand-modified shard. The base install is unaffected; you lose only the two features in [§4](#4-the-patch-tier-optional). Apply the hunks by hand if you want them. |
|
|
|
|
|