mirror of
https://github.com/uprightbass360/AzerothCore-RealmMaster.git
synced 2026-01-13 00:58:34 +00:00
cleanup
This commit is contained in:
4
.env
4
.env
@@ -298,8 +298,8 @@ PMA_MAX_EXECUTION_TIME=600
|
||||
# Keira3 Database Editor settings
|
||||
KEIRA3_EXTERNAL_PORT=4201
|
||||
|
||||
# CMS Web Interface settings
|
||||
CMS_EXTERNAL_PORT=8001
|
||||
# CMS Web Interface settings (removed - build your own)
|
||||
# CMS_EXTERNAL_PORT=8001
|
||||
|
||||
# Grafana settings
|
||||
GF_EXTERNAL_PORT=3001
|
||||
|
||||
@@ -481,27 +481,6 @@ services:
|
||||
networks:
|
||||
- azerothcore
|
||||
|
||||
# ACore CMS Web Interface
|
||||
ac-cms:
|
||||
image: nginx:alpine
|
||||
container_name: ac-cms
|
||||
depends_on:
|
||||
ac-mysql:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
# External access configuration
|
||||
EXTERNAL_BASE_URL: ${EXTERNAL_BASE_URL:-}
|
||||
PMA_EXTERNAL_PORT: ${PMA_EXTERNAL_PORT:-8081}
|
||||
KEIRA3_EXTERNAL_PORT: ${KEIRA3_EXTERNAL_PORT:-4201}
|
||||
GF_EXTERNAL_PORT: ${GF_EXTERNAL_PORT:-3001}
|
||||
INFLUXDB_EXTERNAL_PORT: ${INFLUXDB_EXTERNAL_PORT:-8087}
|
||||
ports:
|
||||
- "${CMS_EXTERNAL_PORT:-8001}:80"
|
||||
volumes:
|
||||
- ./assets/cms:/usr/share/nginx/html:ro
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- azerothcore
|
||||
|
||||
# Automated Backup System
|
||||
ac-backup:
|
||||
@@ -572,8 +551,6 @@ volumes:
|
||||
driver: local
|
||||
ac_grafana_config:
|
||||
driver: local
|
||||
ac_cms_data:
|
||||
driver: local
|
||||
ac_keira3_data:
|
||||
driver: local
|
||||
|
||||
|
||||
@@ -1,486 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AzerothCore Administration Portal</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #3498db;
|
||||
--secondary-color: #2c3e50;
|
||||
--success-color: #27ae60;
|
||||
--background-color: #f8f9fa;
|
||||
--card-background: #ffffff;
|
||||
--border-radius: 12px;
|
||||
--shadow: 0 4px 20px rgba(0,0,0,0.1);
|
||||
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: var(--card-background);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
box-shadow: var(--shadow);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
color: var(--secondary-color);
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.header .subtitle {
|
||||
color: #6c757d;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.status-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.status-card {
|
||||
background: var(--card-background);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 1.5rem;
|
||||
box-shadow: var(--shadow);
|
||||
border-left: 4px solid var(--success-color);
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: var(--success-color);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
.services-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.service-card {
|
||||
background: var(--card-background);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 2rem;
|
||||
box-shadow: var(--shadow);
|
||||
transition: var(--transition);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.service-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: linear-gradient(90deg, var(--primary-color), #9b59b6);
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.service-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 30px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.service-icon {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 1rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.service-title {
|
||||
color: var(--secondary-color);
|
||||
font-size: 1.3rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.service-description {
|
||||
color: #6c757d;
|
||||
margin-bottom: 1.5rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.service-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
background: linear-gradient(135deg, var(--primary-color), #9b59b6);
|
||||
color: white;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.service-link:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 15px rgba(52, 152, 219, 0.3);
|
||||
}
|
||||
|
||||
.service-link.unavailable {
|
||||
background: #95a5a6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.connection-info {
|
||||
background: var(--card-background);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 2rem;
|
||||
box-shadow: var(--shadow);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.connection-title {
|
||||
color: var(--secondary-color);
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.connection-details {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.connection-item {
|
||||
background: #f8f9fa;
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.connection-label {
|
||||
font-weight: 600;
|
||||
color: var(--secondary-color);
|
||||
display: block;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.connection-value {
|
||||
font-family: 'Consolas', 'Monaco', monospace;
|
||||
background: var(--secondary-color);
|
||||
color: white;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 3px solid #f3f3f3;
|
||||
border-top: 3px solid var(--primary-color);
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
color: rgba(255,255,255,0.8);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.dashboard {
|
||||
padding: 1rem;
|
||||
}
|
||||
.header h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
.services-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="dashboard">
|
||||
<div class="header">
|
||||
<h1>🏰 AzerothCore Administration Portal</h1>
|
||||
<div class="subtitle">Comprehensive server management and monitoring dashboard</div>
|
||||
</div>
|
||||
|
||||
<div class="status-grid">
|
||||
<div class="status-card">
|
||||
<div class="status-indicator">
|
||||
<span class="status-dot"></span>
|
||||
<strong>World Server</strong>
|
||||
</div>
|
||||
<span id="world-status">Initializing...</span>
|
||||
</div>
|
||||
<div class="status-card">
|
||||
<div class="status-indicator">
|
||||
<span class="status-dot"></span>
|
||||
<strong>Database</strong>
|
||||
</div>
|
||||
<span id="db-status">Initializing...</span>
|
||||
</div>
|
||||
<div class="status-card">
|
||||
<div class="status-indicator">
|
||||
<span class="status-dot"></span>
|
||||
<strong>Authentication</strong>
|
||||
</div>
|
||||
<span id="auth-status">Initializing...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="services-grid" id="services-container">
|
||||
<!-- Services will be populated by JavaScript -->
|
||||
</div>
|
||||
|
||||
<div class="connection-info">
|
||||
<div class="connection-title">🎮 Game Server Connection Details</div>
|
||||
<div class="connection-details">
|
||||
<div class="connection-item">
|
||||
<span class="connection-label">Server Host</span>
|
||||
<span class="connection-value" id="server-host">{{EXTERNAL_BASE_URL}}</span>
|
||||
</div>
|
||||
<div class="connection-item">
|
||||
<span class="connection-label">Auth Port</span>
|
||||
<span class="connection-value">{{DOCKER_AUTH_EXTERNAL_PORT}}</span>
|
||||
</div>
|
||||
<div class="connection-item">
|
||||
<span class="connection-label">World Port</span>
|
||||
<span class="connection-value">{{DOCKER_WORLD_EXTERNAL_PORT}}</span>
|
||||
</div>
|
||||
<div class="connection-item">
|
||||
<span class="connection-label">Database Port</span>
|
||||
<span class="connection-value">{{DOCKER_DB_EXTERNAL_PORT}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>AzerothCore Docker Compose Stack • Built with ❤️ for the community</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Configuration object with environment variables injected
|
||||
const CONFIG = {
|
||||
baseUrl: '{{EXTERNAL_BASE_URL}}',
|
||||
services: {
|
||||
phpmyadmin: {
|
||||
name: 'Database Management',
|
||||
icon: '📊',
|
||||
description: 'Complete MySQL database administration with full query capabilities',
|
||||
port: '{{PMA_EXTERNAL_PORT}}',
|
||||
path: '',
|
||||
status: 'checking'
|
||||
},
|
||||
keira3: {
|
||||
name: 'Database Editor',
|
||||
icon: '⚙️',
|
||||
description: 'Specialized AzerothCore database editor for world data management',
|
||||
port: '{{KEIRA3_EXTERNAL_PORT}}',
|
||||
path: '',
|
||||
status: 'checking'
|
||||
},
|
||||
grafana: {
|
||||
name: 'Server Monitoring',
|
||||
icon: '📈',
|
||||
description: 'Real-time performance dashboards and system metrics visualization',
|
||||
port: '{{GF_EXTERNAL_PORT}}',
|
||||
path: '',
|
||||
status: 'checking'
|
||||
},
|
||||
influxdb: {
|
||||
name: 'Metrics Database',
|
||||
icon: '💾',
|
||||
description: 'Time-series database for historical performance data and analytics',
|
||||
port: '{{INFLUXDB_EXTERNAL_PORT}}',
|
||||
path: '',
|
||||
status: 'checking'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class AzerothDashboard {
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.processConfig();
|
||||
this.renderServices();
|
||||
this.updateServerHost();
|
||||
this.checkServiceStatus();
|
||||
this.startStatusUpdates();
|
||||
}
|
||||
|
||||
processConfig() {
|
||||
// Detect if we're using a custom base URL or current location
|
||||
if (!CONFIG.baseUrl || CONFIG.baseUrl === '{{EXTERNAL_BASE_URL}}' || CONFIG.baseUrl.trim() === '') {
|
||||
CONFIG.baseUrl = `${window.location.protocol}//${window.location.hostname}`;
|
||||
}
|
||||
|
||||
// Process each service configuration
|
||||
Object.keys(CONFIG.services).forEach(key => {
|
||||
const service = CONFIG.services[key];
|
||||
service.url = this.buildServiceUrl(service);
|
||||
});
|
||||
}
|
||||
|
||||
buildServiceUrl(service) {
|
||||
const port = service.port === `{{${service.name.toUpperCase().replace(/ /g, '_')}_EXTERNAL_PORT}}` ?
|
||||
this.getDefaultPort(service) : service.port;
|
||||
|
||||
// If port is set, append it; otherwise use base URL as-is
|
||||
if (port && port !== 'undefined') {
|
||||
return `${CONFIG.baseUrl}:${port}${service.path}`;
|
||||
}
|
||||
return `${CONFIG.baseUrl}${service.path}`;
|
||||
}
|
||||
|
||||
getDefaultPort(service) {
|
||||
const defaults = {
|
||||
'Database Management': '8081',
|
||||
'Database Editor': '4201',
|
||||
'Server Monitoring': '3001',
|
||||
'Metrics Database': '8087'
|
||||
};
|
||||
return defaults[service.name] || '';
|
||||
}
|
||||
|
||||
renderServices() {
|
||||
const container = document.getElementById('services-container');
|
||||
container.innerHTML = '';
|
||||
|
||||
Object.entries(CONFIG.services).forEach(([key, service]) => {
|
||||
const serviceCard = document.createElement('div');
|
||||
serviceCard.className = 'service-card';
|
||||
serviceCard.innerHTML = `
|
||||
<span class="service-icon">${service.icon}</span>
|
||||
<div class="service-title">${service.name}</div>
|
||||
<div class="service-description">${service.description}</div>
|
||||
<a href="${service.url}" class="service-link" id="link-${key}" target="_blank">
|
||||
<span class="loading" id="loading-${key}"></span>
|
||||
<span id="text-${key}">Checking availability...</span>
|
||||
</a>
|
||||
`;
|
||||
container.appendChild(serviceCard);
|
||||
});
|
||||
}
|
||||
|
||||
updateServerHost() {
|
||||
const hostElement = document.getElementById('server-host');
|
||||
if (hostElement) {
|
||||
const displayHost = CONFIG.baseUrl.replace(/^https?:\/\//, '');
|
||||
hostElement.textContent = displayHost;
|
||||
}
|
||||
}
|
||||
|
||||
async checkServiceStatus() {
|
||||
const statusChecks = Object.keys(CONFIG.services).map(async (key) => {
|
||||
try {
|
||||
const service = CONFIG.services[key];
|
||||
const response = await fetch(service.url, {
|
||||
method: 'HEAD',
|
||||
mode: 'no-cors',
|
||||
timeout: 5000
|
||||
});
|
||||
this.updateServiceStatus(key, 'available');
|
||||
} catch (error) {
|
||||
// In no-cors mode, we can't read the response, so we assume it's available if no network error
|
||||
this.updateServiceStatus(key, 'available');
|
||||
}
|
||||
});
|
||||
|
||||
// Fallback: assume all services are available after 3 seconds
|
||||
setTimeout(() => {
|
||||
Object.keys(CONFIG.services).forEach(key => {
|
||||
const link = document.getElementById(`link-${key}`);
|
||||
if (link && link.classList.contains('service-link')) {
|
||||
this.updateServiceStatus(key, 'available');
|
||||
}
|
||||
});
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
updateServiceStatus(serviceKey, status) {
|
||||
const link = document.getElementById(`link-${serviceKey}`);
|
||||
const loading = document.getElementById(`loading-${serviceKey}`);
|
||||
const text = document.getElementById(`text-${serviceKey}`);
|
||||
|
||||
if (loading) loading.style.display = 'none';
|
||||
|
||||
if (status === 'available') {
|
||||
link.classList.remove('unavailable');
|
||||
text.textContent = `Open ${CONFIG.services[serviceKey].name}`;
|
||||
} else {
|
||||
link.classList.add('unavailable');
|
||||
text.textContent = 'Service Unavailable';
|
||||
link.onclick = (e) => e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
startStatusUpdates() {
|
||||
// Update server status indicators
|
||||
setTimeout(() => {
|
||||
document.getElementById('world-status').textContent = 'Online • Ready for Players';
|
||||
document.getElementById('db-status').textContent = 'Connected • All Tables Loaded';
|
||||
document.getElementById('auth-status').textContent = 'Active • Accepting Connections';
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize dashboard when DOM is loaded
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new AzerothDashboard();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
21
readme.md
21
readme.md
@@ -124,7 +124,6 @@ azerothcore-docker/
|
||||
| `ac-grafana` | grafana/grafana | Monitoring dashboard | 3001:3000 |
|
||||
| `ac-influxdb` | influxdb:2.7-alpine | Metrics database | 8087:8086 |
|
||||
| `ac-keira3` | node:18-alpine | Database editor web UI | 4201:4200 |
|
||||
| `ac-cms` | nginx:alpine | Admin dashboard | 8001:80 |
|
||||
| `ac-backup` | mysql:8.0 | Automated backup service | - |
|
||||
|
||||
### Container Relationships
|
||||
@@ -268,7 +267,6 @@ All configuration is managed through the `.env` file. Key variables:
|
||||
- `KEIRA3_EXTERNAL_PORT`: Database editor port (4201)
|
||||
- `GF_EXTERNAL_PORT`: Grafana monitoring port (3001)
|
||||
- `INFLUXDB_EXTERNAL_PORT`: InfluxDB metrics port (8087)
|
||||
- `CMS_EXTERNAL_PORT`: Admin dashboard port (8001)
|
||||
|
||||
#### Performance Settings
|
||||
- `MAX_PLAYERS`: Maximum concurrent players
|
||||
@@ -630,6 +628,25 @@ docker stats --no-stream
|
||||
- **[AzerothCore Forums](https://github.com/azerothcore/azerothcore-wotlk/discussions)** - Discussions
|
||||
- **[ChromieCraft](https://www.chromiecraft.com/)** - AzerothCore-based progressive server
|
||||
|
||||
## Available Services
|
||||
|
||||
| Service | Endpoint | Port | Purpose |
|
||||
|---------|----------|------|---------|
|
||||
| **Game Server** | `localhost:8215` | 8215 | World server (game connection) |
|
||||
| **Auth Server** | `localhost:3784` | 3784 | Authentication server |
|
||||
| **SOAP API** | `localhost:7778` | 7778 | Server administration API |
|
||||
| **PHPMyAdmin** | `http://localhost:8081` | 8081 | Database management interface |
|
||||
| **Keira3** | `http://localhost:4201` | 4201 | Database editor web UI |
|
||||
| **Grafana** | `http://localhost:3001` | 3001 | Monitoring dashboard |
|
||||
| **InfluxDB** | `localhost:8087` | 8087 | Metrics database |
|
||||
| **MySQL** | `localhost:64306` | 64306 | Direct database access |
|
||||
|
||||
### Database Credentials
|
||||
- **Host**: `localhost:64306`
|
||||
- **User**: `root`
|
||||
- **Password**: `azerothcore123` (configurable in .env)
|
||||
- **Databases**: `acore_auth`, `acore_world`, `acore_characters`
|
||||
|
||||
### Related Projects
|
||||
- **[Original Docker Setup](https://github.com/coc0nut/AzerothCore-with-Playerbots-Docker-Setup)** - Base Docker configuration this project extends
|
||||
- **[AzerothCore Modules](https://github.com/azerothcore/mod-repo-list)** - Additional modules catalog
|
||||
|
||||
Reference in New Issue
Block a user