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

How to sync configurations between environments on your MU Online server

Keep configurations consistent between staging and production on your MU Online server, using environment variables, versioned template files, and a clear change promotion process.

BR Bruno · Updated on Feb 2, 2026 · ⏱ 13 min read
Quick answer

A common problem on MU Online servers managed by more than one person is silent configuration drift between environments: the administrator tests a change in staging, it works, but forgets to apply the same change to production — or worse, applies a slightly different version, creating a bug that on

A common problem on MU Online servers managed by more than one person is silent configuration drift between environments: the administrator tests a change in staging, it works, but forgets to apply the same change to production — or worse, applies a slightly different version, creating a bug that only shows up in front of players. Systematically syncing configurations between environments, with a clear process for "what's the same everywhere" versus "what's specific to each environment," eliminates this entire class of error. This tutorial shows how to structure that process, from template files to the change promotion workflow.

The problem of diverging configuration

MU servers typically have dozens of configuration files scattered around: GameServerInfo.dat, ConnectServerInfo.dat, balancing .ini files (experience rate, drop, PvP), event configurations, and database connection strings. When each environment (development, staging, production) has these files edited manually and without control, it's practically guaranteed they will diverge in undocumented ways — and the day this is discovered is usually the day something has already broken in production.

Separating what's common from what's environment-specific

The first conceptual step is to classify each configuration into two categories:

CategoryExampleWhere it should live
Common to all environmentsExperience rates, event rules, item optionsGit repository, versioned, identical everywhere
Specific to each environmentDatabase IP/host, password, port, license keyEnvironment variable or secrets vault, never in Git

Mixing these two categories in the same file is what causes most problems — an event configuration file shouldn't contain the production database password in the same structure.

Configuration template structure

Instead of maintaining a complete configuration file per environment, keep a versioned template with placeholders, and generate the final file at deploy time by substituting the placeholders with the environment's values:

; template: GameServerInfo.template.ini
[Database]
Server={{DB_HOST}}
Database=MuOnline
User={{DB_USER}}
Password={{DB_PASSWORD}}

[Rates]
ExperienceRate=1.0
DropRate=0.7
ZenRate=1.0

[Server]
ServerName={{SERVER_NAME}}
MaxConnections={{MAX_CONNECTIONS}}

Experience and drop rates are the same in staging and production (so the test is representative); the database host and server name change per environment.

Generating the final file per environment

A simple placeholder substitution script, using environment-specific variables:

#!/bin/bash
set -euo pipefail
ENV_FILE=".env.$1"   # e.g.: .env.staging or .env.production
source "$ENV_FILE"

envsubst < config/GameServerInfo.template.ini > /opt/mu-server/config/GameServerInfo.ini

echo "[sync] Configuration generated for environment: $1"

Each environment has its own .env file (never committed to Git — only a .env.example with placeholders goes into the repository), keeping sensitive values out of version control while the structure stays identical.

# .env.staging (not versioned)
DB_HOST=10.1.2.10
DB_USER=gameserver_svc_staging
DB_PASSWORD=StagingPassword123
SERVER_NAME=MU-Staging
MAX_CONNECTIONS=50

# .env.production (not versioned)
DB_HOST=10.0.3.10
DB_USER=gameserver_svc
DB_PASSWORD=StrongProductionPassword!2026
SERVER_NAME=MU-Production
MAX_CONNECTIONS=1000

Change promotion flow between environments

Every common configuration change (rates, events, rules) should follow a promotion flow, never be edited directly in production:

  1. The change is made in the versioned template, on a development branch.
  2. The template is applied to staging first, generating the final file with the staging variables.
  3. The team tests the behavior in staging (event, new rate, new item).
  4. If approved, the change is merged into the main branch.
  5. The deploy pipeline applies the same template to production, with the production variables.

This flow ensures production never receives a configuration that hasn't been through staging first — eliminating silent drift.

Comparing environments automatically

To detect drift that already exists (files manually edited in the past, outside the process), a structural comparison script helps identify what diverges beyond what's expected:

#!/bin/bash
# Compares the keys present in each environment, ignoring values expected to differ
diff <(grep -oP '^\w+(?==)' /opt/mu-server-staging/config/GameServerInfo.ini | sort) \
     <(grep -oP '^\w+(?==)' /opt/mu-server-production/config/GameServerInfo.ini | sort)

If the diff output isn't empty, it means a key exists in one environment and not the other — a clear sign of configuration that has fallen out of sync.

Table of typical configurations and their category

File/keyCategoryNote
Experience/drop/zen ratesCommonShould be identical between staging and production for representative testing
Event rules (time, reward)CommonVersioned; times may have a specific override in staging for quick testing
Database host/port/passwordSpecificNever versioned; comes from .env or a secrets vault
Server name shown in the clientSpecificStaging should make it clear it's not production
Emulator license keySpecificEach environment with its own license, if applicable
Concurrent connection limitSpecificStaging typically much lower than production

Syncing the database schema between environments

Beyond configuration files, the database schema (tables, columns, stored procedures) also needs to stay in sync. Use the same set of versioned migrations (see the continuous deployment tutorial) applied to both environments, in the same order, never altering the schema manually directly in production after already having tested it in staging.

Handling sensitive data when syncing staging with production

When staging needs a copy of production data for more realistic testing (not just configuration, but data), never copy the raw dump. Anonymize it first:

-- Run only on the staging database, after restoring a copy
UPDATE Account SET Password = 'generic_test_hash', Email = 'test+' + CAST(AccountID AS VARCHAR) + '@staging.local';
UPDATE MEMB_STAT SET bloc1='0',bloc2='0',bloc3='0',bloc4='0' WHERE 1=1; -- example of zeroing sensitive payment fields, if present

Document this anonymization script as part of the data sync process, not as a manual step "remembered from memory."

Tools that help formalize this process

For larger teams, configuration management tools (Ansible, Terraform for infrastructure, or even a simple templating system with Jinja2/envsubst as shown above) make this process auditable and repeatable. What matters isn't which tool, but the principle: no configuration should exist only in an administrator's head or terminal — everything should be versioned, with a clear process for how it moves from one environment to another.

Common errors and fixes

SymptomLikely causeFix
Bug appears in production but not in stagingDiverging configuration between environments (rate, rule)Run the structural comparison script and align via the templates
Database password leaked in the Git repositorySensitive value placed directly in the template instead of a variableMove it to .env/secrets vault and rewrite Git history if necessary
Staging doesn't reflect real production behaviorStaging rates/rules different from production "to make testing easier"Use the same common rates; adjust only what's necessary (e.g. connection limit)
Change applied to production without going through stagingNo formal promotion process in placeImplement the merge + deploy flow described in this tutorial
Test data in staging exposes real player informationProduction copy used without anonymizationRun the anonymization script before making the dump available in staging

Environment sync checklist

  • Configurations classified between "common" and "environment-specific".
  • Templates versioned in Git, with no embedded secrets.
  • .env files per environment, outside version control.
  • Promotion flow (staging before production) documented and followed.
  • Structural comparison script run periodically to detect drift.
  • Database schema synced via versioned migrations, not manual editing.
  • Anonymization process defined for data copied from production to staging.

With configurations reliably synced between environments, the next step is connecting this process to the automated deploy pipeline — see the continuous deployment script tutorial for MU Online servers to close the loop between configuration, build, and production release.

Frequently asked questions

What's the difference between syncing and simply copying config files between environments?

Blindly copying drags environment-specific values (like a production database IP) into another, breaking the destination. Syncing means keeping the structure and non-sensitive values identical, while values specific to each environment (hosts, passwords, keys) come from that environment's own variables.

Does staging need to have exactly the same data as production?

No, and generally it shouldn't. Staging should have the same configuration structure and database schema, but with synthetic data or an anonymized copy — never real player passwords or real payment history.

How do I prevent an administrator from forgetting to apply a configuration change to production after testing it in staging?

Treat every configuration change like a code change: versioned in Git, reviewed by someone else (pull request), and applied through a defined deploy process, not manual editing directly on the server. This removes the dependency on human memory.

Where should I store secrets (passwords, API keys) if they can't go into the Git repository?

Use environment variables injected at deploy time, or a dedicated secrets vault (Vault, AWS Secrets Manager, Azure Key Vault). The repository should only contain templates with placeholders, never the actual secret values.

Is it worth having more than two environments (e.g. dev, staging, production)?

It depends on team size. For a small server with one or two administrators, dev and staging can be combined. For larger teams or servers with a high frequency of changes, separating all three reduces the risk of an unstable change reaching production directly.

BR
Events, maps & items editor

Bruno specializes in MU Online events, maps, bosses and item economy. He documents every detail based on real gameplay.

Keep reading

Related articles