Brazil's biggest MU Online portal — since 2003
Tutorial Advanced Infrastructure

How to build a CI pipeline for MU Online server changes

Structure a continuous integration (CI) pipeline for your MU Online server's configurations and scripts, with version control, a staging environment, automated tests, and controlled production deploys.

GA Gabriel · Updated on Apr 16, 2025 · ⏱ 17 min read
Quick answer

Changing a MU Online server's configuration files in production with no process — editing directly on the server via RDP, with no backup, with no prior testing — is the most common recipe for incidents: a GameServer that won't boot, an event that doesn't trigger, an item duplicated by a misconfigure

Changing a MU Online server's configuration files in production with no process — editing directly on the server via RDP, with no backup, with no prior testing — is the most common recipe for incidents: a GameServer that won't boot, an event that doesn't trigger, an item duplicated by a misconfigured condition. A CI (continuous integration) pipeline brings the same discipline used in software development to private server operations: every change goes through version control, automated validation, and a test environment before reaching production. This tutorial shows how to structure that pipeline specifically for the particularities of a MU server (configuration files, SQL scripts, client binaries).

Why treat server configuration as code

The files that define your server's behavior — Item.txt, MonsterSetBase.txt, drop settings, event scripts, SQL procedures — are, in practice, code: they determine behavior, have dependencies among each other, and can break the system if edited incorrectly. Treating them as code means applying the same practices: versioning, review before applying, an isolated test environment, and an auditable history of who changed what and when.

Organize a (private) Git repository mirroring the server's folder structure, clearly separating what is versionable configuration from what is generated or too large a binary to version directly:

mu-server-config/
├── GameServer/
│   ├── Data/ItemList.xml
│   ├── Data/MonsterSetBase.txt
│   └── GameServerInfo.dat
├── ConnectServer/
│   └── ConnectServerInfo.dat
├── sql/
│   ├── migrations/
│   │   ├── 001_add_socket_columns.sql
│   │   └── 002_add_event_log_table.sql
│   └── procedures/
├── scripts/
│   ├── deploy_staging.ps1
│   └── deploy_production.ps1
└── .github/workflows/
    └── ci.yml

Large binary files (BMD models for custom items/wings, textures) go in a separate repository or use Git LFS, so they don't bloat the history of the main configuration repository.

Environments: local, staging, and production

A CI pipeline only works with at least two environments beyond the development machine: staging (a faithful replica of production, but isolated, with no real players) and production (the server players connect to). Every change follows the same path: edit locally → commit → automatic deploy to staging → validation → manual approval → deploy to production.

EnvironmentPurposeWho accesses it
Local/devEditing and initial isolated testingDeveloper/admin
StagingProduction replica for full validationInternal team, test GMs
ProductionReal server, players connectedPlayers

Defining the pipeline in GitHub Actions

A basic CI workflow for this scenario covers three stages: syntax validation, staging deploy, and, pending approval, production deploy.

name: MU Server CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  validate:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
      - name: Validate configuration file syntax
        run: powershell -File scripts/validate_config.ps1
      - name: Validate SQL scripts (dry-run)
        run: powershell -File scripts/validate_sql.ps1

  deploy-staging:
    needs: validate
    if: github.ref == 'refs/heads/main'
    runs-on: self-hosted
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to staging
        run: powershell -File scripts/deploy_staging.ps1
      - name: Smoke test (login, create character)
        run: powershell -File scripts/smoke_test.ps1

  deploy-production:
    needs: deploy-staging
    if: github.ref == 'refs/heads/main'
    runs-on: self-hosted
    environment:
      name: production
    steps:
      - name: Deploy to production (with manual approval)
        run: powershell -File scripts/deploy_production.ps1

The deploy-production job uses a protected environment on GitHub, requiring a manual approval from a responsible person before running — this prevents any merge from triggering a direct production deploy without a final human review.

Self-hosted runners: why they're needed here

Unlike a typical web application pipeline, deploying a MU server needs to run on a Windows machine with direct access to MuServer and SQL Server — usually the server machine itself or an intermediary on the same network. Because of this, the deploy stages use self-hosted runners (GitHub Actions agents installed on your own infrastructure), while syntax validation, which doesn't depend on the real environment, can run on hosted runners (windows-latest).

Automated tests possible in this context

Test typeWhat it validatesWhen it runs
Syntax validationConfig file is well-formed (valid XML/INI)Every commit
SQL dry-runSQL migration runs without error on a test databaseEvery commit touching sql/
Smoke testGameServer boots, login works, character is created and equips a basic itemAfter staging deploy
Custom system regression testSockets, custom wings, events keep workingBefore production deploy, when the PR touches these files

Smoke tests can be scripted with an automated test client or, at minimum, a quick manual checklist run by a GM before production approval.

Managing database migrations with versioning

SQL scripts that alter the schema (new columns, log tables, procedures) should follow sequential numbering and be idempotent whenever possible — that is, safe to run more than once without duplicating the effect:

-- 002_add_event_log_table.sql
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'EventLog')
BEGIN
    CREATE TABLE EventLog (
        EventLogID INT IDENTITY PRIMARY KEY,
        EventName VARCHAR(100),
        CreateDate DATETIME DEFAULT GETDATE()
    );
END

Keep a control table (SchemaVersion) tracking which migrations have already run in each environment, avoiding reapplying scripts that already executed.

Rollback: planning the exit before the entrance

Every deploy needs a documented rollback plan before it's executed, not improvised after an incident. For configuration files, that means always keeping the previous version available (Git already covers this via git revert); for SQL schema changes, every migration should have a corresponding rollback script (002_add_event_log_table_rollback.sql) tested in staging before going to production.

Approval and audit trail

Use pull requests as the formal review mechanism: no configuration change goes to the main branch without at least one approval from another team member (or, on smaller teams, a second self-check on a different day, to reduce the "looks right because I just wrote it" bias). Git history, combined with GitHub's approval log, becomes the audit trail: who changed what, when, and who approved it.

Common errors and fixes

SymptomLikely causeFix
Deploy breaks production with no warningNo staging before the real deployAlways go through staging with a smoke test before production
SQL migration fails in production but passed in stagingData/schema difference between environmentsPeriodically sync a production snapshot into staging
No one knows how to revert a changeNo documented rollback scriptRequire a tested rollback as part of every schema migration PR
Pipeline stalls for lack of a runnerSelf-hosted runner offlineMonitor the runner machine and set up an availability alert
Critical change applied without reviewDirect deploy on the main branch without a PRProtect the main branch requiring PR and approval

CI pipeline checklist

  • Git repository created with a structure mirroring the server's folders.
  • Isolated staging environment configured as a production replica.
  • CI workflow with syntax validation on every commit.
  • Automated smoke tests or manual checklist after staging deploy.
  • Manual approval required before production deploy.
  • SQL migration scripts numbered, idempotent, and with tested rollback.
  • Main branch protected, requiring pull request and review.
  • Audit trail (who changed what, when) accessible through Git history.

With the pipeline running, every configuration change, custom system, or SQL script becomes traceable and reversible — a solid foundation for safely evolving the server's more advanced systems, like the ones described in the MU Online server creation tutorial.

Frequently asked questions

Is it worth setting up CI for a small/hobby server?

A simplified version pays off even on small projects: at minimum version control (Git) for configurations and a staging environment to test before applying to production. The full pipeline with automated tests pays off more on servers with a team and frequent changes.

How do I version-control MuServer's binary files (like item .bmd files)?

Git doesn't handle binary diffs well, but it's still worth versioning — use Git LFS (Large File Storage) for large/binary files, keeping the history without bloating the main repository with full blobs on every change.

Is it safe to automate deployment straight to production?

Not without an intermediate staging step. The recommended flow is always commit → staging → validation (manual or automated) → approval → production. Skipping staging is the most common cause of breaking the server at peak hours due to an untested configuration change.

What kind of automated test makes sense for MU server configuration?

Syntax tests (the configuration file is valid and the GameServer boots without error), smoke tests (login, create character, equip a basic item), and regression tests on custom systems (sockets, wings, events) before every deploy that touches those files.

Do I need a dedicated CI server (Jenkins, GitHub Actions) for this?

Not necessarily from scratch. GitHub Actions or GitLab CI (with your own runners, since the build/deploy likely runs on a Windows machine with MuServer) handle most cases well with no additional infrastructure cost beyond the runner itself.

GA
Guides & builds editor

Gabriel covers gameplay, class builds, PvP and progression. He tests every strategy on a live server before publishing.

Keep reading

Related articles