Como configurar reinício automático em falha (watchdog) no servidor de MU
Monte um watchdog confiável que detecta quando GameServer, ConnectServer ou DataServer caem e reinicia os processos automaticamente, sem você precisar estar na frente do VPS.
Servidor de MU que cai às 3 da manhã e só volta quando você acorda perde jogador — e reputação. O processo do GameServer fecha por um crash de memória, um pico de conexões, um pacote malformado de bot, e ninguém está no VPS para reabrir. O watchdog resolve isso: é um vigia que monitora seus processo
Servidor de MU que cai às 3 da manhã e só volta quando você acorda perde jogador — e reputação. O processo do GameServer fecha por um crash de memória, um pico de conexões, um pacote malformado de bot, e ninguém está no VPS para reabrir. O watchdog resolve isso: é um vigia que monitora seus processos e portas o tempo todo e, no instante em que detecta que algo caiu ou travou, reinicia o que precisa ser reiniciado, na ordem certa, e te avisa. Este guia monta um watchdog robusto usando apenas PowerShell e o Agendador de Tarefas do Windows — depois mostra como reforçar com NSSM e alertas. Todos os caminhos, nomes de processo e portas aqui são exemplos que variam por versão do MuServer; adapte aos seus.
Pré-requisitos
Antes de montar o watchdog, confirme que você tem:
- Um VPS ou máquina Windows (Server 2016/2019/2022 ou Windows 10/11) com o MuServer já subindo manualmente sem erro;
- Acesso administrador ao Windows (o watchdog precisa reiniciar processos e criar tarefas agendadas);
- Os nomes exatos dos executáveis do seu MuServer e as portas que cada um usa;
- Os arquivos
.batou os.exeque você usa hoje para ligar cada serviço; - PowerShell 5.1 ou superior (já vem no Windows) com permissão de execução de scripts.
Levante primeiro o mapa dos seus processos. Abra o Gerenciador de Tarefas com o servidor ligado e anote os nomes exatos. Um conjunto típico de MuServer é assim (varia por versão):
| Serviço | Executável (exemplo) | Porta padrão (exemplo) | Função |
|---|---|---|---|
| DataServer | DataServer.exe | 55960 / 55970 | Ponte entre GameServer e SQL |
| ConnectServer | ConnectServer.exe | 44405 | Lista de servidores e roteamento inicial |
| JoinServer | JoinServer.exe | 55901 | Login/autenticação de contas |
| GameServer | GameServer.exe / Main.exe | 55901–55910 | O mundo do jogo em si |
GameServer.exe para Main.exe, MuServer.exe ou algo customizado. Se o watchdog procurar o nome errado, ele nunca detecta a queda — ou pior, mata o processo errado.Passo 1 — Habilitar a execução de scripts PowerShell
Por padrão o Windows bloqueia scripts. Abra o PowerShell como Administrador e libere a execução para scripts locais assinados ou locais:
# Permite scripts locais; scripts baixados precisam de assinatura
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force
# Confirmar
Get-ExecutionPolicy -List
Isso é suficiente para rodar o watchdog que fica no próprio disco do servidor.
Passo 2 — Padronizar os scripts de inicialização
O watchdog vai chamar um script por serviço. Padronizar isso agora evita dor depois. Crie uma pasta C:\MuServer\watchdog\ e, dentro dela, um .bat de start para cada serviço que respeite o diretório de trabalho correto (muitos MuServer só sobem se o working directory for a pasta do próprio executável):
@echo off
REM start_gameserver.bat (exemplo — ajuste caminho e nome)
cd /d "C:\MuServer\GameServer"
start "" "GameServer.exe"
Faça o equivalente para start_dataserver.bat, start_connectserver.bat e start_joinserver.bat. A ordem de subida importa muito e será respeitada pelo watchdog:
- DataServer (precisa do SQL Server já rodando);
- JoinServer;
- ConnectServer;
- GameServer.
services.msc. O watchdog cuida do MuServer, mas se o banco não subir com o Windows, o DataServer vai bater a cabeça na parede eternamente.Passo 3 — Escrever o script watchdog
Este é o coração do sistema. O script abaixo faz três coisas para cada serviço: verifica se o processo existe, verifica se a porta está escutando e, se algum dos dois falhar, dispara o start correspondente — sempre respeitando limites para não entrar em loop. Salve como C:\MuServer\watchdog\watchdog.ps1:
# ===== watchdog.ps1 (exemplo — varia por versão) =====
$ErrorActionPreference = "Stop"
$logFile = "C:\MuServer\watchdog\watchdog.log"
# Cada serviço: nome do processo, porta a checar, script de start, ordem
$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 se algo está escutando na porta 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) { "processo ausente" } else { "porta $($s.Porta) sem escuta" }
Escrever-Log "[QUEDA] $($s.Nome): $motivo -> reiniciando"
# Se o processo existe mas a porta morreu (travamento), matar antes
if ($proc -and -not $portaOk) {
Escrever-Log "[KILL] $($s.Nome) travado, encerrando PID $($proc.Id)"
Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 3
}
Start-Process -FilePath $s.Start -WindowStyle Minimized
# Delay para o serviço subir antes de checar o próximo da ordem
Start-Sleep -Seconds 8
}
}
O detalhe crucial está no bloco que mata o processo travado: um GameServer pode continuar aberto no Gerenciador de Tarefas mas parar de aceitar conexões (deadlock, thread travada). Nesse caso, checar só o processo diria "está tudo bem" enquanto ninguém consegue logar. Ao checar a porta e derrubar o zumbi antes de reiniciar, você cobre os dois cenários.
Passo 4 — Proteção contra loop de reinício
Um watchdog sem freio é perigoso: se o GameServer crasha na inicialização (config errada, banco fora do ar), o watchdog reinicia mil vezes por minuto, enche o log, martela o SQL e pode corromper dados. Adicione um contador com janela de tempo. Crie C:\MuServer\watchdog\watchdog-guard.ps1 que envolve a lógica com limite:
# ===== Controle de taxa de reinício =====
$stateFile = "C:\MuServer\watchdog\restart-state.json"
$maxReinicios = 5 # máximo de reinícios...
$janelaMinutos = 10 # ...dentro desta janela
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 # estourou o limite: NÃO reinicia, apenas alerta
}
$eventos += $agora.ToString("o")
$state[$nome] = $eventos
$state | ConvertTo-Json -Depth 5 | Set-Content $stateFile
return $true
}
Passo 5 — Agendar o watchdog para rodar a cada minuto
O Agendador de Tarefas do Windows dispara o script em intervalo curto. Crie a tarefa por PowerShell (mais confiável que a interface gráfica):
$acao = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NoProfile -ExecutionPolicy Bypass -File C:\MuServer\watchdog\watchdog.ps1"
# Gatilho: a 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 dos processos do MuServer"
Rodar como SYSTEM garante que o watchdog funcione mesmo sem ninguém logado no VPS. Confirme que a tarefa está ativa:
Get-ScheduledTask -TaskName "MU Watchdog" | Get-ScheduledTaskInfo
Passo 6 — Alertas: saber que caiu, não só reiniciar
Reinício automático é ótimo, mas quedas repetidas são sintoma de um problema real. Adicione um alerta simples via webhook do Discord (o mais comum entre donos de MU). Coloque no ponto em que o watchdog detecta queda ou estoura o limite:
function Alertar-Discord($mensagem) {
$webhook = "https://discord.com/api/webhooks/SEU_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] falha ao enviar Discord: $_"
}
}
Chame Alertar-Discord "GameServer caiu e foi reiniciado às $(Get-Date -Format HH:mm)" dentro do bloco de reinício, e um alerta mais forte quando o limite de reinícios estoura (aí é hora de você abrir o VPS e investigar). Não coloque o webhook real em repositório público.
Passo 7 — Alternativa robusta com NSSM
Se preferir tratar cada serviço do MuServer como um serviço do Windows de verdade, o NSSM (Non-Sucking Service Manager) faz isso — e ele já traz recuperação automática embutida. Baixe o nssm.exe e registre cada executável:
# Registrar o GameServer como serviço (exemplo)
nssm install MU-GameServer "C:\MuServer\GameServer\GameServer.exe"
nssm set MU-GameServer AppDirectory "C:\MuServer\GameServer"
# Reiniciar automaticamente se sair, com throttle de 60s
nssm set MU-GameServer AppExit Default Restart
nssm set MU-GameServer AppThrottle 60000
O NSSM cobre bem o cenário "o processo fechou", com reinício e throttle nativos. Ele não cobre travamento com processo vivo — por isso a abordagem mais completa é usar NSSM para o ciclo de vida e manter o script PowerShell só para a checagem de porta. As duas técnicas se complementam.
Passo 8 — Testar o watchdog de propósito
Nunca confie num watchdog que você não viu funcionar. Force uma queda controlada:
- Com o servidor no ar, abra o Gerenciador de Tarefas;
- Finalize manualmente o
GameServer.exe; - Cronometre: em até 1 minuto (o intervalo da tarefa) o watchdog deve reabri-lo;
- Confira o
watchdog.log— deve haver a linha[QUEDA] GameServer: processo ausente -> reiniciando; - Confirme que o alerta chegou no Discord;
- Repita matando o DataServer para validar a ordem de subida.
Erros comuns e soluções
| Sintoma | Causa provável | Solução |
|---|---|---|
| Watchdog nunca detecta queda | Nome do processo errado no script | Conferir nome exato no Gerenciador de Tarefas e ajustar Processo= |
| Reinicia em loop infinito | Sem controle de taxa; config quebrada | Aplicar o guard de maxReinicios e corrigir a causa raiz |
| GameServer sobe sem banco | Ordem de subida errada / SQL fora do ar | Garantir DataServer e SQL Server antes do GameServer |
| Porta aparece como caída mas o serviço está ok | Firewall ou porta diferente da real | Confirmar a porta com Get-NetTCPConnection -State Listen |
| Tarefa não roda sem login | Rodando como usuário comum | Recriar a tarefa com principal SYSTEM e RunLevel Highest |
| Processo travado nunca é morto | Só checa processo, não checa porta | Ativar a checagem de porta + Stop-Process do zumbi |
| Log cresce sem parar | Sem rotação de log | Truncar/arquivar o .log semanalmente por tarefa agendada |
Checklist de lançamento
- Nomes exatos de todos os executáveis do MuServer conferidos no Gerenciador de Tarefas
- Scripts
.batde start criados comcd /dpara o diretório correto de cada serviço - SQL Server e SQL Server Agent em inicialização Automática
watchdog.ps1checando processo E porta de cada serviço- Controle de taxa de reinício ativo (limite por janela de tempo)
- Bloco que mata processo travado (porta morta, processo vivo) funcionando
- Tarefa agendada rodando como SYSTEM a cada 1 minuto
- Alerta de Discord/webhook disparando em queda e ao estourar o limite
- Teste real: matei o GameServer e ele voltou em < 1 minuto
- Teste real: matei o DataServer e a ordem de subida foi respeitada
- Log com rotação semanal configurada
- Webhook e senhas fora de qualquer arquivo público/repositório
Com o watchdog no ar, seu servidor deixa de depender de você estar acordado e na frente do VPS. Quedas viram eventos de segundos registrados no log, não horas de servidor offline. O passo seguinte natural é somar backup automático do banco à mesma rotina de resiliência — assim você fica coberto tanto contra quedas de processo quanto contra perda de dados.
Perguntas frequentes
O que é um watchdog em servidor de MU?
É um processo vigia que fica checando se os executáveis do MuServer (ConnectServer, DataServer, GameServer) estão vivos e respondendo. Quando um deles fecha ou trava, o watchdog reinicia automaticamente aquele processo, mantendo o servidor online sem intervenção manual.
Monitorar por processo ou por porta é melhor?
Os dois juntos. Checar só o processo detecta quando o .exe fecha, mas não pega travamentos em que o processo continua aberto sem responder. Checar a porta TCP confirma que o serviço realmente aceita conexões. A combinação evita falsos positivos e falsos negativos.
Preciso de programa pago para ter watchdog?
Não. Dá para montar um watchdog sólido só com PowerShell + Agendador de Tarefas do Windows, que já vêm no VPS. Ferramentas como NSSM ou um MuServer com watchdog embutido ajudam, mas o essencial é gratuito.
O watchdog pode piorar as coisas?
Pode, se mal configurado. Um watchdog que reinicia em loop rápido demais mascara a causa raiz e corrompe o banco. Sempre coloque limite de reinícios por janela de tempo, delays entre tentativas e um alerta para você investigar.
Qual a ordem correta de reinício dos serviços?
Primeiro o DataServer (conexão com o banco), depois o ConnectServer, e por último o GameServer/JoinServer. Reiniciar fora de ordem faz o GameServer subir sem banco e derrubar tudo de novo. O detalhe exato varia por versão.