Native Windows REST agent for windrose-panel (Go, NSSM)
  • Go 89.4%
  • PowerShell 9.5%
  • Dockerfile 0.6%
  • Makefile 0.5%
Find a file
2026-06-05 07:52:40 +00:00
.forgejo/workflows ci: Forgejo Actions build/release workflow 2026-05-10 22:23:30 +01:00
cmd/windrose-agent feat: skeleton Go REST agent (health/status/lifecycle/logs SSE) 2026-05-10 21:44:57 +01:00
docs ci: Forgejo Actions build/release workflow 2026-05-10 22:23:30 +01:00
internal feat: F9 RCON proxy — POST /api/v1/rcon → Windrose+ 2026-05-10 22:27:12 +01:00
scripts feat: F9 RCON proxy — POST /api/v1/rcon → Windrose+ 2026-05-10 22:27:12 +01:00
.gitignore feat: skeleton Go REST agent (health/status/lifecycle/logs SSE) 2026-05-10 21:44:57 +01:00
.gitlab-ci.yml ci: migrate Forgejo Actions → GitLab CI [skip ci] 2026-06-04 13:51:40 +00:00
Dockerfile feat: skeleton Go REST agent (health/status/lifecycle/logs SSE) 2026-05-10 21:44:57 +01:00
go.mod feat: skeleton Go REST agent (health/status/lifecycle/logs SSE) 2026-05-10 21:44:57 +01:00
go.sum feat: config/backups/mods endpoints (WIN-C-bis) 2026-05-10 21:57:56 +01:00
Makefile feat: skeleton Go REST agent (health/status/lifecycle/logs SSE) 2026-05-10 21:44:57 +01:00
README.md feat: F9 RCON proxy — POST /api/v1/rcon → Windrose+ 2026-05-10 22:27:12 +01:00
renovate.json Add renovate.json 2026-06-05 02:31:01 +00:00

windrose-windows-agent

Build

Tiny Go REST agent that runs on a native Windows host alongside the Steam Windrose Dedicated Server. It is consumed by windrose-webgui-server (Linux Docker) over Tailscale + a static Bearer token.

Designed against ADR-005 (multi-backend abstraction) and ADR-006 (Windows agent stack).

CI / runner setup: see docs/CI-SETUP.md.

What it does

  • Wraps windrose-server.exe as a Windows service (WindroseServer) via NSSM.
  • Exposes a small HTTP API the panel calls to start / stop / restart the server, query status, and stream logs (SSE).
  • Listens only on a Tailscale IP (recommended bind: 100.x.y.z:7878). Tailscale provides transport encryption — agent serves plain HTTP.

API (v0.2)

Method Path Auth Notes
GET /api/v1/health no liveness
GET /api/v1/status yes service state
POST /api/v1/start yes start service
POST /api/v1/stop yes stop (90s timeout)
POST /api/v1/restart yes stop+start
GET /api/v1/logs/stream yes SSE tail of server log
GET /api/v1/config/{server|world} yes read JSON config
PUT /api/v1/config/{server|world} yes write JSON config (409 while running)
GET /api/v1/backups yes list tar.gz archives
POST /api/v1/backups yes create backup of Saves dir
DELETE /api/v1/backups/{name} yes delete archive
GET /api/v1/mods yes list .pak mods
POST /api/v1/mods yes upload mod (multipart, max 200 MiB)
DELETE /api/v1/mods/{name}?confirm=true yes delete mod
POST /api/v1/rcon yes proxy wp.* to Windrose+ (F9, gated)

Auth header: Authorization: Bearer <WINDROSE_AGENT_TOKEN>.

Examples

# Status
curl -H "Authorization: Bearer $TOKEN" http://$AGENT/api/v1/status

# Read server config
curl -H "Authorization: Bearer $TOKEN" http://$AGENT/api/v1/config/server

# Write server config (service must be stopped)
curl -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  --data @ServerDescription.json http://$AGENT/api/v1/config/server

# List backups
curl -H "Authorization: Bearer $TOKEN" http://$AGENT/api/v1/backups

# Create backup (service must be stopped if BACKUP_REQUIRE_STOPPED=true)
curl -X POST -H "Authorization: Bearer $TOKEN" http://$AGENT/api/v1/backups

# Delete backup
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
  http://$AGENT/api/v1/backups/windrose-20260510T120000Z.tar.gz

# Upload mod
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "X-File-Name: MyMod.pak" \
  -F file=@./MyMod.pak \
  http://$AGENT/api/v1/mods

# Delete mod
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
  "http://$AGENT/api/v1/mods/MyMod.pak?confirm=true"

Install (Windows host)

  1. Build the binary on a Linux/macOS box:
    make windows
    
    This produces bin/windrose-agent.exe.
  2. Copy the repo (or just bin/windrose-agent.exe and scripts/install.ps1) to the Windows host.
  3. Open an elevated PowerShell and run:
    .\scripts\install.ps1 -InstallPath "C:\Path\To\WindroseDedicatedServer"
    
    The script:
    • downloads NSSM,
    • registers WindroseServer and WindroseAgent services,
    • generates a 32-byte Bearer token,
    • adds Defender exclusions,
    • prints the agent URL + token at the end.

Configure the panel

Set these in the panel's environment:

WINDROSE_BACKEND=winagent
WINDROSE_AGENT_URL=http://<tailscale-ip>:7878
WINDROSE_AGENT_TOKEN=<token from install.ps1 output>

Environment variables (agent)

Var Default Required Notes
WINDROSE_AGENT_TOKEN yes min 32 chars
WINDROSE_AGENT_BIND 127.0.0.1:7878 no use Tailscale IP in prod
WINDROSE_INSTALL_PATH yes server install dir
WINDROSE_AGENT_LOG_PATH C:\Windrose\logs\server.log no NSSM stdout target
WINDROSE_CONFIG_DIR C:\Windrose\config no reserved
WINDROSE_BACKUP_DIR C:\Windrose\backups no tar.gz archive root
WINDROSE_MODS_DIR <InstallPath>\Mods no .pak directory
WINDROSE_SAVES_DIR <InstallPath>\R5\Saved no what backups archive
WINDROSE_SERVER_CONFIG_PATH <InstallPath>\R5\Saved\Config\WindowsServer\ServerDescription.json no served by /config/server
WINDROSE_WORLD_CONFIG_PATH <InstallPath>\R5\Saved\Config\WindowsServer\WorldDescription.json no served by /config/world
WINDROSE_SERVICE_NAME WindroseServer no NSSM service name
WINDROSE_MAX_UPLOAD_MB 200 no upload cap
BACKUP_RETENTION_DAYS 7 no auto-prune older archives
BACKUP_REQUIRE_STOPPED true no refuse backup if running
WINDROSE_AGENT_LOG_LEVEL info no debug/info/warn/error
WINDROSE_RCON_ENABLED false no F9 — gate /api/v1/rcon
WINDROSE_RCON_URL http://127.0.0.1:8780/api/rcon/command no Windrose+ HTTP RCON
WINDROSE_RCON_PASSWORD no sent as X-Auth + ?password=

RCON (F9)

When WINDROSE_RCON_ENABLED=true, the agent exposes POST /api/v1/rcon accepting { "command": "wp.players" }. The handler validates the command against ^wp\.[a-z]+(\s+[\w._-]+)*$, forwards it to WINDROSE_RCON_URL with both X-Auth header and ?password= query string (Windrose+ builds vary), and returns { "output": "..." } to the panel. Disabled by default — operators opt in during install.ps1 or by editing agent.env.

Build

make build      # native (Linux/macOS) — Windows code stubbed out
make windows    # cross-compile windrose-agent.exe
make tidy

Repo layout

cmd/windrose-agent/    entry point
internal/config/       env loading + validation
internal/server/       HTTP + middleware (auth, logging)
internal/handlers/     health, status, lifecycle, logs
internal/svc/          Windows SCM wrapper (build-tagged)
internal/fs/           path-traversal-safe filesystem helpers
scripts/install.ps1    Windows bootstrap
Dockerfile             Linux cross-compile for CI