Monta una red de Minecraft con Workers
Una red de juego tiene una puerta y muchas salas. Los jugadores se conectan a una sola dirección pública; detrás, un proxy (Velocity o BungeeCord) envía a cada jugador a un lobby, un minijuego o un servidor survival. En Zaroz son dos tipos de Worker en un mismo proyecto:
Code
- El Worker proxy ejecuta una unidad y posee el único puerto público.
- Cada Worker backend ejecuta tantas unidades como necesites. No tiene dirección pública: el proxy llega a cada unidad por su nombre privado,
<clave>.<slug>. - El proxy encuentra los backends mediante la API de Units, así que subir o bajar un backend no exige editar ninguna configuración.
Un Worker es el producto para cualquier programa de larga duración que no sea una web. Puede tener puertos públicos TCP y UDP raw y puede ejecutar muchas unidades. Los endpoints HTTPS son para webs y un Worker no los ofrece. Los términos se explican en Units, Puertos públicos y Nombres privados.
Antes de empezar
Necesitas una organización con un proyecto, una imagen de proxy de Minecraft y una imagen de backend en un registro (la guía para desplegar un Workload explica cómo desplegar desde una imagen) y un token de API personal. Las llamadas de abajo usan el ayudante de la introducción a la API de Units: $ZAROZ_API, $AUTH, $PROJECT.
1. Crea los dos Workers en un proyecto
Crea ambos Workers en el mismo proyecto, porque los nombres privados solo funcionan dentro de un proyecto. Dale a cada uno un slug que empiece por una letra, ya que el slug pasa a ser el nombre (mira las reglas):
| Worker | slug | unidades | público |
|---|---|---|---|
| Proxy Velocity | proxy | 1 | TCP 25565 (y UDP 19132 para Bedrock) |
| Lobbies | lobby | 4 | ninguno |
Elige un plan cuya memoria quepa en la JVM: un proxy Velocity es ligero, un servidor Paper necesita su heap más margen. Zaroz define MEMORY_LIMIT_MIB en el entorno de cada unidad, y tu comando de arranque puede usarlo para dimensionar el heap.
Exporta los dos ids de servicio, que aparecen en la URL de la consola de cada Worker:
Code
2. Abre el único puerto público en el proxy
Abre un puerto TCP raw. internal_port es el puerto en el que escucha Velocity dentro del contenedor; Zaroz asigna la dirección y el número públicos y los devuelve.
curl
Code
TypeScript
Code
Python
Code
Los jugadores entran por public_ip:public_port. Cada puerto raw cuesta 1 EUR al mes, facturado por las horas que se mantiene (mira la factura). La petición se rechaza con not_ready hasta que la unidad del proxy esté en marcha, así que despliega primero y abre el puerto después.
Estado de la API
Las rutas de endpoints las usa la consola y son solo de consola en la referencia de la API: aceptan tu token de sesión o un token de API personal, y rechazan a un service principal. Haz este paso tú, o desde la consola, no desde el proxy.
Los backends no tienen ningún endpoint. Siguen siendo privados.
3. Escala el backend a N unidades
Una política fija ejecuta exactamente N unidades. Sus claves son u1 a uN, y sus nombres privados u1.lobby a uN.lobby:
curl
Code
TypeScript
Code
Python
Code
Si quieres nombres que elijas tú, como survival y skyblock, o una unidad por partida de minijuego, usa el modo code y crea las unidades por clave: una unidad creada con la clave skyblock es accesible como skyblock.lobby. El resto de esta guía funciona igual en ambos casos, porque el proxy lee los nombres de la API.
4. Apunta Velocity a los backends
La configuración más simple del proxy nombra los backends de forma estática. En velocity.toml:
Code
Cada backend debe escuchar en el 25565 dentro de su contenedor y confiar en el secreto de reenvío de Velocity (forwarding.secret en el proxy, [proxies.velocity] en la configuración global de Paper). Como los backends no tienen dirección pública, online-mode=false en ellos es seguro: solo tu propio proyecto puede conectarse.
El nombre lobby a secas también es válido y llega a todas las unidades listas, pero un proxy de Minecraft necesita una dirección por servidor para poder enviar a un jugador a uno concreto, así que lista los nombres con clave.
5. Descubre los backends dinámicamente
Una lista estática se rompe en cuanto escalas a cinco. En su lugar, dale al Worker proxy un service principal con units.read sobre el Worker lobby, y deja que un plugin o un script auxiliar en el proxy liste las unidades y registre un servidor de Velocity por cada unidad lista.
Crea el principal y la concesión
curl
Code
TypeScript
Code
Python
Code
units.read basta para descubrir backends. Usa units.control solo si el proxy también debe arrancar y parar servidores (por ejemplo, despertar una unidad de minijuego parada cuando un jugador entra en cola). Activar un principal cambia la plantilla del Worker, así que se aplica cuando la unidad del proxy se reinicia.
Cada unidad del proxy tiene ahora ZAROZ_API_URL y ZAROZ_PROJECT_ID en su entorno y un token en /zaroz/credentials/token. El token rota: lee el archivo en cada petición.
Lista las unidades
GET .../units devuelve de cada unidad su key, private_name, state, labels y accepting. Un backend es utilizable cuando tiene private_name y está en running:
curl
Code
TypeScript
Code
Python
Code
Filtra por etiqueta para separar tipos de servidor: dale a las unidades lobby {"kind":"lobby"} (mira las etiquetas) y lista con ?label=kind:lobby.
Reacciona a los cambios
Consulta la lista cada pocos segundos, o sigue el flujo de eventos con unit.ready, unit.draining, unit.stopped y unit.destroyed (con wait=30 la petición vuelve en cuanto ocurre algo), y vuelve a listar cuando llegue uno. El flujo encaja mejor que un webhook aquí, porque los webhooks se entregan a una URL pública y el proxy solo expone su puerto de juego. En cada cambio, compara la lista con los servidores registrados y llama a registerServer / unregisterServer de Velocity para la diferencia. unit.ready incluye el nombre privado de la unidad, así que ni siquiera necesitas una segunda lectura.
Librería auxiliar
zaroz-minecraft-helper, un plugin de Velocity y Paper que hace los pasos 4 y 5 por ti, llegará próximamente. Hasta que se publique, las llamadas de arriba son todo lo que hace.
Jugadores de Bedrock con Geyser
Geyser traduce a los jugadores de Bedrock a Java, así que usan los mismos backends. Ejecútalo como plugin en el proxy (Geyser-Velocity) y abre un segundo puerto en el Worker proxy:
Code
Es un puerto raw más, 1 EUR al mes. (tcp_udp es un endpoint que lleva ambos protocolos por un único número público, para cuando Java y Bedrock deban compartir número de puerto.)
El tráfico de Bedrock es UDP, y UDP no tiene conexión, así que el borde mantiene a cada jugador en el mismo backend por flujo: un flujo nuevo elige un backend a partir del último byte de la IPv4 del jugador, y un flujo ya iniciado se queda donde está hasta que termina, aunque cambie el conjunto de backends. Para un juego esto significa dos cosas: mantén el proxy en una unidad, que es lo que incluye el plan del Worker y lo que hace irrelevante la cuestión, y no esperes que un jugador UDP se mueva entre unidades a mitad de sesión. Entre el proxy y tus backends Java no hay UDP en absoluto, porque Geyser habla el protocolo Java por TCP con ellos.
Cuando los jugadores deben llegar a un servidor concreto
A veces un servidor necesita su propia dirección pública: un servidor creativo que comparte un streamer, un servidor de torneo cuya dirección repartes. Un nombre privado no puede, porque nunca es público. Abre en su lugar un endpoint por unidad (kind: unit) en el Worker backend:
Code
Cada unidad del Worker recibe entonces su propia dirección y puerto públicos para ese puerto del contenedor, que llegan solo a esa unidad, y una unidad nueva recibe los suyos al añadirse. El campo public_endpoints de cada unidad (public_ip, public_port, protocol, internal_port) te dice la dirección, y se mantiene igual entre reinicios de la unidad. Se factura como un puerto por unidad, así que cuatro unidades son cuatro puertos; cerrar el endpoint quita el puerto de todas las unidades. Úsalo para los pocos servidores que lo necesiten, no para todos los backends: el proxy más los nombres privados es más barato y mantiene los backends fuera de internet.
La factura
Cada cifra de abajo sale de las reglas de Lo que cuestan las unidades y de las reglas de endpoints. Los precios de plan son provisionales (el precio del Worker aún se está fijando; es el mismo plan de ejemplo de 7,20 EUR al mes de la página de facturación, con una unidad incluida); lee el precio real de tu plan en su página o en el endpoint de cotización. La estructura de la factura no cambia cuando cambia el precio.
Las reglas:
- El precio del plan de un Worker cubre su unidad incluida (una) y se paga por adelantado.
- Cada unidad por encima de las incluidas es una unidad extra, facturada por las horas que realmente funciona al precio mensual del plan / 720, sin recargo, y con un mínimo de 5 minutos por arranque.
- Cada puerto público raw cuesta 1 EUR al mes, facturado por las horas que se mantiene (1 EUR / 720 por hora), sin puertos gratis en un Worker.
- Los nombres privados, la API de Units, los eventos y los service principals son gratis. Los backends sin puerto público no pagan puerto.
La red de arriba, durante un mes entero de 30 días (720 horas):
| línea | cálculo | EUR |
|---|---|---|
| plan del proxy (1 unidad incluida) | precio de plan provisional | 7,20 |
| puerto TCP 25565 del proxy | 1 puerto x 1,00 EUR | 1,00 |
| plan de lobby (1 unidad incluida) | precio de plan provisional | 7,20 |
| 3 unidades lobby extra | 3 x 720 h x (7,20 / 720) | 21,60 |
| total | 37,00 |
Añade Bedrock y el total es 38,00 EUR (un puerto más). Haz público un servidor creativo con un endpoint por unidad en un Worker lobby de cuatro unidades y son cuatro puertos más, 4,00 EUR. Si escalas el lobby entre 1 y 4 con una política que mantiene tres unidades extra durante 100 horas en el mes, las unidades extra cuestan 3 x 100 x 0,01 = 3,00 EUR ese mes en lugar de 21,60 EUR. Una unidad parada no cuesta nada, así que una unidad de minijuego parada entre rondas solo cuesta las horas que funcionó.
Comprueba la cifra real antes de comprometerte: POST .../units/policy/quote devuelve lo máximo que podría costar una política, sin guardarla.
Solución de problemas
| síntoma | causa |
|---|---|
private_name es null | el slug del Worker empieza por un dígito, renómbralo |
u2.lobby no se resuelve | esa unidad aún no está lista, o el proxy está en otro proyecto |
| Velocity dice "connection refused" | el backend no escucha en el puerto que escribiste, o solo escucha en 127.0.0.1; enlaza 0.0.0.0 |
abrir el puerto responde not_ready | la unidad del proxy aún no está en marcha |
ports_not_offered | el producto elegido no ofrece puertos públicos; elige un Worker |
| la lista de unidades se rechaza | el principal no tiene la concesión units.read sobre ese Worker (mira Service principals) |
| falta el archivo del token | el principal se acaba de activar; se aplica cuando la unidad del proxy se reinicia |
