From aecb98b83da6ca3ce377e2b861923ff59543d7b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Mass=C3=A9?= Date: Wed, 25 Mar 2026 15:47:43 +0000 Subject: [PATCH] add quadlet for unifi network application --- unifi/Makefile | 10 ++++++ unifi/README.md | 23 +++++++++++++ unifi/config/examples/config.env | 22 ++++++++++++ unifi/config/examples/init-mongo.js | 15 +++++++++ unifi/overlay.bu | 9 +++++ unifi/tmpfiles.d/unifi.conf | 5 +++ unifi/unifi-app.container | 52 +++++++++++++++++++++++++++++ unifi/unifi-mongo.container | 52 +++++++++++++++++++++++++++++ unifi/unifi.target | 13 ++++++++ 9 files changed, 201 insertions(+) create mode 100644 unifi/Makefile create mode 100644 unifi/README.md create mode 100644 unifi/config/examples/config.env create mode 100755 unifi/config/examples/init-mongo.js create mode 100644 unifi/overlay.bu create mode 100644 unifi/tmpfiles.d/unifi.conf create mode 100644 unifi/unifi-app.container create mode 100644 unifi/unifi-mongo.container create mode 100644 unifi/unifi.target diff --git a/unifi/Makefile b/unifi/Makefile new file mode 100644 index 0000000..bd268cc --- /dev/null +++ b/unifi/Makefile @@ -0,0 +1,10 @@ +## +## Makefile for Unifi Network Application quadlet +## + +# Unifi quadlet is mapped to the 10011 user (unifi) and 10000 group (itix-svc) +PROJECT_UID = 10011 +PROJECT_GID = 10000 + +TOP_LEVEL_DIR := .. +include $(TOP_LEVEL_DIR)/common.mk diff --git a/unifi/README.md b/unifi/README.md new file mode 100644 index 0000000..b499e71 --- /dev/null +++ b/unifi/README.md @@ -0,0 +1,23 @@ +# Podman Quadlet: Unifi Network Application + +## Overview + +The Unifi software is a powerful, enterprise wireless software engine ideal for high-density client deployments requiring low latency and high uptime performance. + +This cookbook: + +- Runs the Unifi Network Application as a rootless container with minimal privileges. +- Uses the supplied MongoDB as the database backend. +- Includes health checks to monitor the service status. +- Stores backup in `/var/lib/virtiofs/data/unifi/`. +- Supports automatic container image updates via Podman auto-update. + +## Prerequisites + +- Configuration file `/etc/quadlets/unifi/config.env` must exist. + +## Container images + +- lscr.io/linuxserver/unifi-network-application:latest +- docker.io/library/mongo:8 + diff --git a/unifi/config/examples/config.env b/unifi/config/examples/config.env new file mode 100644 index 0000000..0e10760 --- /dev/null +++ b/unifi/config/examples/config.env @@ -0,0 +1,22 @@ +## +## Unifi Network Application Configuration Environment Variables +## + +# Major version of MongoDB +MONGO_MAJOR=8 + +# MongoDB root credentials (for initialization) +MONGO_INITDB_ROOT_USERNAME=root +MONGO_INITDB_ROOT_PASSWORD=unifi + +# MongoDB connection settings for Unifi +MONGO_USER=unifi +MONGO_PASS=unifi +MONGO_HOST=localhost +MONGO_PORT=27017 +MONGO_DBNAME=unifi +MONGO_AUTHSOURCE=admin + +# Optional: Java memory limits +#MEM_LIMIT=1024 +#MEM_STARTUP=1024 diff --git a/unifi/config/examples/init-mongo.js b/unifi/config/examples/init-mongo.js new file mode 100755 index 0000000..aca88f1 --- /dev/null +++ b/unifi/config/examples/init-mongo.js @@ -0,0 +1,15 @@ +const authSource = process.env.MONGO_AUTHSOURCE || "admin"; +const dbName = process.env.MONGO_DBNAME || "unifi"; +const user = process.env.MONGO_USER || "unifi"; +const pass = process.env.MONGO_PASS || "unifi"; + +db = db.getSiblingDB(authSource); +db.createUser({ + user: user, + pwd: pass, + roles: [ + { db: dbName, role: "dbOwner" }, + { db: dbName + "_stat", role: "dbOwner" }, + { db: dbName + "_audit", role: "dbOwner" } + ] +}); diff --git a/unifi/overlay.bu b/unifi/overlay.bu new file mode 100644 index 0000000..9299611 --- /dev/null +++ b/unifi/overlay.bu @@ -0,0 +1,9 @@ +variant: fcos +version: 1.4.0 +passwd: + users: + - name: unifi + uid: 10011 + gecos: Unifi Network Application + home_dir: /var/lib/quadlets/unifi + primary_group: itix-svc diff --git a/unifi/tmpfiles.d/unifi.conf b/unifi/tmpfiles.d/unifi.conf new file mode 100644 index 0000000..35974b4 --- /dev/null +++ b/unifi/tmpfiles.d/unifi.conf @@ -0,0 +1,5 @@ +d$ /var/lib/quadlets/unifi/mongo 0700 10011 10000 - +d$ /var/lib/quadlets/unifi/mongo/db 0700 10011 10000 - +d$ /var/lib/quadlets/unifi/mongo/configdb 0700 10011 10000 - +d$ /var/lib/quadlets/unifi/app 0700 10011 10000 - +d$ /var/lib/virtiofs/data/unifi 0700 10011 10000 - diff --git a/unifi/unifi-app.container b/unifi/unifi-app.container new file mode 100644 index 0000000..8d73a83 --- /dev/null +++ b/unifi/unifi-app.container @@ -0,0 +1,52 @@ +[Unit] +Description=Unifi Network Application +Documentation=https://docs.linuxserver.io/images/docker-unifi-network-application/ +After=network.target unifi-mongo.service +Requires=unifi-mongo.service + +# Only start if Unifi has been configured +ConditionPathExists=/etc/quadlets/unifi/config.env + +# Start/stop this unit when the target is started/stopped +PartOf=unifi.target + +[Container] +ContainerName=unifi-app +Image=lscr.io/linuxserver/unifi-network-application:latest +AutoUpdate=registry + +# Network configuration +Network=host + +# The LinuxServer Unifi image runs as root and then drops privileges to the PUID/PGID specified by environment variables. +Environment=PUID=10011 PGID=10000 + +# Environment variables for MongoDB initialization +Environment=TZ=Etc/UTC +EnvironmentFile=/etc/quadlets/unifi/config.env + +# Volume mounts +Volume=/var/lib/quadlets/unifi/app:/config:Z +Volume=/var/lib/virtiofs/data/unifi:/config/data/backup:z + +# Health check +HealthCmd=curl -kfs https://localhost:8443 || exit 1 +HealthInterval=30s +HealthTimeout=10s +HealthStartPeriod=60s +HealthRetries=3 + +[Service] +Restart=always +RestartSec=10 +TimeoutStartSec=300 +TimeoutStopSec=30 + +# These environment variables are sourced to be used by systemd in the Exec* commands +EnvironmentFile=/etc/quadlets/unifi/config.env + +# Wait for MongoDB to be ready on localhost +ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/27017; then echo "Waiting for MongoDB to be available..."; sleep 5; else exit 0; fi; done; exit 1' + +[Install] +WantedBy=unifi.target diff --git a/unifi/unifi-mongo.container b/unifi/unifi-mongo.container new file mode 100644 index 0000000..c53c5af --- /dev/null +++ b/unifi/unifi-mongo.container @@ -0,0 +1,52 @@ +[Unit] +Description=MongoDB for Unifi Network Application +Documentation=https://hub.docker.com/_/mongo/ +After=network.target + +# Only start if Unifi has been configured +ConditionPathExists=/etc/quadlets/unifi/config.env + +# Start/stop this unit when the target is started/stopped +PartOf=unifi.target + +[Container] +ContainerName=unifi-mongo +Image=docker.io/library/mongo:${MONGO_MAJOR} +AutoUpdate=registry + +# Network configuration +Network=host + +# No need for root privileges +User=10011 +Group=10000 + +# Environment variables for MongoDB initialization +Environment=MONGO_INITDB_ROOT_USERNAME MONGO_INITDB_ROOT_PASSWORD MONGO_DBNAME MONGO_USER MONGO_PASS MONGO_AUTHSOURCE + +# Bind MongoDB to localhost to prevent it from being accessible from the network, since the Unifi app will connect to it via localhost +Exec=--bind_ip 127.0.0.1 + +# Volume mounts for data persistence +Volume=/var/lib/quadlets/unifi/mongo/db:/data/db:Z +Volume=/var/lib/quadlets/unifi/mongo/configdb:/data/configdb:Z +Volume=/etc/quadlets/unifi/init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro,z + +# Health check +HealthCmd=mongosh --quiet --eval "db.runCommand({ping: 1})" || exit 1 +HealthInterval=30s +HealthTimeout=10s +HealthStartPeriod=30s +HealthRetries=3 + +[Service] +Restart=always +RestartSec=5 +TimeoutStartSec=300 +TimeoutStopSec=30 + +# These environment variables are sourced to be used by systemd in the Exec* commands +EnvironmentFile=/etc/quadlets/unifi/config.env + +[Install] +WantedBy=unifi.target diff --git a/unifi/unifi.target b/unifi/unifi.target new file mode 100644 index 0000000..e8767d6 --- /dev/null +++ b/unifi/unifi.target @@ -0,0 +1,13 @@ +[Unit] +Description=Unifi Network Application Service Target +Documentation=man:systemd.target(5) +Requires=unifi-mongo.service unifi-app.service +After=unifi-mongo.service unifi-app.service + +# Allow isolation - can stop/start this target independently +AllowIsolate=yes +# Only start if Unifi has been configured +ConditionPathExists=/etc/quadlets/unifi/config.env + +[Install] +WantedBy=multi-user.target