From e07bba7dbdefa4752800de237a1fd7cb677a4934 Mon Sep 17 00:00:00 2001 From: MacRimi Date: Sun, 31 May 2026 18:16:11 +0200 Subject: [PATCH 1/4] lang/es/CHANGELOG.md: ship the Spanish-translated changelog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Next.js changelog page (app/[locale]/changelog/page.tsx) already has the per-locale lookup logic — it reads lang//CHANGELOG.md first and falls back to the canonical English CHANGELOG.md at the repo root if no localized copy exists. The Spanish file has lived in develop for weeks (65 KB, 1065 lines, full translation including the v1.2.1 SR-IOV / GPU passthrough hardening notes) but was never committed to the repo, so the live site at proxmenux.com/es/changelog fell back to English on every visit. Add the file to the tree so the lookup finds it. No code change in the page — the resolution logic in `resolveChangelogPath()` already handles both branches and is unchanged. Co-Authored-By: Claude Opus 4.7 --- lang/es/CHANGELOG.md | 1065 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1065 insertions(+) create mode 100644 lang/es/CHANGELOG.md diff --git a/lang/es/CHANGELOG.md b/lang/es/CHANGELOG.md new file mode 100644 index 00000000..c751889a --- /dev/null +++ b/lang/es/CHANGELOG.md @@ -0,0 +1,1065 @@ + +## 2026-04-20 + +### Nueva versión ProxMenux v1.2.1 — *SR-IOV Awareness & GPU Passthrough Hardening* + +Release puntual sobre **v1.2.0** que aborda tres áreas reportadas por la comunidad y que necesitaban arreglo antes del siguiente ciclo estable: reconocimiento completo de SR-IOV en todo el subsistema GPU/PCI, gestión robusta de los dispositivos de audio acompañantes de la GPU durante el attach y detach de passthrough (Intel iGPU con audio del chipset, tarjetas discretas con audio HDMI, VMs con GPU mixta), y fixes de compatibilidad para los proveedores de notificaciones con IA (endpoints custom OpenAI-compatible tipo LiteLLM/MLX/LM Studio, modelos de razonamiento de OpenAI, y modelos thinking de Gemini 2.5+/3.x). También incluye mejoras de calidad de vida en el instalador NVIDIA, el Monitor de salud de discos, y los helpers de ciclo de vida de LXC usados por los wizards de passthrough. + +--- + +## 🎛️ SR-IOV Awareness en todo el subsistema GPU + +Intel `i915-sriov-dkms` y AMD MxGPU dividen la Physical Function (PF) de una GPU en Virtual Functions (VFs) que pueden asignarse de forma independiente a LXCs y VMs. Anteriormente ProxMenux no tenía reconocimiento alguno de SR-IOV: trataba VFs y PFs de manera idéntica, lo que podía reescribir `vfio.conf` con el vendor:device ID de la PF, colapsar el árbol de VFs en el siguiente arranque, y dejar a los usuarios sin poder iniciar sus guests. Se ha auditado y endurecido cada ruta que pudiera alterar un árbol de VFs activo. + +### Helpers de detección +- Nuevos `_pci_is_vf`, `_pci_has_active_vfs`, `_pci_sriov_role`, `_pci_sriov_filter_array` en `scripts/global/pci_passthrough_helpers.sh` +- Equivalentes HTTP/JSON en la ruta Flask de GPU — la UI del Monitor lee el estado VF/PF directamente desde sysfs (`physfn`, `sriov_totalvfs`, `sriov_numvfs`, `virtfn*`) + +### Pre-start hook (`gpu_hook_guard_helpers.sh`) +El guard pre-start de las VMs ahora reconoce Virtual Functions. Tanto la rama de sintaxis slot-only (que solía iterar todas las funciones del slot y exigir `vfio-pci` en todas) como la rama full-BDF saltan las VFs, de modo que Proxmox puede realizar su rebind vfio-pci por VF con normalidad. El falso bloqueo "GPU passthrough device is not ready" en VMs SR-IOV ha desaparecido. + +### Los scripts de mode-switch rechazan operaciones SR-IOV +`switch_gpu_mode.sh`, `switch_gpu_mode_direct.sh`, `add_gpu_vm.sh`, `add_gpu_lxc.sh`, `vm_creator.sh`, `synology.sh`, `zimaos.sh` y `add_controller_nvme_vm.sh` rechazan ahora las VFs y las PFs con VFs activas antes de tocar la configuración del host. Un dialog claro "SR-IOV Configuration Detected" explica la situación. Para los wizards invocados en mitad de flujo (creadores de VM) el mensaje se entrega por `whiptail` para que interrumpa limpiamente, seguido de una línea `msg_warn` por dispositivo para dejar rastro en el log. + +### Nuevo estado "SR-IOV active" en la UI del Monitor +La tarjeta GPU de la página Hardware gana un tercer estado visual con un color teal dedicado, una pill in-line `SR-IOV ×N` (o `SR-IOV VF` para una Virtual Function), y ramas LXC y VM en discontinuo/atenuadas. El botón Edit se oculta porque el estado está gestionado por hardware. + +![SR-IOV active card and modal](https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/sriov-indicator.png) + +### Modal dashboard para GPUs SR-IOV +Al abrir el modal de una Physical Function con VFs activas se muestra ahora: +- Banner de métricas agregadas ("Metrics below reflect the Physical Function, aggregate across N VFs") +- Telemetría normal en tiempo real de la GPU para la PF +- Una tabla **Virtual Functions**, una fila por VF, con el driver actual (`i915`, `vfio-pci`, unbound) y la VM o LXC específica que la consume, incluyendo el estado running/stopped — los consumidores se descubren cruzando entradas `hostpci` y líneas de mount `/dev/dri/renderDN` contra el BDF de la VF y el nodo DRM render + +Al abrir el modal de una Virtual Function se muestran su PF padre (clickable para navegar de vuelta al modal de la PF), el driver actual y el consumidor. + +### El popup de VM Conflict Policy ya no se dispara para VFs de SR-IOV +La regex en `detect_affected_vms_for_selected` casaba el slot (`00:02`) contra VMs que tenían una VF (`00:02.1`) asignada, produciendo un dialog confuso "Keep GPU in VM config". Con el gate SR-IOV upstream, el flujo nunca llega a ese camino de código para slots SR-IOV. + +--- + +## 🔊 GPU + Audio Passthrough — Hardening de ciclo de vida completo + +Una ronda de fixes en torno a cómo el passthrough de GPU gestiona su dispositivo de audio acompañante. Anteriormente, solo se recogía automáticamente el hermano `.1` de una GPU discreta; el passthrough de iGPU Intel a una VM — donde el audio vive separado en el chipset en `00:1f.3` y no en `00:02.1` — se saltaba silenciosamente. En el detach, el viejo `sed` que limpiaba líneas hostpci por substring de slot también podía eliminar una GPU no relacionada cuyo BDF contuviera el slot buscado como substring (p. ej. el slot `00:02` casando dentro de `0000:02:00.0`). Ambos caminos son ahora robustos. + +### Checklist de audio-companion de iGPU en el attach +`add_gpu_vm.sh::detect_optional_gpu_audio` mantiene la fast path de auto-include para el clásico hermano `.1` (NVIDIA / AMD discretas con audio HDMI en la tarjeta). Cuando no existe audio `.1`, el script ahora: +- Escanea sysfs en busca de cada controlador PCI de audio del host +- Salta cualquier cosa ya cubierta por el IOMMU group de la GPU +- Pregunta al usuario mediante un `_pmx_checklist` (`dialog` en modo standalone, `whiptail` en modo wizard llamado desde `vm_creator`/`synology`/`zimaos`) qué controladores de audio pasar junto con la GPU +- Muestra cada entrada con su driver actual en el host (`snd_hda_intel`, `snd_hda_codec_*`, etc.) para que la decisión sea informada +- Por defecto **none** — el usuario opta activamente por incluirlos + +### Cascada de audio huérfano en el detach +Cuando el usuario elige "Remove GPU from VM config" durante un mode switch, los scripts hacen ahora un seguimiento con limpieza dirigida: +- `switch_gpu_mode.sh`, `switch_gpu_mode_direct.sh` y `add_gpu_vm.sh::cleanup_vm_config` (limpieza de la VM origen en el flujo "move GPU") llaman todos al helper compartido `_vm_list_orphan_audio_hostpci` +- El helper usa un escaneo en dos pasadas del config de la VM: pasada 1 registra las bases de slot de las entradas hostpci display/3D; pasada 2 clasifica las entradas de audio y **salta cualquier audio cuyo slot aún tenga un hermano display en la misma VM** — protegiendo el audio HDMI de otras dGPUs que queden en la VM +- Antes el simple match por substring habría marcado el `02:00.1` de NVIDIA como huérfano al hacer detach de una iGPU Intel en `00:02.0` +- El flujo interactivo de switch confirma las eliminaciones con un checklist de `dialog` (por defecto ON). La variante web hace auto-remove sin preguntar — el runner no tiene buena forma de renderizar un checklist — y loguea cada BDF que ha tocado + +### Extensión de la cascada a vfio.conf +Para cada audio eliminado por la cascada, los scripts de switch-mode comprueban ahora si su BDF sigue referenciado por cualquier otra VM vía `_pci_bdf_in_any_vm`. Si nada más lo usa, el `vendor:device` se añade a `SELECTED_IOMMU_IDS` antes de que se ejecute el update de `/etc/modprobe.d/vfio.conf`. Eso cierra el bucle para el caso de la iGPU Intel: `8086:51c8` (PCH HD Audio) se retira ahora de `vfio.conf` junto con `8086:46a3` (iGPU) cuando ambos salen del modo VM y ninguna otra VM los referencia. Si otra VM aún usa el audio, el ID se conserva deliberadamente — sin efectos secundarios rompedores sobre otras VMs. `add_gpu_vm.sh` NO extiende la limpieza en el flujo *move*, porque la GPU sigue en uso en otro sitio y sus IDs deben permanecer. + +### Regex precisa de eliminación de hostpci +Cada `sed` inline usado para hacer detach de una GPU del config de una VM casaba antes el slot como substring libre: +``` +/^hostpci[0-9]+:.*${slot}/d +``` +Para `slot=00:02` ese patrón casa la substring dentro de `0000:02:00.0` (una dGPU NVIDIA no relacionada en el slot `02:00`) y borraría ambas tarjetas. El fix ancla el match a la forma BDF real: +``` +/^hostpci[0-9]+:[[:space:]]*(0000:)?${slot}\.[0-7]([,[:space:]]|$)/d +``` +Aplicado en `switch_gpu_mode.sh`, `switch_gpu_mode_direct.sh` y `add_gpu_vm.sh::cleanup_vm_config`. El helper basado en awk en `vm_storage_helpers.sh::_remove_pci_slot_from_vm_config` (usado por los wizards NVMe) ya usaba el patrón correcto y no necesitó cambios. + +--- + +## 🤖 Compatibilidad de proveedores de IA — OpenAI-Compatible, modelos Reasoning y Thinking + +Tres fixes coordinados que desbloquean categorías de modelos previamente rechazadas por el pipeline de mejora de notificaciones. + +### Endpoints OpenAI-compatible +LiteLLM, MLX, LM Studio, vLLM, LocalAI, Ollama-proxy — el `list_models()` del proveedor exigía antes `"gpt"` en cada nombre de modelo, así que los setups locales sirviendo `mlx-community/...`, `Qwen3-...`, `mistralai/...` veían una lista de modelos vacía. Cuando se establece una Custom Base URL, la comprobación de substring `"gpt"` se omite ahora y `EXCLUDED_PATTERNS` (embeddings, whisper, tts, dall-e) es el único filtro. La capa de ruta Flask también deja de intersectar el resultado contra `verified_ai_models.json` para endpoints custom — la lista verificada solo describe los IDs oficiales de modelo de OpenAI y estaba borrando cada modelo local que el usuario realmente servía. + +### Modelos reasoning de OpenAI +`o1`, `o3`, `o3-mini`, `o4-mini`, `gpt-5`, `gpt-5-mini`, `gpt-5.1`, `gpt-5.2-pro`, `gpt-5.4-nano`, etc. (excluyendo las variantes `*-chat-latest`) usan un contrato API más estricto: `max_completion_tokens` en lugar de `max_tokens`, sin `temperature`. Enviar los parámetros clásicos de chat producía HTTP 400 Bad Request para todos ellos. Un detector en `openai_provider.py` bifurca ahora el payload en consecuencia y establece `reasoning_effort: "minimal"` — por defecto estos modelos gastan su presupuesto de output en razonamiento interno y devuelven una respuesta vacía para la breve petición de traducción de notificación. + +### Modelos thinking de Gemini 2.5+ / 3.x +`gemini-2.5-flash`, `2.5-pro`, `gemini-3-pro-preview`, `gemini-3.1-pro-preview`, etc. tienen "thinking" interno activado por defecto. Con el pequeño presupuesto de tokens usado para el enriquecimiento de notificaciones (≤250 tokens), el presupuesto de thinking consumía toda la asignación y el modelo devolvía output vacío con `finishReason: MAX_TOKENS`. `gemini_provider.py` establece ahora `thinkingConfig.thinkingBudget: 0` para variantes no-`lite` de 2.5+ y 3.x, de modo que los tokens disponibles van a la respuesta visible al usuario. Las variantes lite (sin thinking activado) quedan intactas. + +--- + +## 📋 Refresh de Verified AI Models + +`AppImage/config/verified_ai_models.json` refrescado para los proveedores re-testeados contra APIs en vivo. La nueva herramienta privada de mantenimiento (mantenida fuera de la AppImage) re-ejecuta un test estandarizado de translate+explain contra cada modelo que anuncia cada proveedor, clasifica pass / warn / fail, e imprime un snippet JSON listo para pegar. Re-ejecutar antes de cada release de ProxMenux para mantener la lista al día. + +| Provider | New recommended | Notes | +|----------|-----------------|-------| +| **OpenAI** | `gpt-4.1-nano` | `gpt-4.1-nano`, `gpt-4.1-mini`, `gpt-4o-mini`, `gpt-4.1`, `gpt-4o`, `gpt-5-chat-latest`, más `gpt-5.4-nano` / `gpt-5.4-mini` desde 2026-03. Snapshots con fecha y modelos legacy excluidos. Modelos reasoning soportados por el código pero no listados por defecto — más lentos / más caros sin mejorar la calidad de las notificaciones | +| **Gemini** | `gemini-2.5-flash-lite` | `gemini-2.5-flash-lite`, `gemini-2.5-flash` (funciona ahora), `gemini-3-flash-preview`. Aliases `latest` omitidos intencionadamente — resolvían a modelos distintos entre ejecuciones y producían timeouts en algunas regiones. Las variantes Pro rechazan `thinkingBudget=0` y son excesivas para traducción de notificaciones | +| Groq / Anthropic / OpenRouter | *sin cambios* | Marcados con un `_note` — se re-verificarán en cuanto haya keys disponibles | + +--- + +## 🩺 Monitor de salud de discos — Persistencia de observaciones en el journal watcher + +Un bug latente en `notification_events.py::_check_disk_io` hacía que los errores de I/O del kernel en tiempo real capturados por el journal watcher se superficiaran como notificaciones pero nunca se escribieran en la tabla permanente de observaciones por disco. En la práctica el escaneo paralelo periódico de dmesg solía registrar la observación poco después, pero bajo casos límite de timing (ventana de dmesg obsoleta, restart de servicio justo después del error, rotación de buffer) la observación podía perderse. + +El journal watcher registra ahora la observación antes del gate de cooldown de notificación de 24h, usando la misma clasificación de signature por familia (`io__ata_connection_error`, `io__block_io_error`, `io__ata_failed_command`) que el escaneo periódico. Ambos caminos deduplican ahora en la misma fila vía el UPSERT en `record_disk_observation`, de modo que los conteos de ocurrencias son precisos sin importar qué detector disparó primero. + +--- + +## 🔧 Pulido del instalador NVIDIA + +### Race condition de `lsmod` silenciada +Durante la reinstalación, la verificación de unload de módulos en `unload_nvidia_modules` producía errores espurios `lsmod: ERROR: could not open '/sys/module/nvidia_uvm/holders'` porque `lsmod` lee `/proc/modules` y luego abre el directorio `holders/` de cada módulo, que desaparece transitoriamente mientras el módulo está siendo eliminado. La comprobación lee ahora `/proc/modules` directamente e inserta sleeps cortos para dejar que el kernel finalice el unload antes de re-verificar. Aplicado en el mismo espíritu a los otros cuatro call sites de `lsmod` en el script. + +### Dialog → whiptail en el flujo de update LXC +El mensaje "Insufficient Disk Space" en `update_lxc_nvidia` y la confirmación "Update NVIDIA in LXC Containers" usan ahora dialogs estilo `whiptail` consistentes con el resto del messaging in-flow, evitando la rotura visual que `dialog --msgbox` causaba al renderizarse en mitad de la secuencia en la fase de update de contenedores. + +--- + +## 🧵 Helper de ciclo de vida LXC — Stop seguro con timeout + +Un `pct stop` simple puede colgarse indefinidamente cuando el contenedor tiene un lock obsoleto de una operación abortada previa, cuando los procesos de dentro (Plex, Jellyfin, bases de datos) ignoran TERM y caen en uninterruptible-sleep mientras la GPU que estaban usando es arrancada, o cuando `pct shutdown --timeout` no es respetado por pct mismo. Reportes de campo de esperas de 5+ min durante mode switches de GPU hicieron de esto un peligro real de UX. + +Nuevo helper compartido `_pmx_stop_lxc [log_file]` en `pci_passthrough_helpers.sh`: +1. Devuelve 0 inmediatamente si el contenedor no está corriendo +2. `pct unlock` best-effort (silencioso ante fallo) — la mayoría de contenedores no están realmente bloqueados; solo nos importan los casos en que lo están +3. `pct shutdown --forceStop 1 --timeout 30` envuelto en un `timeout 45` externo para no esperar nunca más que eso a la fase graceful, incluso si pct se atasca en I/O del backend +4. Verifica el estado real vía `pct status` — pct puede devolver no-cero mientras el contenedor está de hecho parado +5. Si sigue corriendo, `pct stop` envuelto en `timeout 60`. Verificar de nuevo +6. Devuelve 1 solo si el contenedor está realmente atascado tras ~107 s totales — el wizard continúa en lugar de colgarse + +Cableado en las tres rutas de modo GPU que paran LXCs durante un switch: `switch_gpu_mode.sh`, `switch_gpu_mode_direct.sh`, y `add_gpu_vm.sh::cleanup_lxc_configs`. + +--- + +## ⚙️ Estabilidad del prompt de reboot en `add_gpu_vm.sh` + +El prompt final "Reboot Required" del wizard de asignación GPU-a-VM estaba disparando reboots espurios en ciertas invocaciones de cadena de menú (`menu` → `main_menu` → `hw_grafics_menu` → `add_gpu_vm`). Con el helper `_pmx_yesno` a veces devolvía exit 0 sin que el usuario hubiera confirmado realmente, llamando `reboot` de inmediato. Con un `read` simple en su lugar el proceso quedaba suspendido por SIGTTIN cuando la cadena de menú desligaba el script del grupo de proceso foreground del terminal, dejando `[N]+ Stopped menu` en el shell padre sin posibilidad de responder. + +El prompt usa ahora `whiptail --yesno` invocado directamente (el patrón verificado para funcionar de forma fiable en esa cadena de menú) e inserta una pausa `Press Enter to continue ... read -r` entre la respuesta "Yes" y la llamada real a `reboot` — de modo que un Enter accidental en el botón de confirmar no puede disparar un reboot inmediato sin un paso de confirmación visible primero. + +--- + +### 🙏 Gracias + +Gracias a los usuarios que reportaron los casos de SR-IOV, LiteLLM/MLX y GPU + audio — estas mejoras existen gracias a reportes detallados y reproducibles. No dudéis en seguir reportando issues o sugiriendo mejoras 🙌. + +--- + + +## 2026-04-17 + +### Nueva versión ProxMenux v1.2.0 — *AI-Enhanced Monitoring* + + +![ProxMenux AI](https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/ProxMenux_ai.png) + +Esta release es la culminación del ciclo beta v1.1.9.1 → v1.1.9.6 e introduce la mayor evolución de **ProxMenux Monitor** hasta la fecha: notificaciones mejoradas con IA, un sistema de notificaciones multicanal rediseñado, una experiencia de hardware y almacenamiento totalmente reelaborada, y mejoras amplias de rendimiento en todo el stack de monitorización. También consolida todo el trabajo reciente en los scripts de Storage, Hardware y GPU/TPU. + +--- + +## 🤖 ProxMenux Monitor — Notificaciones mejoradas con IA + +Las notificaciones pueden mejorarse ahora usando IA para generar mensajes claros y contextuales en lugar del output técnico crudo. + +Ejemplo — en lugar de `backup completed exitcode=0 size=2.3GB`, la IA produce: *"The web server backup completed successfully. Size: 2.3GB"*. + +### Lo que hace la IA +- Transforma notificaciones técnicas en mensajes legibles +- Traduce a tu idioma preferido +- Te deja elegir el nivel de detalle: minimal, standard o detailed +- Funciona con Telegram, Discord, Email, Pushover y Webhooks + +### Lo que la IA NO hace +- **No** es un chatbot ni un asistente +- **No** analiza tu sistema ni toma decisiones +- **No** tiene acceso a datos más allá de la notificación que está procesando +- **No** ejecuta comandos ni modifica el servidor +- **No** almacena historial ni aprende de tus datos + +### Soporte multi-proveedor +Elige entre 6 proveedores de IA, cada uno con su propia API key almacenada de forma independiente: +- **Groq** — inferencia rápida, free tier generoso +- **Google Gemini** — excelente relación calidad/precio, free tier disponible +- **OpenAI** — estándar de la industria +- **Anthropic Claude** — excelente para escritura y traducción +- **OpenRouter** — 300+ modelos con una sola API key +- **Ollama** — ejecución 100% local, sin internet + +### Verified AI Models +Una lista curada de modelos (`verified_ai_models.json`) testeada específicamente para mejora de notificaciones. + +- **Verificación híbrida**: el sistema obtiene los modelos del lado del proveedor y filtra para mostrar solo los testeados que funcionan correctamente +- **Memoria de modelo por proveedor**: el modelo seleccionado se guarda por proveedor, de modo que cambiar de proveedor preserva cada elección +- **Verificación diaria**: una tarea en background comprueba la disponibilidad de modelos y migra automáticamente a una alternativa verificada si el modelo actual desaparece +- **Modelos incompatibles excluidos**: Whisper, TTS, image/video, embeddings, guard models, etc. se filtran por proveedor + +| Provider | Recommended | Also Verified | +|----------|-------------|---------------| +| Gemini | gemini-2.5-flash-lite | gemini-flash-lite-latest | +| OpenAI | gpt-4o-mini | gpt-4.1-mini | +| Groq | llama-3.3-70b-versatile | llama-3.1-70b-versatile, llama-3.1-8b-instant, llama3-70b-8192, llama3-8b-8192, mixtral-8x7b-32768, gemma2-9b-it | +| Anthropic | claude-3-5-haiku-latest | claude-3-5-sonnet-latest, claude-3-opus-latest | +| OpenRouter | meta-llama/llama-3.3-70b-instruct | meta-llama/llama-3.1-70b-instruct, anthropic/claude-3.5-haiku, google/gemini-flash-2.5-flash-lite, openai/gpt-4o-mini, mistralai/mixtral-8x7b-instruct | +| Ollama | (todos los modelos locales) | Sin filtrado — muestra todos los modelos instalados | + +### Custom AI Prompts +Los usuarios avanzados pueden definir su propio prompt para tener control total sobre el formato y la traducción. + +- **Selector de Prompt Mode** — Default Prompt o Custom Prompt +- **Export / Import** — guarda y comparte prompts custom entre instalaciones +- **Example Template** — punto de partida para construir tu propio prompt +- **Community Prompts** — enlace directo a GitHub Discussions para compartir plantillas +- El selector de idioma se oculta en modo Custom Prompt (defines el idioma de salida en el propio prompt) + +### Contexto enriquecido +- El **uptime** del sistema se incluye solo para eventos de error/warning (no informativos) — ayuda a distinguir errores de arranque vs runtime +- Tracking de **frecuencia de eventos** — indica problemas recurrentes vs puntuales +- Datos de **SMART disk health** pasados para errores relacionados con discos +- La base de datos de **errores conocidos de Proxmox** mejora la precisión del diagnóstico +- Instrucciones de prompt más claras para prevenir alucinaciones de la IA + +--- + +## 📨 Rediseño del sistema de notificaciones + +- **Arquitectura multicanal** — canales Telegram, Discord, Pushover, Email y Webhook corriendo simultáneamente +- **Configuración por evento** — habilita/deshabilita tipos de evento específicos por canal +- **Channel Overrides** — personaliza el comportamiento de notificación por canal +- **Endpoint webhook seguro** — sistemas externos pueden enviar notificaciones autenticadas +- **Almacenamiento cifrado** — API keys y datos sensibles guardados cifrados +- **Procesamiento basado en cola** — worker en background con reintento automático para notificaciones fallidas +- **Almacenamiento de config basado en SQLite** — reemplaza el config basado en ficheros para mayor fiabilidad + +### Soporte de Telegram Topics +Envía notificaciones a un topic específico dentro de grupos con Topics habilitado. +- Nuevo campo **Topic ID** en el canal Telegram +- Detección automática de grupos con topics habilitados +- Totalmente retrocompatible + +### Notificaciones de update de ProxMenux +El Monitor detecta ahora cuándo se publica una nueva versión de ProxMenux. +- **Doble canal** — monitoriza tanto stable (`version.txt`) como beta (`beta_version.txt`) +- **Integración con GitHub** — compara versiones locales vs remotas +- **Dashboard Update Indicator** — el logo de ProxMenux cambia a una variante de update cuando se detecta una nueva versión (no intrusivo, sin popups) +- **Estado persistente** — el estado se guarda en `config.json`, reseteado por los scripts de update +- Un único toggle en Settings controla ambos canales (habilitado por defecto) + +--- + +## 🖥️ Panel de Hardware — Detección ampliada + +La página Hardware se ha ampliado significativamente, con mejor detección y detalle por dispositivo más rico. + +- **Controladoras SCSI / SAS / RAID** — modelo, driver y slot PCI mostrados en la sección de storage controllers +- **Detección de PCIe Link Speed** — los drives NVMe muestran la velocidad de link actual (generación PCIe y ancho de carriles), facilitando detectar drives que rinden por debajo por ancho de banda limitado del slot +- **Modal de detalle de disco mejorado** — los drives NVMe, SATA, SAS y USB exponen ahora sus campos específicos (info de link PCIe, versión/velocidad SAS, tipo de interfaz) en lugar de una vista genérica +- **Reconocimiento más inteligente de tipo de disco** — etiquetado uniforme para NVMe SSDs, SATA SSDs, HDDs y discos extraíbles +- **Caching de Hardware Info** (`lspci`, `lspci -vmm`) — la caché de 5 min evita escaneos repetidos de datos que no cambian + +--- + +## 💽 Storage Overview — Salud, observaciones, exclusiones + +El Storage Overview se ha reelaborado en torno al estado en tiempo real y al tracking controlado por el usuario. + +### Alineación del estado de salud de disco +- Los badges reflejan ahora el estado **actual** SMART reportado por Proxmox, no un peor histórico +- **Observaciones preservadas** — los hallazgos históricos siguen accesibles vía el badge "X obs." +- **Recuperación automática** — cuando SMART reporta healthy de nuevo, el disco muestra inmediatamente **Healthy** +- Eliminado el viejo tracking `worst_health` que requería limpieza manual + +### Mejoras del registro de discos +- **Lookup inteligente por serial** — cuando un serial es desconocido el sistema comprueba si existe una entrada con serial antes de insertar una nueva +- **Sin duplicados** — previene entradas separadas para el mismo disco apareciendo con/sin serial +- **Soporte de discos USB** — gestiona drives USB que pueden aparecer bajo nombres de dispositivo distintos entre reboots + +### Exclusiones de Storage e interfaces de Red +- Sección **Storage Exclusions** — excluye drives de la monitorización de salud y notificaciones +- **Network Interface Exclusions** — nueva sección para excluir interfaces (bridges `vmbr`, bonds, NICs físicas, VLANs) de salud y notificaciones; ideal para interfaces deshabilitadas intencionadamente que de otro modo generarían falsas alertas +- **Toggles separados** por ítem para Health monitoring y Notifications + +### Robustez en la detección de discos +- **Validación de Power-On-Hours** — detecta y corrige valores absurdamente grandes (miles de millones de horas) en drives con codificación SMART no estándar +- **Bit masking inteligente** — extrae el valor correcto de drives que empaquetan info extra en bytes altos +- **Fallback elegante** — muestra "N/A" en lugar de números imposibles cuando los datos no pueden parsearse + +--- + +## 🧠 Monitor de salud y ciclo de vida de errores + +### Limpieza de errores obsoletos +Los errores de recursos que ya no existen se resuelven ahora automáticamente. +- **VMs / CTs eliminadas** — los errores relacionados se auto-resuelven cuando se elimina el recurso +- **Discos retirados** — los errores de drives USB desconectados o hot-swap se limpian +- **Cambios de cluster** — los errores de cluster se limpian cuando un nodo abandona el cluster +- **Patrones de log** — los errores basados en logs se auto-resuelven tras 48 horas sin recurrencia +- **Updates de seguridad** — las notificaciones de update se auto-resuelven tras 7 días + +### Sistema de migración de base de datos +- **Detección automática de columnas** — las columnas faltantes se añaden en el arranque +- **Compatibilidad de schema** — funciona tanto con convenciones de nombrado de columna antiguas como nuevas +- **Retrocompatible** — se soportan bases de datos de versiones anteriores de ProxMenux +- **Migración elegante** — sin pérdida de datos durante updates de schema + +--- + +## 🧩 Modal de detalle VM / CT + +El modal de detalle VM/CT se ha rediseñado por completo para mejorar la usabilidad. + +- **Navegación con tabs** — *Overview* (información general, estado, uso de recursos) y *Backups* (historial dedicado) +- **Mejoras visuales** — iconos en todo, jerarquía y espaciado mejorados, mejor distinción VM vs CT +- **Adaptación a móvil** — se adapta correctamente a pantallas móviles tanto en webapp como en acceso directo por navegador, sin más overflow en dispositivos pequeños +- **Controles touch-friendly** — botones y espaciado mayores + +### Modal de Secure Gateway +- **Lista de storage con scroll** cuando hay muchos destinos disponibles +- Layout adaptado a móvil y jerarquía visual mejorada + +### Conexión de terminal +- **Fix de bucle de reconexión** que afectaba a dispositivos móviles +- Manejo mejorado de WebSocket para navegadores móviles +- Recuperación más elegante de timeouts de conexión + +### Gestión de Fail2ban y Lynis +- **Botones de delete** añadidos en Settings para ambas herramientas +- Eliminación limpia de paquetes y ficheros de configuración +- Dialog de confirmación para prevenir borrado accidental + +--- + +## ⚡ Optimizaciones de rendimiento + +Reducción importante de uso de CPU y eliminación de picos en el Monitor. + +### Intervalos de polling escalonados +Los collectors corren ahora en schedules con offset para prevenir ejecución simultánea: + +| Collector | Schedule | +|-----------|----------| +| CPU sampling | Cada 30s en offset 0 | +| Temperature sampling | Cada 15s en offset 7s | +| Latency pings | Cada 60s en offset 25s | +| Temperature record | Cada 60s en offset 40s | +| Health collector | Arranca en offset 55s | +| Notification polling | Health=10s, Updates=30s, ProxMenux=45s, AI=50s | + +### Información de sistema cacheada +Los comandos costosos se cachean ahora para reducir ejecución repetida: + +| Command | Cache TTL | Impact | +|---------|-----------|--------| +| `pveversion` | 6 horas | Elimina picos de CPU del 23%+ por ejecución de Perl | +| `apt list --upgradable` | 6 horas | Reduce consultas del gestor de paquetes | +| `pvesh get /cluster/resources` | 30 segundos | 6 llamadas API por request reducidas a 1 | +| `sensors` | 10 segundos | Lecturas de temperatura cacheadas entre polls | +| `smartctl` (SMART health) | 30 minutos | Health checks de disco reducidos desde cada 5 min | +| `lspci` / `lspci -vmm` | 5 minutos | Info de hardware cacheada (no cambia) | +| `journalctl --since 24h` | 1 hora | Conteo de intentos de login cacheado (92% de reducción) | + +### Timeouts de journalctl aumentados +Previene cascadas de timeout bajo carga del sistema: + +| Query Type | Before | After | +|------------|--------|-------| +| Short-term (3-10 min) | 3s | 10s | +| Medium-term (1 hour) | 5s | 15s | +| Long-term (24 hours) | 5s | 20s | + +### Frecuencia de polling reducida +- Intervalo de `TaskWatcher` subido de **2s → 5s** (60% menos comprobaciones) + +### GitHub Actions +- Todas las actions de workflow actualizadas a **v6** para compatibilidad con Node.js 24 +- Warnings de deprecación eliminados en CI/CD + +--- + +## 🧰 Scripts — Trabajo en Storage, Hardware y GPU/TPU + +Esta release también consolida trabajo significativo en los scripts core de ProxMenux. + +### Scripts de Storage +- **Tests SMART programados** y flujo interactivo de test SMART mejorado con feedback de progreso más claro +- Reelaboración de **formateo de disco** (`format-disk.sh`) con selección de dispositivo más segura y flujo de dialog +- **Disk passthrough** para VMs y CTs — enumeración de dispositivos actualizada, identificación basada en serial, y teardown más limpio +- **Adición de controladora NVMe para VMs** — selección de tipo de controladora y detección de slot mejoradas +- **Import disk image** — validación de path más suave y reporte de progreso +- Refresh de la guía manual de **Disk & storage** + +### Scripts de Hardware / GPU / TPU +- **Coral TPU installer** actualizado para kernels y udev rules actuales (Proxmox VE 8 & VE 9) +- **NVIDIA installer** — instalación de driver más limpia, manejo de kernel headers, y flujo de attachment VM/LXC +- **GPU mode switch** (variantes directa e interactiva) — switching más seguro entre modos iGPU +- **Add GPU to VM / LXC** — dialogs de selección unificados y gestión de permisos +- **Herramientas de GPU Intel / AMD** mantenidas en sync con los nuevos patrones compartidos +- **Hardware & graphics menu** reestructurado para consistencia con el resto de ProxMenux + + +## 2026-03-14 + +### Nueva versión v1.1.9 — *Helper Scripts Catalog Rebuilt* + +### Cambiado + +- **Helper Scripts Menu — Reconstrucción completa del catálogo** + El catálogo de Helper Scripts se ha reconstruido por completo para adaptarse a la nueva arquitectura de datos del proyecto [Community Scripts](https://community-scripts.github.io/ProxmoxVE/). + + La implementación previa dependía de un fichero `metadata.json` que ya no existe en el repositorio upstream. El catálogo conecta ahora directamente a la **API de PocketBase** (`db.community-scripts.org`), que es la nueva fuente de datos oficial del proyecto. + + Un nuevo workflow de GitHub Actions genera un índice local `helpers_cache.json` que reemplaza la antigua dependencia de metadata. Esta nueva caché es más rica, más estructurada, e incluye: + - Tipo de script, slug, descripción, notas y credenciales por defecto + - Variantes de OS por script (p. ej. Debian, Alpine) — cada una mostrada como una opción seleccionable separada en el menú + - URL directa de GitHub y **URL Mirror** (`git.community-scripts.org`) para cada script + - Nombres de categoría embebidos directamente en la caché — sin necesidad de requests externos para construir el menú + - Metadata adicional: puerto por defecto, website, logo, soporte de update, disponibilidad ARM + + Los scripts que soportan múltiples variantes de OS (p. ej. Docker con Alpine y Debian) muestran ahora correctamente **una entrada por OS**, cada una con su propia opción de descarga GitHub y Mirror — restaurando el comportamiento que existía antes de la migración upstream. + +--- + +### 🎖 Reconocimiento especial + +Esta actualización no habría sido posible sin la apertura y colaboración de los mantenedores de **Community Scripts**. + +Cuando la estructura de metadata upstream cambió y rompió el catálogo de ProxMenux, los mantenedores respondieron rápidamente, explicaron la nueva arquitectura en detalle y proporcionaron toda la información necesaria para reconstruir la integración limpiamente. + +Agradecimientos especiales a: + +- **MickLeskCanbiZ ([@MickLesk](https://github.com/MickLesk))** — por documentar la nueva estructura de path de scripts por tipo y slug, y por la guía técnica clara y directa. +- **Michel Roegl-Brunner ([@michelroegl-brunner](https://github.com/michelroegl-brunner))** — por explicar la nueva estructura de colecciones de PocketBase (`script_scripts`, `script_categories`). + +El proyecto Helper Scripts es un recurso extraordinario para la comunidad Proxmox. Los scripts pertenecen enteramente a sus autores y mantenedores — ProxMenux simplemente ofrece una forma guiada de descubrirlos y lanzarlos. Todo el crédito va a la comunidad detrás de [community-scripts/ProxmoxVE](https://github.com/community-scripts/ProxmoxVE). + +## 2025-09-18 + +### Nueva versión v1.1.8 — *ProxMenux Offline Mode* + +![ProxMenux Offline](https://macrimi.github.io/ProxMenux/ProxMenux_offline.png) + +--- + +### Añadido + +- **Modo de ejecución offline (sin dependencia de GitHub)** + Todos los scripts core de ProxMenux se ejecutan ahora **enteramente en local**, sin requerir requests en vivo a GitHub (`raw.githubusercontent.com`). + Este cambio proporciona: + - Mayor estabilidad durante la ejecución + - Sin interrupciones por timeouts de red o bloqueos regionales de GitHub + - Soporte para **entornos offline o aislados** + + ⚠️ Esta actualización resuelve issues recientes donde usuarios en ciertas regiones eran incapaces de ejecutar scripts debido a errores de CDN o filtrado TLS al descargar ficheros `.sh` desde URLs raw de GitHub. + + **🎖 Reconocimiento especial: @cod378** + Esta conversión offline ha sido posible gracias al extraordinario trabajo de **@cod378**, + que rediseñó toda la lógica interna del installer y el updater, refactorizó el sistema de gestión de ficheros, + e implementó el nuevo workflow de ejecución totalmente local. + Sin su colaboración, dedicación y aportación técnica, esta transformación no habría sido posible. + +- **ProxMenux Monitor v1.0.1** + Esta actualización trae un gran salto en la interfaz de **ProxMenux Monitor**. + Nuevas funciones y mejoras: + - `Proxy Support`: Accede a ProxMenux a través de proxies inversos con plena funcionalidad + - `Authentication System`: Asegura tu dashboard con protección por contraseña + - `Two-Factor Authentication (2FA)`: Soporte opcional TOTP para mayor seguridad + - `PCIe Link Speed Detection`: Ver velocidades de conexión NVMe y detectar cuellos de botella de rendimiento + - `Enhanced Storage Display`: Auto-formatea tamaños de disco (GB → TB cuando corresponde) + - `SATA/SAS Interface Info`: Detecta y muestra el tipo de storage (SATA, SAS, NVMe, etc.) + - `Health Monitoring System`: Health check integrado del sistema con alertas descartables + - Renderizado mejorado entre navegadores y mejor rendimiento + +- **Helper Scripts Menu (Mirror Support)** + El menú `Helper Scripts` ahora: + - Detecta **URLs mirror** y muestra opciones de descarga alternativas cuando están disponibles + - Lista las versiones de OS disponibles cuando un helper script depende de la versión (p. ej. instaladores de plantillas) + +--- + +### Arreglado + +- Fixes menores y refinamientos a lo largo del codebase para asegurar compatibilidad offline total y una experiencia de usuario más suave. + + + +## 2025-09-04 + +### Nueva versión v1.1.7 + +### Añadido + +- **ProxMenux Monitor** + Tu nueva herramienta de monitorización para Proxmox. Descubre todas las funciones que te ayudarán a gestionar y supervisar tu infraestructura eficientemente. + + ProxMenux Monitor está diseñado para soportar futuras actualizaciones donde **se puedan disparar acciones sin usar el terminal**, gestionadas a través de una **interfaz amigable** accesible en múltiples formatos y dispositivos. + + Accede en: **http://your-server-ip:8008** + + ![ProxMenux Monitor](https://macrimi.github.io/ProxMenux/monitor/welcome.png) +- **Nuevo método de eliminación de banner** + Una nueva función para deshabilitar el mensaje de suscripción de Proxmox con seguridad mejorada: + - Crea un backup completo antes de modificar ningún fichero + - Muestra un warning claro de que pueden producirse breaking changes con futuras actualizaciones de la GUI + - Si la GUI no carga, el usuario puede revertir los cambios por SSH desde el menú post-install usando la herramienta **"Uninstall Options → Restore Banner"** + + Gracias especiales a **@eryonki** por proporcionar el método mejorado. + +--- + +### Mejorado + +- **CORAL TPU Installer actualizado para PVE 9** + El instalador del driver CORAL TPU soporta ahora tanto **Proxmox VE 8 como VE 9**, asegurando compatibilidad con los kernels y udev rules más recientes. + +- **Instalación e integración de Log2RAM** + - La instalación de Log2RAM es ahora idempotente y puede ejecutarse con seguridad múltiples veces. + - Ajusta automáticamente la configuración de `journald` para alinearse con el tamaño y comportamiento de Log2RAM. + - Asegura que el journaling esté correctamente afinado para evitar overflows o agotamiento de RAM en sistemas con poca memoria. + +- **Función de optimización de Red (LXC + NFS)** + Mejorada para prevenir warnings de "martian source" en setups donde **contenedores LXC comparten storage con VMs** vía NFS dentro del mismo servidor. + +- **Progreso de APT Upgrade** + Al ejecutar actualizaciones completas del sistema vía ProxMenux, se muestra ahora una **barra de progreso en tiempo real**, dando al usuario visibilidad clara del proceso de update. + +--- + +### Arreglado + +- Otras pequeñas mejoras y fixes para optimizar el rendimiento en runtime y eliminar bugs menores. + + + +## 2025-01-10 + +### Nueva versión v1.1.6 + +![Shared Resources Menu](https://macrimi.github.io/ProxMenux/share/main-menu.png) + + +### Añadido + +- **Nuevo menú: Mount and Share Manager** + Introducido un nuevo menú integral para gestionar recursos compartidos entre el host Proxmox y los contenedores LXC: + + **Opciones de configuración del host:** + - **Configure NFS Shared on Host** - Añadir, ver y eliminar recursos NFS compartidos en el servidor Proxmox con gestión automática de exports + - **Configure Samba Shared on Host** - Añadir, ver y eliminar recursos Samba/CIFS compartidos en el servidor Proxmox con configuración de share + - **Configure Local Shared on Host** - Crear y gestionar directorios locales compartidos con los permisos adecuados en el host Proxmox + + **Opciones de integración LXC:** + - **Configure LXC Mount Points (Host ↔ Container)** - **Función core** que permite montar directorios del host dentro de contenedores LXC con gestión automática de permisos. Incluye la capacidad de **ver los mount points existentes** para cada contenedor de forma clara y organizada y **eliminar mount points** con verificación apropiada de que el proceso se completó con éxito. Especialmente optimizado para **contenedores no privilegiados** donde el mapeo UID/GID es crítico. + - **Configure NFS Client in LXC** - Configura un cliente NFS dentro de contenedores privilegiados + - **Configure Samba Client in LXC** - Configura un cliente Samba dentro de contenedores privilegiados + - **Configure NFS Server in LXC** - Instala servidor NFS dentro de contenedores privilegiados + - **Configure Samba Server in LXC** - Instala servidor Samba dentro de contenedores privilegiados + + **Documentación y soporte:** + - **Help & Info (commands)** - Guías integrales con instrucciones manuales paso a paso para todos los escenarios de compartición + + Todo el sistema está construido en torno a la funcionalidad de **LXC Mount Points**, que detecta automáticamente los tipos de filesystem, gestiona el mapeo de permisos entre usuarios del host y del contenedor, y proporciona integración fluida tanto para contenedores privilegiados como no privilegiados. + +--- + +### Mejorado + +- **Mejora de auto-detección de Log2RAM** + En el script automático de post-install, la función de instalación de Log2RAM ahora pregunta al usuario cuando la detección automática de disco ssd/m2 falla. + Esto asegura que Log2RAM pueda instalarse aún en sistemas donde la detección automática de disco no funciona correctamente. + +--- + +### Arreglado + +- **Verificación del repositorio de updates de Proxmox** + Arreglado un issue en la función de update de Proxmox donde los ficheros source vacíos del repositorio causaban errores durante la verificación de conflictos. La función gestiona ahora correctamente ficheros vacíos de `/etc/apt/sources.list.d/` sin lanzar falsos warnings. + + Gracias a **@JF_Car** por reportar este issue. + +--- + +### Reconocimientos + +Gracias especiales a **@JF_Car**, **@ghosthvj** y **@jonatanc** por sus pruebas, feedback valioso y sugerencias que ayudaron a refinar la funcionalidad de recursos compartidos y a mejorar la experiencia general de usuario. + + + +## 2025-08-20 + +### Nueva versión v1.1.5 + +### Añadido + +- **Nuevo script: Upgrade PVE 8 a PVE 9** + Añadida una herramienta de upgrade completa ubicada bajo `Utilities and Tools`. Proporciona: + 1. **Upgrade automático** de PVE 8 a 9 + 2. **Upgrade interactivo** con confirmaciones paso a paso + 3. **Modo check-only** usando `check-pve8to9` + 4. **Instrucciones manuales** mostradas en orden para usuarios que prefieren actualizar manualmente + +- **Nuevas herramientas en System Utilities** + - [`s-tui`](https://github.com/amanusk/s-tui): Monitorización de CPU basada en terminal con gráficas + - [`intel-gpu-tools`](https://gitlab.freedesktop.org/drm/igt-gpu-tools): Útil para diagnósticos de GPU Intel + +--- + +### Mejorado + +- **Gestión de APT Upgrade** + La función de upgrade de PVE bloquea ahora el proceso si algún paquete pide confirmación manual. Esto evita upgrades parciales y asegura consistencia. + +- **Optimización de Red (sysctl)** + - Parámetros de kernel obsoletos eliminados (p. ej. `tcp_tw_recycle`, `nf_conntrack_helper`) para prevenir warnings en **Proxmox 9 / kernel 6.14** + - Ahora genera solo parámetros sysctl válidos y al día + +- **Gestión de Patch de CPU AMD** + - Aplica ahora `idle=nomwait` correcto y opciones KVM (`ignore_msrs=1`, `report_ignored_msrs=0`) + - El warning esperado está ahora documentado y gestionado con seguridad para estabilidad con Ryzen/EPYC + +- **Fixes de Timezone y NTP** + - Detecta automáticamente la timezone usando geolocalización por IP pública + - Fallback a UTC si la detección falla + - Reinicia Postfix tras establecer la timezone → resuelve el warning de mismatch `/var/spool/postfix/etc/localtime` + +- **Lógica del Repository & Package Installer** + - Verifica ahora que existan repositorios funcionales antes de instalar ningún paquete + - Si no hay ninguno disponible, añade un repositorio **Debian stable** como fallback + - Reemplaza el obsoleto `mlocate` por `plocate` (compatible con Debian 13 y Proxmox 9) + +- **Logs y Feedback de usuario mejorados** + - Las acciones que fallan proporcionan ahora mensajes precisos (en lugar de marcarse falsamente como éxito) + - Ayuda a los usuarios a entender claramente qué se ha aplicado o saltado + + + +## 2025-08-06 + +### Nueva versión v1.1.4 + +### Añadido + +- **Preparación de compatibilidad con Proxmox 9** + Esta versión prepara **ProxMenux** para el próximo **Proxmox VE 9**: + - La función para añadir los repositorios oficiales de Proxmox soporta ahora el nuevo formato `.sources` usado en Proxmox 9, manteniendo retrocompatibilidad con Proxmox 8. + - La eliminación de banner se soporta ahora opcionalmente para Proxmox 9. + +- **Detección de xshok-proxmox** + Añadida una comprobación para detectar si el script post-install `xshok-proxmox` ya ha sido ejecutado. + Si se detecta, se muestra un warning para evitar ajustes conflictivos: + + ``` + It appears that you have already executed the xshok-proxmox post-install script on this system. + + If you continue, some adjustments may be duplicated or conflict with those already made by xshok. + + Do you want to continue anyway? + ``` + +--- + +### Mejorado + +- **Eliminación de banner (Proxmox 8.4.9+)** + Actualizada la lógica para eliminar el banner de suscripción en **Proxmox 8.4.9**, debido a cambios en `proxmoxlib.js`. + +- **LXC Disk Passthrough (UUID persistente)** + La función para añadir un disco físico a un contenedor LXC usa ahora **paths persistentes basados en UUID**. + Esto asegura que los discos permanezcan correctamente montados, incluso si el orden `/dev/sdX` cambia por hardware nuevo. + + ```bash + PERSISTENT_DISK=$(get_persistent_path "$DISK") + if [[ "$PERSISTENT_DISK" != "$DISK" ]] ... + ``` + +- **System Utilities Installer** + Comprueba ahora si las sources APT están disponibles antes de instalar las herramientas seleccionadas. + Si una nueva instalación de Proxmox no tiene repos activos, **añadirá automáticamente las sources por defecto** para evitar fallos de instalación. + +- **Activación de IOMMU en sistemas ZFS** + La función que habilita IOMMU para passthrough verifica ahora los parámetros de kernel existentes para evitar duplicación si el usuario ya los ha configurado manualmente. + +--- + +### Arreglado + +- Limpieza de código menor y rendimiento de runtime mejorado en varios módulos. + + + +## 2025-07-20 + +### Cambiado + +- **Eliminación del banner de suscripción (Proxmox 8.4.5+)** + Mejorada la función `remove_subscription_banner` para asegurar compatibilidad con Proxmox 8.4.5, donde el método de eliminación de banner fallaba tras instalaciones limpias. + +- **Detección de Log2RAM mejorada** + Tanto en los scripts post-install automático como personalizable, se ha mejorado la lógica para la instalación de Log2RAM. + Ahora detecta correctamente si Log2RAM ya está configurado y evita disparar errores o reconfiguración. + +- **Instalación de Figurine optimizada** + La función `install_figurine` evita ahora duplicar entradas en `.bashrc` si la personalización del prompt root ya existe. + + +### Añadido + +- **Nueva función: Nombrado persistente de interfaces de Red** + Añadida una nueva función `setup_persistent_network` para crear nombres de interfaz de red estables usando ficheros `.link` basados en direcciones MAC. + Esto evita renombrados impredecibles (p. ej. `enp2s0` convirtiéndose en `enp3s0`) cuando cambia el hardware, se reordena la topología PCI o se aplican configuraciones de passthrough. + + **¿Por qué usar ficheros `.link`?** + Porque los nombres predecibles de interfaz en `systemd` pueden cambiar con reordenamientos o reemplazos de hardware. Usar ficheros `.link` estáticos atados a direcciones MAC asegura consistencia, especialmente en sistemas con múltiples NICs o setups de passthrough. + + Gracias especiales a [@Andres_Eduardo_Rojas_Moya] por contribuir la función de nombrado + de red persistente y por la idea original. + +```bash +[Match] +MACAddress=XX:XX:XX:XX:XX:XX + +[Link] +Name=eth0 +``` + + +## 2025-07-01 + +### Nueva versión v1.1.3 + +![Installer Menu](https://macrimi.github.io/ProxMenux/install/install.png) + +- **Dos modos de instalación para ProxMenux** + El installer ofrece ahora dos modos distintos: + 1. **Versión Lite (sin traducciones):** Solo instala dos paquetes oficiales de Debian (`dialog`, `jq`) para habilitar menús y parsing JSON. No se escriben ficheros más allá del directorio de configuración. + 2. **Versión Full (con traducciones):** Usa un virtual environment y permite seleccionar el idioma de interfaz durante la instalación. + + Al actualizar, si el usuario cambia de full a lite, la versión vieja se **eliminará automáticamente** para una transición limpia. + +### Añadido + +- **Nuevo script: Setup automatizado de post-instalación** + Un nuevo script post-install minimal que realiza el setup esencial automáticamente: + - Upgrade y sync del sistema + - Eliminar el banner enterprise + - Optimizar APT, journald, logrotate, límites del sistema + - Mejorar gestión de kernel panic, ajustes de memoria, entropía, red + - Añadir tweaks a `.bashrc` y **auto-instalación de Log2RAM** (si se detecta SSD/M.2) + +- **Nueva función: Configuración de Log2RAM** + Disponible ahora tanto en los scripts post-install personalizable como automático. + En sistemas con SSD/NVMe, Log2RAM se **habilita automáticamente** para preservar la vida del disco. + +- **Nuevos menús:** + - 🧰 **System Utilities Menu** + Permite a los usuarios seleccionar e instalar herramientas CLI útiles con validación de comando apropiada. + - 🌐 **Network Configuration & Repair** + Un nuevo menú interactivo para analizar y reparar interfaces de red. + +### Mejorado + +- **Lógica del menú Post-Install** + Las opciones están ahora agrupadas más lógicamente para mejor usabilidad. + +- **Menú VM Creation** + Mejorado con soporte mejorado de modelo de CPU y opciones custom. + +- **Script UUP Dump ISO Creator** + - Añadida opción para **personalizar la ubicación de la carpeta temporal** + - Arreglado un issue donde se eliminaba la carpeta temp entera en lugar de solo el contenido + 💡 Sugerido por [@igrokit](https://github.com/igrokit) + [#17](https://github.com/MacRimi/ProxMenux/issues/17), [#11](https://github.com/MacRimi/ProxMenux/issues/11) + +- **Script Physical Disk to LXC** + Gestiona ahora **discos formateados con XFS** correctamente. + ¡Gracias a [@antroxin](https://github.com/antroxin) por reportar y testear! + +- **System Utilities Installer** + Reescrito para **verificar la disponibilidad del comando** tras la instalación, asegurando que las herramientas funcionen como se espera. + 🐛 Fix para [#18](https://github.com/MacRimi/ProxMenux/issues/18) por [@DST73](https://github.com/DST73) + +### Arreglado + +- **Habilitar IOMMU en ZFS** + La detección y configuración para habilitar IOMMU en sistemas basados en ZFS es ahora totalmente funcional. + 🐛 Fix para [#15](https://github.com/MacRimi/ProxMenux/issues/15) por [@troponaut](https://github.com/troponaut) + +### Otros + +- Mejoras de rendimiento y limpieza de código en varios módulos. + + + +## 2025-06-06 + +### Añadido + +- **Nuevo menú: Proxmox PVE Helper Scripts** + Introducido oficialmente el nuevo menú **Proxmox PVE Helper Scripts**, reemplazando el anterior: Esenciales Proxmox. + Este nuevo menú incluye: + - Búsqueda de script por nombre en tiempo real + - Navegación basada en categoría + + Es una forma más limpia, rápida y funcional de acceder a los scripts de la comunidad en Proxmox. + + ![Helper Scripts Menu](https://macrimi.github.io/ProxMenux/menu-helpers-script.png) + + +- **Nuevos modelos de CPU en VM Creation** + El menú de selección de CPU en VM creation ha sido ampliado considerablemente para soportar perfiles avanzados de CPU QEMU y x86-64. + Esto permite mejor compatibilidad con sistemas guest modernos y fine-tuning del rendimiento para workloads específicos, incluyendo virtualización anidada y funciones asistidas por hardware. + + + ![CPU Config](https://macrimi.github.io/ProxMenux/vm/config-cpu.png) + + Gracias a **@Nida Légé (Nidouille)** por sugerir esta mejora. + + +- **Soporte para imágenes de disco `.raw`** + La herramienta de import de disco para VMs soporta ahora ficheros `.raw`, además de `.img`, `.qcow2` y `.vmdk`. + Esto mejora la compatibilidad cuando se trabaja con exports de disco de otros hypervisors o herramientas de backup. + + 💡 Sugerido por **@guilloking** en [GitHub Issue #5](https://github.com/MacRimi/ProxMenux/issues/5) + + +- **Detección de Locale al saltarse idiomas** + La función que deshabilita idiomas extra de APT incluye ahora: + - Detección automática de locale (`LANG`) + - Auto-generación de `en_US.UTF-8` si no se encuentra ninguno + - Previene warnings durante ejecución de scripts debido a locale indefinido + + +### Mejorado + +- **Lógica de saltado de idioma APT** + La gestión mejorada de locale asegura compatibilidad del sistema antes de deshabilitar traducciones: + ```bash + if ! locale -a | grep -qi "^${default_locale//-/_}$"; then + echo "$default_locale UTF-8" >> /etc/locale.gen + locale-gen "$default_locale" + fi + ``` + +- **Velocidad de System Update** + Los upgrades de sistema post-install son ahora más rápidos: + - El proceso de upgrade (`dist-upgrade`) está separado de las actualizaciones de índice de plantillas de contenedor. + - El refresh de índice es ahora una función opcional seleccionada en el script. + + + +## 2025-05-27 + +### Arreglado +- **URL de ISO de Kali Linux actualizada** + Arreglada la URL de descarga incorrecta para el ISO de Kali Linux en el módulo de instalador Linux. El nuevo path correcto es: + ``` + https://cdimage.kali.org/kali-2025.1c/kali-linux-2025.1c-installer-amd64.iso + ``` + +### Mejorado +- **Transiciones de menú dialog más rápidas** + Mejorada la respuesta UI en todos los menús interactivos reemplazando `whiptail` por `dialog`, ofreciendo transiciones más rápidas y navegación más suave. + +- **Soporte Coral USB en LXC** + Mejorada la lógica para configurar passthrough de Coral USB TPU en contenedores LXC: + - Refactorizada la configuración en bloques modulares con mejor estructura y comentarios inline. + - Separación clara de la lógica de Coral USB (`/dev/coral`) y Coral M.2 (`/dev/apex_0`). + - Mantiene retrocompatibilidad con configuraciones LXC existentes. + - Introducido passthrough Coral USB persistente usando una udev rule: + ```bash + # Create udev rule for Coral USB + SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="9302", MODE="0666", TAG+="uaccess", SYMLINK+="coral" + + # Map /dev/coral if it exists + if [ -e /dev/coral ]; then + echo "lxc.mount.entry: /dev/coral dev/coral none bind,optional,create=file" >> "$CONFIG_FILE" + fi + ``` + - Gracias especiales a **@Blaspt** por validar el passthrough Coral USB persistente y por sugerir el uso del symlink `/dev/coral`. + + +### Añadido +- **Soporte de passthrough Coral USB persistente** + Añadido soporte de udev rule para dispositivos Coral USB para mapearlos persistentemente como `/dev/coral`, habilitando passthrough consistente entre reboots. Este path se detecta y mapea automáticamente en la configuración del contenedor. + +- **Integración de RSS Feed** + Añadido soporte para generar un RSS feed para el changelog, permitiendo a los usuarios mantenerse informados de updates a través de clientes de noticias. + +- **Automatización del Release Service** + Implementado un nuevo servicio de gestión de release para automatizar la publicación y tagging de versiones, empezando con la versión **v1.1.2**. + + +## 2025-05-13 + +### Arreglado + +- **Fix de startup en versiones recientes de Proxmox**\ + Arreglado un issue donde algunas instalaciones recientes de Proxmox carecían del directorio `/usr/local/bin`, causando errores al instalar el menú de ejecución. El script crea ahora el directorio si no existe antes de descargar el menú principal.\ + Gracias a **@danielmateos** por detectar y reportar este issue. + +### Mejorado + +- **Lógica de instalación de Lynis actualizada en Post-Install Settings**\ + La función `install_lynis()` se ha mejorado para instalar siempre la **última versión** de Lynis clonando el repositorio oficial de GitHub: + ``` + https://github.com/CISOfy/lynis.git + ``` + El proceso de instalación asegura ahora que siempre se obtenga la última versión y se enlace correctamente dentro del path del sistema. + + Gracias a **@Kamunhas** por reportar esta oportunidad de mejora. + +- **Optimización de memoria equilibrada para sistemas con poca memoria** + Mejorados los ajustes de memoria por defecto para soportar mejor sistemas con RAM limitada. La configuración previa podía impedir que servidores de bajas specs arrancaran. Ahora se usa un conjunto más equilibrado de parámetros de kernel, y la compactación de memoria se habilita si el sistema la soporta. + + ```bash + cat < Date: Sun, 31 May 2026 18:37:48 +0200 Subject: [PATCH 2/4] Add 4 testers to contributors page + refine deploy.yml triggers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contributors page (app/[locale]/docs/about/contributors/page.tsx): add heriberto, JF_Carr, rafapuerta and JcMinarro to the testers grid. All with the "testing" role and GitHub's default avatar URL (https://github.com/.png) so the entries work immediately without requiring custom avatar files. Swap to a per-contributor /images/avatars/.png later if/when custom artwork is ready. deploy.yml triggers: drop `guides/**` (the legacy /guides/[slug]/ page that read those markdown files was removed in PR #211 — the folder no longer affects what the web renders) and `scripts/**` (the bash scripts get rsynced into public/scripts/ during prebuild but they are downloaded by users via install_proxmenux.sh, not browsed via the doc site, so a stale copy is harmless). Add `lang/**` so future translated CHANGELOG / docs (e.g. the Spanish CHANGELOG just shipped in PR #217) auto-deploy. Local build verified: 232 pages, 14450 indexed words, no errors. Co-Authored-By: Claude Opus 4.7 --- .github/workflows/deploy.yml | 3 +-- .../[locale]/docs/about/contributors/page.tsx | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 6451d0de..d6d6bc47 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -6,8 +6,7 @@ on: - "main" paths: - "web/**" - - "guides/**" - - "scripts/**" + - "lang/**" - "CHANGELOG.md" workflow_dispatch: diff --git a/web/app/[locale]/docs/about/contributors/page.tsx b/web/app/[locale]/docs/about/contributors/page.tsx index e5cecf75..d5980fc6 100644 --- a/web/app/[locale]/docs/about/contributors/page.tsx +++ b/web/app/[locale]/docs/about/contributors/page.tsx @@ -54,6 +54,31 @@ const contributors: Contributor[] = [ roleKey: "testing", avatar: "https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/avatars/Kamunhas.png", }, + // Added 2026-05-31 after the v1.2.2 release. Defaulted to "testing" + // and GitHub's avatar service so the entries work immediately + // without needing avatar files uploaded under /images/avatars/. + // Swap to a per-contributor /images/avatars/.png once the + // custom artwork is ready. + { + name: "heriberto", + roleKey: "testing", + avatar: "https://github.com/heriberto.png", + }, + { + name: "JF_Carr", + roleKey: "testing", + avatar: "https://github.com/JF_Carr.png", + }, + { + name: "rafapuerta", + roleKey: "testing", + avatar: "https://github.com/rafapuerta.png", + }, + { + name: "JcMinarro", + roleKey: "testing", + avatar: "https://github.com/JcMinarro.png", + }, ] export default async function ContributorsPage({ params }: { params: Promise<{ locale: string }> }) { From 66262fddc8196506649a179802793f0a4a91e2e6 Mon Sep 17 00:00:00 2001 From: MacRimi Date: Sun, 31 May 2026 18:39:18 +0200 Subject: [PATCH 3/4] Contributors: switch new 4 testers to custom avatars Replace the temporary github.com/.png placeholders with the project's standard raw.githubusercontent.com/.../images/avatars/.png pattern used by every other contributor on the page. Added avatar files: - images/avatars/heriberto.png - images/avatars/JF_Carr.png (renamed from JF_Car.png on disk so the filename matches the display name) - images/avatars/rafapuerta.png - images/avatars/JcMinarro.png Co-Authored-By: Claude Opus 4.7 --- images/avatars/JF_Carr.png | Bin 0 -> 19600 bytes images/avatars/JcMinarro.png | Bin 0 -> 5124 bytes images/avatars/heriberto.png | Bin 0 -> 17529 bytes images/avatars/rafapuerta.png | Bin 0 -> 14639 bytes .../[locale]/docs/about/contributors/page.tsx | 14 +++++--------- 5 files changed, 5 insertions(+), 9 deletions(-) create mode 100644 images/avatars/JF_Carr.png create mode 100644 images/avatars/JcMinarro.png create mode 100644 images/avatars/heriberto.png create mode 100644 images/avatars/rafapuerta.png diff --git a/images/avatars/JF_Carr.png b/images/avatars/JF_Carr.png new file mode 100644 index 0000000000000000000000000000000000000000..2b2a467b296e2d3320bf4c4d206c34b5cfdc461f GIT binary patch literal 19600 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 LNkvXXu0mjfPw)B_ literal 0 HcmV?d00001 diff --git a/images/avatars/JcMinarro.png b/images/avatars/JcMinarro.png new file mode 100644 index 0000000000000000000000000000000000000000..99d8e335c79843d8f27ba063b7a41cb738493054 GIT binary patch literal 5124 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 literal 0 HcmV?d00001 diff --git a/web/app/[locale]/docs/about/contributors/page.tsx b/web/app/[locale]/docs/about/contributors/page.tsx index d5980fc6..36464bcd 100644 --- a/web/app/[locale]/docs/about/contributors/page.tsx +++ b/web/app/[locale]/docs/about/contributors/page.tsx @@ -54,30 +54,26 @@ const contributors: Contributor[] = [ roleKey: "testing", avatar: "https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/avatars/Kamunhas.png", }, - // Added 2026-05-31 after the v1.2.2 release. Defaulted to "testing" - // and GitHub's avatar service so the entries work immediately - // without needing avatar files uploaded under /images/avatars/. - // Swap to a per-contributor /images/avatars/.png once the - // custom artwork is ready. + // Added 2026-05-31 after the v1.2.2 release. { name: "heriberto", roleKey: "testing", - avatar: "https://github.com/heriberto.png", + avatar: "https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/avatars/heriberto.png", }, { name: "JF_Carr", roleKey: "testing", - avatar: "https://github.com/JF_Carr.png", + avatar: "https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/avatars/JF_Carr.png", }, { name: "rafapuerta", roleKey: "testing", - avatar: "https://github.com/rafapuerta.png", + avatar: "https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/avatars/rafapuerta.png", }, { name: "JcMinarro", roleKey: "testing", - avatar: "https://github.com/JcMinarro.png", + avatar: "https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/avatars/JcMinarro.png", }, ] From d022c4fe8133cc07298098d8e76a439372c3b8e9 Mon Sep 17 00:00:00 2001 From: MacRimi Date: Sun, 31 May 2026 18:40:36 +0200 Subject: [PATCH 4/4] Fix typo: contributor is JF_Car (one r), not JF_Carr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Last commit renamed images/avatars/JF_Car.png to JF_Carr.png on the assumption the file name was the typo. It wasn't — the user's name is actually JF_Car. Rename the file back and update the display name + avatar URL in the contributors page accordingly. Co-Authored-By: Claude Opus 4.7 --- images/avatars/{JF_Carr.png => JF_Car.png} | Bin web/app/[locale]/docs/about/contributors/page.tsx | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename images/avatars/{JF_Carr.png => JF_Car.png} (100%) diff --git a/images/avatars/JF_Carr.png b/images/avatars/JF_Car.png similarity index 100% rename from images/avatars/JF_Carr.png rename to images/avatars/JF_Car.png diff --git a/web/app/[locale]/docs/about/contributors/page.tsx b/web/app/[locale]/docs/about/contributors/page.tsx index 36464bcd..1065a285 100644 --- a/web/app/[locale]/docs/about/contributors/page.tsx +++ b/web/app/[locale]/docs/about/contributors/page.tsx @@ -61,9 +61,9 @@ const contributors: Contributor[] = [ avatar: "https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/avatars/heriberto.png", }, { - name: "JF_Carr", + name: "JF_Car", roleKey: "testing", - avatar: "https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/avatars/JF_Carr.png", + avatar: "https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/avatars/JF_Car.png", }, { name: "rafapuerta",