From 9ab744e7840cc3963ec025ae59045d98cd12e331 Mon Sep 17 00:00:00 2001 From: Jonatan Date: Tue, 27 Oct 2026 20:49:25 +0100 Subject: [PATCH 1/2] feat(oci): add Zigbee2MQTT --- lang/de.json | 2 + lang/es.json | 2 + lang/fr.json | 2 + lang/it.json | 2 + lang/pt.json | 2 + lang/sk.json | 2 + lang/sv.json | 2 + oci/VALIDATION.md | 2 +- oci/catalog/apps/zigbee2mqtt.json | 430 +++++++++++++++++++++++++++ oci/catalog/curated/zigbee2mqtt.json | 430 +++++++++++++++++++++++++++ oci/catalog/index.json | 33 ++ 11 files changed, 908 insertions(+), 1 deletion(-) create mode 100644 oci/catalog/apps/zigbee2mqtt.json create mode 100644 oci/catalog/curated/zigbee2mqtt.json diff --git a/lang/de.json b/lang/de.json index 8a299f33..84917c9d 100644 --- a/lang/de.json +++ b/lang/de.json @@ -1283,6 +1283,7 @@ "Conflicting drivers blacklisted successfully.": "In Konflikt stehende Treiber wurden erfolgreich auf die schwarze Liste gesetzt.", "Conflicting path included in backup:": "In der Sicherung enthaltener widersprüchlicher Pfad:", "Conflicting utilities removed": "Widersprüchliche Dienstprogramme entfernt", + "Connect Zigbee devices to MQTT with a browser-based setup interface.": "Verbinde Zigbee-Geräte mit MQTT über eine webbasierte Einrichtungsoberfläche.", "Connect a Coral Accelerator and try again.": "Schließen Sie einen Coral Accelerator an und versuchen Sie es erneut.", "Connect it, or remove it from the container in Proxmox (Resources), and run the recovery again.": "Verbinden Sie es oder entfernen Sie es aus dem Container in Proxmox (Ressourcen) und führen Sie die Wiederherstellung erneut aus.", "Connect your devices and users together in your own secure virtual private network.": "Verbinden Sie Ihre Geräte und Benutzer in Ihrem eigenen sicheren virtuellen privaten Netzwerk.", @@ -6316,6 +6317,7 @@ "Settings": "Einstellungen", "Settings post-install Proxmox": "Einstellungen nach der Installation von Proxmox", "Setup Persistent Network Names": "Persistente Netzwerknamen einrichten", + "Setup Web UI": "Weboberfläche zur Einrichtung", "Setup key from the NetBird dashboard": "Setup-Schlüssel aus dem NetBird-Dashboard", "Shaarli": "Shaarli", "Share Access Error": "Fehler beim Freigabezugriff", diff --git a/lang/es.json b/lang/es.json index 10d69865..79607210 100644 --- a/lang/es.json +++ b/lang/es.json @@ -1283,6 +1283,7 @@ "Conflicting drivers blacklisted successfully.": "Los controladores en conflicto se incluyeron correctamente en la lista negra.", "Conflicting path included in backup:": "Ruta conflictiva incluida en el backup:", "Conflicting utilities removed": "Se eliminaron las utilidades conflictivas", + "Connect Zigbee devices to MQTT with a browser-based setup interface.": "Conecta dispositivos Zigbee a MQTT mediante una interfaz web de configuración.", "Connect a Coral Accelerator and try again.": "Conecta un Coral Accelerator y vuelve a intentarlo.", "Connect it, or remove it from the container in Proxmox (Resources), and run the recovery again.": "Conéctalo, o elimínalo del contenedor en Proxmox (Recursos), y vuelve a lanzar la recuperación.", "Connect your devices and users together in your own secure virtual private network.": "Conecta tus dispositivos y usuarios en tu propia red privada virtual segura.", @@ -6300,6 +6301,7 @@ "Settings": "Ajustes", "Settings post-install Proxmox": "Configuración post instalación de Proxmox", "Setup Persistent Network Names": "Configurar nombres de red persistentes", + "Setup Web UI": "Interfaz web de configuración", "Setup key from the NetBird dashboard": "Clave de configuración (setup key) del panel de NetBird", "Shaarli": "Shaarli", "Share Access Error": "Error de acceso al recurso compartido", diff --git a/lang/fr.json b/lang/fr.json index ad7891f6..a34d90ea 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -1283,6 +1283,7 @@ "Conflicting drivers blacklisted successfully.": "Pilotes en conflit mis sur liste noire avec succès.", "Conflicting path included in backup:": "Chemin d'accès en conflit inclus dans la sauvegarde :", "Conflicting utilities removed": "Utilitaires en conflit supprimés", + "Connect Zigbee devices to MQTT with a browser-based setup interface.": "Connectez les appareils Zigbee à MQTT via une interface web de configuration.", "Connect a Coral Accelerator and try again.": "Connectez un accélérateur Coral et réessayez.", "Connect it, or remove it from the container in Proxmox (Resources), and run the recovery again.": "Connectez-le ou supprimez-le du conteneur dans Proxmox (Ressources) et réexécutez la récupération.", "Connect your devices and users together in your own secure virtual private network.": "Connectez vos appareils et utilisateurs ensemble dans votre propre réseau privé virtuel sécurisé.", @@ -6316,6 +6317,7 @@ "Settings": "Paramètres", "Settings post-install Proxmox": "Paramètres post-installation de Proxmox", "Setup Persistent Network Names": "configurer des noms de réseau persistants", + "Setup Web UI": "Interface web de configuration", "Setup key from the NetBird dashboard": "Clé de configuration du tableau de bord NetBird", "Shaarli": "Shaarli", "Share Access Error": "Erreur d'accès au partage", diff --git a/lang/it.json b/lang/it.json index 6b1c6089..04d6a7df 100644 --- a/lang/it.json +++ b/lang/it.json @@ -1283,6 +1283,7 @@ "Conflicting drivers blacklisted successfully.": "Driver in conflitto inseriti nella lista nera correttamente.", "Conflicting path included in backup:": "Percorso in conflitto incluso nel backup:", "Conflicting utilities removed": "Utilità in conflitto rimosse", + "Connect Zigbee devices to MQTT with a browser-based setup interface.": "Collega i dispositivi Zigbee a MQTT tramite un’interfaccia web di configurazione.", "Connect a Coral Accelerator and try again.": "Collega un Coral Accelerator e riprova.", "Connect it, or remove it from the container in Proxmox (Resources), and run the recovery again.": "Collegalo o rimuovilo dal container in Proxmox (Risorse), poi ripeti il recupero.", "Connect your devices and users together in your own secure virtual private network.": "Collega dispositivi e utenti nella tua rete privata virtuale sicura.", @@ -6316,6 +6317,7 @@ "Settings": "Impostazioni", "Settings post-install Proxmox": "Impostazioni post-installazione Proxmox", "Setup Persistent Network Names": "Imposta nomi persistenti per le interfacce di rete", + "Setup Web UI": "Interfaccia web di configurazione", "Setup key from the NetBird dashboard": "Setup key dalla dashboard NetBird", "Shaarli": "Shaarli", "Share Access Error": "Errore di accesso alla condivisione", diff --git a/lang/pt.json b/lang/pt.json index b1db5161..da964694 100644 --- a/lang/pt.json +++ b/lang/pt.json @@ -1283,6 +1283,7 @@ "Conflicting drivers blacklisted successfully.": "Drivers conflitantes colocados na lista negra com sucesso.", "Conflicting path included in backup:": "Caminho conflitante incluído no backup:", "Conflicting utilities removed": "Utilitários conflitantes removidos", + "Connect Zigbee devices to MQTT with a browser-based setup interface.": "Conecte dispositivos Zigbee ao MQTT por meio de uma interface web de configuração.", "Connect a Coral Accelerator and try again.": "Conecte um Coral Accelerator e tente novamente.", "Connect it, or remove it from the container in Proxmox (Resources), and run the recovery again.": "Conecte-o ou remova-o do contêiner em Proxmox (Recursos) e execute a recuperação novamente.", "Connect your devices and users together in your own secure virtual private network.": "Conecte seus dispositivos e usuários em sua própria rede privada virtual segura.", @@ -6316,6 +6317,7 @@ "Settings": "Configurações", "Settings post-install Proxmox": "Configurações pós-instalação do Proxmox", "Setup Persistent Network Names": "Configurar nomes de rede persistentes", + "Setup Web UI": "Interface web de configuração", "Setup key from the NetBird dashboard": "Chave de configuração do painel NetBird", "Shaarli": "Shaarli", "Share Access Error": "Erro de acesso ao compartilhamento", diff --git a/lang/sk.json b/lang/sk.json index 83546d74..c71d30da 100644 --- a/lang/sk.json +++ b/lang/sk.json @@ -1283,6 +1283,7 @@ "Conflicting drivers blacklisted successfully.": "Konfliktné ovládače boli úspešne pridané na blacklist.", "Conflicting path included in backup:": "Konfliktná cesta zahrnutá v zálohe:", "Conflicting utilities removed": "Konfliktné nástroje odstránené", + "Connect Zigbee devices to MQTT with a browser-based setup interface.": "Pripojte zariadenia Zigbee k MQTT prostredníctvom webového rozhrania na nastavenie.", "Connect a Coral Accelerator and try again.": "Pripojte Coral Accelerator a skúste to znova.", "Connect it, or remove it from the container in Proxmox (Resources), and run the recovery again.": "Pripojte zariadenie alebo ho odstráňte z konfigurácie kontajnera v Proxmoxe (Zdroje) a registráciu zopakujte.", "Connect your devices and users together in your own secure virtual private network.": "Spojte svoje zariadenia a užívateľov vo vlastnej zabezpečenej virtuálnej súkromnej sieti.", @@ -6318,6 +6319,7 @@ "Settings": "Nastavenia", "Settings post-install Proxmox": "Nastavenie Proxmoxu po inštalácii", "Setup Persistent Network Names": "Nastaviť trvalé názvy sieťových rozhraní", + "Setup Web UI": "Webové rozhranie na nastavenie", "Setup key from the NetBird dashboard": "Inštalačný kľúč z ovládacieho panela NetBird", "Shaarli": "Shaarli", "Share Access Error": "Chyba prístupu k zdieľaniu", diff --git a/lang/sv.json b/lang/sv.json index ceed8d07..ede4a768 100644 --- a/lang/sv.json +++ b/lang/sv.json @@ -1283,6 +1283,7 @@ "Conflicting drivers blacklisted successfully.": "Motstridiga drivrutiner har svartlistats framgångsrikt.", "Conflicting path included in backup:": "Motstridig sökväg som ingår i säkerhetskopieringen:", "Conflicting utilities removed": "Motstridiga verktyg har tagits bort", + "Connect Zigbee devices to MQTT with a browser-based setup interface.": "Anslut Zigbee-enheter till MQTT med ett webbaserat konfigurationsgränssnitt.", "Connect a Coral Accelerator and try again.": "Anslut en Coral Accelerator och försök igen.", "Connect it, or remove it from the container in Proxmox (Resources), and run the recovery again.": "Anslut den, eller ta bort den från behållaren i Proxmox (Resurser), och kör återställningen igen.", "Connect your devices and users together in your own secure virtual private network.": "Anslut dina enheter och användare tillsammans i ditt eget säkra virtuella privata nätverk.", @@ -6316,6 +6317,7 @@ "Settings": "Inställningar", "Settings post-install Proxmox": "Inställningar efter installation av Proxmox", "Setup Persistent Network Names": "Ställ in beständiga nätverksnamn", + "Setup Web UI": "Webbgränssnitt för konfiguration", "Setup key from the NetBird dashboard": "Setup-nyckel från NetBird-instrumentpanelen", "Shaarli": "Shaarli", "Share Access Error": "Dela åtkomstfel", diff --git a/oci/VALIDATION.md b/oci/VALIDATION.md index 58bf4135..528773e6 100644 --- a/oci/VALIDATION.md +++ b/oci/VALIDATION.md @@ -2,7 +2,7 @@ -43 of 526 applications in the OCI catalog have been tested for real: 41 in the ProxMenux lab and 2 by the community. The OCI installer shows them as verified, with a ✓ in the lists. +43 of 527 applications in the OCI catalog have been tested for real: 41 in the ProxMenux lab and 2 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. diff --git a/oci/catalog/apps/zigbee2mqtt.json b/oci/catalog/apps/zigbee2mqtt.json new file mode 100644 index 00000000..a1f94973 --- /dev/null +++ b/oci/catalog/apps/zigbee2mqtt.json @@ -0,0 +1,430 @@ +{ + "schema_version": "0.5.0", + "kind": "proxmenux.oci-template", + "id": "image-zigbee2mqtt", + "status": "generated-unvalidated", + "catalog_ui": { + "title": { + "en_US": "Zigbee2MQTT" + }, + "tagline": { + "en_US": "Connect Zigbee devices to MQTT with a browser-based setup interface." + }, + "description": { + "en_US": "Zigbee2MQTT bridges Zigbee devices to MQTT and provides a web interface for configuration and monitoring." + }, + "category": "smarthome", + "category_label": "IoT & Smart Home", + "author": "Koenkk", + "developer": "Koenkk", + "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/zigbee2mqtt.webp", + "thumbnail": null, + "screenshots": [], + "architectures": [ + "amd64", + "arm64" + ], + "launch": { + "scheme": "http", + "port": 8080, + "path": "/" + }, + "website": "https://www.zigbee2mqtt.io/", + "documentation": "https://www.zigbee2mqtt.io/guide/installation/02_docker.html", + "repository": "https://github.com/Koenkk/zigbee2mqtt", + "tips": [ + "On the first start, the setup interface is available at port 8080 before MQTT and an adapter are configured.", + "For Zigbee operation, configure an MQTT broker and pass through a compatible USB/serial adapter in Advanced settings." + ], + "mini_changelog": [], + "display_version": null, + "updated_at": null + }, + "source": { + "provider": "official", + "repository": "https://github.com/Koenkk/zigbee2mqtt", + "revision": "344b6e03b43644c97154a72ca9eae17193c553a2", + "image_repository_url": "https://github.com/Koenkk/zigbee2mqtt/pkgs/container/zigbee2mqtt", + "readme_pushed_at": "2026-10-27T00:00:00Z", + "compose_sha256": "5ab8af290e69c4fed429e741334f8a68263c8d274abccbeaf1ddc2c282d8f8e4", + "generated_at": "2026-10-27T19:27:26+00:00", + "readme_raw_url": "https://www.zigbee2mqtt.io/guide/installation/02_docker.html" + }, + "container_contract": { + "service_name": "zigbee2mqtt", + "container_name": "zigbee2mqtt", + "image": { + "reference": "ghcr.io/koenkk/zigbee2mqtt:latest", + "registry": "ghcr.io", + "repository": "ghcr.io/koenkk/zigbee2mqtt", + "tag": "latest", + "digest": null, + "pull_policy": "resolve-selected-tag-to-architecture-digest-at-install" + }, + "environment": [], + "volumes": [ + { + "id": "volume-0", + "container_path": "/app/data", + "compose_source_example": "./data", + "read_only": false, + "required": true, + "installation_choice": [ + "managed-volume", + "host-bind" + ], + "default": "managed-volume", + "managed_volume": { + "backup": true, + "default_size_gb": 8 + } + } + ], + "ports": [ + { + "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": "name: zigbee2mqtt\nservices:\n zigbee2mqtt:\n image: ghcr.io/koenkk/zigbee2mqtt:latest\n container_name: zigbee2mqtt\n restart: unless-stopped\n ports:\n - 8080:8080/tcp\n volumes:\n - ./data:/app/data\n" + }, + "compose_stack": { + "project_name": "zigbee2mqtt", + "deployment_model": "one-native-oci-lxc-per-compose-service", + "user_experience": "single-application-install", + "main_service": "zigbee2mqtt", + "service_count": 1, + "services": [ + { + "name": "zigbee2mqtt", + "image": "ghcr.io/koenkk/zigbee2mqtt:latest", + "is_main": true, + "role": "frontend", + "vmid_offset": 0, + "depends_on": [], + "frontend_network": true, + "private_network": false, + "compose": { + "image": "ghcr.io/koenkk/zigbee2mqtt:latest", + "container_name": "zigbee2mqtt", + "restart": "unless-stopped", + "ports": [ + "8080:8080/tcp" + ], + "volumes": [ + "./data:/app/data" + ] + } + } + ], + "top_level": { + "name": "zigbee2mqtt" + }, + "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": "zigbee2mqtt-volume-0", + "service": "zigbee2mqtt", + "container_path": "/app/data", + "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": [ + "zigbee2mqtt" + ], + "stop_order": [ + "zigbee2mqtt" + ], + "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": [] + } + }, + "first_run": { + "endpoints": [ + { + "label": "Setup Web UI", + "scheme": "http", + "port": 8080, + "path": "/", + "source": "official-docker-documentation" + } + ], + "credentials": [] + }, + "proxmox": { + "runtime": "native-oci-lxc", + "technology_status": "proxmox-technology-preview", + "defaults": { + "unprivileged": true, + "ostype": "auto-from-image", + "cores": 2, + "memory_mb": 1024, + "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" + } + ], + "installer_profile": { + "startup_healthcheck": { + "scheme": "http", + "port": 8080, + "path": "/", + "timeout_seconds": 180, + "request_timeout_seconds": 10, + "stability_seconds": 4, + "verify_tls": true + } + } + }, + "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", + "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": "pending", + "service_health": "pending", + "restart_persistence": "pending", + "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 + } +} diff --git a/oci/catalog/curated/zigbee2mqtt.json b/oci/catalog/curated/zigbee2mqtt.json new file mode 100644 index 00000000..a1f94973 --- /dev/null +++ b/oci/catalog/curated/zigbee2mqtt.json @@ -0,0 +1,430 @@ +{ + "schema_version": "0.5.0", + "kind": "proxmenux.oci-template", + "id": "image-zigbee2mqtt", + "status": "generated-unvalidated", + "catalog_ui": { + "title": { + "en_US": "Zigbee2MQTT" + }, + "tagline": { + "en_US": "Connect Zigbee devices to MQTT with a browser-based setup interface." + }, + "description": { + "en_US": "Zigbee2MQTT bridges Zigbee devices to MQTT and provides a web interface for configuration and monitoring." + }, + "category": "smarthome", + "category_label": "IoT & Smart Home", + "author": "Koenkk", + "developer": "Koenkk", + "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/zigbee2mqtt.webp", + "thumbnail": null, + "screenshots": [], + "architectures": [ + "amd64", + "arm64" + ], + "launch": { + "scheme": "http", + "port": 8080, + "path": "/" + }, + "website": "https://www.zigbee2mqtt.io/", + "documentation": "https://www.zigbee2mqtt.io/guide/installation/02_docker.html", + "repository": "https://github.com/Koenkk/zigbee2mqtt", + "tips": [ + "On the first start, the setup interface is available at port 8080 before MQTT and an adapter are configured.", + "For Zigbee operation, configure an MQTT broker and pass through a compatible USB/serial adapter in Advanced settings." + ], + "mini_changelog": [], + "display_version": null, + "updated_at": null + }, + "source": { + "provider": "official", + "repository": "https://github.com/Koenkk/zigbee2mqtt", + "revision": "344b6e03b43644c97154a72ca9eae17193c553a2", + "image_repository_url": "https://github.com/Koenkk/zigbee2mqtt/pkgs/container/zigbee2mqtt", + "readme_pushed_at": "2026-10-27T00:00:00Z", + "compose_sha256": "5ab8af290e69c4fed429e741334f8a68263c8d274abccbeaf1ddc2c282d8f8e4", + "generated_at": "2026-10-27T19:27:26+00:00", + "readme_raw_url": "https://www.zigbee2mqtt.io/guide/installation/02_docker.html" + }, + "container_contract": { + "service_name": "zigbee2mqtt", + "container_name": "zigbee2mqtt", + "image": { + "reference": "ghcr.io/koenkk/zigbee2mqtt:latest", + "registry": "ghcr.io", + "repository": "ghcr.io/koenkk/zigbee2mqtt", + "tag": "latest", + "digest": null, + "pull_policy": "resolve-selected-tag-to-architecture-digest-at-install" + }, + "environment": [], + "volumes": [ + { + "id": "volume-0", + "container_path": "/app/data", + "compose_source_example": "./data", + "read_only": false, + "required": true, + "installation_choice": [ + "managed-volume", + "host-bind" + ], + "default": "managed-volume", + "managed_volume": { + "backup": true, + "default_size_gb": 8 + } + } + ], + "ports": [ + { + "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": "name: zigbee2mqtt\nservices:\n zigbee2mqtt:\n image: ghcr.io/koenkk/zigbee2mqtt:latest\n container_name: zigbee2mqtt\n restart: unless-stopped\n ports:\n - 8080:8080/tcp\n volumes:\n - ./data:/app/data\n" + }, + "compose_stack": { + "project_name": "zigbee2mqtt", + "deployment_model": "one-native-oci-lxc-per-compose-service", + "user_experience": "single-application-install", + "main_service": "zigbee2mqtt", + "service_count": 1, + "services": [ + { + "name": "zigbee2mqtt", + "image": "ghcr.io/koenkk/zigbee2mqtt:latest", + "is_main": true, + "role": "frontend", + "vmid_offset": 0, + "depends_on": [], + "frontend_network": true, + "private_network": false, + "compose": { + "image": "ghcr.io/koenkk/zigbee2mqtt:latest", + "container_name": "zigbee2mqtt", + "restart": "unless-stopped", + "ports": [ + "8080:8080/tcp" + ], + "volumes": [ + "./data:/app/data" + ] + } + } + ], + "top_level": { + "name": "zigbee2mqtt" + }, + "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": "zigbee2mqtt-volume-0", + "service": "zigbee2mqtt", + "container_path": "/app/data", + "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": [ + "zigbee2mqtt" + ], + "stop_order": [ + "zigbee2mqtt" + ], + "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": [] + } + }, + "first_run": { + "endpoints": [ + { + "label": "Setup Web UI", + "scheme": "http", + "port": 8080, + "path": "/", + "source": "official-docker-documentation" + } + ], + "credentials": [] + }, + "proxmox": { + "runtime": "native-oci-lxc", + "technology_status": "proxmox-technology-preview", + "defaults": { + "unprivileged": true, + "ostype": "auto-from-image", + "cores": 2, + "memory_mb": 1024, + "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" + } + ], + "installer_profile": { + "startup_healthcheck": { + "scheme": "http", + "port": 8080, + "path": "/", + "timeout_seconds": 180, + "request_timeout_seconds": 10, + "stability_seconds": 4, + "verify_tls": true + } + } + }, + "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", + "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": "pending", + "service_health": "pending", + "restart_persistence": "pending", + "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 + } +} diff --git a/oci/catalog/index.json b/oci/catalog/index.json index 2dd9fd72..f9b1db94 100644 --- a/oci/catalog/index.json +++ b/oci/catalog/index.json @@ -18340,6 +18340,39 @@ "hidden": false, "template_id": "linuxserver-zen" }, + { + "id": "zigbee2mqtt", + "provider": "official", + "template_family": "curated-profile", + "title": "Zigbee2MQTT", + "repository": "https://github.com/Koenkk/zigbee2mqtt", + "description": "Zigbee2MQTT bridges Zigbee devices to MQTT and provides a web interface for configuration and monitoring.", + "website": "https://www.zigbee2mqtt.io/", + "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/zigbee2mqtt.webp", + "architectures": [ + "amd64", + "arm64" + ], + "updated_at": null, + "main_image": "ghcr.io/koenkk/zigbee2mqtt:latest", + "category": "smarthome", + "category_label": "IoT & Smart Home", + "replaces_discovered_ids": [], + "curated_path": "catalog/curated/zigbee2mqtt.json", + "template": "apps/zigbee2mqtt.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, + "multi_container": false, + "template_id": "image-zigbee2mqtt" + }, { "id": "zipkin", "provider": "OpenZipkin", From a079f3fc90e491edebe88f118cd656f04779888e Mon Sep 17 00:00:00 2001 From: Jonatan Date: Tue, 27 Oct 2026 23:21:32 +0100 Subject: [PATCH 2/2] feat(oci): add optional Zigbee serial adapter --- oci/catalog/apps/zigbee2mqtt.json | 18 +++++++++++++++++- oci/catalog/curated/zigbee2mqtt.json | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/oci/catalog/apps/zigbee2mqtt.json b/oci/catalog/apps/zigbee2mqtt.json index a1f94973..378c8dcd 100644 --- a/oci/catalog/apps/zigbee2mqtt.json +++ b/oci/catalog/apps/zigbee2mqtt.json @@ -362,7 +362,23 @@ "request_timeout_seconds": 10, "stability_seconds": 4, "verify_tls": true - } + }, + "optional_devices": [ + { + "id": "zigbee-serial-adapter", + "kind": "character-device", + "purpose": "serial", + "enable_prompt": "Pass a host device to the LXC", + "enabled_default": false, + "required_by_compose": false, + "path_prompt": "USB or serial device node", + "host_path_default": "/dev/ttyACM0", + "container_path_strategy": "same-as-host", + "mode": "preserve-host", + "deny_write": false, + "gid_strategy": "host-device-gid" + } + ] } }, "compatibility": { diff --git a/oci/catalog/curated/zigbee2mqtt.json b/oci/catalog/curated/zigbee2mqtt.json index a1f94973..378c8dcd 100644 --- a/oci/catalog/curated/zigbee2mqtt.json +++ b/oci/catalog/curated/zigbee2mqtt.json @@ -362,7 +362,23 @@ "request_timeout_seconds": 10, "stability_seconds": 4, "verify_tls": true - } + }, + "optional_devices": [ + { + "id": "zigbee-serial-adapter", + "kind": "character-device", + "purpose": "serial", + "enable_prompt": "Pass a host device to the LXC", + "enabled_default": false, + "required_by_compose": false, + "path_prompt": "USB or serial device node", + "host_path_default": "/dev/ttyACM0", + "container_path_strategy": "same-as-host", + "mode": "preserve-host", + "deny_write": false, + "gid_strategy": "host-device-gid" + } + ] } }, "compatibility": {