version: '3.8' # ============================================== # AZEROTHCORE UNIFIED DOCKER COMPOSE # ============================================== # Compatible with both local development and Portainer deployment # Set DEPLOYMENT_MODE=local|portainer in .env file services: # Step 1: Standard MySQL database ac-mysql: image: mysql:8.0 container_name: ac-mysql environment: MYSQL_ROOT_PASSWORD: ${DOCKER_DB_ROOT_PASSWORD:-password} MYSQL_ROOT_HOST: '%' ports: - "${DOCKER_DB_EXTERNAL_PORT:-64306}:3306" volumes: - ${STORAGE_PATH_CONTAINERS}${STORAGE_PATH_CONTAINERS:+/azerothcore/mysql}${STORAGE_PATH_CONTAINERS:-ac_mysql_data}:/var/lib/mysql command: > --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max_connections=1000 --innodb-buffer-pool-size=256M --innodb-log-file-size=64M restart: unless-stopped healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-p${DOCKER_DB_ROOT_PASSWORD:-password}"] interval: 10s timeout: 5s retries: 10 start_period: 30s networks: - azerothcore # Step 2: Initialize databases ac-db-init: image: mysql:8.0 container_name: ac-db-init depends_on: ac-mysql: condition: service_healthy networks: - azerothcore environment: MYSQL_PWD: ${DOCKER_DB_ROOT_PASSWORD:-password} command: | sh -c ' echo "Creating AzerothCore databases..." mysql -h ac-mysql -uroot -e " CREATE DATABASE IF NOT EXISTS acore_auth DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE IF NOT EXISTS acore_world DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE IF NOT EXISTS acore_characters DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; SHOW DATABASES; " || true echo "Databases created!" ' restart: "no" # Step 3: Import AzerothCore database schema and data ac-db-import: image: acore/ac-wotlk-db-import:14.0.0-dev container_name: ac-db-import depends_on: - ac-db-init networks: - azerothcore volumes: - ${STORAGE_PATH_CONTAINERS}${STORAGE_PATH_CONTAINERS:+/azerothcore/config}${STORAGE_PATH_CONTAINERS:-ac_config}:/azerothcore/env/dist/etc environment: AC_DATA_DIR: "/azerothcore/data" AC_LOGS_DIR: "/azerothcore/logs" AC_LOGIN_DATABASE_INFO: "ac-mysql;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_auth" AC_WORLD_DATABASE_INFO: "ac-mysql;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_world" AC_CHARACTER_DATABASE_INFO: "ac-mysql;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_characters" 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" entrypoint: ["/bin/bash", "-c"] command: | " echo 'Waiting for databases to be ready...' sleep 10 echo 'Creating config file for dbimport...' mkdir -p /azerothcore/env/dist/etc cat > /azerothcore/env/dist/etc/dbimport.conf < sh -c " apk add --no-cache curl unzip wget ca-certificates p7zip if [ -d '/azerothcore/data/maps' ] && [ -d '/azerothcore/data/vmaps' ] && [ -d '/azerothcore/data/mmaps' ] && [ -d '/azerothcore/data/dbc' ]; then echo 'โœ… Game data already exists, skipping download' exit 0 fi echo '๐Ÿš€ Starting AzerothCore game data download...' echo 'This will download ~15GB of data and may take 10-30 minutes' # Get the latest release info from wowgaming/client-data echo '๐Ÿ“ก Fetching latest client data release info...' LATEST_URL=$$(wget -qO- https://api.github.com/repos/wowgaming/client-data/releases/latest | grep '"browser_download_url":' | grep '\.7z' | cut -d'"' -f4 | head -1) if [ -z \"$$LATEST_URL\" ]; then echo 'โŒ Could not fetch latest release URL' echo '๐Ÿ“ฅ Using fallback: direct download from v16 release' LATEST_URL='https://github.com/wowgaming/client-data/releases/download/v16/data.7z' fi echo \"๐Ÿ“ฅ Downloading client data from: $$LATEST_URL\" # Download the client data wget -O data.7z \"$$LATEST_URL\" || { echo 'โŒ Download failed, trying alternative method' curl -L -o data.7z \"$$LATEST_URL\" || { echo 'โŒ All download methods failed' exit 1 } } echo '๐Ÿ“Š Download completed, file size:' ls -lh data.7z echo '๐Ÿ“‚ Extracting client data (this may take 10-15 minutes)...' 7z x data.7z -o/azerothcore/data/ || { echo 'โŒ Extraction failed' exit 1 } echo '๐Ÿงน Cleaning up downloaded archive...' rm -f data.7z echo 'โœ… Client data extraction complete!' echo '๐Ÿ“ Verifying extracted directories:' ls -la /azerothcore/data/ # Verify required directories exist for dir in maps vmaps mmaps dbc; do if [ -d \"/azerothcore/data/$$dir\" ]; then echo \"โœ… $$dir directory: OK\" else echo \"โŒ $$dir directory: MISSING\" fi done echo '๐ŸŽ‰ Game data setup complete! AzerothCore worldserver can now start.' " restart: "no" networks: - azerothcore # Step 5: World server with Playerbots support ac-worldserver: image: acore/ac-wotlk-worldserver:14.0.0-dev container_name: ac-worldserver stdin_open: true tty: true depends_on: - ac-authserver - ac-client-data environment: AC_LOGIN_DATABASE_INFO: "ac-mysql;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_auth" AC_WORLD_DATABASE_INFO: "ac-mysql;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_world" AC_CHARACTER_DATABASE_INFO: "ac-mysql;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_characters" AC_UPDATES_ENABLE_DATABASES: "0" AC_BIND_IP: "0.0.0.0" AC_DATA_DIR: "/azerothcore/data" AC_SOAP_PORT: "7878" AC_PROCESS_PRIORITY: "0" PLAYERBOT_ENABLED: "${PLAYERBOT_ENABLED:-1}" PLAYERBOT_MAX_BOTS: "${PLAYERBOT_MAX_BOTS:-40}" # Logger configuration - Use config file defaults with proper log level AC_LOG_LEVEL: "2" ports: - "${DOCKER_WORLD_EXTERNAL_PORT:-8215}:8085" - "${DOCKER_SOAP_EXTERNAL_PORT:-7778}:7878" volumes: - ${HOST_DATA_PATH:-./data}:/azerothcore/data - ${STORAGE_PATH_CONTAINERS}${STORAGE_PATH_CONTAINERS:+/azerothcore/config}${STORAGE_PATH_CONTAINERS:-ac_config}:/azerothcore/env/dist/etc - ${STORAGE_PATH_CONTAINERS}${STORAGE_PATH_CONTAINERS:+/azerothcore/logs}${STORAGE_PATH_CONTAINERS:-ac_logs}:/azerothcore/logs - ${STORAGE_PATH_CONTAINERS}${STORAGE_PATH_CONTAINERS:+/azerothcore/modules}${STORAGE_PATH_CONTAINERS:-ac_modules}:/azerothcore/modules restart: unless-stopped networks: - azerothcore cap_add: - SYS_NICE healthcheck: test: ["CMD", "sh", "-c", "ps aux | grep '[w]orldserver' | grep -v grep || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 120s # Optional: Eluna Lua Engine ac-eluna: image: acore/eluna-ts:master container_name: ac-eluna depends_on: - ac-worldserver restart: unless-stopped networks: - azerothcore # Module Management Service ac-modules: image: alpine/git:latest container_name: ac-modules volumes: - ${STORAGE_PATH_CONTAINERS}${STORAGE_PATH_CONTAINERS:+/azerothcore/modules}${STORAGE_PATH_CONTAINERS:-ac_modules}:/modules environment: - MODULE_PLAYERBOTS=${MODULE_PLAYERBOTS:-1} - MODULE_AOE_LOOT=${MODULE_AOE_LOOT:-0} - MODULE_LEARN_SPELLS=${MODULE_LEARN_SPELLS:-0} - MODULE_FIREWORKS=${MODULE_FIREWORKS:-0} - MODULE_INDIVIDUAL_PROGRESSION=${MODULE_INDIVIDUAL_PROGRESSION:-0} - DEPLOYMENT_MODE=${DEPLOYMENT_MODE:-local} entrypoint: ["/bin/sh", "-c"] command: | " echo 'Initializing module management...' cd /modules if [ \"$DEPLOYMENT_MODE\" = \"portainer\" ]; then echo 'Simple module setup for Portainer deployment...' mkdir -p mod-playerbots echo 'โœ… Playerbot module directory created' else echo 'Advanced module setup for local development...' # Install Playerbots if enabled if [ \"$$MODULE_PLAYERBOTS\" = \"1\" ] && [ ! -d \"mod-playerbots\" ]; then echo 'Installing mod-playerbots...' git clone https://github.com/liyunfan1223/mod-playerbots.git mod-playerbots fi # Install AOE Loot if enabled if [ \"$$MODULE_AOE_LOOT\" = \"1\" ] && [ ! -d \"mod-aoe-loot\" ]; then echo 'Installing mod-aoe-loot...' git clone https://github.com/azerothcore/mod-aoe-loot.git mod-aoe-loot fi # Install Learn Spells if enabled if [ \"$$MODULE_LEARN_SPELLS\" = \"1\" ] && [ ! -d \"mod-learn-spells\" ]; then echo 'Installing mod-learn-spells...' git clone https://github.com/azerothcore/mod-learn-spells.git mod-learn-spells fi # Install Fireworks on Level if enabled if [ \"$$MODULE_FIREWORKS\" = \"1\" ] && [ ! -d \"mod-fireworks-on-level\" ]; then echo 'Installing mod-fireworks-on-level...' git clone https://github.com/azerothcore/mod-fireworks-on-level.git mod-fireworks-on-level fi # Install Individual Progression if enabled if [ \"$$MODULE_INDIVIDUAL_PROGRESSION\" = \"1\" ] && [ ! -d \"mod-individual-progression\" ]; then echo 'Installing mod-individual-progression...' git clone https://github.com/azerothcore/mod-individual-progression.git mod-individual-progression fi fi echo 'Module management complete. Keeping container alive...' tail -f /dev/null " restart: "no" networks: - azerothcore # PHPMyAdmin Database Management Interface ac-phpmyadmin: image: phpmyadmin/phpmyadmin:latest container_name: ac-phpmyadmin depends_on: ac-mysql: condition: service_healthy environment: PMA_HOST: ${PMA_HOST:-ac-mysql} PMA_PORT: ${PMA_PORT:-3306} PMA_USER: ${PMA_USER:-root} PMA_PASSWORD: ${DOCKER_DB_ROOT_PASSWORD:-password} MYSQL_ROOT_PASSWORD: ${DOCKER_DB_ROOT_PASSWORD:-password} PMA_ARBITRARY: ${PMA_ARBITRARY:-1} PMA_ABSOLUTE_URI: ${PMA_ABSOLUTE_URI:-} UPLOAD_LIMIT: ${PMA_UPLOAD_LIMIT:-300M} MEMORY_LIMIT: ${PMA_MEMORY_LIMIT:-512M} MAX_EXECUTION_TIME: ${PMA_MAX_EXECUTION_TIME:-600} ports: - "${PMA_EXTERNAL_PORT:-8081}:80" restart: unless-stopped networks: - azerothcore # Keira3 Database Editor (Production Ready) ac-keira3: image: uprightbass360/keira3:latest container_name: ac-keira3 restart: unless-stopped depends_on: ac-mysql: condition: service_healthy environment: - NODE_ENV=production - KEIRA_PORT=8080 - KEIRA_HOST=0.0.0.0 - KEIRA_DATABASE_HOST=ac-mysql - KEIRA_DATABASE_PORT=3306 - KEIRA_DATABASE_USER=root - KEIRA_DATABASE_PASSWORD=${DOCKER_DB_ROOT_PASSWORD:-password} - KEIRA_DATABASE_NAME=acore_world ports: - "${KEIRA3_EXTERNAL_PORT:-4201}:8080" deploy: resources: limits: memory: 512M cpus: '0.5' reservations: memory: 256M cpus: '0.25' healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s logging: driver: json-file options: max-size: "10m" max-file: "3" security_opt: - no-new-privileges:true networks: - azerothcore # InfluxDB for Monitoring ac-influxdb: image: influxdb:2.7-alpine container_name: ac-influxdb environment: DOCKER_INFLUXDB_INIT_MODE: ${INFLUXDB_INIT_MODE:-setup} DOCKER_INFLUXDB_INIT_USERNAME: ${INFLUXDB_ADMIN_USER:-acore} DOCKER_INFLUXDB_INIT_PASSWORD: ${INFLUXDB_ADMIN_PASSWORD:-acore123} DOCKER_INFLUXDB_INIT_ORG: ${INFLUXDB_ORG:-azerothcore} DOCKER_INFLUXDB_INIT_BUCKET: ${INFLUXDB_BUCKET:-metrics} DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: ${INFLUXDB_TOKEN:-acore-monitoring-token-12345} INFLUXDB_HTTP_AUTH_ENABLED: ${INFLUXDB_HTTP_AUTH_ENABLED:-true} INFLUXDB_HTTP_HTTPS_ENABLED: ${INFLUXDB_HTTP_HTTPS_ENABLED:-false} ports: - "${INFLUXDB_EXTERNAL_PORT:-8087}:8086" volumes: - ${STORAGE_PATH_CONTAINERS}${STORAGE_PATH_CONTAINERS:+/azerothcore/influxdb}${STORAGE_PATH_CONTAINERS:-ac_influxdb_data}:/var/lib/influxdb2 restart: unless-stopped networks: - azerothcore # Grafana Monitoring Dashboard ac-grafana: image: grafana/grafana:latest container_name: ac-grafana depends_on: - ac-influxdb environment: GF_SECURITY_ADMIN_USER: ${GF_SECURITY_ADMIN_USER:-admin} GF_SECURITY_ADMIN_PASSWORD: ${GF_SECURITY_ADMIN_PASSWORD:-acore123} GF_INSTALL_PLUGINS: ${GF_INSTALL_PLUGINS:-grafana-piechart-panel} GF_SERVER_ROOT_URL: ${GF_SERVER_ROOT_URL:-http://localhost:3000} GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION: ${GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION:-false} GF_SECURITY_SECRET_KEY: ${GF_SECURITY_SECRET_KEY:-} GF_USERS_ALLOW_SIGN_UP: ${GF_USERS_ALLOW_SIGN_UP:-false} GF_USERS_ALLOW_ORG_CREATE: ${GF_USERS_ALLOW_ORG_CREATE:-false} GF_AUTH_ANONYMOUS_ENABLED: ${GF_AUTH_ANONYMOUS_ENABLED:-false} GF_SERVER_ENABLE_GZIP: ${GF_SERVER_ENABLE_GZIP:-true} GF_SECURITY_COOKIE_SECURE: ${GF_SECURITY_COOKIE_SECURE:-false} GF_SECURITY_COOKIE_SAMESITE: ${GF_SECURITY_COOKIE_SAMESITE:-lax} ports: - "${GF_EXTERNAL_PORT:-3001}:3000" volumes: - ${STORAGE_PATH_CONTAINERS}${STORAGE_PATH_CONTAINERS:+/azerothcore/grafana}${STORAGE_PATH_CONTAINERS:-ac_grafana_data}:/var/lib/grafana - ${STORAGE_PATH_CONTAINERS}${STORAGE_PATH_CONTAINERS:+/azerothcore/grafana-config}${STORAGE_PATH_CONTAINERS:-ac_grafana_config}:/etc/grafana restart: unless-stopped networks: - azerothcore # Automated Backup System ac-backup: image: mysql:8.0 container_name: ac-backup depends_on: ac-mysql: condition: service_healthy environment: MYSQL_HOST: ac-mysql MYSQL_PORT: 3306 MYSQL_USER: root MYSQL_PASSWORD: ${DOCKER_DB_ROOT_PASSWORD:-password} BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7} BACKUP_CRON_SCHEDULE: ${BACKUP_CRON_SCHEDULE:-0 3 * * *} TZ: ${TZ:-UTC} volumes: - ${HOST_BACKUP_PATH:-./backups}:/backups - ${HOST_BACKUP_SCRIPTS_PATH:-./backup-scripts}:/scripts working_dir: /scripts command: - /bin/bash - -c - | apt-get update && apt-get install -y cron chmod +x /scripts/*.sh 2>/dev/null || echo 'No scripts to make executable' touch /var/log/backup.log echo "$$BACKUP_CRON_SCHEDULE /scripts/backup.sh >> /var/log/backup.log 2>&1" | crontab - echo "Starting backup service with schedule: $$BACKUP_CRON_SCHEDULE" echo "Backup retention: $$BACKUP_RETENTION_DAYS days" echo "Scripts location: /scripts" echo "Backup location: /backups" if [ -f "/scripts/backup.sh" ]; then echo "Running initial backup..." /scripts/backup.sh >> /var/log/backup.log 2>&1 else echo "No backup script found at /scripts/backup.sh" fi echo "Starting cron daemon..." /etc/init.d/cron start tail -f /var/log/backup.log restart: unless-stopped networks: - azerothcore volumes: ac_mysql_data: driver: local ac_config: driver: local ac_logs: driver: local ac_modules: driver: local ac_influxdb_data: driver: local ac_grafana_data: driver: local ac_grafana_config: driver: local ac_keira3_data: driver: local networks: azerothcore: driver: bridge name: ${NETWORK_NAME:-azerothcore} ipam: config: - subnet: ${NETWORK_SUBNET:-172.20.0.0/16} gateway: ${NETWORK_GATEWAY:-172.20.0.1}