Cómo montar un servidor dedicado de Windrose en Linux (Bazzite + Podman)
Guía paso a paso para levantar un servidor privado de Windrose usando la imagen Docker oficial (windroseserver/windroseserver) en un sistema Linux tipo Bazzite/Fedora Atomic con Podman rootless. Documentado a partir de una instalación real, incluyendo los errores que salieron y cómo se resolvieron.
0. Requisitos previos
Linux con Podman (o Docker) instalado.
Al menos ~6 GB libres (la imagen pesa varios GB por el payload del juego).
Puerto 7777 TCP/UDP disponible.
Acceso al router (para exponer el servidor a internet, opcional).
Verifica qué tienes disponible:
which podman docker
En Bazzite, Podman viene de fábrica con un alias docker='podman', así que ambos comandos funcionan igual.
1. Preparar la carpeta del servidor
mkdir -p ~/Windrose-Server/Saved
cd ~/Windrose-Server
2. Primer arranque SIN configuración propia (para generar IDs válidos)
Importante: no crear el ServerDescription.json a mano desde cero con campos vacíos (PersistentServerId, WorldIslandId, etc. en ""). Eso provoca un crash tipo:
Fatal error: [R5DataKeeperForServerCoop.cpp:154] InitializeBLServer - Cannot init Coop NetServer
Condition: 'ServerDescription.WorldIslandId.IsValid()'
En su lugar, deja que el propio servidor genere el archivo la primera vez:
podman run --user ue_user --name WindroseServer \
-p 7777:7777/tcp -p 7777:7777/udp \
-d \
-v ~/Windrose-Server/Saved:/home/ue_user/app/R5/Saved:Z \
docker.io/windroseserver/windroseserver:latest
sleep 20
podman stop WindroseServer
Copia el archivo generado a tu carpeta local:
podman cp WindroseServer:/home/ue_user/app/R5/ServerDescription.json ~/Windrose-Server/ServerDescription.json
Este archivo ya trae PersistentServerId real y otros valores válidos generados por el motor — no los toques.
3. Editar solo los campos que quieres personalizar
# Nombre del servidor
sed -i 's/"ServerName": *"[^"]*"/"ServerName": "TU_NOMBRE_AQUI"/' ServerDescription.json
# Habilitar conexión directa por IP (necesario para Docker/Podman)
sed -i 's/"UseDirectConnection": false/"UseDirectConnection": true/' ServerDescription.json
sed -i 's/"DirectConnectionServerPort": -1/"DirectConnectionServerPort": 7777/' ServerDescription.json
Campos relevantes en ServerDescription_Persistent:
Campo
Qué hace
ServerName
Nombre visible del servidor
MaxPlayerCount
Jugadores máximos
IsPasswordProtected / Password
Contraseña de acceso
UseDirectConnection
true = conexión por IP directa. false = conexión por código de invitación (relay P2P vía Epic Online Services)
DirectConnectionServerPort
Puerto a usar (7777 por defecto)
InviteCode
Código de invitación — solo funciona si UseDirectConnection está en false
️ UseDirectConnection y el código de invitación son mutuamente excluyentes. No puedes usar ambos al mismo tiempo. Con true, el invite code queda inútil aunque tenga un valor válido. Para hosting dedicado con IP fija, true (Direct IP) es lo recomendado: menos latencia, no depende del relay de Epic/AWS.
4. Borrar el contenedor de prueba y lanzar el definitivo
Clave: usar --userns=keep-id en Podman rootless. Sin esto, el UID ue_user (1000) dentro del contenedor no mapea al UID real del host, y el servidor no puede reescribir ServerDescription.json cuando genera el mundo — causa el mismo crash del paso 2 pero después de crear el mundo:
open('.../ServerDescription.json', ...) failed: errno=13 (Permission denied)
Cannot save ServerDescription file.
Comando final:
podman rm -f WindroseServer
podman run --user ue_user --userns=keep-id --name WindroseServer \
-p 7777:7777/tcp -p 7777:7777/udp \
-d \
-v ~/Windrose-Server/Saved:/home/ue_user/app/R5/Saved:Z \
-v ~/Windrose-Server/ServerDescription.json:/home/ue_user/app/R5/ServerDescription.json:Z \
docker.io/windroseserver/windroseserver:latest
El flag :Z en los volúmenes es necesario en sistemas con SELinux (Fedora/Bazzite) para evitar errores de permisos.
5. Verificar que está corriendo bien
podman logs -f WindroseServer
Busca estas líneas como señal de éxito:
IpNetDriver listening on port 7777
Bringing World .../GenlandiaMulty up for play
Server. Change state LoadedIslandData => WaitingForFirstAccount
Para ver logs sin quedarte pegado en tiempo real:
podman logs --tail 100 WindroseServer
Guardar log completo a archivo:
podman logs WindroseServer > ~/Windrose-Server/server.log
6. Ver nombre, contraseña e invite code guardados
grep -E '"ServerName"|"Password"|"IsPasswordProtected"|"InviteCode"' ~/Windrose-Server/ServerDescription.json
7. Cómo conectan tus amigos
En la misma red local:
IP_LOCAL_DEL_HOST:7777
(consíguela con ip addr show | grep 'inet ' | grep -v 127.0.0.1)
Remotos (por internet): necesitan la IP pública del host, más el port forwarding hecho en el router (ver sección 8).
curl ifconfig.me
En el juego: Play → Connect to Server → Direct IP tab → pegan IP:7777.
8. Port forwarding en router MikroTik (RouterOS)
Reemplaza ether1 por tu interfaz WAN y 192.168.88.254 por la IP local del host (idealmente fijada por DHCP lease estático).
Fijar la IP del host (opcional pero recomendado):
/ip dhcp-server lease print
/ip dhcp-server lease make-static <número_de_la_entrada>
Reglas NAT (port forward), TCP y UDP:
/ip firewall nat add chain=dstnat protocol=tcp dst-port=7777 in-interface=ether1 action=dst-nat to-addresses=192.168.88.254 to-ports=7777 comment="Windrose TCP"
/ip firewall nat add chain=dstnat protocol=udp dst-port=7777 in-interface=ether1 action=dst-nat to-addresses=192.168.88.254 to-ports=7777 comment="Windrose UDP"
Reglas de firewall filter (deben quedar antes de cualquier drop general en la cadena forward):
/ip firewall filter add chain=forward protocol=tcp dst-port=7777 dst-address=192.168.88.254 action=accept place-before=0 comment="Allow Windrose TCP"
/ip firewall filter add chain=forward protocol=udp dst-port=7777 dst-address=192.168.88.254 action=accept place-before=0 comment="Allow Windrose UDP"
Verificar:
/ip firewall nat print
/ip firewall filter print
Revisar CGNAT (paso crítico): compara la IP de tu interfaz WAN...
/ip address print
...contra la que te da curl ifconfig.me desde el host, o whatismyip.com. Si son diferentes, hay CGNAT/doble NAT de por medio y el forwarding no funcionará desde afuera sin pasos extra (pedir IP pública al ISP, o usar una alternativa tipo VPN/túnel).
Resumen de comandos útiles
# Ver contenedores corriendo
podman ps
# Ver logs en vivo
podman logs -f WindroseServer
# Reiniciar el servidor (tras editar ServerDescription.json)
podman rm -f WindroseServer
podman run --user ue_user --userns=keep-id --name WindroseServer \
-p 7777:7777/tcp -p 7777:7777/udp -d \
-v ~/Windrose-Server/Saved:/home/ue_user/app/R5/Saved:Z \
-v ~/Windrose-Server/ServerDescription.json:/home/ue_user/app/R5/ServerDescription.json:Z \
docker.io/windroseserver/windroseserver:latest
# Parar / iniciar sin borrar
podman stop WindroseServer
podman start WindroseServer
Notas finales
La imagen oficial (windroseserver/windroseserver) corre el binario nativo Linux del motor (no requiere Wine).
Actualizar el servidor: podman pull docker.io/windroseserver/windroseserver:latest y volver a lanzar el contenedor (los datos del mundo persisten en Saved/ porque está montado como volumen).
Pendiente para el futuro: configurar arranque automático con Quadlet (systemd nativo de Fedora Atomic/Bazzite) para que el servidor levante solo al encender la máquina.