init
This commit is contained in:
339
SETUP.md
Normal file
339
SETUP.md
Normal file
@@ -0,0 +1,339 @@
|
||||
# Windrose Dedicated Server auf Hetzner CPX22 — Runbook
|
||||
|
||||
Anleitung für einen Agent zum Aufsetzen eines privaten Windrose-Dedicated-Servers
|
||||
(max. 4 Spieler, Invite-Code-only) auf einem frischen Hetzner CPX22 mit Ubuntu 24.04.
|
||||
|
||||
## Eckdaten
|
||||
|
||||
- **Hardware:** CPX22 = 2 vCPU AMD EPYC, **4 GB RAM**, 80 GB NVMe SSD.
|
||||
- **RAM-Risiko:** Windrose verlangt offiziell min. 8 GB für 2 Spieler. Wir kompensieren mit
|
||||
8 GB Swap und cappen `MaxPlayerCount=4`. Wenn Performance schlecht ist → Hetzner-Console
|
||||
→ Rescale auf CPX31 (8 GB RAM, ~€13/Monat), kein Datenverlust.
|
||||
- **Server ist Windows-only.** Lauf über Wine + Xvfb (headless).
|
||||
- **Setup-Variante:** Bare-Metal mit systemd (geringerer RAM-Footprint als Docker).
|
||||
- **Connectivity:** Spieler joinen per Invite-Code. UDP 7777/7778 müssen aber trotzdem
|
||||
reachable sein (NAT-Punch-Through über die öffentliche IP).
|
||||
- **SteamCMD App-ID:** `4129620` (Windrose Dedicated Server, anonymous).
|
||||
|
||||
## Regeln für den ausführenden Agent
|
||||
|
||||
- Schritte **2, 3, 6 als root**, Schritte **4, 5, 7 als User `windrose`** (`sudo -iu windrose`).
|
||||
- **Idempotent** arbeiten: vor jedem destruktiven Schritt prüfen, ob der Zielzustand schon
|
||||
existiert (Swapfile, WineHQ-Repo, systemd-Unit, …) und ggf. überspringen.
|
||||
- **Nicht-interaktiv**: bei `apt install` immer `-y`. Für `steamcmd` vorher die Lizenz
|
||||
per debconf akzeptieren (siehe Schritt 2.6).
|
||||
- Nach Schritt 5.2 den **InviteCode** aus `ServerDescription.json` extrahieren und im
|
||||
finalen Report zurückmelden — den braucht der User zum Joinen.
|
||||
- **Verifikation (Schritt 8) zwingend** ausführen und Ergebnisse berichten.
|
||||
- **Nicht** ohne Rückfrage den Server neu starten, Snapshots löschen oder die
|
||||
Hetzner-Cloud-Firewall ändern. Bei Fehlschlag: Log + Hypothese melden, nicht stumm
|
||||
reparieren.
|
||||
- Erwartete Dauer: 15–25 Min. (SteamCMD-Download ~3 GB + winetricks vcrun2022).
|
||||
|
||||
---
|
||||
|
||||
## Schritt 1 — Hetzner-Console (manuell durch den User)
|
||||
|
||||
Vor dem Server-Setup in der Hetzner Cloud Console:
|
||||
|
||||
1. **Snapshot** des frischen CPX22 anlegen (Rollback-Punkt).
|
||||
2. **Cloud-Firewall** anhängen mit Inbound-Regeln:
|
||||
- SSH: TCP 22 (am besten nur eigene IP)
|
||||
- Windrose Game: **UDP 7777** (any source)
|
||||
- Windrose Query: **UDP 7778** (any source)
|
||||
3. Outbound: alles erlauben (default). Wichtig für STUN/TURN nach
|
||||
`*.windrose.support:3478` (UDP/TCP).
|
||||
|
||||
---
|
||||
|
||||
## Schritt 2 — System-Vorbereitung (als root)
|
||||
|
||||
```bash
|
||||
# 2.1 Basis-Update
|
||||
apt update && apt -y full-upgrade
|
||||
|
||||
# 2.2 Server-User
|
||||
id windrose >/dev/null 2>&1 || adduser --disabled-password --gecos "" windrose
|
||||
usermod -aG sudo windrose
|
||||
|
||||
# 2.3 Swap (8 GB)
|
||||
if ! swapon --show | grep -q '/swapfile'; then
|
||||
fallocate -l 8G /swapfile
|
||||
chmod 600 /swapfile
|
||||
mkswap /swapfile
|
||||
swapon /swapfile
|
||||
echo '/swapfile none swap sw 0 0' >> /etc/fstab
|
||||
fi
|
||||
echo 'vm.swappiness=10' > /etc/sysctl.d/99-swappiness.conf
|
||||
sysctl --system
|
||||
|
||||
# 2.4 Multiarch + Repos
|
||||
dpkg --add-architecture i386
|
||||
add-apt-repository -y multiverse
|
||||
add-apt-repository -y universe
|
||||
|
||||
# 2.5 WineHQ-Repo (stable, aktueller als Distro-Wine)
|
||||
mkdir -pm755 /etc/apt/keyrings
|
||||
wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key
|
||||
wget -NP /etc/apt/sources.list.d/ \
|
||||
https://dl.winehq.org/wine-builds/ubuntu/dists/noble/winehq-noble.sources
|
||||
apt update
|
||||
|
||||
# 2.6 SteamCMD-Lizenz vorab akzeptieren (sonst hängt apt interaktiv)
|
||||
echo steam steam/question select "I AGREE" | debconf-set-selections
|
||||
echo steam steam/license note '' | debconf-set-selections
|
||||
|
||||
# 2.7 Pakete
|
||||
DEBIAN_FRONTEND=noninteractive apt install -y --install-recommends winehq-stable
|
||||
DEBIAN_FRONTEND=noninteractive apt install -y \
|
||||
software-properties-common lib32gcc-s1 steamcmd \
|
||||
xvfb cabextract winbind ufw fail2ban unzip jq wget
|
||||
|
||||
# 2.8 winetricks
|
||||
if [ ! -x /usr/local/bin/winetricks ]; then
|
||||
wget -O /usr/local/bin/winetricks \
|
||||
https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
|
||||
chmod +x /usr/local/bin/winetricks
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schritt 3 — Lokale Firewall + SSH-Härtung (als root)
|
||||
|
||||
```bash
|
||||
ufw default deny incoming
|
||||
ufw default allow outgoing
|
||||
ufw allow 22/tcp
|
||||
ufw allow 7777/udp
|
||||
ufw allow 7778/udp
|
||||
ufw --force enable
|
||||
|
||||
systemctl enable --now fail2ban
|
||||
```
|
||||
|
||||
In `/etc/ssh/sshd_config` setzen (nur wenn SSH-Key bereits funktioniert):
|
||||
```
|
||||
PasswordAuthentication no
|
||||
PermitRootLogin prohibit-password
|
||||
```
|
||||
Dann `systemctl reload ssh`.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 4 — Server-Installation (als User `windrose`)
|
||||
|
||||
```bash
|
||||
sudo -iu windrose bash <<'EOF'
|
||||
mkdir -p ~/steam ~/log ~/backup
|
||||
cd ~/steam
|
||||
|
||||
# 4.1 SteamCMD: Server-Files (forciert Windows-Platform)
|
||||
steamcmd \
|
||||
+@sSteamCmdForcePlatformType windows \
|
||||
+force_install_dir /home/windrose/steam/windrose \
|
||||
+login anonymous \
|
||||
+app_update 4129620 validate \
|
||||
+quit
|
||||
|
||||
# 4.2 Wine-Prefix initialisieren
|
||||
export WINEPREFIX=/home/windrose/steam/windrose/pfx
|
||||
export WINEARCH=win64
|
||||
xvfb-run -a wineboot --init
|
||||
xvfb-run -a winetricks -q win10 vcrun2022
|
||||
EOF
|
||||
```
|
||||
|
||||
> `vcrun2022` verhindert die häufigsten "missing MSVC runtime"-Crashes.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 5 — Server-Config
|
||||
|
||||
### 5.1 Start-Script `/home/windrose/steam/start_windrose.sh`
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
export WINEPREFIX=/home/windrose/steam/windrose/pfx
|
||||
export WINEARCH=win64
|
||||
export WINEDEBUG=-all
|
||||
export DISPLAY=:99
|
||||
|
||||
if ! pgrep -f "Xvfb :99" >/dev/null; then
|
||||
Xvfb :99 -screen 0 1024x768x16 &
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
cd /home/windrose/steam/windrose
|
||||
exec wine64 WindroseServer.exe
|
||||
```
|
||||
|
||||
`chmod +x /home/windrose/steam/start_windrose.sh`
|
||||
|
||||
### 5.2 Erst-Start (Config-Generierung)
|
||||
|
||||
Als `windrose`:
|
||||
```bash
|
||||
~/steam/start_windrose.sh &
|
||||
SERVER_PID=$!
|
||||
sleep 60 # warten bis Erst-Init durch ist
|
||||
kill $SERVER_PID 2>/dev/null || true
|
||||
sleep 5
|
||||
```
|
||||
|
||||
Damit werden `ServerDescription.json` und der erste Welt-Ordner unter
|
||||
`R5/Saved/SaveProfiles/Default/RocksDB/<version>/Worlds/<world_id>/` erzeugt.
|
||||
|
||||
### 5.3 ServerDescription patchen
|
||||
|
||||
Datei finden + patchen:
|
||||
```bash
|
||||
CFG=$(find /home/windrose/steam/windrose -maxdepth 4 -name ServerDescription.json | head -n1)
|
||||
|
||||
# InviteCode für Report extrahieren
|
||||
INVITE=$(jq -r '.ServerDescription_Persistent.InviteCode' "$CFG")
|
||||
|
||||
# ServerName + MaxPlayer setzen, kein Passwort
|
||||
jq '.ServerDescription_Persistent.ServerName = "Marhas Windrose"
|
||||
| .ServerDescription_Persistent.MaxPlayerCount = 4
|
||||
| .ServerDescription_Persistent.IsPasswordProtected = false
|
||||
| .ServerDescription_Persistent.Password = ""' \
|
||||
"$CFG" > "$CFG.tmp" && mv "$CFG.tmp" "$CFG"
|
||||
|
||||
echo "INVITE_CODE=$INVITE" # !!! Dem User zurückmelden !!!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schritt 6 — systemd Service (als root)
|
||||
|
||||
`/etc/systemd/system/windrose.service`:
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Windrose Dedicated Server
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=windrose
|
||||
Group=windrose
|
||||
WorkingDirectory=/home/windrose/steam
|
||||
ExecStart=/home/windrose/steam/start_windrose.sh
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StandardOutput=append:/home/windrose/log/windrose.log
|
||||
StandardError=append:/home/windrose/log/windrose.log
|
||||
MemoryHigh=3G
|
||||
MemoryMax=3500M
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Aktivieren:
|
||||
```bash
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now windrose
|
||||
systemctl status windrose --no-pager
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schritt 7 — Update- & Backup-Helfer (als User `windrose`)
|
||||
|
||||
### 7.1 Update-Script `/home/windrose/steam/update_windrose.sh`
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
sudo systemctl stop windrose
|
||||
steamcmd \
|
||||
+@sSteamCmdForcePlatformType windows \
|
||||
+force_install_dir /home/windrose/steam/windrose \
|
||||
+login anonymous \
|
||||
+app_update 4129620 validate \
|
||||
+quit
|
||||
sudo systemctl start windrose
|
||||
```
|
||||
|
||||
### 7.2 Backup-Script `/home/windrose/steam/backup_windrose.sh`
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
TS=$(date +%Y%m%d-%H%M%S)
|
||||
SRC=/home/windrose/steam/windrose/R5/Saved
|
||||
DST=/home/windrose/backup/windrose-${TS}.tar.gz
|
||||
tar -czf "$DST" -C "$(dirname "$SRC")" "$(basename "$SRC")"
|
||||
ls -1t /home/windrose/backup/windrose-*.tar.gz | tail -n +8 | xargs -r rm
|
||||
```
|
||||
|
||||
Beide ausführbar machen: `chmod +x ~/steam/{update,backup}_windrose.sh`
|
||||
|
||||
### 7.3 Cron (täglich 04:00) als `windrose`
|
||||
|
||||
```
|
||||
0 4 * * * /home/windrose/steam/backup_windrose.sh >> /home/windrose/log/backup.log 2>&1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schritt 8 — Verifikation (zwingend)
|
||||
|
||||
```bash
|
||||
systemctl status windrose --no-pager
|
||||
ss -ulnp | grep -E '7777|7778' || echo "WARN: Ports nicht gebunden"
|
||||
free -h
|
||||
tail -n 50 /home/windrose/log/windrose.log
|
||||
vmstat 5 3 # Swap-Aktivität: si/so sollten ~0 sein im Idle
|
||||
```
|
||||
|
||||
Erwartet:
|
||||
- Service `active (running)`
|
||||
- UDP 7777 + 7778 gebunden
|
||||
- Idle-RAM <2 GB belegt, Swap fast leer
|
||||
- Log zeigt "Server ready" o.ä., keine Wine-Stacktraces
|
||||
|
||||
Im Spiel-Client: "Join via Invite Code" → den im Report ausgegebenen Code eingeben.
|
||||
|
||||
---
|
||||
|
||||
## Eskalation bei Problemen
|
||||
|
||||
- **OOM / extreme Lags:** Hetzner-Console → Server stoppen → "Rescale" auf CPX31 → starten. ~3 Min., kein Datenverlust.
|
||||
- **Wine-Crashes beim Start:** `journalctl -u windrose -n 200` nach `wine: Unhandled` durchsuchen, ggf. `winetricks -q dotnet48` nachschieben oder `winehq-staging` statt `winehq-stable` testen.
|
||||
- **Clients finden Server nicht:** Hetzner-Cloud-Firewall checken (UDP 7777/7778 wirklich offen?), Outbound zu `*.windrose.support:3478` nicht geblockt.
|
||||
|
||||
---
|
||||
|
||||
## Kritische Dateien
|
||||
|
||||
| Pfad | Zweck |
|
||||
|---|---|
|
||||
| `/home/windrose/steam/windrose/WindroseServer.exe` | Server-Binary |
|
||||
| `/home/windrose/steam/windrose/ServerDescription.json` | ServerName, InviteCode, MaxPlayer |
|
||||
| `…/R5/Saved/SaveProfiles/Default/RocksDB/<ver>/Worlds/<id>/WorldDescription.json` | Welt-Konfig |
|
||||
| `/home/windrose/steam/windrose/pfx` | Wine-Prefix |
|
||||
| `/home/windrose/steam/start_windrose.sh` | Launcher (Xvfb + wine) |
|
||||
| `/etc/systemd/system/windrose.service` | systemd-Unit |
|
||||
| `/home/windrose/log/windrose.log` | Server-Log |
|
||||
| `/home/windrose/backup/` | tägliche Save-Backups |
|
||||
|
||||
---
|
||||
|
||||
## Final-Report-Template (vom Agent zurück an User)
|
||||
|
||||
```
|
||||
Status: success | failed
|
||||
Invite-Code: <CODE>
|
||||
Server-Name: Marhas Windrose
|
||||
Max-Spieler: 4
|
||||
Public-IPv4: <hetzner-ip>
|
||||
Service-Status: <output von systemctl status windrose>
|
||||
RAM-Idle: <free -h>
|
||||
Swap-Aktivität: <vmstat>
|
||||
Letzte Log-Zeilen: <tail -n 20 windrose.log>
|
||||
Auffälligkeiten / Warnings: …
|
||||
```
|
||||
Reference in New Issue
Block a user