Operators
Goosetower And Gooseweb Deployment
Deploy the Gooseweb browser app and Goosetower realtime gateway with Gooselake as the source of truth.
Goosetower And Gooseweb Deployment
Gooseweb and Goosetower are deployed as separate pieces:
- Gooseweb runs on Vercel and serves the TanStack Start app only.
- The browser connects directly to Goosetower with
wss://goosetower.example.com/v1/realtime?ticket=.... - Goosetower runs on the VPS near
gg-runtime-server. - Goosetower routes source-of-truth commands to Gooselake runtime HTTP APIs and consumes runtime event replay/SSE.
- Goosetower keeps upstream runtime bearer tokens server-side only. Do not put the Gooselake runtime token in Gooseweb, Vercel env vars that are exposed to the client, browser storage, or WebSocket query strings.
Files
Recommended starting points:
examples/goosetower.tomlfor production-style config.examples/goosetower.local.tomlfor local development.deploy/systemd/gg-goosetower.service.examplefor a user service.deploy/systemd/gg-goosetower.env.examplefor non-secret environment overrides.scripts/preflight-goosetower.shfor config and endpoint checks.
Production Config
Use exact origins in server.allowed_gooseweb_origins. Include the production Vercel origin and every preview origin pattern as explicit URLs. Do not use wildcard origin matching.
Keep secrets in files referenced by config:
auth.api_token_filefor protected Goosetower HTTP endpoints.tickets.signing_key_filefor short-lived Gooseweb connection tickets.runtimes.sources[].bearer_token_filefor the upstream Gooselake runtime token.
Goosetower should usually bind to localhost behind a TLS reverse proxy:
[server]
bind_address = "127.0.0.1:8090"
public_base_url = "https://goosetower.example.com"
allowed_gooseweb_origins = [
"https://gooseweb.example.com",
"https://gooseweb-git-main-example.vercel.app",
]
Reverse Proxy
Terminate TLS at nginx, Caddy, Cloudflare Tunnel, or another VPS proxy that supports WebSocket upgrades. The proxy must forward:
UpgradeConnectionHostX-Forwarded-Proto
For nginx, the relevant location shape is:
location / {
proxy_pass http://127.0.0.1:8090;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
}
Goosetower validates the browser Origin header on the WebSocket upgrade. CORS settings for fetch routes do not protect WebSocket connections, so the exact origin allowlist is a production requirement.
Local Development
One local development layout:
gg-runtime-server --config examples/runtime-server.toml
gg-goosetower --config examples/goosetower.local.toml
make gooseweb-dev
The local Gooseweb dev server runs from apps/gooseweb and connects to the local gateway. The local Goosetower example enables debug endpoints and uses the development API token dev-goosetower-token.
Preflight
Validate the config only:
make goosetower-check-config \
GOOSETOWER_BIN=target/debug/gg-goosetower \
GOOSETOWER_CONFIG=examples/goosetower.local.toml
Validate a running gateway:
make goosetower-preflight \
GOOSETOWER_BIN=target/debug/gg-goosetower \
GOOSETOWER_CONFIG=examples/goosetower.local.toml \
BASE_URL=http://127.0.0.1:8090 \
TOKEN=dev-goosetower-token
The preflight checks:
gg-goosetower --check-configGET /health- authenticated
GET /v1/health - authenticated
GET /v1/sources - authenticated
GET /v1/metrics
Debug endpoints are intentionally separate and require both bearer auth and [debug].endpoints_enabled = true:
GET /v1/debug/protocolGET /v1/debug/sourcesGET /v1/debug/subscriptionsGET /v1/debug/materializerGET /v1/debug/audit
Observability
Goosetower emits structured tracing fields for connection, command, source, resume, and subscription audit events. The authenticated /v1/metrics endpoint returns current in-process counters for:
- connection open/close totals and active connections
- source health and stale age
- browser RTT
- command accepted/rejected counts and admission/upstream latency
- event ingest lag and materializer reduce time
- outbound messages by critical/state/token/bulk lane
- coalesced state messages and dropped bulk/backpressure messages
- WebSocket buffered messages
- resume success, partial replay, gap, and snapshot resync counts
For production, scrape or poll /v1/metrics from the VPS side or from trusted infrastructure only. Do not expose the Goosetower API bearer token to browser code.