Cómo Integrar el Sitio Web y el Juego en tu Servidor de MU Online
Aprende a conectar tu servidor de juego MU Online con un panel web, compartiendo la misma base de datos para gestión de cuentas, rankings y funciones web.
Comprendiendo la Arquitectura de Integración
Conectar un sitio web a un servidor de MU Online no es instalar un plugin: es una decisión arquitectónica que une dos sistemas separados a través de una base de datos compartida. El servidor de juego (GameServer, ConnectServer, JoinServer, DataServer) escribe y lee datos de jugadores desde Microsoft SQL Server. Tu panel web lee y escribe en esa misma base de datos para proporcionar registro de cuentas, rankings de personajes, tiendas de ítems, sistemas de votos y herramientas administrativas.
Antes de tocar cualquier archivo de configuración, necesitas tener claro qué hace cada componente:
- SQL Server — la única fuente de verdad compartida por el juego y el sitio web.
- Procesos del servidor de juego — ConnectServer, GameServer, JoinServer, DataServer. Nunca deben quedar expuestos directamente a la web.
- Servidor web — Apache o Nginx sirviendo páginas PHP, ASP.NET o Node.js. Se comunica solo con SQL Server, nunca directamente con los procesos del servidor de juego.
- Firewall — controla qué puertos son accesibles desde internet. SQL Server nunca debe estar abierto a la internet pública.
> [!ATENCION] > Nunca expongas el puerto de SQL Server (1433) a la internet pública. Todo el tráfico web-a-base-de-datos debe viajar a través de una interfaz de red privada o localhost. Un firewall mal configurado es una de las causas más comunes de servidores comprometidos.
Preparando SQL Server para el Acceso Web
Tus bases de datos del juego probablemente ya existen (MuOnline, MEMB_INFO, MuEventChips y otras según tu temporada). El primer paso es crear un login de SQL Server dedicado para la aplicación web.
Abre SQL Server Management Studio (SSMS) y ejecuta el siguiente script. Reemplaza los valores de ejemplo con los tuyos:
-- Crear un login a nivel de servidor
CREATE LOGIN [mu_webuser] WITH PASSWORD = 'ContrasenaFuerte!42',
DEFAULT_DATABASE = [MuOnline],
CHECK_EXPIRATION = OFF,
CHECK_POLICY = ON;
-- Mapear el login a cada base de datos relevante
USE [MuOnline];
CREATE USER [mu_webuser] FOR LOGIN [mu_webuser];
-- Otorgar solo lo que el sitio necesita
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO [mu_webuser];
USE [MEMB_INFO];
CREATE USER [mu_webuser] FOR LOGIN [mu_webuser];
GRANT SELECT, INSERT, UPDATE ON SCHEMA::dbo TO [mu_webuser];
Tablas clave con las que tu panel web interactuará con más frecuencia:
MEMB_INFO → credenciales de cuenta y estado
MEMB_STAT → estado en línea, marcas de tiempo del último acceso
Character → nombre, clase, nivel y resets del personaje
T_CashShop_Item → registros de la tienda web / ítems de cash
MuEventChips → Puntos Goblin u otras tablas de recompensas por voto
Formato de cadena de conexión (ejemplo PHP PDO):
Host → 127.0.0.1 o IP de LAN privada (nunca 0.0.0.0)
Puerto → 1433
Driver → ODBC Driver 17 for SQL Server
DB → MuOnline (establecer por consulta con USE o calificar nombres de tabla)
> [!CONSEJO] > Habilita el modo de autenticación mixta de SQL Server (SQL Server y Autenticación de Windows) si aún no está activo. Puedes verificarlo en SSMS en Propiedades del Servidor → Seguridad. Reinicia el servicio de SQL Server después de cambiar el modo de autenticación.
Configurando el Servidor Web
Apache con PHP (Windows)
Si tu servidor de juego corre en Windows (lo habitual para setups de Season 6 a Season 15), es probable que estés ejecutando Apache a través de XAMPP o una instalación independiente. Puntos clave de configuración:
- Vincula Apache a una dirección IP específica, no a
0.0.0.0, si quieres restringir el acceso a una interfaz de administración. - Coloca los archivos de tu panel web fuera de los directorios del servidor de juego — por ejemplo
C:\WebPanel\htdocs\en lugar de dentro del árbol de carpetas del MuServer. - Habilita las extensiones
php_sqlsrvyphp_pdo_sqlsrvenphp.ini. Estos son los drivers PHP oficiales de Microsoft para SQL Server y ofrecen mejor rendimiento y compatibilidad que la extensión ODBC genérica.
; Adiciones a php.ini
extension = php_sqlsrv.dll
extension = php_pdo_sqlsrv.dll
; Configuraciones de seguridad recomendadas
expose_php = Off
display_errors = Off
log_errors = On
error_log = C:\WebPanel\logs\php_errors.log
session.cookie_httponly = 1
session.use_strict_mode = 1
Nginx como Proxy Inverso (paneles Linux)
Si ejecutas un panel web basado en Linux (como un setup de PHP-FPM o una aplicación Node.js) y quieres que Nginx actúe de intermediario:
server {
listen 80;
server_name panel.tudominio.com;
# Redirigir todo HTTP a HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name panel.tudominio.com;
ssl_certificate /etc/ssl/certs/tu_certificado.pem;
ssl_certificate_key /etc/ssl/private/tu_clave.pem;
location / {
proxy_pass http://127.0.0.1:3000; # → upstream Node o PHP-FPM
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Vinculando el Registro de Cuentas al Juego
La creación de cuentas en el sitio web debe escribir los datos exactamente en el formato que espera el servidor de juego. La tabla más crítica es MEMB_INFO. Un insert de registro mínimo luce así:
-- Ejemplo: registrar una nueva cuenta
-- El hash de contraseña debe coincidir con el formato esperado por tu núcleo
INSERT INTO MEMB_INFO (
memb___id, -- → nombre de cuenta (máx 10 caracteres, alfanumérico)
memb__pwd, -- → contraseña hasheada (MD5 u hash específico del servidor)
memb_name, -- → nombre para mostrar
sno__numb, -- → campo de número social/ID (usar '0000000000' si no aplica)
bloc_code, -- → 0 = activa, 1 = bloqueada
mail_addr, -- → dirección de correo electrónico
mail_chek, -- → indicador de email verificado (0 o 1)
appl_days, -- → fecha de creación de cuenta
modi_days, -- → fecha de última modificación
out__days, -- → fecha del último cierre de sesión
true_days -- → fecha de validez/suscripción
)
VALUES (
@nombreCuenta,
UPPER(CONVERT(VARCHAR(32), HASHBYTES('MD5', @contrasena), 2)),
@nombreMostrado,
'0000000000',
0,
@email,
0,
GETDATE(),
GETDATE(),
GETDATE(),
'2099-12-31'
);
MEMB_INFO en SSMS antes de escribir cualquier código de registro. Algunos núcleos usan un hash XOR personalizado o SHA1 en lugar de MD5 simple.Construyendo Páginas de Rankings y Estadísticas de Personajes
Los rankings son una de las páginas más visitadas en cualquier panel web de MU Online. El enfoque recomendado es pre-computar los datos de ranking en una tabla dedicada, en lugar de ejecutar joins pesados en cada carga de página.
Crea una tabla de resumen:
CREATE TABLE dbo.WebRankingCache (
PosicionRanking INT NOT NULL,
NombreChar VARCHAR(10) NOT NULL,
ClaseChar SMALLINT NOT NULL,
NivelChar SMALLINT NOT NULL,
CantResets INT NOT NULL DEFAULT 0,
NombreGuild VARCHAR(8) NULL,
UltimaActual DATETIME NOT NULL DEFAULT GETDATE(),
CONSTRAINT PK_WebRankingCache PRIMARY KEY (PosicionRanking)
);
-- Procedimiento almacenado para refrescar los rankings
-- Programar con SQL Server Agent cada 5 minutos
CREATE PROCEDURE dbo.sp_RefrescarWebRankings
AS
BEGIN
TRUNCATE TABLE dbo.WebRankingCache;
INSERT INTO dbo.WebRankingCache (PosicionRanking, NombreChar, ClaseChar, NivelChar, CantResets, NombreGuild)
SELECT
ROW_NUMBER() OVER (ORDER BY C.cLevel DESC, C.LevelUpPoint DESC) AS PosicionRanking,
C.Name AS NombreChar,
C.Class AS ClaseChar,
C.cLevel AS NivelChar,
ISNULL(CR.ResetCount, 0) AS CantResets,
G.G_Name AS NombreGuild
FROM dbo.Character C
LEFT JOIN dbo.CharacterResets CR ON CR.Name = C.Name -- → ajustar tabla/columna a tu núcleo
LEFT JOIN dbo.GuildMember GM ON GM.Name = C.Name
LEFT JOIN dbo.Guild G ON G.G_Name = GM.G_Name
WHERE C.CtlCode = 0 -- → excluir personajes GM del ranking público
ORDER BY PosicionRanking;
END;
Lista de Verificación de Seguridad
Antes de que tu panel web sea accesible desde internet, verifica lo siguiente:
- El puerto 1433 de SQL Server está bloqueado en el firewall para todas las IPs externas.
- El usuario de la base de datos web no tiene permisos DDL (sin CREATE, DROP, ALTER).
- Todas las entradas del usuario están parametrizadas — nunca concatenadas en cadenas SQL.
- HTTPS está forzado; las solicitudes HTTP redirigen a HTTPS.
- Los tokens de sesión se regeneran después del inicio de sesión y se invalidan al cerrar sesión.
- Las páginas de administración están protegidas por lista blanca de IP o autenticación de dos factores a nivel de aplicación.
- Los mensajes de error mostrados a los usuarios no revelan estructura de la base de datos, nombres de tablas ni trazas de pila.
Mantener el servidor de juego y el servidor web en una LAN privada, con solo el puerto 443 del servidor web expuesto a internet, es la medida individual más efectiva que puedes tomar para proteger tu infraestructura.
Perguntas frequentes
¿El sitio web y el servidor de juego pueden correr en la misma máquina?
Sí. Ejecutar ambos en la misma máquina es el punto de partida más sencillo. Apuntas tu servidor web (Apache o Nginx) a localhost y te conectas a la misma instancia de SQL Server que usa el juego. Para entornos de producción con muchos jugadores, separar el servidor web del servidor de juego reduce la competencia por recursos y mejora la estabilidad.
¿Qué permisos de base de datos necesita el sitio web?
La aplicación web debe usar un login de SQL Server dedicado con solo permisos SELECT, INSERT, UPDATE y DELETE sobre las bases de datos específicas de MU (MuOnline, MEMB_INFO, etc.). Nunca uses la cuenta sa ni ninguna cuenta con derechos de sysadmin para la cadena de conexión del panel web.
¿Cómo mantengo seguro el registro de cuentas?
Usa HTTPS en tu panel web, hashea las contraseñas con un método compatible con el que tu núcleo de servidor utiliza (normalmente MD5 o un hash personalizado), aplica límite de velocidad en el endpoint de registro y valida todas las entradas del lado del servidor para prevenir inyección SQL. Se recomienda encarecidamente CAPTCHA en el formulario de registro.
¿Por qué los rankings de mi sitio no se actualizan en tiempo real?
Los servidores de MU Online actualizan las estadísticas de personajes en intervalos de guardado (normalmente cada pocos minutos o al cerrar sesión). Tu sitio web lee directamente de la base de datos, por lo que los rankings siempre reflejarán el último estado guardado. Puedes programar un trabajo del Agente SQL o un script ejecutado por cron para pre-computar tablas de ranking a intervalos regulares, reduciendo la carga de consultas y mejorando la velocidad de las páginas.