From c62545faf124c0e7f929194ed2e30c73b322d324 Mon Sep 17 00:00:00 2001 From: Jeremy lb Date: Fri, 11 Sep 2026 13:40:34 +0000 Subject: [PATCH 1/9] try this build --- .github/workflows/docker_build.yml | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 7341a089e..706c8b949 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -6,11 +6,9 @@ on: pull_request: branches: [ master, united ] -# Builds images and pushes nothing, so read is all the token ever needs -- at the -# workflow level and again on the job, because a job may widen what the workflow grants -# but never the other way round. permissions: contents: read + packages: write concurrency: group: docker-build-${{ github.ref }} @@ -21,6 +19,7 @@ jobs: runs-on: ubuntu-latest permissions: contents: read + packages: write # Appliqué aussi au niveau du job steps: - name: Checkout repository @@ -29,6 +28,13 @@ jobs: submodules: recursive fetch-depth: 1 + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -37,8 +43,10 @@ jobs: with: context: . file: extra/docker/DockerFile-mangosd - tags: mangosd:latest - push: false + tags: | + ghcr.io/${{ github.repository_owner }}/mangosd:latest + ghcr.io/${{ github.repository_owner }}/mangosd:v${{ github.run_number }} + push: ${{ github.ref == 'refs/heads/master' }} cache-from: type=gha,scope=mangosd cache-to: type=gha,scope=mangosd,mode=max @@ -47,7 +55,9 @@ jobs: with: context: . file: extra/docker/DockerFile-realmd - tags: realmd:latest - push: false + tags: | + ghcr.io/${{ github.repository_owner }}/realmd:latest + ghcr.io/${{ github.repository_owner }}/realmd:v${{ github.run_number }} + push: ${{ github.ref == 'refs/heads/master' }} cache-from: type=gha,scope=realmd cache-to: type=gha,scope=realmd,mode=max From 4ff44ff1a267fa9fa32c397cae109eff396a1e5b Mon Sep 17 00:00:00 2001 From: Jeremy lb Date: Fri, 11 Sep 2026 14:20:00 +0000 Subject: [PATCH 2/9] Refresh docker build --- .github/workflows/docker_build.yml | 4 ++-- extra/docker/{Readme.txt => README.md} | 3 ++- extra/docker/docker-compose.yml | 5 ++--- extra/docker/{DockerFile-mangosd => mangosd.Dockerfile} | 4 ++-- extra/docker/{DockerFile-realmd => realmd.Dockerfile} | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) rename extra/docker/{Readme.txt => README.md} (99%) rename extra/docker/{DockerFile-mangosd => mangosd.Dockerfile} (94%) rename extra/docker/{DockerFile-realmd => realmd.Dockerfile} (93%) diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 706c8b949..7a6c4288f 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -42,7 +42,7 @@ jobs: uses: docker/build-push-action@v6 with: context: . - file: extra/docker/DockerFile-mangosd + file: extra/docker/mangosd.Dockerfile tags: | ghcr.io/${{ github.repository_owner }}/mangosd:latest ghcr.io/${{ github.repository_owner }}/mangosd:v${{ github.run_number }} @@ -54,7 +54,7 @@ jobs: uses: docker/build-push-action@v6 with: context: . - file: extra/docker/DockerFile-realmd + file: extra/docker/realmd.Dockerfile tags: | ghcr.io/${{ github.repository_owner }}/realmd:latest ghcr.io/${{ github.repository_owner }}/realmd:v${{ github.run_number }} diff --git a/extra/docker/Readme.txt b/extra/docker/README.md similarity index 99% rename from extra/docker/Readme.txt rename to extra/docker/README.md index 357848bd3..10380a389 100644 --- a/extra/docker/Readme.txt +++ b/extra/docker/README.md @@ -17,4 +17,5 @@ Here the default values: - MYSQL_ROOT_PASSWORD=mangos - MYSQL_ROOT_HOST=% -The database need to be run manualy in order to have it initialize \ No newline at end of file +The database need to be run manualy in order to have it initialize + diff --git a/extra/docker/docker-compose.yml b/extra/docker/docker-compose.yml index 7d079772e..de08e9c63 100644 --- a/extra/docker/docker-compose.yml +++ b/extra/docker/docker-compose.yml @@ -1,12 +1,11 @@ #To start the server from this docker-compose file you can run the command "docker-compose up" #Configure the location of the configuration file and the data folder #The connection to mysql should match the name of the service in this case "mysqldb" -version: "2.4" services: mangosd: build: context: .. - dockerfile: docker/DockerFile-mangosd + dockerfile: docker/mangosd.Dockerfile depends_on: - mysqldb restart: always @@ -23,7 +22,7 @@ services: realmd: build: context: .. - dockerfile: docker/DockerFile-realmd + dockerfile: docker/realmd.Dockerfile depends_on: - mysqldb restart: always diff --git a/extra/docker/DockerFile-mangosd b/extra/docker/mangosd.Dockerfile similarity index 94% rename from extra/docker/DockerFile-mangosd rename to extra/docker/mangosd.Dockerfile index 25dd0ddbc..6b590ef11 100644 --- a/extra/docker/DockerFile-mangosd +++ b/extra/docker/mangosd.Dockerfile @@ -1,5 +1,5 @@ #Build image -FROM ubuntu:22.04 AS build-step +FROM ubuntu:26.04 AS build-step ENV TZ=US DEBIAN_FRONTEND=noninteractive @@ -17,7 +17,7 @@ RUN make -j4 RUN make install #Runtime image -FROM ubuntu:22.04 AS runtime +FROM ubuntu:26.04 AS runtime ENV TZ=US DEBIAN_FRONTEND=noninteractive diff --git a/extra/docker/DockerFile-realmd b/extra/docker/realmd.Dockerfile similarity index 93% rename from extra/docker/DockerFile-realmd rename to extra/docker/realmd.Dockerfile index e9bddb863..82dba1bdb 100644 --- a/extra/docker/DockerFile-realmd +++ b/extra/docker/realmd.Dockerfile @@ -1,5 +1,5 @@ #Build image -FROM ubuntu:22.04 AS build-step +FROM ubuntu:26.04 AS build-step ENV TZ=US DEBIAN_FRONTEND=noninteractive @@ -17,7 +17,7 @@ RUN make -j4 RUN make install #Runtime image -FROM ubuntu:22.04 AS runtime +FROM ubuntu:26.04 AS runtime RUN apt-get -y update && apt-get -y upgrade RUN apt-get -y install libmysqlclient-dev openssl From 3c1a66ed12f8a1f0b2a8dae144b0abd86b3f72a8 Mon Sep 17 00:00:00 2001 From: Jeremy El Bez Date: Fri, 11 Sep 2026 10:50:07 -0400 Subject: [PATCH 3/9] Add build version --- .github/workflows/docker_build.yml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 7a6c4288f..ed4ba488e 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -26,7 +26,21 @@ jobs: uses: actions/checkout@v4 with: submodules: recursive - fetch-depth: 1 + # 0 = full history + tags, required so `git describe` below can see + # the release tags (v21.9.29, ...). A shallow depth omits tags and + # `describe` would fall back to a bare short hash. + fetch-depth: 0 + + - name: Determine release version + id: version + # Same command GenRevision.cmake uses, so the image tag matches the + # revision string the compiled server reports at startup. + run: | + # Drop the trailing "-g" that git describe appends, keeping + # just "-" (e.g. v21.9.29-593). + VERSION="$(git describe --tags --always --dirty | sed 's/-g[0-9a-f]\{7,\}//')" + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "Release version: ${VERSION}" - name: Log in to GitHub Container Registry uses: docker/login-action@v3 @@ -45,7 +59,7 @@ jobs: file: extra/docker/mangosd.Dockerfile tags: | ghcr.io/${{ github.repository_owner }}/mangosd:latest - ghcr.io/${{ github.repository_owner }}/mangosd:v${{ github.run_number }} + ghcr.io/${{ github.repository_owner }}/mangosd:${{ steps.version.outputs.version }} push: ${{ github.ref == 'refs/heads/master' }} cache-from: type=gha,scope=mangosd cache-to: type=gha,scope=mangosd,mode=max @@ -57,7 +71,7 @@ jobs: file: extra/docker/realmd.Dockerfile tags: | ghcr.io/${{ github.repository_owner }}/realmd:latest - ghcr.io/${{ github.repository_owner }}/realmd:v${{ github.run_number }} + ghcr.io/${{ github.repository_owner }}/realmd:${{ steps.version.outputs.version }} push: ${{ github.ref == 'refs/heads/master' }} cache-from: type=gha,scope=realmd cache-to: type=gha,scope=realmd,mode=max From 6a8c941ad8a3778dc7684e9a3756d3de356d0080 Mon Sep 17 00:00:00 2001 From: Jeremy El Bez Date: Fri, 11 Sep 2026 11:28:48 -0400 Subject: [PATCH 4/9] handle tag differently --- .github/workflows/docker_build.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index ed4ba488e..5b33c3add 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -36,11 +36,16 @@ jobs: # Same command GenRevision.cmake uses, so the image tag matches the # revision string the compiled server reports at startup. run: | - # Drop the trailing "-g" that git describe appends, keeping - # just "-" (e.g. v21.9.29-593). - VERSION="$(git describe --tags --always --dirty | sed 's/-g[0-9a-f]\{7,\}//')" + # If this exact commit carries a tag, that tag is the version. + # Otherwise there is no release for this commit, so publish it as a + # beta keyed to the short commit sha (e.g. beta-4ff44ff1a). + if VERSION="$(git describe --tags --exact-match 2>/dev/null)"; then + echo "Tagged release: ${VERSION}" + else + VERSION="beta-$(git rev-parse --short HEAD)" + echo "No tag on this commit; using ${VERSION}" + fi echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - echo "Release version: ${VERSION}" - name: Log in to GitHub Container Registry uses: docker/login-action@v3 From 13bea67cecf1f64da4fbd3b4444f569539e3bded Mon Sep 17 00:00:00 2001 From: Jeremy El Bez Date: Fri, 11 Sep 2026 12:24:24 -0400 Subject: [PATCH 5/9] Refresh docker compose to be more parametrize --- .github/workflows/docker_build.yml | 14 +-- .gitignore | 4 + extra/docker/.env.example | 58 +++++++++++++ extra/docker/README.md | 119 +++++++++++++++++++++----- extra/docker/docker-compose.build.yml | 14 +++ extra/docker/docker-compose.yml | 53 ++++++++---- extra/docker/docker-entrypoint.sh | 70 +++++++++++++++ extra/docker/mangosd.Dockerfile | 8 +- extra/docker/realmd.Dockerfile | 8 +- 9 files changed, 301 insertions(+), 47 deletions(-) create mode 100644 extra/docker/.env.example create mode 100644 extra/docker/docker-compose.build.yml create mode 100644 extra/docker/docker-entrypoint.sh diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 5b33c3add..2dc794c66 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -36,14 +36,18 @@ jobs: # Same command GenRevision.cmake uses, so the image tag matches the # revision string the compiled server reports at startup. run: | - # If this exact commit carries a tag, that tag is the version. - # Otherwise there is no release for this commit, so publish it as a - # beta keyed to the short commit sha (e.g. beta-4ff44ff1a). + SHA="$(git rev-parse --short HEAD)" + # A tag on this exact commit wins outright -> e.g. "v22.04.245" if VERSION="$(git describe --tags --exact-match 2>/dev/null)"; then echo "Tagged release: ${VERSION}" + # master with no tag on the commit -> e.g. "master-4ff44ff1a" + elif [ "${{ github.ref }}" = "refs/heads/master" ]; then + VERSION="master-${SHA}" + echo "master build: ${VERSION}" + # any other branch -> e.g. "beta-4ff44ff1a" else - VERSION="beta-$(git rev-parse --short HEAD)" - echo "No tag on this commit; using ${VERSION}" + VERSION="beta-${SHA}" + echo "non-master build: ${VERSION}" fi echo "version=${VERSION}" >> "$GITHUB_OUTPUT" diff --git a/.gitignore b/.gitignore index a996968a6..d9502c194 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,7 @@ docs/superpowers/ # "working tree is clean" guard fails on the cache rather than on a real change. .ccache/ .sccache/ + +# Local docker environment overrides (may hold credentials); keep the example. +.env +!.env.example diff --git a/extra/docker/.env.example b/extra/docker/.env.example new file mode 100644 index 000000000..ddf948ad7 --- /dev/null +++ b/extra/docker/.env.example @@ -0,0 +1,58 @@ +# Copy this file to ".env" (in this extra/docker folder) and adjust as needed. +# docker compose reads .env automatically; every value below is optional and +# falls back to the default shown if left unset. + +################################################################################ +# Image selection (docker-compose.yml only; ignored by the local build file) +################################################################################ + +# GitHub Container Registry owner the images were published under. +REGISTRY_OWNER=mangostwo +# Image tag to pull. Matches the docker_build.yml workflow output: +# a git tag (v22.04.245), master-, beta-, or latest. +MANGOS_TAG=latest + +################################################################################ +# Database connection used by mangosd / realmd +# +# On first start the entrypoint seeds mangosd.conf / realmd.conf from these +# values. If a .conf already exists in the mounted etc folder it is left +# untouched, so these are ignored once the files exist. +################################################################################ + +# Host of the MySQL server. Inside compose this is the "mysqldb" service name. +DB_HOST=mysqldb +DB_PORT=3306 +# Credentials mangosd/realmd log in with. Defaulted to root because the bundled +# mysql image only grants full DB access to root (the mangos user has none). +DB_USER=root +DB_PASS=mangos +# Database (schema) names. +DB_REALMD=realmd +DB_WORLD=mangos2 +DB_CHARS=character2 + +################################################################################ +# Bundled MySQL container +################################################################################ + +MYSQL_USER=mangos +MYSQL_PASSWORD=mangos +MYSQL_ROOT_PASSWORD=mangos +# Host mask the root account may connect from. "%" = any host, required so the +# mangosd/realmd containers can reach it over the compose network. +MYSQL_ROOT_HOST=% + +################################################################################ +# Public address players connect to (NOT set here — see note) +# +# The address the game client connects to is stored in the realmd database, in +# the `realmlist` table's `address` column, NOT in any .conf file or env var. +# After the databases are initialised, set it manually, e.g.: +# +# UPDATE realmd.realmlist SET address = '203.0.113.10' WHERE id = 1; +# +# Use the server's public IP or DNS name (127.0.0.1 only works for a client on +# the same machine). realmd's BindIP in the conf stays 0.0.0.0 (listen on all +# interfaces) and does not need changing for containers. +################################################################################ diff --git a/extra/docker/README.md b/extra/docker/README.md index 10380a389..57d339d28 100644 --- a/extra/docker/README.md +++ b/extra/docker/README.md @@ -1,21 +1,100 @@ -How to start: -To start the docker container use the command "docker-compose up" inside the extra/docker folder -If you need to rebuild the images use "docker-compose build" - -Now to setup the server make sure you have the correct configuration and the data folder in the correct location: -The configuration should be place here "../../etc" from the extra/docker folder -The data folder should be place here "../../data" from the extra/docker folder -Note: those paths can be change inside the docker-compose.yml file - -Configutation: -Inside your "mangosd.conf" make sure the "DataDir" is set to "/mangos/data" -Make sure all the mysql hostname is set to "mysqldb" -The Mysql connection seting is set inside the docker-compose.yml file and can be change -Here the default values: -- MYSQL_USER=mangos -- MYSQL_PASSWORD=mangos -- MYSQL_ROOT_PASSWORD=mangos -- MYSQL_ROOT_HOST=% - -The database need to be run manualy in order to have it initialize +# Running MangosTwo with Docker +This folder contains everything needed to run the world server (`mangosd`) and +login server (`realmd`) in containers, backed by a MySQL container. + +There are two compose files: + +| File | Use | +| --------------------------- | -------------------------------------------------------------- | +| `docker-compose.yml` | Pull prebuilt images from GitHub Container Registry (default). | +| `docker-compose.build.yml` | Build the images locally from the Dockerfiles here. | + +`docker-compose.build.yml` is an *override* layered on top of the base file. + +## 1. Configure + +Copy the example environment file and edit it: + +```sh +cp .env.example .env +``` + +`docker compose` reads `.env` automatically. Every value is optional and falls +back to a sensible default; see `.env.example` for the full list. The common +ones: + +- `REGISTRY_OWNER` / `MANGOS_TAG` — which image and tag to pull (registry mode). +- `DB_HOST`, `DB_PORT`, `DB_USER`, `DB_PASS`, `DB_REALMD`, `DB_WORLD`, `DB_CHARS` + — the database connection the servers use. +- `MYSQL_USER`, `MYSQL_PASSWORD`, `MYSQL_ROOT_PASSWORD`, `MYSQL_ROOT_HOST` + — the bundled MySQL container. + +### Config files are generated for you + +On first start each container seeds its config from the shipped template: + +- If `mangosd.conf` / `realmd.conf` does **not** exist in the mounted `etc` + folder, it is created from the `.conf.dist` and the database connection lines + are filled in from the `DB_*` variables above. +- If the `.conf` already exists, it is left untouched — edit it by hand for + anything the environment variables do not cover. + +The config and data folders are bind-mounted from the repository: + +- configuration: `../../etc` → `/mangos/etc` +- client data: `../../data` → `/mangos/data` + +These paths can be changed in `docker-compose.yml`. Inside `mangosd.conf`, +`DataDir` should be `/mangos/data`. + +## 2. Start + +Registry images (default): + +```sh +docker compose pull +docker compose up +``` + +Build locally instead: + +```sh +docker compose -f docker-compose.yml -f docker-compose.build.yml up --build +``` + +## 3. Initialise the databases + +The MySQL data is stored in `../../dbdata`. The game databases must be created +and populated once before the servers will run — see the `mangostwo/database` +repository for the schema and migrations. The `mysqldb` service must be running +for this step. + +## 4. Set the public address players connect to + +The address the game **client** connects to is stored in the database, not in a +config file. After the databases are initialised, point the realm at your +public IP or DNS name: + +```sql +UPDATE realmd.realmlist SET address = '203.0.113.10' WHERE id = 1; +``` + +`127.0.0.1` only works for a client on the same machine. `realmd`'s `BindIP` +stays `0.0.0.0` (listen on all interfaces) and does not need changing. + +## Ports + +- `8085` — world server (`mangosd`) +- `3724` — login server (`realmd`) +- `3306` — MySQL + +## Kubernetes / other orchestrators + +The entrypoint is baked into the image and behaves well outside compose: + +- Mount your own `mangosd.conf` / `realmd.conf` and the entrypoint leaves it + alone (it only seeds when absent). +- Override the command entirely and it is `exec`'d verbatim, e.g. + `command: ["/usr/local/bin/docker-entrypoint.sh", "mangosd"]` with your own + `args`. diff --git a/extra/docker/docker-compose.build.yml b/extra/docker/docker-compose.build.yml new file mode 100644 index 000000000..435642f2e --- /dev/null +++ b/extra/docker/docker-compose.build.yml @@ -0,0 +1,14 @@ +# Builds the server images locally from the Dockerfiles in this folder. +# docker compose -f docker-compose.yml -f docker-compose.build.yml up --build +# Configure the location of the configuration file and the data folder. +# The connection to mysql should match the name of the service, here "mysqldb". +services: + mangosd: + build: + context: .. + dockerfile: docker/mangosd.Dockerfile + + realmd: + build: + context: .. + dockerfile: docker/realmd.Dockerfile \ No newline at end of file diff --git a/extra/docker/docker-compose.yml b/extra/docker/docker-compose.yml index de08e9c63..8f7d44a35 100644 --- a/extra/docker/docker-compose.yml +++ b/extra/docker/docker-compose.yml @@ -1,14 +1,29 @@ -#To start the server from this docker-compose file you can run the command "docker-compose up" -#Configure the location of the configuration file and the data folder -#The connection to mysql should match the name of the service in this case "mysqldb" +# Pulls the prebuilt server images published to GitHub Container Registry by +# .github/workflows/docker_build.yml (no local compilation). +# docker compose -f docker-compose.ghcr.yml pull +# docker compose -f docker-compose.ghcr.yml up +# +# Select the owner and tag without editing this file, e.g.: +# REGISTRY_OWNER=mangostwo MANGOS_TAG=v22.04.245 \ +# docker compose -f docker-compose.ghcr.yml up +# Tag values follow the workflow: a git tag (v22.04.245), master-, +# beta-, or latest. services: mangosd: - build: - context: .. - dockerfile: docker/mangosd.Dockerfile + image: ghcr.io/${REGISTRY_OWNER:-mangostwo}/mangosd:${MANGOS_TAG:-latest} depends_on: - mysqldb - restart: always + restart: unless-stopped + # The entrypoint seeds mangosd.conf from these on first start (only when + # no mangosd.conf already exists in the mounted etc directory). + environment: + - DB_HOST=${DB_HOST:-mysqldb} + - DB_PORT=${DB_PORT:-3306} + - DB_USER=${DB_USER:-root} + - DB_PASS=${DB_PASS:-mangos} + - DB_REALMD=${DB_REALMD:-realmd} + - DB_WORLD=${DB_WORLD:-mangos2} + - DB_CHARS=${DB_CHARS:-character2} ports: - "8085:8085" stdin_open: true @@ -20,12 +35,18 @@ services: - ../../data:/mangos/data realmd: - build: - context: .. - dockerfile: docker/realmd.Dockerfile + image: ghcr.io/${REGISTRY_OWNER:-mangostwo}/realmd:${MANGOS_TAG:-latest} depends_on: - mysqldb - restart: always + restart: unless-stopped + # The entrypoint seeds realmd.conf from these on first start (only when + # no realmd.conf already exists in the mounted etc directory). + environment: + - DB_HOST=${DB_HOST:-mysqldb} + - DB_PORT=${DB_PORT:-3306} + - DB_USER=${DB_USER:-root} + - DB_PASS=${DB_PASS:-mangos} + - DB_REALMD=${DB_REALMD:-realmd} ports: - "3724:3724" volumes: @@ -34,12 +55,12 @@ services: mysqldb: image: mysql:5.6 - restart: always + restart: unless-stopped environment: - - MYSQL_USER=mangos - - MYSQL_PASSWORD=mangos - - MYSQL_ROOT_PASSWORD=mangos - - MYSQL_ROOT_HOST=% + - MYSQL_USER=${MYSQL_USER:-mangos} + - MYSQL_PASSWORD=${MYSQL_PASSWORD:-mangos} + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-mangos} + - MYSQL_ROOT_HOST=${MYSQL_ROOT_HOST:-%} ports: - "3306:3306" volumes: diff --git a/extra/docker/docker-entrypoint.sh b/extra/docker/docker-entrypoint.sh new file mode 100644 index 000000000..dbf65229a --- /dev/null +++ b/extra/docker/docker-entrypoint.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# Entrypoint for the mangosd / realmd containers. +# +# On first start (when the target .conf does not yet exist) it seeds the config +# from the shipped .conf.dist and rewrites the database connection lines from +# environment variables. If the .conf already exists (e.g. bind-mounted by the +# operator) it is left untouched. +# +# Database environment variables (all optional, defaults shown): +# DB_HOST host of the MySQL server (mysqldb) +# DB_PORT port of the MySQL server (3306) +# DB_USER MySQL user (mangos) +# DB_PASS MySQL password (mangos) +# DB_REALMD realm/login database name (realmd) +# DB_WORLD world database name (mangos2) [mangosd only] +# DB_CHARS character database name (character2)[mangosd only] +set -eu + +DAEMON="${1:?usage: docker-entrypoint.sh [command...]}" +shift + +DB_HOST="${DB_HOST:-mysqldb}" +DB_PORT="${DB_PORT:-3306}" +DB_USER="${DB_USER:-mangos}" +DB_PASS="${DB_PASS:-mangos}" +DB_REALMD="${DB_REALMD:-realmd}" +DB_WORLD="${DB_WORLD:-mangos2}" +DB_CHARS="${DB_CHARS:-character2}" + +CONF="/mangos/etc/${DAEMON}.conf" +# The template is kept outside /mangos/etc so it survives a bind-mount of the +# etc directory (compose mounts the host's etc over /mangos/etc). +DIST="/mangos-defaults/${DAEMON}.conf.dist" + +# Rewrite a "Key = "..."" line in place with a fresh connection string. +set_dbinfo() +{ + key="$1" + dbname="$2" + value="${DB_HOST};${DB_PORT};${DB_USER};${DB_PASS};${dbname}" + # Anchor on the key at start of line; replace the whole line so whatever + # default the .dist carried is overwritten. + sed -i "s|^${key}[[:space:]]*=.*|${key} = \"${value}\"|" "$CONF" +} + +if [ ! -f "$CONF" ] +then + echo "[entrypoint] ${CONF} not found; seeding from ${DIST}" + cp "$DIST" "$CONF" + + set_dbinfo "LoginDatabaseInfo" "$DB_REALMD" + if [ "$DAEMON" = "mangosd" ] + then + set_dbinfo "WorldDatabaseInfo" "$DB_WORLD" + set_dbinfo "CharacterDatabaseInfo" "$DB_CHARS" + fi + echo "[entrypoint] database connection info written to ${CONF}" +else + echo "[entrypoint] ${CONF} exists; leaving it untouched" +fi + +# With no extra arguments, run the daemon against the seeded config. Any +# arguments passed after the daemon name (e.g. a k8s command/args override) +# are exec'd verbatim instead, so the image stays fully controllable. +if [ "$#" -eq 0 ] +then + exec "./${DAEMON}" -c "$CONF" +else + exec "$@" +fi diff --git a/extra/docker/mangosd.Dockerfile b/extra/docker/mangosd.Dockerfile index 6b590ef11..e901c89e3 100644 --- a/extra/docker/mangosd.Dockerfile +++ b/extra/docker/mangosd.Dockerfile @@ -25,12 +25,14 @@ RUN apt-get -y update && apt-get -y upgrade RUN apt-get -y install libmysqlclient-dev openssl lua-readline COPY --from=build-step /mangos /mangos -COPY --from=build-step /mangos/etc/mangosd.conf.dist /mangos/etc/mangosd.conf.dist +# Keep the template outside /mangos/etc so a bind-mount of etc can't hide it. +COPY --from=build-step /mangos/etc/mangosd.conf.dist /mangos-defaults/mangosd.conf.dist +COPY docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh RUN echo "/mangos/lib" >> /etc/ld.so.conf && ldconfig WORKDIR /mangos/bin -RUN chmod +x mangosd +RUN chmod +x mangosd /usr/local/bin/docker-entrypoint.sh EXPOSE 8085 -ENTRYPOINT [ "./mangosd","-c","/mangos/etc/mangosd.conf" ] +ENTRYPOINT [ "/usr/local/bin/docker-entrypoint.sh", "mangosd" ] diff --git a/extra/docker/realmd.Dockerfile b/extra/docker/realmd.Dockerfile index 82dba1bdb..2e10abe62 100644 --- a/extra/docker/realmd.Dockerfile +++ b/extra/docker/realmd.Dockerfile @@ -23,9 +23,11 @@ RUN apt-get -y update && apt-get -y upgrade RUN apt-get -y install libmysqlclient-dev openssl COPY --from=build-step /mangos /mangos -COPY --from=build-step /mangos/etc/realmd.conf.dist /mangos/etc/realmd.conf.dist +# Keep the template outside /mangos/etc so a bind-mount of etc can't hide it. +COPY --from=build-step /mangos/etc/realmd.conf.dist /mangos-defaults/realmd.conf.dist +COPY docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh WORKDIR /mangos/bin -RUN chmod +x realmd +RUN chmod +x realmd /usr/local/bin/docker-entrypoint.sh EXPOSE 3724 -ENTRYPOINT [ "./realmd","-c","/mangos/etc/realmd.conf" ] +ENTRYPOINT [ "/usr/local/bin/docker-entrypoint.sh", "realmd" ] From a9b2afffa8a7ebe0959ca56732aa25dbfaa3e330 Mon Sep 17 00:00:00 2001 From: Jeremy El Bez Date: Fri, 11 Sep 2026 14:05:58 -0400 Subject: [PATCH 6/9] fix build --- extra/docker/docker-compose.build.yml | 10 ++++++---- extra/docker/mangosd.Dockerfile | 2 +- extra/docker/realmd.Dockerfile | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/extra/docker/docker-compose.build.yml b/extra/docker/docker-compose.build.yml index 435642f2e..cc10cec17 100644 --- a/extra/docker/docker-compose.build.yml +++ b/extra/docker/docker-compose.build.yml @@ -5,10 +5,12 @@ services: mangosd: build: - context: .. - dockerfile: docker/mangosd.Dockerfile + # Context is the repository root: the Dockerfile compiles the full source + # tree (COPY . /mangoserver) and copies extra/docker/docker-entrypoint.sh. + context: ../.. + dockerfile: extra/docker/mangosd.Dockerfile realmd: build: - context: .. - dockerfile: docker/realmd.Dockerfile \ No newline at end of file + context: ../.. + dockerfile: extra/docker/realmd.Dockerfile \ No newline at end of file diff --git a/extra/docker/mangosd.Dockerfile b/extra/docker/mangosd.Dockerfile index e901c89e3..568f25574 100644 --- a/extra/docker/mangosd.Dockerfile +++ b/extra/docker/mangosd.Dockerfile @@ -27,7 +27,7 @@ RUN apt-get -y install libmysqlclient-dev openssl lua-readline COPY --from=build-step /mangos /mangos # Keep the template outside /mangos/etc so a bind-mount of etc can't hide it. COPY --from=build-step /mangos/etc/mangosd.conf.dist /mangos-defaults/mangosd.conf.dist -COPY docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +COPY extra/docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh RUN echo "/mangos/lib" >> /etc/ld.so.conf && ldconfig diff --git a/extra/docker/realmd.Dockerfile b/extra/docker/realmd.Dockerfile index 2e10abe62..4b6e58b43 100644 --- a/extra/docker/realmd.Dockerfile +++ b/extra/docker/realmd.Dockerfile @@ -25,7 +25,7 @@ RUN apt-get -y install libmysqlclient-dev openssl COPY --from=build-step /mangos /mangos # Keep the template outside /mangos/etc so a bind-mount of etc can't hide it. COPY --from=build-step /mangos/etc/realmd.conf.dist /mangos-defaults/realmd.conf.dist -COPY docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +COPY extra/docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh WORKDIR /mangos/bin RUN chmod +x realmd /usr/local/bin/docker-entrypoint.sh From 8caae57b1dd39255ac3c6d9ddb1115513d23561f Mon Sep 17 00:00:00 2001 From: Jeremy El Bez Date: Fri, 11 Sep 2026 14:27:37 -0400 Subject: [PATCH 7/9] Allow bring your own config --- extra/docker/.env.example | 6 +++++ extra/docker/README.md | 10 +++++++ extra/docker/docker-entrypoint.sh | 44 +++++++++++++++++++++---------- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/extra/docker/.env.example b/extra/docker/.env.example index ddf948ad7..4883f923d 100644 --- a/extra/docker/.env.example +++ b/extra/docker/.env.example @@ -32,6 +32,12 @@ DB_REALMD=realmd DB_WORLD=mangos2 DB_CHARS=character2 +# Bring your own config: an existing mangosd.conf / realmd.conf in the mounted +# etc folder is ALWAYS left untouched. When true (default) a .conf is seeded +# from the template if none exists; set to false to disable seeding entirely +# (nothing generated even when no .conf is present). +INIT_ENV_CONFIG=true + ################################################################################ # Bundled MySQL container ################################################################################ diff --git a/extra/docker/README.md b/extra/docker/README.md index 57d339d28..2c5085f5b 100644 --- a/extra/docker/README.md +++ b/extra/docker/README.md @@ -29,6 +29,8 @@ ones: — the database connection the servers use. - `MYSQL_USER`, `MYSQL_PASSWORD`, `MYSQL_ROOT_PASSWORD`, `MYSQL_ROOT_HOST` — the bundled MySQL container. +- `INIT_ENV_CONFIG` — whether the entrypoint seeds a `.conf` from the template + when none exists (default `true`; see "Bringing your own configuration"). ### Config files are generated for you @@ -40,6 +42,14 @@ On first start each container seeds its config from the shipped template: - If the `.conf` already exists, it is left untouched — edit it by hand for anything the environment variables do not cover. +### Bringing your own configuration + +Mount your own `mangosd.conf` / `realmd.conf` into `/mangos/etc` and the +entrypoint will detect it and run it as-is, without generating or rewriting +anything. To turn off seeding altogether (even when no `.conf` is present, e.g. +you supply it another way or override the command), set +`INIT_ENV_CONFIG=false`. + The config and data folders are bind-mounted from the repository: - configuration: `../../etc` → `/mangos/etc` diff --git a/extra/docker/docker-entrypoint.sh b/extra/docker/docker-entrypoint.sh index dbf65229a..31da45e2c 100644 --- a/extra/docker/docker-entrypoint.sh +++ b/extra/docker/docker-entrypoint.sh @@ -6,6 +6,13 @@ # environment variables. If the .conf already exists (e.g. bind-mounted by the # operator) it is left untouched. # +# Bring-your-own-config is always respected: +# * If the target .conf already exists (bind-mounted or baked in), it is left +# exactly as-is; nothing is generated or rewritten. +# * INIT_ENV_CONFIG defaults to true (seed config from env when no .conf is +# present). Set it to false to disable seeding entirely, for operators who +# manage configuration themselves. +# # Database environment variables (all optional, defaults shown): # DB_HOST host of the MySQL server (mysqldb) # DB_PORT port of the MySQL server (3306) @@ -16,6 +23,8 @@ # DB_CHARS character database name (character2)[mangosd only] set -eu +INIT_ENV_CONFIG="${INIT_ENV_CONFIG:-true}" + DAEMON="${1:?usage: docker-entrypoint.sh [command...]}" shift @@ -43,21 +52,28 @@ set_dbinfo() sed -i "s|^${key}[[:space:]]*=.*|${key} = \"${value}\"|" "$CONF" } -if [ ! -f "$CONF" ] -then - echo "[entrypoint] ${CONF} not found; seeding from ${DIST}" - cp "$DIST" "$CONF" +case "$INIT_ENV_CONFIG" in + false|False|FALSE) + echo "[entrypoint] INIT_ENV_CONFIG=false; not generating config" + ;; + *) + if [ ! -f "$CONF" ] + then + echo "[entrypoint] ${CONF} not found; seeding from ${DIST}" + cp "$DIST" "$CONF" - set_dbinfo "LoginDatabaseInfo" "$DB_REALMD" - if [ "$DAEMON" = "mangosd" ] - then - set_dbinfo "WorldDatabaseInfo" "$DB_WORLD" - set_dbinfo "CharacterDatabaseInfo" "$DB_CHARS" - fi - echo "[entrypoint] database connection info written to ${CONF}" -else - echo "[entrypoint] ${CONF} exists; leaving it untouched" -fi + set_dbinfo "LoginDatabaseInfo" "$DB_REALMD" + if [ "$DAEMON" = "mangosd" ] + then + set_dbinfo "WorldDatabaseInfo" "$DB_WORLD" + set_dbinfo "CharacterDatabaseInfo" "$DB_CHARS" + fi + echo "[entrypoint] database connection info written to ${CONF}" + else + echo "[entrypoint] ${CONF} exists; leaving it untouched" + fi + ;; +esac # With no extra arguments, run the daemon against the seeded config. Any # arguments passed after the daemon name (e.g. a k8s command/args override) From 53a97acaf70190cdd33366935ee7ca5d90685b62 Mon Sep 17 00:00:00 2001 From: Jeremy El Bez Date: Fri, 11 Sep 2026 14:35:39 -0400 Subject: [PATCH 8/9] Update mysql --- extra/docker/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/docker/docker-compose.yml b/extra/docker/docker-compose.yml index 8f7d44a35..2e95f7b42 100644 --- a/extra/docker/docker-compose.yml +++ b/extra/docker/docker-compose.yml @@ -54,7 +54,7 @@ services: - ../../etc:/mangos/etc mysqldb: - image: mysql:5.6 + image: mysql:9.7 restart: unless-stopped environment: - MYSQL_USER=${MYSQL_USER:-mangos} From 5db903489a72c9bc86f66e92d3dd3d8a831964da Mon Sep 17 00:00:00 2001 From: Jeremy El Bez Date: Tue, 15 Sep 2026 23:19:27 -0400 Subject: [PATCH 9/9] Update documentation --- extra/docker/README.md | 84 ++++++++++++++++++++++++++------- extra/docker/docker-compose.yml | 10 ++-- 2 files changed, 70 insertions(+), 24 deletions(-) diff --git a/extra/docker/README.md b/extra/docker/README.md index 2c5085f5b..80edb1441 100644 --- a/extra/docker/README.md +++ b/extra/docker/README.md @@ -50,35 +50,43 @@ anything. To turn off seeding altogether (even when no `.conf` is present, e.g. you supply it another way or override the command), set `INIT_ENV_CONFIG=false`. -The config and data folders are bind-mounted from the repository: +The config folder is bind-mounted from the repository: -- configuration: `../../etc` → `/mangos/etc` -- client data: `../../data` → `/mangos/data` +- configuration: `./etc` → `/mangos/etc` -These paths can be changed in `docker-compose.yml`. Inside `mangosd.conf`, -`DataDir` should be `/mangos/data`. +This path can be changed in `docker-compose.yml`. There is no separate data +volume — client data (`tiles`, `gomodels`, `dbc`) is placed under this same +mounted `etc` folder; see "Extract and add the client data" below. Inside +`mangosd.conf`, `DataDir` should point at wherever you place it under +`/mangos/etc`. -## 2. Start +## 2. Initialise the databases -Registry images (default): +The MySQL data is stored in `../../dbdata`. The game databases must be created +and populated once before the servers will run — see the `mangostwo/database` +repository for the schema and migrations. The `mysqldb` service must be running +for this step; start just that service with: ```sh -docker compose pull -docker compose up +docker compose up mysqldb ``` -Build locally instead: +For the SQL import itself, follow the "Import the databases" section of the +official installation guide: -```sh -docker compose -f docker-compose.yml -f docker-compose.build.yml up --build -``` + -## 3. Initialise the databases +Point the `mysql` client at the container instead of a local install, e.g. +`mysql -h 127.0.0.1 -P 3306 -u root -p`, using the `DB_*` / `MYSQL_*` values +from your `.env`. -The MySQL data is stored in `../../dbdata`. The game databases must be created -and populated once before the servers will run — see the `mangostwo/database` -repository for the schema and migrations. The `mysqldb` service must be running -for this step. +## 3. Extract and add the client data + +Run the extractor (`mangos-extractor`, built from `src/tools/extractor`) against +your client install to produce `tiles`, `gomodels` and `dbc`, then copy the +result into `./etc` (the folder bind-mounted to `/mangos/etc`) so the +container can see it. Set `DataDir` in `mangosd.conf` to match wherever you +place it under `/mangos/etc`. ## 4. Set the public address players connect to @@ -99,6 +107,46 @@ stays `0.0.0.0` (listen on all interfaces) and does not need changing. - `3724` — login server (`realmd`) - `3306` — MySQL +## 6. Start + +Registry images (default): + +```sh +docker compose pull +docker compose up -d # Detach version +# or +docker compose up +``` + +Build locally instead: + +```sh +docker compose -f docker-compose.yml -f docker-compose.build.yml up --build +``` + + +## Attaching to the mangosd console + +`mangosd` runs as the container's foreground process and reads commands from +stdin, so you can attach to it for interactive console access. + +Find the container ID (or name) with: + +```sh +docker compose ps +``` + +or, from anywhere, `docker ps` and look for the `mangosd` image/service. Then +attach to it: + +```sh +docker attach +``` + +**Detach with `Ctrl+P` then `Ctrl+Q`, not `Ctrl+C`.** `Ctrl+C` sends `SIGINT` to +`mangosd` inside the container and shuts the server down; the detach sequence +leaves the process running and just returns you to your shell. + ## Kubernetes / other orchestrators The entrypoint is baked into the image and behaves well outside compose: diff --git a/extra/docker/docker-compose.yml b/extra/docker/docker-compose.yml index 2e95f7b42..a58ea95cb 100644 --- a/extra/docker/docker-compose.yml +++ b/extra/docker/docker-compose.yml @@ -30,9 +30,7 @@ services: tty: true volumes: # - ./local/path/to/etc:/mangos/etc -# - ./local/path/to/data:/mangos/data - - ../../etc:/mangos/etc - - ../../data:/mangos/data + - ./etc:/mangos/etc realmd: image: ghcr.io/${REGISTRY_OWNER:-mangostwo}/realmd:${MANGOS_TAG:-latest} @@ -51,10 +49,10 @@ services: - "3724:3724" volumes: # - ./local/path/to/etc:/mangos/etc - - ../../etc:/mangos/etc + - ./etc:/mangos/etc mysqldb: - image: mysql:9.7 + image: mysql:5.7 restart: unless-stopped environment: - MYSQL_USER=${MYSQL_USER:-mangos} @@ -65,4 +63,4 @@ services: - "3306:3306" volumes: # - ./local/path/to/mysqldatabase:/var/lib/mysql - - ../../dbdata:/var/lib/mysql + - ./dbdata:/var/lib/mysql