mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-01 10:22:08 +00:00
397 lines
36 KiB
JSON
397 lines
36 KiB
JSON
{
|
|
"meta": {
|
|
"title": "Autenticación del panel de Proxmox — 2FA, tokens API, perfil de usuario, proxy inverso | ProxMenux Monitor",
|
|
"description": "Acceder y asegurar ProxMenux Monitor: flujo de proteger-tu-panel en el primer arranque, autenticación con contraseña con nombre visible + avatar, página de perfil, alta de TOTP 2FA, API tokens de larga duración para scripts, configuración HTTPS, snippets de reverse proxy para Nginx, Caddy y Traefik, el log de auditoría y el jail Fail2Ban opcional.",
|
|
"ogTitle": "Autenticación del panel de Proxmox — 2FA, tokens API, proxy inverso",
|
|
"ogDescription": "Asegura ProxMenux Monitor con contraseña + TOTP 2FA, API tokens de larga duración, HTTPS, snippets de reverse proxy y un jail Fail2Ban opcional.",
|
|
"twitterTitle": "Autenticación del panel de Proxmox | ProxMenux Monitor",
|
|
"twitterDescription": "Contraseña + TOTP 2FA, API tokens, HTTPS, snippets de Nginx/Caddy/Traefik y log de auditoría."
|
|
},
|
|
"header": {
|
|
"title": "Acceso y autenticación",
|
|
"description": "Cómo llegar al panel, el flujo de seguridad de primer arranque y cada capa que puede situarse entre un atacante y el host: contraseña + TOTP, sesiones JWT, API tokens de larga duración, HTTPS, reverse proxies, Secure Gateway y el jail Fail2Ban opcional.",
|
|
"section": "Monitor de ProxMenux"
|
|
},
|
|
"intro": {
|
|
"title": "La autenticación es opt-in",
|
|
"body": "Al abrir el panel por primera vez aparece un diálogo: <em>«¿Proteger el panel?»</em>, con los botones <strong>Sí, configurar contraseña</strong> y <strong>No, continuar sin protección</strong>. Al elegir que no, los endpoints de la API quedan abiertos en TCP 8008: puede servir en una LAN de laboratorio aislada, pero resulta peligroso en otros entornos. La autenticación de dos factores (2FA) <strong>no</strong> forma parte de esta primera elección; se configura después desde <strong>la pestaña Seguridad</strong>, una vez establecida la contraseña."
|
|
},
|
|
"reaching": {
|
|
"heading": "Cómo llegar al panel",
|
|
"intro": "ProxMenux Monitor escucha en <code>0.0.0.0:8008</code>. Hay tres formas habituales de llegar a él:",
|
|
"outro": "El acceso directo corresponde a la unidad systemd predeterminada. El proxy inverso y Secure Gateway se describen más abajo. Para confiar en la IP de <code>X-Forwarded-For</code> se requiere PROXMENUX_TRUST_PROXY=1 y un proxy que controles. La presencia de <code>X-Forwarded-Proto</code> o <code>X-Forwarded-Host</code> no activa esa confianza. En los puertos 80/443 el frontend usa URL relativas <code>/api/*</code>; en cualquier otro puerto llama al puerto 8008 del mismo nombre de host."
|
|
},
|
|
"firstLaunch": {
|
|
"heading": "Flujo de primer arranque",
|
|
"intro": "La primera vez que abres el panel, el frontend llama a <code>GET /api/auth/status</code>. Si la configuración de auth nunca se ha escrito (<code>configured: false</code>), aparece un único diálogo titulado <em>\"¿Proteger tu panel?\"</em> con dos opciones:",
|
|
"imageAlt": "Diálogo de primer arranque '¿Proteger tu panel?' con dos botones: Sí configurar contraseña, No continuar sin protección",
|
|
"imageCaption": "El selector de autenticación del primer arranque. Dos botones — protección con contraseña o saltar. Se vuelve a mostrar tras una instalación recién hecha o tras \"Desactivar autenticación\" desde Settings.",
|
|
"headerButton": "Botón",
|
|
"headerWhat": "Qué pasa",
|
|
"headerApi": "Llamada a la API",
|
|
"rows": [
|
|
{
|
|
"button": "Sí, configurar contraseña",
|
|
"what": "Abre un formulario con nombre de usuario y contraseña obligatorios, más <em>nombre visible</em> e <em>imagen de avatar</em> opcionales. Activa la autenticación en <code>auth.json</code> con <code>enabled: true</code> y devuelve un JWT para iniciar sesión. Los campos opcionales del perfil se guardan mediante llamadas posteriores, como se explica abajo.",
|
|
"api": "POST /api/auth/setup"
|
|
},
|
|
{
|
|
"button": "No, continuar sin protección",
|
|
"what": "Marca <code>declined: true</code> en <code>auth.json</code>. Los endpoints de la API permanecen abiertos hasta que actives la protección desde Ajustes.",
|
|
"api": "POST /api/auth/skip"
|
|
}
|
|
],
|
|
"twofaCalloutTitle": "El 2FA se configura después, no aquí",
|
|
"twofaCalloutBody": "El diálogo inicial solo decide la protección con contraseña. La <strong>autenticación de dos factores (TOTP)</strong> se configura después desde <strong>la pestaña Seguridad</strong>, una vez iniciada la sesión con contraseña. El procedimiento completo de TOTP se explica más abajo.",
|
|
"createTitle": "Crear el primer usuario",
|
|
"createIntro": "Al pulsar <em>Sí, configurar contraseña</em>, un formulario crea la cuenta y permite completar el perfil para que el avatar aparezca en la cabecera al guardar. Los campos son:",
|
|
"headerField": "Campo",
|
|
"headerRequired": "Requerido",
|
|
"headerNotes": "Notas",
|
|
"fieldRows": [
|
|
{
|
|
"field": "Nombre de usuario",
|
|
"required": "Sí",
|
|
"notes": "Identificador de inicio de sesión. No se puede cambiar desde la interfaz; hay que editar <code>auth.json</code> directamente."
|
|
},
|
|
{
|
|
"field": "Contraseña",
|
|
"required": "Sí",
|
|
"notes": "Mínimo 10 caracteres, con al menos 3 de las 4 categorías (minúscula, mayúscula, dígito, símbolo). Una lista corta de contraseñas obvias (<code>password</code>, <code>12345678</code>, <code>proxmenux</code>…) se rechaza directamente. Las mismas reglas se aplican en el lado del servidor, así que una llamada curl no puede saltarse la comprobación del frontend."
|
|
},
|
|
{
|
|
"field": "Nombre visible",
|
|
"required": "No",
|
|
"notes": "Nombre que aparece en el menú de la cabecera y en el perfil. Si está vacío se usa el nombre de usuario. Puedes cambiarlo desde <strong>Avatar → Ver perfil</strong>."
|
|
},
|
|
{
|
|
"field": "Imagen de avatar",
|
|
"required": "No",
|
|
"notes": "PNG, JPEG, WebP o GIF de hasta 2 MB. Renderizado como un círculo en la cabecera y en la página de perfil. Cuando está vacío, la cabecera muestra la primera letra del nombre visible (o del username) sobre un círculo coloreado. Se puede subir, reemplazar o eliminar después desde la página de perfil."
|
|
}
|
|
],
|
|
"createImageAlt": "Formulario de creación de usuario con campos obligatorios Username + Contraseña y la sección opcional Nombre visible + subida de Avatar",
|
|
"createImageCaption": "Formulario inicial de creación de usuario. El nombre visible y el avatar son opcionales; si los dejas vacíos, la cuenta se crea y la cabecera muestra un círculo con una letra.",
|
|
"saveCalloutTitle": "Un único guardado, tres llamadas a la API por dentro",
|
|
"saveCalloutBody": "El formulario envía primero <code>POST /api/auth/setup</code> (username + contraseña). Si tiene éxito usa el JWT recién emitido para hacer a continuación <code>PUT /api/auth/profile</code> (nombre visible) y <code>POST /api/auth/profile/avatar</code> (bytes del avatar) si esos campos se rellenaron. Los fallos en las llamadas de perfil no son fatales — la cuenta ya está creada y puedes terminar el perfil después desde la página dedicada.",
|
|
"avatarTitle": "Menú del avatar y página de perfil",
|
|
"avatarBody1": "Tras configurar la autenticación, aparece el avatar arriba a la derecha, junto al selector de tema. Su menú contiene accesos al perfil, a Seguridad y la acción <strong>Cerrar sesión</strong>. También puedes cerrar la sesión desde Seguridad.",
|
|
"avatarBody2": "La página de perfil en sí es una pequeña tarjeta con una vista previa del avatar, el username (solo lectura) y el nombre visible con un botón de edición en línea. Las subidas, reemplazos y eliminaciones de avatar son atómicas — el avatar de la cabecera se refresca automáticamente cuando cualquiera tiene éxito, así que no hay necesidad de recargar la página. El mismo conjunto de endpoints documentado en la siguiente sección lo usan tanto el formulario de creación de usuario como la página de perfil.",
|
|
"profileImageAlt": "Página de perfil con círculo de vista previa del avatar, botones Subir / Reemplazar / Eliminar, username de solo lectura y campo de nombre visible editable",
|
|
"profileImageCaption": "La página de perfil dedicada. El username es solo lectura; el nombre visible y el avatar se pueden editar desde aquí sin tocar la pestaña Security.",
|
|
"headerEndpoint": "Endpoint",
|
|
"headerEpWhat": "Qué hace",
|
|
"endpointRows": [
|
|
{
|
|
"endpoint": "GET /api/auth/profile",
|
|
"what": "Devuelve el username actual, el nombre visible y si hay un avatar configurado (<code>has_avatar</code>, <code>avatar_mtime</code>)."
|
|
},
|
|
{
|
|
"endpoint": "PUT /api/auth/profile",
|
|
"what": "Actualiza el nombre visible. Cuerpo de la petición: <code>'{' \"display_name\": \"...\" '}'</code>."
|
|
},
|
|
{
|
|
"endpoint": "GET /api/auth/profile/avatar",
|
|
"what": "Devuelve los bytes del avatar (PNG / JPEG / WebP / GIF) con el content type adecuado. Requiere la cabecera Bearer — el frontend lo descarga como blob y lo convierte en una URL de objeto local para renderizar."
|
|
},
|
|
{
|
|
"endpoint": "POST /api/auth/profile/avatar",
|
|
"what": "Sube un avatar nuevo (máx 2 MB). El content type debe coincidir con el archivo. El avatar antiguo se reemplaza atómicamente."
|
|
},
|
|
{
|
|
"endpoint": "DELETE /api/auth/profile/avatar",
|
|
"what": "Elimina el avatar. La cabecera vuelve a mostrar una inicial en un círculo de color."
|
|
}
|
|
],
|
|
"reversibleTitle": "Puedes activar la protección más adelante",
|
|
"reversibleBody": "Tras pulsar <em>No, continuar sin protección</em>, el diálogo inicial no vuelve a aparecer. Puedes activar la autenticación desde <strong>la pestaña Seguridad</strong> o editar <code>/root/.config/proxmenux-monitor/auth.json</code>, quitar el indicador <code>declined</code> y reiniciar el servicio."
|
|
},
|
|
"password": {
|
|
"heading": "Autenticación con contraseña",
|
|
"intro": "Tras configurar la protección, las llamadas protegidas requieren un JWT en <code>Authorization: Bearer <token></code>:",
|
|
"items": [
|
|
"<strong>Token de sesión (login):</strong> expiración de 24 horas. Emitido por <code>POST /api/auth/login</code>.",
|
|
"<strong>API token (integraciones):</strong> expiración de 365 días. Emitido por <code>POST /api/auth/generate-api-token</code>. Documentado por separado en la siguiente sección."
|
|
],
|
|
"loginImageAlt": "Pantalla de login mostrada tras configurar la autenticación — campos de usuario y contraseña",
|
|
"loginImageCaption": "Una vez configurada la autenticación, cada visita al panel empieza aquí. Con 2FA activado, la pantalla pide el código de 6 dígitos en un segundo paso tras aceptar la contraseña.",
|
|
"loginFlowTitle": "Flujo de login",
|
|
"twofaIntro": "Con 2FA activado, la misma llamada devuelve primero <code>requires_totp: true</code>. Reemite con el código de 6 dígitos:",
|
|
"publicTitle": "Endpoints públicos (sin token)",
|
|
"publicIntro": "El inicio de sesión, su estado, la configuración inicial y el endpoint ligero <code>/api/system-info</code> son públicos:",
|
|
"publicItems": [
|
|
"<code>/api/auth/login</code> y <code>/api/auth/status</code> son públicos. <code>/api/auth/setup</code> crea la cuenta inicial y rechaza sobrescribir credenciales existentes.",
|
|
"<code>/api/system-info</code> es un endpoint público de información básica del sistema, incluido <code>health.status</code>. No lleva el requisito de token. /api/auth/status también es público y sirve para comprobar disponibilidad."
|
|
],
|
|
"cryptoTitle": "Criptografía y almacenamiento",
|
|
"cryptoIntro": "ProxMenux Monitor es código abierto — nada de esto es secreto. Documentar el stack aquí de forma explícita es una decisión deliberada: los usuarios que guardan credenciales en su host merecen saber cómo se protegen esas credenciales antes de decidir confiar en ellas. Los algoritmos de abajo son los mismos que usa el código en <code>scripts/auth_manager.py</code>; esta sección es un contrato, no una promesa de marketing.",
|
|
"headerAsset": "Elemento",
|
|
"headerAlgo": "Algoritmo",
|
|
"headerWhere": "Ubicación",
|
|
"cryptoRows": [
|
|
{
|
|
"asset": "Contraseña",
|
|
"algorithm": "PBKDF2-HMAC-SHA256 con un salt aleatorio por contraseña y un alto número de iteraciones (línea base OWASP 2023+). Guardada como <code>pbkdf2_sha256$<iters>$<salt>$<hash></code>.",
|
|
"where": "<code>auth.json</code> → <code>password_hash</code>"
|
|
},
|
|
{
|
|
"asset": "JWT de sesión / API",
|
|
"algorithm": "HS256 firmado con un secret por instalación generado en el primer arranque (<code>secrets.token_urlsafe</code>, ≥48 bytes). Los tokens llevan claims <code>iss=proxmenux-monitor</code> + <code>aud=api</code>; la firma se valida contra el secret actual en cada petición.",
|
|
"where": "Secret: <code>auth.json</code> → <code>jwt_secret</code>. El JWT en sí: solo en el cliente."
|
|
},
|
|
{
|
|
"asset": "Metadatos de API token",
|
|
"algorithm": "SHA-256 del JWT guardado junto con una huella <code>signed_with</code> del <code>jwt_secret</code> usado para emitirlo — usado para mostrar el token en la UI y para detectar tokens cuyo secret de firma se ha rotado.",
|
|
"where": "<code>auth.json</code> → <code>api_tokens[]</code>"
|
|
},
|
|
{
|
|
"asset": "Secret TOTP de 2FA",
|
|
"algorithm": "TOTP estándar (RFC 6238), con secreto codificado en base32. Los ocho códigos de backup son de un solo uso y se almacenan como hashes SHA-256.",
|
|
"where": "<code>auth.json</code> → <code>totp_secret</code> + <code>backup_codes[]</code>"
|
|
},
|
|
{
|
|
"asset": "Revocaciones",
|
|
"algorithm": "Cuando un token o sesión se revoca, su SHA-256 se añade a una deny-list comprobada en cada verificación (en memoria caché ~30 s para evitar lecturas de disco en la ruta caliente).",
|
|
"where": "<code>auth.json</code> → <code>revoked_tokens[]</code>"
|
|
}
|
|
],
|
|
"authJsonTitle": "auth.json — qué contiene y cómo se protege",
|
|
"authJsonBody": "Todo lo que ProxMenux Monitor necesita para autenticarte vive en un único archivo: <code>/root/.config/proxmenux-monitor/auth.json</code>, modo <code>0600</code>, propietario <code>root</code>. El archivo guarda <em>hashes</em> (PBKDF2) y <em>material de firma</em> (<code>jwt_secret</code>, <code>totp_secret</code>) — nunca una contraseña en texto plano. Trátalo como cualquier otro secreto de solo-root: si haces backup o replicas el host, cifra el destino y nunca lo subas a control de versiones.",
|
|
"rotateTitle": "Rotar jwt_secret invalida todos los JWTs existentes",
|
|
"rotateBody": "Si <code>auth.json</code> se regenera (borrado manual, reinstalación, restauración desde un backup con un secret distinto) el <code>jwt_secret</code> cambia y cada JWT previamente emitido — tanto sesiones interactivas como API tokens de larga duración — falla la verificación con \"Invalid or expired token\". La UI marca los API tokens afectados con un badge <strong>Invalid — regenerate</strong> para que el usuario sepa que tiene que revocarlos y volver a emitirlos; Home Assistant / scripts / cualquier cliente externo necesita un token fresco después de eso.",
|
|
"recoverTitle": "Recuperar una contraseña perdida",
|
|
"recoverIntro": "No hay un flujo online de \"olvidé mi contraseña\" — por diseño, ya que el panel corre en el propio host del usuario y el camino de recuperación es acceso shell a ese host. ProxMenux trae un reset guiado dentro del menú de configuración para que no tengas que editar a mano <code>auth.json</code>:",
|
|
"survivesTitle": "Qué sobrevive al reset",
|
|
"survivesBody": "Solo el login interactivo se borra. El <code>jwt_secret</code> y los <code>api_tokens</code> registrados se preservan — así que Home Assistant y cualquier otro script que use un API token de larga duración siguen funcionando sin reconfiguración. Si quieres una pizarra totalmente limpia (también rotar el secret JWT), borra <code>auth.json</code> manualmente y reinicia el servicio. El siguiente arranque genera un secret fresco y todos los tokens viejos se vuelven inválidos.",
|
|
"physicalTitle": "Prerrequisito de acceso físico",
|
|
"physicalBody": "Esta ruta de reset necesita <strong>shell root en el host</strong>. Esa es el ancla de confianza de todo el esquema de autenticación: cualquiera que pueda ejecutar <code>menu</code> como root ya puede hacer cualquier cosa en la máquina, así que darle reset de contraseña no es un aumento de privilegios. El corolario: si dejas que un usuario no confiable llegue a la shell de Proxmox, el login del Monitor no protegerá nada que ese usuario no pueda ya destruir por otros medios."
|
|
},
|
|
"twofa": {
|
|
"heading": "Autenticación de dos factores (TOTP)",
|
|
"intro": "El 2FA añade un segundo factor encima de tu contraseña: un código de 6 dígitos que rota cada 30 segundos, generado en un móvil o gestor de contraseñas que controlas. Aunque alguien obtenga la contraseña, sigue sin poder entrar sin el código de tu dispositivo. ProxMenux Monitor implementa el protocolo estándar <strong>TOTP</strong> (RFC 6238), así que cualquier app autenticadora funciona.",
|
|
"pickTitle": "Elige una app autenticadora",
|
|
"pickIntro": "Si ya tienes una aplicación TOTP, puedes usarla aquí. La tabla recoge opciones habituales: algunas son gratuitas y otras requieren suscripción. También cambian las plataformas y los métodos de backup.",
|
|
"headerApp": "Aplicación",
|
|
"headerPlatforms": "Plataformas",
|
|
"headerAppNotes": "Notas",
|
|
"apps": [
|
|
{
|
|
"name": "Google Authenticator",
|
|
"href": "https://safety.google/authentication/",
|
|
"platforms": "iOS, Android",
|
|
"notes": "El predeterminado para muchos usuarios. Backup opcional a la cuenta de Google."
|
|
},
|
|
{
|
|
"name": "Microsoft Authenticator",
|
|
"href": "https://www.microsoft.com/en-us/security/mobile-authenticator-app",
|
|
"platforms": "iOS, Android",
|
|
"notes": "Backup a la cuenta Microsoft. También maneja notificaciones push de MS si las usas en el trabajo."
|
|
},
|
|
{
|
|
"name": "Authy",
|
|
"href": "https://authy.com/",
|
|
"platforms": "iOS, Android",
|
|
"notes": "Sincronización cifrada entre dispositivos. La aplicación de escritorio dejó de recibir soporte el 19 de marzo de 2024."
|
|
},
|
|
{
|
|
"name": "Apple Passwords",
|
|
"href": "https://support.apple.com/guide/passwords/welcome/mac",
|
|
"platforms": "iOS, iPadOS, macOS, visionOS, Windows (vía iCloud)",
|
|
"notes": "Integrada en los SO de Apple; app Passwords independiente desde iOS 18 / macOS Sequoia. Guarda el TOTP junto a la contraseña y sincroniza entre dispositivos vía iCloud Keychain."
|
|
},
|
|
{
|
|
"name": "Bitwarden",
|
|
"href": "https://bitwarden.com/",
|
|
"platforms": "iOS, Android, escritorio, navegador",
|
|
"notes": "Código abierto. Permite guardar TOTP junto a las contraseñas en la bóveda. Resulta cómodo, pero guardar ambos en ella no los separa en un segundo dispositivo."
|
|
},
|
|
{
|
|
"name": "1Password",
|
|
"href": "https://1password.com/",
|
|
"platforms": "iOS, Android, escritorio, navegador",
|
|
"notes": "Misma idea que Bitwarden — TOTP integrado con la bóveda de contraseñas. Por suscripción."
|
|
},
|
|
{
|
|
"name": "Aegis Authenticator",
|
|
"href": "https://getaegis.app/",
|
|
"platforms": "Android",
|
|
"notes": "Código abierto. Archivo de backup cifrado en dispositivo que tú controlas. Sin nube, sin cuenta requerida."
|
|
},
|
|
{
|
|
"name": "Raivo OTP",
|
|
"href": "https://raivo-otp.com/",
|
|
"platforms": "iOS, macOS",
|
|
"notes": "Código abierto. Sync opcional a iCloud. La contraparte del ecosistema Apple a Aegis."
|
|
},
|
|
{
|
|
"name": "Ente Auth",
|
|
"href": "https://ente.io/auth/",
|
|
"platforms": "iOS, Android, escritorio, web",
|
|
"notes": "Código abierto. Sync en la nube cifrado de extremo a extremo entre dispositivos."
|
|
},
|
|
{
|
|
"name": "2FAS",
|
|
"href": "https://2fas.com/",
|
|
"platforms": "iOS, Android, extensión de navegador",
|
|
"notes": "Código abierto. Backup en la nube cifrado opcional; la extensión de navegador puede autocompletar códigos."
|
|
},
|
|
{
|
|
"name": "FreeOTP+",
|
|
"href": "https://github.com/helloworld1/FreeOTPPlus",
|
|
"platforms": "Android",
|
|
"notes": "Bifurcación de código abierto de FreeOTP para Android, con importación y exportación. No requiere cuenta."
|
|
}
|
|
],
|
|
"backupTitle": "Para qué importa realmente el \"backup\"",
|
|
"backupBody": "Si pierdes el dispositivo autenticador, usa un código de backup guardado o restaura un backup de la app que hubieras configurado previamente. La sincronización en la nube y las exportaciones varían según la aplicación; comprueba que restauren los secretos TOTP. El acceso root al host también permite recuperar el acceso, como se explica abajo. Conserva un backup separado y seguro.",
|
|
"setupTitle": "Configuración paso a paso desde el panel",
|
|
"setupImageAlt": "Pantalla de configuración de 2FA con código QR y códigos de backup",
|
|
"setupImageCaption": "El diálogo de 2FA muestra un código QR, el secreto Base32 para introducirlo manualmente y, tras la verificación, ocho códigos de backup de un solo uso. Cópialos antes de cerrar; no volverán a mostrarse.",
|
|
"setupSteps": [
|
|
"<strong>Instala la app autenticadora en tu móvil</strong> (o abre tu gestor de contraseñas). Una de las apps de la tabla de arriba. Solo necesitas hacerlo una vez — la misma app guardará códigos para cada servicio que protejas.",
|
|
"<strong>Loguéate en el panel</strong> con tu usuario y contraseña.",
|
|
"<strong>Abre la pestaña Seguridad</strong> en la barra lateral y pulsa <strong>Activar 2FA</strong> y <strong>Iniciar configuración</strong>. El diálogo muestra un QR y la clave manual; los ocho códigos de backup aparecen tras verificar el código.",
|
|
"<strong>Añade la entrada a la app autenticadora:</strong>",
|
|
"<strong>Confirma escribiendo el código actual de 6 dígitos</strong> de la app en el campo \"Código de verificación\" del diálogo de configuración y envía. Los códigos se renuevan cada 30 segundos, así que si caduca mientras escribes, introduce el siguiente.",
|
|
"<strong>Guarda los códigos de backup.</strong> Tras la verificación, conserva los ocho en un gestor de contraseñas, nota cifrada o copia impresa segura. Cada uno funciona una vez si no tienes el autenticador.",
|
|
"<strong>Hecho.</strong> El 2FA está ahora activo. La próxima vez que te logues, el panel pide primero la contraseña; una vez aceptada pide el código actual de 6 dígitos."
|
|
],
|
|
"setupStep4Sub": [
|
|
"<em>Camino fácil:</em> en la app, pulsa <em>Añadir cuenta</em> → <em>Escanear código QR</em>, apunta la cámara al QR en la pantalla. La app nombra la entrada automáticamente (algo como <code>ProxMenux Monitor (your-username)</code>) y empieza a mostrar un código de 6 dígitos que se refresca cada 30 segundos.",
|
|
"<em>Plan B manual</em> (cuando escanear no es posible — p. ej. configurando en el mismo móvil con el que abriste el panel): pulsa <em>Añadir cuenta</em> → <em>Introducir clave de setup</em>. Escribe cualquier nombre (p. ej. <em>Proxmox Monitor</em>), pega la cadena Base32 del diálogo, deja <em>Tipo</em> como <em>Basado en tiempo</em>, guarda."
|
|
],
|
|
"testTitle": "Prueba antes de cerrar sesión",
|
|
"testBody": "Mantén la sesión actual abierta y prueba un nuevo acceso en una ventana privada <em>inmediatamente</em> después de configurar 2FA. Si el código falla, comprueba los relojes del servidor y del móvil antes de cerrar la sesión válida. Si ya perdiste el acceso, usa un código de backup o edita <code>auth.json</code> desde la consola del host.",
|
|
"lostTitle": "Autenticador perdido",
|
|
"lostIntro": "Tres salidas de emergencia, en orden de cuán disruptivas son:",
|
|
"lostItems": [
|
|
"<strong>Usa un código de backup.</strong> Introduce uno de los ocho códigos guardados en el campo TOTP. Funciona una vez; los no usados siguen siendo válidos. Tras entrar, abre Seguridad, elige <strong>Desactivar 2FA</strong> y después <strong>Activar 2FA</strong> para obtener ocho códigos nuevos.",
|
|
"<strong>Restaura el autenticador desde la nube / backup.</strong> Si tu app tiene sync en la nube (Google, Microsoft, Authy, Apple Passwords vía iCloud Keychain, Ente, 2FAS) instálala en un dispositivo nuevo, loguéate y las entradas reaparecen. Si tu app usa un archivo de exportación cifrado (Aegis, Raivo, FreeOTP+), instala la app en el dispositivo nuevo e importa el archivo.",
|
|
"<strong>Desactiva el 2FA desde la shell del host.</strong> Cuando las opciones anteriores no están disponibles, edita <code>/root/.config/proxmenux-monitor/auth.json</code> en el host Proxmox (necesitas SSH root o acceso por consola), pon <code>totp_enabled</code> a <code>false</code>, guarda y reinicia el servicio:"
|
|
],
|
|
"lostShellOutro": "Puedes loguearte con usuario + contraseña solo, luego reactivar el 2FA desde Settings.",
|
|
"disableTitle": "Desactivar el 2FA",
|
|
"disableBody": "Abre <strong>Seguridad</strong> y elige <strong>Desactivar 2FA</strong>. <code>POST /api/auth/totp/disable</code> exige la contraseña actual y un código TOTP o de backup válido. Elimina el secreto TOTP y los códigos de backup. Elimina también la entrada antigua en la aplicación autenticadora.",
|
|
"rejectedTitle": "El código de 6 dígitos se rechaza siempre",
|
|
"rejectedIntro": "El TOTP está basado en tiempo — el reloj del servidor y el del móvil deben coincidir dentro de unos ~30 s. Dos comprobaciones:",
|
|
"rejectedItems": [
|
|
"<strong>Móvil:</strong> Ajustes → Fecha y hora → sync automático / de red ACTIVADO.",
|
|
"<strong>Host Proxmox:</strong> <code>timedatectl status</code> — \"System clock synchronized: yes\" debería aparecer. Si no, <code>timedatectl set-ntp true</code> y espera un minuto."
|
|
],
|
|
"rejectedOutro": "Una vez que ambos relojes coinciden, el código se acepta dentro de la siguiente ventana de 30 segundos."
|
|
},
|
|
"apiTokens": {
|
|
"heading": "API tokens (larga duración)",
|
|
"intro": "Las sesiones de navegador caducan tras 24 horas. Para integraciones desatendidas (widgets de Homepage, sensores de Home Assistant, scrapers de Grafana, probes de Uptime Kuma…) generas un <strong>API token</strong> aparte que vive 365 días. El token es un JWT firmado con el mismo secret que el token de sesión, pero su claim <code>token_name</code> facilita rastrearlo y revocarlo individualmente.",
|
|
"imageAlt": "Panel de API tokens mostrando la lista de tokens con nombre, prefijo, fecha de creación y caducidad",
|
|
"imageCaption": "La lista de API tokens bajo Settings — nombre, prefijo (se muestran los últimos 4 caracteres para identificación), fechas de creación y caducidad, acción de revocar.",
|
|
"generateTitle": "Generar un token",
|
|
"generateIntro": "Desde el panel:",
|
|
"generateSteps": [
|
|
"Abre <strong>Seguridad → Tokens de acceso API</strong>.",
|
|
"Escribe un nombre descriptivo (<em>p. ej. \"Home Assistant\"</em>).",
|
|
"Vuelve a introducir tu contraseña. Si el 2FA está activado, también el código actual de 6 dígitos.",
|
|
"Pulsa <strong>Generar token</strong>. Se muestra <strong>una sola vez</strong>: cópialo al momento."
|
|
],
|
|
"generateCli": "Desde la línea de comandos:",
|
|
"useTitle": "Usar un token",
|
|
"revokeTitle": "Revocar un token",
|
|
"revokeBody": "Cada fila ofrece <strong>Revocar</strong>, que añade el hash del token a <code>revoked_tokens</code> en <code>auth.json</code>. El token revocado falla la validación en la siguiente petición.",
|
|
"cheatTitle": "Chuleta de seguridad de tokens",
|
|
"cheatItems": [
|
|
"Guarda los tokens en el almacén de secrets nativo de tu integración — Homepage <code>secrets.yaml</code>, Home Assistant <code>!secret</code>, variables de entorno, etc. Nunca los subas a git.",
|
|
"Un token por integración, nombrado por el consumidor. Revoca individualmente al retirar una integración.",
|
|
"Rota cada 6-12 meses. La expiración es un límite duro, no una recomendación."
|
|
],
|
|
"outro": "Consulta las recomendaciones de almacenamiento y los ejemplos en <apiLink>Referencia de la API → Gestión de tokens</apiLink> e <intLink>Integraciones</intLink>."
|
|
},
|
|
"https": {
|
|
"heading": "HTTPS",
|
|
"intro": "Dos rutas hacia TLS:",
|
|
"items": [
|
|
"<strong>Reverse proxy (recomendado).</strong> Termina TLS en Nginx / Caddy / Traefik y reenvía HTTP en el puerto 8008 al proceso Flask. Snippets más abajo.",
|
|
"<strong>HTTPS directo en AppImage.</strong> Configura un certificado con <code>POST /api/ssl/configure</code> (interfaz: <strong>Ajustes → SSL</strong>). HTTPS usa <code>gevent.pywsgi</code> con su manejador estándar; flask-sock gestiona la conexión WebSocket para WSS. Las rutas de los certificados se guardan en la configuración SSL."
|
|
],
|
|
"calloutTitle": "Limitaciones del HTTPS directo",
|
|
"calloutBody": "Monitor puede usar un certificado gestionado por Proxmox o archivos de certificados propios. No emite certificados ACME. Para emitirlos y renovarlos automáticamente, usa ACME de Proxmox o un proxy inverso como Caddy, Traefik o Nginx y asegúrate de cargar los certificados renovados."
|
|
},
|
|
"gateway": {
|
|
"heading": "Secure Gateway (Tailscale)",
|
|
"intro": "Un proxy inverso es una opción de acceso remoto. <strong>Secure Gateway</strong> permite acceder sin exponer TCP 8008: despliega un LXC Alpine con <a>Tailscale</a> como router de subred. El acceso a la IP LAN del host depende de las rutas aprobadas y de las reglas de acceso de la tailnet.",
|
|
"calloutTitle": "Por qué esto es cómodo",
|
|
"calloutBody": "Usa la URL LAN <code>http://<proxmox-lan-ip>:8008</code> mediante la ruta de subred aprobada. Tailscale usa SNAT por defecto, por lo que Monitor suele ver la IP LAN de la pasarela, no la dirección <code>100.x.y.z</code> del cliente. Los registros y Fail2Ban identifican la dirección de origen que recibe el host.",
|
|
"deployBody": "El flujo de despliegue es una sola pantalla — elige el storage LXC del host, pega un auth-key de Tailscale (generado en <a>login.tailscale.com/admin/settings/keys</a>), elige qué subnets anunciar, pulsa Deploy. El LXC tarda ~30 segundos en arrancar y se registra en el tailnet automáticamente.",
|
|
"outro": "El despliegue paso a paso, la configuración de subnet-routes, las ACLs de Tailscale y el modo Exit Node se documentan por separado en <link>Dashboard → Security → Secure Gateway</link> — ahí vive el wizard de despliegue en la UI del panel. Esta página solo cubre el patrón de acceso."
|
|
},
|
|
"proxy": {
|
|
"heading": "Snippets de reverse proxy",
|
|
"intro": "Usa un <strong>nombre de host dedicado</strong>, como <code>monitor.example.com</code>, que reenvíe al puerto 8008 del host Proxmox. Los ejemplos siguen ese patrón. Una subruta como <code>example.com/proxmenux-monitor/</code> requiere cambios adicionales en frontend y proxy; quitar el prefijo no basta.",
|
|
"nginxTitle": "Nginx",
|
|
"caddyTitle": "Caddy",
|
|
"traefikTitle": "Traefik (etiquetas: Docker / Kubernetes)",
|
|
"subPathTitle": "Avanzado: montajes en sub-path bajo un dominio existente",
|
|
"subPathBody": "El frontend actual no tiene una base de subruta configurada y crea llamadas desde la raíz mediante URL <code>/api/*</code>. Quitar un prefijo como <code>example.com/proxmenux-monitor/</code> no resuelve esas llamadas ni todos los recursos de la interfaz. Usa un nombre de host dedicado. Una subruta exige cambios coordinados en frontend y proxy y pruebas específicas."
|
|
},
|
|
"audit": {
|
|
"heading": "Log de auditoría",
|
|
"intro": "Los fallos de inicio de sesión y los avisos del límite de intentos se escriben en <code>/var/log/proxmenux-auth.log</code>, con una línea por evento. Este logger no registra los accesos correctos:",
|
|
"outro": "Sigue la cola con el método habitual: <code>tail -F /var/log/proxmenux-auth.log</code>. El archivo se rota con <code>logrotate</code> si se añade un drop-in de configuración; el Monitor no lo rota por sí mismo."
|
|
},
|
|
"fail2ban": {
|
|
"heading": "Opcional: jail de Fail2Ban",
|
|
"calloutTitle": "Fail2Ban no viene incluido con el Monitor",
|
|
"calloutBody": "Fail2Ban <strong>no</strong> lo instala ProxMenux Monitor por sí mismo. Instálalo vía <link>Seguridad → Fail2Ban</link> en el menú de ProxMenux (o con el paquete estándar de Debian). Sin él, el Monitor sigue escribiendo el log de auditoría de arriba — simplemente no banea automáticamente a los repetidores.",
|
|
"intro": "Cuando Fail2Ban está instalado, la integración de ProxMenux trae un jail <code>[proxmenux]</code> que:",
|
|
"items": [
|
|
"Lee <code>/var/log/proxmenux-auth.log</code>.",
|
|
"Hace match con el patrón <code>authentication failure; rhost=<ip></code> con un filtro dedicado.",
|
|
"Banea la IP infractora a nivel del firewall del kernel por defecto.",
|
|
"El hook <code>before_request</code> de Flask contrasta las peticiones con la lista de bloqueos, almacenada en caché durante 30 s. Tras un proxy inverso, el bloqueo por IP requiere también PROXMENUX_TRUST_PROXY=1 y un proxy controlado que establezca cabeceras fiables."
|
|
],
|
|
"outro": "La configuración, el ajuste del tiempo de ban y los procedimientos de desbaneo están en <link>Seguridad → Fail2Ban</link>."
|
|
},
|
|
"troubleshoot": {
|
|
"heading": "Solución de problemas",
|
|
"noScreenTitle": "La pantalla de primer arranque nunca aparece",
|
|
"noScreenBody": "O bien auth ya está configurado (<code>configured: true</code>) o bien alguien ya eligió Skip. Para empezar desde cero:",
|
|
"noScreenOutro": "Esto borra el estado de auth — también cualquier secret TOTP y API tokens. Haz backup de <code>auth.json</code> primero si tienes tokens que quieres conservar.",
|
|
"tokenTitle": "HTTP 401 en cada petición desde un API token que funcionaba",
|
|
"tokenBody": "El token caducó (límite de 365 días) o entró en la lista <code>revoked_tokens</code>. Genera uno nuevo en Settings y actualiza la integración. Para comprobar:",
|
|
"tokenOutro": "Los tokens caducados o revocados devuelven <code>'{'\"error\":\"Invalid or expired token\"'}'</code>.",
|
|
"no2faTitle": "No puedo loguearme tras activar el 2FA, sin autenticador a mano",
|
|
"no2faBody": "Usa un código de backup en el campo TOTP. Si ya no quedan, edita <code>/root/.config/proxmenux-monitor/auth.json</code> desde una shell del host, pon <code>totp_enabled</code> a <code>false</code>, reinicia el servicio.",
|
|
"wsTitle": "El reverse proxy funciona pero la pestaña del terminal se desconecta cada minuto",
|
|
"wsBody": "Timeout de idle de WebSocket en el proxy. Sube el read timeout (Nginx: <code>proxy_read_timeout 86400s</code>; Traefik: <code>idleTimeout</code> en el entry-point o middleware) y confirma que <code>proxy_set_header Upgrade $http_upgrade</code> y <code>Connection \"upgrade\"</code> están presentes."
|
|
},
|
|
"whereNext": {
|
|
"heading": "Por dónde seguir",
|
|
"items": [
|
|
{
|
|
"label": "Referencia de la API → Gestión de tokens",
|
|
"href": "/docs/monitor/api",
|
|
"tail": " — ciclo de vida completo de API tokens (generar / listar / revocar), mejores prácticas de seguridad, patrones de almacenamiento de secrets."
|
|
},
|
|
{
|
|
"label": "Integraciones",
|
|
"href": "/docs/monitor/integrations",
|
|
"tail": " — Homepage, Home Assistant, Grafana / Prometheus, Uptime Kuma, cURL genérico."
|
|
},
|
|
{
|
|
"label": "Dashboard → Seguridad → Secure Gateway",
|
|
"href": "/docs/monitor/dashboard/security",
|
|
"tail": " — despliega el LXC gateway Tailscale paso a paso (subnet routes, ACLs, modo Exit Node)."
|
|
},
|
|
{
|
|
"label": "Seguridad → Fail2Ban",
|
|
"href": "/docs/security/fail2ban",
|
|
"tail": " — cómo instalar y configurar el jail opcional."
|
|
},
|
|
{
|
|
"label": "Ajustes → ProxMenux Monitor",
|
|
"href": "/docs/settings/proxmenux-monitor",
|
|
"tail": " — arranca / para el servicio systemd desde la TUI de ProxMenux."
|
|
}
|
|
]
|
|
}
|
|
}
|