Self-host a Windrose dedicated server on Linux — no Windows machine required, no technical expertise needed.
Windrose is a co-op pirate survival-adventure game by Windrose Crew. A dedicated server lets you and your friends play together anytime — even when the host is offline — by running the game world on a separate machine 24/7.
This project is a Docker container that makes self-hosting a Windrose server on Linux straightforward. The official server software is Windows-only, so this container handles all the compatibility work automatically using Wine. You just provide a Linux machine or cheap VPS — no Windows required, no manual Wine setup, no Steam account needed to download the server.
In plain terms: clone this repo, run one command, and you have a permanent private Windrose server your crew can join whenever they want.
- ✅ No Windows needed — runs the Windows server binary on Linux via WineHQ stable
- ✅ No Steam account needed — server files download anonymously via SteamCMD
- ✅ One-command setup —
docker compose up -dand you're done - ✅ Auto-updates — SteamCMD checks for server updates on every start
- ✅ Persistent world — saves and config survive container restarts and rebuilds
- ✅ Easy configuration — all settings via environment variables, no file editing required
- ✅ VPS-friendly — tested on a standard Linux VPS; ~$5–10/month is plenty
- ✅ Graceful shutdown — world is saved cleanly on
docker compose down - ✅ Pre-built image — pull from GHCR, no local build required
- A Linux machine or VPS (a cheap $5–10/month VPS works fine)
- Docker and Docker Compose installed
- About 6 GB of free disk space (for the server files)
- An x86_64 CPU with AVX support (any modern CPU from ~2012 onward; very old server Xeons may not qualify)
- UPnP enabled on your router, or the ability to use host networking (see Networking)
git clone https://github.com/AlexBraguta/windrose-server.git
cd windrose-server
cp .env.example .env
# open .env in a text editor and set SERVER_NAME to whatever you want
docker compose up -d
docker compose logs -fThe first launch takes a few minutes — Docker downloads ~3 GB of server files automatically. Once it's running, grab your invite code from the log or by running:
docker exec windrose cat /home/steam/windrose/R5/ServerDescription.jsonShare the InviteCode value with your friends and they can join from inside the game.
You can skip building the image entirely and pull the pre-built one:
# docker-compose.override.yml
services:
windrose:
image: ghcr.io/alexbraguta/windrose-server:latest
build: !reset nullEvery knob is an env var. Drop them in .env (auto-loaded by compose) or export them before docker compose up.
| Variable | Default | Purpose |
|---|---|---|
SERVER_NAME |
Windrose Server |
Display name in the server browser. |
SERVER_PASSWORD |
(empty) | Non-empty value enables password protection. |
INVITE_CODE |
(empty) | 6+ alphanumeric chars, case-sensitive. Empty = server generates one. |
MAX_PLAYERS |
4 |
Up to 4 is what Windrose officially recommends. |
UPDATE_ON_START |
1 |
Run SteamCMD app_update on each start. |
VALIDATE |
0 |
Pass validate to SteamCMD (slow; repairs corrupt files). |
WINDROSE_BRANCH |
public |
Steam beta branch — pin a specific server build to dodge version mismatches. |
WINE_HEADLESS |
1 |
Wrap Wine in xvfb-run for a virtual display. |
P2P_PROXY_ADDRESS |
127.0.0.1 |
Internal P2P proxy address. Keep default unless you know otherwise. |
USER_SELECTED_REGION |
(empty) | Region pin for connectivity-server selection: SEA, CIS, EU, or empty (auto). |
USE_DIRECT_CONNECTION |
0 |
1 enables Direct IP mode — clients join via your IP, invite codes are bypassed. |
DIRECT_CONNECTION_PORT |
7777 |
TCP+UDP port used in Direct IP mode. Forward both protocols. |
DIRECT_CONNECTION_PROXY_ADDRESS |
0.0.0.0 |
Bind interface for Direct IP mode. 0.0.0.0 = all interfaces. |
BACKUP_INTERVAL |
0 |
Seconds between automatic save snapshots. 0 disables. 3600 = hourly. |
BACKUP_KEEP |
7 |
How many save snapshots to retain (oldest get pruned). |
AUTO_LOAD_BACKUP |
1 |
1 = server auto-restores the latest backup if the active save is broken on launch. |
STEAM_USER |
(empty) | Optional real Steam login if anonymous install is ever revoked. |
STEAM_PASSWORD |
(empty) | Paired with STEAM_USER. |
After first start, the server creates these inside the volume:
| File | Purpose |
|---|---|
R5/ServerDescription.json |
Server-level config (patched from env). |
R5/Saved/SaveProfiles/Default/RocksDB/<version>/Worlds/<IslandId>/WorldDescription.json |
Per-world tuning (difficulty, multipliers). |
R5/Saved/Logs/R5.log |
Full UE5 server log (vastly richer than stdout). |
Edit either JSON directly for settings the env vars don't cover. Env var changes win on the next start because the entrypoint re-patches ServerDescription.json via jq before launch.
Windrose offers two connection modes. Pick the one that matches your network.
The server uses Windrose's connectivity services to negotiate the connection. No fixed ports to forward; UPnP on your router does the work. Host networking is the most reliable setup and the default in docker-compose.yml.
If host networking isn't an option, switch to network_mode: bridge, expose 7777/udp + 7778/udp, and keep UPnP enabled. Expect reduced connectivity behind symmetric NAT or CGNAT — game-design limitation, not a container issue.
Bypass the connectivity services entirely. Clients connect to your public IP on a fixed port. Invite codes are not used.
USE_DIRECT_CONNECTION=1
DIRECT_CONNECTION_PORT=7777
DIRECT_CONNECTION_PROXY_ADDRESS=0.0.0.0Forward DIRECT_CONNECTION_PORT on both TCP and UDP at your router. Then share your.public.ip:7777 with friends — they'll use the in-game "Direct IP" join option. This is the most reliable mode behind symmetric NAT / CGNAT, since it doesn't rely on hole-punching.
Set BACKUP_INTERVAL (seconds) to enable automatic save snapshots. The entrypoint tars R5/Saved/SaveProfiles to /home/steam/windrose/backups/ on the schedule and prunes to BACKUP_KEEP most recent.
AUTO_LOAD_BACKUP=1 (default) tells the server to automatically restore the most recent backup if it detects a broken save on startup — pairs well with periodic snapshots.
BACKUP_INTERVAL=3600 # hourly
BACKUP_KEEP=24 # keep last 24 hours
AUTO_LOAD_BACKUP=1 # auto-recover from backup on corrupt saveTo copy backups out of the volume:
docker cp windrose:/home/steam/windrose/backups ./backupsdocker exec -it windrose tail -f /home/steam/windrose/R5/Saved/Logs/R5.log# Edit .env, then:
docker compose up -dVALIDATE=1 docker compose up -dThe entrypoint runs app_update on every start (disable with UPDATE_ON_START=0). To pull a new image version:
docker compose pull
docker compose up -ddocker exec -it windrose bashdocker run --rm -v windrose_windrose-data:/src -v "$PWD:/dst" alpine \
tar czf /dst/windrose-backup-$(date +%F).tar.gz -C /src R5/SavedSteam has (temporarily) disabled anonymous install for this app. Fall back to a real account:
echo "STEAM_USER=your_login" >> .env
echo "STEAM_PASSWORD=your_password" >> .env
docker compose up -dThe image preloads vcrun2022 and d3dcompiler_47. If the binary asks for more:
docker exec -it windrose bash
winetricks --unattended <component>Common extras if R5/Shipping dies on start: dxvk, vkd3d, msvcrt.
- Confirm you're on
network_mode: hostin compose. - Check UPnP status on your router.
- Verify the server registered successfully:
docker exec windrose grep "Server Connection Info" /home/steam/windrose/R5/Saved/Logs/R5.log
- Symmetric NAT or a carrier-grade NAT (CGNAT) upstream will break P2P — there is no workaround on the server side.
This image patches R5/ServerDescription.json from env vars on every start. If the name in-game doesn't match your .env, recreate the container:
docker compose up -d --force-recreate┌────────────────────────────────┐
│ docker compose up │
└───────────────┬────────────────┘
│
▼
┌────────────────────────────────┐
│ entry.sh │
│ 1. steamcmd +login anonymous │
│ +app_update 4129620 │
│ 2. jq-patch ServerDescription │
│ .json from env vars │
│ 3. xvfb-run wine │
│ WindroseServer.exe │
└───────────────┬────────────────┘
│
▼
┌────────────────────────────────┐
│ WindroseServer-Win64-Shipping │
│ • UE5 engine + R5Net module │
│ • Auths with │
│ r5coopapigateway-* │
│ .windrose.support:443 │
│ • Opens R5P2P listen socket │
│ • Prints invite code to log │
└────────────────────────────────┘
All game state lives in the windrose-data named volume, so container rebuilds and restarts are cheap.
Does this work on a cheap VPS? Yes. Any Linux VPS with ~2 vCPUs, 4 GB RAM, and 6 GB disk is enough. DigitalOcean, Hetzner, Vultr, Linode all work fine.
Do I need a copy of Windrose to run the server?
No. The dedicated server is a separate free tool (Steam app 4129620) that downloads anonymously — you don't need to own the game on the server machine.
Can I run this on Windows? Yes, via Docker Desktop with Linux containers enabled (WSL2 or Hyper-V backend). Native Linux hosting is simpler and more common.
Do I need to open ports?
Windrose uses NAT punch-through, so there are no fixed ports to forward. Run the container with network_mode: host (the default in this repo) and UPnP enabled on your router.
How do my friends join?
Once the server is running, share your InviteCode from ServerDescription.json. Friends enter it directly in the Windrose in-game server browser.
Will the server keep running when I close my computer? Yes — that's the whole point of a dedicated server. As long as the host machine (VPS or home server) stays on, your Windrose world is always available.
See CONTRIBUTING.md. Bug reports with full logs are always welcome.
MIT. Windrose itself is © Windrose Crew; this project is not affiliated with or endorsed by the game's developer.
