Como montar um script de deploy contínuo (CI/CD) para servidor de MU Online
Construa um pipeline de deploy contínuo para o seu servidor de MU Online, automatizando build do emulador, migração de banco, distribuição de arquivos de cliente e reinício seguro do GameServer/ConnectServer.
Manter um servidor de MU Online privado atualizado manualmente — copiando DLLs, editando configs e reiniciando serviços na mão — funciona enquanto o projeto é pequeno, mas vira fonte de erro humano assim que a equipe cresce ou a frequência de updates aumenta. Um script de deploy contínuo (CI/CD) res
Manter um servidor de MU Online privado atualizado manualmente — copiando DLLs, editando configs e reiniciando serviços na mão — funciona enquanto o projeto é pequeno, mas vira fonte de erro humano assim que a equipe cresce ou a frequência de updates aumenta. Um script de deploy contínuo (CI/CD) resolve isso: cada alteração no código do emulador, nos arquivos de configuração ou no banco de dados passa por um pipeline repetível, testado e reversível. Este tutorial mostra como estruturar esse pipeline do zero, dos requisitos de infraestrutura ao script de rollback, cobrindo GameServer, ConnectServer, banco de dados e arquivos de configuração.
Por que automatizar o deploy de um servidor de MU
Um servidor de MU típico tem múltiplos componentes que precisam ser atualizados em conjunto: o binário do GameServer (compilado a partir do código do emulador, ex. IGCN/MuEMU/OpenMU), o ConnectServer, os arquivos .txt/.xml de configuração de itens e monstros, e o schema do banco (MSSQL ou MySQL, dependendo do emulador). Atualizar esses componentes fora de ordem — por exemplo, subir um ItemList.txt novo sem a stored procedure correspondente — é a causa mais comum de crash pós-update. Um pipeline de deploy contínuo garante que tudo suba na ordem certa, com validação em cada etapa.
Pré-requisitos de infraestrutura
- Repositório de código versionado (Git) com o código-fonte do emulador e os arquivos de configuração.
- Um ambiente de staging — réplica do servidor de produção, mesmo que menor, para validar builds antes de liberar.
- Acesso via SSH/WinRM ao(s) servidor(es) de produção, com uma conta de serviço dedicada (não a conta pessoal do administrador).
- Um runner de CI (GitHub Actions, GitLab CI, Jenkins ou até um script agendado via Task Scheduler/cron) que execute o pipeline.
- Backup automatizado do banco de dados e dos arquivos de configuração antes de qualquer deploy.
Estrutura do repositório
Organize o repositório separando claramente o que é código-fonte compilável do que é configuração de dados de jogo:
mu-server/
├── src/ # código-fonte do emulador (GameServer, ConnectServer)
├── config/ # arquivos .ini/.txt de configuração de ambiente
├── db/
│ ├── migrations/ # scripts .sql numerados sequencialmente
│ └── seed/ # dados iniciais (itens, monstros, mapas)
├── deploy/
│ ├── deploy.sh # script principal de deploy
│ ├── rollback.sh # script de rollback
│ └── healthcheck.sh # validação pós-deploy
└── .github/workflows/deploy.yml
Essa separação permite versionar mudanças de gameplay (um evento novo, um item novo) independentemente de mudanças de infraestrutura (uma correção de bug no core do emulador).
Etapa 1 — Build do emulador
O pipeline começa compilando o código-fonte do GameServer/ConnectServer. Um exemplo de etapa de build em bash, assumindo um projeto C++ com CMake:
#!/bin/bash
set -euo pipefail
echo "[deploy] Compilando GameServer..."
cd src/GameServer
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j"$(nproc)"
if [ ! -f build/GameServer.exe ]; then
echo "[deploy] ERRO: build falhou, binário não gerado."
exit 1
fi
echo "[deploy] Build concluída com sucesso."
Se o seu emulador é distribuído como binário fechado (sem recompilação), essa etapa vira apenas a validação de integridade do pacote baixado (checksum) antes de seguir.
Etapa 2 — Migração de banco de dados
Toda alteração de schema deve viver em um arquivo de migração numerado e versionado, nunca aplicada manualmente via SSMS/HeidiSQL direto em produção. Um exemplo de script de aplicação de migrações incrementais:
#!/bin/bash
set -euo pipefail
DB_HOST="$1"
LAST_APPLIED=$(sqlcmd -S "$DB_HOST" -Q "SELECT MAX(version) FROM SchemaMigrations" -h -1)
for file in db/migrations/*.sql; do
version=$(basename "$file" | cut -d'_' -f1)
if [ "$version" -gt "$LAST_APPLIED" ]; then
echo "[deploy] Aplicando migração $file"
sqlcmd -S "$DB_HOST" -i "$file"
sqlcmd -S "$DB_HOST" -Q "INSERT INTO SchemaMigrations (version, applied_at) VALUES ($version, GETDATE())"
fi
done
Nunca use DROP TABLE ou ALTER COLUMN destrutivo em uma migração sem antes confirmar que o backup pré-deploy foi concluído com sucesso.
Etapa 3 — Backup automático antes do deploy
O passo de backup deve ser bloqueante: se ele falhar, o pipeline inteiro para e nada é implantado. Um exemplo mínimo:
#!/bin/bash
set -euo pipefail
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups/mu/$TIMESTAMP"
mkdir -p "$BACKUP_DIR"
sqlcmd -S "$DB_HOST" -Q "BACKUP DATABASE MuOnline TO DISK='$BACKUP_DIR/MuOnline.bak'"
cp -r /opt/mu-server/config "$BACKUP_DIR/config"
tar -czf "$BACKUP_DIR/binaries.tar.gz" /opt/mu-server/bin
echo "[deploy] Backup salvo em $BACKUP_DIR"
Mantenha ao menos os últimos 7 backups diários e 4 semanais, com rotação automática para não estourar o disco.
Etapa 4 — Distribuição dos arquivos ao servidor
Com a build validada e o backup concluído, o pipeline copia os artefatos para o(s) servidor(es) de produção. Usando rsync sobre SSH:
rsync -avz --delete \
--exclude 'config/local.ini' \
build/GameServer.exe deploy/ \
usuario@mu-prod:/opt/mu-server/bin/
O --exclude é importante: arquivos de configuração específicos do ambiente (senhas de banco, chaves de licença) não devem ser sobrescritos pelo pipeline — eles vivem fora do controle de versão, geridos por variáveis de ambiente ou um cofre de segredos (Vault, AWS Secrets Manager).
Etapa 5 — Reinício seguro dos serviços
Reiniciar o GameServer derruba todos os jogadores conectados, então essa etapa deve ser cronometrada e comunicada. Um script de restart controlado:
#!/bin/bash
set -euo pipefail
echo "[deploy] Avisando jogadores sobre reinício em 5 minutos..."
echo "notice Servidor reiniciará em 5 minutos para manutenção" > /opt/mu-server/gs_console_pipe
sleep 300
systemctl stop mu-gameserver
systemctl stop mu-connectserver
cp /tmp/new_build/GameServer.exe /opt/mu-server/bin/
systemctl start mu-connectserver
systemctl start mu-gameserver
Prefira sempre reiniciar o ConnectServer por último a subir, para que ele só aceite novas conexões quando o GameServer já estiver de pé.
Etapa 6 — Healthcheck pós-deploy
Depois do restart, valide automaticamente que os serviços subiram corretamente antes de declarar o deploy como concluído:
#!/bin/bash
RETRIES=10
for i in $(seq 1 $RETRIES); do
if nc -z localhost 44405; then
echo "[deploy] ConnectServer respondendo na porta 44405."
exit 0
fi
echo "[deploy] Aguardando ConnectServer subir... ($i/$RETRIES)"
sleep 10
done
echo "[deploy] ERRO: ConnectServer não respondeu. Iniciando rollback."
exit 1
Se o healthcheck falhar, o pipeline deve acionar automaticamente o script de rollback, sem esperar intervenção manual.
Etapa 7 — Script de rollback
O rollback restaura o backup gerado na Etapa 3 e reverte os binários:
#!/bin/bash
set -euo pipefail
BACKUP_DIR="$1"
systemctl stop mu-gameserver mu-connectserver
sqlcmd -S "$DB_HOST" -Q "RESTORE DATABASE MuOnline FROM DISK='$BACKUP_DIR/MuOnline.bak' WITH REPLACE"
tar -xzf "$BACKUP_DIR/binaries.tar.gz" -C /
systemctl start mu-connectserver mu-gameserver
echo "[deploy] Rollback concluído a partir de $BACKUP_DIR"
Teste esse script periodicamente em staging — um rollback nunca testado tem grande chance de falhar exatamente no momento em que você mais precisa dele.
Integrando com GitHub Actions
Um exemplo de workflow que orquestra as etapas acima, disparado em push na branch main após aprovação de pull request:
name: Deploy MU Server
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: ./deploy/build.sh
- name: Backup produção
run: ./deploy/backup.sh
- name: Migrar banco
run: ./deploy/migrate.sh ${{ secrets.DB_HOST }}
- name: Distribuir arquivos
run: ./deploy/rsync-deploy.sh
- name: Reiniciar serviços
run: ssh deploy@mu-prod './deploy/restart.sh'
- name: Healthcheck
run: ./deploy/healthcheck.sh || ./deploy/rollback.sh
Mantenha os segredos (host do banco, chaves SSH) em Secrets do repositório, nunca hardcoded no YAML.
Ambiente de staging como gate obrigatório
Nenhuma build deve ir direto para produção. Configure o pipeline para primeiro implantar em staging, rodar um smoke test automatizado (login, criação de personagem, teleporte, drop de item) e só então liberar o deploy de produção — manual ou automaticamente, dependendo da maturidade da equipe. Esse gate é o que separa deploy contínuo de "deploy no escuro".
Erros comuns e soluções
| Sintoma | Causa provável | Solução |
|---|---|---|
| GameServer não sobe após deploy | DLL/binário incompatível com schema de banco atual | Rode as migrações antes de trocar o binário, nunca depois |
| Rollback falha | Script de rollback nunca testado em staging | Teste o rollback a cada release maior, não só documente |
| Jogadores caem sem aviso | Restart não avisado com antecedência | Adicione mensagem in-game/Discord automatizada antes do restart |
| Pipeline trava no backup | Disco cheio no servidor de banco | Configure rotação de backups antigos e monitore espaço livre |
| Configuração local sobrescrita | rsync sem exclude de arquivos de ambiente | Liste explicitamente os arquivos de config que não vêm do repositório |
Checklist de implementação do pipeline
- Repositório versionado com separação entre código, config e migrações de banco.
- Ambiente de staging funcional para validar builds antes de produção.
- Script de backup automático bloqueante antes de cada deploy.
- Migrações de banco numeradas e aplicadas em ordem.
- Script de restart com aviso prévio aos jogadores.
- Healthcheck automatizado pós-deploy.
- Script de rollback testado periodicamente em staging.
- Segredos (senhas, chaves) fora do controle de versão.
Com o pipeline de deploy contínuo no ar, o próximo passo é aplicar essa mesma disciplina de automação à configuração inicial do ambiente — veja o tutorial de criação de servidor de MU Online para entender a base sobre a qual esse pipeline foi construído.
Perguntas frequentes
Preciso de um servidor de CI dedicado (Jenkins/GitLab) para isso?
Não é obrigatório. Você pode começar com um script bash/PowerShell disparado manualmente ou por uma task agendada, e evoluir para GitHub Actions/GitLab CI/Jenkins conforme a equipe crescer. O importante é que o processo seja repetível e versionado, não a ferramenta em si.
É seguro automatizar o deploy em um servidor de MU em produção?
Sim, desde que o pipeline inclua backup automático antes de cada deploy, um ambiente de staging para validar a build e um passo de rollback testado. Deploy manual tende a ser mais arriscado que um pipeline bem desenhado, porque depende de memória humana.
Como lidar com o cliente do jogo no deploy contínuo?
O cliente (arquivos que o jogador baixa) normalmente tem um pipeline separado do servidor, publicando pacotes de atualização via launcher. O deploy do servidor deve verificar compatibilidade de versão de protocolo antes de liberar a atualização do cliente.
O que fazer se o deploy quebrar o GameServer em produção?
O pipeline deve ter um passo de rollback automático: restaurar o binário/DLL anterior e o dump de banco do backup pré-deploy, então reiniciar os serviços. Esse rollback precisa ser testado periodicamente, não só escrito e esquecido.
Dá para fazer deploy sem derrubar os jogadores online?
Parcialmente. Trocar DLLs do GameServer normalmente exige reinício do processo, então o ideal é agendar deploys em janelas de baixo tráfego e avisar a comunidade com antecedência. Para o ConnectServer e serviços web, é possível fazer deploy com zero downtime usando um balanceador simples.