Files
AzerothCore-RealmMaster/docker-compose.yml
2025-11-22 16:56:02 -05:00

900 lines
33 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: ${COMPOSE_PROJECT_NAME}
services:
# =====================
# Database Layer (db)
# =====================
ac-mysql:
profiles: ["db"]
image: ${MYSQL_IMAGE}
container_name: ${CONTAINER_MYSQL}
userns_mode: "keep-id"
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_ROOT_HOST: '${MYSQL_ROOT_HOST}'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATADIR: /var/lib/mysql-runtime
MYSQL_CHARACTER_SET: ${MYSQL_CHARACTER_SET}
MYSQL_COLLATION: ${MYSQL_COLLATION}
MYSQL_MAX_CONNECTIONS: ${MYSQL_MAX_CONNECTIONS}
MYSQL_INNODB_BUFFER_POOL_SIZE: ${MYSQL_INNODB_BUFFER_POOL_SIZE}
MYSQL_INNODB_LOG_FILE_SIZE: ${MYSQL_INNODB_LOG_FILE_SIZE}
TZ: "${TZ}"
entrypoint:
- /usr/local/bin/mysql-entrypoint.sh
volumes:
- ./scripts/bash/mysql-entrypoint.sh:/usr/local/bin/mysql-entrypoint.sh:ro
- mysql-data:/var/lib/mysql-persistent
- ${BACKUP_PATH}:/backups
- ${HOST_ZONEINFO_PATH}:/usr/share/zoneinfo:ro
- ${MYSQL_CONFIG_DIR:-${STORAGE_PATH}/config/mysql/conf.d}:/etc/mysql/conf.d
tmpfs:
- /var/lib/mysql-runtime:size=${MYSQL_RUNTIME_TMPFS_SIZE}
command:
- mysqld
- --datadir=/var/lib/mysql-runtime
- --default-authentication-plugin=mysql_native_password
- --character-set-server=${MYSQL_CHARACTER_SET}
- --collation-server=${MYSQL_COLLATION}
- --max_connections=${MYSQL_MAX_CONNECTIONS}
- --innodb-buffer-pool-size=${MYSQL_INNODB_BUFFER_POOL_SIZE}
- --innodb-log-file-size=${MYSQL_INNODB_LOG_FILE_SIZE}
- --innodb-redo-log-capacity=${MYSQL_INNODB_REDO_LOG_CAPACITY}
restart: unless-stopped
logging:
healthcheck:
test: ["CMD", "sh", "-c", "mysqladmin ping -h localhost -u ${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} --silent || exit 1"]
interval: ${MYSQL_HEALTHCHECK_INTERVAL}
timeout: ${MYSQL_HEALTHCHECK_TIMEOUT}
retries: ${MYSQL_HEALTHCHECK_RETRIES}
start_period: ${MYSQL_HEALTHCHECK_START_PERIOD}
networks:
- azerothcore
ac-db-import:
profiles: ["db"]
image: ${AC_DB_IMPORT_IMAGE}
container_name: ${CONTAINER_DB_IMPORT}
user: "${CONTAINER_USER}"
userns_mode: "keep-id"
depends_on:
ac-mysql:
condition: service_healthy
ac-storage-init:
condition: service_completed_successfully
networks:
- azerothcore
volumes:
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
- ${STORAGE_PATH}/logs:/azerothcore/logs
- ${AC_SQL_SOURCE_PATH:-${STORAGE_PATH_LOCAL}/source/azerothcore-playerbots/data/sql}:/azerothcore/data/sql:ro
- ${MODULE_SQL_STAGE_PATH:-${STORAGE_PATH}/module-sql-updates}:/modules-sql
- mysql-data:/var/lib/mysql-persistent
- ${STORAGE_PATH}/modules:/modules
- ${BACKUP_PATH}:/backups
- ./scripts/bash/db-import-conditional.sh:/tmp/db-import-conditional.sh:ro
- ./scripts/bash/restore-and-stage.sh:/tmp/restore-and-stage.sh:ro
environment:
AC_DATA_DIR: "/azerothcore/data"
AC_LOGS_DIR: "/azerothcore/logs"
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
AC_WORLD_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_WORLD_NAME}"
AC_CHARACTER_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}"
AC_CLOSE_IDLE_CONNECTIONS: "false"
AC_UPDATES_ENABLE_DATABASES: "7"
AC_UPDATES_AUTO_SETUP: "1"
AC_LOG_LEVEL: "1"
AC_LOGGER_ROOT_CONFIG: "1,Console"
AC_LOGGER_SERVER_CONFIG: "1,Console"
AC_APPENDER_CONSOLE_CONFIG: "1,2,0"
CONTAINER_MYSQL: ${CONTAINER_MYSQL}
MYSQL_PORT: ${MYSQL_PORT}
MYSQL_USER: ${MYSQL_USER}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
DB_AUTH_NAME: ${DB_AUTH_NAME}
DB_WORLD_NAME: ${DB_WORLD_NAME}
DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME}
CONTAINER_USER: ${CONTAINER_USER}
DB_RECONNECT_SECONDS: ${DB_RECONNECT_SECONDS}
DB_RECONNECT_ATTEMPTS: ${DB_RECONNECT_ATTEMPTS}
DB_UPDATES_ALLOWED_MODULES: ${DB_UPDATES_ALLOWED_MODULES}
DB_UPDATES_REDUNDANCY: ${DB_UPDATES_REDUNDANCY}
DB_LOGIN_WORKER_THREADS: ${DB_LOGIN_WORKER_THREADS}
DB_WORLD_WORKER_THREADS: ${DB_WORLD_WORKER_THREADS}
DB_CHARACTER_WORKER_THREADS: ${DB_CHARACTER_WORKER_THREADS}
DB_LOGIN_SYNCH_THREADS: ${DB_LOGIN_SYNCH_THREADS}
DB_WORLD_SYNCH_THREADS: ${DB_WORLD_SYNCH_THREADS}
DB_CHARACTER_SYNCH_THREADS: ${DB_CHARACTER_SYNCH_THREADS}
entrypoint:
- sh
- -c
- |
echo "📥 Using local database import script..."
/tmp/db-import-conditional.sh
restart: "no"
ac-db-guard:
profiles: ["db"]
image: ${AC_DB_IMPORT_IMAGE}
container_name: ${CONTAINER_DB_GUARD}
user: "${CONTAINER_USER}"
userns_mode: "keep-id"
depends_on:
ac-mysql:
condition: service_healthy
ac-storage-init:
condition: service_completed_successfully
ac-db-import:
condition: service_completed_successfully
networks:
- azerothcore
volumes:
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
- ${STORAGE_PATH}/logs:/azerothcore/logs
- ${AC_SQL_SOURCE_PATH:-${STORAGE_PATH_LOCAL}/source/azerothcore-playerbots/data/sql}:/azerothcore/data/sql:ro
- ${MODULE_SQL_STAGE_PATH:-${STORAGE_PATH}/module-sql-updates}:/modules-sql
- mysql-data:/var/lib/mysql-persistent
- ${STORAGE_PATH}/modules:/modules
- ${BACKUP_PATH}:/backups
- ./scripts/bash/db-import-conditional.sh:/tmp/db-import-conditional.sh:ro
- ./scripts/bash/restore-and-stage.sh:/tmp/restore-and-stage.sh:ro
- ./scripts/bash/db-guard.sh:/tmp/db-guard.sh:ro
environment:
AC_DATA_DIR: "/azerothcore/data"
AC_LOGS_DIR: "/azerothcore/logs"
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
AC_WORLD_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_WORLD_NAME}"
AC_CHARACTER_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}"
CONTAINER_MYSQL: ${CONTAINER_MYSQL}
MYSQL_PORT: ${MYSQL_PORT}
MYSQL_USER: ${MYSQL_USER}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
DB_AUTH_NAME: ${DB_AUTH_NAME}
DB_WORLD_NAME: ${DB_WORLD_NAME}
DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME}
DB_PLAYERBOTS_NAME: ${DB_PLAYERBOTS_NAME}
DB_GUARD_RECHECK_SECONDS: ${DB_GUARD_RECHECK_SECONDS}
DB_GUARD_RETRY_SECONDS: ${DB_GUARD_RETRY_SECONDS}
DB_GUARD_WAIT_ATTEMPTS: ${DB_GUARD_WAIT_ATTEMPTS}
DB_RECONNECT_SECONDS: ${DB_RECONNECT_SECONDS}
DB_RECONNECT_ATTEMPTS: ${DB_RECONNECT_ATTEMPTS}
DB_UPDATES_ALLOWED_MODULES: ${DB_UPDATES_ALLOWED_MODULES}
DB_UPDATES_REDUNDANCY: ${DB_UPDATES_REDUNDANCY}
DB_LOGIN_WORKER_THREADS: ${DB_LOGIN_WORKER_THREADS}
DB_WORLD_WORKER_THREADS: ${DB_WORLD_WORKER_THREADS}
DB_CHARACTER_WORKER_THREADS: ${DB_CHARACTER_WORKER_THREADS}
DB_LOGIN_SYNCH_THREADS: ${DB_LOGIN_SYNCH_THREADS}
DB_WORLD_SYNCH_THREADS: ${DB_WORLD_SYNCH_THREADS}
DB_CHARACTER_SYNCH_THREADS: ${DB_CHARACTER_SYNCH_THREADS}
entrypoint:
- /bin/bash
- -c
- |
chmod +x /tmp/db-import-conditional.sh /tmp/restore-and-stage.sh 2>/dev/null || true
exec /bin/bash /tmp/db-guard.sh
restart: unless-stopped
healthcheck:
test:
- "CMD"
- "sh"
- "-c"
- >
file=/tmp/db-guard.ready;
[ -f "$${file}" ] || exit 1;
now=$$(date +%s);
mod=$$(stat -c %Y "$${file}" 2>/dev/null) || exit 1;
[ $$(( now - mod )) -lt ${DB_GUARD_HEALTH_MAX_AGE} ] || exit 1
interval: ${DB_GUARD_HEALTHCHECK_INTERVAL}
timeout: ${DB_GUARD_HEALTHCHECK_TIMEOUT}
retries: ${DB_GUARD_HEALTHCHECK_RETRIES}
ac-db-init:
profiles: ["db"]
image: ${MYSQL_IMAGE}
container_name: ${CONTAINER_DB_INIT}
userns_mode: "keep-id"
depends_on:
ac-db-import:
condition: service_completed_successfully
volumes:
- mysql-data:/var/lib/mysql-persistent
- ${BACKUP_PATH}:/backups
networks:
- azerothcore
environment:
MYSQL_PWD: ${MYSQL_ROOT_PASSWORD}
MYSQL_HOST: ${CONTAINER_MYSQL}
MYSQL_USER: ${MYSQL_USER}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
DB_WAIT_RETRIES: ${DB_WAIT_RETRIES}
DB_WAIT_SLEEP: ${DB_WAIT_SLEEP}
DB_AUTH_NAME: ${DB_AUTH_NAME}
DB_WORLD_NAME: ${DB_WORLD_NAME}
DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME}
MYSQL_CHARACTER_SET: ${MYSQL_CHARACTER_SET}
MYSQL_COLLATION: ${MYSQL_COLLATION}
command:
- sh
- -c
- |
if [ -f "/var/lib/mysql-persistent/.restore-completed" ]; then
echo "✅ Databases already restored from backup - init not needed"; exit 0; fi
if mysql -h ${MYSQL_HOST} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e "
SELECT COUNT(*) FROM information_schema.tables WHERE table_schema IN ('${DB_AUTH_NAME}', '${DB_WORLD_NAME}', '${DB_CHARACTERS_NAME}');" -s -N 2>/dev/null | grep -q -v '^0$'; then
echo "✅ Databases already populated - init not needed"; exit 0; fi
echo "🔧 Creating fresh AzerothCore databases..."
microdnf install -y curl || yum install -y curl || (apt-get update && apt-get install -y curl)
mysql -h ${MYSQL_HOST} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e "
CREATE DATABASE IF NOT EXISTS ${DB_AUTH_NAME} DEFAULT CHARACTER SET ${MYSQL_CHARACTER_SET} COLLATE ${MYSQL_COLLATION};
CREATE DATABASE IF NOT EXISTS ${DB_WORLD_NAME} DEFAULT CHARACTER SET ${MYSQL_CHARACTER_SET} COLLATE ${MYSQL_COLLATION};
CREATE DATABASE IF NOT EXISTS ${DB_CHARACTERS_NAME} DEFAULT CHARACTER SET ${MYSQL_CHARACTER_SET} COLLATE ${MYSQL_COLLATION};
SHOW DATABASES;" || { echo "❌ Failed to create databases"; exit 1; }
echo "$(date): Fresh databases created - import needed" > /var/lib/mysql-persistent/.restore-failed
echo "✅ Fresh databases created!"
restart: "no"
ac-backup:
profiles: ["db"]
image: ${MYSQL_IMAGE}
container_name: ${CONTAINER_BACKUP}
user: "0:0"
userns_mode: "keep-id"
depends_on:
ac-db-import:
condition: service_completed_successfully
environment:
MYSQL_HOST: ${CONTAINER_MYSQL}
MYSQL_PORT: ${MYSQL_PORT}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD}
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS}
BACKUP_RETENTION_HOURS: ${BACKUP_RETENTION_HOURS}
BACKUP_DAILY_TIME: ${BACKUP_DAILY_TIME}
BACKUP_INTERVAL_MINUTES: ${BACKUP_INTERVAL_MINUTES}
DB_AUTH_NAME: ${DB_AUTH_NAME}
DB_WORLD_NAME: ${DB_WORLD_NAME}
DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME}
BACKUP_EXTRA_DATABASES: ${BACKUP_EXTRA_DATABASES}
TZ: ${TZ}
CONTAINER_USER: ${CONTAINER_USER}
volumes:
- ${BACKUP_PATH}:/backups
- ${STORAGE_PATH}/modules/.modules-meta:/modules-meta:ro
- ./scripts:/tmp/scripts:ro
working_dir: /tmp
command:
- /bin/bash
- -c
- |
install_curl(){
microdnf install -y curl >/dev/null 2>&1 && return
yum install -y curl >/dev/null 2>&1 && return
apt-get update -qq && apt-get install -y curl >/dev/null 2>&1 && return
echo "❌ Failed to install curl"; exit 1
}
ensure_gosu(){
if command -v gosu >/dev/null 2>&1; then
return
fi
install_curl
arch="$$(uname -m)"
case "$${arch}" in
x86_64|amd64) gosu_arch=amd64 ;;
aarch64|arm64) gosu_arch=arm64 ;;
*) echo "❌ Unsupported architecture for gosu: $${arch}"; exit 1 ;;
esac
echo "⬇️ Installing gosu for privilege drop..."
curl -fsSL "https://github.com/tianon/gosu/releases/download/1.14/gosu-$${gosu_arch}" -o /usr/local/bin/gosu
chmod +x /usr/local/bin/gosu
}
install_curl
ensure_gosu
echo "📥 Preparing backup scheduler (running as ${CONTAINER_USER})..."
chown -R ${CONTAINER_USER} /backups 2>/dev/null || true
chmod -R 755 /backups 2>/dev/null || true
if [ -f /tmp/scripts/bash/backup-scheduler.sh ]; then
chmod +x /tmp/scripts/bash/backup-scheduler.sh 2>/dev/null || true
exec gosu ${CONTAINER_USER} /tmp/scripts/bash/backup-scheduler.sh
else
echo "No local scheduler provided"
sleep infinity
fi
restart: unless-stopped
healthcheck:
test:
- "CMD"
- "sh"
- "-c"
- >
mysql -h${MYSQL_HOST} -P${MYSQL_PORT} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e 'SELECT 1'
>/dev/null 2>&1 &&
(
find /backups -name '*.sql.gz' -mmin -${BACKUP_HEALTHCHECK_MAX_MINUTES} -print -quit >/dev/null ||
awk -v limit=${BACKUP_HEALTHCHECK_GRACE_SECONDS} 'NR==1 { exit ($1 < limit) ? 0 : 1 }' /proc/uptime
)
interval: ${BACKUP_HEALTHCHECK_INTERVAL}
timeout: ${BACKUP_HEALTHCHECK_TIMEOUT}
retries: ${BACKUP_HEALTHCHECK_RETRIES}
start_period: ${BACKUP_HEALTHCHECK_START_PERIOD}
networks:
- azerothcore
# =====================
# Volume Initialization
# =====================
ac-volume-init:
profiles: ["client-data", "client-data-bots"]
image: ${ALPINE_IMAGE}
container_name: ac-volume-init
user: "${CONTAINER_USER}"
volumes:
- ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- client-data-cache:/cache
command:
- sh
- -c
- |
mkdir -p /azerothcore/data /cache
if [ "$(id -u)" -eq 0 ]; then
echo "🔧 Normalizing client-data volume ownership..."
chown -R ${CONTAINER_USER} /azerothcore/data /cache
chmod -R 755 /azerothcore/data /cache
echo "✅ Docker volume permissions fixed"
else
echo " Running as $(id -u):$(id -g); skipping ownership changes."
fi
echo "📦 Client data volumes ready"
restart: "no"
networks:
- azerothcore
ac-storage-init:
profiles: ["db", "modules"]
image: ${ALPINE_IMAGE}
container_name: ac-storage-init
user: "${CONTAINER_USER}"
volumes:
- ${STORAGE_PATH}:/storage-root
- ${STORAGE_PATH_LOCAL}:/local-storage-root
command:
- sh
- -c
- |
echo "🔧 Initializing storage directories with proper permissions..."
mkdir -p /storage-root/config /storage-root/logs /storage-root/modules /storage-root/lua_scripts /storage-root/install-markers
mkdir -p /storage-root/config/mysql/conf.d
mkdir -p /storage-root/client-data
mkdir -p /storage-root/backups
# Copy core config files if they don't exist
if [ -f "/local-storage-root/source/azerothcore-playerbots/src/tools/dbimport/dbimport.conf.dist" ] && [ ! -f "/storage-root/config/dbimport.conf.dist" ]; then
echo "📄 Copying dbimport.conf.dist..."
cp /local-storage-root/source/azerothcore-playerbots/src/tools/dbimport/dbimport.conf.dist /storage-root/config/
fi
# Fix ownership of root directories and all contents
if [ "$(id -u)" -eq 0 ]; then
chown -R ${CONTAINER_USER} /storage-root /local-storage-root
chmod -R 755 /storage-root /local-storage-root
echo "✅ Storage permissions initialized"
else
echo " Running as $(id -u):$(id -g); assuming host permissions are already correct."
fi
restart: "no"
networks:
- azerothcore
# =====================
# Client Data (client-data)
# =====================
ac-client-data-standard:
profiles: ["client-data"]
image: ${AC_CLIENT_DATA_IMAGE}
container_name: ac-client-data
user: "${CONTAINER_USER}"
depends_on:
ac-volume-init:
condition: service_completed_successfully
volumes:
- ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- client-data-cache:/cache
- ./scripts:/tmp/scripts:ro
working_dir: /tmp
environment:
- CONTAINER_USER=${CONTAINER_USER}
- CLIENT_DATA_VERSION=${CLIENT_DATA_VERSION:-}
command:
- sh
- -c
- |
mkdir -p /cache
if [ -f /tmp/scripts/bash/download-client-data.sh ]; then
chmod +x /tmp/scripts/bash/download-client-data.sh 2>/dev/null || true
bash /tmp/scripts/bash/download-client-data.sh
else
echo "No local client-data script"
fi
restart: "no"
networks:
- azerothcore
ac-client-data-playerbots:
profiles: ["client-data-bots"]
image: ${AC_CLIENT_DATA_IMAGE_PLAYERBOTS}
container_name: ac-client-data
user: "0:0"
depends_on:
ac-volume-init:
condition: service_completed_successfully
volumes:
- ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- client-data-cache:/cache
- ./scripts:/tmp/scripts:ro
working_dir: /tmp
environment:
- CONTAINER_USER=${CONTAINER_USER}
- CLIENT_DATA_VERSION=${CLIENT_DATA_VERSION:-}
command:
- sh
- -c
- |
echo "📦 Installing 7z + gosu for client data extraction..."
apt-get update -qq && apt-get install -y p7zip-full gosu
gosu ${CONTAINER_USER} bash -c '
set -e
mkdir -p /cache
if [ -f /tmp/scripts/bash/download-client-data.sh ]; then
chmod +x /tmp/scripts/bash/download-client-data.sh 2>/dev/null || true
bash /tmp/scripts/bash/download-client-data.sh
echo "✅ Client data extraction completed under UID $(id -u)"
else
echo "No local client-data script"
fi
'
restart: "no"
networks:
- azerothcore
# =====================
# Services - Standard (services-standard)
# =====================
ac-authserver-standard:
profiles: ["services-standard"]
image: ${AC_AUTHSERVER_IMAGE}
container_name: ac-authserver
user: "${CONTAINER_USER}"
depends_on:
ac-mysql:
condition: service_healthy
ac-db-import:
condition: service_completed_successfully
ac-db-init:
condition: service_completed_successfully
environment:
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
AC_UPDATES_ENABLE_DATABASES: "0"
AC_BIND_IP: "0.0.0.0"
AC_LOG_LEVEL: "1"
AC_LOGGER_ROOT_CONFIG: "1,Console"
AC_LOGGER_SERVER_CONFIG: "1,Console"
AC_APPENDER_CONSOLE_CONFIG: "1,2,0"
ports:
- "${AUTH_EXTERNAL_PORT}:${AUTH_PORT}"
restart: unless-stopped
logging:
networks:
- azerothcore
volumes:
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
cap_add: ["SYS_NICE"]
healthcheck:
test: ["CMD", "sh", "-c", "ps aux | grep '[a]uthserver' | grep -v grep || exit 1"]
interval: ${AUTH_HEALTHCHECK_INTERVAL}
timeout: ${AUTH_HEALTHCHECK_TIMEOUT}
retries: ${AUTH_HEALTHCHECK_RETRIES}
start_period: ${AUTH_HEALTHCHECK_START_PERIOD}
ac-worldserver-standard:
profiles: ["services-standard"]
image: ${AC_WORLDSERVER_IMAGE}
container_name: ac-worldserver
user: "${CONTAINER_USER}"
stdin_open: true
tty: true
depends_on:
ac-authserver-standard:
condition: service_healthy
ac-client-data-standard:
condition: service_completed_successfully
environment:
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
AC_WORLD_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_WORLD_NAME}"
AC_CHARACTER_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}"
AC_UPDATES_ENABLE_DATABASES: "7"
AC_BIND_IP: "0.0.0.0"
AC_DATA_DIR: "/azerothcore/data"
AC_SOAP_PORT: "7878"
AC_PROCESS_PRIORITY: "0"
AC_ELUNA_ENABLED: "${AC_ELUNA_ENABLED}"
AC_ELUNA_TRACE_BACK: "${AC_ELUNA_TRACE_BACK}"
AC_ELUNA_AUTO_RELOAD: "${AC_ELUNA_AUTO_RELOAD}"
AC_ELUNA_BYTECODE_CACHE: "${AC_ELUNA_BYTECODE_CACHE}"
AC_ELUNA_SCRIPT_PATH: "${AC_ELUNA_SCRIPT_PATH}"
AC_ELUNA_REQUIRE_PATHS: "${AC_ELUNA_REQUIRE_PATHS}"
AC_ELUNA_REQUIRE_CPATHS: "${AC_ELUNA_REQUIRE_CPATHS}"
AC_ELUNA_AUTO_RELOAD_INTERVAL: "${AC_ELUNA_AUTO_RELOAD_INTERVAL}"
PLAYERBOT_ENABLED: "${PLAYERBOT_ENABLED}"
PLAYERBOT_MAX_BOTS: "${PLAYERBOT_MAX_BOTS}"
AC_LOG_LEVEL: "2"
ports:
- "${WORLD_EXTERNAL_PORT}:${WORLD_PORT}"
- "${SOAP_EXTERNAL_PORT}:${SOAP_PORT}"
volumes:
- ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
- ${STORAGE_PATH}/logs:/azerothcore/logs
- ${STORAGE_PATH}/modules:/azerothcore/modules
- ${STORAGE_PATH}/lua_scripts:/azerothcore/lua_scripts
restart: unless-stopped
logging:
networks:
- azerothcore
cap_add: ["SYS_NICE"]
healthcheck:
test: ["CMD", "sh", "-c", "ps aux | grep '[w]orldserver' | grep -v grep || exit 1"]
interval: ${WORLD_HEALTHCHECK_INTERVAL}
timeout: ${WORLD_HEALTHCHECK_TIMEOUT}
retries: ${WORLD_HEALTHCHECK_RETRIES}
start_period: ${WORLD_HEALTHCHECK_START_PERIOD}
# =====================
# Services - Playerbots (services-playerbots)
# =====================
ac-authserver-playerbots:
profiles: ["services-playerbots"]
image: ${AC_AUTHSERVER_IMAGE_PLAYERBOTS}
container_name: ac-authserver
user: "${CONTAINER_USER}"
depends_on:
ac-mysql:
condition: service_healthy
ac-db-guard:
condition: service_healthy
ac-db-init:
condition: service_completed_successfully
environment:
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
AC_UPDATES_ENABLE_DATABASES: "0"
AC_BIND_IP: "0.0.0.0"
TZ: "${TZ}"
AC_LOG_LEVEL: "1"
AC_LOGGER_ROOT_CONFIG: "1,Console"
AC_LOGGER_SERVER_CONFIG: "1,Console"
AC_APPENDER_CONSOLE_CONFIG: "1,2,0"
ports:
- "${AUTH_EXTERNAL_PORT}:${AUTH_PORT}"
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
networks:
- azerothcore
volumes:
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
cap_add: ["SYS_NICE"]
healthcheck:
test: ["CMD", "sh", "-c", "ps aux | grep '[a]uthserver' | grep -v grep || exit 1"]
interval: ${AUTH_HEALTHCHECK_INTERVAL}
timeout: ${AUTH_HEALTHCHECK_TIMEOUT}
retries: ${AUTH_HEALTHCHECK_RETRIES}
start_period: ${AUTH_HEALTHCHECK_START_PERIOD}
ac-authserver-modules:
profiles: ["services-modules"]
image: ${AC_AUTHSERVER_IMAGE_MODULES}
container_name: ac-authserver
user: "${CONTAINER_USER}"
depends_on:
ac-mysql:
condition: service_healthy
ac-db-guard:
condition: service_healthy
ac-db-init:
condition: service_completed_successfully
environment:
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
AC_UPDATES_ENABLE_DATABASES: "7"
AC_BIND_IP: "0.0.0.0"
AC_LOG_LEVEL: "1"
AC_LOGGER_ROOT_CONFIG: "1,Console"
AC_LOGGER_SERVER_CONFIG: "1,Console"
AC_APPENDER_CONSOLE_CONFIG: "1,2,0"
ports:
- "${AUTH_EXTERNAL_PORT}:${AUTH_PORT}"
restart: unless-stopped
logging:
networks:
- azerothcore
volumes:
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
cap_add: ["SYS_NICE"]
healthcheck:
test: ["CMD", "sh", "-c", "ps aux | grep '[a]uthserver' | grep -v grep || exit 1"]
interval: ${AUTH_HEALTHCHECK_INTERVAL}
timeout: ${AUTH_HEALTHCHECK_TIMEOUT}
retries: ${AUTH_HEALTHCHECK_RETRIES}
start_period: ${AUTH_HEALTHCHECK_START_PERIOD}
ac-worldserver-playerbots:
profiles: ["services-playerbots"]
image: ${AC_WORLDSERVER_IMAGE_PLAYERBOTS}
container_name: ac-worldserver
user: "${CONTAINER_USER}"
stdin_open: true
tty: true
depends_on:
ac-authserver-playerbots:
condition: service_healthy
ac-client-data-playerbots:
condition: service_completed_successfully
ac-db-guard:
condition: service_healthy
environment:
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
AC_WORLD_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_WORLD_NAME}"
AC_CHARACTER_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}"
AC_UPDATES_ENABLE_DATABASES: "7"
AC_BIND_IP: "0.0.0.0"
AC_DATA_DIR: "/azerothcore/data"
AC_SOAP_PORT: "7878"
AC_PROCESS_PRIORITY: "0"
AC_ELUNA_ENABLED: "${AC_ELUNA_ENABLED}"
AC_ELUNA_TRACE_BACK: "${AC_ELUNA_TRACE_BACK}"
AC_ELUNA_AUTO_RELOAD: "${AC_ELUNA_AUTO_RELOAD}"
AC_ELUNA_BYTECODE_CACHE: "${AC_ELUNA_BYTECODE_CACHE}"
AC_ELUNA_SCRIPT_PATH: "${AC_ELUNA_SCRIPT_PATH}"
TZ: "${TZ}"
AC_ELUNA_REQUIRE_PATHS: "${AC_ELUNA_REQUIRE_PATHS}"
AC_ELUNA_REQUIRE_CPATHS: "${AC_ELUNA_REQUIRE_CPATHS}"
AC_ELUNA_AUTO_RELOAD_INTERVAL: "${AC_ELUNA_AUTO_RELOAD_INTERVAL}"
PLAYERBOT_ENABLED: "${PLAYERBOT_ENABLED}"
PLAYERBOT_MAX_BOTS: "${PLAYERBOT_MAX_BOTS}"
AC_LOG_LEVEL: "2"
ports:
- "${WORLD_EXTERNAL_PORT}:${WORLD_PORT}"
- "${SOAP_EXTERNAL_PORT}:${SOAP_PORT}"
volumes:
- ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
- ${STORAGE_PATH}/logs:/azerothcore/logs
- ${STORAGE_PATH}/modules:/azerothcore/modules
- ${STORAGE_PATH}/lua_scripts:/azerothcore/lua_scripts
restart: unless-stopped
logging:
networks:
- azerothcore
cap_add: ["SYS_NICE"]
healthcheck:
test: ["CMD", "sh", "-c", "ps aux | grep '[w]orldserver' | grep -v grep || exit 1"]
interval: ${WORLD_HEALTHCHECK_INTERVAL}
timeout: ${WORLD_HEALTHCHECK_TIMEOUT}
retries: ${WORLD_HEALTHCHECK_RETRIES}
start_period: ${WORLD_HEALTHCHECK_START_PERIOD}
ac-worldserver-modules:
profiles: ["services-modules"]
image: ${AC_WORLDSERVER_IMAGE_MODULES}
container_name: ac-worldserver
user: "${CONTAINER_USER}"
stdin_open: true
tty: true
depends_on:
ac-authserver-modules:
condition: service_healthy
ac-client-data-standard:
condition: service_completed_successfully
ac-db-guard:
condition: service_healthy
environment:
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
AC_WORLD_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_WORLD_NAME}"
AC_CHARACTER_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}"
AC_UPDATES_ENABLE_DATABASES: "7"
AC_BIND_IP: "0.0.0.0"
AC_DATA_DIR: "/azerothcore/data"
AC_SOAP_PORT: "7878"
AC_PROCESS_PRIORITY: "0"
AC_ELUNA_ENABLED: "${AC_ELUNA_ENABLED}"
AC_ELUNA_TRACE_BACK: "${AC_ELUNA_TRACE_BACK}"
AC_ELUNA_AUTO_RELOAD: "${AC_ELUNA_AUTO_RELOAD}"
AC_ELUNA_BYTECODE_CACHE: "${AC_ELUNA_BYTECODE_CACHE}"
AC_ELUNA_SCRIPT_PATH: "${AC_ELUNA_SCRIPT_PATH}"
AC_ELUNA_REQUIRE_PATHS: "${AC_ELUNA_REQUIRE_PATHS}"
AC_ELUNA_REQUIRE_CPATHS: "${AC_ELUNA_REQUIRE_CPATHS}"
AC_ELUNA_AUTO_RELOAD_INTERVAL: "${AC_ELUNA_AUTO_RELOAD_INTERVAL}"
PLAYERBOT_ENABLED: "${PLAYERBOT_ENABLED}"
PLAYERBOT_MAX_BOTS: "${PLAYERBOT_MAX_BOTS}"
AC_LOG_LEVEL: "2"
volumes:
- ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
- ${STORAGE_PATH}/logs:/azerothcore/logs
- ${STORAGE_PATH}/modules:/azerothcore/modules
- ${STORAGE_PATH}/lua_scripts:/azerothcore/lua_scripts
networks:
- azerothcore
ports:
- "${WORLD_EXTERNAL_PORT}:${WORLD_PORT}"
- "${SOAP_EXTERNAL_PORT}:${SOAP_PORT}"
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
cap_add: ["SYS_NICE"]
healthcheck:
test: ["CMD", "sh", "-c", "ps aux | grep '[w]orldserver' | grep -v grep || exit 1"]
interval: ${WORLD_HEALTHCHECK_INTERVAL}
timeout: ${WORLD_HEALTHCHECK_TIMEOUT}
retries: ${WORLD_HEALTHCHECK_RETRIES}
start_period: ${WORLD_HEALTHCHECK_START_PERIOD}
# =====================
# Modules & Post-install (modules)
# =====================
ac-modules:
profiles: ["modules"]
image: ${ALPINE_IMAGE}
container_name: ${CONTAINER_MODULES}
user: "0:0"
depends_on:
ac-mysql:
condition: service_healthy
ac-db-import:
condition: service_completed_successfully
ac-db-init:
condition: service_completed_successfully
ac-storage-init:
condition: service_completed_successfully
volumes:
- ${STORAGE_PATH}/modules:/modules
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
- ./scripts:/tmp/scripts:ro
- ./config:/tmp/config:ro
env_file:
- ./.env
environment:
MODULES_MANIFEST_PATH: /tmp/config/module-manifest.json
entrypoint: ["/bin/sh"]
command:
- -c
- |
apk add --no-cache curl bash git python3 su-exec
chmod +x /tmp/scripts/bash/manage-modules.sh /tmp/scripts/bash/manage-modules-sql.sh 2>/dev/null || true
echo "🔐 Running module manager as ${CONTAINER_USER}"
su-exec ${CONTAINER_USER} /bin/sh -c 'set -e; cd /modules && /tmp/scripts/bash/manage-modules.sh'
restart: "no"
networks:
- azerothcore
ac-post-install:
profiles: ["modules"]
image: ${ALPINE_IMAGE}
container_name: ${CONTAINER_POST_INSTALL}
user: "0:0"
volumes:
- ${STORAGE_PATH}/config:/azerothcore/config
- ${STORAGE_PATH}/install-markers:/install-markers
- ./scripts:/tmp/scripts:ro
- /var/run/docker.sock:/var/run/docker.sock:rw
working_dir: /tmp
environment:
MYSQL_HOST: ${CONTAINER_MYSQL}
MYSQL_PORT: ${MYSQL_PORT}
MYSQL_USER: ${MYSQL_USER}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
DB_AUTH_NAME: ${DB_AUTH_NAME}
DB_WORLD_NAME: ${DB_WORLD_NAME}
DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME}
DB_PLAYERBOTS_NAME: ${DB_PLAYERBOTS_NAME}
MYSQL_CHARACTER_SET: ${MYSQL_CHARACTER_SET}
MYSQL_COLLATION: ${MYSQL_COLLATION}
STORAGE_PATH: ${STORAGE_PATH}
SERVER_ADDRESS: ${SERVER_ADDRESS}
REALM_PORT: ${REALM_PORT}
NETWORK_NAME: ${NETWORK_NAME}
CONTAINER_AUTHSERVER: ac-authserver
CONTAINER_WORLDSERVER: ac-worldserver
CONTAINER_USER: ${CONTAINER_USER}
depends_on:
ac-modules:
condition: service_completed_successfully
ac-mysql:
condition: service_healthy
ac-storage-init:
condition: service_completed_successfully
command:
- sh
- -c
- |
apk add --no-cache bash curl docker-cli su-exec
chmod +x /tmp/scripts/bash/auto-post-install.sh 2>/dev/null || true
echo "📥 Running post-install as ${CONTAINER_USER}"
su-exec ${CONTAINER_USER} bash /tmp/scripts/bash/auto-post-install.sh
restart: "no"
networks:
- azerothcore
# =====================
# Tools (tools)
# =====================
ac-phpmyadmin:
profiles: ["tools"]
image: phpmyadmin/phpmyadmin:latest
container_name: ac-phpmyadmin
environment:
PMA_HOST: ${PMA_HOST}
PMA_PORT: ${PMA_PORT}
PMA_USER: ${PMA_USER}
PMA_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
PMA_ARBITRARY: ${PMA_ARBITRARY}
PMA_ABSOLUTE_URI: ${PMA_ABSOLUTE_URI}
UPLOAD_LIMIT: ${PMA_UPLOAD_LIMIT}
MEMORY_LIMIT: ${PMA_MEMORY_LIMIT}
MAX_EXECUTION_TIME: ${PMA_MAX_EXECUTION_TIME}
ports:
- "${PMA_EXTERNAL_PORT}:80"
healthcheck:
test: ["CMD", "sh", "-c", "curl -fsS http://localhost:80/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
restart: unless-stopped
networks:
- azerothcore
ac-keira3:
profiles: ["tools"]
image: uprightbass360/keira3:latest
container_name: ac-keira3
restart: unless-stopped
environment:
- NODE_ENV=production
- KEIRA_PORT=8080
- KEIRA_HOST=0.0.0.0
- KEIRA_DATABASE_HOST=${KEIRA_DATABASE_HOST}
- KEIRA_DATABASE_PORT=${KEIRA_DATABASE_PORT}
- KEIRA_DATABASE_USER=root
- KEIRA_DATABASE_PASSWORD=${MYSQL_ROOT_PASSWORD}
- KEIRA_DATABASE_NAME=${DB_WORLD_NAME}
ports:
- "${KEIRA3_EXTERNAL_PORT}:8080"
healthcheck:
test: ["CMD", "sh", "-c", "curl -f http://localhost:8080/health >/dev/null 2>&1 || nc -z localhost 8080 || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
logging:
security_opt:
- no-new-privileges:true
networks:
- azerothcore
volumes:
client-data-cache:
driver: local
mysql-data:
driver: local
networks:
azerothcore:
name: ${NETWORK_NAME}
driver: bridge
ipam:
config:
- subnet: ${NETWORK_SUBNET}
gateway: ${NETWORK_GATEWAY}