Merge develop into feature/oci-airdcpp

Resolve the catalog index conflict and regenerate VALIDATION.md.
This commit is contained in:
MacRimi
2026-11-03 17:47:35 +01:00
26 changed files with 2600 additions and 34 deletions
+5
View File
@@ -25,6 +25,11 @@ on:
permissions:
contents: read
# A newer push to the same branch or pull request replaces the run in progress.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
check:
runs-on: ubuntu-latest
+5
View File
@@ -112,6 +112,11 @@ on:
permissions:
contents: read
# A newer push to the same branch or pull request replaces the run in progress.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
apprise-services:
runs-on: ubuntu-latest
+5
View File
@@ -51,6 +51,11 @@ on:
permissions:
contents: read
# A newer push to the same branch or pull request replaces the run in progress.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
# Preserve this check ID for existing branch protection rules. This suite
# includes menu, download and scheduler regressions as well as i18n tests.
@@ -57,6 +57,11 @@ on:
permissions:
contents: read
# A newer push to the same branch or pull request replaces the run in progress.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
offline-python:
runs-on: ubuntu-latest
+12
View File
@@ -256,6 +256,7 @@
"Acceleration for llama.cpp": "Beschleunigung für llama.cpp",
"Accept routes from other nodes?": "Routen von anderen Knoten akzeptieren?",
"Accept this host monitoring profile?": "Akzeptieren Sie dieses Host Monitoring Profil?",
"Access Movistar and O2 Cloud from WebDAV clients and backup tools.": "Zugriff auf die Movistar- und O2-Cloud über WebDAV-Clients und Backup-Werkzeuge.",
"Access Scope:": "Zugriffsbereich:",
"Access bridge": "Zugangsbrücke",
"Access bridge for Immich": "Access Bridge für Immich",
@@ -603,6 +604,9 @@
"Audit socket disabled or not required": "Audit-Socket deaktiviert oder nicht erforderlich",
"Auth key is required.": "Authentifizierungsschlüssel ist erforderlich.",
"Auth:": "Authentifizierung:",
"Authelia Web UI": "Authelia Web-Benutzeroberfläche",
"Authelia administrator": "Authelia-Administrator",
"Authelia session cookie domain for this portal (for example example.com)": "Authelia Sitzungscookie-Domäne für dieses Portal (z. B. example.com)",
"Authentication": "Authentifizierung",
"Authentication & Security": "Authentifizierung und Sicherheit",
"Authentication Error": "Authentifizierungsfehler",
@@ -4897,6 +4901,7 @@
"Open the page of an application in the menu": "Die Seite einer Anwendung im Menü öffnen",
"Open the web address and create the first account: the daemon registers by itself and starts the first scan.": "Öffne die Webadresse und erstelle das erste Konto: Der Daemon registriert sich selbst und startet den ersten Scan.",
"Open the web address and create the password of the akadmin user in the first-run setup.": "Öffnen Sie die Webadresse und erstellen Sie im ersten Setup das Passwort des akadmin-Benutzers.",
"Open the web dashboard and link your Movistar/O2 account using its SMS flow.": "Öffnen Sie das Web-Dashboard und verknüpfen Sie Ihr Movistar/O2-Konto über die SMS-Bestätigung.",
"Open-source AI-powered coding assistant": "Open-Source AI-powered Coding Assistant",
"Open-source UI for building and debugging multi-agent and RAG applications": "Open-Source-Benutzeroberfläche zum Erstellen und Debuggen von Multi-Agenten- und RAG-Anwendungen",
"Open-source in-memory data store.": "Open-Source-Datenspeicher im Arbeitsspeicher.",
@@ -5396,6 +5401,7 @@
"Proxmox web interface: Datacenter > Storage > Add > ZFS": "Proxmox-Weboberfläche: Datencenter > Speicher > Hinzufügen > ZFS",
"Proxmox web interface: Datacenter > Storage > Add > iSCSI": "Proxmox-Weboberfläche: Rechenzentrum > Speicher > Hinzufügen > iSCSI",
"Proxy address to reach the API (optional)": "Proxy-Adresse zum Erreichen der API (optional)",
"Public HTTPS URL used to open this Authelia portal (for example https://auth.example.com)": "Öffentliche HTTPS-URL, die zum Öffnen dieses Authelia-Portals verwendet wird (zum Beispiel https://auth.example.com)",
"Public UDP port clients connect to": "Öffentliche UDP Port Clients verbinden sich mit",
"Public UDP port peers connect to": "Öffentliche UDP-Port Peers verbinden sich mit",
"Public URL of phpMyAdmin when it is served behind a reverse proxy": "Öffentliche URL von phpMyAdmin, wenn sie hinter einem Reverse-Proxy bereitgestellt wird",
@@ -6453,6 +6459,7 @@
"Simple and easy to use DDNS": "Einfach und einfach zu bedienen DDNS",
"Simple self-hosted file sharing.": "Einfacher, selbst gehosteter Dateiaustausch.",
"Single GPU Warning": "Warnung vor einer einzelnen GPU",
"Single sign-on and multi-factor authentication": "Single Sign-On und Multi-Faktor-Authentifizierung",
"Single target found — selected automatically:": "Einzelnes Ziel gefunden – automatisch ausgewählt:",
"Single-node log storage and query UI.": "Logspeicher mit Abfrageoberfläche für einen einzelnen Knoten.",
"Single-node observability database for metrics, logs and traces.": "Einzelknoten-Datenbank für Metriken, Protokolle und Traces.",
@@ -8202,12 +8209,17 @@
"Web access": "Webzugang",
"Web address of the AdGuard Home that receives the settings (e.g. http://192.168.1.3)": "Webadresse des AdGuard Home, der die Einstellungen erhält (z. B. http://192.168.1.3)",
"Web address of the main AdGuard Home, whose settings are copied (e.g. http://192.168.1.2)": "Webadresse des AdGuard Home, dessen Einstellungen kopiert sind (z. B. http://192.168.1.2)",
"Web dashboard": "Web-Dashboard",
"Web dashboard and WebDAV": "Web-Dashboard und WebDAV",
"Web interface": "Weboberfläche",
"Web interface for Borg Backup repositories and jobs.": "Weboberfläche für Borg-Backup-Repositories und -Jobs.",
"Web interface for managing 3D printers.": "Weboberfläche zur Verwaltung von 3D-Druckern.",
"Web interface to manage devices running Tasmota firmware.": "Web-Schnittstelle zur Verwaltung von Geräten mit Tasmota-Firmware.",
"Web reverse proxy with an administration interface.": "Web-Reverse-Proxy mit Administrationsoberfläche.",
"WebCord can be summarized as a pack of security and privacy hardenings, Discord features reimplementations, Electron / Chromium / Discord bugs workarounds, stylesheets, internal pages and wrapped https://discord.com page, designed to conform with ToS as much as it is possible (or hide the changes that might violate it from Discord's eyes).": "WebCord kann als ein Paket von Sicherheits- und Datenschutz-Härtungen, Discord-Features-Reimplementierungen, Electron / Chromium / Discord-Bugs-Workarounds, Stylesheets, interne Seiten und verpackte https://discord.com-Seite zusammengefasst werden, die so weit wie möglich mit ToS konform sind (oder die Änderungen, die es verletzen könnten, vor Discords Augen verbergen).",
"WebDAV": "WebDAV",
"WebDAV and dashboard password (leave empty to generate)": "Passwort für WebDAV und Dashboard (leer = generiert)",
"WebDAV is available on container port 8080. Account linking is required before cloud file operations.": "WebDAV ist auf Port 8080 des Containers verfügbar. Vor Dateioperationen in der Cloud muss das Konto verknüpft werden.",
"Webgrabplus is a multi-site incremental xmltv epg grabber. It collects tv-program guide data from selected tvguide sites for your favourite channels.": "Webgrabplus ist ein multi-site inkrementeller xmltv epg grabber. Es sammelt tv-programm-guide-daten von ausgewählten tvguide-seiten für ihre lieblingskanäle.",
"Webservers & Proxies": "Webserver und Proxys",
"Website": "Webseite",
+12
View File
@@ -255,6 +255,7 @@
"Acceleration for llama.cpp": "Aceleración para llama.cpp",
"Accept routes from other nodes?": "¿Aceptar rutas de otros nodos?",
"Accept this host monitoring profile?": "¿Aceptar este perfil de monitorización del host?",
"Access Movistar and O2 Cloud from WebDAV clients and backup tools.": "Accede a la nube de Movistar y O2 desde clientes WebDAV y herramientas de backup.",
"Access Scope:": "Ámbito de acceso:",
"Access bridge": "Puente de acceso",
"Access bridge for Immich": "Puente de acceso para Immich",
@@ -601,6 +602,9 @@
"Audit socket disabled or not required": "Socket de auditoría deshabilitado o no requerido",
"Auth key is required.": "Se requiere clave de autenticación.",
"Auth:": "Autenticación:",
"Authelia Web UI": "Authelia Interfaz de usuario web",
"Authelia administrator": "administrador Authelia",
"Authelia session cookie domain for this portal (for example example.com)": "dominio de cookie de sesión Authelia para este portal (por ejemplo, ejemplo.com)",
"Authentication": "Autenticación",
"Authentication & Security": "Authentication & Security",
"Authentication Error": "Error de autenticación",
@@ -4888,6 +4892,7 @@
"Open the page of an application in the menu": "Abrir la página de una aplicación en el menú",
"Open the web address and create the first account: the daemon registers by itself and starts the first scan.": "Abre la dirección web y crea la primera cuenta: el daemon se registra solo y empieza el primer escaneo.",
"Open the web address and create the password of the akadmin user in the first-run setup.": "abra la dirección web y cree la contraseña del usuario akaadmin en la configuración de primera ejecución.",
"Open the web dashboard and link your Movistar/O2 account using its SMS flow.": "Abre el panel web y vincula tu cuenta de Movistar/O2 con su verificación por SMS.",
"Open-source AI-powered coding assistant": "Asistente de programación con IA de código abierto",
"Open-source UI for building and debugging multi-agent and RAG applications": "Interfaz de código abierto para crear y depurar aplicaciones multiagente y RAG",
"Open-source in-memory data store.": "Almacén de datos en memoria de código abierto.",
@@ -5386,6 +5391,7 @@
"Proxmox web interface: Datacenter > Storage > Add > ZFS": "Interfaz web de Proxmox: Datacenter > Storage > Add > ZFS",
"Proxmox web interface: Datacenter > Storage > Add > iSCSI": "Interfaz web de Proxmox: Datacenter > Storage > Add > iSCSI",
"Proxy address to reach the API (optional)": "Dirección del proxy para llegar a la API (opcional)",
"Public HTTPS URL used to open this Authelia portal (for example https://auth.example.com)": "URL HTTPS pública utilizada para abrir este portal Authelia (por ejemplo, https://auth.example.com)",
"Public UDP port clients connect to": "Puerto UDP público al que se conectan los clientes",
"Public UDP port peers connect to": "Puerto UDP público al que se conectan los peers",
"Public URL of phpMyAdmin when it is served behind a reverse proxy": "URL pública de phpMyAdmin cuando se sirve detrás de un proxy inverso",
@@ -6436,6 +6442,7 @@
"Simple and easy to use DDNS": "DDNS simple y fácil de usar",
"Simple self-hosted file sharing.": "Servicio sencillo y autoalojado para compartir archivos.",
"Single GPU Warning": "Advertencia de GPU única",
"Single sign-on and multi-factor authentication": "inicio de sesión único y autenticación multifactor",
"Single target found — selected automatically:": "Destino único encontrado: seleccionado automáticamente:",
"Single-node log storage and query UI.": "Almacenamiento de logs para un solo nodo con interfaz de consulta.",
"Single-node observability database for metrics, logs and traces.": "Base de datos de observabilidad de un solo nodo para métricas, registros y trazas.",
@@ -8175,12 +8182,17 @@
"Web access": "Acceso web",
"Web address of the AdGuard Home that receives the settings (e.g. http://192.168.1.3)": "Dirección web del AdGuard Home que recibe los ajustes (por ejemplo, http://192.168.1.3)",
"Web address of the main AdGuard Home, whose settings are copied (e.g. http://192.168.1.2)": "Dirección web del AdGuard Home principal, cuyos ajustes se copian (por ejemplo, http://192.168.1.2)",
"Web dashboard": "Panel web",
"Web dashboard and WebDAV": "Panel web y WebDAV",
"Web interface": "interfaz web",
"Web interface for Borg Backup repositories and jobs.": "Interfaz web para gestionar repositorios y tareas de Borg Backup.",
"Web interface for managing 3D printers.": "Interfaz web para gestionar impresoras 3D.",
"Web interface to manage devices running Tasmota firmware.": "Interfaz web para gestionar dispositivos con firmware Tasmota.",
"Web reverse proxy with an administration interface.": "Proxy inverso web con interfaz de administración.",
"WebCord can be summarized as a pack of security and privacy hardenings, Discord features reimplementations, Electron / Chromium / Discord bugs workarounds, stylesheets, internal pages and wrapped https://discord.com page, designed to conform with ToS as much as it is possible (or hide the changes that might violate it from Discord's eyes).": "WebCord puede resumirse como un conjunto de medidas de hardening de seguridad y privacidad, reimplementaciones de funciones de Discord, soluciones a fallos de Electron / Chromium / Discord, hojas de estilo, páginas internas y la página https://discord.com encapsulada, diseñado para cumplir los ToS en lo posible (u ocultar a Discord los cambios que podrían incumplirlos).",
"WebDAV": "WebDAV",
"WebDAV and dashboard password (leave empty to generate)": "Contraseña de WebDAV y del panel (vacío = generada)",
"WebDAV is available on container port 8080. Account linking is required before cloud file operations.": "WebDAV está disponible en el puerto 8080 del contenedor. Hay que vincular la cuenta antes de trabajar con los archivos de la nube.",
"Webgrabplus is a multi-site incremental xmltv epg grabber. It collects tv-program guide data from selected tvguide sites for your favourite channels.": "Webgrabplus es un capturador incremental de EPG xmltv para múltiples sitios. Recoge los datos de la guía de programación de los sitios de guías de TV seleccionados para tus canales favoritos.",
"Webservers & Proxies": "Webservers & Proxies",
"Website": "Sitio web",
+12
View File
@@ -256,6 +256,7 @@
"Acceleration for llama.cpp": "Accélération pour llama.cpp",
"Accept routes from other nodes?": "Accepter les routes d'autres nœuds ?",
"Accept this host monitoring profile?": "Accepter ce profil de surveillance de l'hôte?",
"Access Movistar and O2 Cloud from WebDAV clients and backup tools.": "Accédez au cloud Movistar et O2 depuis des clients WebDAV et des outils de sauvegarde.",
"Access Scope:": "Portée d'accès :",
"Access bridge": "Pont d'accès",
"Access bridge for Immich": "Pont d'accès pour Immich",
@@ -603,6 +604,9 @@
"Audit socket disabled or not required": "Socket d'audit désactivé ou non requis",
"Auth key is required.": "La clé d'authentification est requise.",
"Auth:": "Authentification :",
"Authelia Web UI": "interface utilisateur Web Authelia",
"Authelia administrator": "Administrateur Authelia",
"Authelia session cookie domain for this portal (for example example.com)": "domaine de cookie de session Authelia pour ce portail (par exemple exemple.com)",
"Authentication": "Authentification",
"Authentication & Security": "Authentification et sécurité",
"Authentication Error": "Erreur d'authentification",
@@ -4897,6 +4901,7 @@
"Open the page of an application in the menu": "Ouvrir la page d'une application dans le menu",
"Open the web address and create the first account: the daemon registers by itself and starts the first scan.": "Ouvrez l'adresse web et créez le premier compte : le daemon s'enregistre tout seul et lance la première analyse.",
"Open the web address and create the password of the akadmin user in the first-run setup.": "ouvrez l'adresse Web et créez le mot de passe de l'utilisateur akadmin lors de la configuration de première exécution.",
"Open the web dashboard and link your Movistar/O2 account using its SMS flow.": "Ouvrez le tableau de bord web et liez votre compte Movistar/O2 avec sa vérification par SMS.",
"Open-source AI-powered coding assistant": "Assistant de codage à source ouverte",
"Open-source UI for building and debugging multi-agent and RAG applications": "UI open-source pour la construction et le débogage d'applications multi-agents et RAG",
"Open-source in-memory data store.": "Magasin de données en mémoire libre.",
@@ -5396,6 +5401,7 @@
"Proxmox web interface: Datacenter > Storage > Add > ZFS": "Interface web Proxmox : Datacenter > Stockage > Ajouter > ZFS",
"Proxmox web interface: Datacenter > Storage > Add > iSCSI": "Interface Web Proxmox : Datacenter > Stockage > Ajouter > iSCSI",
"Proxy address to reach the API (optional)": "Adresse proxy pour accéder à l'API (facultatif)",
"Public HTTPS URL used to open this Authelia portal (for example https://auth.example.com)": "URL HTTPS publique utilisée pour ouvrir ce portail Authelia (par exemple https://auth.example.com)",
"Public UDP port clients connect to": "Les clients du port UDP public se connectent à",
"Public UDP port peers connect to": "Les pairs du port UDP public se connectent à",
"Public URL of phpMyAdmin when it is served behind a reverse proxy": "URL publique de phpMyAdmin quand elle est servie derrière un proxy inversé",
@@ -6453,6 +6459,7 @@
"Simple and easy to use DDNS": "Simple et facile à utiliser DDNS",
"Simple self-hosted file sharing.": "Service simple et auto-hébergé de partage de fichiers.",
"Single GPU Warning": "Avertissement sur un seul GPU",
"Single sign-on and multi-factor authentication": "authentification unique et authentification multifacteur",
"Single target found — selected automatically:": "Cible unique trouvée — sélectionnée automatiquement :",
"Single-node log storage and query UI.": "Stockage de journaux sur un nœud unique avec interface de requête.",
"Single-node observability database for metrics, logs and traces.": "Base de données d’observabilité à nœud unique pour les métriques, les journaux et les traces.",
@@ -8201,12 +8208,17 @@
"Web access": "Accès au Web",
"Web address of the AdGuard Home that receives the settings (e.g. http://192.168.1.3)": "Adresse Web du AdGuard Home qui reçoit les paramètres (p. ex. http://192.168.1.3)",
"Web address of the main AdGuard Home, whose settings are copied (e.g. http://192.168.1.2)": "Adresse Web du principal AdGuard Home, dont les paramètres sont copiés (par exemple http://192.168.1.2)",
"Web dashboard": "Tableau de bord web",
"Web dashboard and WebDAV": "Tableau de bord web et WebDAV",
"Web interface": "interface Web",
"Web interface for Borg Backup repositories and jobs.": "Interface web pour les dépôts et tâches Borg Backup.",
"Web interface for managing 3D printers.": "Interface web de gestion des imprimantes 3D.",
"Web interface to manage devices running Tasmota firmware.": "Interface Web pour gérer les appareils utilisant le firmware Tasmota.",
"Web reverse proxy with an administration interface.": "Proxy inverse web doté d’une interface d’administration.",
"WebCord can be summarized as a pack of security and privacy hardenings, Discord features reimplementations, Electron / Chromium / Discord bugs workarounds, stylesheets, internal pages and wrapped https://discord.com page, designed to conform with ToS as much as it is possible (or hide the changes that might violate it from Discord's eyes).": "WebCord peut être résumé comme un paquet de durcissements de sécurité et de confidentialité, les fonctionnalités Discord réimplémentations, Electron / Chromium / Discord bugs workarounds, les feuilles de style, les pages internes et la page https://discord.com enveloppée, conçue pour se conformer à ToS autant qu'il est possible (ou cacher les changements qui pourraient la violer des yeux de Discord).",
"WebDAV": "WebDAV",
"WebDAV and dashboard password (leave empty to generate)": "Mot de passe WebDAV et du tableau de bord (vide = généré)",
"WebDAV is available on container port 8080. Account linking is required before cloud file operations.": "WebDAV est disponible sur le port 8080 du conteneur. Le compte doit être lié avant toute opération sur les fichiers du cloud.",
"Webgrabplus is a multi-site incremental xmltv epg grabber. It collects tv-program guide data from selected tvguide sites for your favourite channels.": "Webgrabplus est un accrocheur différentiel multisite xmltv egg. Il recueille les données du guide TV-programme à partir de sites sélectionnés pour vos chaînes préférées.",
"Webservers & Proxies": "Serveurs web et proxys",
"Website": "Site web",
+12
View File
@@ -256,6 +256,7 @@
"Acceleration for llama.cpp": "Accelerazione per llama.cpp",
"Accept routes from other nodes?": "Accettare rotte da altri nodi?",
"Accept this host monitoring profile?": "Accettare questo profilo di monitoraggio host?",
"Access Movistar and O2 Cloud from WebDAV clients and backup tools.": "Accedi al cloud di Movistar e O2 da client WebDAV e strumenti di backup.",
"Access Scope:": "Ambito di accesso:",
"Access bridge": "Bridge di accesso",
"Access bridge for Immich": "Bridge di accesso per Immich",
@@ -603,6 +604,9 @@
"Audit socket disabled or not required": "Socket di audit disabilitato o non richiesto",
"Auth key is required.": "È richiesta la chiave di autenticazione.",
"Auth:": "Autenticazione:",
"Authelia Web UI": "interfaccia utente Web Authelia",
"Authelia administrator": "amministratore Authelia",
"Authelia session cookie domain for this portal (for example example.com)": "dominio del cookie di sessione Authelia per questo portale (ad esempio example.com)",
"Authentication": "Autenticazione",
"Authentication & Security": "Autenticazione e sicurezza",
"Authentication Error": "Errore di autenticazione",
@@ -4897,6 +4901,7 @@
"Open the page of an application in the menu": "Apri la pagina di un'applicazione nel menu",
"Open the web address and create the first account: the daemon registers by itself and starts the first scan.": "Apri l'indirizzo web e crea il primo account: il daemon si registra da solo e avvia la prima scansione.",
"Open the web address and create the password of the akadmin user in the first-run setup.": "Apri l'indirizzo web e imposta la password dell'utente akadmin durante la configurazione iniziale.",
"Open the web dashboard and link your Movistar/O2 account using its SMS flow.": "Apri la dashboard web e collega il tuo account Movistar/O2 con la verifica tramite SMS.",
"Open-source AI-powered coding assistant": "Assistente open source per la programmazione basato sull'IA",
"Open-source UI for building and debugging multi-agent and RAG applications": "Interfaccia open source per creare ed eseguire il debug di applicazioni multiagente e RAG",
"Open-source in-memory data store.": "Archivio dati in memoria open source.",
@@ -5396,6 +5401,7 @@
"Proxmox web interface: Datacenter > Storage > Add > ZFS": "Interfaccia web Proxmox: Datacenter > Storage > Aggiungi > ZFS",
"Proxmox web interface: Datacenter > Storage > Add > iSCSI": "Interfaccia web Proxmox: Datacenter > Storage > Aggiungi > iSCSI",
"Proxy address to reach the API (optional)": "Indirizzo proxy per raggiungere l'API (facoltativo)",
"Public HTTPS URL used to open this Authelia portal (for example https://auth.example.com)": "URL HTTPS pubblico utilizzato per aprire questo portale Authelia (ad esempio https://auth.example.com)",
"Public UDP port clients connect to": "Porta UDP pubblica a cui si connettono i client",
"Public UDP port peers connect to": "Porta UDP pubblica a cui si connettono i peer",
"Public URL of phpMyAdmin when it is served behind a reverse proxy": "URL pubblico di phpMyAdmin quando viene servito dietro un proxy inverso",
@@ -6453,6 +6459,7 @@
"Simple and easy to use DDNS": "DDNS semplice e facile da usare",
"Simple self-hosted file sharing.": "Servizio semplice e self-hosted per condividere file.",
"Single GPU Warning": "Avviso GPU singola",
"Single sign-on and multi-factor authentication": "Single Sign-On e autenticazione a più fattori",
"Single target found — selected automatically:": "Unica destinazione trovata - selezionata automaticamente:",
"Single-node log storage and query UI.": "Archiviazione dei log su un singolo nodo e interfaccia di interrogazione.",
"Single-node observability database for metrics, logs and traces.": "Database di osservabilità a nodo singolo per metriche, log e tracce.",
@@ -8202,12 +8209,17 @@
"Web access": "Accesso web",
"Web address of the AdGuard Home that receives the settings (e.g. http://192.168.1.3)": "Indirizzo web dell'istanza AdGuard Home che riceve le impostazioni (ad es. http://192.168.1.3)",
"Web address of the main AdGuard Home, whose settings are copied (e.g. http://192.168.1.2)": "Indirizzo web dell'istanza AdGuard Home principale, da cui vengono copiate le impostazioni (ad es. http://192.168.1.2)",
"Web dashboard": "Dashboard web",
"Web dashboard and WebDAV": "Dashboard web e WebDAV",
"Web interface": "Interfaccia web",
"Web interface for Borg Backup repositories and jobs.": "Interfaccia web per repository e job di Borg Backup.",
"Web interface for managing 3D printers.": "Interfaccia web per gestire stampanti 3D.",
"Web interface to manage devices running Tasmota firmware.": "Interfaccia web per gestire dispositivi con firmware Tasmota.",
"Web reverse proxy with an administration interface.": "Proxy inverso web con interfaccia di amministrazione.",
"WebCord can be summarized as a pack of security and privacy hardenings, Discord features reimplementations, Electron / Chromium / Discord bugs workarounds, stylesheets, internal pages and wrapped https://discord.com page, designed to conform with ToS as much as it is possible (or hide the changes that might violate it from Discord's eyes).": "WebCord comprende miglioramenti alla sicurezza e alla privacy, reimplementazioni di funzioni di Discord, soluzioni alternative ai bug di Electron, Chromium e Discord, fogli di stile, pagine interne e la pagina https://discord.com incapsulata. È progettato per rispettare i termini di servizio per quanto possibile (o nascondere a Discord le modifiche che potrebbero violarli).",
"WebDAV": "WebDAV",
"WebDAV and dashboard password (leave empty to generate)": "Password di WebDAV e della dashboard (campo vuoto = generata)",
"WebDAV is available on container port 8080. Account linking is required before cloud file operations.": "WebDAV è disponibile sulla porta 8080 del container. Prima di operare sui file del cloud bisogna collegare l'account.",
"Webgrabplus is a multi-site incremental xmltv epg grabber. It collects tv-program guide data from selected tvguide sites for your favourite channels.": "Webgrabplus acquisisce dati EPG XMLTV incrementalmente da più siti. Raccoglie le guide TV dai siti selezionati per i canali preferiti.",
"Webservers & Proxies": "Server web e proxy",
"Website": "Sito web",
+12
View File
@@ -256,6 +256,7 @@
"Acceleration for llama.cpp": "Aceleração para llama.cpp",
"Accept routes from other nodes?": "Aceita rotas de outros nós?",
"Accept this host monitoring profile?": "Aceita este perfil de monitorização da máquina?",
"Access Movistar and O2 Cloud from WebDAV clients and backup tools.": "Acesse a nuvem da Movistar e da O2 a partir de clientes WebDAV e ferramentas de backup.",
"Access Scope:": "Escopo de acesso:",
"Access bridge": "Ponte de acesso",
"Access bridge for Immich": "Ponte de acesso para Immich",
@@ -603,6 +604,9 @@
"Audit socket disabled or not required": "soquete de auditoria desabilitado ou não necessário",
"Auth key is required.": "A chave de autenticação é obrigatória.",
"Auth:": "Autenticação:",
"Authelia Web UI": "UI da Web Authelia",
"Authelia administrator": "administrador Authelia",
"Authelia session cookie domain for this portal (for example example.com)": "domínio de cookie de sessão Authelia para este portal (por exemplo example.com)",
"Authentication": "Autenticação",
"Authentication & Security": "Autenticação e segurança",
"Authentication Error": "Erro de autenticação",
@@ -4897,6 +4901,7 @@
"Open the page of an application in the menu": "Abrir a página de uma aplicação no menu",
"Open the web address and create the first account: the daemon registers by itself and starts the first scan.": "Abra o endereço web e crie a primeira conta: o daemon regista-se sozinho e inicia a primeira análise.",
"Open the web address and create the password of the akadmin user in the first-run setup.": "Abra o endereço da web e crie a senha do usuário akadmin na configuração inicial.",
"Open the web dashboard and link your Movistar/O2 account using its SMS flow.": "Abra o painel web e vincule sua conta Movistar/O2 com a verificação por SMS.",
"Open-source AI-powered coding assistant": "Assistente de codificação com código aberto",
"Open-source UI for building and debugging multi-agent and RAG applications": "UI de código aberto para a construção e depuração de aplicações multi-agente e RAG",
"Open-source in-memory data store.": "Armazenamento de dados em memória de código aberto.",
@@ -5396,6 +5401,7 @@
"Proxmox web interface: Datacenter > Storage > Add > ZFS": "Interface web Proxmox: Datacenter > Armazenamento > Adicionar > ZFS",
"Proxmox web interface: Datacenter > Storage > Add > iSCSI": "Interface web Proxmox: Datacenter > Armazenamento > Adicionar > iSCSI",
"Proxy address to reach the API (optional)": "Endereço proxy para acessar a API (opcional)",
"Public HTTPS URL used to open this Authelia portal (for example https://auth.example.com)": "URL HTTPS público usado para abrir este portal Authelia (por exemplo https://auth.example.com)",
"Public UDP port clients connect to": "Clientes públicos de porta UDP se conectam",
"Public UDP port peers connect to": "Os pares públicos de portas UDP se conectam",
"Public URL of phpMyAdmin when it is served behind a reverse proxy": "URL público do phpMyAdmin quando é servido por trás de um proxy reverso",
@@ -6453,6 +6459,7 @@
"Simple and easy to use DDNS": "Simples e fácil de usar DDNS",
"Simple self-hosted file sharing.": "Serviço simples e autoalojado para partilha de ficheiros.",
"Single GPU Warning": "Aviso de GPU única",
"Single sign-on and multi-factor authentication": "login único e autenticação multifator",
"Single target found — selected automatically:": "Único alvo encontrado — selecionado automaticamente:",
"Single-node log storage and query UI.": "Armazenamento de logs para um único nó com interface de consulta.",
"Single-node observability database for metrics, logs and traces.": "Banco de dados de observabilidade de nó único para métricas, logs e traces.",
@@ -8202,12 +8209,17 @@
"Web access": "Acesso à Internet",
"Web address of the AdGuard Home that receives the settings (e.g. http://192.168.1.3)": "Endereço Web do AdGuard Home que recebe as definições (por exemplo, http://192.168.1.3)",
"Web address of the main AdGuard Home, whose settings are copied (e.g. http://192.168.1.2)": "Endereço Web do AdGuard Home principal, cujas configurações são copiadas (por exemplo, http://192.168.1.2)",
"Web dashboard": "Painel web",
"Web dashboard and WebDAV": "Painel web e WebDAV",
"Web interface": "Interface da Web",
"Web interface for Borg Backup repositories and jobs.": "Interface web para gerenciar repositórios e tarefas do Borg Backup.",
"Web interface for managing 3D printers.": "Interface web para gerenciar impressoras 3D.",
"Web interface to manage devices running Tasmota firmware.": "Interface Web para gerenciar dispositivos rodando firmware Tasmota.",
"Web reverse proxy with an administration interface.": "Proxy reverso web com interface de administração.",
"WebCord can be summarized as a pack of security and privacy hardenings, Discord features reimplementations, Electron / Chromium / Discord bugs workarounds, stylesheets, internal pages and wrapped https://discord.com page, designed to conform with ToS as much as it is possible (or hide the changes that might violate it from Discord's eyes).": "WebCord pode ser resumido como um pacote de endurecimentos de segurança e privacidade, recursos de discórdia reimplementações, Electron / Chromium / Erros de discórdia workarounds, stylesheets, páginas internas e página envolto https://discord.com, projetado para se conformar com ToS tanto quanto possível (ou ocultar as alterações que podem violá-lo dos olhos da Discord).",
"WebDAV": "WebDAV",
"WebDAV and dashboard password (leave empty to generate)": "Senha do WebDAV e do painel (vazio = gerada)",
"WebDAV is available on container port 8080. Account linking is required before cloud file operations.": "O WebDAV está disponível na porta 8080 do contêiner. É preciso vincular a conta antes de operar com os arquivos da nuvem.",
"Webgrabplus is a multi-site incremental xmltv epg grabber. It collects tv-program guide data from selected tvguide sites for your favourite channels.": "Webgrabplus é um multi-site incremental xmltv epg grabber. Ele coleta dados de guias de tv-programa de sites selecionados para seus canais favoritos.",
"Webservers & Proxies": "Servidores web e proxies",
"Website": "Site",
+12
View File
@@ -256,6 +256,7 @@
"Acceleration for llama.cpp": "Zrýchlenie pre llama.cpp",
"Accept routes from other nodes?": "Prijímať trasy z iných uzlov?",
"Accept this host monitoring profile?": "Prijať tento profil monitorovania hostiteľa?",
"Access Movistar and O2 Cloud from WebDAV clients and backup tools.": "Prístup ku cloudu Movistar a O2 z klientov WebDAV a nástrojov na zálohovanie.",
"Access Scope:": "Rozsah prístupu:",
"Access bridge": "Sieťový most (bridge)",
"Access bridge for Immich": "Sieťový most (bridge) pre Immich",
@@ -603,6 +604,9 @@
"Audit socket disabled or not required": "Zásuvka auditu je zakázaná alebo sa nevyžaduje",
"Auth key is required.": "Auth key je povinný.",
"Auth:": "Prihlásenie:",
"Authelia Web UI": "Webové rozhranie Authelia",
"Authelia administrator": "Správca Authelia",
"Authelia session cookie domain for this portal (for example example.com)": "Doména súboru cookie relácie Authelia pre tento portál (napríklad example.com)",
"Authentication": "Prihlásenie",
"Authentication & Security": "Overovanie a zabezpečenie",
"Authentication Error": "Chyba prihlásenia",
@@ -4899,6 +4903,7 @@
"Open the page of an application in the menu": "Otvoriť stránku aplikácie v ponuke",
"Open the web address and create the first account: the daemon registers by itself and starts the first scan.": "Otvorte webovú adresu a vytvorte prvé konto: daemon sa zaregistruje sám a spustí prvé skenovanie.",
"Open the web address and create the password of the akadmin user in the first-run setup.": "Otvorte webovú adresu a v prvotnom nastavení vytvorte heslo používateľa akadmin.",
"Open the web dashboard and link your Movistar/O2 account using its SMS flow.": "Otvorte webový panel a prepojte svoj účet Movistar/O2 pomocou overenia cez SMS.",
"Open-source AI-powered coding assistant": "Programátorský asistent využívajúci AI s otvoreným zdrojovým kódom",
"Open-source UI for building and debugging multi-agent and RAG applications": "Rozhranie s otvoreným zdrojovým kódom na tvorbu a ladenie aplikácií s viacerými agentmi a RAG",
"Open-source in-memory data store.": "Úložisko údajov v pamäti s otvoreným zdrojovým kódom.",
@@ -5398,6 +5403,7 @@
"Proxmox web interface: Datacenter > Storage > Add > ZFS": "Webové rozhranie Proxmoxu: Datacenter > Storage > Add > ZFS",
"Proxmox web interface: Datacenter > Storage > Add > iSCSI": "Webové rozhranie Proxmoxu: Datacenter > Storage > Add > iSCSI",
"Proxy address to reach the API (optional)": "Adresa proxy na prístup k API (voliteľné)",
"Public HTTPS URL used to open this Authelia portal (for example https://auth.example.com)": "Verejná adresa HTTPS na otvorenie tohto portálu Authelia (napríklad https://auth.example.com)",
"Public UDP port clients connect to": "Verejný port UDP na pripojenie klientov",
"Public UDP port peers connect to": "Verejný port UDP na pripojenie účastníkov",
"Public URL of phpMyAdmin when it is served behind a reverse proxy": "Verejné URL phpMyAdmin, keď sa podáva za reverzným proxy",
@@ -6455,6 +6461,7 @@
"Simple and easy to use DDNS": "Jednoducho použiteľné dynamické DNS (DDNS)",
"Simple self-hosted file sharing.": "Jednoduchá samohostovaná služba na zdieľanie súborov.",
"Single GPU Warning": "Upozornenie na jednu GPU",
"Single sign-on and multi-factor authentication": "Jednotné prihlásenie a viacfaktorové overovanie",
"Single target found — selected automatically:": "Našiel sa jeden target - vybraný automaticky:",
"Single-node log storage and query UI.": "Úložisko logov a vyhľadávacie rozhranie pre jeden uzol.",
"Single-node observability database for metrics, logs and traces.": "Databáza na jednom uzle na ukladanie metrík, logov a záznamov o priebehu požiadaviek.",
@@ -8202,12 +8209,17 @@
"Web access": "Adresa webového rozhrania",
"Web address of the AdGuard Home that receives the settings (e.g. http://192.168.1.3)": "Webová adresa AdGuard Home, ktorá prijíma nastavenia (napr. http://192.168.1.3)",
"Web address of the main AdGuard Home, whose settings are copied (e.g. http://192.168.1.2)": "Webová adresa hlavného AdGuard Home, ktorého nastavenia sú kopírované (napr. http://192.168.1.2)",
"Web dashboard": "Webový panel",
"Web dashboard and WebDAV": "Webový panel a WebDAV",
"Web interface": "Webové rozhranie",
"Web interface for Borg Backup repositories and jobs.": "Webové rozhranie na správu úložísk a úloh Borg Backup.",
"Web interface for managing 3D printers.": "Webové rozhranie na správu 3D tlačiarní.",
"Web interface to manage devices running Tasmota firmware.": "Webové rozhranie pre správu zariadení bežiacich na Tasmota firmware.",
"Web reverse proxy with an administration interface.": "Webový reverzný proxy server s administračným rozhraním.",
"WebCord can be summarized as a pack of security and privacy hardenings, Discord features reimplementations, Electron / Chromium / Discord bugs workarounds, stylesheets, internal pages and wrapped https://discord.com page, designed to conform with ToS as much as it is possible (or hide the changes that might violate it from Discord's eyes).": "WebCord je klient obklopujúci stránku https://discord.com, ktorý zlepšuje bezpečnosť a súkromie, upravuje funkcie Discordu, obchádza chyby Electronu, Chromia a Discordu a pridáva štýly aj interné stránky. Snaží sa čo najviac dodržiavať podmienky používania alebo skryť pred Discordom úpravy, ktoré by ich mohli porušovať.",
"WebDAV": "WebDAV",
"WebDAV and dashboard password (leave empty to generate)": "Heslo pre WebDAV a panel (prázdne = generované)",
"WebDAV is available on container port 8080. Account linking is required before cloud file operations.": "WebDAV je dostupný na porte 8080 kontajnera. Pred prácou so súbormi v cloude je potrebné prepojiť účet.",
"Webgrabplus is a multi-site incremental xmltv epg grabber. It collects tv-program guide data from selected tvguide sites for your favourite channels.": "WebGrab+Plus priebežne získava elektronický programový sprievodca (EPG) vo formáte XMLTV z viacerých webov. Zhromažďuje televízny program vybraných staníc z podporovaných stránok.",
"Webservers & Proxies": "Webové servery a proxy",
"Website": "Webová stránka",
+11
View File
@@ -256,6 +256,7 @@
"Acceleration for llama.cpp": "Acceleration för llama.cpp",
"Accept routes from other nodes?": "Acceptera rutter från andra noder?",
"Accept this host monitoring profile?": "Acceptera denna värdövervakningsprofil?",
"Access Movistar and O2 Cloud from WebDAV clients and backup tools.": "Kom åt Movistar- och O2-molnet från WebDAV-klienter och säkerhetskopieringsverktyg.",
"Access Scope:": "Åtkomstomfång:",
"Access bridge": "Tillgång bridge",
"Access bridge for Immich": "Tillgångsbro för Immich",
@@ -603,6 +604,8 @@
"Audit socket disabled or not required": "Granskningsuttaget inaktiverat eller inte nödvändigt",
"Auth key is required.": "Auth-nyckel krävs.",
"Auth:": "Auth:",
"Authelia administrator": "Authelia administratör",
"Authelia session cookie domain for this portal (for example example.com)": "Authelia sessionscookiedomän för denna portal (till exempel example.com)",
"Authentication": "Autentisering",
"Authentication & Security": "Autentisering och säkerhet",
"Authentication Error": "Autentiseringsfel",
@@ -4897,6 +4900,7 @@
"Open the page of an application in the menu": "Öppna en applikations sida i menyn",
"Open the web address and create the first account: the daemon registers by itself and starts the first scan.": "Öppna webbadressen och skapa det första kontot: daemonen registrerar sig själv och startar den första skanningen.",
"Open the web address and create the password of the akadmin user in the first-run setup.": "Öppna webbadressen och skapa lösenordet för akadmin-användaren i den första körningen.",
"Open the web dashboard and link your Movistar/O2 account using its SMS flow.": "Öppna webbpanelen och koppla ditt Movistar/O2-konto med SMS-verifieringen.",
"Open-source AI-powered coding assistant": "Open-source AI-driven kodningsassistent",
"Open-source UI for building and debugging multi-agent and RAG applications": "Open-source UI för att bygga och debugga multi-agent- och RAG-applikationer",
"Open-source in-memory data store.": "Öppen datalagring i minnet.",
@@ -5396,6 +5400,7 @@
"Proxmox web interface: Datacenter > Storage > Add > ZFS": "Proxmox webbgränssnitt: Datacenter > Lagring > Lägg till > ZFS",
"Proxmox web interface: Datacenter > Storage > Add > iSCSI": "Proxmox webbgränssnitt: Datacenter > Lagring > Lägg till > iSCSI",
"Proxy address to reach the API (optional)": "Proxyadress för att nå API:t (valfritt)",
"Public HTTPS URL used to open this Authelia portal (for example https://auth.example.com)": "Offentlig HTTPS-URL som används för att öppna denna Authelia-portal (till exempel https://auth.example.com)",
"Public UDP port clients connect to": "Offentliga UDP-portklienter ansluter till",
"Public UDP port peers connect to": "Offentliga UDP-portpeers ansluter till",
"Public URL of phpMyAdmin when it is served behind a reverse proxy": "Public URL av phpMyAdmin när den serveras bakom en omvänd proxy",
@@ -6453,6 +6458,7 @@
"Simple and easy to use DDNS": "Enkelt och enkelt att använda DDNS",
"Simple self-hosted file sharing.": "Enkel självhostad fildelning.",
"Single GPU Warning": "Varning för enkel GPU",
"Single sign-on and multi-factor authentication": "Enkel inloggning och multifaktorautentisering",
"Single target found — selected automatically:": "Enstaka mål hittades — väljs automatiskt:",
"Single-node log storage and query UI.": "Gränssnitt för logglagring och loggsökning på en enda nod.",
"Single-node observability database for metrics, logs and traces.": "Observabilitetsdatabas med en nod för mätvärden, loggar och spår.",
@@ -8202,12 +8208,17 @@
"Web access": "Web access",
"Web address of the AdGuard Home that receives the settings (e.g. http://192.168.1.3)": "Webbadress för AdGuard Home som tar emot inställningarna (t.ex. http://192.168.1.3)",
"Web address of the main AdGuard Home, whose settings are copied (e.g. http://192.168.1.2)": "Webbadressen för AdGuard Home, vars inställningar kopieras (t.ex. http://192.168.1.2)",
"Web dashboard": "Webbpanel",
"Web dashboard and WebDAV": "Webbpanel och WebDAV",
"Web interface": "Webbgränssnitt",
"Web interface for Borg Backup repositories and jobs.": "Webbgränssnitt för Borg Backup-arkiv och jobb.",
"Web interface for managing 3D printers.": "Webbgränssnitt för hantering av 3D-skrivare.",
"Web interface to manage devices running Tasmota firmware.": "Webbgränssnitt för att hantera enheter som kör Tasmota firmware.",
"Web reverse proxy with an administration interface.": "Omvänd proxy för webben med administrationsgränssnitt.",
"WebCord can be summarized as a pack of security and privacy hardenings, Discord features reimplementations, Electron / Chromium / Discord bugs workarounds, stylesheets, internal pages and wrapped https://discord.com page, designed to conform with ToS as much as it is possible (or hide the changes that might violate it from Discord's eyes).": "WebCord kan sammanfattas som ett paket av säkerhets- och sekretesshärdningar, Discord-funktioner reimplementations, Electron / Chromium / Discord bugs workarounds, stylesheets, interna sidor och wrapped https://discord.com sida, utformad för att överensstämma med ToS så mycket som möjligt (eller dölja de förändringar som kan bryta mot det från Discords ögon).",
"WebDAV": "WebDAV",
"WebDAV and dashboard password (leave empty to generate)": "Lösenord för WebDAV och panelen (tom = genererat)",
"WebDAV is available on container port 8080. Account linking is required before cloud file operations.": "WebDAV är tillgängligt på containerns port 8080. Kontot måste kopplas innan du arbetar med filerna i molnet.",
"Webgrabplus is a multi-site incremental xmltv epg grabber. It collects tv-program guide data from selected tvguide sites for your favourite channels.": "Webgrabplus är en multi-site inkrementell xmltv epg grabber. Det samlar in tv-programguide data från utvalda tvguide webbplatser för dina favoritkanaler.",
"Webservers & Proxies": "Webbservrar och proxyservrar",
"Website": "Webbplats",
+1 -1
View File
@@ -2,7 +2,7 @@
<!-- Generated from oci/catalog/verification.json by .github/scripts/oci_validation.py. Do not edit by hand. -->
52 of 534 applications in the OCI catalog have been tested for real: 49 in the ProxMenux lab and 3 by the community. The OCI installer shows them as verified, with a ✓ in the lists.
52 of 536 applications in the OCI catalog have been tested for real: 49 in the ProxMenux lab and 3 by the community. The OCI installer shows them as verified, with a ✓ in the lists.
Each test describes the scenario that was run and names the image it ran on. It does not cover every possible configuration of the application, and a newer image has not been tested until someone reports it.
+453
View File
@@ -0,0 +1,453 @@
{
"schema_version": "0.4.0",
"kind": "proxmenux.oci-template",
"id": "image-authelia",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Authelia",
"es_ES": "Authelia"
},
"tagline": {
"en_US": "Single sign-on and multi-factor authentication",
"es_ES": "Inicio de sesión único y autenticación multifactor"
},
"description": {
"en_US": "An open-source authentication and authorization server for protecting web applications. This single-image profile provides a local SQLite database and file notifications; configure your domain, reverse proxy and access rules before protecting other services.",
"es_ES": "Servidor de autenticación y autorización de código abierto para proteger aplicaciones web. Este perfil de una sola imagen incluye una base de datos SQLite local y notificaciones en archivo; configura el dominio, el proxy inverso y las reglas de acceso antes de proteger otros servicios."
},
"category": "security",
"category_label": "Authentication & Security",
"author": "Authelia",
"developer": "Authelia",
"icon": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/authelia.webp",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 9091,
"path": "/"
},
"website": "https://www.authelia.com/",
"documentation": "https://www.authelia.com/integration/deployment/docker/",
"repository": "https://github.com/authelia/authelia",
"tips": [
"The installer creates a unique admin password and stores only its Argon2id hash in /config/users_database.yml. The password is shown in the installation result.",
"Authelia requires an HTTPS portal URL and a cookie domain matching that hostname. If you use Nginx Proxy Manager, follow the official integration guide and configure trusted proxies and forward-auth separately.",
"The default notifier writes messages to /config/notification.txt. Configure SMTP in /config/configuration.yml if you want email delivery.",
"The initial access-control policy is one_factor. Add explicit access-control rules before attaching Authelia to protected proxy hosts."
],
"mini_changelog": [],
"display_version": "4.39.28",
"updated_at": "2026-09-17"
},
"source": {
"provider": "authelia",
"repository": "https://github.com/authelia/authelia",
"default_branch": "master",
"revision": "8da42b2348b0351c6284a2940a9c5eec3d4cd3fd",
"readme_raw_url": "https://raw.githubusercontent.com/authelia/authelia/v4.39.28/examples/compose/lite/compose.yml",
"readme_pushed_at": "2026-09-17T12:13:30Z",
"compose_sha256": "848ce0f70e502981a050ac200d9d1882978a6c3b0f9f0dfcc6d52ce66ca37fb5",
"generated_at": "2026-11-03T09:10:57+00:00",
"image_repository_url": "https://hub.docker.com/r/authelia/authelia"
},
"container_contract": {
"service_name": "authelia",
"container_name": "authelia",
"image": {
"reference": "docker.io/authelia/authelia:4.39.28",
"registry": "docker.io",
"repository": "docker.io/authelia/authelia",
"tag": "4.39.28",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PROXMENUX_ADMIN_PASSWORD",
"example": "",
"required": true,
"sensitive": true,
"source": "proxmenux-first-start"
},
{
"name": "AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET",
"example": "",
"required": true,
"sensitive": true,
"source": "proxmenux-generated"
},
{
"name": "AUTHELIA_SESSION_SECRET",
"example": "",
"required": true,
"sensitive": true,
"source": "proxmenux-generated"
},
{
"name": "AUTHELIA_STORAGE_ENCRYPTION_KEY",
"example": "",
"required": true,
"sensitive": true,
"source": "proxmenux-generated"
},
{
"name": "X_AUTHELIA_CONFIG_FILTERS",
"example": "template",
"required": true,
"sensitive": false,
"source": "authelia-container"
},
{
"name": "PROXMENUX_AUTHELIA_COOKIE_DOMAIN",
"example": "",
"prompt": "Authelia session cookie domain for this portal (for example example.com)",
"required": true,
"sensitive": false,
"source": "administrator"
},
{
"name": "PROXMENUX_AUTHELIA_URL",
"example": "",
"prompt": "Public HTTPS URL used to open this Authelia portal (for example https://auth.example.com)",
"required": true,
"sensitive": false,
"source": "administrator"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./authelia",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 9091,
"published_example": 9091,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n authelia:\n entrypoint:\n - /bin/sh\n - /usr/local/bin/proxmenux-authelia-bootstrap\n environment:\n AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET: ${GENERATED_RESET_PASSWORD_JWT_SECRET}\n AUTHELIA_SESSION_SECRET: ${GENERATED_SESSION_SECRET}\n AUTHELIA_STORAGE_ENCRYPTION_KEY: ${GENERATED_STORAGE_ENCRYPTION_KEY}\n PROXMENUX_ADMIN_PASSWORD: ${GENERATED_ADMIN_PASSWORD}\n PROXMENUX_AUTHELIA_COOKIE_DOMAIN: ${AUTHELIA_COOKIE_DOMAIN}\n PROXMENUX_AUTHELIA_URL: ${AUTHELIA_URL}\n X_AUTHELIA_CONFIG_FILTERS: template\n image: docker.io/authelia/authelia:4.39.28\n ports:\n - 9091:9091\n restart: unless-stopped\n volumes:\n - ./authelia:/config\n"
},
"first_run": {
"endpoints": [
{
"label": "Authelia Web UI",
"scheme": "http",
"port": 9091,
"path": "/",
"source": "official-image"
}
],
"credentials": [
{
"label": "Authelia administrator",
"type": "configured-or-installer-generated",
"username": "admin",
"password": null,
"password_environment": "PROXMENUX_ADMIN_PASSWORD",
"change_required": false,
"source": "Generated on first start and stored as an Argon2id hash in the persistent users file."
}
]
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 512,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 60
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"runtime": {
"compose_entrypoint": [
"/bin/sh",
"/usr/local/bin/proxmenux-authelia-bootstrap"
]
},
"generated_sensitive_environment": {
"PROXMENUX_ADMIN_PASSWORD": {
"strategy": "token-hex",
"bytes": 24,
"prompt": false
},
"AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET": {
"strategy": "token-hex",
"bytes": 32,
"prompt": false
},
"AUTHELIA_SESSION_SECRET": {
"strategy": "token-hex",
"bytes": 32,
"prompt": false
},
"AUTHELIA_STORAGE_ENCRYPTION_KEY": {
"strategy": "token-hex",
"bytes": 32,
"prompt": false
}
},
"minimum_secret_length": {
"PROXMENUX_ADMIN_PASSWORD": 24,
"AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET": 32,
"AUTHELIA_SESSION_SECRET": 32,
"AUTHELIA_STORAGE_ENCRYPTION_KEY": 32
},
"generated_files": [
{
"container_path": "/config/configuration.yml",
"mode": "0600",
"owner": "mapped-root",
"only_if_missing": true,
"content": "---\nserver:\n address: 'tcp://:9091'\n\nlog:\n level: 'info'\n\ntotp:\n issuer: 'Authelia'\n\nidentity_validation:\n reset_password:\n jwt_secret: 'configured-by-environment'\n\nauthentication_backend:\n file:\n path: '/config/users_database.yml'\n watch: true\n\naccess_control:\n default_policy: 'one_factor'\n\nsession:\n secret: 'configured-by-environment'\n cookies:\n - name: 'authelia_session'\n domain: '{{ env \"PROXMENUX_AUTHELIA_COOKIE_DOMAIN\" }}'\n authelia_url: '{{ env \"PROXMENUX_AUTHELIA_URL\" }}'\n expiration: '1 hour'\n inactivity: '5 minutes'\n\nstorage:\n encryption_key: 'configured-by-environment'\n local:\n path: '/config/db.sqlite3'\n\nnotifier:\n filesystem:\n filename: '/config/notification.txt'\n"
},
{
"container_path": "/usr/local/bin/proxmenux-authelia-bootstrap",
"mode": "0700",
"owner": "mapped-root",
"only_if_missing": false,
"content": "#!/bin/sh\nset -eu\numask 077\n\nusers_file=/config/users_database.yml\nif [ ! -s \"$users_file\" ]; then\n : \"${PROXMENUX_ADMIN_PASSWORD:?ProxMenux did not provide an initial administrator password}\"\n mkdir -p /config\n hash_output=$(authelia crypto hash generate argon2 --password \"$PROXMENUX_ADMIN_PASSWORD\" --no-confirm)\n password_hash=$(printf '%s\\n' \"$hash_output\" | sed -n 's/^Digest: //p')\n case \"$password_hash\" in\n '$argon2id$'*) ;;\n *) printf '%s\\n' 'Authelia did not return an Argon2id password hash' >&2; exit 1 ;;\n esac\n temporary_file=\"${users_file}.tmp.$$\"\n cat >\"$temporary_file\" <<EOF\nusers:\n admin:\n disabled: false\n displayname: 'Authelia Administrator'\n password: \"$password_hash\"\n groups:\n - 'admins'\nEOF\n chmod 0600 \"$temporary_file\"\n mv -f \"$temporary_file\" \"$users_file\"\nfi\nunset PROXMENUX_ADMIN_PASSWORD\nexec /app/entrypoint.sh \"$@\"\n"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 9091,
"path": "/api/health",
"timeout_seconds": 240,
"request_timeout_seconds": 10,
"stability_seconds": 4,
"verify_tls": true
}
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "pending-per-application"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "A single-image profile for the Authelia authentication portal. ProxMenux creates a unique initial administrator account; the local notifier and SQLite storage are kept in /config. Reverse-proxy trust and explicit access-control rules remain administrator settings."
},
"validation": {
"schema": "pending-local-validation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+24 -2
View File
@@ -68,7 +68,7 @@
"source": "docker-compose"
},
{
"name": "LLAMA_ARG_CONTEXT_SIZE",
"name": "LLAMA_ARG_CTX_SIZE",
"example": "8192",
"required": true,
"sensitive": false,
@@ -142,7 +142,7 @@
],
"environment": [
"LLAMA_ARG_N_GPU_LAYERS=999",
"LLAMA_ARG_CONTEXT_SIZE=8192",
"LLAMA_ARG_CTX_SIZE=8192",
"LLAMA_ARG_MODELS_DIR=/models"
],
"devices": [
@@ -342,6 +342,28 @@
"0x1002"
]
}
],
"environment": [
{
"name": "LLAMA_ARG_FLASH_ATTN",
"value": "off"
},
{
"name": "LLAMA_ARG_UBATCH",
"value": "32"
},
{
"name": "LLAMA_ARG_BATCH",
"value": "128"
},
{
"name": "GGML_VK_DISABLE_F16",
"value": "1"
},
{
"name": "GGML_VK_DISABLE_ASYNC",
"value": "1"
}
]
},
{
+609
View File
@@ -0,0 +1,609 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-movistar-webdav-proxy",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Movistar / O2 Cloud WebDAV Proxy"
},
"tagline": {
"en_US": "Access Movistar and O2 Cloud from WebDAV clients and backup tools."
},
"description": {
"en_US": "Official uniextra image with a web dashboard for Movistar/O2 Cloud account linking. Persistent OAuth credentials, authenticated WebDAV and disk-backed temporary uploads."
},
"category": "backup",
"category_label": "Backup & Recovery",
"author": "uniextra",
"developer": "uniextra",
"icon": "https://raw.githubusercontent.com/uniextra/MovistarWebDAVProxy/main/static/favicon.svg",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 5000,
"path": "/"
},
"website": "https://github.com/uniextra/MovistarWebDAVProxy",
"documentation": "https://github.com/uniextra/MovistarWebDAVProxy#readme",
"repository": "https://github.com/uniextra/MovistarWebDAVProxy",
"tips": [
"Link your Movistar or O2 account from the dashboard after installation.",
"Use the container IP and port 8080 for WebDAV. Docker's published port 5050 is not used by native OCI LXC.",
"Temporary uploads use a separate disk volume, excluded from backups, to avoid filling RAM."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "uniextra",
"repository": "https://github.com/uniextra/MovistarWebDAVProxy",
"revision": "e48485bc8bdf9745caa6249fdc92db6d28214549",
"image_repository_url": "https://hub.docker.com/r/uniextra/movistar-webdav-proxy",
"readme_pushed_at": "",
"compose_sha256": "e51607e979c1a776ececda038caeffb4195f443ebc017eba753a4b4ff8fd5c28",
"generated_at": "2026-11-02T23:42:04+00:00",
"readme_raw_url": "https://raw.githubusercontent.com/uniextra/MovistarWebDAVProxy/e48485bc8bdf9745caa6249fdc92db6d28214549/README.md"
},
"container_contract": {
"service_name": "movistar-webdav-proxy",
"container_name": "movistar-webdav-proxy",
"image": {
"reference": "uniextra/movistar-webdav-proxy:latest",
"registry": "docker.io",
"repository": "uniextra/movistar-webdav-proxy",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "WEBDAV_USER",
"example": "admin",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "WEBDAV_PASSWORD",
"example": "",
"required": true,
"sensitive": true,
"source": "docker-compose",
"prompt": "WebDAV and dashboard password (leave empty to generate)"
},
{
"name": "REQUIRE_AUTH",
"example": "true",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "TOKENS_ENCRYPTION_KEY",
"example": "",
"required": true,
"sensitive": true,
"source": "docker-compose"
},
{
"name": "MAX_UPLOAD_MB",
"example": "4096",
"required": false,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "tokens",
"container_path": "/app/tokens",
"compose_source_example": "./tokens",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
},
{
"id": "uploads",
"container_path": "/tmp",
"compose_source_example": "./tmp",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 5000,
"published_example": 5000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 8080,
"published_example": 8080,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n movistar-webdav-proxy:\n image: uniextra/movistar-webdav-proxy:v2.1.0\n container_name: movistar-webdav-proxy\n restart: unless-stopped\n read_only: true\n tmpfs:\n - /tmp\n security_opt:\n - no-new-privileges:true\n environment:\n - WEBDAV_USER=${WEBDAV_USER:-}\n - WEBDAV_PASSWORD=${WEBDAV_PASSWORD:-}\n - WEBUI_USER=${WEBUI_USER:-}\n - WEBUI_PASSWORD=${WEBUI_PASSWORD:-}\n ports:\n - \"${BIND_IP:-0.0.0.0}:${WEB_PORT:-5000}:5000\" # Panel Web de gestión y logs (usa BIND_IP=127.0.0.1 para acceso solo local)\n - \"${BIND_IP:-0.0.0.0}:${WEBDAV_PORT:-5050}:8080\" # Endpoint WebDAV (Duplicati / Synology HyperBackup)\n volumes:\n - movistar_tokens:/app/tokens\n\nvolumes:\n movistar_tokens:\n name: movistar_webdav_tokens\n"
},
"compose_stack": {
"project_name": "movistar-webdav-proxy",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "movistar-webdav-proxy",
"service_count": 1,
"services": [
{
"name": "movistar-webdav-proxy",
"image": "uniextra/movistar-webdav-proxy:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"environment": {
"MAX_UPLOAD_MB": "4096",
"REQUIRE_AUTH": "true",
"TOKENS_ENCRYPTION_KEY": "${GENERATED_TOKENS_ENCRYPTION_KEY}",
"WEBDAV_PASSWORD": "${GENERATED_WEBDAV_PASSWORD}",
"WEBDAV_USER": "admin"
},
"image": "uniextra/movistar-webdav-proxy:latest",
"ports": [
"5000:5000",
"8080:8080"
],
"volumes": [
"./tokens:/app/tokens",
"./tmp:/tmp"
]
}
}
],
"top_level": {
"name": "movistar-webdav-proxy"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "movistar-webdav-proxy-volume-0",
"service": "movistar-webdav-proxy",
"container_path": "/app/tokens",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "movistar-webdav-proxy-volume-1",
"service": "movistar-webdav-proxy",
"container_path": "/tmp",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"movistar-webdav-proxy"
],
"stop_order": [
"movistar-webdav-proxy"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": [
{
"id": "tokens-encryption-key",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "movistar-webdav-proxy",
"environment_variable": "TOKENS_ENCRYPTION_KEY"
}
]
},
{
"id": "webdav-password",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "movistar-webdav-proxy",
"environment_variable": "WEBDAV_PASSWORD"
}
]
}
]
}
},
"first_run": {
"endpoints": [
{
"label": "Web dashboard",
"scheme": "http",
"port": 5000,
"path": "/",
"source": "upstream-documentation"
},
{
"label": "WebDAV",
"scheme": "http",
"port": 8080,
"path": "/",
"source": "native-container-port"
}
],
"credentials": [
{
"label": "Web dashboard and WebDAV",
"type": "configured-or-installer-generated",
"username": "admin",
"username_environment": "WEBDAV_USER",
"password": null,
"password_environment": "WEBDAV_PASSWORD",
"change_required": false,
"source": "installer-generated",
"retrieval": null
}
]
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 1,
"memory_mb": 512,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
},
{
"id": "disk-backed-upload-scratch",
"upstream_behavior": "Compose mounts /tmp as a tmpfs.",
"native_lxc_behavior": "A separate managed disk volume provides /tmp and is excluded from backups.",
"reason": "Uploads can reach 4096 MB; a disk-backed scratch volume avoids consuming the LXC RAM limit.",
"behavioral_impact": "Scratch data uses disk and can survive a restart; the application removes completed temporary uploads.",
"validation": "passed-in-lab"
},
{
"id": "native-rootfs-permissions",
"upstream_behavior": "Docker Compose requests read_only for the root filesystem.",
"native_lxc_behavior": "Proxmox uses a writable native root disk; /app is owned by root, while the upstream entrypoint drops to UID 10001. Tokens and upload scratch have separate writable volumes.",
"reason": "The Proxmox pre-start setup requires a writable root disk. Protect application code through root ownership instead of declaring unsupported read-only startup.",
"behavioral_impact": "This is not a fully read-only root filesystem; the application user cannot replace the root-owned application directory or binaries.",
"validation": "passed-in-lab"
}
],
"installer_profile": {
"volume_preparations": [
{
"container_path": "/app",
"remove_lost_found": false,
"owner_strategy": "mapped-root",
"mode": "0755"
},
{
"container_path": "/app/tokens",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user",
"mode": "0700"
},
{
"container_path": "/tmp",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user",
"mode": "1777"
}
],
"volume_owner": {
"uid": 10001,
"gid": 10001
},
"generated_sensitive_environment": {
"WEBDAV_PASSWORD": {
"strategy": "token-hex",
"bytes": 16,
"prompt": true
},
"TOKENS_ENCRYPTION_KEY": {
"strategy": "token-hex",
"bytes": 32,
"prompt": false
}
},
"security": {
"options": {
"no_new_privileges": true
}
},
"startup_healthcheck": {
"scheme": "http",
"port": 5000,
"path": "/health",
"timeout_seconds": 90,
"request_timeout_seconds": 5,
"stability_seconds": 4,
"verify_tls": false
},
"completion_notes": [
"Open the web dashboard and link your Movistar/O2 account using its SMS flow.",
"WebDAV is available on container port 8080. Account linking is required before cloud file operations."
]
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "passed",
"service_health": "passed",
"restart_persistence": "passed",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+17 -27
View File
@@ -82,22 +82,6 @@
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-1",
"container_path": "/dev/net/tun",
"compose_source_example": "/dev/net/tun",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [],
@@ -180,17 +164,6 @@
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "tailscale-volume-1",
"service": "tailscale",
"container_path": "/dev/net/tun",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
@@ -288,6 +261,23 @@
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
}
],
"device_requests": [
{
"id": "dev-net-tun",
"kind": "character-device",
"purpose": "tun",
"enable_prompt": "Pass /dev/net/tun to the LXC",
"enabled_default": true,
"required_by_compose": true,
"path_prompt": "Host device for /dev/net/tun",
"host_path_default": "/dev/net/tun",
"container_path": "/dev/net/tun",
"mode": "preserve-host",
"deny_write": false,
"gid_strategy": "host-device-gid",
"source_mapping": "/dev/net/tun:/dev/net/tun"
}
]
},
"adaptations": [
+453
View File
@@ -0,0 +1,453 @@
{
"schema_version": "0.4.0",
"kind": "proxmenux.oci-template",
"id": "image-authelia",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Authelia",
"es_ES": "Authelia"
},
"tagline": {
"en_US": "Single sign-on and multi-factor authentication",
"es_ES": "Inicio de sesión único y autenticación multifactor"
},
"description": {
"en_US": "An open-source authentication and authorization server for protecting web applications. This single-image profile provides a local SQLite database and file notifications; configure your domain, reverse proxy and access rules before protecting other services.",
"es_ES": "Servidor de autenticación y autorización de código abierto para proteger aplicaciones web. Este perfil de una sola imagen incluye una base de datos SQLite local y notificaciones en archivo; configura el dominio, el proxy inverso y las reglas de acceso antes de proteger otros servicios."
},
"category": "security",
"category_label": "Authentication & Security",
"author": "Authelia",
"developer": "Authelia",
"icon": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/authelia.webp",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 9091,
"path": "/"
},
"website": "https://www.authelia.com/",
"documentation": "https://www.authelia.com/integration/deployment/docker/",
"repository": "https://github.com/authelia/authelia",
"tips": [
"The installer creates a unique admin password and stores only its Argon2id hash in /config/users_database.yml. The password is shown in the installation result.",
"Authelia requires an HTTPS portal URL and a cookie domain matching that hostname. If you use Nginx Proxy Manager, follow the official integration guide and configure trusted proxies and forward-auth separately.",
"The default notifier writes messages to /config/notification.txt. Configure SMTP in /config/configuration.yml if you want email delivery.",
"The initial access-control policy is one_factor. Add explicit access-control rules before attaching Authelia to protected proxy hosts."
],
"mini_changelog": [],
"display_version": "4.39.28",
"updated_at": "2026-09-17"
},
"source": {
"provider": "authelia",
"repository": "https://github.com/authelia/authelia",
"default_branch": "master",
"revision": "8da42b2348b0351c6284a2940a9c5eec3d4cd3fd",
"readme_raw_url": "https://raw.githubusercontent.com/authelia/authelia/v4.39.28/examples/compose/lite/compose.yml",
"readme_pushed_at": "2026-09-17T12:13:30Z",
"compose_sha256": "848ce0f70e502981a050ac200d9d1882978a6c3b0f9f0dfcc6d52ce66ca37fb5",
"generated_at": "2026-11-03T09:10:57+00:00",
"image_repository_url": "https://hub.docker.com/r/authelia/authelia"
},
"container_contract": {
"service_name": "authelia",
"container_name": "authelia",
"image": {
"reference": "docker.io/authelia/authelia:4.39.28",
"registry": "docker.io",
"repository": "docker.io/authelia/authelia",
"tag": "4.39.28",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PROXMENUX_ADMIN_PASSWORD",
"example": "",
"required": true,
"sensitive": true,
"source": "proxmenux-first-start"
},
{
"name": "AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET",
"example": "",
"required": true,
"sensitive": true,
"source": "proxmenux-generated"
},
{
"name": "AUTHELIA_SESSION_SECRET",
"example": "",
"required": true,
"sensitive": true,
"source": "proxmenux-generated"
},
{
"name": "AUTHELIA_STORAGE_ENCRYPTION_KEY",
"example": "",
"required": true,
"sensitive": true,
"source": "proxmenux-generated"
},
{
"name": "X_AUTHELIA_CONFIG_FILTERS",
"example": "template",
"required": true,
"sensitive": false,
"source": "authelia-container"
},
{
"name": "PROXMENUX_AUTHELIA_COOKIE_DOMAIN",
"example": "",
"prompt": "Authelia session cookie domain for this portal (for example example.com)",
"required": true,
"sensitive": false,
"source": "administrator"
},
{
"name": "PROXMENUX_AUTHELIA_URL",
"example": "",
"prompt": "Public HTTPS URL used to open this Authelia portal (for example https://auth.example.com)",
"required": true,
"sensitive": false,
"source": "administrator"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./authelia",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 9091,
"published_example": 9091,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n authelia:\n entrypoint:\n - /bin/sh\n - /usr/local/bin/proxmenux-authelia-bootstrap\n environment:\n AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET: ${GENERATED_RESET_PASSWORD_JWT_SECRET}\n AUTHELIA_SESSION_SECRET: ${GENERATED_SESSION_SECRET}\n AUTHELIA_STORAGE_ENCRYPTION_KEY: ${GENERATED_STORAGE_ENCRYPTION_KEY}\n PROXMENUX_ADMIN_PASSWORD: ${GENERATED_ADMIN_PASSWORD}\n PROXMENUX_AUTHELIA_COOKIE_DOMAIN: ${AUTHELIA_COOKIE_DOMAIN}\n PROXMENUX_AUTHELIA_URL: ${AUTHELIA_URL}\n X_AUTHELIA_CONFIG_FILTERS: template\n image: docker.io/authelia/authelia:4.39.28\n ports:\n - 9091:9091\n restart: unless-stopped\n volumes:\n - ./authelia:/config\n"
},
"first_run": {
"endpoints": [
{
"label": "Authelia Web UI",
"scheme": "http",
"port": 9091,
"path": "/",
"source": "official-image"
}
],
"credentials": [
{
"label": "Authelia administrator",
"type": "configured-or-installer-generated",
"username": "admin",
"password": null,
"password_environment": "PROXMENUX_ADMIN_PASSWORD",
"change_required": false,
"source": "Generated on first start and stored as an Argon2id hash in the persistent users file."
}
]
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 512,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 60
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"runtime": {
"compose_entrypoint": [
"/bin/sh",
"/usr/local/bin/proxmenux-authelia-bootstrap"
]
},
"generated_sensitive_environment": {
"PROXMENUX_ADMIN_PASSWORD": {
"strategy": "token-hex",
"bytes": 24,
"prompt": false
},
"AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET": {
"strategy": "token-hex",
"bytes": 32,
"prompt": false
},
"AUTHELIA_SESSION_SECRET": {
"strategy": "token-hex",
"bytes": 32,
"prompt": false
},
"AUTHELIA_STORAGE_ENCRYPTION_KEY": {
"strategy": "token-hex",
"bytes": 32,
"prompt": false
}
},
"minimum_secret_length": {
"PROXMENUX_ADMIN_PASSWORD": 24,
"AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET": 32,
"AUTHELIA_SESSION_SECRET": 32,
"AUTHELIA_STORAGE_ENCRYPTION_KEY": 32
},
"generated_files": [
{
"container_path": "/config/configuration.yml",
"mode": "0600",
"owner": "mapped-root",
"only_if_missing": true,
"content": "---\nserver:\n address: 'tcp://:9091'\n\nlog:\n level: 'info'\n\ntotp:\n issuer: 'Authelia'\n\nidentity_validation:\n reset_password:\n jwt_secret: 'configured-by-environment'\n\nauthentication_backend:\n file:\n path: '/config/users_database.yml'\n watch: true\n\naccess_control:\n default_policy: 'one_factor'\n\nsession:\n secret: 'configured-by-environment'\n cookies:\n - name: 'authelia_session'\n domain: '{{ env \"PROXMENUX_AUTHELIA_COOKIE_DOMAIN\" }}'\n authelia_url: '{{ env \"PROXMENUX_AUTHELIA_URL\" }}'\n expiration: '1 hour'\n inactivity: '5 minutes'\n\nstorage:\n encryption_key: 'configured-by-environment'\n local:\n path: '/config/db.sqlite3'\n\nnotifier:\n filesystem:\n filename: '/config/notification.txt'\n"
},
{
"container_path": "/usr/local/bin/proxmenux-authelia-bootstrap",
"mode": "0700",
"owner": "mapped-root",
"only_if_missing": false,
"content": "#!/bin/sh\nset -eu\numask 077\n\nusers_file=/config/users_database.yml\nif [ ! -s \"$users_file\" ]; then\n : \"${PROXMENUX_ADMIN_PASSWORD:?ProxMenux did not provide an initial administrator password}\"\n mkdir -p /config\n hash_output=$(authelia crypto hash generate argon2 --password \"$PROXMENUX_ADMIN_PASSWORD\" --no-confirm)\n password_hash=$(printf '%s\\n' \"$hash_output\" | sed -n 's/^Digest: //p')\n case \"$password_hash\" in\n '$argon2id$'*) ;;\n *) printf '%s\\n' 'Authelia did not return an Argon2id password hash' >&2; exit 1 ;;\n esac\n temporary_file=\"${users_file}.tmp.$$\"\n cat >\"$temporary_file\" <<EOF\nusers:\n admin:\n disabled: false\n displayname: 'Authelia Administrator'\n password: \"$password_hash\"\n groups:\n - 'admins'\nEOF\n chmod 0600 \"$temporary_file\"\n mv -f \"$temporary_file\" \"$users_file\"\nfi\nunset PROXMENUX_ADMIN_PASSWORD\nexec /app/entrypoint.sh \"$@\"\n"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 9091,
"path": "/api/health",
"timeout_seconds": 240,
"request_timeout_seconds": 10,
"stability_seconds": 4,
"verify_tls": true
}
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "pending-per-application"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "A single-image profile for the Authelia authentication portal. ProxMenux creates a unique initial administrator account; the local notifier and SQLite storage are kept in /config. Reverse-proxy trust and explicit access-control rules remain administrator settings."
},
"validation": {
"schema": "pending-local-validation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+24 -2
View File
@@ -68,7 +68,7 @@
"source": "docker-compose"
},
{
"name": "LLAMA_ARG_CONTEXT_SIZE",
"name": "LLAMA_ARG_CTX_SIZE",
"example": "8192",
"required": true,
"sensitive": false,
@@ -142,7 +142,7 @@
],
"environment": [
"LLAMA_ARG_N_GPU_LAYERS=999",
"LLAMA_ARG_CONTEXT_SIZE=8192",
"LLAMA_ARG_CTX_SIZE=8192",
"LLAMA_ARG_MODELS_DIR=/models"
],
"devices": [
@@ -342,6 +342,28 @@
"0x1002"
]
}
],
"environment": [
{
"name": "LLAMA_ARG_FLASH_ATTN",
"value": "off"
},
{
"name": "LLAMA_ARG_UBATCH",
"value": "32"
},
{
"name": "LLAMA_ARG_BATCH",
"value": "128"
},
{
"name": "GGML_VK_DISABLE_F16",
"value": "1"
},
{
"name": "GGML_VK_DISABLE_ASYNC",
"value": "1"
}
]
},
{
@@ -0,0 +1,609 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-movistar-webdav-proxy",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Movistar / O2 Cloud WebDAV Proxy"
},
"tagline": {
"en_US": "Access Movistar and O2 Cloud from WebDAV clients and backup tools."
},
"description": {
"en_US": "Official uniextra image with a web dashboard for Movistar/O2 Cloud account linking. Persistent OAuth credentials, authenticated WebDAV and disk-backed temporary uploads."
},
"category": "backup",
"category_label": "Backup & Recovery",
"author": "uniextra",
"developer": "uniextra",
"icon": "https://raw.githubusercontent.com/uniextra/MovistarWebDAVProxy/main/static/favicon.svg",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 5000,
"path": "/"
},
"website": "https://github.com/uniextra/MovistarWebDAVProxy",
"documentation": "https://github.com/uniextra/MovistarWebDAVProxy#readme",
"repository": "https://github.com/uniextra/MovistarWebDAVProxy",
"tips": [
"Link your Movistar or O2 account from the dashboard after installation.",
"Use the container IP and port 8080 for WebDAV. Docker's published port 5050 is not used by native OCI LXC.",
"Temporary uploads use a separate disk volume, excluded from backups, to avoid filling RAM."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "uniextra",
"repository": "https://github.com/uniextra/MovistarWebDAVProxy",
"revision": "e48485bc8bdf9745caa6249fdc92db6d28214549",
"image_repository_url": "https://hub.docker.com/r/uniextra/movistar-webdav-proxy",
"readme_pushed_at": "",
"compose_sha256": "e51607e979c1a776ececda038caeffb4195f443ebc017eba753a4b4ff8fd5c28",
"generated_at": "2026-11-02T23:42:04+00:00",
"readme_raw_url": "https://raw.githubusercontent.com/uniextra/MovistarWebDAVProxy/e48485bc8bdf9745caa6249fdc92db6d28214549/README.md"
},
"container_contract": {
"service_name": "movistar-webdav-proxy",
"container_name": "movistar-webdav-proxy",
"image": {
"reference": "uniextra/movistar-webdav-proxy:latest",
"registry": "docker.io",
"repository": "uniextra/movistar-webdav-proxy",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "WEBDAV_USER",
"example": "admin",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "WEBDAV_PASSWORD",
"example": "",
"required": true,
"sensitive": true,
"source": "docker-compose",
"prompt": "WebDAV and dashboard password (leave empty to generate)"
},
{
"name": "REQUIRE_AUTH",
"example": "true",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "TOKENS_ENCRYPTION_KEY",
"example": "",
"required": true,
"sensitive": true,
"source": "docker-compose"
},
{
"name": "MAX_UPLOAD_MB",
"example": "4096",
"required": false,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "tokens",
"container_path": "/app/tokens",
"compose_source_example": "./tokens",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
},
{
"id": "uploads",
"container_path": "/tmp",
"compose_source_example": "./tmp",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 5000,
"published_example": 5000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 8080,
"published_example": 8080,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n movistar-webdav-proxy:\n image: uniextra/movistar-webdav-proxy:v2.1.0\n container_name: movistar-webdav-proxy\n restart: unless-stopped\n read_only: true\n tmpfs:\n - /tmp\n security_opt:\n - no-new-privileges:true\n environment:\n - WEBDAV_USER=${WEBDAV_USER:-}\n - WEBDAV_PASSWORD=${WEBDAV_PASSWORD:-}\n - WEBUI_USER=${WEBUI_USER:-}\n - WEBUI_PASSWORD=${WEBUI_PASSWORD:-}\n ports:\n - \"${BIND_IP:-0.0.0.0}:${WEB_PORT:-5000}:5000\" # Panel Web de gestión y logs (usa BIND_IP=127.0.0.1 para acceso solo local)\n - \"${BIND_IP:-0.0.0.0}:${WEBDAV_PORT:-5050}:8080\" # Endpoint WebDAV (Duplicati / Synology HyperBackup)\n volumes:\n - movistar_tokens:/app/tokens\n\nvolumes:\n movistar_tokens:\n name: movistar_webdav_tokens\n"
},
"compose_stack": {
"project_name": "movistar-webdav-proxy",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "movistar-webdav-proxy",
"service_count": 1,
"services": [
{
"name": "movistar-webdav-proxy",
"image": "uniextra/movistar-webdav-proxy:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"environment": {
"MAX_UPLOAD_MB": "4096",
"REQUIRE_AUTH": "true",
"TOKENS_ENCRYPTION_KEY": "${GENERATED_TOKENS_ENCRYPTION_KEY}",
"WEBDAV_PASSWORD": "${GENERATED_WEBDAV_PASSWORD}",
"WEBDAV_USER": "admin"
},
"image": "uniextra/movistar-webdav-proxy:latest",
"ports": [
"5000:5000",
"8080:8080"
],
"volumes": [
"./tokens:/app/tokens",
"./tmp:/tmp"
]
}
}
],
"top_level": {
"name": "movistar-webdav-proxy"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "movistar-webdav-proxy-volume-0",
"service": "movistar-webdav-proxy",
"container_path": "/app/tokens",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "movistar-webdav-proxy-volume-1",
"service": "movistar-webdav-proxy",
"container_path": "/tmp",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"movistar-webdav-proxy"
],
"stop_order": [
"movistar-webdav-proxy"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": [
{
"id": "tokens-encryption-key",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "movistar-webdav-proxy",
"environment_variable": "TOKENS_ENCRYPTION_KEY"
}
]
},
{
"id": "webdav-password",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "movistar-webdav-proxy",
"environment_variable": "WEBDAV_PASSWORD"
}
]
}
]
}
},
"first_run": {
"endpoints": [
{
"label": "Web dashboard",
"scheme": "http",
"port": 5000,
"path": "/",
"source": "upstream-documentation"
},
{
"label": "WebDAV",
"scheme": "http",
"port": 8080,
"path": "/",
"source": "native-container-port"
}
],
"credentials": [
{
"label": "Web dashboard and WebDAV",
"type": "configured-or-installer-generated",
"username": "admin",
"username_environment": "WEBDAV_USER",
"password": null,
"password_environment": "WEBDAV_PASSWORD",
"change_required": false,
"source": "installer-generated",
"retrieval": null
}
]
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 1,
"memory_mb": 512,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
},
{
"id": "disk-backed-upload-scratch",
"upstream_behavior": "Compose mounts /tmp as a tmpfs.",
"native_lxc_behavior": "A separate managed disk volume provides /tmp and is excluded from backups.",
"reason": "Uploads can reach 4096 MB; a disk-backed scratch volume avoids consuming the LXC RAM limit.",
"behavioral_impact": "Scratch data uses disk and can survive a restart; the application removes completed temporary uploads.",
"validation": "passed-in-lab"
},
{
"id": "native-rootfs-permissions",
"upstream_behavior": "Docker Compose requests read_only for the root filesystem.",
"native_lxc_behavior": "Proxmox uses a writable native root disk; /app is owned by root, while the upstream entrypoint drops to UID 10001. Tokens and upload scratch have separate writable volumes.",
"reason": "The Proxmox pre-start setup requires a writable root disk. Protect application code through root ownership instead of declaring unsupported read-only startup.",
"behavioral_impact": "This is not a fully read-only root filesystem; the application user cannot replace the root-owned application directory or binaries.",
"validation": "passed-in-lab"
}
],
"installer_profile": {
"volume_preparations": [
{
"container_path": "/app",
"remove_lost_found": false,
"owner_strategy": "mapped-root",
"mode": "0755"
},
{
"container_path": "/app/tokens",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user",
"mode": "0700"
},
{
"container_path": "/tmp",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user",
"mode": "1777"
}
],
"volume_owner": {
"uid": 10001,
"gid": 10001
},
"generated_sensitive_environment": {
"WEBDAV_PASSWORD": {
"strategy": "token-hex",
"bytes": 16,
"prompt": true
},
"TOKENS_ENCRYPTION_KEY": {
"strategy": "token-hex",
"bytes": 32,
"prompt": false
}
},
"security": {
"options": {
"no_new_privileges": true
}
},
"startup_healthcheck": {
"scheme": "http",
"port": 5000,
"path": "/health",
"timeout_seconds": 90,
"request_timeout_seconds": 5,
"stability_seconds": 4,
"verify_tls": false
},
"completion_notes": [
"Open the web dashboard and link your Movistar/O2 account using its SMS flow.",
"WebDAV is available on container port 8080. Account linking is required before cloud file operations."
]
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "passed",
"service_health": "passed",
"restart_persistence": "passed",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+65
View File
@@ -9980,6 +9980,39 @@
"hidden": false,
"template_id": "image-motioneye"
},
{
"id": "movistar-webdav-proxy",
"provider": "uniextra",
"template_family": "curated-profile",
"title": "Movistar / O2 Cloud WebDAV Proxy",
"repository": "https://github.com/uniextra/MovistarWebDAVProxy",
"description": "Official uniextra image with a web dashboard for Movistar/O2 Cloud account linking. Persistent OAuth credentials, authenticated WebDAV and disk-backed temporary uploads.",
"website": "https://github.com/uniextra/MovistarWebDAVProxy",
"icon": "https://raw.githubusercontent.com/uniextra/MovistarWebDAVProxy/main/static/favicon.svg",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "uniextra/movistar-webdav-proxy:latest",
"category": "backup",
"category_label": "Backup & Recovery",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/movistar-webdav-proxy.json",
"template_id": "image-movistar-webdav-proxy",
"template": "apps/movistar-webdav-proxy.json",
"template_status": "generated-unvalidated",
"hidden": false,
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"multi_container": false
},
{
"id": "msedge",
"provider": "linuxserver.io",
@@ -18734,6 +18767,38 @@
"hidden": true,
"template_id": "image-ztnet"
},
{
"id": "authelia",
"provider": "authelia",
"template_family": "curated-profile",
"title": "Authelia",
"repository": "https://github.com/authelia/authelia",
"description": "An open-source authentication and authorization server for protecting web applications. This single-image profile provides a local SQLite database and file notifications; configure your domain, reverse proxy and access rules before protecting other services.",
"website": "https://www.authelia.com/",
"icon": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/authelia.webp",
"architectures": [
"amd64",
"arm64"
],
"updated_at": "2026-09-17",
"main_image": "docker.io/authelia/authelia:4.39.28",
"category": "security",
"category_label": "Authentication & Security",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/authelia.json",
"template": "apps/authelia.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false,
"template_id": "image-authelia"
},
{
"id": "airdcpp-webclient",
"provider": "gangefors",
+20
View File
@@ -239,6 +239,26 @@ def recover_untouched(root, journal):
return False
def recover_failed_update(root, journal):
"""Attempt the guarded rollback after an update/Modify command fails.
Unlike recovery of an untouched guest, replacement failures may have
parked its volumes or removed its root disk. The existing recovery
journal validates ownership, configuration and backup before restoring.
Stack transactions remain the responsibility of their coordinator.
"""
try:
with instances.locked(root):
state = json.loads(Path(journal).read_text())
if state.get('coordinated') or state.get('phase') in TERMINAL:
return False
recover(root, Path(journal))
return True
except (OSError, ValueError, KeyError, RuntimeError, subprocess.SubprocessError) as error:
log(f'automatic update recovery failed: {error}')
return False
def fit(text):
"""A step line that is rewritten in place must not wrap."""
width = max(shutil.get_terminal_size((80, 24)).columns - 8, 30)
+1 -1
View File
@@ -289,7 +289,7 @@ def main():
except (OSError, ValueError, KeyError, RuntimeError, subprocess.SubprocessError) as error:
transaction.report_error(error, f'update-{args.vmid}')
journal = transaction.pending_journal()
if journal and not transaction.recover_untouched(instances.ROOT, journal):
if journal and not transaction.recover_failed_update(instances.ROOT, journal):
transaction.recovery_hint()
return 1
+24
View File
@@ -187,6 +187,24 @@ def _split_short_mount(value: str) -> tuple[str | None, str, str | None]:
return ":".join(parts[:-2]), parts[-2], parts[-1]
# Host device nodes a Compose file may bind as a volume. They are passed to
# the LXC as devices: a mount at that path would hide the device.
DEVICE_NODE_BINDS = ("/dev/net/tun", "/dev/fuse", "/dev/kvm")
def _device_bind(item: Any) -> str | None:
"""The `source:target` of a volume that binds a host device node."""
if isinstance(item, dict):
if item.get("type", "bind") != "bind":
return None
source, target = item.get("source"), item.get("target")
else:
source, target, _ = _split_short_mount(str(item))
if str(source or "") in DEVICE_NODE_BINDS and str(target or "") == str(source):
return f"{source}:{target}"
return None
def _mount_contract(value: Any, optional: set[str]) -> list[dict[str, Any]]:
if value is None:
return []
@@ -194,6 +212,8 @@ def _mount_contract(value: Any, optional: set[str]) -> list[dict[str, Any]]:
raise ConversionError("volumes must be a list")
result: list[dict[str, Any]] = []
for index, item in enumerate(value):
if _device_bind(item):
continue
if isinstance(item, dict):
source = item.get("source")
target = item.get("target")
@@ -606,6 +626,10 @@ def _device_installer_profile(
) -> tuple[dict[str, Any], list[str]]:
optional = optional or set()
raw_devices = service.get("devices")
volumes = service.get("volumes")
device_binds = [bind for bind in map(_device_bind, volumes) if bind] if isinstance(volumes, list) else []
if device_binds and (raw_devices is None or isinstance(raw_devices, list)):
raw_devices = [*(raw_devices or []), *device_binds]
requests: list[dict[str, Any]] = []
blockers: list[str] = []
nvidia_requested = _nvidia_requested(service)
+99
View File
@@ -0,0 +1,99 @@
"""The Authelia profile bootstraps a usable single-image authentication portal."""
import json
from pathlib import Path
import sys
import unittest
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
from proxmenux_oci.catalog import Catalog
class AutheliaRecipeTests(unittest.TestCase):
def setUp(self):
self.path = ROOT / "catalog/curated/authelia.json"
self.recipe = json.loads(self.path.read_text(encoding="utf-8"))
self.index_copy = json.loads(
(ROOT / "catalog/apps/authelia.json").read_text(encoding="utf-8")
)
self.profile = self.recipe["proxmox"]["installer_profile"]
self.generated = {
item["container_path"]: item
for item in self.profile["generated_files"]
}
def test_local_catalog_lists_and_loads_the_curated_recipe(self):
catalog = Catalog(ROOT)
item = catalog.find_item("authelia")
self.assertEqual(item["template_family"], "curated-profile")
self.assertEqual(catalog.compose("authelia")["id"], "image-authelia")
self.assertEqual(self.recipe, self.index_copy)
def test_official_image_tag_icon_and_supported_architectures_are_declared(self):
self.assertEqual(
self.recipe["container_contract"]["image"]["reference"],
"docker.io/authelia/authelia:4.39.28",
)
self.assertEqual(self.recipe["catalog_ui"]["architectures"], ["amd64", "arm64"])
self.assertEqual(
self.recipe["catalog_ui"]["icon"],
"https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/authelia.webp",
)
def test_sensitive_secrets_are_generated_and_domain_settings_are_prompted(self):
environment = {
item["name"]: item
for item in self.recipe["container_contract"]["environment"]
}
for name in (
"PROXMENUX_ADMIN_PASSWORD",
"AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET",
"AUTHELIA_SESSION_SECRET",
"AUTHELIA_STORAGE_ENCRYPTION_KEY",
):
self.assertTrue(environment[name]["sensitive"])
self.assertEqual(self.profile["generated_sensitive_environment"][name]["strategy"], "token-hex")
self.assertTrue(environment["PROXMENUX_AUTHELIA_COOKIE_DOMAIN"]["required"])
self.assertTrue(environment["PROXMENUX_AUTHELIA_URL"]["required"])
self.assertIn("cookie domain", environment["PROXMENUX_AUTHELIA_COOKIE_DOMAIN"]["prompt"])
self.assertIn("HTTPS URL", environment["PROXMENUX_AUTHELIA_URL"]["prompt"])
self.assertEqual(environment["PROXMENUX_AUTHELIA_COOKIE_DOMAIN"]["example"], "")
self.assertEqual(environment["PROXMENUX_AUTHELIA_URL"]["example"], "")
self.assertEqual(environment["X_AUTHELIA_CONFIG_FILTERS"]["example"], "template")
def test_config_is_persistent_and_has_a_working_initial_policy(self):
config = self.generated["/config/configuration.yml"]["content"]
self.assertIn("path: '/config/users_database.yml'", config)
self.assertIn("path: '/config/db.sqlite3'", config)
self.assertIn("filename: '/config/notification.txt'", config)
self.assertIn("default_policy: 'one_factor'", config)
self.assertIn('{{ env \"PROXMENUX_AUTHELIA_COOKIE_DOMAIN\" }}', config)
self.assertIn('{{ env \"PROXMENUX_AUTHELIA_URL\" }}', config)
self.assertTrue(self.generated["/config/configuration.yml"]["only_if_missing"])
volume = self.recipe["container_contract"]["volumes"][0]
self.assertEqual(volume["container_path"], "/config")
self.assertEqual(volume["installation_choice"], ["managed-volume"])
self.assertTrue(volume["managed_volume"]["backup"])
def test_bootstrap_hashes_initial_password_and_never_ships_a_default_password(self):
bootstrap = self.generated["/usr/local/bin/proxmenux-authelia-bootstrap"]["content"]
self.assertIn("authelia crypto hash generate argon2", bootstrap)
self.assertIn("unset PROXMENUX_ADMIN_PASSWORD", bootstrap)
self.assertIn("exec /app/entrypoint.sh", bootstrap)
self.assertNotIn("password: authelia", bootstrap)
self.assertEqual(
self.recipe["first_run"]["credentials"][0]["password_environment"],
"PROXMENUX_ADMIN_PASSWORD",
)
def test_healthcheck_uses_authelias_documented_endpoint_and_profile_remains_unvalidated(self):
healthcheck = self.profile["startup_healthcheck"]
self.assertEqual((healthcheck["port"], healthcheck["path"]), (9091, "/api/health"))
self.assertFalse(self.recipe["compatibility"]["validated"])
self.assertEqual(self.recipe["status"], "generated-unvalidated")
if __name__ == "__main__":
unittest.main()
+39
View File
@@ -0,0 +1,39 @@
"""A Compose volume that binds a host device node, such as /dev/net/tun for
Tailscale, is passed to the LXC as a device: a mount there hides the device."""
from pathlib import Path
import sys
import unittest
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from proxmenux_oci import converter
class DeviceNodeBindTests(unittest.TestCase):
service = {"image": "tailscale/tailscale:latest", "volumes": [
{"type": "bind", "source": "/DATA/AppData/tailscale", "target": "/var/lib/tailscale"},
{"type": "bind", "source": "/dev/net/tun", "target": "/dev/net/tun"},
"/dev/fuse:/dev/fuse"]}
def test_device_nodes_are_not_volumes(self):
mounts = converter._mount_contract(self.service["volumes"], set())
self.assertEqual([m["container_path"] for m in mounts], ["/var/lib/tailscale"])
def test_device_nodes_become_device_requests(self):
profile, blockers = converter._device_installer_profile(self.service)
self.assertEqual(blockers, [])
self.assertEqual([(r["id"], r["container_path"]) for r in profile["device_requests"]],
[("dev-net-tun", "/dev/net/tun"), ("dev-fuse", "/dev/fuse")])
def test_a_device_directory_is_left_to_its_own_handling(self):
self.assertIsNone(converter._device_bind("/dev/dri:/dev/dri"))
self.assertIsNone(converter._device_bind({"type": "volume", "source": "/dev/net/tun", "target": "/dev/net/tun"}))
def test_the_tailscale_recipe_passes_the_tun_device(self):
import json
recipe = json.loads((Path(__file__).resolve().parents[1] / "catalog/apps/tailscale.json").read_text())
self.assertNotIn("/dev/net/tun", [v["container_path"] for v in recipe["container_contract"]["volumes"]])
self.assertIn("dev-net-tun", [r["id"] for r in recipe["proxmox"]["installer_profile"]["device_requests"]])
if __name__ == "__main__":
unittest.main()
+59 -1
View File
@@ -11,7 +11,7 @@ import socket
import sys
import tempfile
import unittest
from unittest.mock import patch
from unittest.mock import Mock, patch
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'remote'))
import oci_instances as instances
@@ -129,6 +129,37 @@ class UpdateRetainedDiskTests(unittest.TestCase):
self.assertEqual(instances.read(self.root,115)['observed']['image'],self.saved['observed']['image'])
self.assertEqual(json.loads(self.journal().read_text())['phase'],'rolled-back')
def test_update_command_recovers_a_failed_replacement_without_manual_recovery(self):
import oci_update_current as update
self.fail_install = True
with patch.object(update, 'update', side_effect=lambda *a: self.apply()), \
patch.object(instances, 'ROOT', self.root), \
patch.object(update, 'os', Mock(geteuid=lambda: 0)), \
patch.object(sys, 'argv', ['oci_update_current.py', '115']), \
patch.object(transaction, 'report_error'), \
patch.object(transaction, 'recovery_hint') as hint:
self.assertEqual(update.main(), 1)
self.assert_retained()
self.assertEqual(instances.read(self.root,115)['status'], 'installed')
self.assertEqual(instances.read(self.root,115)['observed']['image'],self.saved['observed']['image'])
self.assertEqual(json.loads(self.journal().read_text())['phase'],'rolled-back')
hint.assert_not_called()
def test_update_command_keeps_the_recovery_hint_when_rollback_is_blocked(self):
import oci_update_current as update
self.fail_install = True
with patch.object(update, 'update', side_effect=lambda *a: self.apply()), \
patch.object(instances, 'ROOT', self.root), \
patch.object(update, 'os', Mock(geteuid=lambda: 0)), \
patch.object(sys, 'argv', ['oci_update_current.py', '115']), \
patch.object(transaction, 'report_error'), \
patch.object(transaction, 'recover', side_effect=ValueError('configuration changed')), \
patch.object(transaction, 'recovery_hint') as hint:
self.assertEqual(update.main(), 1)
hint.assert_called_once_with()
self.assertEqual(instances.read(self.root,115)['status'], 'updating')
self.assertNotEqual(json.loads(self.journal().read_text())['phase'],'rolled-back')
def test_recovery_after_parking_data_returns_the_original_unused_disks(self):
with self.assertRaisesRegex(RuntimeError,'Lab interruption'):self.apply(interrupt_after='data-parked')
transaction.recover(self.root,self.journal());self.assert_retained()
@@ -145,4 +176,31 @@ class UpdateRetainedDiskTests(unittest.TestCase):
self.assert_retained()
class AutomaticRecoveryGuardTests(unittest.TestCase):
def test_committed_rolled_back_and_coordinated_journals_are_not_recovered(self):
for state in ({'phase':'committed'}, {'phase':'rolled-back'},
{'phase':'installing-candidate','coordinated':True}):
with self.subTest(state=state), tempfile.TemporaryDirectory() as directory:
root=Path(directory)/'instances'; journal=Path(directory)/'journal.json'
journal.write_text(json.dumps(state))
with patch.object(transaction,'recover') as recover:
self.assertFalse(transaction.recover_failed_update(root,journal))
recover.assert_not_called()
def test_missing_and_malformed_journals_leave_recovery_pending(self):
with tempfile.TemporaryDirectory() as directory:
root=Path(directory)/'instances'; journal=Path(directory)/'journal.json'
with patch.object(transaction,'recover') as recover, patch.object(transaction,'log'):
self.assertFalse(transaction.recover_failed_update(root,journal))
journal.write_text('{')
self.assertFalse(transaction.recover_failed_update(root,journal))
recover.assert_not_called()
def test_a_busy_registry_does_not_start_recovery(self):
with patch.object(instances,'locked',side_effect=BlockingIOError('busy')), \
patch.object(transaction,'recover') as recover, patch.object(transaction,'log'):
self.assertFalse(transaction.recover_failed_update(Path('/unused'),Path('/unused/journal')))
recover.assert_not_called()
if __name__=='__main__':unittest.main()