El mayor portal de MU Online de Brasil — desde 2003
Tutorial Avanzado Infraestructura

Cómo configurar el reinicio automático ante fallos (watchdog) en el servidor de MU

Arma un watchdog confiable que detecte cuándo GameServer, ConnectServer o DataServer caen y reinicie los procesos automáticamente, sin que tengas que estar frente al VPS.

BR Bruno · Actualizado el 30 jun 2026 · ⏱ 22 min de lectura
Respuesta rápida

Un servidor de MU que cae a las 3 de la mañana y solo vuelve cuando despiertas pierde jugadores, y reputación. El proceso del GameServer se cierra por un crash de memoria, un pico de conexiones, un paquete malformado de bot, y nadie está en el VPS para reabrirlo. El watchdog resuelve esto: es un vig

Un servidor de MU que cae a las 3 de la mañana y solo vuelve cuando despiertas pierde jugadores, y reputación. El proceso del GameServer se cierra por un crash de memoria, un pico de conexiones, un paquete malformado de bot, y nadie está en el VPS para reabrirlo. El watchdog resuelve esto: es un vigía que monitorea tus procesos y puertos todo el tiempo y, en el instante en que detecta que algo cayó o se trabó, reinicia lo que hace falta reiniciar, en el orden correcto, y te avisa. Esta guía arma un watchdog robusto usando solo PowerShell y el Programador de Tareas de Windows; después muestra cómo reforzarlo con NSSM y alertas. Todas las rutas, nombres de proceso y puertos aquí son ejemplos que varían por versión del MuServer; adáptalos a los tuyos.

Nota: Este tutorial parte de un servidor ya montado y funcional. Si todavía no llegaste a ese punto, empieza por la guía de cómo crear un servidor de MU Online y vuelve aquí para dejarlo a prueba de caídas.

Requisitos previos

Antes de armar el watchdog, confirma que tienes:

  • Un VPS o máquina Windows (Server 2016/2019/2022 o Windows 10/11) con el MuServer ya arrancando manualmente sin error;
  • Acceso de administrador a Windows (el watchdog necesita reiniciar procesos y crear tareas programadas);
  • Los nombres exactos de los ejecutables de tu MuServer y los puertos que usa cada uno;
  • Los archivos .bat o los .exe que usas hoy para encender cada servicio;
  • PowerShell 5.1 o superior (ya viene en Windows) con permiso de ejecución de scripts.

Levanta primero el mapa de tus procesos. Abre el Administrador de Tareas con el servidor encendido y anota los nombres exactos. Un conjunto típico de MuServer es así (varía por versión):

ServicioEjecutable (ejemplo)Puerto por defecto (ejemplo)Función
DataServerDataServer.exe55960 / 55970Puente entre GameServer y SQL
ConnectServerConnectServer.exe44405Lista de servidores y ruteo inicial
JoinServerJoinServer.exe55901Login/autenticación de cuentas
GameServerGameServer.exe / Main.exe55901–55910El mundo del juego en sí
Atenção: No confíes en la memoria para los nombres. Algunos packs renombran GameServer.exe a Main.exe, MuServer.exe o algo personalizado. Si el watchdog busca el nombre equivocado, nunca detecta la caída, o peor, mata el proceso incorrecto.

Paso 1 — Habilitar la ejecución de scripts PowerShell

Por defecto Windows bloquea los scripts. Abre PowerShell como Administrador y libera la ejecución para scripts locales firmados o locales:

# Permite scripts locales; los scripts descargados necesitan firma
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force

# Confirmar
Get-ExecutionPolicy -List

Esto es suficiente para correr el watchdog que reside en el propio disco del servidor.

Paso 2 — Estandarizar los scripts de inicio

El watchdog va a llamar a un script por servicio. Estandarizar esto ahora evita dolor después. Crea una carpeta C:\MuServer\watchdog\ y, dentro de ella, un .bat de start para cada servicio que respete el directorio de trabajo correcto (muchos MuServer solo arrancan si el working directory es la carpeta del propio ejecutable):

@echo off
REM start_gameserver.bat  (ejemplo — ajusta ruta y nombre)
cd /d "C:\MuServer\GameServer"
start "" "GameServer.exe"

Haz el equivalente para start_dataserver.bat, start_connectserver.bat y start_joinserver.bat. El orden de arranque importa mucho y será respetado por el watchdog:

  1. DataServer (necesita el SQL Server ya corriendo);
  2. JoinServer;
  3. ConnectServer;
  4. GameServer.
Dica: Deja el SQL Server y el SQL Server Agent en inicio Automático en services.msc. El watchdog se encarga del MuServer, pero si la base no arranca con Windows, el DataServer se va a estar dando la cabeza contra la pared eternamente.

Paso 3 — Escribir el script watchdog

Este es el corazón del sistema. El script de abajo hace tres cosas para cada servicio: verifica si el proceso existe, verifica si el puerto está escuchando y, si alguno de los dos falla, dispara el start correspondiente, siempre respetando límites para no entrar en bucle. Guárdalo como C:\MuServer\watchdog\watchdog.ps1:

# ===== watchdog.ps1 (ejemplo — varia por version) =====
$ErrorActionPreference = "Stop"
$logFile = "C:\MuServer\watchdog\watchdog.log"

# Cada servicio: nombre del proceso, puerto a verificar, script de start, orden
$servicos = @(
    @{ Nome="DataServer";    Processo="DataServer";    Porta=55970; Start="C:\MuServer\watchdog\start_dataserver.bat";    Ordem=1 },
    @{ Nome="JoinServer";    Processo="JoinServer";    Porta=55901; Start="C:\MuServer\watchdog\start_joinserver.bat";    Ordem=2 },
    @{ Nome="ConnectServer"; Processo="ConnectServer"; Porta=44405; Start="C:\MuServer\watchdog\start_connectserver.bat"; Ordem=3 },
    @{ Nome="GameServer";    Processo="GameServer";    Porta=55901; Start="C:\MuServer\watchdog\start_gameserver.bat";    Ordem=4 }
)

function Escrever-Log($msg) {
    $linha = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')  $msg"
    Add-Content -Path $logFile -Value $linha
}

function Porta-Escutando($porta) {
    # Retorna $true si algo esta escuchando en el puerto TCP local
    $conn = Get-NetTCPConnection -State Listen -LocalPort $porta -ErrorAction SilentlyContinue
    return [bool]$conn
}

foreach ($s in ($servicos | Sort-Object { $_.Ordem })) {
    $proc = Get-Process -Name $s.Processo -ErrorAction SilentlyContinue
    $portaOk = Porta-Escutando $s.Porta

    if (-not $proc -or -not $portaOk) {
        $motivo = if (-not $proc) { "proceso ausente" } else { "puerto $($s.Porta) sin escucha" }
        Escrever-Log "[CAIDA] $($s.Nome): $motivo -> reiniciando"

        # Si el proceso existe pero el puerto murio (traba), matar antes
        if ($proc -and -not $portaOk) {
            Escrever-Log "[KILL] $($s.Nome) trabado, cerrando PID $($proc.Id)"
            Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue
            Start-Sleep -Seconds 3
        }

        Start-Process -FilePath $s.Start -WindowStyle Minimized
        # Delay para que el servicio arranque antes de verificar el siguiente en orden
        Start-Sleep -Seconds 8
    }
}

El detalle crucial está en el bloque que mata el proceso trabado: un GameServer puede seguir abierto en el Administrador de Tareas pero dejar de aceptar conexiones (deadlock, thread trabado). En ese caso, verificar solo el proceso diría "está todo bien" mientras nadie logra loguearse. Al verificar el puerto y derribar el zombi antes de reiniciar, cubres ambos escenarios.

Paso 4 — Protección contra el bucle de reinicio

Un watchdog sin freno es peligroso: si el GameServer crashea en el arranque (config equivocada, base fuera de servicio), el watchdog reinicia mil veces por minuto, llena el log, martilla el SQL y puede corromper datos. Agrega un contador con ventana de tiempo. Crea C:\MuServer\watchdog\watchdog-guard.ps1 que envuelva la lógica con un límite:

# ===== Control de tasa de reinicio =====
$stateFile = "C:\MuServer\watchdog\restart-state.json"
$maxReinicios = 5          # maximo de reinicios...
$janelaMinutos = 10        # ...dentro de esta ventana

function Pode-Reiniciar($nome) {
    $agora = Get-Date
    $state = @{}
    if (Test-Path $stateFile) {
        $state = Get-Content $stateFile -Raw | ConvertFrom-Json -AsHashtable
    }
    $eventos = @()
    if ($state.ContainsKey($nome)) {
        $eventos = @($state[$nome] | Where-Object {
            ([datetime]$_ ) -gt $agora.AddMinutes(-$janelaMinutos)
        })
    }
    if ($eventos.Count -ge $maxReinicios) {
        return $false   # supero el limite: NO reinicia, solo alerta
    }
    $eventos += $agora.ToString("o")
    $state[$nome] = $eventos
    $state | ConvertTo-Json -Depth 5 | Set-Content $stateFile
    return $true
}
Atenção: Cuando el límite se supera, el watchdog debe dejar de reiniciar y mandar una alerta en vez de insistir. El reinicio infinito no arregla un problema de configuración, solo esconde la causa y genera un log gigante. Cinco reinicios en diez minutos es un buen punto de partida (varía por servidor).

Paso 5 — Programar el watchdog para que corra cada minuto

El Programador de Tareas de Windows dispara el script en un intervalo corto. Crea la tarea por PowerShell (más confiable que la interfaz gráfica):

$acao = New-ScheduledTaskAction -Execute "powershell.exe" `
  -Argument "-NoProfile -ExecutionPolicy Bypass -File C:\MuServer\watchdog\watchdog.ps1"

# Disparador: cada 1 minuto, indefinidamente
$gatilho = New-ScheduledTaskTrigger -Once -At (Get-Date) `
  -RepetitionInterval (New-TimeSpan -Minutes 1)

$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest

Register-ScheduledTask -TaskName "MU Watchdog" -Action $acao `
  -Trigger $gatilho -Principal $principal -Description "Vigia de los procesos del MuServer"

Correr como SYSTEM garantiza que el watchdog funcione incluso sin nadie logueado en el VPS. Confirma que la tarea está activa:

Get-ScheduledTask -TaskName "MU Watchdog" | Get-ScheduledTaskInfo

Paso 6 — Alertas: saber que cayó, no solo reiniciar

El reinicio automático es genial, pero las caídas repetidas son síntoma de un problema real. Agrega una alerta simple vía webhook de Discord (el más común entre dueños de MU). Colócalo en el punto en que el watchdog detecta la caída o supera el límite:

function Alertar-Discord($mensagem) {
    $webhook = "https://discord.com/api/webhooks/TU_WEBHOOK_AQUI"
    $corpo = @{ content = "**[MU Watchdog]** $mensagem" } | ConvertTo-Json
    try {
        Invoke-RestMethod -Uri $webhook -Method Post -Body $corpo -ContentType "application/json"
    } catch {
        Escrever-Log "[ALERTA] fallo al enviar Discord: $_"
    }
}

Llama a Alertar-Discord "GameServer cayo y fue reiniciado a las $(Get-Date -Format HH:mm)" dentro del bloque de reinicio, y una alerta más fuerte cuando el límite de reinicios se supera (ahí es hora de que abras el VPS e investigues). No pongas el webhook real en un repositorio público.

Paso 7 — Alternativa robusta con NSSM

Si prefieres tratar cada servicio del MuServer como un servicio de Windows de verdad, NSSM (Non-Sucking Service Manager) lo hace, y ya trae recuperación automática integrada. Descarga el nssm.exe y registra cada ejecutable:

# Registrar el GameServer como servicio (ejemplo)
nssm install MU-GameServer "C:\MuServer\GameServer\GameServer.exe"
nssm set MU-GameServer AppDirectory "C:\MuServer\GameServer"

# Reiniciar automaticamente si sale, con throttle de 60s
nssm set MU-GameServer AppExit Default Restart
nssm set MU-GameServer AppThrottle 60000

NSSM cubre bien el escenario "el proceso se cerró", con reinicio y throttle nativos. No cubre la traba con proceso vivo, por eso el enfoque más completo es usar NSSM para el ciclo de vida y mantener el script PowerShell solo para la verificación de puerto. Las dos técnicas se complementan.

Paso 8 — Probar el watchdog a propósito

Nunca confíes en un watchdog que no viste funcionar. Fuerza una caída controlada:

  1. Con el servidor en el aire, abre el Administrador de Tareas;
  2. Finaliza manualmente el GameServer.exe;
  3. Cronometra: en hasta 1 minuto (el intervalo de la tarea) el watchdog debe reabrirlo;
  4. Revisa el watchdog.log: debe haber la línea [CAIDA] GameServer: proceso ausente -> reiniciando;
  5. Confirma que la alerta llegó a Discord;
  6. Repite matando el DataServer para validar el orden de arranque.
Dica: Haz esta prueba en un horario de bajo movimiento y avisa que es mantenimiento. Probar en producción llena, si algo sale mal, se vuelve un dolor de cabeza público.

Errores comunes y soluciones

SíntomaCausa probableSolución
El watchdog nunca detecta la caídaNombre del proceso equivocado en el scriptVerifica el nombre exacto en el Administrador de Tareas y ajusta Processo=
Reinicia en bucle infinitoSin control de tasa; config rotaAplica el guard de maxReinicios y corrige la causa raíz
El GameServer arranca sin baseOrden de arranque equivocado / SQL fuera de servicioGarantiza DataServer y SQL Server antes del GameServer
El puerto aparece como caído pero el servicio está okFirewall o puerto distinto del realConfirma el puerto con Get-NetTCPConnection -State Listen
La tarea no corre sin loginCorriendo como usuario comúnRecrea la tarea con principal SYSTEM y RunLevel Highest
El proceso trabado nunca es matadoSolo verifica el proceso, no el puertoActiva la verificación de puerto + Stop-Process del zombi
El log crece sin pararSin rotación de logTrunca/archiva el .log semanalmente por tarea programada

Lista de verificación de lanzamiento

  • Nombres exactos de todos los ejecutables del MuServer verificados en el Administrador de Tareas
  • Scripts .bat de start creados con cd /d para el directorio correcto de cada servicio
  • SQL Server y SQL Server Agent en inicio Automático
  • watchdog.ps1 verificando proceso Y puerto de cada servicio
  • Control de tasa de reinicio activo (límite por ventana de tiempo)
  • Bloque que mata el proceso trabado (puerto muerto, proceso vivo) funcionando
  • Tarea programada corriendo como SYSTEM cada 1 minuto
  • Alerta de Discord/webhook disparando en caída y al superar el límite
  • Prueba real: maté el GameServer y volvió en < 1 minuto
  • Prueba real: maté el DataServer y se respetó el orden de arranque
  • Log con rotación semanal configurada
  • Webhook y contraseñas fuera de cualquier archivo público/repositorio

Con el watchdog en el aire, tu servidor deja de depender de que estés despierto y frente al VPS. Las caídas se vuelven eventos de segundos registrados en el log, no horas de servidor offline. El paso siguiente natural es sumar backup automático de la base a la misma rutina de resiliencia, así quedas cubierto tanto contra caídas de proceso como contra pérdida de datos.

Preguntas frecuentes

¿Qué es un watchdog en un servidor de MU?

Es un proceso vigía que va comprobando si los ejecutables del MuServer (ConnectServer, DataServer, GameServer) están vivos y respondiendo. Cuando uno de ellos se cierra o se traba, el watchdog reinicia automáticamente ese proceso, manteniendo el servidor en línea sin intervención manual.

¿Es mejor monitorear por proceso o por puerto?

Los dos juntos. Comprobar solo el proceso detecta cuándo el .exe se cierra, pero no atrapa trabas en las que el proceso sigue abierto sin responder. Comprobar el puerto TCP confirma que el servicio realmente acepta conexiones. La combinación evita falsos positivos y falsos negativos.

¿Necesito un programa de pago para tener un watchdog?

No. Se puede armar un watchdog sólido solo con PowerShell + el Programador de Tareas de Windows, que ya vienen en el VPS. Herramientas como NSSM o un MuServer con watchdog integrado ayudan, pero lo esencial es gratuito.

¿El watchdog puede empeorar las cosas?

Puede, si está mal configurado. Un watchdog que reinicia en bucle demasiado rápido enmascara la causa raíz y corrompe la base de datos. Coloca siempre un límite de reinicios por ventana de tiempo, delays entre intentos y una alerta para que investigues.

¿Cuál es el orden correcto de reinicio de los servicios?

Primero el DataServer (conexión con la base), después el ConnectServer, y por último el GameServer/JoinServer. Reiniciar fuera de orden hace que el GameServer arranque sin base y derribe todo de nuevo. El detalle exacto varía por versión.

BR
Editor de eventos, mapas e ítems

Bruno es especialista en eventos, mapas, bosses y economía de ítems de MU Online. Documenta cada detalle basándose en el juego real.

Sigue leyendo

Artículos relacionados