AXINServerBridge
Dashboard admin móvil para servidores Vintage Story — consulta y actúa desde cualquier navegador, sin abrir el juego.
AXINServerBridge (también llamado AXIN Mobile Server Bridge) permite abrir una app web desde el juego y consultar o administrar el servidor desde el móvil. El camino normal es usar el enlace que genera /ams appweb.
Pertenece a la familia de mods AXIN y se integra con AxinMenuGui cuando ambos están instalados (p.ej. para la pestaña Tienda).
La app web necesita una dirección segura. El relay de AXIN (https://bridgerelay.axin.es) hace de puerta segura entre la web y tu servidor. Normalmente no tienes que escribir la API key en la app.
📋 Requisitos
| Requisito | Valor |
|---|---|
| VintageStory | 1.21.x+ |
| Tipo de mod | Solo servidor (mod C# server-side) |
| Cliente móvil/web | Cualquier navegador moderno (PWA) |
| Dependencias duras | Ninguna |
| Integraciones opcionales | AxinMenuGui (pestaña Tienda) |
Para uso normal, configura el relay y usa /ams appweb. La conexión directa al puerto del bridge queda como modo avanzado para pruebas o redes controladas.
Instalación
Ruta recomendada para admins: instalar, rellenar lo mínimo, reiniciar y usar /ams appweb.
1. Descargar e instalar el mod
- Descarga la última versión del mod compatible con tu Vintage Story desde la página oficial de mods (ModDB de VS).
- Copia el ZIP descargado, sin descomprimir, en la carpeta
Mods/de tu servidor. - Arranca el servidor una vez. En ese primer arranque se crea el archivo
ModConfig/axinbridge/config.jsonque vas a editar en el siguiente paso.
El mod ya viene compilado dentro del ZIP. Solo el equipo de desarrollo compila desde el código fuente; un admin de servidor normal no tiene que hacerlo.
2. Crear una clave privada
La clave privada protege el bridge. No la escribas en la app web cuando uses relay; el relay la usará por detrás.
# Windows
scripts\gen-apikey.cmd
# Linux / macOS
openssl rand -hex 32
3. Rellenar la configuración mínima
Edita ModConfig/axinbridge/config.json. Para el camino recomendado con relay, rellena estos campos:
axinbridge/config.json{
"Port": 42421,
"ListenAddress": "+",
"ApiKey": "TU_API_KEY_GENERADA",
"RelayEnabled": true,
"RelayUrl": "https://bridgerelay.axin.es",
"RelaySlug": "mi-servidor",
"PublicBridgeUrl": "http://TU_IP_PUBLICA:42421",
"RateLimitPerMinute": 30
}
| Campo | Qué poner | Para qué sirve |
|---|---|---|
Port | El puerto que escucha el mod. Por defecto 42421. Si tu hosting ya lo tiene ocupado, elige otro y abre ese mismo en el firewall. | La puerta del bridge dentro del servidor. |
ApiKey | La clave larga generada en el paso anterior. | Evita que alguien sin permiso llame al bridge. |
RelaySlug | Un nombre corto sin espacios, por ejemplo mi-servidor. | Aparece en la URL pública de la app. |
PublicBridgeUrl | La dirección pública de tu servidor con http:// delante y el mismo puerto que pusiste en Port. Ejemplo: http://176.57.153.46:42421. | La dirección por la que el relay llama a tu servidor desde fuera. |
http:// delante es obligatorio
El campo PublicBridgeUrl tiene que ser una URL completa.
- ✅ Correcto:
http://176.57.153.46:42421 - ❌ Incorrecto:
176.57.153.46:42421(le faltahttp://) - ❌ Incorrecto:
https://176.57.153.46:42421(el bridge habla HTTP, no HTTPS — del HTTPS se encarga el relay)
Son dos puertos distintos y normalmente abiertos en el firewall por separado:
- Puerto del juego de Vintage Story: el que usan los jugadores para conectarse al servidor (por ejemplo
42420). - Puerto del bridge (
Porten este config): el que usa la app web. Por defecto42421.
Si tu hosting solo deja abierto el puerto del juego, tendrás que pedir o configurar otro puerto distinto para el bridge.
Si ves en el JSON otros campos relacionados con el relay o una URL final del dashboard, no los rellenes a mano: los escribe el mod automáticamente cuando arranca y se registra.
Reinicia el servidor. En los logs debe aparecer una línea del tipo:
[AxinBridge] Listening on http://+:42421/
Con RelayEnabled=true, el mod intentará registrarse solo en el relay. Puedes comprobar el estado con /ams relay status.
4. Abrir la app
- Asegúrate de que el puerto configurado está abierto en tu hosting/firewall.
- Entra al juego como jugador.
- Ejecuta
/ams appweb. - Abre el enlace que aparece en el chat.
- La app debería aparecer con el servidor y el código de vinculación preparados. Si falta la URL, la guía de conexión te dirá qué campo falta.
Página de conexión del dashboard:
Configuración
Qué campos debe tocar un admin y qué campos escribe el mod automáticamente.
🔧 Bloque recomendado
axinbridge/config.json{
"Port": 42421,
"ListenAddress": "+",
"ApiKey": "TU_API_KEY_GENERADA",
"RelayEnabled": true,
"RelayUrl": "https://bridgerelay.axin.es",
"RelaySlug": "mi-servidor",
"PublicBridgeUrl": "http://TU_IP_PUBLICA:42421",
"RateLimitPerMinute": 30
}
El puerto por defecto del mod es 42421. Si tu hosting permite abrirlo, deja ese valor — los ejemplos de la wiki lo usan. Si está ocupado o tu hosting te obliga a otro, elige uno y úsalo igual en Port, en PublicBridgeUrl y en el firewall.
📋 Campos para admins
| Campo | Obligatorio | Explicación humana |
|---|---|---|
Port | Sí | Puerto del bridge dentro del servidor. Por defecto 42421. No es el puerto del juego — son dos cosas distintas. |
ListenAddress | Sí para uso externo | Usa "+" si el bridge debe aceptar conexiones desde fuera del servidor. |
ApiKey | Sí | Clave privada larga. No se comparte con jugadores ni se escribe en la app cuando usas relay. |
RelayEnabled | Sí en modo recomendado | Activa la puerta segura de AXIN para que la app web pueda conectar. |
RelayUrl | Sí en modo recomendado | Debe ser https://bridgerelay.axin.es para el relay público actual. |
RelaySlug | Recomendado | Nombre corto que aparecerá en la URL pública. Ejemplo: mi-servidor. |
PublicBridgeUrl | Sí para relay | Dirección pública del servidor escrita como URL completa: http:// + tu IP + : + el mismo puerto que pusiste en Port. Ejemplo: http://176.57.153.46:42421. |
RateLimitPerMinute | No | Límite básico de peticiones por minuto. El valor por defecto suele servir. |
AccountsAllowPassword | No | Permite que jugadores vinculados creen contraseña para volver a entrar sin pedir otro código. |
SessionMaxInactiveDays | No | Días que una sesión puede estar sin usarse antes de caducar. |
🤖 Campos que escribe el mod
Estos campos pueden aparecer en el JSON, pero no son tareas normales del admin:
ServerApiUrl: URL final que debe usar la app. El mod la calcula cuando puede.RelayServerIdyRelayOwnerToken: identidad interna del servidor en el relay.RelayAssignedSlug: nombre confirmado por el relay. Puede coincidir conRelaySlugo cambiar si el solicitado no está disponible.
El puerto debe coincidir en tres sitios: Port, PublicBridgeUrl y el firewall del hosting. Si uno no coincide, el relay no podrá llegar al servidor.
♻ Recarga en caliente
Usa /ams reload ingame. La config se relee de disco y se aplica sobre la instancia viva sin romper sesiones activas.
El reload sirve para muchos campos, pero puerto, dirección de escucha y cambios de red deben comprobarse con reinicio si no ves efecto claro.
Comandos /ams
Comandos ingame del AXINServerBridge. Para la mayoría de jugadores, el importante es /ams appweb.
📐 Sintaxis general
El comando raíz es /ams. Algunos subcomandos son para jugadores y otros requieren permisos de administrador.
🔧 Subcomandos
| Comando | Descripción |
|---|---|
/ams appweb | Genera un enlace clicable a la app web con el código de vinculación preparado. Es el flujo recomendado. |
/ams link | Genera solo un código de vinculación. Útil si quieres abrir la app manualmente. |
/ams register | Permite crear o cambiar contraseña web para volver a entrar sin pedir otro código. |
/ams wiki | Muestra el enlace a esta documentación. |
/ams reload | Recarga axinbridge/config.json en caliente sobre la instancia viva. |
/ams relay status | Muestra el estado del relay, slug asignado, URL efectiva del bridge y URL pública para el dashboard. |
/ams relay register | Lanza un registro manual inmediato en el relay si RelayEnabled=true. |
/ams relay reset | Limpia el estado local del relay y fuerza un registro nuevo. |
/ams web info <action> [args…] | Gestiona la sección Info del dashboard (listar/añadir/borrar). |
/ams web evento <action> [args…] | Gestiona eventos anunciados en la UI del dashboard. |
Los comandos /ams web ... son para admins que quieren editar textos visibles en el dashboard. Si solo quieres conectar la app, no los necesitas.
🚫 Si algo falla
Usa /ams status y /ams relay status. Si el problema está en la URL pública, normalmente será uno de estos tres puntos: puerto cerrado, PublicBridgeUrl con puerto incorrecto o relay todavía sin registro.
Conexión y login
Distingue dos cosas: conectar la app al servidor y vincular tu jugador dentro de la app.
🌐 Camino recomendado: /ams appweb
- Entra al servidor de Vintage Story.
- Ejecuta
/ams appweb. - Abre el enlace del chat.
- La app recibe el código de vinculación y, si el mod ya conoce la URL pública, también recibe la URL del servidor.
La app necesita una URL pública para hablar con tu servidor. Con relay, esa URL tiene forma https://bridgerelay.axin.es/s/<nombre>/api. Si el relay aún no ha terminado de registrar el servidor, el enlace puede incluir solo el código y la app pedirá completar la URL.
🔑 Modo directo (solo despliegues controlados)
Si conectas la web directamente al bridge, usa http://host:puerto y proporciona la API key. Ese modo sigue existiendo, pero no es la vía pública normal cuando el relay está activo.
🎟 Vinculación de sesión
- En el juego, ejecuta
/ams link. Recibes un código corto. - En el dashboard, introduce el código en el formulario de vinculación.
- La sesión queda guardada para no tener que repetir el proceso cada vez que se reinicia el servidor.
🔒 Login por contraseña (opcional)
Si el admin deja activadas las contraseñas, un jugador vinculado puede crear una contraseña para volver a entrar sin pedir otro código en el juego.
- La contraseña no sustituye al primer vínculo ingame.
- Si olvidas la contraseña, vuelve a vincular desde el juego.
- Los detalles técnicos de hash y rate-limit quedan en la documentación técnica.
La UI debe validar la sesión con /auth/me al arrancar y antes de acciones sensibles. Si el backend responde invalid_session, limpia localStorage. En modo relay, tampoco reintroduzcas la API key directa del bridge como si fuese el acceso público normal.
Pestaña Chat
Lee el chat del servidor en tiempo casi-real y envía mensajes bajo tu identidad vinculada.
📖 Lectura
El dashboard hace polling al endpoint de chat. El backend sirve una ventana deslizante de mensajes recientes, filtrando ruido interno.
✍ Envío
Si la sesión está vinculada, los mensajes salen como el jugador real (p.ej. elYandrack). Sin vinculación válida, la identidad degrada a externa (Externo-AxinMovil) y las acciones admin quedan denegadas.
El badge de usuario (jugador vs externo, rol, permisos) debe venir de /auth/me, no de localStorage. Evita mostrar acciones admin a un token ya caducado.
Pestaña Admin
Acciones operativas seguras para administradores vinculados.
👢 Kick con motivo
Al hacer kick desde el dashboard:
- El bridge envía un
SendMessageal jugador con el motivo normalizado. - Tras un breve retardo por callback, se ejecuta
player.Disconnect(reason). - Así el jugador ve el motivo personalizado antes de ser desconectado.
Disconnect(reason)En RUN real, el motor no siempre renderiza ese motivo al cliente. Enviar primero un mensaje explícito y luego desconectar es el patrón estable.
📣 Mensajería operativa
Broadcast corto a todos los jugadores conectados desde la UI del dashboard. Útil para avisos de reinicio, mantenimiento y eventos.
📊 Métricas
Estado básico del servidor: uptime, jugadores conectados, version, mods cargados. Estas métricas no requieren admin para leer, solo API key y sesión válida (configurable).
Pestaña Tienda
Interfaz web del Mercado Global de AxinMenuGui: ver ofertas activas, comprar y consultar tus ventas.
🔗 Contrato
La tienda web no toca market.json directamente. Depende del mod axinmenugui, resuelve AxinMenuGuiMod con api.ModLoader.GetModSystem<T>() y opera contra MarketStore / BankService vivos en el hilo principal.
market.json a espaldas del MarketStoreEl MarketStore mantiene el mercado en memoria y solo flushea cuando está dirty. Una escritura externa al JSON quedaría invisible y una operación ingame posterior podría pisarla.
💰 Precio: unidad vs lote
pricePerUnit | Coste total | Compras parciales |
|---|---|---|
true | price × quantity | Permitidas |
false | price (sin multiplicar) | No — lote completo |
El texto del precio en el listado siempre formatea price[] con multiplicador 1. La multiplicación por cantidad solo se aplica al calcular el coste total en checkout.
🧯 Errores de dominio
Los fallos del servicio salen como errores específicos con log de alta señal:
market_query_failed— fallo al enumerar ofertas.market_main_thread_timeout— la consulta no volvió al hilo principal a tiempo.
Nunca se degradan a internal_error HTTP genérico.
Sesiones y autenticación
Dos capas separadas: persistir tokens (siempre) y permitir contraseña (opt-in).
📚 Modelo
- Tokens persistidos (
AuthStore.sessions.json): sobreviven a reinicios del servidor. TTL de inactividad =SessionMaxInactiveDays(default 30 días). - Password opt-in: habilitado por
AccountsAllowPassword. Permite re-auth sin volver al juego.
Persistir el token es barato y cubre la UX de "no me desloguees al reiniciar". Añadir contraseña es otra capa, opt-in por admin.
🔁 Rehidratación
Al arrancar el bridge, SessionManager.Rehydrate() carga sessions.json, descarta sesiones vencidas y repuebla el diccionario en memoria.
🔒 Password
- Hash: PBKDF2-SHA256, 100.000 iteraciones, salt 16B aleatorio.
- Comparación en tiempo constante (
FixedTimeEquals). - Rate-limit por IP: 3 fallos = 30 s, 5 = 5 min.
Exposición segura
Cómo publicar el bridge sin obligar a la app web a conectar directamente por HTTP.
AXIN dispone de dominio axin.es y VPS en IONOS. El dominio principal se reserva para una futura web general del ecosistema; el relay usa subdominio propio: bridgerelay.axin.es.
🧭 Explicación sin jerga
La app web está en HTTPS. Muchos servidores de Vintage Story solo pueden exponer el mod por HTTP. El relay es una puerta intermedia segura: la app habla con el relay por HTTPS y el relay habla con tu servidor por la dirección que pusiste en PublicBridgeUrl.
| Nombre en la guía | Qué significa | Quién lo usa |
|---|---|---|
| URL de la app | La web que abre el jugador/admin. | El usuario. |
| URL pública del dashboard | https://bridgerelay.axin.es/s/<nombre>/api. | La app web. |
PublicBridgeUrl | Dirección de tu servidor para que el relay pueda llegar al mod. | El relay. |
ServerApiUrl | URL final que el mod calcula para la app. | El mod y /ams appweb. |
🚫 Qué no hacer
- Decir a los usuarios que usen directamente
http://ip:puertocomo ruta normal de la app pública. - Dejar
ApiKeyvacía o derivada de texto corto. - Compartir la API key en canales no cifrados.
- Confundir
PublicBridgeUrlcon la URL que debe escribir el usuario en la app.
✅ Qué hacer
- Usar como URL normal de la app
https://bridgerelay.axin.es/s/<slug>/api. - Mantener el puerto del bridge bajo control: por defecto es
42421; si tu hosting tiene reglas estrictas o quieres una capa extra de privacidad, puedes elegir otro puerto TCP alto, siempre coordinándolo conPort,PublicBridgeUrly el firewall. - Abrir en el hosting/firewall el puerto real del bridge y hacer que
PublicBridgeUrluse exactamente ese mismo puerto. - Si el hosting/firewall lo permite, restringir el acceso al puerto del bridge solo a la IP del relay (
212.227.153.142). - Reservar la conexión directa al bridge (sin relay) para despliegues controlados o pruebas concretas.
Si el registro ya está hecho, /ams relay status te mostrará la URL para el dashboard. Si el relay no alcanza al bridge, revisa tres cosas: que el puerto está abierto, que PublicBridgeUrl usa ese mismo puerto y que el servidor responde desde fuera.
Integración con el Mercado
El AXINServerBridge se apoya en AxinMenuGui para operar el mercado P2P desde la web.
📐 Principio
El bridge no es dueño del mercado. Actúa como cliente del MarketStore vivo: lee ofertas, prepara transacciones y delega la mutación a la misma API que usa el GUI ingame.
🧵 Hilo principal
Toda operación sobre el MarketStore se ejecuta en el main thread del servidor (api.Event.EnqueueMainThreadTask / equivalente). Si el salto de hilo se demora demasiado, el bridge devuelve market_main_thread_timeout.
💳 Fuentes de pago
Cuando el comprador no tiene saldo suficiente en el inventario, el sistema encadena fuentes — cada una cubre solo lo que puede:
fromInventory = Min(remaining, inventory.CountItem(...))
fromTreasury = Min(remaining, treasury.CountItem(...))
fromBank = Min(remaining, bank.CountItem(...))
remaining enteroSi pasas el total a una fuente que no tiene suficiente, TakeItem puede devolver false sin tomar nada y la siguiente fuente nunca se consulta.
Enlaces y capturas
Atajos al propio dashboard (configurados en tu instalación) y capturas de referencia.
🔗 Atajos del dashboard
En wiki/Imagenes/AXINMobileServerBridgeImages/ se incluyen accesos directos .url a las vistas reales del dashboard desplegado. Apuntan al servidor concreto — ábrelos desde el explorador, no desde la web:
| Archivo | Vista |
|---|---|
pagina princial.url | Landing del dashboard. |
chat.url | Pestaña de chat remoto. |
admin.url | Pestaña admin (kick, broadcast, métricas). |
Tienda online.url | Pestaña Tienda (mercado integrado con AxinMenuGui). |
tienda in game.url | Enlace a la vista ingame equivalente. |
🖼 Capturas
Pantalla de conexión — introducir la URL del relay, dejar la API key vacía si usas relay y vincular la sesión.
Coloca nuevas imágenes en wiki/Imagenes/AXINMobileServerBridgeImages/ y referencíalas aquí con <img class="shot" src="..."> + <p class="shot-caption">. No se requieren cambios de CSS.
Roadmap
Hitos previstos. Orden aproximado, sujeto a prioridades operativas.
axin.es queda reservado para una web principal del ecosistema AXIN. Los servicios concretos deben vivir en subdominios, por ejemplo bridgerelay.axin.es.