Infraestructura · Sistemas Distribuidos
Clúster proxy multi-nodo
con autenticación híbrida
01 · Visión general
El objetivo era montar una infraestructura de red de juego con comportamiento de proxy de capa de aplicación: un nodo de entrada por región que enruta tráfico hacia múltiples backends segregados por función, con control centralizado de sesiones, autenticación propia y capa de datos compartida entre regiones.
La red operó en dos regiones simultáneas — Europa y Latinoamérica — cada una con su propio proxy Waterfall y conjunto de nodos backend independientes, pero compartiendo la misma base de datos PostgreSQL y el mismo estado de permisos LuckPerms. Un jugador podía cambiar de región manteniendo su rango, inventario y sesión intactos.
02 · Topología de nodos
Cada región corre en su propio hardware gestionado desde Pterodactyl sobre Proxmox, con contenedores Docker aislados por nodo. La capa de datos (PostgreSQL y Redis) es compartida entre regiones, actuando como fuente de verdad única para cuentas, permisos y tienda.
REGIÓN EU · Europa
REGIÓN LATAM · Latinoamérica
03 · Pipeline de autenticación
El servidor corre en modo offline a nivel de Waterfall para poder interceptar la autenticación antes de delegarla. El plugin propio en Java implementa tres ramas:
- Cliente inicia sesión contra los servidores de Mojang (online mode local)
- El plugin consulta
sessionserver.mojang.com/session/minecraft/hasJoined - Respuesta positiva → UUID canónico extraído del perfil JSON
- Sesión creada en Redis con TTL de 30 min y UUID como clave primaria
- Cliente redirigido al hub sin pantalla de login
- Cliente detectado como offline (UUID v3 basado en nombre)
- Plugin bloquea al hub y fuerza pantalla de login
- Credenciales introducidas en chat cifrado (canal privado de plugin)
- Contraseña verificada contra hash BCrypt almacenado en base de datos
- Sesión creada en Redis; cliente desbloqueado hacia el hub
- Segundo factor activable por usuario desde panel de comandos
- Generación de secreto TOTP (Base32) vinculado a la cuenta
- Compatible con cualquier autenticador estándar (Google Authenticator, Aegis…)
- Código de 6 dígitos requerido tras la contraseña en cada sesión
- Ventana de validación de ±30 s con tolerancia de drift de un intervalo
04 · Gestión de sesiones
Redis actúa como capa de estado compartido entre el proxy y todos los nodos backend. Cada sesión autenticada escribe una clave con el UUID del jugador y metadatos: estado de auth, tipo de cuenta, timestamp, nodo actual.
Estructura de clave en Redis
session:<uuid> → Hash
├── authenticated : "true"
├── account_type : "premium" | "offline"
├── 2fa_verified : "true" | "false"
├── current_node : "lobby" | "skywars" | "minekoro" | "ffa" | "eventos"
├── login_ts : <unix timestamp>
└── ip : <ip de origen>
TTL: 1800s (renovado on activity)
Revocación: DEL session:<uuid> en disconnect Al cambiar de nodo, el backend destino consulta Redis antes de cargar al jugador, evitando que un cliente no autenticado pueda acceder directamente al puerto del nodo aunque lo conozca por otros medios.
05 · Permisos distribuidos
El sistema de permisos se gestiona con LuckPerms configurado en modo de almacenamiento PostgreSQL, lo que permite que todos los nodos compartan el mismo estado de permisos en tiempo real sin necesidad de sincronización manual.
Cada nodo arranca con LuckPerms apuntando a la misma base de datos central. Un cambio de rango aplicado desde cualquier nodo, o desde la consola del proxy, se refleja de forma inmediata en el resto del clúster.
Jerarquía de grupos (extracto)
default → permisos base (todos los jugadores)
vip → acceso a comandos cosméticos, prioridad de cola
vip+ → slots reservados, kits adicionales
staff → moderación, /kick, /mute, /ban (con log)
admin → acceso total + gestión de nodos Los rangos de la tienda (VIP, VIP+) se asignan automáticamente vía la integración con el sistema de compras, sin intervención manual del equipo de administración.
06 · Tienda con entrega automática
La tienda externa se integra directamente con el clúster mediante un sistema de entrega automática en juego: el jugador completa la compra en la web y recibe los ítems o el rango sin intervención del equipo.
- Jugador realiza la compra en la tienda web (Tebex / panel propio)
- Tienda dispara un webhook HTTP hacia el listener del proxy
- Listener valida la firma del webhook y extrae UUID + producto comprado
- Si el jugador está conectado: entrega inmediata vía comando en el nodo actual
- Si está desconectado: entrega encolada en PostgreSQL, se ejecuta al siguiente login
Los productos se mapean a acciones configurables: ejecución de comandos con privilegios, asignación de grupos en LuckPerms, entrega de ítems en inventario o modificación de metadatos en la base de datos del jugador. La cola de entregas pendientes garantiza que ninguna compra se pierde ante desconexiones.
Tabla de entregas pendientes (PostgreSQL)
pending_deliveries
├── id SERIAL PRIMARY KEY
├── player_uuid UUID NOT NULL
├── product_id VARCHAR(64) NOT NULL
├── commands JSONB -- lista de comandos a ejecutar
├── purchased_at TIMESTAMPTZ
└── delivered_at TIMESTAMPTZ -- NULL hasta ejecución 07 · Gestión operativa
Toda la infraestructura de procesos corre sobre Pterodactyl Panel, desplegado en una VM dedicada en Proxmox. Pterodactyl gestiona:
- Arranque, parada y reinicio de cada nodo de forma independiente
- Límites de recursos por contenedor (CPU, RAM, swap, disco)
- Acceso a consola en tiempo real con logs por nodo
- Gestión de backups programados del mundo y la base de datos
- Control de usuarios con permisos granulares por servidor
El acceso al panel está restringido por IP y protegido con Caddy como reverse proxy HTTPS, con certificado emitido por Let's Encrypt.