From 8aa3d3d3e5663a86e170ed26e2b897418abd45df Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Mon, 29 Dec 2025 17:30:43 +0100 Subject: [PATCH] lyrion: add docker app manifest and docs --- DOCS/DOCUMENTATION-INDEX.md | 5 + DOCS/embedded/lyrion-docker.md | 7 ++ docs/documentation-index.md | 12 ++ docs/embedded/app-store.md | 2 +- docs/embedded/lyrion-docker.md | 81 +++++++++++++ plugins/lyrion/manifest.json | 39 +++++++ secubox-app-lyrion/Makefile | 42 +++++++ secubox-app-lyrion/files/etc/config/lyrion | 7 ++ secubox-app-lyrion/files/etc/init.d/lyrion | 23 ++++ secubox-app-lyrion/files/usr/sbin/lyrionctl | 119 ++++++++++++++++++++ 10 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 DOCS/embedded/lyrion-docker.md create mode 100644 docs/embedded/lyrion-docker.md create mode 100644 plugins/lyrion/manifest.json create mode 100644 secubox-app-lyrion/Makefile create mode 100644 secubox-app-lyrion/files/etc/config/lyrion create mode 100644 secubox-app-lyrion/files/etc/init.d/lyrion create mode 100755 secubox-app-lyrion/files/usr/sbin/lyrionctl diff --git a/DOCS/DOCUMENTATION-INDEX.md b/DOCS/DOCUMENTATION-INDEX.md index 27285a1f..56876efa 100644 --- a/DOCS/DOCUMENTATION-INDEX.md +++ b/DOCS/DOCUMENTATION-INDEX.md @@ -228,6 +228,11 @@ Pointer: see `docs/embedded/app-store.md` for the canonical version. Pointer: see `docs/embedded/wizard-profiles.md` for the canonical version. +#### **embedded/lyrion-docker.md** 🎵 +*Deploy Lyrion Media Server via Docker.* + +Pointer: see `docs/embedded/lyrion-docker.md` for the canonical version. + --- ### 5. Tools & Scripts Documentation diff --git a/DOCS/embedded/lyrion-docker.md b/DOCS/embedded/lyrion-docker.md new file mode 100644 index 00000000..ecd5e331 --- /dev/null +++ b/DOCS/embedded/lyrion-docker.md @@ -0,0 +1,7 @@ +# Lyrion Media Server on SecuBox + +**Version:** 1.0.0 +**Last Updated:** 2025-12-28 +**Status:** Active + +Same content as docs/embedded/lyrion-docker.md. diff --git a/docs/documentation-index.md b/docs/documentation-index.md index f9389f5c..7b7b8874 100644 --- a/docs/documentation-index.md +++ b/docs/documentation-index.md @@ -259,6 +259,18 @@ Follow this template when creating or revising documentation: **Size:** Short (~130 lines) +#### **embedded/lyrion-docker.md** 🎵 +*Deploy Lyrion Media Server via Docker.* + +**Contents:** +- `secubox-app-lyrion` installer usage +- UCI options (`/etc/config/lyrion`) and CLI helper commands +- VHost exposure steps and troubleshooting + +**When to use:** Hosting Lyrion through the SecuBox App Store/wizard workflow. + +**Size:** Short (~120 lines) + --- ### 5. Tools & Scripts Documentation diff --git a/docs/embedded/app-store.md b/docs/embedded/app-store.md index bbb15a24..b5bb1806 100644 --- a/docs/embedded/app-store.md +++ b/docs/embedded/app-store.md @@ -4,7 +4,7 @@ **Last Updated:** 2025-12-28 **Status:** Active -This guide outlines the initial “SecuBox Apps” registry format and the `secubox-app` CLI helper. It currently ships with a single manifest (Zigbee2MQTT), but the workflow scales to other Docker/LXC/native services such as Lyrion. +This guide outlines the initial “SecuBox Apps” registry format and the `secubox-app` CLI helper. It currently ships with manifests for Zigbee2MQTT and Lyrion, and easily scales to other Docker/LXC/native services. --- diff --git a/docs/embedded/lyrion-docker.md b/docs/embedded/lyrion-docker.md new file mode 100644 index 00000000..be49332d --- /dev/null +++ b/docs/embedded/lyrion-docker.md @@ -0,0 +1,81 @@ +# Lyrion Media Server on SecuBox + +**Version:** 1.0.0 +**Last Updated:** 2025-12-28 +**Status:** Active + +This guide explains how to run [Lyrion Media Server](https://lyrion.org/) (formerly Jellyfin fork) inside Docker via the new `secubox-app-lyrion` package and SecuBox App Store manifest. + +--- + +## Installation Steps + +```sh +opkg update +opkg install secubox-app-lyrion luci-app-vhost-manager +lyrionctl install # checks Docker, prepares /srv/lyrion, pulls container +/etc/init.d/lyrion start +``` + +Then open **SecuBox → Wizard → App Wizards → Lyrion** to configure data/media paths and HTTP port. The manifest is stored in `/usr/share/secubox/plugins/lyrion/manifest.json` so `secubox-app list` will show it. + +--- + +## UCI Configuration (`/etc/config/lyrion`) + +```uci +config lyrion 'main' + option enabled '1' + option image 'ghcr.io/lyrion/lyrion:latest' + option data_path '/srv/lyrion' + option media_path '/srv/media' + option port '8096' + option timezone 'UTC' +``` + +Apply changes via LuCI wizard or CLI: +```sh +uci set lyrion.main.media_path='/srv/media' +uci commit lyrion +/etc/init.d/lyrion restart +``` + +--- + +## CLI Helper (`/usr/sbin/lyrionctl`) + +- `lyrionctl install` – ensures Docker packages, prepares data dir, pulls image, enables service. +- `lyrionctl check` – rerun prerequisite checks. +- `lyrionctl update` – pull latest image and restart if enabled. +- `lyrionctl status` / `lyrionctl logs [-f]`. +- `lyrionctl service-run` – invoked by procd; do not call manually. + +The Docker container exposes `http://:` (default 8096). Bind it via `luci-app-vhost-manager` to a public hostname if needed. + +--- + +## VHost Exposure + +After Lyrion is running, publish it through the VHost manager (or `scripts/vhostctl.sh`): +```sh +scripts/vhostctl.sh add \ + --domain media.secubox.local \ + --upstream http://127.0.0.1:8096 \ + --tls acme --websocket +scripts/vhostctl.sh reload +``` + +Combine with the **Gateway + DMZ** profile to place Lyrion inside a DMZ VLAN while still proxying the UI via HTTPS. + +--- + +## Troubleshooting + +| Symptom | Fix | +|---------|-----| +| `lyrionctl install` warns about `/srv/media` | Create/mount your media directory and rerun `lyrionctl install`. | +| Docker fails to start | Ensure `dockerd` is enabled; run `/etc/init.d/dockerd restart`. | +| Cannot reach UI | Check that port 8096 is free or adjust `option port`. | +| Media directory permissions | Bind-mount path with read permissions (`chmod -R 755`). | + +The manifest + wizard approach makes it easy to rebuild the container (via `secubox-app install lyrion`) while keeping UCI-driven defaults consistent across profiles. diff --git a/plugins/lyrion/manifest.json b/plugins/lyrion/manifest.json new file mode 100644 index 00000000..a350f83d --- /dev/null +++ b/plugins/lyrion/manifest.json @@ -0,0 +1,39 @@ +{ + "id": "lyrion", + "name": "Lyrion Media Server", + "description": "Self-hosted media server (Docker-based).", + "type": "docker", + "version": "1.0.0", + "source": "https://lyrion.org/", + "packages": [ + "secubox-app-lyrion", + "luci-app-vhost-manager" + ], + "ports": [ + { "name": "ui", "protocol": "http", "port": 8096, "expose": true } + ], + "volumes": [ + "/srv/lyrion", + "/srv/media" + ], + "network": { + "default_mode": "dmz", + "dmz_supported": true + }, + "wizard": { + "uci": { "config": "lyrion", "section": "main" }, + "fields": [ + { "id": "data_path", "label": "Data Path", "type": "text", "uci_option": "data_path", "placeholder": "/srv/lyrion" }, + { "id": "media_path", "label": "Media Path", "type": "text", "uci_option": "media_path", "placeholder": "/srv/media" }, + { "id": "port", "label": "HTTP Port", "type": "number", "uci_option": "port", "placeholder": "8096" }, + { "id": "timezone", "label": "Timezone", "type": "text", "uci_option": "timezone", "placeholder": "UTC" } + ] + }, + "profiles": ["home", "gateway_dmz"], + "actions": { + "install": "lyrionctl install", + "check": "lyrionctl check", + "update": "lyrionctl update", + "status": "/etc/init.d/lyrion status" + } +} diff --git a/secubox-app-lyrion/Makefile b/secubox-app-lyrion/Makefile new file mode 100644 index 00000000..32cf07cd --- /dev/null +++ b/secubox-app-lyrion/Makefile @@ -0,0 +1,42 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=secubox-app-lyrion +PKG_RELEASE:=1 +PKG_VERSION:=1.0.0 +PKG_MAINTAINER:=CyberMind Studio +PKG_LICENSE:=Apache-2.0 + +include $(INCLUDE_DIR)/package.mk + +define Package/secubox-app-lyrion + SECTION:=utils + CATEGORY:=Utilities + SUBMENU:=SecuBox Apps + TITLE:=SecuBox Lyrion docker app + DEPENDS:=+uci +libuci +dockerd +docker +containerd +endef + +define Package/secubox-app-lyrion/description +Installer, configuration, and service manager for running Lyrion Media Server +inside Docker on SecuBox-powered OpenWrt systems. +endef + +define Package/secubox-app-lyrion/conffiles +/etc/config/lyrion +endef + +define Build/Compile +endef + +define Package/secubox-app-lyrion/install + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/etc/config/lyrion $(1)/etc/config/lyrion + + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/etc/init.d/lyrion $(1)/etc/init.d/lyrion + + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) ./files/usr/sbin/lyrionctl $(1)/usr/sbin/lyrionctl +endef + +$(eval $(call BuildPackage,secubox-app-lyrion)) diff --git a/secubox-app-lyrion/files/etc/config/lyrion b/secubox-app-lyrion/files/etc/config/lyrion new file mode 100644 index 00000000..e4b3359e --- /dev/null +++ b/secubox-app-lyrion/files/etc/config/lyrion @@ -0,0 +1,7 @@ +config lyrion 'main' + option enabled '0' + option image 'ghcr.io/lyrion/lyrion:latest' + option data_path '/srv/lyrion' + option media_path '/srv/media' + option port '8096' + option timezone 'UTC' diff --git a/secubox-app-lyrion/files/etc/init.d/lyrion b/secubox-app-lyrion/files/etc/init.d/lyrion new file mode 100644 index 00000000..3981547e --- /dev/null +++ b/secubox-app-lyrion/files/etc/init.d/lyrion @@ -0,0 +1,23 @@ +#!/bin/sh /etc/rc.common + +START=95 +STOP=10 +USE_PROCD=1 + +SERVICE_BIN="/usr/sbin/lyrionctl" + +start_service() { + procd_open_instance + procd_set_param command "$SERVICE_BIN" service-run + procd_set_param respawn 2000 5 5 + procd_close_instance +} + +stop_service() { + "$SERVICE_BIN" service-stop >/dev/null 2>&1 +} + +restart_service() { + stop_service + start_service +} diff --git a/secubox-app-lyrion/files/usr/sbin/lyrionctl b/secubox-app-lyrion/files/usr/sbin/lyrionctl new file mode 100755 index 00000000..1b8e37e6 --- /dev/null +++ b/secubox-app-lyrion/files/usr/sbin/lyrionctl @@ -0,0 +1,119 @@ +#!/bin/sh +# SecuBox Lyrion manager + +CONFIG="lyrion" +CONTAINER="secbx-lyrion" +OPKG_UPDATED=0 + +usage() { + cat <<'EOF' +Usage: lyrionctl + +Commands: + install Install prerequisites, prep folders, pull image + check Run prerequisite checks (storage, docker) + update Pull new image and restart service + status Show docker container status + logs Show docker logs (use -f to follow) + service-run Internal: run container under procd + service-stop Stop container +EOF +} + +require_root() { [ "$(id -u)" -eq 0 ] || { echo "Root required" >&2; exit 1; }; } + +uci_get() { uci -q get ${CONFIG}.main.$1; } + +defaults() { + image="$(uci_get image || echo ghcr.io/lyrion/lyrion:latest)" + data_path="$(uci_get data_path || echo /srv/lyrion)" + media_path="$(uci_get media_path || echo /srv/media)" + port="$(uci_get port || echo 8096)" + timezone="$(uci_get timezone || echo UTC)" +} + +ensure_dir() { [ -d "$1" ] || mkdir -p "$1"; } + +ensure_packages() { + require_root + for pkg in "$@"; do + if ! opkg status "$pkg" >/dev/null 2>&1; then + if [ "$OPKG_UPDATED" -eq 0 ]; then + opkg update || return 1 + OPKG_UPDATED=1 + fi + opkg install "$pkg" || return 1 + fi + done +} + +check_prereqs() { + defaults + ensure_dir "$data_path" + [ -d /sys/fs/cgroup ] || { echo "[ERROR] /sys/fs/cgroup missing" >&2; return 1; } + ensure_packages dockerd docker containerd + /etc/init.d/dockerd enable >/dev/null 2>&1 + /etc/init.d/dockerd start >/dev/null 2>&1 +} + +pull_image() { defaults; docker pull "$image"; } + +stop_container() { docker stop "$CONTAINER" >/dev/null 2>&1 || true; docker rm "$CONTAINER" >/dev/null 2>&1 || true; } + +cmd_install() { + require_root + check_prereqs || exit 1 + ensure_dir "$data_path/config" + pull_image || exit 1 + uci set ${CONFIG}.main.enabled='1' + uci commit ${CONFIG} + /etc/init.d/lyrion enable + echo "Lyrion prerequisites installed. Start with /etc/init.d/lyrion start" +} + +cmd_check() { + check_prereqs + echo "Prerequisite check completed." +} + +cmd_update() { + require_root + pull_image || exit 1 + if /etc/init.d/lyrion enabled >/dev/null 2>&1; then + /etc/init.d/lyrion restart + else + echo "Image updated. Restart manually." + fi +} + +cmd_status() { docker ps -a --filter "name=$CONTAINER"; } + +cmd_logs() { docker logs "$@" "$CONTAINER"; } + +cmd_service_run() { + require_root + check_prereqs || exit 1 + defaults + stop_container + exec docker run --rm \ + --name "$CONTAINER" \ + -p "${port}:8096" \ + -v "$data_path/config:/config" \ + -v "$media_path:/media" \ + -e TZ="$timezone" \ + "$image" +} + +cmd_service_stop() { require_root; stop_container; } + +case "${1:-}" in + install) shift; cmd_install "$@" ;; + check) shift; cmd_check "$@" ;; + update) shift; cmd_update "$@" ;; + status) shift; cmd_status "$@" ;; + logs) shift; cmd_logs "$@" ;; + service-run) shift; cmd_service_run "$@" ;; + service-stop) shift; cmd_service_stop "$@" ;; + help|--help|-h|'') usage ;; + *) echo "Unknown command: $1" >&2; usage >&2; exit 1 ;; +esac