Dockerized Windrose dedicated server — Windows binary running under Wine on Linux.
- 🪟 Wine-powered — runs the official Windows-only
WindroseServer-Win64-Shipping.exeon Linux. - 📦 Auto-install / auto-update — pulls the dedicated server via DepotDownloader (Steam app
4129620). - ⚙️ Env-driven config —
ServerDescription.jsonis generated on first boot, then patched from environment variables. - 🎨 Two flavors —
winehq-stable(default) andwinehq-staging+vcrun2022. - 🛡️ Unprivileged runtime — drops to a non-root
steamuser; UID/GID matchPUID/PGID. - 🩺 Healthcheck —
pgrepon the server process, with a 5-minute start grace. - 🛑 Graceful shutdown — SIGTERM is forwarded to
wineserver; falls back towineserver -kafter 30 s. - 🪵 Live log tail —
R5.logstreamed to container stdout.
docker run -d \
--name windrose \
-p 7777:7777/udp -p 7777:7777/tcp \
-e PUID=1000 -e PGID=1000 \
-e SERVER_NAME="My Windrose Server" \
-e SERVER_PASSWORD="changeme" \
-e MAX_PLAYERS=10 \
-v windrose-data:/home/steam/server-files \
ghcr.io/kalevski/windrose-server:latest
docker logs -f windroseFirst boot will:
- 📥 Pull the dedicated server via DepotDownloader.
- 🌀 Briefly launch under Wine to generate the default
ServerDescription.json. - 🔧 Patch the JSON from your environment variables.
- 🟢 Start the server for real.
⏱️ Expect 5–10 minutes the first time — the healthcheck has a matching 5m start period.
services:
windrose:
image: ghcr.io/kalevski/windrose-server:latest
container_name: windrose
restart: unless-stopped
ports:
- "7777:7777/udp"
- "7777:7777/tcp"
environment:
PUID: "1000"
PGID: "1000"
SERVER_NAME: "My Windrose Server"
SERVER_PASSWORD: ""
MAX_PLAYERS: "10"
volumes:
- ./data:/home/steam/server-filesAll configuration is via environment variables. Required ones marked with 🔑.
| Variable | Default | Description |
|---|---|---|
🔑 PUID |
— | UID owning /home/steam/server-files. |
🔑 PGID |
— | GID owning /home/steam/server-files. |
UPDATE_ON_START |
true |
Run DepotDownloader on every container start. |
GENERATE_SETTINGS |
true |
Allow scripts to overwrite ServerDescription.json from env. |
FIRST_BOOT_TIMEOUT |
120 |
Seconds to wait for the default config to be written. |
| Variable | Default | Description |
|---|---|---|
SERVER_NAME |
Windrose Server |
Display name in the server browser. |
SERVER_PASSWORD |
(empty) | Empty = open server. Sets IsPasswordProtected automatically. |
SERVER_PORT |
7777 |
UDP/TCP port the server listens on. |
MAX_PLAYERS |
10 |
Concurrent player cap. |
INVITE_CODE |
(empty) | Optional pre-set invite code. |
USER_SELECTED_REGION |
(empty) | Optional region hint. |
| Variable | Default | Description |
|---|---|---|
USE_DIRECT_CONNECTION |
false |
true = direct connect (skip P2P proxy). |
DIRECT_CONNECTION_PROXY_ADDRESS |
0.0.0.0 |
Bind address used when direct connection is on. |
P2P_PROXY_ADDRESS |
127.0.0.1 |
Address advertised for P2P proxy mode. |
| Variable | Default | Description |
|---|---|---|
WINEDEBUG |
-all |
Set fixme-all (or similar) for verbose Wine logs. |
NO_COLOR |
(unset) | Set to 1 to strip ANSI colors from container logs. |
💡 Field mappings live in
scripts/server.sh— every variable above maps 1:1 to a key inServerDescription_Persistent.
| Path | Purpose |
|---|---|
/home/steam/server-files |
🎯 Game install + world saves. Persist this. |
| Port | Protocol | Purpose |
|---|---|---|
7777 |
UDP/TCP | Server traffic (override with SERVER_PORT). |
Published to GitHub Container Registry: ghcr.io/kalevski/windrose-server.
| Tag | Source | Variant |
|---|---|---|
latest |
release | winehq-stable |
vX.Y.Z, vX.Y, vX |
release | winehq-stable |
wine-staging |
release | winehq-staging + vcrun2022 |
vX.Y.Z-wine-staging, vX.Y-wine-staging, vX-wine-staging |
release | winehq-staging + vcrun2022 |
dev |
push to main |
winehq-stable (unstable) |
dev-wine-staging |
push to main |
winehq-staging (unstable) |
docker pull ghcr.io/kalevski/windrose-server:latest
# or staging Wine
docker pull ghcr.io/kalevski/windrose-server:wine-staging# Stable Wine (default)
docker build -t windrose-server .
# Staging Wine + winetricks vcrun2022
docker build --build-arg WINE_VARIANT=staging -t windrose-server:staging .Build args:
| Arg | Default | Description |
|---|---|---|
WINE_VARIANT |
stable |
stable or staging. |
DEPOT_DOWNLOADER_VERSION |
3.4.0 |
DepotDownloader release pinned at build time. |
# Lint shell scripts (CI runs the same)
shellcheck scripts/*.sh
# Mount scripts for live iteration without rebuilds
docker run --rm -it --env-file .env \
-e PUID=1000 -e PGID=1000 \
-p 7777:7777/udp -p 7777:7777/tcp \
-v "$PWD/scripts:/home/steam/server" \
-v "$PWD/data:/home/steam/server-files" \
windrose-serverLayout:
├── Dockerfile # Debian + Wine + .NET 8 + DepotDownloader
├── motd # Banner printed at container start
├── scripts/
│ ├── entrypoint.sh # Aligns PUID/PGID, runs install/update, drops to steam
│ ├── server.sh # First-boot config gen + jq patch + Xvfb/Wine launch
│ └── lib.sh # Logging + DepotDownloader + graceful shutdown helpers
└── .github/workflows/
└── build-publish.yml # GHCR publish for stable + staging variants
MIT — see LICENSE (or the SPDX header in Dockerfile).