From b8a1879b24d2fb8802b8521ad2e28194dd4e97b9 Mon Sep 17 00:00:00 2001 From: MickLesk Date: Fri, 3 Jul 2026 09:34:21 +0200 Subject: [PATCH 001/245] hotfix: retry npm install with --force for corepack shims Add a fallback retry using `npm install -g --force` when the initial install fails. This handles EEXIST errors caused by corepack-provided shims for pnpm/yarn that ship with recent Node.js versions and block installation to /usr/bin/. --- misc/tools.func | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/misc/tools.func b/misc/tools.func index 742244c3a..fc01a6fc0 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -7627,7 +7627,10 @@ setup_nodejs() { MODULE_INSTALLED_VERSION="$(npm list -g --depth=0 "$MODULE_NAME" 2>&1 | grep "$MODULE_NAME@" | awk -F@ '{print $2}' 2>/dev/null | tr -d '[:space:]' || echo '')" if [[ "$MODULE_REQ_VERSION" != "latest" && "$MODULE_REQ_VERSION" != "$MODULE_INSTALLED_VERSION" ]]; then msg_info "Updating $MODULE_NAME to v$MODULE_REQ_VERSION" - if $STD npm install -g "${MODULE_NAME}@${MODULE_REQ_VERSION}" 2>/dev/null; then + # Retry with --force to overwrite corepack-provided shims (pnpm/yarn), which now + # ship with recent corepack and cause EEXIST on /usr/bin/ + if $STD npm install -g "${MODULE_NAME}@${MODULE_REQ_VERSION}" 2>/dev/null || + $STD npm install -g --force "${MODULE_NAME}@${MODULE_REQ_VERSION}" 2>/dev/null; then msg_ok "Updated $MODULE_NAME" else msg_warn "Failed to update $MODULE_NAME to version $MODULE_REQ_VERSION" @@ -7635,7 +7638,8 @@ setup_nodejs() { fi elif [[ "$MODULE_REQ_VERSION" == "latest" ]]; then msg_info "Updating $MODULE_NAME to latest version" - if $STD npm install -g "${MODULE_NAME}@latest" 2>/dev/null; then + if $STD npm install -g "${MODULE_NAME}@latest" 2>/dev/null || + $STD npm install -g --force "${MODULE_NAME}@latest" 2>/dev/null; then msg_ok "Updated $MODULE_NAME" else msg_warn "Failed to update $MODULE_NAME to latest version" @@ -7644,7 +7648,10 @@ setup_nodejs() { fi else msg_info "Installing $MODULE_NAME@$MODULE_REQ_VERSION" - if $STD npm install -g "${MODULE_NAME}@${MODULE_REQ_VERSION}" 2>/dev/null; then + # Retry with --force to overwrite corepack-provided shims (pnpm/yarn), which now + # ship with recent corepack and cause EEXIST on /usr/bin/ + if $STD npm install -g "${MODULE_NAME}@${MODULE_REQ_VERSION}" 2>/dev/null || + $STD npm install -g --force "${MODULE_NAME}@${MODULE_REQ_VERSION}" 2>/dev/null; then msg_ok "Installed $MODULE_NAME" else msg_warn "Failed to install $MODULE_NAME@$MODULE_REQ_VERSION" From 225329a62ffc3fc74e551dbbfdb72d416aa46a8c Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 07:34:47 +0000 Subject: [PATCH 002/245] Update CHANGELOG.md (#15567) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 025f25e5f..69206e15d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -489,6 +489,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-03 + ## 2026-07-02 ### 🆕 New Scripts From 6ad04d8b191fce4bf5b8fe637ec42c3db144caa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20Oreste?= <39156285+alpargatagazer@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:09:41 +0200 Subject: [PATCH 003/245] Removed deprecated parameter in Filebrowser Quantum configuration (#15573) --- tools/addon/filebrowser-quantum.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/addon/filebrowser-quantum.sh b/tools/addon/filebrowser-quantum.sh index 66fdb3455..ca586f04d 100644 --- a/tools/addon/filebrowser-quantum.sh +++ b/tools/addon/filebrowser-quantum.sh @@ -176,11 +176,10 @@ if [[ "${noauth_prompt,,}" =~ ^(y|yes)$ ]]; then server: port: $PORT sources: - - path: "$SRC_DIR" + - path: "$SRC_DIR" name: "RootFS" config: denyByDefault: false - disableIndexing: false indexingIntervalMinutes: 240 conditionals: rules: @@ -204,7 +203,6 @@ server: name: "RootFS" config: denyByDefault: false - disableIndexing: false indexingIntervalMinutes: 240 conditionals: rules: From 2b3e2346e102345cf3ce5b4cb760f24d442d14a8 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 16:10:02 +0000 Subject: [PATCH 004/245] Update CHANGELOG.md (#15576) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69206e15d..887e28e34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -491,6 +491,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-03 +### 🧰 Tools + + - #### 🐞 Bug Fixes + + - Removed deprecated parameter in Filebrowser Quantum configuration [@alpargatagazer](https://github.com/alpargatagazer) ([#15573](https://github.com/community-scripts/ProxmoxVE/pull/15573)) + ## 2026-07-02 ### 🆕 New Scripts From c07570858874ce83113d0876d6ee37aec0fe453b Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 3 Jul 2026 12:14:26 -0400 Subject: [PATCH 005/245] Opencloud: Pin to v7.2.0 (#15575) --- ct/opencloud.sh | 2 +- install/opencloud-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/opencloud.sh b/ct/opencloud.sh index d2d78c805..b64dc34d0 100644 --- a/ct/opencloud.sh +++ b/ct/opencloud.sh @@ -30,7 +30,7 @@ function update_script() { exit fi - RELEASE="v7.0.0" + RELEASE="v7.2.0" if check_for_gh_release "OpenCloud" "opencloud-eu/opencloud" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then msg_info "Stopping services" systemctl stop opencloud opencloud-wopi diff --git a/install/opencloud-install.sh b/install/opencloud-install.sh index 807dd2e75..608440062 100644 --- a/install/opencloud-install.sh +++ b/install/opencloud-install.sh @@ -64,7 +64,7 @@ $STD sudo -u cool coolconfig set-admin-password --user=admin --password="$COOLPA echo "$COOLPASS" >~/.coolpass msg_ok "Installed Collabora Online" -fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v7.0.0" "/usr/bin" "opencloud-*-linux-$(arch_resolve)" +fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v7.2.0" "/usr/bin" "opencloud-*-linux-$(arch_resolve)" mv /usr/bin/OpenCloud /usr/bin/opencloud msg_info "Configuring OpenCloud" From 84a1f13fa7f2962a5fa4a4f6ea713568e2521a6d Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 16:14:53 +0000 Subject: [PATCH 006/245] Update CHANGELOG.md (#15577) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 887e28e34..9ca858c73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -491,6 +491,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-03 +### 🚀 Updated Scripts + + - Opencloud: Pin to v7.2.0 [@vhsdream](https://github.com/vhsdream) ([#15575](https://github.com/community-scripts/ProxmoxVE/pull/15575)) + ### 🧰 Tools - #### 🐞 Bug Fixes From 044bffcea4141f6f238046e1e1be8c413fbfaa50 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Fri, 3 Jul 2026 19:30:41 +0200 Subject: [PATCH 007/245] Immich: handle mise monorepo_root rename correctly | bump to 3.0.1 (#15557) --- ct/immich.sh | 93 +++++++++++++++++++++++++++------------ install/immich-install.sh | 64 +++++++++++++++------------ 2 files changed, 102 insertions(+), 55 deletions(-) diff --git a/ct/immich.sh b/ct/immich.sh index e97231997..321889a09 100644 --- a/ct/immich.sh +++ b/ct/immich.sh @@ -110,7 +110,7 @@ EOF msg_ok "Image-processing libraries up to date" fi - RELEASE="v2.7.5" + RELEASE="v3.0.1" if check_for_gh_release "Immich" "immich-app/immich" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then if [[ $(cat ~/.immich) > "2.5.1" ]]; then msg_info "Enabling Maintenance Mode" @@ -124,7 +124,7 @@ EOF systemctl stop immich-web systemctl stop immich-ml msg_ok "Stopped Services" - VCHORD_RELEASE="0.5.3" + VCHORD_RELEASE="1.0.0" [[ -f ~/.vchord_version ]] && mv ~/.vchord_version ~/.vectorchord if check_for_gh_release "VectorChord" "tensorchord/VectorChord" "${VCHORD_RELEASE}" "updated together with Immich after testing"; then fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" "${VCHORD_RELEASE}" "/tmp" "postgresql-16-vchord_*_$(arch_resolve).deb" @@ -140,7 +140,7 @@ EOF UPLOAD_DIR="$(sed -n '/^IMMICH_MEDIA_LOCATION/s/[^=]*=//p' /opt/immich/.env)" SRC_DIR="${INSTALL_DIR}/source" APP_DIR="${INSTALL_DIR}/app" - PLUGIN_DIR="${APP_DIR}/corePlugin" + PLUGIN_DIR="${APP_DIR}/plugins/immich-plugin-core" ML_DIR="${APP_DIR}/machine-learning" GEO_DIR="${INSTALL_DIR}/geodata" @@ -168,19 +168,21 @@ EOF setup_uv CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Immich" "immich-app/immich" "tarball" "${RELEASE}" "$SRC_DIR" PNPM_VERSION="$(jq -r '.packageManager | split("@")[1] | split("+")[0]' ${SRC_DIR}/package.json)" - NODE_VERSION="24" NODE_MODULE="corepack,pnpm@${PNPM_VERSION}" setup_nodejs + export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 + export CI=1 + NODE_VERSION="24" NODE_MODULE="corepack" setup_nodejs + $STD corepack prepare "pnpm@${PNPM_VERSION}" --activate + export PATH="/root/.local/share/pnpm/bin:$PATH" + $STD pnpm config set --global dangerouslyAllowAllBuilds true msg_info "Updating Immich web and microservices" cd "$SRC_DIR"/server - export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 - export CI=1 - # server build export SHARP_IGNORE_GLOBAL_LIBVIPS=true - $STD pnpm --filter immich --frozen-lockfile build + $STD pnpm --filter @immich/sdk --filter @immich/plugin-sdk --filter immich build unset SHARP_IGNORE_GLOBAL_LIBVIPS export SHARP_FORCE_GLOBAL_LIBVIPS=true - $STD pnpm --filter immich --frozen-lockfile --prod --no-optional deploy "$APP_DIR" + $STD pnpm --filter immich --prod --no-optional deploy "$APP_DIR" # Patch helmet.json: disable upgrade-insecure-requests for HTTP access if [[ -f "$APP_DIR/helmet.json" ]]; then @@ -190,32 +192,50 @@ EOF cp "$APP_DIR"/package.json "$APP_DIR"/bin sed -i "s|^start|${APP_DIR}/bin/start|" "$APP_DIR"/bin/immich-admin - # openapi & web build + # sdk, cli & web build cd "$SRC_DIR" echo "packageImportMethod: hardlink" >>./pnpm-workspace.yaml - $STD pnpm --filter @immich/sdk --filter immich-web --frozen-lockfile --force install unset SHARP_FORCE_GLOBAL_LIBVIPS export SHARP_IGNORE_GLOBAL_LIBVIPS=true - $STD pnpm --filter @immich/sdk --filter immich-web build + $STD pnpm --filter @immich/sdk --filter immich-web --filter @immich/cli build + $STD pnpm --filter @immich/cli --prod --no-optional deploy "$APP_DIR"/cli cp -a web/build "$APP_DIR"/www cp LICENSE "$APP_DIR" - - # cli build - $STD pnpm --filter @immich/sdk --filter @immich/cli --frozen-lockfile install - $STD pnpm --filter @immich/sdk --filter @immich/cli build - $STD pnpm --filter @immich/cli --prod --no-optional deploy "$APP_DIR"/cli [[ -f "$INSTALL_DIR"/start.sh ]] && mv "$INSTALL_DIR"/start.sh "$APP_DIR"/bin # plugins cd "$SRC_DIR" - $STD mise trust --ignore ./mise.toml - $STD mise trust ./plugins/mise.toml - cd plugins + export MISE_TRUSTED_CONFIG_PATHS="$SRC_DIR"/mise.toml + export MISE_DISABLE_TOOLS=github:jellyfin/jellyfin-ffmpeg $STD mise install - $STD mise run build + export PATH="$(mise bin-paths 2>/dev/null | tr '\n' ':')$PATH" + if ! command -v extism-js >/dev/null 2>&1; then + # extism-js ships as a bare gzip-compressed single binary (.gz) that + # fetch_and_deploy_gh_release cannot deploy; fetch + gunzip it directly. + EXTISM_ARCH="$(arch_resolve x86_64 aarch64)" + curl_download /tmp/extism-js.gz "https://github.com/extism/js-pdk/releases/download/v1.6.0/extism-js-${EXTISM_ARCH}-linux-v1.6.0.gz" + gunzip -f /tmp/extism-js.gz + install -m 0755 /tmp/extism-js /usr/local/bin/extism-js + rm -f /tmp/extism-js + fi + if ! command -v wasm-merge >/dev/null 2>&1; then + # extism-js needs binaryen's `wasm-merge` to build the plugin wasm. mise + # 2026.7.0's github backend no longer exposes `wasm-merge` on PATH (ubi only + # extracts a single binary), so install the pinned binaryen release from + # mise.toml directly. The extracted bin/ keeps libbinaryen.so alongside it. + BINARYEN_VERSION="$(grep -oiP 'binaryen"\s*=\s*"\Kversion_[0-9]+' "$SRC_DIR"/mise.toml | head -n1)" + [[ -z "$BINARYEN_VERSION" ]] && BINARYEN_VERSION="version_124" + BINARYEN_ARCH="$(arch_resolve x86_64 aarch64)" + curl_download /tmp/binaryen.tar.gz "https://github.com/WebAssembly/binaryen/releases/download/${BINARYEN_VERSION}/binaryen-${BINARYEN_VERSION}-${BINARYEN_ARCH}-linux.tar.gz" + tar -xzf /tmp/binaryen.tar.gz -C /opt + rm -f /tmp/binaryen.tar.gz + export PATH="/opt/binaryen-${BINARYEN_VERSION}/bin:$PATH" + fi + $STD mise exec -- pnpm --filter @immich/sdk --filter @immich/plugin-sdk --filter @immich/plugin-core install --frozen-lockfile + $STD mise exec -- pnpm --filter @immich/sdk --filter @immich/plugin-sdk --filter @immich/plugin-core build mkdir -p "$PLUGIN_DIR" - cp -r ./dist "$PLUGIN_DIR"/dist - cp ./manifest.json "$PLUGIN_DIR" + cp -r ./packages/plugin-core/dist "$PLUGIN_DIR"/dist + cp ./packages/plugin-core/manifest.json "$PLUGIN_DIR" msg_ok "Updated Immich server, web, cli and plugins" cd "$SRC_DIR"/machine-learning @@ -231,13 +251,13 @@ EOF ML_PYTHON="python3.13" msg_info "Pre-installing Python ${ML_PYTHON} for machine-learning" for attempt in $(seq 1 3); do - $STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv python install "${ML_PYTHON}" && break + $STD sudo --preserve-env=VIRTUAL_ENV -Pnu immich uv python install "${ML_PYTHON}" && break [[ $attempt -lt 3 ]] && msg_warn "Python download attempt $attempt failed, retrying..." && sleep 5 done msg_ok "Pre-installed Python ${ML_PYTHON}" msg_info "Updating Intel OpenVINO machine-learning" for attempt in $(seq 1 3); do - $STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT -nu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break + $STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT -Pnu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break [[ $attempt -lt 3 ]] && msg_warn "uv sync attempt $attempt failed, retrying..." && sleep 10 done patchelf --clear-execstack "${VIRTUAL_ENV}/lib/python3.13/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-313-$(arch_resolve "x86_64" "aarch64")-linux-gnu.so" @@ -246,13 +266,13 @@ EOF ML_PYTHON="python3.11" msg_info "Pre-installing Python ${ML_PYTHON} for machine-learning" for attempt in $(seq 1 3); do - $STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv python install "${ML_PYTHON}" && break + $STD sudo --preserve-env=VIRTUAL_ENV -Pnu immich uv python install "${ML_PYTHON}" && break [[ $attempt -lt 3 ]] && msg_warn "Python download attempt $attempt failed, retrying..." && sleep 5 done msg_ok "Pre-installed Python ${ML_PYTHON}" msg_info "Updating machine-learning" for attempt in $(seq 1 3); do - $STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT -nu immich uv sync --extra cpu --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break + $STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT -Pnu immich uv sync --extra cpu --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break [[ $attempt -lt 3 ]] && msg_warn "uv sync attempt $attempt failed, retrying..." && sleep 10 done msg_ok "Updated machine-learning" @@ -260,6 +280,23 @@ EOF cd "$SRC_DIR" cp -a machine-learning/{ann,immich_ml} "$ML_DIR" [[ -f "$INSTALL_DIR"/ml_start.sh ]] && mv "$INSTALL_DIR"/ml_start.sh "$ML_DIR" + # Regenerate ml_start.sh if it is missing (e.g. lost by a previously interrupted update), + # otherwise immich-ml.service fails to start with status=203/EXEC + if [[ ! -f "$ML_DIR"/ml_start.sh ]]; then + cat <"$ML_DIR"/ml_start.sh +#!/usr/bin/env bash + +cd ${ML_DIR} +. ${VIRTUAL_ENV}/bin/activate + +set -a +. ${INSTALL_DIR}/.env +set +a + +python3 -m immich_ml +EOF + chmod +x "$ML_DIR"/ml_start.sh + fi [[ -f ~/.openvino ]] && sed -i "/intra_op/s/int = 0/int = os.cpu_count() or 0/" "$ML_DIR"/immich_ml/config.py ln -sf "$APP_DIR"/resources "$INSTALL_DIR" cd "$APP_DIR" @@ -429,7 +466,7 @@ function compile_imagemagick() { function compile_libvips() { SOURCE=$SOURCE_DIR/libvips - LIBVIPS_REVISION="17ad2f62dda7e39985955da189183e594683d45e" + LIBVIPS_REVISION="3664cfc5dc2c5661288f5bf5a85ccc51c64c1626" if [[ "$LIBVIPS_REVISION" != "$(grep 'libvips' ~/.immich_library_revisions | awk '{print $2}')" ]]; then msg_info "Recompiling libvips" [[ -d "$SOURCE" ]] && rm -rf "$SOURCE" diff --git a/install/immich-install.sh b/install/immich-install.sh index 88bff3693..9270b29e1 100644 --- a/install/immich-install.sh +++ b/install/immich-install.sh @@ -162,7 +162,7 @@ PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql ACTUAL_PG_VERSION=$(ls /etc/postgresql/ 2>/dev/null | sort -V | tail -1) ACTUAL_PG_VERSION=${ACTUAL_PG_VERSION:-16} -VCHORD_RELEASE="0.5.3" +VCHORD_RELEASE="1.0.0" fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" "${VCHORD_RELEASE}" "/tmp" "postgresql-${ACTUAL_PG_VERSION}-vchord_*_$(arch_resolve).deb" sed -i "s/^#shared_preload.*/shared_preload_libraries = 'vchord.so'/" /etc/postgresql/${ACTUAL_PG_VERSION}/main/postgresql.conf @@ -282,7 +282,7 @@ msg_ok "(4/5) Compiled imagemagick" msg_info "(5/5) Compiling libvips" SOURCE=$SOURCE_DIR/libvips -LIBVIPS_REVISION="17ad2f62dda7e39985955da189183e594683d45e" +LIBVIPS_REVISION="3664cfc5dc2c5661288f5bf5a85ccc51c64c1626" $STD git clone https://github.com/libvips/libvips.git "$SOURCE" cd "$SOURCE" $STD git reset --hard "$LIBVIPS_REVISION" @@ -306,14 +306,20 @@ INSTALL_DIR="/opt/${APPLICATION}" UPLOAD_DIR="${INSTALL_DIR}/upload" SRC_DIR="${INSTALL_DIR}/source" APP_DIR="${INSTALL_DIR}/app" -PLUGIN_DIR="${APP_DIR}/corePlugin" +PLUGIN_DIR="${APP_DIR}/plugins/immich-plugin-core" ML_DIR="${APP_DIR}/machine-learning" GEO_DIR="${INSTALL_DIR}/geodata" mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache} -fetch_and_deploy_gh_release "Immich" "immich-app/immich" "tarball" "v2.7.5" "$SRC_DIR" +fetch_and_deploy_gh_release "Immich" "immich-app/immich" "tarball" "v3.0.1" "$SRC_DIR" PNPM_VERSION="$(jq -r '.packageManager | split("@")[1] | split("+")[0]' ${SRC_DIR}/package.json)" -NODE_VERSION="24" NODE_MODULE="corepack,pnpm@${PNPM_VERSION}" setup_nodejs +export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 +NODE_VERSION="24" NODE_MODULE="corepack" setup_nodejs +# Provision the exact pnpm pinned in package.json's packageManager field via corepack instead +# of `npm i -g pnpm@X`, which collides (EEXIST) with the corepack pnpm shim shipped by the +$STD corepack prepare "pnpm@${PNPM_VERSION}" --activate +export PATH="/root/.local/share/pnpm/bin:$PATH" +$STD pnpm config set --global dangerouslyAllowAllBuilds true msg_info "Installing Immich (patience)" @@ -323,10 +329,10 @@ export CI=1 # server build export SHARP_IGNORE_GLOBAL_LIBVIPS=true -$STD pnpm --filter immich --frozen-lockfile build +$STD pnpm --filter @immich/sdk --filter @immich/plugin-sdk --filter immich build unset SHARP_IGNORE_GLOBAL_LIBVIPS export SHARP_FORCE_GLOBAL_LIBVIPS=true -$STD pnpm --filter immich --frozen-lockfile --prod --no-optional deploy "$APP_DIR" +$STD pnpm --filter immich --prod --no-optional deploy "$APP_DIR" # Patch helmet.json: disable upgrade-insecure-requests for HTTP access if [[ -f "$APP_DIR/helmet.json" ]]; then @@ -336,31 +342,35 @@ fi cp "$APP_DIR"/package.json "$APP_DIR"/bin sed -i "s|^start|${APP_DIR}/bin/start|" "$APP_DIR"/bin/immich-admin -# openapi & web build +# sdk, cli & web build cd "$SRC_DIR" echo "packageImportMethod: hardlink" >>./pnpm-workspace.yaml -$STD pnpm --filter @immich/sdk --filter immich-web --frozen-lockfile --force install unset SHARP_FORCE_GLOBAL_LIBVIPS export SHARP_IGNORE_GLOBAL_LIBVIPS=true -$STD pnpm --filter @immich/sdk --filter immich-web build +$STD pnpm --filter @immich/sdk --filter immich-web --filter @immich/cli build +$STD pnpm --filter @immich/cli --prod --no-optional deploy "$APP_DIR"/cli cp -a web/build "$APP_DIR"/www cp LICENSE "$APP_DIR" - -# cli build -$STD pnpm --filter @immich/sdk --filter @immich/cli --frozen-lockfile install -$STD pnpm --filter @immich/sdk --filter @immich/cli build -$STD pnpm --filter @immich/cli --prod --no-optional deploy "$APP_DIR"/cli - -# plugins cd "$SRC_DIR" -$STD mise trust --ignore ./mise.toml -$STD mise trust ./plugins/mise.toml -cd plugins +export MISE_TRUSTED_CONFIG_PATHS="$SRC_DIR"/mise.toml +export MISE_DISABLE_TOOLS=github:jellyfin/jellyfin-ffmpeg $STD mise install -$STD mise run build +export PATH="$(mise bin-paths 2>/dev/null | tr '\n' ':')$PATH" +if ! command -v extism-js >/dev/null 2>&1; then + # extism-js is published as a bare gzip-compressed single binary (.gz), which + # fetch_and_deploy_gh_release cannot deploy (singlefile leaves it compressed, + # prebuild only handles zip/tar). Fetch + gunzip it directly. + EXTISM_ARCH="$(arch_resolve x86_64 aarch64)" + curl_download /tmp/extism-js.gz "https://github.com/extism/js-pdk/releases/download/v1.6.0/extism-js-${EXTISM_ARCH}-linux-v1.6.0.gz" + gunzip -f /tmp/extism-js.gz + install -m 0755 /tmp/extism-js /usr/local/bin/extism-js + rm -f /tmp/extism-js +fi +$STD mise exec -- pnpm --filter @immich/sdk --filter @immich/plugin-sdk --filter @immich/plugin-core install --frozen-lockfile +$STD mise exec -- pnpm --filter @immich/sdk --filter @immich/plugin-sdk --filter @immich/plugin-core build mkdir -p "$PLUGIN_DIR" -cp -r ./dist "$PLUGIN_DIR"/dist -cp ./manifest.json "$PLUGIN_DIR" +cp -r ./packages/plugin-core/dist "$PLUGIN_DIR"/dist +cp ./packages/plugin-core/manifest.json "$PLUGIN_DIR" msg_ok "Installed Immich Server, Web and Plugin Components" cd "$SRC_DIR"/machine-learning @@ -376,13 +386,13 @@ if [[ -f ~/.openvino ]]; then ML_PYTHON="python3.13" msg_info "Pre-installing Python ${ML_PYTHON} for machine-learning" for attempt in $(seq 1 3); do - $STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv python install "${ML_PYTHON}" && break + $STD sudo --preserve-env=VIRTUAL_ENV -Pnu immich uv python install "${ML_PYTHON}" && break [[ $attempt -lt 3 ]] && msg_warn "Python download attempt $attempt failed, retrying..." && sleep 5 done msg_ok "Pre-installed Python ${ML_PYTHON}" msg_info "Installing Intel OpenVINO machine-learning" for attempt in $(seq 1 3); do - $STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT -nu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break + $STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT -Pnu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break [[ $attempt -lt 3 ]] && msg_warn "uv sync attempt $attempt failed, retrying..." && sleep 10 done patchelf --clear-execstack "${VIRTUAL_ENV}/lib/python3.13/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-313-$(arch_resolve "x86_64" "aarch64")-linux-gnu.so" @@ -391,13 +401,13 @@ else ML_PYTHON="python3.11" msg_info "Pre-installing Python ${ML_PYTHON} for machine-learning" for attempt in $(seq 1 3); do - $STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv python install "${ML_PYTHON}" && break + $STD sudo --preserve-env=VIRTUAL_ENV -Pnu immich uv python install "${ML_PYTHON}" && break [[ $attempt -lt 3 ]] && msg_warn "Python download attempt $attempt failed, retrying..." && sleep 5 done msg_ok "Pre-installed Python ${ML_PYTHON}" msg_info "Installing machine-learning" for attempt in $(seq 1 3); do - $STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT -nu immich uv sync --extra cpu --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break + $STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT -Pnu immich uv sync --extra cpu --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break [[ $attempt -lt 3 ]] && msg_warn "uv sync attempt $attempt failed, retrying..." && sleep 10 done msg_ok "Installed machine-learning" From 3c84f2d6c17889ca0b5a20df5c06668fcd94d34a Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 17:31:02 +0000 Subject: [PATCH 008/245] Update CHANGELOG.md (#15578) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ca858c73..c32ffbea5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -495,6 +495,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Opencloud: Pin to v7.2.0 [@vhsdream](https://github.com/vhsdream) ([#15575](https://github.com/community-scripts/ProxmoxVE/pull/15575)) + - #### 🐞 Bug Fixes + + - Immich: handle mise monorepo_root rename correctly | bump to 3.0.1 [@MickLesk](https://github.com/MickLesk) ([#15557](https://github.com/community-scripts/ProxmoxVE/pull/15557)) + ### 🧰 Tools - #### 🐞 Bug Fixes From 704916d27d49426d1e6396df7a5e775611c75649 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Fri, 3 Jul 2026 22:22:06 +0200 Subject: [PATCH 009/245] tools.func: fix corepack/pnpm install flow in setup_nodejs (#15579) Ensure Node module setup runs non-interactively by exporting COREPACK_ENABLE_DOWNLOAD_PROMPT=0, then handle corepack first when requested (including versioned specs). pnpm/yarn are now provisioned through corepack when enabled to avoid shim EEXIST collisions, with corepack modules skipped in the generic npm loop and conflicting shims cleaned only for npm-global installs. Also replace the global pnpm dangerouslyAllowAllBuilds setting with strictDepBuilds=false to avoid project-level config conflicts while keeping installs usable. --- misc/tools.func | 79 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/misc/tools.func b/misc/tools.func index fc01a6fc0..883c98da0 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -7442,6 +7442,13 @@ setup_nodejs() { local wants_corepack=0 local node_setup_ok_msg="" + # Corepack must run fully non-interactive. Without this it prints + # "Corepack is about to download X. Do you want to continue? [Y/n]" and blocks + # the whole install waiting for keyboard input - both here and in the calling + # script's later `corepack prepare` / `corepack ` calls, which run in this + # same shell and inherit the export. + export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 + # ALWAYS clean up legacy installations first (nvm, etc.) to prevent conflicts cleanup_legacy_install "nodejs" @@ -7596,17 +7603,48 @@ setup_nodejs() { IFS=',' read -ra MODULES <<<"$NODE_MODULE" + local corepack_spec="corepack@latest" for i in "${!MODULES[@]}"; do if [[ "${MODULES[$i]}" == "corepack" || "${MODULES[$i]}" == corepack@* ]]; then wants_corepack=1 + [[ "${MODULES[$i]}" == corepack@* ]] && corepack_spec="${MODULES[$i]}" fi if [[ "${MODULES[$i]}" == "pnpm" ]]; then MODULES[$i]="pnpm@^10" fi done + # When corepack is requested, install and enable it FIRST. The corepack npm + # package owns the global yarn/pnpm/pnpx/yarnpkg bin shims, so a second + # `npm install -g yarn`/`pnpm` collides on /usr/bin/ (EEXIST). With + # corepack ready we provision those package managers THROUGH corepack instead. + local corepack_ready=0 + if ((wants_corepack)); then + msg_info "Installing corepack" + if $STD npm install -g "$corepack_spec" 2>/dev/null || + $STD npm install -g --force "$corepack_spec" 2>/dev/null; then + msg_ok "Installed corepack" + else + msg_warn "Failed to install corepack" + fi + if [[ "$NODE_COREPACK_ENABLE" == "1" ]] && command -v corepack >/dev/null 2>&1; then + msg_info "Enabling corepack" + if $STD corepack enable 2>/dev/null; then + corepack_ready=1 + msg_ok "Enabled corepack" + else + msg_warn "corepack enable failed" + fi + fi + fi + local failed_modules=0 for mod in "${MODULES[@]}"; do + # corepack itself is already handled above + if [[ "$mod" == "corepack" || "$mod" == corepack@* ]]; then + continue + fi + local MODULE_NAME MODULE_REQ_VERSION MODULE_INSTALLED_VERSION if [[ "$mod" == @*/*@* ]]; then # Scoped package with version, e.g. @vue/cli-service@latest @@ -7622,6 +7660,27 @@ setup_nodejs() { MODULE_REQ_VERSION="latest" fi + # Provision pnpm/yarn through corepack when it is active, so we never fight + # corepack over the /usr/bin/{yarn,pnpm} shim locations it owns. + if ((corepack_ready)) && [[ "$MODULE_NAME" == "pnpm" || "$MODULE_NAME" == "yarn" ]]; then + local corepack_pkg="$MODULE_NAME" + [[ "$MODULE_REQ_VERSION" != "latest" ]] && corepack_pkg="${MODULE_NAME}@${MODULE_REQ_VERSION}" + msg_info "Provisioning $MODULE_NAME via corepack" + if $STD corepack prepare "$corepack_pkg" --activate 2>/dev/null || command -v "$MODULE_NAME" >/dev/null 2>&1; then + msg_ok "Provisioned $MODULE_NAME via corepack" + else + msg_warn "Failed to provision $MODULE_NAME via corepack" + ((failed_modules++)) || true + fi + continue + fi + + # For the npm-global path, drop any corepack-provided shim first so the + # bin link can be created without an EEXIST collision. + if [[ "$MODULE_NAME" == "pnpm" || "$MODULE_NAME" == "yarn" || "$MODULE_NAME" == "yarnpkg" ]]; then + rm -f /usr/bin/"$MODULE_NAME" /usr/local/bin/"$MODULE_NAME" 2>/dev/null || true + fi + # Check if the module is already installed if $STD npm list -g --depth=0 "$MODULE_NAME" 2>&1 | grep -q "$MODULE_NAME@"; then MODULE_INSTALLED_VERSION="$(npm list -g --depth=0 "$MODULE_NAME" 2>&1 | grep "$MODULE_NAME@" | awk -F@ '{print $2}' 2>/dev/null | tr -d '[:space:]' || echo '')" @@ -7664,19 +7723,15 @@ setup_nodejs() { fi fi - # pnpm v10+ blocks dependency build scripts by default (ERR_PNPM_IGNORED_BUILDS). - # In a container environment all installed packages are trusted, so we enable builds globally. + # pnpm v10+ blocks dependency build scripts by default. Do NOT force + # `dangerouslyAllowAllBuilds` globally: pnpm implements that flag as an empty + # `neverBuiltDependencies`, which then clashes with any project that ships its + # own `onlyBuiltDependencies` (every create-t3-app based app, e.g. Split Pro) + # and aborts with ERR_PNPM_CONFIG_CONFLICT_BUILT_DEPENDENCIES. Instead relax the + # strict check so an unapproved build is a warning, not a fatal error; scripts + # that truly need every build script executed enable that themselves. if command -v pnpm >/dev/null 2>&1; then - pnpm config set --global dangerouslyAllowAllBuilds true >/dev/null 2>&1 || true - fi - - if [[ "$NODE_COREPACK_ENABLE" == "1" ]] && ((wants_corepack)) && command -v corepack >/dev/null 2>&1; then - msg_info "Enabling corepack" - if $STD corepack enable 2>/dev/null; then - msg_ok "Enabled corepack" - else - msg_warn "corepack enable failed" - fi + pnpm config set --global strictDepBuilds false >/dev/null 2>&1 || true fi } From d58123a5187d5f5ad3c5689a6fc7e2650885f630 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 20:22:29 +0000 Subject: [PATCH 010/245] Update CHANGELOG.md (#15582) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c32ffbea5..564e72d1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -499,6 +499,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Immich: handle mise monorepo_root rename correctly | bump to 3.0.1 [@MickLesk](https://github.com/MickLesk) ([#15557](https://github.com/community-scripts/ProxmoxVE/pull/15557)) +### 💾 Core + + - #### 🔧 Refactor + + - tools.func: fix corepack/pnpm install flow in setup_nodejs [@MickLesk](https://github.com/MickLesk) ([#15579](https://github.com/community-scripts/ProxmoxVE/pull/15579)) + ### 🧰 Tools - #### 🐞 Bug Fixes From 9406a1ca9871ab99c32506c9fc22beaf2caa5d74 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 22:24:51 +0000 Subject: [PATCH 011/245] Update CHANGELOG.md (#15583) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 564e72d1c..4feef706d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -493,12 +493,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🚀 Updated Scripts - - Opencloud: Pin to v7.2.0 [@vhsdream](https://github.com/vhsdream) ([#15575](https://github.com/community-scripts/ProxmoxVE/pull/15575)) - - #### 🐞 Bug Fixes - Immich: handle mise monorepo_root rename correctly | bump to 3.0.1 [@MickLesk](https://github.com/MickLesk) ([#15557](https://github.com/community-scripts/ProxmoxVE/pull/15557)) + - #### ✨ New Features + + - Opencloud: bump to v7.2.0 [@vhsdream](https://github.com/vhsdream) ([#15575](https://github.com/community-scripts/ProxmoxVE/pull/15575)) + ### 💾 Core - #### 🔧 Refactor From 7e15a4bf2635817b8974ae9c638fc3ba6a3f4763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Vit=C3=B3ria=20Silva?= <8648976+joaovitoriasilva@users.noreply.github.com> Date: Sat, 4 Jul 2026 10:55:36 +0100 Subject: [PATCH 012/245] fix(endurain): update frontend dist path after upstream restructure (#15590) --- ct/endurain.sh | 6 +++--- install/endurain-install.sh | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ct/endurain.sh b/ct/endurain.sh index 67ead130f..934532aea 100644 --- a/ct/endurain.sh +++ b/ct/endurain.sh @@ -36,7 +36,7 @@ function update_script() { msg_info "Creating Backup" cp /opt/endurain/.env /opt/endurain.env - cp /opt/endurain/frontend/app/dist/env.js /opt/endurain.env.js + cp /opt/endurain/frontend/dist/env.js /opt/endurain.env.js msg_ok "Created Backup" CLEAN_INSTALL=1 fetch_and_deploy_codeberg_release "endurain" "endurain-project/endurain" "tarball" "latest" "/opt/endurain" @@ -52,10 +52,10 @@ function update_script() { msg_ok "Prepared Update" msg_info "Updating Frontend" - cd /opt/endurain/frontend/app + cd /opt/endurain/frontend $STD npm ci $STD npm run build - cp /opt/endurain.env.js /opt/endurain/frontend/app/dist/env.js + cp /opt/endurain.env.js /opt/endurain/frontend/dist/env.js rm /opt/endurain.env.js msg_ok "Updated Frontend" diff --git a/install/endurain-install.sh b/install/endurain-install.sh index ca34b2c4e..b0e7953e5 100644 --- a/install/endurain-install.sh +++ b/install/endurain-install.sh @@ -55,7 +55,7 @@ DB_HOST=localhost DATABASE_URL=postgresql+psycopg://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME} BACKEND_DIR="/opt/endurain/backend/app" -FRONTEND_DIR="/opt/endurain/frontend/app/dist" +FRONTEND_DIR="/opt/endurain/frontend/dist" DATA_DIR="/opt/endurain_data/data" LOGS_DIR="/opt/endurain_data/logs" @@ -69,10 +69,10 @@ EOF msg_ok "Setup Endurain" msg_info "Building Frontend" -cd /opt/endurain/frontend/app +cd /opt/endurain/frontend $STD npm ci --prefer-offline $STD npm run build -cat </opt/endurain/frontend/app/dist/env.js +cat </opt/endurain/frontend/dist/env.js window.env = { ENDURAIN_HOST: "${ENDURAIN_HOST}" } From 819ecc1105d8ca5691d912ff2ce5d4543ce32b49 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sat, 4 Jul 2026 09:55:57 +0000 Subject: [PATCH 013/245] Update CHANGELOG.md (#15591) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4feef706d..971a5e4ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -489,6 +489,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-04 + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - fix(endurain): update frontend dist path after upstream restructure [@joaovitoriasilva](https://github.com/joaovitoriasilva) ([#15590](https://github.com/community-scripts/ProxmoxVE/pull/15590)) + ## 2026-07-03 ### 🚀 Updated Scripts From d29eec949466008e3fd69246bf1820a95b4654a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Slavi=C5=A1a=20Are=C5=BEina?= <58952836+tremor021@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:48:45 +0200 Subject: [PATCH 014/245] Refactor configuration restoration to use restore_backup (#15586) Removed manual configuration restoration and replaced it with a backup restore function. --- ct/twenty.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ct/twenty.sh b/ct/twenty.sh index 3bde6f746..0b212ef0f 100644 --- a/ct/twenty.sh +++ b/ct/twenty.sh @@ -41,11 +41,8 @@ function update_script() { create_backup /opt/twenty/.env \ /opt/twenty/packages/twenty-server/.local-storage CLEAN_INSTALL=1 fetch_and_deploy_gh_release "twenty" "twentyhq/twenty" "tarball" - - msg_info "Restoring Configuration" - cp /opt/twenty.env.bak /opt/twenty/.env - msg_ok "Restored Configuration" - + restore_backup + msg_info "Building Application" cd /opt/twenty export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 @@ -66,7 +63,6 @@ function update_script() { $STD npx -y typeorm migration:run -d dist/database/typeorm/core/core.datasource msg_ok "Ran Database Migrations" - restore_backup msg_info "Starting Services" systemctl start twenty-server twenty-worker From cc5976baa63aadadd03a302693022689cef9f0e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Slavi=C5=A1a=20Are=C5=BEina?= <58952836+tremor021@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:49:09 +0200 Subject: [PATCH 015/245] Fix heredoc syntax in elementsynapse-install.sh (#15594) --- install/elementsynapse-install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/elementsynapse-install.sh b/install/elementsynapse-install.sh index 8a23996bf..11b5e50f1 100644 --- a/install/elementsynapse-install.sh +++ b/install/elementsynapse-install.sh @@ -44,7 +44,7 @@ ADMIN_PASS="$(openssl rand -base64 18 | cut -c1-13)" echo "enable_registration_without_verification: true" >>/etc/matrix-synapse/homeserver.yaml echo "registration_shared_secret: ${SECRET}" >>/etc/matrix-synapse/homeserver.yaml -cat </etc/matrix-synapse/homeserver.yaml +cat <>/etc/matrix-synapse/homeserver.yaml # MatrixRTC / Element Call configuration experimental_features: From dbd591ada652635e25989479864608bf3ee1b201 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sat, 4 Jul 2026 19:49:30 +0000 Subject: [PATCH 016/245] Update CHANGELOG.md (#15597) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 971a5e4ac..77110e343 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -495,6 +495,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - Element Synapse: Fix heredoc syntax in elementsynapse-install.sh [@tremor021](https://github.com/tremor021) ([#15594](https://github.com/community-scripts/ProxmoxVE/pull/15594)) + - Twenty: Fix backup restore [@tremor021](https://github.com/tremor021) ([#15586](https://github.com/community-scripts/ProxmoxVE/pull/15586)) - fix(endurain): update frontend dist path after upstream restructure [@joaovitoriasilva](https://github.com/joaovitoriasilva) ([#15590](https://github.com/community-scripts/ProxmoxVE/pull/15590)) ## 2026-07-03 From 604f7c7ae99c120f7a95a3d04f41e709efcab304 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 5 Jul 2026 00:21:02 +0000 Subject: [PATCH 017/245] Archive old changelog entries (#15599) Co-authored-by: github-actions[bot] --- .github/changelogs/2026/06.md | 44 ++++++++++ .github/changelogs/2026/07.md | 91 +++++++++++++++++++++ CHANGELOG.md | 147 +++------------------------------- 3 files changed, 147 insertions(+), 135 deletions(-) create mode 100644 .github/changelogs/2026/07.md diff --git a/.github/changelogs/2026/06.md b/.github/changelogs/2026/06.md index e0e87d170..b155f052e 100644 --- a/.github/changelogs/2026/06.md +++ b/.github/changelogs/2026/06.md @@ -1,3 +1,47 @@ +## 2026-06-30 + +### 🚀 Updated Scripts + + - #### 🔧 Refactor + + - Refactor: Use heredoc when creating env files and creds/other [@tremor021](https://github.com/tremor021) ([#15469](https://github.com/community-scripts/ProxmoxVE/pull/15469)) + +### 🧰 Tools + + - #### 🐞 Bug Fixes + + - [tools/pve/*.sh] https://download.proxmox.com -> http://download.proxmox.com (PVE8 Only) [@galeksandrp](https://github.com/galeksandrp) ([#15498](https://github.com/community-scripts/ProxmoxVE/pull/15498)) + +## 2026-06-29 + +### 🆕 New Scripts + + - Koffan ([#15467](https://github.com/community-scripts/ProxmoxVE/pull/15467)) +- Etherpad ([#15468](https://github.com/community-scripts/ProxmoxVE/pull/15468)) +- Flame ([#15464](https://github.com/community-scripts/ProxmoxVE/pull/15464)) + +### 🚀 Updated Scripts + + - chore(ct): sync snapotter defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#15472](https://github.com/community-scripts/ProxmoxVE/pull/15472)) + + - #### 🐞 Bug Fixes + + - feat: update nginx proxy manager to trixie [@asylumexp](https://github.com/asylumexp) ([#15457](https://github.com/community-scripts/ProxmoxVE/pull/15457)) + +### 💾 Core + + - #### ✨ New Features + + - [tools.func]: add edit_yaml_config function [@tremor021](https://github.com/tremor021) ([#15484](https://github.com/community-scripts/ProxmoxVE/pull/15484)) + +## 2026-06-28 + +### 🚀 Updated Scripts + + - #### 💥 Breaking Changes + + - remove: promtail as EOL and other fixes [@asylumexp](https://github.com/asylumexp) ([#15455](https://github.com/community-scripts/ProxmoxVE/pull/15455)) + ## 2026-06-27 ### 🆕 New Scripts diff --git a/.github/changelogs/2026/07.md b/.github/changelogs/2026/07.md new file mode 100644 index 000000000..4c20ca3e6 --- /dev/null +++ b/.github/changelogs/2026/07.md @@ -0,0 +1,91 @@ +## 2026-07-04 + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - Element Synapse: Fix heredoc syntax in elementsynapse-install.sh [@tremor021](https://github.com/tremor021) ([#15594](https://github.com/community-scripts/ProxmoxVE/pull/15594)) + - Twenty: Fix backup restore [@tremor021](https://github.com/tremor021) ([#15586](https://github.com/community-scripts/ProxmoxVE/pull/15586)) + - fix(endurain): update frontend dist path after upstream restructure [@joaovitoriasilva](https://github.com/joaovitoriasilva) ([#15590](https://github.com/community-scripts/ProxmoxVE/pull/15590)) + +## 2026-07-03 + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - Immich: handle mise monorepo_root rename correctly | bump to 3.0.1 [@MickLesk](https://github.com/MickLesk) ([#15557](https://github.com/community-scripts/ProxmoxVE/pull/15557)) + + - #### ✨ New Features + + - Opencloud: bump to v7.2.0 [@vhsdream](https://github.com/vhsdream) ([#15575](https://github.com/community-scripts/ProxmoxVE/pull/15575)) + +### 💾 Core + + - #### 🔧 Refactor + + - tools.func: fix corepack/pnpm install flow in setup_nodejs [@MickLesk](https://github.com/MickLesk) ([#15579](https://github.com/community-scripts/ProxmoxVE/pull/15579)) + +### 🧰 Tools + + - #### 🐞 Bug Fixes + + - Removed deprecated parameter in Filebrowser Quantum configuration [@alpargatagazer](https://github.com/alpargatagazer) ([#15573](https://github.com/community-scripts/ProxmoxVE/pull/15573)) + +## 2026-07-02 + +### 🆕 New Scripts + + - Rackula ([#15465](https://github.com/community-scripts/ProxmoxVE/pull/15465)) + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - typo: fix npm update to npm install for n8n [@MickLesk](https://github.com/MickLesk) ([#15545](https://github.com/community-scripts/ProxmoxVE/pull/15545)) + + - #### ✨ New Features + + - Frigate: bump to v0.17.2 [@MickLesk](https://github.com/MickLesk) ([#15536](https://github.com/community-scripts/ProxmoxVE/pull/15536)) + + - #### 💥 Breaking Changes + + - Revert "Immich v3.0.0" [@MickLesk](https://github.com/MickLesk) ([#15558](https://github.com/community-scripts/ProxmoxVE/pull/15558)) + - Immich v3.0.0 [@vhsdream](https://github.com/vhsdream) ([#15153](https://github.com/community-scripts/ProxmoxVE/pull/15153)) + +### 💾 Core + + - #### 🐞 Bug Fixes + + - tools.func: configure pnpm to allow all build scripts for environments [@MickLesk](https://github.com/MickLesk) ([#15532](https://github.com/community-scripts/ProxmoxVE/pull/15532)) + + - #### ✨ New Features + + - feat(build.func): add var_ignore_disable to bypass disabled-script guard [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15544](https://github.com/community-scripts/ProxmoxVE/pull/15544)) + +## 2026-07-01 + +### 🆕 New Scripts + + - iVentoy ([#15503](https://github.com/community-scripts/ProxmoxVE/pull/15503)) + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - Stirling-PDF: patch libicudata execstack flag for LXC container compatibility [@MickLesk](https://github.com/MickLesk) ([#15531](https://github.com/community-scripts/ProxmoxVE/pull/15531)) + - FlowiseAI: align install to use pnpm instead of npm to fix missing dependencies [@MickLesk](https://github.com/MickLesk) ([#15530](https://github.com/community-scripts/ProxmoxVE/pull/15530)) + - Vaultwarden: handle version detection failure gracefully in update [@MickLesk](https://github.com/MickLesk) ([#15526](https://github.com/community-scripts/ProxmoxVE/pull/15526)) + - homarr: fix: update-fail [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15512](https://github.com/community-scripts/ProxmoxVE/pull/15512)) + - n8n: pin version to 2.27.5 [@tremor021](https://github.com/tremor021) ([#15516](https://github.com/community-scripts/ProxmoxVE/pull/15516)) + + - #### ✨ New Features + + - [arm64] feat: iventory arm64 support [@asylumexp](https://github.com/asylumexp) ([#15521](https://github.com/community-scripts/ProxmoxVE/pull/15521)) + +### 💾 Core + + - #### 🐞 Bug Fixes + + - core: fix SDN vnet network parameter to use bridge instead of vnet [@MickLesk](https://github.com/MickLesk) ([#15527](https://github.com/community-scripts/ProxmoxVE/pull/15527)) + - tools.func: use safe variable expansion in check_for_gh_release RETURN trap [@MickLesk](https://github.com/MickLesk) ([#15529](https://github.com/community-scripts/ProxmoxVE/pull/15529)) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77110e343..4fe0af921 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,9 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit + + + @@ -84,7 +87,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
-

June (27 entries)

+

July (4 entries)

+ +[View July 2026 Changelog](.github/changelogs/2026/07.md) + +
+ +
+

June (30 entries)

[View June 2026 Changelog](.github/changelogs/2026/06.md) @@ -1134,137 +1144,4 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 💥 Breaking Changes - - update authentik to 2026.5.2 [@thieneret](https://github.com/thieneret) ([#14846](https://github.com/community-scripts/ProxmoxVE/pull/14846)) - -## 2026-06-04 - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - Fix status messages for several alpine scripts [@tremor021](https://github.com/tremor021) ([#14911](https://github.com/community-scripts/ProxmoxVE/pull/14911)) - - ReactiveResume: Fix Service Path [@MickLesk](https://github.com/MickLesk) ([#14926](https://github.com/community-scripts/ProxmoxVE/pull/14926)) - - Jellyfin: install intel-igc deps before intel-opencl-icd to fix dependency order [@MickLesk](https://github.com/MickLesk) ([#14927](https://github.com/community-scripts/ProxmoxVE/pull/14927)) - - - #### 🔧 Refactor - - - OpenThread-BR: use official GitHub releases [@tomfrenzel](https://github.com/tomfrenzel) ([#14916](https://github.com/community-scripts/ProxmoxVE/pull/14916)) - - Grist: remove extra text at the end of installation [@tremor021](https://github.com/tremor021) ([#14905](https://github.com/community-scripts/ProxmoxVE/pull/14905)) - -### ❔ Uncategorized - - - chore(ct): sync sparkyfitness defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#14925](https://github.com/community-scripts/ProxmoxVE/pull/14925)) - -## 2026-06-03 - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - Glance: Use separate directory for configuration files [@tremor021](https://github.com/tremor021) ([#14906](https://github.com/community-scripts/ProxmoxVE/pull/14906)) - -### 💾 Core - - - #### 🐞 Bug Fixes - - - [core]: Fix alignment for `msg_` functions [@tremor021](https://github.com/tremor021) ([#14908](https://github.com/community-scripts/ProxmoxVE/pull/14908)) - -## 2026-06-02 - -### 🆕 New Scripts - - - DDNS-Updater ([#14883](https://github.com/community-scripts/ProxmoxVE/pull/14883)) -- InvoiceShelf ([#14882](https://github.com/community-scripts/ProxmoxVE/pull/14882)) -- Certimate ([#14881](https://github.com/community-scripts/ProxmoxVE/pull/14881)) - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - OpenThread-BR: preserve config during update [@tomfrenzel](https://github.com/tomfrenzel) ([#14893](https://github.com/community-scripts/ProxmoxVE/pull/14893)) - - infisical: fix update abort due to creds field mismatch (#14868) [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14870](https://github.com/community-scripts/ProxmoxVE/pull/14870)) - - - #### ✨ New Features - - - feat(degoog): enable default valkey cache integration [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14871](https://github.com/community-scripts/ProxmoxVE/pull/14871)) - - - #### 🔧 Refactor - - - chore: bump Node version in selected scripts [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14873](https://github.com/community-scripts/ProxmoxVE/pull/14873)) - -### 💾 Core - - - #### ✨ New Features - - - tools.func: add support for Rust installation profile in setup_rust [@MickLesk](https://github.com/MickLesk) ([#14872](https://github.com/community-scripts/ProxmoxVE/pull/14872)) - -### 📂 Github - - - fix(workflow): only flag node drift when local is behind upstream [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14874](https://github.com/community-scripts/ProxmoxVE/pull/14874)) - -## 2026-06-01 - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - fix(dispatcharr): forward nginx port for M3U URLs on new installs [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14862](https://github.com/community-scripts/ProxmoxVE/pull/14862)) - - Set environment paths in service for apprise-api-install.sh [@SystemIdleProcess](https://github.com/SystemIdleProcess) ([#14805](https://github.com/community-scripts/ProxmoxVE/pull/14805)) - - fix(fireshare): rebuild client on update to fix nginx 500 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14848](https://github.com/community-scripts/ProxmoxVE/pull/14848)) - - Fix Kan build failure (TS7016 nodemailer) [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14856](https://github.com/community-scripts/ProxmoxVE/pull/14856)) - - fix(firefly): set Data Importer APP_URL for subdirectory install [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14847](https://github.com/community-scripts/ProxmoxVE/pull/14847)) - - kan: extend fetch_and_deploy_gh_tag to use 'latest' tag [@MickLesk](https://github.com/MickLesk) ([#14853](https://github.com/community-scripts/ProxmoxVE/pull/14853)) - - Glance: preserve glance.yml across updates [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14845](https://github.com/community-scripts/ProxmoxVE/pull/14845)) - - NginxProxymanager: set Certbot version in npm.service environment variable (2.15.0) [@MickLesk](https://github.com/MickLesk) ([#14843](https://github.com/community-scripts/ProxmoxVE/pull/14843)) - - [FileFlows] Fix service handling by using systemctl --all with quoted glob [@adrianmusante](https://github.com/adrianmusante) ([#14838](https://github.com/community-scripts/ProxmoxVE/pull/14838)) - - - #### ✨ New Features - - - Kometa: also update Quickstart in update_script [@MickLesk](https://github.com/MickLesk) ([#14529](https://github.com/community-scripts/ProxmoxVE/pull/14529)) - -## 2026-05-31 - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - Manyfold: regenerate Rails credentials on update to fix encryption mimatch [@MickLesk](https://github.com/MickLesk) ([#14817](https://github.com/community-scripts/ProxmoxVE/pull/14817)) - - OpenThread-BR: use correct ipv6 configuration [@tomfrenzel](https://github.com/tomfrenzel) ([#14829](https://github.com/community-scripts/ProxmoxVE/pull/14829)) - - - #### 🔧 Refactor - - - Webtrees: use PHP CLI for initial setup instead of curl to setup wizard [@MickLesk](https://github.com/MickLesk) ([#14818](https://github.com/community-scripts/ProxmoxVE/pull/14818)) - - Kima-Hub: use curl_with_retry for ML model downloads to fix possible timeout issues [@MickLesk](https://github.com/MickLesk) ([#14816](https://github.com/community-scripts/ProxmoxVE/pull/14816)) - -### 🧰 Tools - - - #### 🔧 Refactor - - - PBS4-Upgrade: update current PBS3 packages before switching to Trixie repos [@MickLesk](https://github.com/MickLesk) ([#14815](https://github.com/community-scripts/ProxmoxVE/pull/14815)) - -## 2026-05-30 - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - Flatnotes: fix empty package name in pyproject.toml [@MickLesk](https://github.com/MickLesk) ([#14814](https://github.com/community-scripts/ProxmoxVE/pull/14814)) - -## 2026-05-29 - -### 🆕 New Scripts - - - Kan ([#14776](https://github.com/community-scripts/ProxmoxVE/pull/14776)) -- Dynacat ([#14777](https://github.com/community-scripts/ProxmoxVE/pull/14777)) - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - Fix lobehub docker path [@dannyyy](https://github.com/dannyyy) ([#14793](https://github.com/community-scripts/ProxmoxVE/pull/14793)) - - karakeep: add more hdd space [@MickLesk](https://github.com/MickLesk) ([#14797](https://github.com/community-scripts/ProxmoxVE/pull/14797)) - - Grist: Revert installation of EE [@tremor021](https://github.com/tremor021) ([#14784](https://github.com/community-scripts/ProxmoxVE/pull/14784)) - - - #### 🔧 Refactor - - - Sure: Remove `$STD` for `systemctl enable -q` [@tremor021](https://github.com/tremor021) ([#14801](https://github.com/community-scripts/ProxmoxVE/pull/14801)) \ No newline at end of file + - update authentik to 2026.5.2 [@thieneret](https://github.com/thieneret) ([#14846](https://github.com/community-scripts/ProxmoxVE/pull/14846)) \ No newline at end of file From 954da140f14fe91b861d01ca1a1647a5f66ba1b4 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 5 Jul 2026 00:21:27 +0000 Subject: [PATCH 018/245] Update CHANGELOG.md (#15600) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fe0af921..02e01d7e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -499,6 +499,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
+## 2026-07-05 + ## 2026-07-04 ### 🚀 Updated Scripts From a8aa1ba085962c95ec7727aae5303c1ba54dc593 Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Sun, 5 Jul 2026 21:34:42 +0200 Subject: [PATCH 019/245] excalidash (#15604) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add excalidash (ct) * Apply suggestion from @tremor021 --------- Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com> Co-authored-by: Slaviša Arežina <58952836+tremor021@users.noreply.github.com> --- ct/excalidash.sh | 79 +++++++++++++++++++ ct/headers/excalidash | 6 ++ install/excalidash-install.sh | 139 ++++++++++++++++++++++++++++++++++ 3 files changed, 224 insertions(+) create mode 100644 ct/excalidash.sh create mode 100644 ct/headers/excalidash create mode 100644 install/excalidash-install.sh diff --git a/ct/excalidash.sh b/ct/excalidash.sh new file mode 100644 index 000000000..07f2f1764 --- /dev/null +++ b/ct/excalidash.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/ZimengXiong/ExcaliDash + +APP="ExcaliDash" +var_tags="${var_tags:-documents;drawing;collaboration}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-8}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-no}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/excalidash ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "excalidash" "ZimengXiong/ExcaliDash"; then + msg_info "Stopping Service" + systemctl stop excalidash + msg_ok "Stopped Service" + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "excalidash" "ZimengXiong/ExcaliDash" "tarball" + ln -sf /opt/excalidash_data/.env /opt/excalidash/backend/.env + set -a && source /opt/excalidash_data/.env && set +a + + msg_info "Configuring Database Provider (${DATABASE_PROVIDER:-sqlite})" + cd /opt/excalidash/backend + sed -i '/datasource db {/,/}/ s/provider = env("[^"]*")/provider = "'"${DATABASE_PROVIDER:-sqlite}"'"/' prisma/schema.prisma + mv prisma/migrations/"${DATABASE_PROVIDER:-sqlite}"/* prisma/migrations/ + rm -rf prisma/migrations/postgresql prisma/migrations/sqlite + msg_ok "Configured Database Provider" + + msg_info "Rebuilding Application" + $STD npm ci + $STD npx prisma generate + $STD npx tsc + cd /opt/excalidash/frontend + $STD npm ci + $STD npm run build + cp -r /opt/excalidash/frontend/dist/. /var/www/excalidash/ + msg_ok "Rebuilt Application" + + msg_info "Running Migrations" + cd /opt/excalidash/backend + $STD npx prisma migrate deploy + msg_ok "Ran Migrations" + + msg_info "Starting Service" + systemctl start excalidash + msg_ok "Started Service" + msg_ok "Updated successfully!" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:6767${CL}" diff --git a/ct/headers/excalidash b/ct/headers/excalidash new file mode 100644 index 000000000..5fb762583 --- /dev/null +++ b/ct/headers/excalidash @@ -0,0 +1,6 @@ + ______ ___ ____ __ + / ____/ ___________ _/ (_) __ \____ ______/ /_ + / __/ | |/_/ ___/ __ `/ / / / / / __ `/ ___/ __ \ + / /____> /opt/excalidash_data/.env +DATABASE_PROVIDER=postgresql +DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME} +PORT=8000 +NODE_ENV=production +FRONTEND_URL=http://${LOCAL_IP}:6767 +AUTH_MODE=local +TRUST_PROXY=false +RUN_MIGRATIONS=false +JWT_SECRET=$(openssl rand -hex 32) +CSRF_SECRET=$(openssl rand -base64 32) +EOF +ln -sf /opt/excalidash_data/.env /opt/excalidash/backend/.env +cd /opt/excalidash/backend +set -a && source /opt/excalidash_data/.env && set +a +$STD npx prisma migrate deploy +msg_ok "Configured Application" + +msg_info "Configuring Nginx" +cat </etc/nginx/sites-available/excalidash +server { + listen 6767; + server_name _; + root /var/www/excalidash; + index index.html; + client_max_body_size 50M; + + location /api/ { + proxy_pass http://127.0.0.1:8000/; + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_read_timeout 300s; + proxy_send_timeout 300s; + } + + location /socket.io/ { + proxy_pass http://127.0.0.1:8000/socket.io/; + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + } + + location / { + try_files \$uri \$uri/ /index.html; + } +} +EOF +ln -sf /etc/nginx/sites-available/excalidash /etc/nginx/sites-enabled/excalidash +rm -f /etc/nginx/sites-enabled/default +systemctl reload nginx +msg_ok "Configured Nginx" + +msg_info "Creating Service" +cat </etc/systemd/system/excalidash.service +[Unit] +Description=ExcaliDash Service +After=network.target postgresql.service + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/excalidash/backend +EnvironmentFile=/opt/excalidash/backend/.env +ExecStart=/usr/bin/node dist/index.js +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now excalidash +msg_ok "Created Service" + +motd_ssh +customize +cleanup_lxc From 4b71ee8b3a32ae4114a5de764e37a81a581f6d9b Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 5 Jul 2026 19:35:03 +0000 Subject: [PATCH 020/245] Update CHANGELOG.md (#15606) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02e01d7e8..91681c18f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -501,6 +501,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-05 +### 🆕 New Scripts + + - excalidash ([#15604](https://github.com/community-scripts/ProxmoxVE/pull/15604)) + ## 2026-07-04 ### 🚀 Updated Scripts From d8c636eaef3e076745942f0c88ae9035e9d293ec Mon Sep 17 00:00:00 2001 From: Kevin O'Brien Date: Sun, 5 Jul 2026 16:03:56 -0400 Subject: [PATCH 021/245] immich: vacuum smart_search/face_search before VectorChord bump (#15607) Co-authored-by: Kevin O'Brien --- ct/immich.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ct/immich.sh b/ct/immich.sh index 321889a09..77500920c 100644 --- a/ct/immich.sh +++ b/ct/immich.sh @@ -127,6 +127,11 @@ EOF VCHORD_RELEASE="1.0.0" [[ -f ~/.vchord_version ]] && mv ~/.vchord_version ~/.vectorchord if check_for_gh_release "VectorChord" "tensorchord/VectorChord" "${VCHORD_RELEASE}" "updated together with Immich after testing"; then + # dead tuples in smart_search/face_search make the REINDEX below fail with + # "missing chunk ... for toast value" on VectorChord 1.0.0 (#15588); must vacuum + # while still on the old extension version, a post-upgrade vacuum errors instead + $STD sudo -u postgres psql -d immich -c "VACUUM (ANALYZE) smart_search;" + $STD sudo -u postgres psql -d immich -c "VACUUM (ANALYZE) face_search;" fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" "${VCHORD_RELEASE}" "/tmp" "postgresql-16-vchord_*_$(arch_resolve).deb" systemctl restart postgresql $STD sudo -u postgres psql -d immich -c "ALTER EXTENSION vector UPDATE;" From 4ebae9f1c45d2cb6b55ce316d6fa28756e2bb362 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 5 Jul 2026 20:04:20 +0000 Subject: [PATCH 022/245] Update CHANGELOG.md (#15608) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91681c18f..a0d13cf9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -505,6 +505,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - excalidash ([#15604](https://github.com/community-scripts/ProxmoxVE/pull/15604)) +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - immich: vacuum smart_search/face_search before VectorChord bump [@irishpadres](https://github.com/irishpadres) ([#15607](https://github.com/community-scripts/ProxmoxVE/pull/15607)) + ## 2026-07-04 ### 🚀 Updated Scripts From 86991b283daa00eb1e49d0b50c9da0b955a85f05 Mon Sep 17 00:00:00 2001 From: Tobias <96661824+CrazyWolf13@users.noreply.github.com> Date: Sun, 5 Jul 2026 22:28:00 +0200 Subject: [PATCH 023/245] fix: homarr: cli (#15603) --- ct/homarr.sh | 5 +++++ install/homarr-install.sh | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ct/homarr.sh b/ct/homarr.sh index 82a27cfd6..620b147a9 100644 --- a/ct/homarr.sh +++ b/ct/homarr.sh @@ -35,6 +35,11 @@ function update_script() { systemctl stop redis-server msg_ok "Services Stopped" + if ! grep -q "source /opt/homarr.env" /usr/bin/homarr 2>/dev/null; then + echo $'#!/bin/bash\nset -a\nsource /opt/homarr.env\nset +a\ncd /opt/homarr/apps/cli && timeout 10 node ./cli.cjs "$@"' >/usr/bin/homarr + chmod +x /usr/bin/homarr + fi + if ! { grep -q '^REDIS_IS_EXTERNAL=' /opt/homarr/.env 2>/dev/null || grep -q '^REDIS_IS_EXTERNAL=' /opt/homarr.env 2>/dev/null; }; then msg_info "Fixing old structure" systemctl disable -q --now nginx diff --git a/install/homarr-install.sh b/install/homarr-install.sh index 0a976b668..db89c2542 100644 --- a/install/homarr-install.sh +++ b/install/homarr-install.sh @@ -52,7 +52,7 @@ grep -q '^bind 127.0.0.1 -::1$' /etc/redis/redis.conf || echo "bind 127.0.0.1 -: rm -f /etc/nginx/nginx.conf mkdir -p /etc/nginx/templates cp /opt/homarr/nginx.conf /etc/nginx/templates/nginx.conf -echo $'#!/bin/bash\ncd /opt/homarr/apps/cli && node ./cli.cjs "$@"' >/usr/bin/homarr +echo $'#!/bin/bash\nset -a\nsource /opt/homarr.env\nset +a\ncd /opt/homarr/apps/cli && node ./cli.cjs "$@"' >/usr/bin/homarr chmod +x /usr/bin/homarr msg_ok "Copied config files" From 417b0641a0d6196aadcce450ac17b9ccc96c6f10 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 5 Jul 2026 20:28:22 +0000 Subject: [PATCH 024/245] Update CHANGELOG.md (#15609) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0d13cf9d..4c48a7a4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -509,6 +509,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - fix: homarr: cli [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15603](https://github.com/community-scripts/ProxmoxVE/pull/15603)) - immich: vacuum smart_search/face_search before VectorChord bump [@irishpadres](https://github.com/irishpadres) ([#15607](https://github.com/community-scripts/ProxmoxVE/pull/15607)) ## 2026-07-04 From 20740c3ca20adf808dc043eb00fd5f6aa468d005 Mon Sep 17 00:00:00 2001 From: MickLesk Date: Mon, 6 Jul 2026 14:38:07 +0200 Subject: [PATCH 025/245] fix(docker): remove interactive container update check from setup_docker The 'Interactive Container Update Check' block scanned ALL running Docker containers, pulled their images, then stopped and removed them with only a message asking the user to manually recreate them. This is destructive and outside the scope of the Docker LXC update script, which is responsible for updating the Docker engine itself and the Portainer / Portainer-Agent containers that this script originally installed. Removes the entire block. Updates now cover: - OS packages (apt) - Docker engine (via setup_docker / repo) - Portainer CE (if installed by this script) - Portainer Agent (if installed by this script) Self-hosted / user-managed containers are intentionally left alone. Fixes #15601 --- misc/tools.func | 60 ------------------------------------------------- 1 file changed, 60 deletions(-) diff --git a/misc/tools.func b/misc/tools.func index 883c98da0..29bf34314 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -4641,66 +4641,6 @@ EOF fi fi - # Interactive Container Update Check - if [[ "${DOCKER_SKIP_UPDATES:-}" != "true" ]] && [ "$docker_installed" = true ] && ! _docker_is_noninteractive; then - msg_info "Checking for container updates" - - # Get list of running containers with update status - local containers_with_updates=() - local container_info=() - local index=1 - - while IFS= read -r container; do - local name=$(echo "$container" | awk '{print $1}') - local image=$(echo "$container" | awk '{print $2}') - local current_digest=$(docker inspect "$name" --format='{{.Image}}' 2>/dev/null | cut -d':' -f2 | cut -c1-12) - - # Pull latest image digest (ignore failures, e.g. local-only images or registry/permission issues) - docker pull "$image" >/dev/null 2>&1 || true - local latest_digest=$(docker inspect "$image" --format='{{.Id}}' 2>/dev/null | cut -d':' -f2 | cut -c1-12) - - if [ -n "$latest_digest" ] && [ "$current_digest" != "$latest_digest" ]; then - containers_with_updates+=("$name") - container_info+=("${index}) ${name} (${image})") - ((index++)) - fi - done < <(docker ps --format '{{.Names}} {{.Image}}') - - if [ ${#containers_with_updates[@]} -gt 0 ]; then - echo "" - echo "${TAB3}Container updates available:" - for info in "${container_info[@]}"; do - echo "${TAB3} $info" - done - echo "" - read -r -p "${TAB3}Select containers to update (e.g., 1,3,5 or 'all' or 'none'): " selection - - if [[ ${selection,,} == "all" ]]; then - for container in "${containers_with_updates[@]}"; do - msg_info "Updating container: $container" - docker stop "$container" - docker rm "$container" - # Note: This requires the original docker run command - best to recreate via compose - msg_ok "Stopped and removed $container (please recreate with updated image)" - done - elif [[ ${selection,,} != "none" ]]; then - IFS=',' read -ra SELECTED <<<"$selection" - for num in "${SELECTED[@]}"; do - num=$(echo "$num" | xargs) # trim whitespace - if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le "${#containers_with_updates[@]}" ]; then - container="${containers_with_updates[$((num - 1))]}" - msg_info "Updating container: $container" - docker stop "$container" - docker rm "$container" - msg_ok "Stopped and removed $container (please recreate with updated image)" - fi - done - fi - else - msg_ok "All containers are up-to-date" - fi - fi - msg_ok "Docker setup completed" } From 728726d5ccac635527c34e7ae1280510d1473abe Mon Sep 17 00:00:00 2001 From: MickLesk Date: Mon, 6 Jul 2026 14:43:25 +0200 Subject: [PATCH 026/245] fix(docker): safe, interactive per-container update check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the destructive multi-select container update block with a proper per-container Y/N workflow: - Unattended / non-interactive (DOCKER_NONINTERACTIVE=1 or no tty): skip silently -- no docker pulls, no prompts. - Interactive: stop_spinner() before any prompt to keep the terminal clean, then for each container with a newer image: Compose-managed → prompt Y/N (auto-no after 60 s) → on Y: docker compose pull && docker compose up -d Standalone run → prompt Y/N (auto-no after 60 s) → on Y: docker pull only; no stop/rm; user is told to recreate manually - portainer / portainer_agent are excluded (handled earlier in setup_docker) The old code always stopped and removed the container without recreating it, leaving users with a destroyed service. Standalone containers without a Compose project can never be auto-recreated safely, so only the image is pulled. Fixes #15601 --- misc/tools.func | 84 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/misc/tools.func b/misc/tools.func index 29bf34314..e8e18f4f3 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -4454,7 +4454,9 @@ setup_composer() { # - Uses stable distro packages by default # - Migrates from get.docker.com to repository-based installation # - Updates Docker Engine if newer version available -# - Interactive container update with multi-select +# - Interactive per-container update prompt (Y/N, 60 s auto-no) +# - Compose-managed containers: full restart via docker compose +# - Standalone containers: image pull only, no destructive stop/rm # - Portainer installation and update support # - Set DOCKER_NONINTERACTIVE=1 to skip interactive prompts (CI/unattended) # ------------------------------------------------------------------------------ @@ -4641,6 +4643,86 @@ EOF fi fi + # Container Update Check + # - Skipped entirely when running unattended / non-interactive + # - Compose-managed containers: offered via Y/N → docker compose pull + up -d + # - Standalone containers: offered via Y/N → image pull only (no stop/rm) + if [ "$docker_installed" = true ] && ! _docker_is_noninteractive; then + msg_info "Checking for container updates" + + local name image compose_workdir compose_service current_digest latest_digest + local compose_updates=() + local standalone_updates=() + + while IFS= read -r line; do + name=$(echo "$line" | awk '{print $1}') + image=$(echo "$line" | awk '{print $2}') + + # Portainer containers are handled by the dedicated block above + [[ "$name" == "portainer" || "$name" == "portainer_agent" ]] && continue + + current_digest=$(docker inspect "$name" --format='{{.Image}}' 2>/dev/null | cut -d':' -f2 | cut -c1-12) + docker pull "$image" >/dev/null 2>&1 || continue + latest_digest=$(docker inspect "$image" --format='{{.Id}}' 2>/dev/null | cut -d':' -f2 | cut -c1-12) + [[ -z "$latest_digest" || "$current_digest" == "$latest_digest" ]] && continue + + compose_workdir=$(docker inspect "$name" \ + --format='{{index .Config.Labels "com.docker.compose.project.working_dir"}}' 2>/dev/null || true) + compose_service=$(docker inspect "$name" \ + --format='{{index .Config.Labels "com.docker.compose.service"}}' 2>/dev/null || true) + + if [[ -n "$compose_workdir" && -n "$compose_service" && -d "$compose_workdir" ]]; then + compose_updates+=("${name}|${image}|${compose_workdir}|${compose_service}") + else + standalone_updates+=("${name}|${image}") + fi + done < <(docker ps --format '{{.Names}} {{.Image}}') + + # Stop spinner before any interactive prompt + stop_spinner + + if [[ ${#compose_updates[@]} -eq 0 && ${#standalone_updates[@]} -eq 0 ]]; then + msg_ok "All containers are up-to-date" + else + local reply + for entry in "${compose_updates[@]}"; do + IFS='|' read -r name image compose_workdir compose_service <<<"$entry" + reply="" + if read -r -t 60 -p "${TAB3}Update ${name} (${image}) via Compose? (auto-no in 60s): " reply; then + echo "" + else + echo "" + fi + if [[ "${reply,,}" =~ ^(y|yes)$ ]]; then + msg_info "Updating $name" + if (cd "$compose_workdir" && $STD docker compose pull "$compose_service" && $STD docker compose up -d "$compose_service"); then + msg_ok "Updated $name" + else + msg_warn "Could not update $name — try manually in $compose_workdir" + fi + fi + done + + for entry in "${standalone_updates[@]}"; do + IFS='|' read -r name image <<<"$entry" + reply="" + if read -r -t 60 -p "${TAB3}Pull new image for ${name} (${image})? (auto-no in 60s): " reply; then + echo "" + else + echo "" + fi + if [[ "${reply,,}" =~ ^(y|yes)$ ]]; then + msg_info "Pulling new image for $name" + if $STD docker pull "$image"; then + msg_ok "New image available for $name — recreate the container to apply the update" + else + msg_warn "Failed to pull image for $name" + fi + fi + done + fi + fi + msg_ok "Docker setup completed" } From 93ce08aa72d6fde738a7328f4fb4ec78b82f87ae Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 12:44:28 +0000 Subject: [PATCH 027/245] Update CHANGELOG.md (#15616) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c48a7a4b..af1d268f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -499,6 +499,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-06 + ## 2026-07-05 ### 🆕 New Scripts From 555953117c76a17f75521247bcbd2cbd1c6ed303 Mon Sep 17 00:00:00 2001 From: Sam Heinz Date: Mon, 6 Jul 2026 23:00:41 +1000 Subject: [PATCH 028/245] fix(plane): don't clobber global app var, breaking /usr/bin/update (#15612) --- install/plane-install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/plane-install.sh b/install/plane-install.sh index 2c03938a3..d481c6551 100644 --- a/install/plane-install.sh +++ b/install/plane-install.sh @@ -85,8 +85,8 @@ VITE_SPACE_BASE_PATH=/spaces VITE_LIVE_BASE_URL=http://${LOCAL_IP} VITE_LIVE_BASE_PATH=/live" # Each Vite app needs its own .env for the build -for app in web admin space; do - echo "$FRONTEND_ENV" >/opt/plane/apps/${app}/.env +for frontend_app in web admin space; do + echo "$FRONTEND_ENV" >/opt/plane/apps/${frontend_app}/.env done export NODE_OPTIONS="--max-old-space-size=4096" export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 From 81d6b2beeea2032529790e8eda19c9443243ba23 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 13:01:09 +0000 Subject: [PATCH 029/245] Update CHANGELOG.md (#15617) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af1d268f1..d3b266ab5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -501,6 +501,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-06 +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - fix(plane): don't clobber global app var, breaking /usr/bin/update [@asylumexp](https://github.com/asylumexp) ([#15612](https://github.com/community-scripts/ProxmoxVE/pull/15612)) + ## 2026-07-05 ### 🆕 New Scripts From 68cc4f3da7ac91f6a6ecbb63159f63051bf35033 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 6 Jul 2026 09:38:39 -0400 Subject: [PATCH 030/245] Immich: Update libvips to 8.18.4 (#15619) --- ct/immich.sh | 2 +- install/immich-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/immich.sh b/ct/immich.sh index 77500920c..48ae7ceda 100644 --- a/ct/immich.sh +++ b/ct/immich.sh @@ -471,7 +471,7 @@ function compile_imagemagick() { function compile_libvips() { SOURCE=$SOURCE_DIR/libvips - LIBVIPS_REVISION="3664cfc5dc2c5661288f5bf5a85ccc51c64c1626" + LIBVIPS_REVISION="e01a4797cabe77d457fdfa7d776b7a7e7ca6d6a7" if [[ "$LIBVIPS_REVISION" != "$(grep 'libvips' ~/.immich_library_revisions | awk '{print $2}')" ]]; then msg_info "Recompiling libvips" [[ -d "$SOURCE" ]] && rm -rf "$SOURCE" diff --git a/install/immich-install.sh b/install/immich-install.sh index 9270b29e1..fcaad3e0b 100644 --- a/install/immich-install.sh +++ b/install/immich-install.sh @@ -282,7 +282,7 @@ msg_ok "(4/5) Compiled imagemagick" msg_info "(5/5) Compiling libvips" SOURCE=$SOURCE_DIR/libvips -LIBVIPS_REVISION="3664cfc5dc2c5661288f5bf5a85ccc51c64c1626" +LIBVIPS_REVISION="e01a4797cabe77d457fdfa7d776b7a7e7ca6d6a7" $STD git clone https://github.com/libvips/libvips.git "$SOURCE" cd "$SOURCE" $STD git reset --hard "$LIBVIPS_REVISION" From 766f8519a3ccabdcdef30223afffbb894223903d Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 13:39:09 +0000 Subject: [PATCH 031/245] Update CHANGELOG.md (#15620) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3b266ab5..d7b63cd8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -503,6 +503,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🚀 Updated Scripts + - Immich: Update libvips to 8.18.4 [@vhsdream](https://github.com/vhsdream) ([#15619](https://github.com/community-scripts/ProxmoxVE/pull/15619)) + - #### 🐞 Bug Fixes - fix(plane): don't clobber global app var, breaking /usr/bin/update [@asylumexp](https://github.com/asylumexp) ([#15612](https://github.com/community-scripts/ProxmoxVE/pull/15612)) From 7027d67eb3a2080cfdef33b2c4547d9640ac3ba8 Mon Sep 17 00:00:00 2001 From: Sam Heinz Date: Mon, 6 Jul 2026 23:41:55 +1000 Subject: [PATCH 032/245] attempt to port docker-vm to support arm64 (#15611) --- misc/vm-core.func | 15 +++++++++++---- vm/docker-vm.sh | 33 ++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/misc/vm-core.func b/misc/vm-core.func index 8ad2dfc37..da9ee5584 100644 --- a/misc/vm-core.func +++ b/misc/vm-core.func @@ -620,12 +620,19 @@ pve_check() { } arch_check() { - if [ "$(dpkg --print-architecture)" != "amd64" ]; then - echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n" - echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n" + local arch + arch="$(dpkg --print-architecture)" + if [[ "$arch" != "amd64" && "$arch" != "arm64" ]]; then + msg_error "This script requires amd64 or arm64." echo -e "Exiting..." sleep 2 - exit + exit 106 + fi + if [[ "$arch" == "arm64" && "${var_arm64:-}" != "yes" ]]; then + echo -e "\n ${INFO}${YWB}This script does not yet support ARM64! \n" + echo -e "Exiting..." + sleep 2 + exit 106 fi } diff --git a/vm/docker-vm.sh b/vm/docker-vm.sh index 194470a40..35d247333 100644 --- a/vm/docker-vm.sh +++ b/vm/docker-vm.sh @@ -11,7 +11,6 @@ source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/misc/api.func) 2>/dev/null source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/misc/vm-core.func) 2>/dev/null source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/misc/cloud-init.func) 2>/dev/null || true -load_functions # ============================================================================== # SCRIPT VARIABLES @@ -21,6 +20,7 @@ APP_TYPE="vm" NSAPP="docker-vm" var_os="debian" var_version="13" +ARCH=$(dpkg --print-architecture) GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//') RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" @@ -30,6 +30,9 @@ USE_CLOUD_INIT="no" OS_TYPE="" OS_VERSION="" THIN="discard=on,ssd=1," +var_arm64="yes" + +load_functions # ============================================================================== # ERROR HANDLING & CLEANUP @@ -136,11 +139,16 @@ function default_settings() { VMID=$(get_valid_nextid) FORMAT="" - MACHINE=" -machine q35" + if [ "$ARCH" = "arm64" ]; then + MACHINE="" + CPU_TYPE="" + else + MACHINE=" -machine q35" + CPU_TYPE=" -cpu host" + fi DISK_CACHE="" DISK_SIZE="10G" HN="docker" - CPU_TYPE=" -cpu host" CORE_COUNT="2" RAM_SIZE="4096" BRG="vmbr0" @@ -151,11 +159,15 @@ function default_settings() { METHOD="default" echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}${VMID}${CL}" - echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}Q35 (Modern)${CL}" + if [ "$ARCH" = "arm64" ]; then + echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}virt (ARM64)${CL}" + else + echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}Q35 (Modern)${CL}" + fi echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE}${CL}" echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}" echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}${HN}${CL}" - echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}" + echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}$([ "$ARCH" = "arm64" ] && echo "Default" || echo "Host")${CL}" echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}" echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE}${CL}" echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}${BRG}${CL}" @@ -197,7 +209,11 @@ function advanced_settings() { done # Machine Type - if MACH=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \ + if [ "$ARCH" = "arm64" ]; then + FORMAT="" + MACHINE="" + echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}virt${CL}" + elif MACH=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \ "q35" "Q35 (Modern, PCIe)" ON \ "i440fx" "i440fx (Legacy, PCI)" OFF \ 3>&1 1>&2 2>&3); then @@ -262,7 +278,10 @@ function advanced_settings() { fi # CPU Model - if CPU_TYPE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \ + if [ "$ARCH" = "arm64" ]; then + CPU_TYPE="" + echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Default${CL}" + elif CPU_TYPE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \ "1" "Host (Recommended)" ON \ "0" "KVM64" OFF \ 3>&1 1>&2 2>&3); then From bff3c6932a0f699d1f1934485c40a772ad9a0655 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 13:42:23 +0000 Subject: [PATCH 033/245] Update CHANGELOG.md (#15621) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7b63cd8a..8bdbe2bf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -507,6 +507,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - attempt to port docker-vm to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15611](https://github.com/community-scripts/ProxmoxVE/pull/15611)) - fix(plane): don't clobber global app var, breaking /usr/bin/update [@asylumexp](https://github.com/asylumexp) ([#15612](https://github.com/community-scripts/ProxmoxVE/pull/15612)) ## 2026-07-05 From c5f905ccf1a32d2cfe73349df4371cee755e17b9 Mon Sep 17 00:00:00 2001 From: Austin Date: Mon, 6 Jul 2026 14:18:09 -0400 Subject: [PATCH 034/245] cliproxyapi: point setup message at /management.html (#15628) The completion message previously pointed to the bare host:port, which serves the proxy API rather than the admin UI. Provider authentication happens at /management.html. Co-authored-by: root --- ct/cliproxyapi.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/cliproxyapi.sh b/ct/cliproxyapi.sh index cffa0fc17..9eb49a1a6 100644 --- a/ct/cliproxyapi.sh +++ b/ct/cliproxyapi.sh @@ -52,5 +52,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW}Access it using the following URL:${CL}" -echo -e "${GATEWAY}${BGN}http://${IP}:8317${CL}" +echo -e "${INFO}${YW}Authenticate your AI providers via the management panel at:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:8317/management.html${CL}" From 87ccf49dc32f47a9e843e1fb1768cce455b71bb0 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 18:18:31 +0000 Subject: [PATCH 035/245] Update CHANGELOG.md (#15629) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bdbe2bf7..c6fdda187 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -510,6 +510,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - attempt to port docker-vm to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15611](https://github.com/community-scripts/ProxmoxVE/pull/15611)) - fix(plane): don't clobber global app var, breaking /usr/bin/update [@asylumexp](https://github.com/asylumexp) ([#15612](https://github.com/community-scripts/ProxmoxVE/pull/15612)) + - #### 🔧 Refactor + + - cliproxyapi: point setup message at /management.html [@austinpilz](https://github.com/austinpilz) ([#15628](https://github.com/community-scripts/ProxmoxVE/pull/15628)) + ## 2026-07-05 ### 🆕 New Scripts From fe7de5e26cec5587f27e1b33b23d0ca4f6d6ab33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Slavi=C5=A1a=20Are=C5=BEina?= <58952836+tremor021@users.noreply.github.com> Date: Mon, 6 Jul 2026 20:18:45 +0200 Subject: [PATCH 036/245] Update URL format in rustdeskserver.sh (#15626) --- ct/rustdeskserver.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ct/rustdeskserver.sh b/ct/rustdeskserver.sh index 921ab1130..8831bda20 100644 --- a/ct/rustdeskserver.sh +++ b/ct/rustdeskserver.sh @@ -60,4 +60,4 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" echo -e "${INFO}${YW}Access it using the following URL:${CL}" -echo -e "${GATEWAY}${BGN}${IP}:21114${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:21114${CL}" From e00df4fd6e3cd4d8f62fe290ff5d738b9e5c4279 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 18:18:57 +0000 Subject: [PATCH 037/245] Update CHANGELOG.md (#15630) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6fdda187..c67f8c59a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -507,6 +507,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - RustDesk Server: Update URL format in rustdeskserver.sh [@tremor021](https://github.com/tremor021) ([#15626](https://github.com/community-scripts/ProxmoxVE/pull/15626)) - attempt to port docker-vm to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15611](https://github.com/community-scripts/ProxmoxVE/pull/15611)) - fix(plane): don't clobber global app var, breaking /usr/bin/update [@asylumexp](https://github.com/asylumexp) ([#15612](https://github.com/community-scripts/ProxmoxVE/pull/15612)) From 0102d5bd83e79970f73241072be8b36aebe8151b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Slavi=C5=A1a=20Are=C5=BEina?= <58952836+tremor021@users.noreply.github.com> Date: Mon, 6 Jul 2026 21:15:04 +0200 Subject: [PATCH 039/245] fix alignment in various ct end messages (#15632) --- ct/alpine-cinny.sh | 4 +- ct/apache-airflow.sh | 6 +- ct/authentik.sh | 120 ++++++++++++++++++++-------------------- ct/baserow.sh | 4 +- ct/bookorbit.sh | 4 +- ct/clickhouse.sh | 4 +- ct/cross-seed.sh | 2 +- ct/cyberchef.sh | 8 +-- ct/etherpad.sh | 4 +- ct/excalidash.sh | 4 +- ct/feishin.sh | 4 +- ct/flame.sh | 6 +- ct/fmd-server.sh | 4 +- ct/hev-socks5-server.sh | 3 +- ct/iventoy.sh | 4 +- ct/kiwix.sh | 8 +-- ct/koffan.sh | 4 +- ct/kometa.sh | 2 +- ct/loki.sh | 62 ++++++++++----------- ct/lyrionmusicserver.sh | 4 +- ct/matterjs-server.sh | 8 +-- ct/netbird.sh | 2 +- ct/paperclip.sh | 4 +- ct/pinchflat.sh | 4 +- ct/plane.sh | 12 ++-- ct/postiz.sh | 7 +-- ct/rackula.sh | 4 +- ct/shlink.sh | 2 +- ct/snapotter.sh | 4 +- ct/spliit.sh | 4 +- ct/tolgee.sh | 4 +- ct/twenty.sh | 9 ++- ct/xyops.sh | 4 +- 33 files changed, 163 insertions(+), 166 deletions(-) diff --git a/ct/alpine-cinny.sh b/ct/alpine-cinny.sh index 72c93f3e6..17a6019ae 100644 --- a/ct/alpine-cinny.sh +++ b/ct/alpine-cinny.sh @@ -54,5 +54,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following IP:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}" +echo -e "${INFO}${YW}Access it using the following IP:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:8080${CL}" diff --git a/ct/apache-airflow.sh b/ct/apache-airflow.sh index d6a331177..2a97f914d 100644 --- a/ct/apache-airflow.sh +++ b/ct/apache-airflow.sh @@ -33,7 +33,7 @@ function update_script() { INSTALLED=$(cat ~/.airflow 2>/dev/null || echo "0") LATEST=$(curl -fsSL "https://pypi.org/pypi/apache-airflow/json" | jq -r '.info.version') - if [[ "$INSTALLED" == "$LATEST" ]]; then + if [[ $INSTALLED == "$LATEST" ]]; then msg_ok "Already on the latest version (${LATEST})" exit fi @@ -71,5 +71,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:8080${CL}" diff --git a/ct/authentik.sh b/ct/authentik.sh index b857bcff4..c8b99db82 100644 --- a/ct/authentik.sh +++ b/ct/authentik.sh @@ -30,7 +30,7 @@ function update_script() { exit fi - read -r MAJOR MINOR PATCH <<< "$(sed 's/^version\///; s/\./ /g' "$HOME/.authentik")" + read -r MAJOR MINOR PATCH <<<"$(sed 's/^version\///; s/\./ /g' "$HOME/.authentik")" msg_info "Update dependencies" ensure_dependencies crossbuild-essential-$(arch_resolve) gcc-$(arch_resolve "x86-64" "aarch64")-linux-gnu cmake clang libunwind-18-dev @@ -66,26 +66,26 @@ function update_script() { if check_for_gh_release "authentik" "goauthentik/authentik" "${AUTHENTIK_VERSION}"; then msg_info "Stopping Services" systemctl stop authentik-server authentik-worker - if [[ $(systemctl is-active authentik-ldap) == active ]]; then - systemctl stop authentik-ldap - fi - if [[ $(systemctl is-active authentik-rac) == active ]]; then - systemctl stop authentik-rac - fi - if [[ $(systemctl is-active authentik-radius) == active ]]; then - systemctl stop authentik-radius - fi + if [[ $(systemctl is-active authentik-ldap) == active ]]; then + systemctl stop authentik-ldap + fi + if [[ $(systemctl is-active authentik-rac) == active ]]; then + systemctl stop authentik-rac + fi + if [[ $(systemctl is-active authentik-radius) == active ]]; then + systemctl stop authentik-radius + fi msg_ok "Stopped Services" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "authentik" "goauthentik/authentik" "tarball" "${AUTHENTIK_VERSION}" "/opt/authentik" - msg_info "Configuring rust" - cd /opt/authentik - $STD rustup install - $STD rustup default "$(sed -n 's/channel = "\(.*\)"/\1/p' rust-toolchain.toml)" - msg_ok "Configured rust" + msg_info "Configuring rust" + cd /opt/authentik + $STD rustup install + $STD rustup default "$(sed -n 's/channel = "\(.*\)"/\1/p' rust-toolchain.toml)" + msg_ok "Configured rust" - msg_info "Updating web" + msg_info "Updating web" cd /opt/authentik/web export NODE_ENV="production" $STD npm install @@ -99,18 +99,18 @@ function update_script() { export CC="$(arch_resolve "x86_64" "aarch64")-linux-gnu-gcc" $STD go mod download $STD go build -o /opt/authentik/authentik-server ./cmd/server - $STD go build -o /opt/authentik/ldap ./cmd/ldap - $STD go build -o /opt/authentik/rac ./cmd/rac - $STD go build -o /opt/authentik/radius ./cmd/radius + $STD go build -o /opt/authentik/ldap ./cmd/ldap + $STD go build -o /opt/authentik/rac ./cmd/rac + $STD go build -o /opt/authentik/radius ./cmd/radius msg_ok "Updated go proxy" - msg_info "Building worker" - export AWS_LC_FIPS_SYS_CC="clang" - cd /opt/authentik - $STD cargo build --package authentik --no-default-features --features core --locked --release --jobs 1 - cp ./target/release/authentik /opt/authentik/authentik-worker - rm -r ./target - msg_ok "Built worker" + msg_info "Building worker" + export AWS_LC_FIPS_SYS_CC="clang" + cd /opt/authentik + $STD cargo build --package authentik --no-default-features --features core --locked --release --jobs 1 + cp ./target/release/authentik /opt/authentik/authentik-worker + rm -r ./target + msg_ok "Built worker" msg_info "Updating python server" export UV_NO_BINARY_PACKAGE="cryptography lxml python-kadmin-rs xmlsec" @@ -125,26 +125,26 @@ function update_script() { msg_ok "Updated python server" if [[ $MAJOR == 2026 && $MINOR -lt 5 ]]; then - msg_info "Updating Worker and Server config" - cp /etc/authentik/config.yml /etc/authentik/config.bak - yq -i ".postgresql.conn_max_age = 0" /etc/authentik/config.yml - yq -i ".postgresql.conn_health_checks = false" /etc/authentik/config.yml - yq -i ".listen.debug_tokio = \"[::]:6669\"" /etc/authentik/config.yml - yq -i ".log.rust_log.console_subscriber = \"info\"" /etc/authentik/config.yml - yq -i ".log.rust_log.h2 = \"info\"" /etc/authentik/config.yml - yq -i ".log.rust_log.hyper_util = \"warn\"" /etc/authentik/config.yml - yq -i ".log.rust_log.mio = \"info\"" /etc/authentik/config.yml - yq -i ".log.rust_log.notify = \"info\"" /etc/authentik/config.yml - yq -i ".log.rust_log.reqwest = \"info\"" /etc/authentik/config.yml - yq -i ".log.rust_log.runtime = \"info\"" /etc/authentik/config.yml - yq -i ".log.rust_log.rustls = \"info\"" /etc/authentik/config.yml - yq -i ".log.rust_log.sqlx = \"info\"" /etc/authentik/config.yml - yq -i ".log.rust_log.sqlx_postgres = \"info\"" /etc/authentik/config.yml - yq -i ".log.rust_log.tokio = \"info\"" /etc/authentik/config.yml - yq -i ".log.rust_log.tungstenite = \"info\"" /etc/authentik/config.yml - yq -i ".web.workers = 2" /etc/authentik/config.yml - mv /etc/default/authentik /etc/default/authentik.bak - cat </etc/default/authentik-server + msg_info "Updating Worker and Server config" + cp /etc/authentik/config.yml /etc/authentik/config.bak + yq -i ".postgresql.conn_max_age = 0" /etc/authentik/config.yml + yq -i ".postgresql.conn_health_checks = false" /etc/authentik/config.yml + yq -i '.listen.debug_tokio = "[::]:6669"' /etc/authentik/config.yml + yq -i '.log.rust_log.console_subscriber = "info"' /etc/authentik/config.yml + yq -i '.log.rust_log.h2 = "info"' /etc/authentik/config.yml + yq -i '.log.rust_log.hyper_util = "warn"' /etc/authentik/config.yml + yq -i '.log.rust_log.mio = "info"' /etc/authentik/config.yml + yq -i '.log.rust_log.notify = "info"' /etc/authentik/config.yml + yq -i '.log.rust_log.reqwest = "info"' /etc/authentik/config.yml + yq -i '.log.rust_log.runtime = "info"' /etc/authentik/config.yml + yq -i '.log.rust_log.rustls = "info"' /etc/authentik/config.yml + yq -i '.log.rust_log.sqlx = "info"' /etc/authentik/config.yml + yq -i '.log.rust_log.sqlx_postgres = "info"' /etc/authentik/config.yml + yq -i '.log.rust_log.tokio = "info"' /etc/authentik/config.yml + yq -i '.log.rust_log.tungstenite = "info"' /etc/authentik/config.yml + yq -i ".web.workers = 2" /etc/authentik/config.yml + mv /etc/default/authentik /etc/default/authentik.bak + cat </etc/default/authentik-server TMPDIR=/dev/shm/ UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=0 @@ -159,7 +159,7 @@ AUTHENTIK_LISTEN__HTTP="[::]:9000" AUTHENTIK_LISTEN__HTTPS="[::]:9443" AUTHENTIK_LISTEN__METRICS="[::]:9300" EOF - cat </etc/default/authentik-worker + cat </etc/default/authentik-worker TMPDIR=/dev/shm/ UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=0 @@ -174,11 +174,11 @@ AUTHENTIK_LISTEN__HTTP="[::]:8000" AUTHENTIK_LISTEN__HTTPS="[::]:8443" AUTHENTIK_LISTEN__METRICS="[::]:8300" EOF - msg_ok "Updated Worker and Server config!" - msg_warn "Please check /etc/default/authentik-worker and /etc/default/authentik-server config files for port configurations!" + msg_ok "Updated Worker and Server config!" + msg_warn "Please check /etc/default/authentik-worker and /etc/default/authentik-server config files for port configurations!" - msg_info "Updating services" - cat </etc/systemd/system/authentik-server.service + msg_info "Updating services" + cat </etc/systemd/system/authentik-server.service [Unit] Description=authentik Go Server (API Gateway) After=network.target @@ -198,7 +198,7 @@ EnvironmentFile=/etc/default/authentik-server WantedBy=multi-user.target EOF - cat </etc/systemd/system/authentik-worker.service + cat </etc/systemd/system/authentik-worker.service [Unit] Description=authentik Worker After=network.target postgresql.service @@ -217,21 +217,21 @@ RestartSec=5 [Install] WantedBy=multi-user.target EOF - systemctl daemon-reload - msg_ok "Updated services" - fi + systemctl daemon-reload + msg_ok "Updated services" + fi fi msg_info "Starting Services" systemctl start authentik-server authentik-worker if [[ $(systemctl is-enabled authentik-ldap) == enabled ]]; then - systemctl start authentik-ldap + systemctl start authentik-ldap fi if [[ $(systemctl is-enabled authentik-rac) == enabled ]]; then - systemctl start authentik-rac + systemctl start authentik-rac fi if [[ $(systemctl is-enabled authentik-radius) == enabled ]]; then - systemctl start authentik-radius + systemctl start authentik-radius fi msg_ok "Started Services" msg_ok "Updated successfully!" @@ -270,5 +270,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:9443${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}https://${IP}:9443${CL}" diff --git a/ct/baserow.sh b/ct/baserow.sh index fa0d044db..836ca4840 100644 --- a/ct/baserow.sh +++ b/ct/baserow.sh @@ -71,5 +71,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}" diff --git a/ct/bookorbit.sh b/ct/bookorbit.sh index 16e330e24..7b0e95c13 100644 --- a/ct/bookorbit.sh +++ b/ct/bookorbit.sh @@ -75,5 +75,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}" diff --git a/ct/clickhouse.sh b/ct/clickhouse.sh index a0e49e619..966dffa39 100644 --- a/ct/clickhouse.sh +++ b/ct/clickhouse.sh @@ -41,5 +41,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8123${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:8123${CL}" diff --git a/ct/cross-seed.sh b/ct/cross-seed.sh index a61f1274c..7970657d8 100644 --- a/ct/cross-seed.sh +++ b/ct/cross-seed.sh @@ -52,5 +52,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access cross-seed API using the following URL:${CL}" +echo -e "${INFO}${YW}Access cross-seed API using the following URL:${CL}" echo -e "${GATEWAY}${BGN}http://${IP}:2468${CL}" diff --git a/ct/cyberchef.sh b/ct/cyberchef.sh index e50d1c7b3..d698f1c86 100644 --- a/ct/cyberchef.sh +++ b/ct/cyberchef.sh @@ -26,8 +26,8 @@ function update_script() { check_container_resources if [[ ! -d /opt/cyberchef ]]; then - msg_error "No ${APP} Installation Found!" - exit + msg_error "No ${APP} Installation Found!" + exit fi if check_for_gh_release "cyberchef" "gchq/CyberChef"; then @@ -58,5 +58,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}${CL}" diff --git a/ct/etherpad.sh b/ct/etherpad.sh index f5a63852d..df7cd61bf 100755 --- a/ct/etherpad.sh +++ b/ct/etherpad.sh @@ -61,5 +61,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9001${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:9001${CL}" diff --git a/ct/excalidash.sh b/ct/excalidash.sh index 07f2f1764..09a265fcd 100644 --- a/ct/excalidash.sh +++ b/ct/excalidash.sh @@ -75,5 +75,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:6767${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:6767${CL}" diff --git a/ct/feishin.sh b/ct/feishin.sh index 4f3f8cd63..dec1ece1b 100644 --- a/ct/feishin.sh +++ b/ct/feishin.sh @@ -75,5 +75,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9180${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:9180${CL}" diff --git a/ct/flame.sh b/ct/flame.sh index 4378f4d10..c903fcc4c 100644 --- a/ct/flame.sh +++ b/ct/flame.sh @@ -36,7 +36,7 @@ function update_script() { msg_ok "Stopped Service" create_backup /opt/flame/.env \ - /opt/flame/data + /opt/flame/data CLEAN_INSTALL=1 fetch_and_deploy_gh_release "flame" "pawelmalak/flame" "tarball" restore_backup @@ -65,5 +65,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5005${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:5005${CL}" diff --git a/ct/fmd-server.sh b/ct/fmd-server.sh index 76a7bd96d..0c8b75293 100644 --- a/ct/fmd-server.sh +++ b/ct/fmd-server.sh @@ -60,5 +60,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:8443${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}https://${IP}:8443${CL}" diff --git a/ct/hev-socks5-server.sh b/ct/hev-socks5-server.sh index 3b9ffe873..b2a84616a 100644 --- a/ct/hev-socks5-server.sh +++ b/ct/hev-socks5-server.sh @@ -30,7 +30,6 @@ function update_script() { exit fi - if check_for_gh_release "hev-socks5-server" "heiher/hev-socks5-server"; then msg_info "Stopping Service" systemctl stop hev-socks5-server @@ -52,6 +51,6 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it with a SOCKS5 client using the following URL:${CL}" +echo -e "${INFO}${YW}Access it with a SOCKS5 client using the following URL:${CL}" echo -e "${GATEWAY}${BGN}${IP}:1080${CL}" echo -e "${INFO}${YW} and the credentials stored at /root/hev.creds${CL}" diff --git a/ct/iventoy.sh b/ct/iventoy.sh index 441312c11..89aac7813 100644 --- a/ct/iventoy.sh +++ b/ct/iventoy.sh @@ -52,5 +52,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:26000${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:26000${CL}" diff --git a/ct/kiwix.sh b/ct/kiwix.sh index c66803e2e..ecde55d14 100644 --- a/ct/kiwix.sh +++ b/ct/kiwix.sh @@ -37,12 +37,12 @@ function update_script() { msg_ok "Updated Package Index" CANDIDATE=$(apt-cache policy kiwix-tools | awk '/Candidate:/{print $2}') - if [[ -z "$CANDIDATE" || "$CANDIDATE" == "(none)" ]]; then + if [[ -z $CANDIDATE || $CANDIDATE == "(none)" ]]; then msg_error "No Candidate Version Found for kiwix-tools" exit fi - if [[ "$CURRENT" == "$CANDIDATE" ]]; then + if [[ $CURRENT == "$CANDIDATE" ]]; then echo "${CURRENT}" >/root/.kiwix msg_ok "Already on latest version: ${CURRENT}" exit @@ -71,5 +71,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:8080${CL}" diff --git a/ct/koffan.sh b/ct/koffan.sh index 910070c7f..ec87a32b0 100644 --- a/ct/koffan.sh +++ b/ct/koffan.sh @@ -59,5 +59,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}" diff --git a/ct/kometa.sh b/ct/kometa.sh index b0a9e0caa..965076f8c 100644 --- a/ct/kometa.sh +++ b/ct/kometa.sh @@ -83,5 +83,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access Kometa Quickstart:${CL}" +echo -e "${INFO}${YW}Access Kometa Quickstart:${CL}" echo -e "${GATEWAY}${BGN}http://${IP}:7171${CL}" diff --git a/ct/loki.sh b/ct/loki.sh index 2156eac5a..d1c6a2570 100644 --- a/ct/loki.sh +++ b/ct/loki.sh @@ -37,38 +37,38 @@ function update_script() { case $CHOICE in 1) - msg_info "Stopping Loki" - systemctl stop loki - msg_ok "Stopped Loki" + msg_info "Stopping Loki" + systemctl stop loki + msg_ok "Stopped Loki" - msg_info "Updating Loki" - $STD apt update - $STD apt install -y --only-upgrade loki - msg_ok "Updated Loki" + msg_info "Updating Loki" + $STD apt update + $STD apt install -y --only-upgrade loki + msg_ok "Updated Loki" - msg_info "Starting Loki" - systemctl start loki - msg_ok "Started Loki" - msg_ok "Updated successfully!" - exit - ;; - 2) - msg_info "Configuring Loki to listen on 0.0.0.0" - sed -i 's/http_listen_address:.*/http_listen_address: 0.0.0.0/' /etc/loki/config.yml - sed -i 's/http_listen_port:.*/http_listen_port: 3100/' /etc/loki/config.yml - systemctl restart loki - msg_ok "Configured Loki to listen on 0.0.0.0" - exit - ;; - 3) - msg_info "Configuring Loki to listen on ${LOCAL_IP}" - sed -i "s/http_listen_address:.*/http_listen_address: $LOCAL_IP/" /etc/loki/config.yml - sed -i 's/http_listen_port:.*/http_listen_port: 3100/' /etc/loki/config.yml - systemctl restart loki - msg_ok "Configured Loki to listen on ${LOCAL_IP}" - exit - ;; - esac + msg_info "Starting Loki" + systemctl start loki + msg_ok "Started Loki" + msg_ok "Updated successfully!" + exit + ;; + 2) + msg_info "Configuring Loki to listen on 0.0.0.0" + sed -i 's/http_listen_address:.*/http_listen_address: 0.0.0.0/' /etc/loki/config.yml + sed -i 's/http_listen_port:.*/http_listen_port: 3100/' /etc/loki/config.yml + systemctl restart loki + msg_ok "Configured Loki to listen on 0.0.0.0" + exit + ;; + 3) + msg_info "Configuring Loki to listen on ${LOCAL_IP}" + sed -i "s/http_listen_address:.*/http_listen_address: $LOCAL_IP/" /etc/loki/config.yml + sed -i 's/http_listen_port:.*/http_listen_port: 3100/' /etc/loki/config.yml + systemctl restart loki + msg_ok "Configured Loki to listen on ${LOCAL_IP}" + exit + ;; + esac exit 0 } @@ -78,5 +78,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access loki using the following URL:${CL}" +echo -e "${INFO}${YW}Access loki using the following URL:${CL}" echo -e "${GATEWAY}${BGN}http://${IP}:3100${CL}\n" diff --git a/ct/lyrionmusicserver.sh b/ct/lyrionmusicserver.sh index 8ef432b93..b14d0d791 100644 --- a/ct/lyrionmusicserver.sh +++ b/ct/lyrionmusicserver.sh @@ -35,7 +35,7 @@ function update_script() { DEB_URL=$(curl_with_retry 'https://lyrion.org/getting-started/' | grep -oP "]*href=\"\K[^\"]*${DEB_ARCH}\.deb(?=\"[^>]*>)" | head -n 1) RELEASE=$(echo "$DEB_URL" | grep -oP "lyrionmusicserver_\K[0-9.]+(?=_${DEB_ARCH}\.deb)") DEB_FILE="/tmp/lyrionmusicserver_${RELEASE}_${DEB_ARCH}.deb" - if [[ ! -f /opt/lyrion_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/lyrion_version.txt)" ]]; then + if [[ ! -f /opt/lyrion_version.txt ]] || [[ ${RELEASE} != "$(cat /opt/lyrion_version.txt)" ]]; then msg_info "Updating $APP to ${RELEASE}" curl_with_retry "$DEB_URL" "$DEB_FILE" $STD apt install "$DEB_FILE" -y @@ -56,5 +56,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access the web interface at:${CL}" +echo -e "${INFO}${YW}Access the web interface at:${CL}" echo -e "${GATEWAY}${BGN}http://${IP}:9000${CL}" diff --git a/ct/matterjs-server.sh b/ct/matterjs-server.sh index 65d53f5f5..0904c4974 100644 --- a/ct/matterjs-server.sh +++ b/ct/matterjs-server.sh @@ -31,10 +31,10 @@ function update_script() { fi NODE_VERSION="24" setup_nodejs - + CURRENT=$(cat /opt/matter-server/node_modules/matter-server/package.json | grep '"version"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/') LATEST=$(npm view matter-server version 2>/dev/null) - if [[ "$CURRENT" != "$LATEST" ]]; then + if [[ $CURRENT != "$LATEST" ]]; then msg_info "Stopping Service" systemctl stop matterjs-server msg_ok "Stopped Service" @@ -60,5 +60,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5580${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:5580${CL}" diff --git a/ct/netbird.sh b/ct/netbird.sh index 336094791..8359805be 100644 --- a/ct/netbird.sh +++ b/ct/netbird.sh @@ -44,5 +44,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access NetBird by entering the container and running:${CL}" +echo -e "${INFO}${YW}Access NetBird by entering the container and running:${CL}" echo -e "${GATEWAY}${BGN}netbird up${CL}" diff --git a/ct/paperclip.sh b/ct/paperclip.sh index e7c1f5101..10c27de23 100644 --- a/ct/paperclip.sh +++ b/ct/paperclip.sh @@ -79,5 +79,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3100${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:3100${CL}" diff --git a/ct/pinchflat.sh b/ct/pinchflat.sh index 7b696dd41..c930b741a 100644 --- a/ct/pinchflat.sh +++ b/ct/pinchflat.sh @@ -66,5 +66,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8945${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:8945${CL}" diff --git a/ct/plane.sh b/ct/plane.sh index 13c29969c..0d8d9f6c9 100644 --- a/ct/plane.sh +++ b/ct/plane.sh @@ -38,10 +38,10 @@ function update_script() { msg_ok "Stopped Services" create_backup /opt/plane/.env \ - /opt/plane/apps/admin/.env \ - /opt/plane/apps/api/.env \ - /opt/plane/apps/space/.env \ - /opt/plane/apps/web/.env + /opt/plane/apps/admin/.env \ + /opt/plane/apps/api/.env \ + /opt/plane/apps/space/.env \ + /opt/plane/apps/web/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "plane" "makeplane/plane" "tarball" @@ -86,5 +86,5 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}${CL}" diff --git a/ct/postiz.sh b/ct/postiz.sh index cdfbc51b2..dc004abb5 100644 --- a/ct/postiz.sh +++ b/ct/postiz.sh @@ -37,7 +37,7 @@ function update_script() { msg_ok "Stopped Services" create_backup /opt/postiz/.env \ - /opt/postiz/uploads + /opt/postiz/uploads CLEAN_INSTALL=1 fetch_and_deploy_gh_release "postiz" "gitroomhq/postiz-app" "tarball" @@ -56,7 +56,6 @@ function update_script() { $STD pnpm run prisma-db-push msg_ok "Ran Database Migrations" - mkdir -p /opt/postiz/uploads restore_backup @@ -74,5 +73,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}${CL}" diff --git a/ct/rackula.sh b/ct/rackula.sh index 74f453c55..c0b15a9b9 100755 --- a/ct/rackula.sh +++ b/ct/rackula.sh @@ -77,5 +77,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}${CL}" diff --git a/ct/shlink.sh b/ct/shlink.sh index 0d6a210dd..a9238fe49 100644 --- a/ct/shlink.sh +++ b/ct/shlink.sh @@ -80,7 +80,7 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access Shlink Web Client using the following URL:${CL}" +echo -e "${INFO}${YW}Access Shlink Web Client using the following URL:${CL}" echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}" echo -e "${INFO}${YW} Shlink HTTP API:${CL}" echo -e "${GATEWAY}${BGN}http://${IP}:8080${CL}" diff --git a/ct/snapotter.sh b/ct/snapotter.sh index 86671ab42..2ebea2959 100644 --- a/ct/snapotter.sh +++ b/ct/snapotter.sh @@ -59,5 +59,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:1349${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:1349${CL}" diff --git a/ct/spliit.sh b/ct/spliit.sh index 33076cd42..d039b75d9 100755 --- a/ct/spliit.sh +++ b/ct/spliit.sh @@ -72,5 +72,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}" diff --git a/ct/tolgee.sh b/ct/tolgee.sh index fab3dc278..4455852ff 100644 --- a/ct/tolgee.sh +++ b/ct/tolgee.sh @@ -52,5 +52,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:8080${CL}" diff --git a/ct/twenty.sh b/ct/twenty.sh index 0b212ef0f..e1e9e35d3 100644 --- a/ct/twenty.sh +++ b/ct/twenty.sh @@ -39,10 +39,10 @@ function update_script() { msg_ok "Stopped Services" create_backup /opt/twenty/.env \ - /opt/twenty/packages/twenty-server/.local-storage + /opt/twenty/packages/twenty-server/.local-storage CLEAN_INSTALL=1 fetch_and_deploy_gh_release "twenty" "twentyhq/twenty" "tarball" restore_backup - + msg_info "Building Application" cd /opt/twenty export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 @@ -63,7 +63,6 @@ function update_script() { $STD npx -y typeorm migration:run -d dist/database/typeorm/core/core.datasource msg_ok "Ran Database Migrations" - msg_info "Starting Services" systemctl start twenty-server twenty-worker msg_ok "Started Services" @@ -78,5 +77,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}" diff --git a/ct/xyops.sh b/ct/xyops.sh index 61f641119..2768a39ae 100644 --- a/ct/xyops.sh +++ b/ct/xyops.sh @@ -69,5 +69,5 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5522${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:5522${CL}" From 7a9726b1dda667f79bb83235b36979754588c1e4 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 19:15:29 +0000 Subject: [PATCH 040/245] Update CHANGELOG.md (#15633) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c67f8c59a..00a310fea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -503,7 +503,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🚀 Updated Scripts - - Immich: Update libvips to 8.18.4 [@vhsdream](https://github.com/vhsdream) ([#15619](https://github.com/community-scripts/ProxmoxVE/pull/15619)) + - Fix alignment in various ct end messages [@tremor021](https://github.com/tremor021) ([#15632](https://github.com/community-scripts/ProxmoxVE/pull/15632)) +- Immich: Update libvips to 8.18.4 [@vhsdream](https://github.com/vhsdream) ([#15619](https://github.com/community-scripts/ProxmoxVE/pull/15619)) - #### 🐞 Bug Fixes From d9d724ce57bc7721b724187cb530b71e1b2659da Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 6 Jul 2026 23:27:42 +0200 Subject: [PATCH 041/245] Remove: FlowiseAI (#15624) --- ct/flowiseai.sh | 54 ------------------------------------ install/flowiseai-install.sh | 52 ---------------------------------- 2 files changed, 106 deletions(-) delete mode 100644 ct/flowiseai.sh delete mode 100644 install/flowiseai-install.sh diff --git a/ct/flowiseai.sh b/ct/flowiseai.sh deleted file mode 100644 index 7d4c6468e..000000000 --- a/ct/flowiseai.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash -source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) -# Copyright (c) 2021-2026 tteck -# Author: tteck (tteckster) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://flowiseai.com/ | Github: https://github.com/FlowiseAI/Flowise - -APP="FlowiseAI" -var_tags="${var_tags:-low-code}" -var_disk="${var_disk:-10}" -var_cpu="${var_cpu:-4}" -var_ram="${var_ram:-4096}" -var_os="${var_os:-debian}" -var_version="${var_version:-13}" -var_arm64="${var_arm64:-yes}" -var_unprivileged="${var_unprivileged:-1}" - -header_info "$APP" -variables -color -catch_errors - -function update_script() { - header_info - check_container_storage - check_container_resources - if [[ ! -f /etc/systemd/system/flowise.service ]]; then - msg_error "No ${APP} Installation Found!" - exit - fi - - NODE_VERSION="22" NODE_MODULE="pnpm" setup_nodejs - - msg_info "Updating FlowiseAI (this may take some time)" - systemctl stop flowise - $STD pnpm add -g flowise - if grep -q 'ExecStart=npx flowise start' /etc/systemd/system/flowise.service; then - sed -i 's|ExecStart=npx flowise start|ExecStart=flowise start|' /etc/systemd/system/flowise.service - systemctl daemon-reload - fi - systemctl start flowise - msg_ok "Updated FlowiseAI" - msg_ok "Updated successfully!" - exit -} - -start -build_container -description - -msg_ok "Completed successfully!\n" -echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW}Access it using the following URL:${CL}" -echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}" diff --git a/install/flowiseai-install.sh b/install/flowiseai-install.sh deleted file mode 100644 index 73cc8c1eb..000000000 --- a/install/flowiseai-install.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (c) 2021-2026 tteck -# Author: tteck (tteckster) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://flowiseai.com/ | Github: https://github.com/FlowiseAI/Flowise - -source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" -color -verb_ip6 -catch_errors -setting_up_container -network_check -update_os - -msg_info "Installing Dependencies" -$STD apt install -y \ - build-essential \ - pkg-config -msg_ok "Installed Dependencies" - -PYTHON_VERSION="3.11" setup_uv -NODE_VERSION="22" NODE_MODULE="pnpm" setup_nodejs - -msg_info "Installing FlowiseAI (Patience)" -PYTHON_BIN="$(uv python find 3.11)" -export npm_config_python="$PYTHON_BIN" -$STD pnpm add -g flowise -mkdir -p /opt/flowiseai -curl -fsSL "https://raw.githubusercontent.com/FlowiseAI/Flowise/main/packages/server/.env.example" -o "/opt/flowiseai/.env" -msg_ok "Installed FlowiseAI" - -msg_info "Creating Service" -cat </etc/systemd/system/flowise.service -[Unit] -Description=FlowiseAI -After=network.target - -[Service] -EnvironmentFile=/opt/flowiseai/.env -ExecStart=flowise start -Restart=always - -[Install] -WantedBy=multi-user.target -EOF -systemctl enable -q --now flowise -msg_ok "Created Service" - -motd_ssh -customize -cleanup_lxc From 3143d25caa9eb55d89f2bcd51cde6eeec8a36be9 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 21:28:09 +0000 Subject: [PATCH 042/245] Update CHANGELOG.md (#15637) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00a310fea..237f4f130 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -516,6 +516,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - cliproxyapi: point setup message at /management.html [@austinpilz](https://github.com/austinpilz) ([#15628](https://github.com/community-scripts/ProxmoxVE/pull/15628)) +### 🗑️ Deleted Scripts + + - Remove: FlowiseAI [@MickLesk](https://github.com/MickLesk) ([#15624](https://github.com/community-scripts/ProxmoxVE/pull/15624)) + ## 2026-07-05 ### 🆕 New Scripts From 2bf6c5e5da85d5208db396340bececa0e476000a Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 6 Jul 2026 17:28:48 -0400 Subject: [PATCH 043/245] Wizarr: Build JS and CSS static assets (#15634) --- ct/wizarr.sh | 34 ++++++++++++++++++++++++++-------- install/wizarr-install.sh | 12 ++++++++---- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/ct/wizarr.sh b/ct/wizarr.sh index febc1e4c3..af6a2adac 100644 --- a/ct/wizarr.sh +++ b/ct/wizarr.sh @@ -50,20 +50,38 @@ function update_script() { $STD /usr/local/bin/uv sync --frozen $STD /usr/local/bin/uv run --frozen pybabel compile -d app/translations $STD npm --prefix app/static install - $STD npm --prefix app/static run build:css + $STD npm --prefix app/static run build mkdir -p ./.cache $STD tar -xf "$BACKUP_FILE" --directory=/ - if grep -q 'workers' /opt/wizarr/start.sh; then - sed -i 's/--workers 4//' /opt/wizarr/start.sh + if grep -q 'bind' /opt/wizarr/start.sh; then + WIZARR_PORT=$(awk -F: '{print $2}' /opt/wizarr/start.sh | awk -F' ' '{print $1}' | tr -d '[:space:]') fi - if ! grep -qE 'FLASK|WORKERS|VERSION' /opt/wizarr/.env; then - cat </opt/wizarr/.env + sed -i -E -e 's/[[:space:]]+/ /g' \ + -e 's/--workers 4//' \ + -e 's/--bind 0.0.0.0:[0-9]+//' /opt/wizarr/start.sh + KEYS=("FLASK" "WORKERS" "HOST" "PORT") + for key in "${KEYS[@]}"; do + if ! grep -q "$key" /opt/wizarr/.env; then + cat </opt/wizarr/.env +APP_URL=http://${LOCAL_IP} +DISABLE_BUILTIN_AUTH=false FLASK_ENV=production GUNICORN_WORKERS=4 -APP_VERSION=$(sed 's/^20/v&/' ~/.wizarr) +HOST=0.0.0.0 +PORT=${WIZARR_PORT:-5690} +LOG_LEVEL=info +APP_VERSION=$(cat ~/.wizarr) EOF - else - sed -i "s/_VERSION=v.*$/_VERSION=v$(cat ~/.wizarr)/" /opt/wizarr/.env + fi + continue + done + sed -i "s/_VERSION=.*$/_VERSION=$(cat ~/.wizarr)/" /opt/wizarr/.env + if grep -q 'abnormal' /etc/systemd/system/wizarr.service; then + sed -i 's/on-abnormal/always \ +RestartSec=10 \ +KillMode=mixed \ +TimeoutStopSec=10/' /etc/systemd/system/wizarr.service + systemctl daemon-reload fi rm -rf "$BACKUP_FILE" export FLASK_SKIP_SCHEDULER=true diff --git a/install/wizarr-install.sh b/install/wizarr-install.sh index 57a152d11..ba6bca712 100644 --- a/install/wizarr-install.sh +++ b/install/wizarr-install.sh @@ -27,15 +27,17 @@ cd /opt/wizarr $STD /usr/local/bin/uv sync --frozen $STD /usr/local/bin/uv run --frozen pybabel compile -d app/translations $STD npm --prefix app/static install -$STD npm --prefix app/static run build:css +$STD npm --prefix app/static run build mkdir -p ./.cache cat </opt/wizarr/.env FLASK_ENV=production GUNICORN_WORKERS=4 APP_URL=http://${LOCAL_IP} +HOST=0.0.0.0 +PORT=5690 DISABLE_BUILTIN_AUTH=false LOG_LEVEL=INFO -APP_VERSION=v$(get_latest_github_release "wizarrrr/wizarr") +APP_VERSION=$(get_latest_github_release "wizarrrr/wizarr") EOF cat </opt/wizarr/start.sh @@ -44,7 +46,6 @@ cat </opt/wizarr/start.sh uv run --frozen gunicorn \ --config gunicorn.conf.py \ --preload \ - --bind 0.0.0.0:5690 \ --umask 007 \ run:app EOF @@ -62,7 +63,10 @@ Type=simple WorkingDirectory=/opt/wizarr EnvironmentFile=/opt/wizarr/.env ExecStart=/opt/wizarr/start.sh -Restart=on-abnormal +Restart=always +RestartSec=10 +KillMode=mixed +TimeoutStopSec=10 [Install] WantedBy=multi-user.target From a9d71b7d234f532843511e574337f9be030bfd91 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 21:29:10 +0000 Subject: [PATCH 044/245] Update CHANGELOG.md (#15638) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 237f4f130..420ba6fb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -508,6 +508,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - Wizarr: Build JS and CSS static assets [@vhsdream](https://github.com/vhsdream) ([#15634](https://github.com/community-scripts/ProxmoxVE/pull/15634)) - RustDesk Server: Update URL format in rustdeskserver.sh [@tremor021](https://github.com/tremor021) ([#15626](https://github.com/community-scripts/ProxmoxVE/pull/15626)) - attempt to port docker-vm to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15611](https://github.com/community-scripts/ProxmoxVE/pull/15611)) - fix(plane): don't clobber global app var, breaking /usr/bin/update [@asylumexp](https://github.com/asylumexp) ([#15612](https://github.com/community-scripts/ProxmoxVE/pull/15612)) From 87f2189cbb5b73c9c2204a292fd06efa465b0824 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 23:47:06 +0200 Subject: [PATCH 045/245] Update .app files (#15636) Co-authored-by: GitHub Actions --- ct/headers/flowiseai | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 ct/headers/flowiseai diff --git a/ct/headers/flowiseai b/ct/headers/flowiseai deleted file mode 100644 index 7011f22b4..000000000 --- a/ct/headers/flowiseai +++ /dev/null @@ -1,6 +0,0 @@ - ________ _ ___ ____ - / ____/ /___ _ __(_)_______ / | / _/ - / /_ / / __ \ | /| / / / ___/ _ \/ /| | / / - / __/ / / /_/ / |/ |/ / (__ ) __/ ___ |_/ / -/_/ /_/\____/|__/|__/_/____/\___/_/ |_/___/ - From 67e0c7e9f83fda92c2b5516626a495e90fe9536b Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2026 22:45:52 +0200 Subject: [PATCH 046/245] Forgejo-Runner (#15046) --- ct/forgejo-runner.sh | 79 +++++++++++++++++++++ ct/headers/forgejo-runner | 6 ++ install/forgejo-runner-install.sh | 114 ++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 ct/forgejo-runner.sh create mode 100644 ct/headers/forgejo-runner create mode 100644 install/forgejo-runner-install.sh diff --git a/ct/forgejo-runner.sh b/ct/forgejo-runner.sh new file mode 100644 index 000000000..7c7c1774f --- /dev/null +++ b/ct/forgejo-runner.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Simon Friedrich (lengschder97) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://forgejo.org/ + +APP="Forgejo-Runner" +var_tags="${var_tags:-ci}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-8}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +var_unprivileged="${var_unprivileged:-1}" +var_nesting="${var_nesting:-1}" +var_keyctl="${var_keyctl:-1}" + +export var_forgejo_instance="${var_forgejo_instance:-}" +export var_forgejo_runner_token="${var_forgejo_runner_token:-}" +export var_runner_labels="${var_runner_labels:-}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -f /usr/local/bin/forgejo-runner ]]; then + msg_error "No ${APP} installation found!" + exit 1 + fi + + RELEASE=$(curl -fsSL https://data.forgejo.org/api/v1/repos/forgejo/runner/releases/latest | grep -oP '"tag_name":\s*"\K[^"]+' | sed 's/^v//') + if [[ "${RELEASE}" == "$(cat ~/.forgejo-runner 2>/dev/null)" ]]; then + msg_ok "No update required. ${APP} is already at v${RELEASE}" + exit + fi + + msg_info "Stopping Services" + systemctl stop forgejo-runner + msg_ok "Stopped Services" + + msg_info "Updating Forgejo Runner to v${RELEASE}" + curl -fsSL "https://code.forgejo.org/forgejo/runner/releases/download/v${RELEASE}/forgejo-runner-${RELEASE}-linux-$(arch_resolve)" -o /usr/local/bin/forgejo-runner + chmod +x /usr/local/bin/forgejo-runner + echo "${RELEASE}" >~/.forgejo-runner + msg_ok "Updated Forgejo Runner" + + msg_info "Starting Services" + systemctl start forgejo-runner + msg_ok "Started Services" + msg_ok "Updated successfully!" + exit +} + +if [[ -n "${mode:-}" ]]; then + if [[ -z "${var_forgejo_instance:-}" ]]; then + msg_error "var_forgejo_instance is required for unattended installs." + exit 1 + fi + if [[ -z "${var_forgejo_runner_token:-}" ]]; then + msg_error "var_forgejo_runner_token is required for unattended installs." + exit 1 + fi +fi + +start +build_container +description + +msg_ok "Completed successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} After first boot, check your Forgejo Instance for the new Runner.${CL}" diff --git a/ct/headers/forgejo-runner b/ct/headers/forgejo-runner new file mode 100644 index 000000000..5be4a07fe --- /dev/null +++ b/ct/headers/forgejo-runner @@ -0,0 +1,6 @@ + ______ _ ____ + / ____/___ _________ ____ (_)___ / __ \__ ______ ____ ___ _____ + / /_ / __ \/ ___/ __ `/ _ \ / / __ \______/ /_/ / / / / __ \/ __ \/ _ \/ ___/ + / __/ / /_/ / / / /_/ / __/ / / /_/ /_____/ _, _/ /_/ / / / / / / / __/ / +/_/ \____/_/ \__, /\___/_/ /\____/ /_/ |_|\__,_/_/ /_/_/ /_/\___/_/ + /____/ /___/ diff --git a/install/forgejo-runner-install.sh b/install/forgejo-runner-install.sh new file mode 100644 index 000000000..94ceb6877 --- /dev/null +++ b/install/forgejo-runner-install.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Simon Friedrich (lengschder97) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://forgejo.org/ + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +setup_yq + +if [[ -z "${var_forgejo_instance:-}" ]]; then + read -r -p "${TAB3}Forgejo Instance URL (e.g. https://codeberg.org): " var_forgejo_instance + var_forgejo_instance="${var_forgejo_instance:-https://codeberg.org}" +fi + +if [[ -z "${var_forgejo_runner_uuid:-}" ]]; then + read -r -p "${TAB3}Forgejo Runner UUID: " var_forgejo_runner_uuid +fi + +if [[ -z "${var_forgejo_runner_uuid:-}" ]]; then + msg_error "No runner UUID provided. Cannot continue." + exit 1 +fi + +if [[ -z "${var_forgejo_runner_token:-}" ]]; then + read -r -p "${TAB3}Forgejo Runner Token: " var_forgejo_runner_token +fi + +if [[ -z "${var_forgejo_runner_token:-}" ]]; then + msg_error "No runner registration token provided. Cannot continue." + exit 1 +fi + +DEFAULT_RUNNER_LABELS="linux-amd64:docker://node:22-bookworm" +if [[ -z "${var_runner_labels:-}" ]]; then + read -r -p "${TAB3}Additional runner labels (comma-separated, or leave blank for default only): " var_runner_labels +fi +if [[ -n "${var_runner_labels:-}" ]]; then + RUNNER_LABELS="${DEFAULT_RUNNER_LABELS},${var_runner_labels}" +else + RUNNER_LABELS="${DEFAULT_RUNNER_LABELS}" +fi + +export FORGEJO_INSTANCE="$var_forgejo_instance" +export FORGEJO_RUNNER_TOKEN="$var_forgejo_runner_token" +export FORGEJO_RUNNER_UUID="$var_forgejo_runner_uuid" +export RUNNER_LABELS + +msg_info "Installing dependencies" +$STD apt install -y \ + git \ + podman podman-docker +msg_ok "Installed dependencies" + +msg_info "Enabling Podman socket" +systemctl enable --now podman.socket +msg_ok "Enabled Podman socket" + +msg_info "Installing Forgejo Runner" +RUNNER_VERSION=$(curl -fsSL https://data.forgejo.org/api/v1/repos/forgejo/runner/releases/latest | jq -r .name | sed 's/^v//') +curl -fsSL "https://code.forgejo.org/forgejo/runner/releases/download/v${RUNNER_VERSION}/forgejo-runner-${RUNNER_VERSION}-linux-$(arch_resolve)" -o /usr/local/bin/forgejo-runner +chmod +x /usr/local/bin/forgejo-runner +echo "${RUNNER_VERSION}" >~/.forgejo-runner +msg_ok "Installed Forgejo Runner" + +msg_info "Registering Forgejo Runner" +export DOCKER_HOST="unix:///run/podman/podman.sock" + +msg_info "Generating Forgejo Runner Configuration" +mkdir -p /etc/forgejo-runner +CONFIG_FILE="/etc/forgejo-runner/config.yaml" +forgejo-runner generate-config > $CONFIG_FILE +yq -i ' + .container.docker_host = strenv(DOCKER_HOST) | + .server.connections.forgejo.url = strenv(FORGEJO_INSTANCE) | + .server.connections.forgejo.uuid = strenv(FORGEJO_RUNNER_UUID) | + .server.connections.forgejo.token = strenv(FORGEJO_RUNNER_TOKEN) | + .server.connections.forgejo.labels = (strenv(RUNNER_LABELS) | split(",") | map(select(length > 0))) + ' $CONFIG_FILE +msg_ok "Generated Forgejo Runner Configuration" + + +msg_info "Creating Services" +cat </etc/systemd/system/forgejo-runner.service +[Unit] +Description=Forgejo Runner +Documentation=https://forgejo.org/docs/latest/admin/actions/ +After=podman.socket +Requires=podman.socket + +[Service] +User=root +WorkingDirectory=/root +Environment=DOCKER_HOST=unix:///run/podman/podman.sock +ExecStart=/usr/local/bin/forgejo-runner daemon -c $CONFIG_FILE +Restart=on-failure +RestartSec=10 +TimeoutSec=0 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now forgejo-runner +msg_ok "Created Services" + +motd_ssh +customize +cleanup_lxc From e64f5a041d136545e9879d30e13cb360a0f98ba4 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2026 20:46:17 +0000 Subject: [PATCH 047/245] Update CHANGELOG.md (#15644) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 420ba6fb2..2dabf3bbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -499,6 +499,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-07 + +### 🆕 New Scripts + + - Forgejo-Runner ([#15046](https://github.com/community-scripts/ProxmoxVE/pull/15046)) + ## 2026-07-06 ### 🚀 Updated Scripts From 6e55269d9fdab34fc774839e93903b383816e79b Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Wed, 8 Jul 2026 13:04:13 +0200 Subject: [PATCH 048/245] BabyBuddy: Harden update script (#15642) Ensure cleanup runs from `/opt/babybuddy` before deleting old files, add `--` to the removal command for safer argument handling, and run `manage.py makemigrations` before `migrate` so database updates are applied reliably during upgrades. --- ct/babybuddy.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ct/babybuddy.sh b/ct/babybuddy.sh index 29fc7703a..b718a42ef 100644 --- a/ct/babybuddy.sh +++ b/ct/babybuddy.sh @@ -40,7 +40,8 @@ function update_script() { create_backup /opt/babybuddy/babybuddy/settings/production.py msg_info "Cleaning old files" - find . -mindepth 1 -maxdepth 1 ! -name '.venv' -exec rm -rf {} + + cd /opt/babybuddy || exit + find . -mindepth 1 -maxdepth 1 ! -name '.venv' -exec rm -rf -- {} + msg_ok "Cleaned old files" fetch_and_deploy_gh_release "babybuddy" "babybuddy/babybuddy" "tarball" @@ -51,6 +52,7 @@ function update_script() { source .venv/bin/activate $STD uv pip install -r requirements.txt export DJANGO_SETTINGS_MODULE=babybuddy.settings.production + $STD python manage.py makemigrations $STD python manage.py migrate msg_ok "Updated ${APP}" From a6a8651000b252c5f7a80fea5b6e3aa63475339b Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 11:04:41 +0000 Subject: [PATCH 049/245] Update CHANGELOG.md (#15647) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dabf3bbe..6b39405fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -499,6 +499,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-08 + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - BabyBuddy: Harden update script [@MickLesk](https://github.com/MickLesk) ([#15642](https://github.com/community-scripts/ProxmoxVE/pull/15642)) + ## 2026-07-07 ### 🆕 New Scripts From 11937bf5fa8bcb2631907389c301b36c7675db4f Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 8 Jul 2026 18:56:59 -0400 Subject: [PATCH 050/245] Opencloud: Bump version to 7.2.1 (#15655) --- ct/opencloud.sh | 2 +- install/opencloud-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/opencloud.sh b/ct/opencloud.sh index b64dc34d0..b328d90ab 100644 --- a/ct/opencloud.sh +++ b/ct/opencloud.sh @@ -30,7 +30,7 @@ function update_script() { exit fi - RELEASE="v7.2.0" + RELEASE="v7.2.1" if check_for_gh_release "OpenCloud" "opencloud-eu/opencloud" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then msg_info "Stopping services" systemctl stop opencloud opencloud-wopi diff --git a/install/opencloud-install.sh b/install/opencloud-install.sh index 608440062..0dc635098 100644 --- a/install/opencloud-install.sh +++ b/install/opencloud-install.sh @@ -64,7 +64,7 @@ $STD sudo -u cool coolconfig set-admin-password --user=admin --password="$COOLPA echo "$COOLPASS" >~/.coolpass msg_ok "Installed Collabora Online" -fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v7.2.0" "/usr/bin" "opencloud-*-linux-$(arch_resolve)" +fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v7.2.1" "/usr/bin" "opencloud-*-linux-$(arch_resolve)" mv /usr/bin/OpenCloud /usr/bin/opencloud msg_info "Configuring OpenCloud" From f1adfc32d30d85529412e80def20e23f0f1e856a Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 22:57:24 +0000 Subject: [PATCH 051/245] Update CHANGELOG.md (#15657) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b39405fe..b5e9bda8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -505,6 +505,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - Opencloud: Bump version to 7.2.1 [@vhsdream](https://github.com/vhsdream) ([#15655](https://github.com/community-scripts/ProxmoxVE/pull/15655)) - BabyBuddy: Harden update script [@MickLesk](https://github.com/MickLesk) ([#15642](https://github.com/community-scripts/ProxmoxVE/pull/15642)) ## 2026-07-07 From bfab0dd034bd182034f1ffb05e45018ec9c85373 Mon Sep 17 00:00:00 2001 From: TowyTowy <85077986+TowyTowy@users.noreply.github.com> Date: Thu, 9 Jul 2026 03:28:40 +0200 Subject: [PATCH 052/245] fix(pihole): repair Unbound DNS-over-TLS (DoT) forwarding config (#15654) When the optional Unbound install is chosen with DoT forwarding, the script truncated (>) /etc/unbound/unbound.conf.d/pi-hole.conf and rewrote it starting with an indented "tls-cert-bundle:" option that has no "server:" section header. unbound-checkconf rejects this ("syntax error, is there no section start"), so "systemctl restart unbound" exits 1 and the install aborts (line 153). The overwrite also dropped the interface/port 5335 settings Pi-hole forwards to. Append (>>) the DoT additions to the existing recursive server block instead, under a proper "server:" section (unbound merges multiple server: clauses), so the tls-cert-bundle and forward-zone are valid and the resolver keeps listening on 127.0.0.1:5335. Recursive (non-DoT) mode is unchanged. Co-authored-by: Claude Fable 5 --- install/pihole-install.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/install/pihole-install.sh b/install/pihole-install.sh index c88a7c997..547d79f23 100644 --- a/install/pihole-install.sh +++ b/install/pihole-install.sh @@ -119,7 +119,8 @@ edns-packet-max=1232 EOF if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then - cat </etc/unbound/unbound.conf.d/pi-hole.conf + cat <>/etc/unbound/unbound.conf.d/pi-hole.conf +server: tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt" forward-zone: name: "." From 25045ef344386fe5855ed2ea19c89f0d03e452b3 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Thu, 9 Jul 2026 01:29:01 +0000 Subject: [PATCH 053/245] Update CHANGELOG.md (#15659) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5e9bda8c..25dc2426a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -499,6 +499,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-09 + +### 🚀 Updated Scripts + + - fix(pihole): repair Unbound DNS-over-TLS (DoT) forwarding config [@TowyTowy](https://github.com/TowyTowy) ([#15654](https://github.com/community-scripts/ProxmoxVE/pull/15654)) + ## 2026-07-08 ### 🚀 Updated Scripts From 89b671880a752c0e7c8cba029bd12d9e4f200f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Slavi=C5=A1a=20Are=C5=BEina?= <58952836+tremor021@users.noreply.github.com> Date: Fri, 10 Jul 2026 10:53:04 +0200 Subject: [PATCH 054/245] Endurain: Fix update procedure (#15674) * Update CHANGELOG.md (#15631) Co-authored-by: github-actions[bot] * Update CHANGELOG.md (#15631) Co-authored-by: github-actions[bot] * Update CHANGELOG.md (#15631) Co-authored-by: github-actions[bot] * Fixed update procedure * ups --------- Co-authored-by: community-scripts-pr-app[bot] <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] --- ct/endurain.sh | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/ct/endurain.sh b/ct/endurain.sh index 934532aea..cdfd6eb0a 100644 --- a/ct/endurain.sh +++ b/ct/endurain.sh @@ -34,31 +34,22 @@ function update_script() { systemctl stop endurain msg_ok "Stopped Service" - msg_info "Creating Backup" - cp /opt/endurain/.env /opt/endurain.env - cp /opt/endurain/frontend/dist/env.js /opt/endurain.env.js - msg_ok "Created Backup" - + create_backup /opt/endurain/.env /opt/endurain/frontend/dist/env.js CLEAN_INSTALL=1 fetch_and_deploy_codeberg_release "endurain" "endurain-project/endurain" "tarball" "latest" "/opt/endurain" msg_info "Preparing Update" cd /opt/endurain - rm -rf \ - /opt/endurain/{docs,example.env,screenshot_01.png} \ - /opt/endurain/docker* \ - /opt/endurain/*.yml - cp /opt/endurain.env /opt/endurain/.env - rm /opt/endurain.env + rm -rf /opt/endurain/{docs,example.env,screenshot_01.png} /opt/endurain/docker* /opt/endurain/*.yml msg_ok "Prepared Update" msg_info "Updating Frontend" cd /opt/endurain/frontend $STD npm ci $STD npm run build - cp /opt/endurain.env.js /opt/endurain/frontend/dist/env.js - rm /opt/endurain.env.js msg_ok "Updated Frontend" + restore_backup + msg_info "Updating Backend" cd /opt/endurain/backend UV_VERSION=$(grep -Po 'required-version\s*=\s*"\K[^"]+' pyproject.toml 2>/dev/null || echo "0.11.18") From f1e952005ebcef591859b4d04686b72fe984e92d Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 08:53:34 +0000 Subject: [PATCH 055/245] Update CHANGELOG.md (#15678) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25dc2426a..62e82d39c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -499,6 +499,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-10 + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - Endurain: Fix update procedure [@tremor021](https://github.com/tremor021) ([#15674](https://github.com/community-scripts/ProxmoxVE/pull/15674)) + ## 2026-07-09 ### 🚀 Updated Scripts From 6716d8de842c5a0507f08c111f6d3c9a7bc11729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Slavi=C5=A1a=20Are=C5=BEina?= <58952836+tremor021@users.noreply.github.com> Date: Fri, 10 Jul 2026 10:53:51 +0200 Subject: [PATCH 056/245] Fireshare: Fix for install and upgrade to v1.7.3 (#15673) * Update CHANGELOG.md (#15631) Co-authored-by: github-actions[bot] * Update CHANGELOG.md (#15631) Co-authored-by: github-actions[bot] * Update CHANGELOG.md (#15631) Co-authored-by: github-actions[bot] * Fix install and upgrade to v1.7.3 --------- Co-authored-by: community-scripts-pr-app[bot] <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] --- ct/fireshare.sh | 21 ++++++++++++++------- install/fireshare-install.sh | 3 +++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/ct/fireshare.sh b/ct/fireshare.sh index 296cb6c01..f10be013b 100644 --- a/ct/fireshare.sh +++ b/ct/fireshare.sh @@ -35,12 +35,22 @@ function update_script() { systemctl stop fireshare msg_ok "Stopped Service" - mv /opt/fireshare/fireshare.env /opt + create_backup /opt/fireshare/fireshare.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "fireshare" "ShaneIsrael/fireshare" "tarball" - mv /opt/fireshare.env /opt/fireshare + restore_backup rm -f /usr/local/bin/fireshare - msg_info "Updating Fireshare" + if ! grep -q "__FIRESHARE_PORT__" /etc/nginx/nginx.conf; then + cp /opt/fireshare/app/nginx/prod.conf /etc/nginx/nginx.conf + sed -i 's|root /processed/|root /opt/fireshare-processed/|g' /etc/nginx/nginx.conf + sed -i 's/^user[[:space:]]\+nginx;/user root;/' /etc/nginx/nginx.conf + sed -i 's|root[[:space:]]\+/app/build;|root /opt/fireshare/app/client/build;|' /etc/nginx/nginx.conf + sed -i 's/__FIRESHARE_PORT__/80/g' /etc/nginx/nginx.conf + cp /opt/fireshare/app/nginx/error.html /etc/nginx/ + cp /opt/fireshare/app/nginx/api_unavailable.html /etc/nginx/ + fi + msg_info "Configuring Fireshare" + cd /opt/fireshare $STD uv venv --clear $STD .venv/bin/python -m ensurepip --upgrade @@ -53,13 +63,10 @@ function update_script() { export VIDEO_DIRECTORY=/opt/fireshare-videos export PROCESSED_DIRECTORY=/opt/fireshare-processed $STD uv run flask db upgrade - - msg_info "Building Fireshare Client" cd /opt/fireshare/app/client $STD npm install $STD npm run build - msg_ok "Built Fireshare Client" - msg_ok "Updated Fireshare" + msg_ok "Configured Fireshare" msg_info "Starting Service" systemctl start fireshare diff --git a/install/fireshare-install.sh b/install/fireshare-install.sh index 982679c6e..311ba230b 100644 --- a/install/fireshare-install.sh +++ b/install/fireshare-install.sh @@ -141,6 +141,9 @@ cp /opt/fireshare/app/nginx/prod.conf /etc/nginx/nginx.conf sed -i 's|root /processed/|root /opt/fireshare-processed/|g' /etc/nginx/nginx.conf sed -i 's/^user[[:space:]]\+nginx;/user root;/' /etc/nginx/nginx.conf sed -i 's|root[[:space:]]\+/app/build;|root /opt/fireshare/app/client/build;|' /etc/nginx/nginx.conf +sed -i 's/__FIRESHARE_PORT__/80/g' /etc/nginx/nginx.conf +cp /opt/fireshare/app/nginx/error.html /etc/nginx/ +cp /opt/fireshare/app/nginx/api_unavailable.html /etc/nginx/ systemctl start nginx cat <~/fireshare.creds From 11139aede74cf8c4aa648a8c8a0ac1bf47270d90 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 08:54:13 +0000 Subject: [PATCH 057/245] Update CHANGELOG.md (#15679) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62e82d39c..d6e442727 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -505,6 +505,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - Fireshare: Fix for install and upgrade to v1.7.3 [@tremor021](https://github.com/tremor021) ([#15673](https://github.com/community-scripts/ProxmoxVE/pull/15673)) - Endurain: Fix update procedure [@tremor021](https://github.com/tremor021) ([#15674](https://github.com/community-scripts/ProxmoxVE/pull/15674)) ## 2026-07-09 From 2e4558e2628c3038b8d32cd44d84d50feaa4d41b Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 10:57:27 +0200 Subject: [PATCH 058/245] Squid (#15605) * Add squid (ct) * Update ct/squid.sh * Simplify squid.sh by removing proxy user instructions Removed instructions for adding a proxy user inside the container. --------- Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com> Co-authored-by: Sam Heinz Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com> --- ct/headers/squid | 6 +++ ct/squid.sh | 53 ++++++++++++++++++++++++ install/squid-install.sh | 88 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 ct/headers/squid create mode 100644 ct/squid.sh create mode 100644 install/squid-install.sh diff --git a/ct/headers/squid b/ct/headers/squid new file mode 100644 index 000000000..3d826ef75 --- /dev/null +++ b/ct/headers/squid @@ -0,0 +1,6 @@ + _____ _ __ + / ___/____ ___ __(_)___/ / + \__ \/ __ `/ / / / / __ / + ___/ / /_/ / /_/ / / /_/ / +/____/\__, /\__,_/_/\__,_/ + /_/ diff --git a/ct/squid.sh b/ct/squid.sh new file mode 100644 index 000000000..1698fc395 --- /dev/null +++ b/ct/squid.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: 007hacky007 +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://www.squid-cache.org/ + +APP="Squid" +var_tags="${var_tags:-proxy}" +var_cpu="${var_cpu:-1}" +var_ram="${var_ram:-512}" +var_disk="${var_disk:-4}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + if [[ ! -f /etc/squid/squid.conf ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + msg_info "Updating Squid" + $STD apt update + $STD apt upgrade -y + msg_ok "Updated Squid" + + msg_info "Validating Squid Configuration" + $STD squid -k parse + msg_ok "Validated Squid Configuration" + + msg_info "Restarting Squid" + systemctl restart squid + msg_ok "Restarted Squid" + exit +} + +start +build_container +description + +msg_ok "Completed successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Proxy endpoint:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}${IP}:3128${CL}" diff --git a/install/squid-install.sh b/install/squid-install.sh new file mode 100644 index 000000000..aa0110820 --- /dev/null +++ b/install/squid-install.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: 007hacky007 +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://www.squid-cache.org/ + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Configuring Squid" +mkdir -p /etc/squid +cat </etc/squid/squid.conf +acl localnet src 0.0.0.1-0.255.255.255 +acl localnet src 10.0.0.0/8 +acl localnet src 100.64.0.0/10 +acl localnet src 169.254.0.0/16 +acl localnet src 172.16.0.0/12 +acl localnet src 192.168.0.0/16 +acl localnet src fc00::/7 +acl localnet src fe80::/10 + +acl SSL_ports port 443 +acl Safe_ports port 80 +acl Safe_ports port 21 +acl Safe_ports port 443 +acl Safe_ports port 70 +acl Safe_ports port 210 +acl Safe_ports port 1025-65535 +acl Safe_ports port 280 +acl Safe_ports port 488 +acl Safe_ports port 591 +acl Safe_ports port 777 +acl CONNECT method CONNECT + +http_access deny !Safe_ports +http_access deny CONNECT !SSL_ports +http_access allow localhost manager +http_access deny manager + +auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords +auth_param basic realm proxy +acl authenticated proxy_auth REQUIRED +http_access allow authenticated +http_access deny all + +http_port 3128 + +coredump_dir /var/spool/squid + +refresh_pattern ^ftp: 1440 20% 10080 +refresh_pattern ^gopher: 1440 0% 1440 +refresh_pattern -i (/cgi-bin/|\\?) 0 0% 0 +refresh_pattern . 0 20% 4320 + +# Privacy / hardening +httpd_suppress_version_string on +visible_hostname $(hostname) +forwarded_for delete +request_header_access X-Forwarded-For deny all +EOF +msg_ok "Configured Squid" + +msg_info "Installing Dependencies" +$STD apt install -y \ + squid \ + apache2-utils +msg_ok "Installed Dependencies" + +msg_info "Configuring Squid Authentication" +touch /etc/squid/passwords +chown proxy:proxy /etc/squid/passwords +chmod 640 /etc/squid/passwords +$STD squid -k parse +msg_ok "Configured Squid Authentication" + +msg_info "Starting Service" +systemctl enable -q --now squid +msg_ok "Started Service" + +motd_ssh +customize +cleanup_lxc From f4e0111ac0236580d5fb78e51922e7a5dcf5bc08 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 08:57:54 +0000 Subject: [PATCH 059/245] Update CHANGELOG.md (#15680) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6e442727..e4c01f33b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -501,6 +501,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-10 +### 🆕 New Scripts + + - Squid ([#15605](https://github.com/community-scripts/ProxmoxVE/pull/15605)) + ### 🚀 Updated Scripts - #### 🐞 Bug Fixes From 92c4fb45a9e36899b4cbddffe4b3680f63ff775e Mon Sep 17 00:00:00 2001 From: wollew Date: Fri, 10 Jul 2026 20:47:58 +0200 Subject: [PATCH 060/245] Adapt to new artifact filename format for pocket id (#15689) * Adapt to new artifact filename format for pocket id * adapt pocket id install to new artifact filename format as well --- ct/pocketid.sh | 2 +- install/pocketid-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/pocketid.sh b/ct/pocketid.sh index 6153b40c0..9ffc54426 100755 --- a/ct/pocketid.sh +++ b/ct/pocketid.sh @@ -71,7 +71,7 @@ function update_script() { cp /opt/pocket-id/.env /opt/env fi - fetch_and_deploy_gh_release "pocket-id" "pocket-id/pocket-id" "singlefile" "latest" "/opt/pocket-id/" "pocket-id-linux-$(arch_resolve)" + fetch_and_deploy_gh_release "pocket-id" "pocket-id/pocket-id" "singlefile" "latest" "/opt/pocket-id/" "pocket-id_linux_$(arch_resolve)" mv /opt/env /opt/pocket-id/.env msg_info "Starting Service" diff --git a/install/pocketid-install.sh b/install/pocketid-install.sh index 47f945d3b..11b8fa591 100644 --- a/install/pocketid-install.sh +++ b/install/pocketid-install.sh @@ -14,7 +14,7 @@ network_check update_os read -r -p "${TAB3}What public URL do you want to use (e.g. pocketid.mydomain.com)? " public_url -fetch_and_deploy_gh_release "pocket-id" "pocket-id/pocket-id" "singlefile" "latest" "/opt/pocket-id/" "pocket-id-linux-$(arch_resolve)" +fetch_and_deploy_gh_release "pocket-id" "pocket-id/pocket-id" "singlefile" "latest" "/opt/pocket-id/" "pocket-id_linux_$(arch_resolve)" msg_info "Configuring Pocket ID" ENCRYPTION_KEY=$(openssl rand -base64 32) From b958252441893470e356cfc0e5073957c5552030 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 18:48:25 +0000 Subject: [PATCH 061/245] Update CHANGELOG.md (#15692) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4c01f33b..67c3be7b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -509,6 +509,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - Adapt to new artifact filename format for pocket id [@wollew](https://github.com/wollew) ([#15689](https://github.com/community-scripts/ProxmoxVE/pull/15689)) - Fireshare: Fix for install and upgrade to v1.7.3 [@tremor021](https://github.com/tremor021) ([#15673](https://github.com/community-scripts/ProxmoxVE/pull/15673)) - Endurain: Fix update procedure [@tremor021](https://github.com/tremor021) ([#15674](https://github.com/community-scripts/ProxmoxVE/pull/15674)) From 98bedb6ccd7a0cb3f9424989b364e835ca0f0249 Mon Sep 17 00:00:00 2001 From: pumrum Date: Sat, 11 Jul 2026 04:48:55 -0400 Subject: [PATCH 062/245] Fix spacing on VLAN Input Box in haos-vm.sh (#15696) --- vm/haos-vm.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/haos-vm.sh b/vm/haos-vm.sh index 85d582170..df5189614 100644 --- a/vm/haos-vm.sh +++ b/vm/haos-vm.sh @@ -475,7 +475,7 @@ function advanced_settings() { done while true; do - if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan(leave blank for default)" 8 58 --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then + if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan (leave blank for default)" 8 58 --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then if [ -z "$VLAN1" ]; then VLAN1="Default" VLAN="" From f137f8c8942e552693a0f2f9f2bdfcb56735e85a Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sat, 11 Jul 2026 08:49:21 +0000 Subject: [PATCH 063/245] Update CHANGELOG.md (#15699) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67c3be7b4..ab1e165fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -499,6 +499,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-11 + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - Fix spacing on VLAN Input Box in haos-vm.sh [@pumrum](https://github.com/pumrum) ([#15696](https://github.com/community-scripts/ProxmoxVE/pull/15696)) + ## 2026-07-10 ### 🆕 New Scripts From 618d578c353149798079c19720f1b0478fc085ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Slavi=C5=A1a=20Are=C5=BEina?= <58952836+tremor021@users.noreply.github.com> Date: Sat, 11 Jul 2026 20:00:29 +0200 Subject: [PATCH 064/245] [tools.func]: Add function to handle deployment via GitLab release tags (#15641) * Update CHANGELOG.md (#15631) Co-authored-by: github-actions[bot] * Update CHANGELOG.md (#15631) Co-authored-by: github-actions[bot] * Update CHANGELOG.md (#15631) Co-authored-by: github-actions[bot] * add gl tag handling funcs --------- Co-authored-by: community-scripts-pr-app[bot] <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] --- misc/tools.func | 193 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) diff --git a/misc/tools.func b/misc/tools.func index e8e18f4f3..9360535a3 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -2559,6 +2559,199 @@ fetch_and_deploy_gh_tag() { return 0 } +# ------------------------------------------------------------------------------ +# Get the latest GitLab repository tag matching a glob pattern. +# +# Description: +# - Queries the GitLab repository tags API (up to 100 tags per page) +# - Filters tag names against a shell glob pattern (e.g. "web-v*" or "mobile-v*") +# - Always excludes pre-release tags (those containing alpha, beta, or rc) +# - Sorts matching tags with `sort -V` and returns the highest one +# - Supports GITLAB_TOKEN for private/rate-limited projects +# +# Usage: +# get_latest_gl_tag "owner/repo" "web-v*" +# get_latest_gl_tag "owner/repo" "mobile-v*" +# get_latest_gl_tag "owner/repo" # returns newest tag (no filter) +# +# Arguments: +# $1 - GitLab repo path (namespace/project, e.g. "mygroup/myapp") +# $2 - Optional glob pattern to filter tag names (e.g. "web-v*") +# +# Returns: +# Latest matching tag name on stdout, or non-zero on failure +# ------------------------------------------------------------------------------ +get_latest_gl_tag() { + local repo="$1" + local pattern="${2:-}" + + local repo_encoded + repo_encoded=$(printf '%s' "$repo" | sed 's|/|%2F|g') + + local api_base="https://gitlab.com/api/v4/projects/${repo_encoded}/repository/tags" + local api_timeout="--connect-timeout 10 --max-time 60" + + local header=() + [[ -n "${GITLAB_TOKEN:-}" ]] && header=(-H "PRIVATE-TOKEN: $GITLAB_TOKEN") + + # If a pattern is given, pass it as a regex search to reduce server-side results. + # GitLab ?search= supports anchored regex; convert leading glob prefix to regex anchor. + local search_param="" + if [[ -n "$pattern" ]]; then + # Strip trailing wildcard for the search hint (server-side prefix filter). + local prefix="${pattern%%\**}" + [[ -n "$prefix" ]] && search_param="?search=^${prefix}&per_page=100" || search_param="?per_page=100" + else + search_param="?per_page=100" + fi + + local temp_file + temp_file=$(mktemp) || return 1 + + local http_code + http_code=$(curl $api_timeout -sSL -w "%{http_code}" -o "$temp_file" \ + "${header[@]}" "${api_base}${search_param}" 2>/dev/null) || true + + if [[ "$http_code" != "200" ]]; then + rm -f "$temp_file" + msg_error "GitLab tags API returned HTTP $http_code for $repo" + return 22 + fi + + local tag="" + if [[ -n "$pattern" ]]; then + # Client-side glob filter + pre-release exclusion, then version-sort to pick the highest match. + tag=$(jq -r '.[].name' "$temp_file" 2>/dev/null | while IFS= read -r t; do + case "$t" in + *alpha* | *beta* | *rc*) continue ;; + $pattern) echo "$t" ;; + esac + done | sort -V | tail -n1) + else + # No pattern: skip pre-release tags, take the first remaining (newest) one. + tag=$(jq -r '.[].name' "$temp_file" 2>/dev/null | + grep -Eiv '(alpha|beta|rc)' | + head -n1) + fi + + rm -f "$temp_file" + + if [[ -z "$tag" ]]; then + msg_error "No tags matching '${pattern:-*}' found for ${repo}" + return 250 + fi + + echo "$tag" +} + +# ------------------------------------------------------------------------------ +# Fetches and deploys a GitLab tag-based source tarball. +# +# Description: +# - Resolves the latest tag matching the given glob pattern via get_latest_gl_tag +# (or uses the exact tag if one is provided instead of "latest") +# - Downloads the GitLab source tarball for that tag +# - Extracts it to the target directory +# - Writes the resolved tag to ~/. for update-checking +# +# Usage: +# fetch_and_deploy_gl_tag "myapp" "mygroup/myrepo" "web-v*" +# fetch_and_deploy_gl_tag "myapp" "mygroup/myrepo" "mobile-v*" "/opt/myapp" +# fetch_and_deploy_gl_tag "myapp" "mygroup/myrepo" "v*" # any v-tag +# fetch_and_deploy_gl_tag "myapp" "mygroup/myrepo" "web-v3.0*" # narrow version range +# +# Arguments: +# $1 - App name (used for version file ~/. and lowercase tarball name) +# $2 - GitLab repo path (namespace/project, e.g. "mygroup/myapp") +# $3 - Tag pattern: glob (e.g. "web-v*") or exact tag (e.g. "web-v3.0.0"). +# Use "latest" to fetch the single newest tag with no pattern filter. +# $4 - Target directory (default: /opt/$app) +# +# Notes: +# - Supports CLEAN_INSTALL=1 to wipe target before extracting +# - Supports GITLAB_TOKEN for private/rate-limited projects +# - For repos that only publish tags, not formal GitLab Releases +# (use fetch_and_deploy_gl_release for proper Releases with assets) +# ------------------------------------------------------------------------------ +fetch_and_deploy_gl_tag() { + local app="$1" + local repo="$2" + local tag_pattern="${3:-latest}" + local target="${4:-/opt/$app}" + + local app_lc="" + app_lc="$(echo "${app,,}" | tr -d ' ')" + local version_file="$HOME/.${app_lc}" + + local api_timeout="--connect-timeout 10 --max-time 60" + local download_timeout="--connect-timeout 15 --max-time 900" + + local header=() + [[ -n "${GITLAB_TOKEN:-}" ]] && header=(-H "PRIVATE-TOKEN: $GITLAB_TOKEN") + + # Resolve the tag: if caller passed a glob/latest, query the API. + # If caller passed an exact tag (no wildcards), use it directly. + local resolved_tag="$tag_pattern" + if [[ "$tag_pattern" == "latest" || "$tag_pattern" == *"*"* || "$tag_pattern" == *"?"* ]]; then + local glob_arg="" + [[ "$tag_pattern" != "latest" ]] && glob_arg="$tag_pattern" + resolved_tag=$(get_latest_gl_tag "$repo" "$glob_arg") || { + msg_error "Failed to determine latest tag matching '${tag_pattern}' for ${repo}" + return 250 + } + fi + + local current_version="" + [[ -f "$version_file" ]] && current_version=$(<"$version_file") + + if [[ "$current_version" == "$resolved_tag" ]]; then + msg_ok "$app is already up-to-date ($resolved_tag)" + return 0 + fi + + local repo_encoded + repo_encoded=$(printf '%s' "$repo" | sed 's|/|%2F|g') + + # GitLab source tarball URL (no release needed, works for any tag). + local version_safe="${resolved_tag//\//-}" + local tarball_url="https://gitlab.com/${repo}/-/archive/${resolved_tag}/${app_lc}-${version_safe}.tar.gz" + + local tmpdir + tmpdir=$(mktemp -d) || return 1 + local filename="${app_lc}-${version_safe}.tar.gz" + + msg_info "Fetching GitLab tag: ${app} (${resolved_tag})" + + curl $download_timeout -fsSL "${header[@]}" -o "$tmpdir/$filename" "$tarball_url" || { + msg_error "Download failed: $tarball_url" + rm -rf "$tmpdir" + return 7 + } + + mkdir -p "$target" + if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then + rm -rf "${target:?}/"* + fi + + tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { + msg_error "Failed to extract tarball" + rm -rf "$tmpdir" + return 251 + } + + local unpack_dir + unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1) + + shopt -s dotglob nullglob + cp -r "$unpack_dir"/* "$target/" + shopt -u dotglob nullglob + + rm -rf "$tmpdir" + echo "$resolved_tag" >"$version_file" + msg_ok "Deployed ${app} ${resolved_tag} to ${target}" + return 0 +} + # ------------------------------------------------------------------------------ # Checks for new GitHub tag (for repos without releases). # From 0906341e95a151b19095ddf130251f0ef632e053 Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Sat, 11 Jul 2026 20:00:36 +0200 Subject: [PATCH 065/245] LocalAGI (#15687) * Add localagi (ct) * Refactor localagi.sh for better readability Removed unnecessary blank lines and improved script readability. --------- Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com> Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com> --- ct/headers/localagi | 6 +++ ct/localagi.sh | 67 +++++++++++++++++++++++++++++++++ install/localagi-install.sh | 75 +++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 ct/headers/localagi create mode 100644 ct/localagi.sh create mode 100644 install/localagi-install.sh diff --git a/ct/headers/localagi b/ct/headers/localagi new file mode 100644 index 000000000..c47da9aac --- /dev/null +++ b/ct/headers/localagi @@ -0,0 +1,6 @@ + __ _____ __________ + / / ____ _________ _/ / | / ____/ _/ + / / / __ \/ ___/ __ `/ / /| |/ / __ / / + / /___/ /_/ / /__/ /_/ / / ___ / /_/ // / +/_____/\____/\___/\__,_/_/_/ |_\____/___/ + diff --git a/ct/localagi.sh b/ct/localagi.sh new file mode 100644 index 000000000..b2f9fbe91 --- /dev/null +++ b/ct/localagi.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: BillyOutlast +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/mudler/LocalAGI + +APP="LocalAGI" +var_tags="${var_tags:-ai}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-4096}" +var_disk="${var_disk:-20}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-no}" +var_unprivileged="${var_unprivileged:-1}" +var_gpu="${var_gpu:-no}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/localagi ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "localagi" "mudler/LocalAGI"; then + msg_info "Stopping Service" + systemctl stop localagi + msg_ok "Stopped Service" + + create_backup /opt/localagi/.env + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "localagi" "mudler/LocalAGI" "tarball" "latest" "/opt/localagi" + restore_backup + + msg_info "Building LocalAGI" + cd /opt/localagi/webui/react-ui + $STD bun install + $STD bun run build + cd /opt/localagi + $STD go build -o /usr/local/bin/localagi + msg_ok "Updated LocalAGI successfully" + + msg_info "Starting Service" + systemctl start localagi + msg_ok "Started Service" + msg_ok "Updated successfully!" + exit + fi + exit +} + +start +build_container +description + +msg_ok "Completed successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}" diff --git a/install/localagi-install.sh b/install/localagi-install.sh new file mode 100644 index 000000000..3589d1b8b --- /dev/null +++ b/install/localagi-install.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: BillyOutlast +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/mudler/LocalAGI + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +APP="LocalAGI" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt install -y build-essential +msg_ok "Installed Dependencies" + +NODE_VERSION="24" setup_nodejs +setup_go + +msg_info "Installing Bun" +export BUN_INSTALL="/root/.bun" +curl -fsSL https://bun.sh/install | $STD bash +ln -sf /root/.bun/bin/bun /usr/local/bin/bun +ln -sf /root/.bun/bin/bunx /usr/local/bin/bunx +msg_ok "Installed Bun" + +fetch_and_deploy_gh_release "localagi" "mudler/LocalAGI" "tarball" "latest" "/opt/localagi" + +msg_info "Configuring LocalAGI" +mkdir -p /opt/localagi/pool +cat <<'EOF' >/opt/localagi/.env +LOCALAGI_MODEL=gemma-3-4b-it-qat +LOCALAGI_MULTIMODAL_MODEL=moondream2-20250414 +LOCALAGI_IMAGE_MODEL=sd-1.5-ggml +LOCALAGI_LLM_API_URL=http://127.0.0.1:11434/v1 +LOCALAGI_STATE_DIR=/opt/localagi/pool +EOF +msg_ok "Configured LocalAGI" + +msg_info "Setting up LocalAGI" +cd /opt/localagi/webui/react-ui +$STD bun install +$STD bun run build +cd /opt/localagi +$STD go build -o /usr/local/bin/localagi +msg_ok "Set up LocalAGI" + +msg_info "Creating LocalAGI systemd service" +cat </etc/systemd/system/localagi.service +[Unit] +Description=LocalAGI +After=network.target + +[Service] +User=root +Type=simple +EnvironmentFile=/opt/localagi/.env + +WorkingDirectory=/opt/localagi +ExecStart=/usr/local/bin/localagi +Restart=on-failure + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now localagi +msg_ok "Created LocalAGI systemd service" + +motd_ssh +customize +cleanup_lxc From ed9c80f8053f66520b9469225d312a060d2753cf Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sat, 11 Jul 2026 18:00:51 +0000 Subject: [PATCH 066/245] Update CHANGELOG.md (#15707) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab1e165fa..a2bb24f91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -501,12 +501,22 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-11 +### 🆕 New Scripts + + - LocalAGI ([#15687](https://github.com/community-scripts/ProxmoxVE/pull/15687)) + ### 🚀 Updated Scripts - #### 🐞 Bug Fixes - Fix spacing on VLAN Input Box in haos-vm.sh [@pumrum](https://github.com/pumrum) ([#15696](https://github.com/community-scripts/ProxmoxVE/pull/15696)) +### 💾 Core + + - #### ✨ New Features + + - [tools.func]: Add function to handle deployment via GitLab release tags [@tremor021](https://github.com/tremor021) ([#15641](https://github.com/community-scripts/ProxmoxVE/pull/15641)) + ## 2026-07-10 ### 🆕 New Scripts From f1b2bd048600228d0108d5f3fc1b32fce672a656 Mon Sep 17 00:00:00 2001 From: TowyTowy <85077986+TowyTowy@users.noreply.github.com> Date: Sat, 11 Jul 2026 20:07:05 +0200 Subject: [PATCH 068/245] fix(adventurelog): allow pnpm build scripts so install/update doesn't abort (#15681) AdventureLog's frontend install runs a bare `pnpm i`. On pnpm v10+, build scripts of dependencies (esbuild, es5-ext, svelte-preprocess) are ignored by default and pnpm aborts with ERR_PNPM_IGNORED_BUILDS (exit 1), so the install never reaches `pnpm build`. The shipped frontend/pnpm-workspace.yaml already pins esbuild, so those builds are expected to run. Enable the builds for this app only by appending `dangerouslyAllowAllBuilds: true` to the frontend's pnpm-workspace.yaml before `pnpm i`, in both the install and update paths. The change is guarded so it is not duplicated on re-run, and it is scoped to AdventureLog (which ships no onlyBuiltDependencies) to avoid the global config conflict that a repo-wide setting would cause. Fixes #15670 Co-authored-by: Claude Fable 5 --- ct/adventurelog.sh | 1 + install/adventurelog-install.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/ct/adventurelog.sh b/ct/adventurelog.sh index 0da4c09c0..98327747e 100644 --- a/ct/adventurelog.sh +++ b/ct/adventurelog.sh @@ -60,6 +60,7 @@ function update_script() { $STD .venv/bin/python -m manage migrate cd /opt/adventurelog/frontend + grep -q "^dangerouslyAllowAllBuilds:" ./pnpm-workspace.yaml 2>/dev/null || echo "dangerouslyAllowAllBuilds: true" >>./pnpm-workspace.yaml $STD pnpm i $STD pnpm build msg_ok "Updated AdventureLog" diff --git a/install/adventurelog-install.sh b/install/adventurelog-install.sh index 10e664bc6..b480da0d9 100644 --- a/install/adventurelog-install.sh +++ b/install/adventurelog-install.sh @@ -72,6 +72,7 @@ BODY_SIZE_LIMIT=Infinity ORIGIN='http://$LOCAL_IP:3000' EOF cd /opt/adventurelog/frontend +grep -q "^dangerouslyAllowAllBuilds:" ./pnpm-workspace.yaml 2>/dev/null || echo "dangerouslyAllowAllBuilds: true" >>./pnpm-workspace.yaml $STD pnpm i $STD pnpm build msg_ok "Installed AdventureLog" From dcd1eefdd4d5051ce5e6d41fa00cbc9ab6ad52b3 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sat, 11 Jul 2026 18:07:32 +0000 Subject: [PATCH 069/245] Update CHANGELOG.md (#15709) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2bb24f91..707ec2a40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -507,6 +507,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🚀 Updated Scripts + - fix(adventurelog): allow pnpm build scripts so install/update doesn't abort [@TowyTowy](https://github.com/TowyTowy) ([#15681](https://github.com/community-scripts/ProxmoxVE/pull/15681)) + - #### 🐞 Bug Fixes - Fix spacing on VLAN Input Box in haos-vm.sh [@pumrum](https://github.com/pumrum) ([#15696](https://github.com/community-scripts/ProxmoxVE/pull/15696)) From c481c3e24ee6cb91e7d98cb6ef9b517f8060c039 Mon Sep 17 00:00:00 2001 From: TowyTowy <85077986+TowyTowy@users.noreply.github.com> Date: Sat, 11 Jul 2026 22:15:12 +0200 Subject: [PATCH 070/245] fix(fileflows): install .NET 10 ASP.NET Core Runtime to match current release (#15702) * fix(fileflows): install .NET 10 ASP.NET Core Runtime to match current release FileFlows now ships its server/node binaries targeting .NET 10 (Microsoft.NETCore.App 10.0.0), but the install script still installs the ASP.NET Core Runtime 8.0. On a fresh install the app therefore cannot start: You must install or update .NET to run this application. Framework: 'Microsoft.NETCore.App', version '10.0.0' (x64) The following frameworks were found: 8.0.28 at [/usr/share/dotnet/shared/Microsoft.NETCore.App] so "dotnet FileFlows.Server.dll --systemd install" fails with exit code 150 (service failed to start) and the container aborts (issue #15686). Bump the runtime to 10.0 on both branches: aspnetcore-runtime-10.0 from packages.microsoft.com on amd64 (the same repo and package already used by igotify, rdtclient and technitiumdns) and dotnet-install --channel 10.0 on arm64. Co-Authored-By: Claude Fable 5 * fix(fileflows): ensure current .NET runtime on update too An existing install set up under an older .NET (e.g. aspnetcore-runtime-8.0) would download a newer FileFlows on update but keep the old runtime, failing to start with the same framework-not-found error. Mirror the runtime handling used by technitiumdns/rdtclient in update_script. Co-Authored-By: Claude Fable 5 --------- Co-authored-by: Claude Fable 5 --- ct/fileflows.sh | 22 ++++++++++++++++++++++ install/fileflows-install.sh | 6 +++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/ct/fileflows.sh b/ct/fileflows.sh index 1f33d2dd0..473efd435 100644 --- a/ct/fileflows.sh +++ b/ct/fileflows.sh @@ -43,6 +43,28 @@ function update_script() { tar -czf "$backup_filename" -C /opt/fileflows Data msg_ok "Backup Created" + # FileFlows tracks the latest release, whose .NET target can move (e.g. 8 -> 10); + # ensure the current ASP.NET Core Runtime so an existing install doesn't fail to + # start after updating to a newer .NET major version. + msg_info "Ensuring ASP.NET Core Runtime" + if [[ "$(arch_resolve)" == "arm64" ]]; then + if [[ ! -x /usr/lib/dotnet10/dotnet ]]; then + curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh + $STD bash /tmp/dotnet-install.sh --channel 10.0 --runtime aspnetcore --install-dir /usr/lib/dotnet10 + ln -sf /usr/lib/dotnet10/dotnet /usr/bin/dotnet + rm -f /tmp/dotnet-install.sh + fi + elif ! is_package_installed "aspnetcore-runtime-10.0"; then + $STD apt remove -y aspnetcore-runtime-8.0 aspnetcore-runtime-9.0 2>/dev/null || true + setup_deb822_repo \ + "microsoft" \ + "https://packages.microsoft.com/keys/microsoft-2025.asc" \ + "https://packages.microsoft.com/debian/13/prod/" \ + "trixie" + $STD apt install -y aspnetcore-runtime-10.0 + fi + msg_ok "Ensured ASP.NET Core Runtime" + fetch_and_deploy_from_url "https://fileflows.com/downloads/zip" "/opt/fileflows" msg_info "Starting Service" diff --git a/install/fileflows-install.sh b/install/fileflows-install.sh index af93424b6..50242be8a 100644 --- a/install/fileflows-install.sh +++ b/install/fileflows-install.sh @@ -26,8 +26,8 @@ msg_info "Installing ASP.NET Core Runtime" if [[ "$(arch_resolve)" == "arm64" ]]; then # packages.microsoft.com only ships amd64 debs for Debian; use dotnet-install on arm64 curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh - $STD bash /tmp/dotnet-install.sh --channel 8.0 --runtime aspnetcore --install-dir /usr/lib/dotnet8 - ln -sf /usr/lib/dotnet8/dotnet /usr/bin/dotnet + $STD bash /tmp/dotnet-install.sh --channel 10.0 --runtime aspnetcore --install-dir /usr/lib/dotnet10 + ln -sf /usr/lib/dotnet10/dotnet /usr/bin/dotnet rm -f /tmp/dotnet-install.sh else setup_deb822_repo \ @@ -35,7 +35,7 @@ else "https://packages.microsoft.com/keys/microsoft-2025.asc" \ "https://packages.microsoft.com/debian/13/prod/" \ "trixie" - $STD apt install -y aspnetcore-runtime-8.0 + $STD apt install -y aspnetcore-runtime-10.0 fi msg_ok "Installed ASP.NET Core Runtime" From 8fbb4b1988e3fde4cdfdd684401dddc9096b8691 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sat, 11 Jul 2026 20:15:36 +0000 Subject: [PATCH 071/245] Update CHANGELOG.md (#15712) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 707ec2a40..c880c3861 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -511,6 +511,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - fix(fileflows): install .NET 10 ASP.NET Core Runtime to match current release [@TowyTowy](https://github.com/TowyTowy) ([#15702](https://github.com/community-scripts/ProxmoxVE/pull/15702)) - Fix spacing on VLAN Input Box in haos-vm.sh [@pumrum](https://github.com/pumrum) ([#15696](https://github.com/community-scripts/ProxmoxVE/pull/15696)) ### 💾 Core From 76335cefe8790b036249636b12920fb04c6ab254 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 12 Jul 2026 00:17:46 +0000 Subject: [PATCH 072/245] Archive old changelog entries (#15714) Co-authored-by: github-actions[bot] --- .github/changelogs/2026/07.md | 91 ++++++++++++++++++++++ CHANGELOG.md | 138 ++-------------------------------- 2 files changed, 96 insertions(+), 133 deletions(-) diff --git a/.github/changelogs/2026/07.md b/.github/changelogs/2026/07.md index 4c20ca3e6..2ecd58f89 100644 --- a/.github/changelogs/2026/07.md +++ b/.github/changelogs/2026/07.md @@ -1,3 +1,94 @@ +## 2026-07-11 + +### 🆕 New Scripts + + - LocalAGI ([#15687](https://github.com/community-scripts/ProxmoxVE/pull/15687)) + +### 🚀 Updated Scripts + + - fix(adventurelog): allow pnpm build scripts so install/update doesn't abort [@TowyTowy](https://github.com/TowyTowy) ([#15681](https://github.com/community-scripts/ProxmoxVE/pull/15681)) + + - #### 🐞 Bug Fixes + + - fix(fileflows): install .NET 10 ASP.NET Core Runtime to match current release [@TowyTowy](https://github.com/TowyTowy) ([#15702](https://github.com/community-scripts/ProxmoxVE/pull/15702)) + - Fix spacing on VLAN Input Box in haos-vm.sh [@pumrum](https://github.com/pumrum) ([#15696](https://github.com/community-scripts/ProxmoxVE/pull/15696)) + +### 💾 Core + + - #### ✨ New Features + + - [tools.func]: Add function to handle deployment via GitLab release tags [@tremor021](https://github.com/tremor021) ([#15641](https://github.com/community-scripts/ProxmoxVE/pull/15641)) + +## 2026-07-10 + +### 🆕 New Scripts + + - Squid ([#15605](https://github.com/community-scripts/ProxmoxVE/pull/15605)) + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - Adapt to new artifact filename format for pocket id [@wollew](https://github.com/wollew) ([#15689](https://github.com/community-scripts/ProxmoxVE/pull/15689)) + - Fireshare: Fix for install and upgrade to v1.7.3 [@tremor021](https://github.com/tremor021) ([#15673](https://github.com/community-scripts/ProxmoxVE/pull/15673)) + - Endurain: Fix update procedure [@tremor021](https://github.com/tremor021) ([#15674](https://github.com/community-scripts/ProxmoxVE/pull/15674)) + +## 2026-07-09 + +### 🚀 Updated Scripts + + - fix(pihole): repair Unbound DNS-over-TLS (DoT) forwarding config [@TowyTowy](https://github.com/TowyTowy) ([#15654](https://github.com/community-scripts/ProxmoxVE/pull/15654)) + +## 2026-07-08 + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - Opencloud: Bump version to 7.2.1 [@vhsdream](https://github.com/vhsdream) ([#15655](https://github.com/community-scripts/ProxmoxVE/pull/15655)) + - BabyBuddy: Harden update script [@MickLesk](https://github.com/MickLesk) ([#15642](https://github.com/community-scripts/ProxmoxVE/pull/15642)) + +## 2026-07-07 + +### 🆕 New Scripts + + - Forgejo-Runner ([#15046](https://github.com/community-scripts/ProxmoxVE/pull/15046)) + +## 2026-07-06 + +### 🚀 Updated Scripts + + - Fix alignment in various ct end messages [@tremor021](https://github.com/tremor021) ([#15632](https://github.com/community-scripts/ProxmoxVE/pull/15632)) +- Immich: Update libvips to 8.18.4 [@vhsdream](https://github.com/vhsdream) ([#15619](https://github.com/community-scripts/ProxmoxVE/pull/15619)) + + - #### 🐞 Bug Fixes + + - Wizarr: Build JS and CSS static assets [@vhsdream](https://github.com/vhsdream) ([#15634](https://github.com/community-scripts/ProxmoxVE/pull/15634)) + - RustDesk Server: Update URL format in rustdeskserver.sh [@tremor021](https://github.com/tremor021) ([#15626](https://github.com/community-scripts/ProxmoxVE/pull/15626)) + - attempt to port docker-vm to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15611](https://github.com/community-scripts/ProxmoxVE/pull/15611)) + - fix(plane): don't clobber global app var, breaking /usr/bin/update [@asylumexp](https://github.com/asylumexp) ([#15612](https://github.com/community-scripts/ProxmoxVE/pull/15612)) + + - #### 🔧 Refactor + + - cliproxyapi: point setup message at /management.html [@austinpilz](https://github.com/austinpilz) ([#15628](https://github.com/community-scripts/ProxmoxVE/pull/15628)) + +### 🗑️ Deleted Scripts + + - Remove: FlowiseAI [@MickLesk](https://github.com/MickLesk) ([#15624](https://github.com/community-scripts/ProxmoxVE/pull/15624)) + +## 2026-07-05 + +### 🆕 New Scripts + + - excalidash ([#15604](https://github.com/community-scripts/ProxmoxVE/pull/15604)) + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - fix: homarr: cli [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15603](https://github.com/community-scripts/ProxmoxVE/pull/15603)) + - immich: vacuum smart_search/face_search before VectorChord bump [@irishpadres](https://github.com/irishpadres) ([#15607](https://github.com/community-scripts/ProxmoxVE/pull/15607)) + ## 2026-07-04 ### 🚀 Updated Scripts diff --git a/CHANGELOG.md b/CHANGELOG.md index c880c3861..8e1c5dcbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,9 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit + + + @@ -87,7 +90,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
-

July (4 entries)

+

July (11 entries)

[View July 2026 Changelog](.github/changelogs/2026/07.md) @@ -1104,135 +1107,4 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### ✨ New Features - - [core] Implement backup and restore functions [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15067](https://github.com/community-scripts/ProxmoxVE/pull/15067)) - -## 2026-06-11 - -### 🆕 New Scripts - - - Clickhouse ([#15045](https://github.com/community-scripts/ProxmoxVE/pull/15045)) - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - Manyfold: add new dependency [@MickLesk](https://github.com/MickLesk) ([#15040](https://github.com/community-scripts/ProxmoxVE/pull/15040)) - - OpenArchiver: switch Rebuild Function [@MickLesk](https://github.com/MickLesk) ([#15042](https://github.com/community-scripts/ProxmoxVE/pull/15042)) - - CLIProxyAPI: Save management password to creds file [@tremor021](https://github.com/tremor021) ([#15051](https://github.com/community-scripts/ProxmoxVE/pull/15051)) - - Jotty: Fix wrong path test in config restore [@vhsdream](https://github.com/vhsdream) ([#15038](https://github.com/community-scripts/ProxmoxVE/pull/15038)) - - Fix for cross-seed after node upgrade [@TorinFrancis](https://github.com/TorinFrancis) ([#15025](https://github.com/community-scripts/ProxmoxVE/pull/15025)) - - - #### 🔧 Refactor - - - Alpine-Nextcloud: Upgrade PHP and dependencies in installation script [@MickLesk](https://github.com/MickLesk) ([#15039](https://github.com/community-scripts/ProxmoxVE/pull/15039)) - - [arm64] porting stage 1: set script arm64 statuses to yes [@asylumexp](https://github.com/asylumexp) ([#15052](https://github.com/community-scripts/ProxmoxVE/pull/15052)) - -### 💾 Core - - - #### ✨ New Features - - - misc scripts: add support for arm64 [@asylumexp](https://github.com/asylumexp) ([#12639](https://github.com/community-scripts/ProxmoxVE/pull/12639)) - - - #### 🔧 Refactor - - - [arm64] remove logic for custom debian arm64 template [@asylumexp](https://github.com/asylumexp) ([#15050](https://github.com/community-scripts/ProxmoxVE/pull/15050)) - -### 📚 Documentation - - - (github): Revise script request template [@MickLesk](https://github.com/MickLesk) ([#15058](https://github.com/community-scripts/ProxmoxVE/pull/15058)) - -## 2026-06-10 - -### 🆕 New Scripts - - - Baserow ([#14968](https://github.com/community-scripts/ProxmoxVE/pull/14968)) - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - Koillection: Fix update procedure [@tremor021](https://github.com/tremor021) ([#15033](https://github.com/community-scripts/ProxmoxVE/pull/15033)) - -## 2026-06-09 - -### 🆕 New Scripts - - - paperclip ([#14990](https://github.com/community-scripts/ProxmoxVE/pull/14990)) - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - endurain: Install pytz package during backend setup [@MickLesk](https://github.com/MickLesk) ([#15014](https://github.com/community-scripts/ProxmoxVE/pull/15014)) - - - #### 🔧 Refactor - - - Refactor: Proxmox Backup Server - use deb822 [@MickLesk](https://github.com/MickLesk) ([#15013](https://github.com/community-scripts/ProxmoxVE/pull/15013)) - -## 2026-06-08 - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - security: Fix HTTP to HTTPS for all package and repository downloads [@MickLesk](https://github.com/MickLesk) ([#15009](https://github.com/community-scripts/ProxmoxVE/pull/15009)) - - homelable: preserve MCP server config across updates [@ferr079](https://github.com/ferr079) ([#14996](https://github.com/community-scripts/ProxmoxVE/pull/14996)) - - changedetection: migrate Python install to uv venv [@ferr079](https://github.com/ferr079) ([#14995](https://github.com/community-scripts/ProxmoxVE/pull/14995)) - - - #### 🔧 Refactor - - - Update Flowwiseai to node 24 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14999](https://github.com/community-scripts/ProxmoxVE/pull/14999)) - -### 🧰 Tools - - - #### 🐞 Bug Fixes - - - security: Fix MITM RCE vulnerability in microcode scripts (CVE) [@MickLesk](https://github.com/MickLesk) ([#15007](https://github.com/community-scripts/ProxmoxVE/pull/15007)) - -## 2026-06-07 - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - Immich: use actual installed PostgreSQL version for vchord package [@MickLesk](https://github.com/MickLesk) ([#14989](https://github.com/community-scripts/ProxmoxVE/pull/14989)) - - - #### 🔧 Refactor - - - Navidrome: remove genereic filebrowser addon setup [@MickLesk](https://github.com/MickLesk) ([#14991](https://github.com/community-scripts/ProxmoxVE/pull/14991)) - -## 2026-06-06 - -### 🆕 New Scripts - - - Spliit ([#14966](https://github.com/community-scripts/ProxmoxVE/pull/14966)) -- Tolgee ([#14965](https://github.com/community-scripts/ProxmoxVE/pull/14965)) -- XYOps ([#14967](https://github.com/community-scripts/ProxmoxVE/pull/14967)) - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - Photoprism: Allow env variables with spaces [@Badintral](https://github.com/Badintral) ([#14969](https://github.com/community-scripts/ProxmoxVE/pull/14969)) - -## 2026-06-05 - -### 🆕 New Scripts - - - MatterJS-Server ([#14951](https://github.com/community-scripts/ProxmoxVE/pull/14951)) -- CyberChef ([#14952](https://github.com/community-scripts/ProxmoxVE/pull/14952)) - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - Jackett: Create missing .env file [@tremor021](https://github.com/tremor021) ([#14959](https://github.com/community-scripts/ProxmoxVE/pull/14959)) - - OpenThread-BR: use systemd instead of init.d [@tomfrenzel](https://github.com/tomfrenzel) ([#14942](https://github.com/community-scripts/ProxmoxVE/pull/14942)) - - - #### ✨ New Features - - - AMD IGPU support [@Learath](https://github.com/Learath) ([#14944](https://github.com/community-scripts/ProxmoxVE/pull/14944)) - - - #### 💥 Breaking Changes - - - update authentik to 2026.5.2 [@thieneret](https://github.com/thieneret) ([#14846](https://github.com/community-scripts/ProxmoxVE/pull/14846)) \ No newline at end of file + - [core] Implement backup and restore functions [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15067](https://github.com/community-scripts/ProxmoxVE/pull/15067)) \ No newline at end of file From 96100474cc54c6a0f64efbd0827c6c8ff7957fe4 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 12 Jul 2026 00:18:12 +0000 Subject: [PATCH 073/245] Update CHANGELOG.md (#15715) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e1c5dcbb..09c1e41bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -502,6 +502,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
+## 2026-07-12 + ## 2026-07-11 ### 🆕 New Scripts From c0b2c906faf271b89a7e6a78e4bf7a8001ef4c9a Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 12 Jul 2026 11:48:43 -0400 Subject: [PATCH 074/245] Immich: Bump version to 3.0.2 (#15668) * Immich: Bump version to 3.0.2 * Bump vchord to 1.1.1 * Add MickLesk HEIC patch --- ct/immich.sh | 25 +++++++++++++++++++++++-- install/immich-install.sh | 25 +++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/ct/immich.sh b/ct/immich.sh index 48ae7ceda..1aa7e0546 100644 --- a/ct/immich.sh +++ b/ct/immich.sh @@ -110,7 +110,7 @@ EOF msg_ok "Image-processing libraries up to date" fi - RELEASE="v3.0.1" + RELEASE="v3.0.2" if check_for_gh_release "Immich" "immich-app/immich" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then if [[ $(cat ~/.immich) > "2.5.1" ]]; then msg_info "Enabling Maintenance Mode" @@ -124,7 +124,7 @@ EOF systemctl stop immich-web systemctl stop immich-ml msg_ok "Stopped Services" - VCHORD_RELEASE="1.0.0" + VCHORD_RELEASE="1.1.1" [[ -f ~/.vchord_version ]] && mv ~/.vchord_version ~/.vectorchord if check_for_gh_release "VectorChord" "tensorchord/VectorChord" "${VCHORD_RELEASE}" "updated together with Immich after testing"; then # dead tuples in smart_search/face_search make the REINDEX below fail with @@ -328,6 +328,27 @@ EOF systemctl daemon-reload fi + # MickLesk temporary patch for HEIC thumbnail gen + msg_info "Patching media.repository.js" + MEDIA_REPO_JS="/opt/immich/app/dist/repositories/media.repository.js" + if [[ -f "$MEDIA_REPO_JS" ]]; then + python3 - <<'PY' +from pathlib import Path +p = Path('/opt/immich/app/dist/repositories/media.repository.js') +s = p.read_text() +old = "(0, sharp_1.default)(input).metadata()" +new = "(0, sharp_1.default)(input, { unlimited: true, limitInputPixels: false }).metadata()" +if new in s: + print('hotfix already there') + elif old in s: + p.write_text(s.replace(old, new, 1)) + print('hotfix applied') + else: + print('pattern not found, skipped') +PY + fi + msg_ok "Patched media.repository.js" + # chown excluding upload dir contents (may be a mount with restricted permissions) chown immich:immich "$INSTALL_DIR" find "$INSTALL_DIR" -maxdepth 1 -mindepth 1 ! -name upload -exec chown -R immich:immich {} + diff --git a/install/immich-install.sh b/install/immich-install.sh index fcaad3e0b..2aa611c61 100644 --- a/install/immich-install.sh +++ b/install/immich-install.sh @@ -162,7 +162,7 @@ PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql ACTUAL_PG_VERSION=$(ls /etc/postgresql/ 2>/dev/null | sort -V | tail -1) ACTUAL_PG_VERSION=${ACTUAL_PG_VERSION:-16} -VCHORD_RELEASE="1.0.0" +VCHORD_RELEASE="1.1.1" fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" "${VCHORD_RELEASE}" "/tmp" "postgresql-${ACTUAL_PG_VERSION}-vchord_*_$(arch_resolve).deb" sed -i "s/^#shared_preload.*/shared_preload_libraries = 'vchord.so'/" /etc/postgresql/${ACTUAL_PG_VERSION}/main/postgresql.conf @@ -311,7 +311,7 @@ ML_DIR="${APP_DIR}/machine-learning" GEO_DIR="${INSTALL_DIR}/geodata" mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache} -fetch_and_deploy_gh_release "Immich" "immich-app/immich" "tarball" "v3.0.1" "$SRC_DIR" +fetch_and_deploy_gh_release "Immich" "immich-app/immich" "tarball" "v3.0.2" "$SRC_DIR" PNPM_VERSION="$(jq -r '.packageManager | split("@")[1] | split("+")[0]' ${SRC_DIR}/package.json)" export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 NODE_VERSION="24" NODE_MODULE="corepack" setup_nodejs @@ -437,6 +437,27 @@ cd "$INSTALL_DIR" ln -s "$GEO_DIR" "$APP_DIR" msg_ok "Installed GeoNames data" +# MickLesk temporary patch for HEIC thumbnail gen +msg_info "Patching media.repository.js" +MEDIA_REPO_JS="/opt/immich/app/dist/repositories/media.repository.js" +if [[ -f "$MEDIA_REPO_JS" ]]; then + python3 - <<'PY' +from pathlib import Path +p = Path('/opt/immich/app/dist/repositories/media.repository.js') +s = p.read_text() +old = "(0, sharp_1.default)(input).metadata()" +new = "(0, sharp_1.default)(input, { unlimited: true, limitInputPixels: false }).metadata()" +if new in s: + print('hotfix already there') +elif old in s: + p.write_text(s.replace(old, new, 1)) + print('hotfix applied') +else: + print('pattern not found, skipped') +PY +fi +msg_ok "Patched media.repository.js" + mkdir -p /var/log/immich touch /var/log/immich/{web.log,ml.log} msg_ok "Installed Immich" From 962c040f441383e70fb6089ba4bb7b3eb29ae0ba Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 12 Jul 2026 15:49:09 +0000 Subject: [PATCH 075/245] Update CHANGELOG.md (#15721) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09c1e41bd..029dc05ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -504,6 +504,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-12 +### 🚀 Updated Scripts + + - Immich: Bump version to 3.0.2 [@vhsdream](https://github.com/vhsdream) ([#15668](https://github.com/community-scripts/ProxmoxVE/pull/15668)) + ## 2026-07-11 ### 🆕 New Scripts From 48483c63b8cb9543ecec4fade1c98dec7838f223 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Jul 2026 18:24:19 +0200 Subject: [PATCH 076/245] fix(immich): correct Python indentation error in ct/immich.sh heredoc patch (#15723) * Initial plan * fix: correct Python indentation in immich heredoc patch (ct/immich.sh) --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- ct/immich.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/immich.sh b/ct/immich.sh index 1aa7e0546..fd3d60a94 100644 --- a/ct/immich.sh +++ b/ct/immich.sh @@ -340,10 +340,10 @@ old = "(0, sharp_1.default)(input).metadata()" new = "(0, sharp_1.default)(input, { unlimited: true, limitInputPixels: false }).metadata()" if new in s: print('hotfix already there') - elif old in s: +elif old in s: p.write_text(s.replace(old, new, 1)) print('hotfix applied') - else: +else: print('pattern not found, skipped') PY fi From 0a7bd0f37ed3a16235abd63054a2b5d204f2e47e Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 12 Jul 2026 16:24:42 +0000 Subject: [PATCH 077/245] Update CHANGELOG.md (#15724) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 029dc05ad..b3b0bf2fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -508,6 +508,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Immich: Bump version to 3.0.2 [@vhsdream](https://github.com/vhsdream) ([#15668](https://github.com/community-scripts/ProxmoxVE/pull/15668)) +### ❔ Uncategorized + + - fix(immich): correct Python indentation error in ct/immich.sh heredoc patch [@Copilot](https://github.com/Copilot) ([#15723](https://github.com/community-scripts/ProxmoxVE/pull/15723)) + ## 2026-07-11 ### 🆕 New Scripts From f7fdf419b10b2fc4a5e55b0e153d433a3f6c431f Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Sun, 12 Jul 2026 23:22:39 +0200 Subject: [PATCH 078/245] AFFiNE (#15690) --- ct/affine.sh | 127 ++++++++++++++++++++++ ct/headers/affine | 6 ++ install/affine-install.sh | 215 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 348 insertions(+) create mode 100644 ct/affine.sh create mode 100644 ct/headers/affine create mode 100644 install/affine-install.sh diff --git a/ct/affine.sh b/ct/affine.sh new file mode 100644 index 000000000..ff8562073 --- /dev/null +++ b/ct/affine.sh @@ -0,0 +1,127 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/toeverything/AFFiNE + +APP="AFFiNE" +var_tags="${var_tags:-knowledge;notes;workspace}" +var_cpu="${var_cpu:-4}" +var_ram="${var_ram:-8192}" +var_disk="${var_disk:-20}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-no}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/affine ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "affine_app" "toeverything/AFFiNE"; then + msg_info "Stopping Services" + systemctl stop affine-web affine-worker + msg_ok "Stopped Services" + + create_backup /root/.affine/config /root/.affine/storage + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "latest" "/opt/affine" + + msg_info "Rebuilding Application (Patience)" + cd /opt/affine + source /root/.profile + export PATH="/root/.cargo/bin:/root/.rbenv/shims:$PATH" + + set -a && source /opt/affine/.env && set +a + + export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 + export VITE_CORE_COMMIT_SHA=$(cat ~/.affine_app) + + # Initialize git repo (required for build process) + $STD git init -q + $STD git config user.email "build@local" + $STD git config user.name "Build" + $STD git add -A + $STD git commit -q -m "update" + + # Force Turbo to run sequentially + mkdir -p /opt/affine/.turbo + cat </opt/affine/.turbo/config.json +{ + "concurrency": 1 +} +TURBO + + $STD corepack enable + $STD corepack prepare yarn@4.12.0 --activate + $STD yarn config set enableTelemetry 0 + + export NODE_OPTIONS="--max-old-space-size=2048" + $STD yarn install + $STD npm install -g typescript + + $STD yarn affine @affine/native build + $STD yarn affine @affine/server-native build + + # Create architecture-specific symlinks + ln -sf /opt/affine/packages/backend/native/server-native.node \ + /opt/affine/packages/backend/native/server-native.x64.node + ln -sf /opt/affine/packages/backend/native/server-native.node \ + /opt/affine/packages/backend/native/server-native.arm64.node + ln -sf /opt/affine/packages/backend/native/server-native.node \ + /opt/affine/packages/backend/native/server-native.armv7.node + + $STD yarn affine init + $STD yarn affine build -p @affine/reader + $STD yarn affine build -p @affine/server + + export NODE_OPTIONS="--max-old-space-size=4096" + $STD yarn affine build -p @affine/web + $STD yarn affine build -p @affine/admin + + # Copy web assets + mkdir -p /opt/affine/packages/backend/server/static + cp -r /opt/affine/packages/frontend/apps/web/dist/* /opt/affine/packages/backend/server/static/ + mkdir -p /opt/affine/packages/backend/server/static/admin + cp -r /opt/affine/packages/frontend/admin/dist/* /opt/affine/packages/backend/server/static/admin/ + + # Mobile manifest placeholder + mkdir -p /opt/affine/packages/backend/server/static/mobile + echo '{"publicPath":"/","js":[],"css":[],"gitHash":"","description":""}' \ + >/opt/affine/packages/backend/server/static/mobile/assets-manifest.json + + # Run migrations + cd /opt/affine/packages/backend/server + set -a && source /opt/affine/.env && set +a + $STD node ./scripts/self-host-predeploy.js + + restore_backup + + msg_info "Starting Services" + systemctl start affine-web affine-worker + msg_ok "Started Services" + msg_ok "Updated Successfully!" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:3010/sign-in${CL}" diff --git a/ct/headers/affine b/ct/headers/affine new file mode 100644 index 000000000..0e1d759f0 --- /dev/null +++ b/ct/headers/affine @@ -0,0 +1,6 @@ + ___ _____________ _ ________ + / | / ____/ ____(_) | / / ____/ + / /| | / /_ / /_ / / |/ / __/ + / ___ |/ __/ / __/ / / /| / /___ +/_/ |_/_/ /_/ /_/_/ |_/_____/ + diff --git a/install/affine-install.sh b/install/affine-install.sh new file mode 100644 index 000000000..2e29234b6 --- /dev/null +++ b/install/affine-install.sh @@ -0,0 +1,215 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/toeverything/AFFiNE + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt install -y \ + build-essential \ + git \ + pkg-config \ + openssl \ + libssl-dev \ + libjemalloc2 \ + redis-server \ + nginx +msg_ok "Installed Dependencies" + +PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql +PG_DB_NAME="affine" PG_DB_USER="affine" setup_postgresql_db +NODE_VERSION="22" setup_nodejs +setup_rust + +fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "latest" "/opt/affine" + +msg_info "Setting up Directories" +rm -rf /root/.affine +mkdir -p /root/.affine/{storage,config} +msg_ok "Set up Directories" + +msg_info "Configuring Environment" +SECRET_KEY=$(openssl rand -hex 32) +cat </opt/affine/.env +NODE_ENV=production +AFFINE_SERVER_PORT=3010 +AFFINE_SERVER_HOST=${LOCAL_IP} +AFFINE_SERVER_EXTERNAL_URL=http://${LOCAL_IP} +DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME} +REDIS_SERVER_HOST=localhost +REDIS_SERVER_PORT=6379 +AFFINE_INDEXER_ENABLED=false +SECRET_KEY=${SECRET_KEY} +EOF +msg_ok "Configured Environment" + +msg_info "Building AFFiNE (Patience)" +cd /opt/affine +source /root/.profile +export PATH="/root/.cargo/bin:$PATH" +export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 +export VITE_CORE_COMMIT_SHA=$(cat ~/.affine_app) +# # Initialize git repo (required for build process) +$STD git init -q +$STD git config user.email "build@local" +$STD git config user.name "Build" +$STD git add -A +$STD git commit -q -m "initial" +mkdir -p /opt/affine/.turbo +cat </opt/affine/.turbo/config.json +{ + "concurrency": 1 +} +TURBO +$STD corepack enable +$STD corepack prepare yarn@4.12.0 --activate +$STD yarn config set enableTelemetry 0 +export NODE_OPTIONS="--max-old-space-size=4096" +export TSC_COMPILE_ON_ERROR=true +$STD yarn install +$STD npm install -g typescript +$STD yarn affine @affine/native build +$STD yarn affine @affine/server-native build + +# Create architecture-specific symlinks for server-native +ln -sf /opt/affine/packages/backend/native/server-native.node \ + /opt/affine/packages/backend/native/server-native.x64.node +ln -sf /opt/affine/packages/backend/native/server-native.node \ + /opt/affine/packages/backend/native/server-native.arm64.node +ln -sf /opt/affine/packages/backend/native/server-native.node \ + /opt/affine/packages/backend/native/server-native.armv7.node + +$STD yarn affine init +$STD yarn affine build -p @affine/reader +$STD yarn affine build -p @affine/server +export NODE_OPTIONS="--max-old-space-size=4096" +$STD yarn affine build -p @affine/web +$STD yarn affine build -p @affine/admin +mkdir -p /opt/affine/packages/backend/server/static +cp -r /opt/affine/packages/frontend/apps/web/dist/* /opt/affine/packages/backend/server/static/ +mkdir -p /opt/affine/packages/backend/server/static/admin +cp -r /opt/affine/packages/frontend/admin/dist/* /opt/affine/packages/backend/server/static/admin/ +# Create empty mobile manifest (server expects it but we don't build mobile) +mkdir -p /opt/affine/packages/backend/server/static/mobile +cat <<'MANIFEST' >/opt/affine/packages/backend/server/static/mobile/assets-manifest.json +{"publicPath":"/","js":[],"css":[],"gitHash":"","description":""} +MANIFEST +msg_ok "Built AFFiNE" + +msg_info "Running Initial Migration" +cd /opt/affine/packages/backend/server +set -a && source /opt/affine/.env && set +a +$STD node ./scripts/self-host-predeploy.js +msg_ok "Ran Initial Migration" + +msg_info "Creating Services" +cat </etc/systemd/system/affine-web.service +[Unit] +Description=AFFiNE Web Server +After=network.target postgresql.service redis-server.service +Requires=postgresql.service redis-server.service + +[Service] +Type=simple +WorkingDirectory=/opt/affine/packages/backend/server +EnvironmentFile=/opt/affine/.env +Environment=LD_PRELOAD=libjemalloc.so.2 +Environment=NODE_OPTIONS=--max-old-space-size=1024 +ExecStart=/usr/bin/node ./dist/main.js +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +EOF + +cat </etc/systemd/system/affine-worker.service +[Unit] +Description=AFFiNE Background Worker +After=network.target postgresql.service redis-server.service +Requires=postgresql.service redis-server.service + +[Service] +Type=simple +WorkingDirectory=/opt/affine/packages/backend/server +EnvironmentFile=/opt/affine/.env +Environment=LD_PRELOAD=libjemalloc.so.2 +Environment=NODE_OPTIONS=--max-old-space-size=1024 +ExecStart=/usr/bin/node ./dist/main.js --worker +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +EOF + +systemctl enable -q --now redis-server affine-web affine-worker +msg_ok "Created Services" + +msg_info "Creating Admin User" +ADMIN_PASS=$(openssl rand -base64 12) +for i in {1..30}; do + if curl -s http://localhost:3010/info >/dev/null 2>&1; then + break + fi + sleep 2 +done +# Create admin via API +ADMIN_RESPONSE=$(curl -s -X POST http://localhost:3010/api/setup/create-admin-user \ + -H "Content-Type: application/json" \ + -d "{\"email\":\"admin@affine.local\",\"password\":\"${ADMIN_PASS}\"}") +if echo "$ADMIN_RESPONSE" | grep -q '"id"'; then + { + echo "AFFiNE Credentials" + echo "==================" + echo "Email: admin@affine.local" + echo "Password: ${ADMIN_PASS}" + } >~/affine.creds + msg_ok "Created Admin User" +else + msg_warn "Admin creation skipped (may already exist)" +fi + +msg_info "Configuring Nginx" +cat </etc/nginx/sites-available/affine.conf +upstream affine_backend { + server 127.0.0.1:3010; +} + +server { + listen 80; + server_name _; + + client_max_body_size 100M; + + location / { + proxy_pass http://affine_backend; + proxy_http_version 1.1; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_redirect off; + proxy_buffering off; + } +} +EOF +ln -sf /etc/nginx/sites-available/affine.conf /etc/nginx/sites-enabled/ +rm -f /etc/nginx/sites-enabled/default +systemctl enable -q --now nginx +msg_ok "Configured Nginx" + +motd_ssh +customize +cleanup_lxc From eb3fb749df39fd4adf58ce9f71c499572857257c Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 12 Jul 2026 21:22:59 +0000 Subject: [PATCH 079/245] Update CHANGELOG.md (#15727) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3b0bf2fb..7e289b0f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -504,6 +504,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-12 +### 🆕 New Scripts + + - AFFiNE ([#15690](https://github.com/community-scripts/ProxmoxVE/pull/15690)) + ### 🚀 Updated Scripts - Immich: Bump version to 3.0.2 [@vhsdream](https://github.com/vhsdream) ([#15668](https://github.com/community-scripts/ProxmoxVE/pull/15668)) From fd20ed1bfc479b89334b5176131e0c794e2d3a5f Mon Sep 17 00:00:00 2001 From: Tobias <96661824+CrazyWolf13@users.noreply.github.com> Date: Mon, 13 Jul 2026 11:05:11 +0200 Subject: [PATCH 080/245] reitti: update to v5 (#15635) --- ct/reitti.sh | 84 +++++++++++++++++++++++++++++++++++---- install/reitti-install.sh | 44 +++++++++++++------- 2 files changed, 106 insertions(+), 22 deletions(-) diff --git a/ct/reitti.sh b/ct/reitti.sh index f160176d4..5980e6ae7 100644 --- a/ct/reitti.sh +++ b/ct/reitti.sh @@ -106,13 +106,6 @@ spring.servlet.multipart.max-file-size=5GB spring.servlet.multipart.max-request-size=5GB server.tomcat.max-part-count=100 -# Rqueue configuration -rqueue.web.enable=false -rqueue.job.enabled=false -rqueue.message.durability.in-terminal-state=0 -rqueue.key.prefix=\${spring.cache.redis.key-prefix} -rqueue.message.converter.provider.class=com.dedicatedcode.reitti.config.RQueueCustomMessageConverter - # Application-specific settings reitti.server.advertise-uri= @@ -168,6 +161,81 @@ PROPEOF msg_ok "Rewrote application.properties (backup: application.properties.bak)" fi + # Migrate v4 -> v5: Remove Rqueue configuration (replaced by Quartz Scheduler) + if grep -q "^rqueue\." /opt/reitti/application.properties 2>/dev/null; then + msg_info "Migrating to v5: Removing Rqueue configuration" + sed -i '/^# Rqueue configuration$/d; /^rqueue\./d' /opt/reitti/application.properties + msg_ok "Removed Rqueue configuration" + fi + + # Migrate v4 -> v5: Update application.properties and nginx tile cache for v5 compatibility + if grep -q "^reitti\.process-data\.schedule=" /opt/reitti/application.properties 2>/dev/null; then + msg_info "Migrating to v5: Updating application.properties" + sed -i '/^reitti\.process-data\.schedule=/d' /opt/reitti/application.properties + sed -i 's/^reitti\.import\.processing-idle-start-time=.*/reitti.import.grace-time-seconds=30/' /opt/reitti/application.properties + sed -i 's/^spring\.datasource\.hikari\.maximum-pool-size=20$/spring.datasource.hikari.maximum-pool-size=30/' /opt/reitti/application.properties + grep -q "devices" /opt/reitti/application.properties || \ + sed -i 's/^spring\.cache\.cache-names=\(.*\)$/spring.cache.cache-names=\1,devices,mapStyles,mapStyleJson/' /opt/reitti/application.properties + grep -q "org.quartz.core.ErrorLogger" /opt/reitti/application.properties || \ + sed -i '/^logging\.level\.com\.dedicatedcode\.reitti=/a logging.level.org.quartz.core.ErrorLogger=FATAL' /opt/reitti/application.properties + grep -q "^spring.servlet.multipart.resolve-lazily=" /opt/reitti/application.properties || \ + sed -i '/^spring\.servlet\.multipart\.max-request-size=/a spring.servlet.multipart.resolve-lazily=true' /opt/reitti/application.properties + grep -q "^spring.mvc.async.request-timeout=" /opt/reitti/application.properties || \ + echo "spring.mvc.async.request-timeout=600000" >>/opt/reitti/application.properties + if ! grep -q "^spring.quartz" /opt/reitti/application.properties; then + cat >>/opt/reitti/application.properties <<'QUARTZEOF' + +# Quartz Scheduler configuration +spring.quartz.job-store-type=jdbc +spring.quartz.jdbc.initialize-schema=never +spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate +spring.quartz.properties.org.quartz.jobStore.isClustered=false +spring.quartz.properties.org.quartz.jobStore.tablePrefix=qrtz_ +spring.quartz.properties.org.quartz.threadPool.threadCount=5 +QUARTZEOF + fi + grep -q "^reitti.import.staging.cleanup.cron=" /opt/reitti/application.properties || \ + echo "reitti.import.staging.cleanup.cron=0 0 4 * * *" >>/opt/reitti/application.properties + grep -q "^reitti.batching.max-batch-size=" /opt/reitti/application.properties || \ + printf "reitti.batching.max-batch-size=100\nreitti.batching.max-wait-time=5\n" >>/opt/reitti/application.properties + grep -q "^reitti.jobs.cleanup.cron=" /opt/reitti/application.properties || \ + printf "reitti.jobs.cleanup.cron=0 0 4 * * ?\nreitti.jobs.cleanup.max-age-hours=24\n" >>/opt/reitti/application.properties + grep -q "^reitti.db-janitor.schedule=" /opt/reitti/application.properties || \ + echo "reitti.db-janitor.schedule=0 0 4 * * ?" >>/opt/reitti/application.properties + msg_ok "Updated application.properties for v5" + + if [[ -f /etc/nginx/nginx.conf ]]; then + msg_info "Migrating to v5: Updating nginx tile cache configuration" + cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.v5 + cat >/etc/nginx/nginx.conf <<'NGINXEOF' +user www-data; + +events { + worker_connections 1024; +} +http { + resolver 1.1.1.1 8.8.8.8 valid=30s ipv6=off; + proxy_cache_path /var/cache/nginx/tiles levels=1:2 keys_zone=tiles:10m max_size=1g inactive=30d use_temp_path=off; + server { + listen 80; + location /custom/ { + set $upstream_url $http_x_reitti_upstream_url; + proxy_pass $upstream_url; + proxy_set_header Host $proxy_host; + proxy_set_header User-Agent "Reitti/1.0"; + proxy_cache tiles; + proxy_cache_key $upstream_url; + proxy_cache_valid 200 30d; + proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; + } + } +} +NGINXEOF + systemctl reload nginx + msg_ok "Updated nginx tile cache configuration" + fi + fi + if check_for_gh_release "reitti" "dedicatedcode/reitti"; then msg_info "Stopping Service" systemctl stop reitti @@ -179,10 +247,12 @@ PROPEOF USE_ORIGINAL_FILENAME="true" fetch_and_deploy_gh_release "reitti" "dedicatedcode/reitti" "singlefile" "latest" "/opt/reitti" "reitti-app.jar" mv /opt/reitti/reitti-*.jar /opt/reitti/reitti.jar + msg_warn "v5 runs a one-time database migration on first start (GPS points → device table). This may take several minutes on large datasets — do not interrupt the container." msg_info "Starting Service" systemctl start reitti msg_ok "Started Service" msg_ok "Updated successfully!" + msg_warn "Post-upgrade: Verify each API token has a Device assigned in Settings → API Tokens. Tokens without a device cannot ingest location data in v5." fi exit } diff --git a/install/reitti-install.sh b/install/reitti-install.sh index 2810b1495..512b0cd13 100644 --- a/install/reitti-install.sh +++ b/install/reitti-install.sh @@ -30,27 +30,30 @@ mv /opt/reitti/reitti-*.jar /opt/reitti/reitti.jar msg_info "Installing Nginx Tile Cache" mkdir -p /var/cache/nginx/tiles -cat </etc/nginx/nginx.conf +cat <<'NGINXEOF' >/etc/nginx/nginx.conf user www-data; events { worker_connections 1024; } http { + resolver 1.1.1.1 8.8.8.8 valid=30s ipv6=off; proxy_cache_path /var/cache/nginx/tiles levels=1:2 keys_zone=tiles:10m max_size=1g inactive=30d use_temp_path=off; server { listen 80; - location / { - proxy_pass https://tile.openstreetmap.org/; - proxy_set_header Host tile.openstreetmap.org; + location /custom/ { + set $upstream_url $http_x_reitti_upstream_url; + proxy_pass $upstream_url; + proxy_set_header Host $proxy_host; proxy_set_header User-Agent "Reitti/1.0"; proxy_cache tiles; + proxy_cache_key $upstream_url; proxy_cache_valid 200 30d; proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; } } } -EOF +NGINXEOF chown -R www-data:www-data /var/cache/nginx chmod -R 750 /var/cache/nginx systemctl restart nginx @@ -71,6 +74,7 @@ server.compression.mime-types=text/plain,application/json logging.level.root=INFO logging.level.org.hibernate.engine.jdbc.spi.SqlExceptionHelper=FATAL logging.level.com.dedicatedcode.reitti=INFO +logging.level.org.quartz.core.ErrorLogger=FATAL # Internationalization spring.messages.basename=messages @@ -82,7 +86,7 @@ spring.messages.fallback-to-system-locale=false spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/$PG_DB_NAME spring.datasource.username=$PG_DB_USER spring.datasource.password=$PG_DB_PASS -spring.datasource.hikari.maximum-pool-size=20 +spring.datasource.hikari.maximum-pool-size=30 # Redis configuration spring.data.redis.host=127.0.0.1 @@ -92,20 +96,23 @@ spring.data.redis.password= spring.data.redis.database=0 spring.cache.redis.key-prefix= -spring.cache.cache-names=processed-visits,significant-places,users,magic-links,configurations,transport-mode-configs,avatarThumbnails,avatarData,user-settings +spring.cache.cache-names=processed-visits,significant-places,users,magic-links,configurations,transport-mode-configs,avatarThumbnails,avatarData,user-settings,devices,mapStyles,mapStyleJson spring.cache.redis.time-to-live=1d # Upload configuration spring.servlet.multipart.max-file-size=5GB spring.servlet.multipart.max-request-size=5GB +spring.servlet.multipart.resolve-lazily=true server.tomcat.max-part-count=100 +spring.mvc.async.request-timeout=600000 -# Rqueue configuration -rqueue.web.enable=false -rqueue.job.enabled=false -rqueue.message.durability.in-terminal-state=0 -rqueue.key.prefix=\${spring.cache.redis.key-prefix} -rqueue.message.converter.provider.class=com.dedicatedcode.reitti.config.RQueueCustomMessageConverter +# Quartz Scheduler configuration +spring.quartz.job-store-type=jdbc +spring.quartz.jdbc.initialize-schema=never +spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate +spring.quartz.properties.org.quartz.jobStore.isClustered=false +spring.quartz.properties.org.quartz.jobStore.tablePrefix=qrtz_ +spring.quartz.properties.org.quartz.threadPool.threadCount=5 # Application-specific settings reitti.server.advertise-uri= @@ -117,18 +124,25 @@ reitti.security.oidc.enabled=false reitti.security.oidc.registration.enabled=false reitti.import.batch-size=10000 -reitti.import.processing-idle-start-time=10 +reitti.import.grace-time-seconds=30 +reitti.import.staging.cleanup.cron=0 0 4 * * * + +reitti.batching.max-batch-size=100 +reitti.batching.max-wait-time=5 reitti.geo-point-filter.max-speed-kmh=1000 reitti.geo-point-filter.max-accuracy-meters=100 reitti.geo-point-filter.history-lookback-hours=24 reitti.geo-point-filter.window-size=50 -reitti.process-data.schedule=0 */10 * * * * reitti.process-data.refresh-views.schedule=0 0 4 * * * reitti.imports.schedule=0 5/10 * * * * reitti.imports.owntracks-recorder.schedule=\${reitti.imports.schedule} +reitti.jobs.cleanup.cron=0 0 4 * * ? +reitti.jobs.cleanup.max-age-hours=24 +reitti.db-janitor.schedule=0 0 4 * * ? + # Geocoding service configuration reitti.geocoding.max-errors=10 reitti.geocoding.photon.base-url= From fae0aacf6d8c227c32920e6e2e2870fd4a427501 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 09:05:39 +0000 Subject: [PATCH 081/245] Update CHANGELOG.md (#15731) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e289b0f1..0035efcd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -502,6 +502,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-13 + +### 🚀 Updated Scripts + + - #### 💥 Breaking Changes + + - reitti: update to v5 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15635](https://github.com/community-scripts/ProxmoxVE/pull/15635)) + ## 2026-07-12 ### 🆕 New Scripts From 12949bce6c4f8af2909e2bcecb1d0cd8c452be10 Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Mon, 13 Jul 2026 11:10:49 +0200 Subject: [PATCH 082/245] fix(build.func): parse script status without jq dependency (#15729) Replace jq-based PocketBase status parsing with sed/grep so disabled and deleted script checks work on hosts that do not have jq installed yet. --- misc/build.func | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/misc/build.func b/misc/build.func index bf74bd3b6..93fced258 100644 --- a/misc/build.func +++ b/misc/build.func @@ -3764,19 +3764,18 @@ runtime_script_status_guard() { return 0 fi - if ! command -v jq >/dev/null 2>&1; then - msg_warn "Missing jq for script status check. Continuing without status verification." + local is_deleted is_disabled deleted_message disable_message info_url + if printf '%s' "$response" | grep -qE '"items":[[:space:]]*\[[[:space:]]*\]'; then return 0 fi - local has_record is_deleted is_disabled deleted_message disable_message info_url - has_record=$(printf '%s' "$response" | jq -r '.items | length') - [[ "$has_record" == "0" ]] && return 0 - - is_deleted=$(printf '%s' "$response" | jq -r '.items[0].is_deleted // false') - is_disabled=$(printf '%s' "$response" | jq -r '.items[0].is_disabled // false') - deleted_message=$(printf '%s' "$response" | jq -r '.items[0].deleted_message // ""') - disable_message=$(printf '%s' "$response" | jq -r '.items[0].disable_message // ""') + # PocketBase returns a flat, fixed-field JSON blob; sed is enough here (no jq needed). + is_deleted=$(printf '%s' "$response" | sed -n 's/.*"is_deleted"[[:space:]]*:[[:space:]]*\(true\|false\).*/\1/p' | head -1) + is_disabled=$(printf '%s' "$response" | sed -n 's/.*"is_disabled"[[:space:]]*:[[:space:]]*\(true\|false\).*/\1/p' | head -1) + deleted_message=$(printf '%s' "$response" | sed -n 's/.*"deleted_message"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) + disable_message=$(printf '%s' "$response" | sed -n 's/.*"disable_message"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) + is_deleted=${is_deleted:-false} + is_disabled=${is_disabled:-false} info_url="https://community-scripts.org/scripts/${script_slug}" if [[ "$is_deleted" == "true" ]]; then From a1333222a806c9022685503469e11ac2140ef7d4 Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Mon, 13 Jul 2026 11:11:08 +0200 Subject: [PATCH 083/245] fix(shinobi): remove obsolete --unsafe-perm npm flag (#15730) Shinobi installs fail on Node.js 22 because npm 10 no longer accepts the --unsafe-perm CLI flag during npm install. --- install/shinobi-install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/shinobi-install.sh b/install/shinobi-install.sh index 383325016..6107c6488 100644 --- a/install/shinobi-install.sh +++ b/install/shinobi-install.sh @@ -54,7 +54,7 @@ cronKey=$(head -c 1024 Date: Mon, 13 Jul 2026 09:11:16 +0000 Subject: [PATCH 084/245] Update CHANGELOG.md (#15733) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0035efcd9..51866c189 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -510,6 +510,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - reitti: update to v5 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15635](https://github.com/community-scripts/ProxmoxVE/pull/15635)) +### 💾 Core + + - #### 🐞 Bug Fixes + + - fix(build.func): parse script status without jq dependency [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15729](https://github.com/community-scripts/ProxmoxVE/pull/15729)) + ## 2026-07-12 ### 🆕 New Scripts From 4a98e86db159d2e3bc56c76ff59576d97506f5cf Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 09:11:36 +0000 Subject: [PATCH 085/245] Update CHANGELOG.md (#15734) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51866c189..a0c2ce581 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -506,6 +506,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🚀 Updated Scripts + - #### 🐞 Bug Fixes + + - fix(shinobi): remove obsolete --unsafe-perm npm flag [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15730](https://github.com/community-scripts/ProxmoxVE/pull/15730)) + - #### 💥 Breaking Changes - reitti: update to v5 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15635](https://github.com/community-scripts/ProxmoxVE/pull/15635)) From f828e629b5c6ceb1a583ae992d5039740b8da433 Mon Sep 17 00:00:00 2001 From: TowyTowy <85077986+TowyTowy@users.noreply.github.com> Date: Mon, 13 Jul 2026 11:12:10 +0200 Subject: [PATCH 086/245] fix(hyperion): keep service running after container reboot (#15653) * fix(hyperion): keep service running after container reboot The packaged hyperion@.service declares "Requisite=network.target" but is not ordered After=network.target. Inside an LXC the unit's start job can be evaluated before network.target is active, and because Requisite= is stricter than Requires= (it does not pull the unit in or wait for it) the job fails with "Dependency failed", so Hyperion does not start after a reboot. Add a systemd drop-in that clears Requisite=; ordering is still provided by the base unit's Wants=/After=network-online.target. Co-Authored-By: Claude Fable 5 * Fix Hyperion service startup issue in LXC Remove Requisite from Hyperion service to ensure it starts correctly in LXC environments. --------- Co-authored-by: Claude Fable 5 Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com> --- install/hyperion-install.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/install/hyperion-install.sh b/install/hyperion-install.sh index db5bf301f..b58798f96 100644 --- a/install/hyperion-install.sh +++ b/install/hyperion-install.sh @@ -24,6 +24,12 @@ msg_ok "Set up Hyperion repository" msg_info "Installing Hyperion" $STD apt install -y hyperion +mkdir -p /etc/systemd/system/hyperion@.service.d +cat </etc/systemd/system/hyperion@.service.d/override.conf +[Unit] +Requisite= +EOF +systemctl daemon-reload systemctl enable -q --now hyperion@root msg_ok "Installed Hyperion" From 1e7667e5f80c19ce960b239922dac8b755923479 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 09:12:36 +0000 Subject: [PATCH 087/245] Update CHANGELOG.md (#15735) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0c2ce581..2fd3b3fb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -506,6 +506,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🚀 Updated Scripts + - fix(hyperion): keep service running after container reboot [@TowyTowy](https://github.com/TowyTowy) ([#15653](https://github.com/community-scripts/ProxmoxVE/pull/15653)) + - #### 🐞 Bug Fixes - fix(shinobi): remove obsolete --unsafe-perm npm flag [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15730](https://github.com/community-scripts/ProxmoxVE/pull/15730)) From ca082aedf06eb27d14aaa41e55f4746c8290456b Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 13 Jul 2026 11:31:53 +0200 Subject: [PATCH 088/245] Docmost: Fix update procedure (#15732) Updated messages for configuring and starting the Docmost service. --- ct/docmost.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ct/docmost.sh b/ct/docmost.sh index c3392c585..a9727d6ad 100644 --- a/ct/docmost.sh +++ b/ct/docmost.sh @@ -39,7 +39,6 @@ function update_script() { create_backup /opt/docmost/.env \ /opt/docmost/data - fetch_and_deploy_gh_release "docmost" "docmost/docmost" "tarball" restore_backup @@ -54,9 +53,11 @@ function update_script() { sed -i '/^@Module({$/i @Global()' /opt/docmost/apps/server/src/core/core.module.ts fi + msg_insfo "Configuring Docmost" + cd /opt/docmost $STD pnpm install --force $STD pnpm build - msg_ok "Updated ${APP}" + msg_ok "Configured Docmost" msg_info "Starting Service" systemctl start docmost From 81bb9c7d71b8fa7903ceec1286db1092cbf9e584 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 09:32:19 +0000 Subject: [PATCH 089/245] Update CHANGELOG.md (#15737) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fd3b3fb0..161a3dfca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -510,6 +510,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - Docmost: Fix update procedure [@MickLesk](https://github.com/MickLesk) ([#15732](https://github.com/community-scripts/ProxmoxVE/pull/15732)) - fix(shinobi): remove obsolete --unsafe-perm npm flag [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15730](https://github.com/community-scripts/ProxmoxVE/pull/15730)) - #### 💥 Breaking Changes From 649e66ed2bd5d08dbe0566022099ac3d13582364 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 13 Jul 2026 11:37:39 +0200 Subject: [PATCH 090/245] tools.func: some improvements (sql injection / command injection / guard) (#15661) * Update tools.func - Add _TOOLS_FUNC_LOADED guard to prevent double-sourcing - Remove duplicate is_alpine() (core.func version is more robust) - Fix end_timer: now actually outputs duration (was silent) - Fix SQL injection in setup_mariadb_db: escape single quotes in identifiers - Fix SQL injection in setup_postgresql_db: escape single quotes in identifiers - Fix sed injection in edit_yaml_config: escape | and & in value - Fix command injection in curl_with_retry: use array instead of string eval - Fix command injection in curl_api_with_retry: use array instead of string eval * Update misc/tools.func Co-authored-by: Sam Heinz --------- Co-authored-by: Sam Heinz --- misc/tools.func | 53 +++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/misc/tools.func b/misc/tools.func index 9360535a3..53486628b 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -36,6 +36,10 @@ # # ============================================================================== +# Guard against double-sourcing (core.func uses the same pattern) +[[ -n "${_TOOLS_FUNC_LOADED:-}" ]] && return 0 +_TOOLS_FUNC_LOADED=1 + # ------------------------------------------------------------------------------ # Debug helper - outputs to stderr when TOOLS_DEBUG is enabled # Usage: debug_log "message" @@ -91,16 +95,17 @@ curl_with_retry() { while [[ $attempt -le $retries ]]; do debug_log "curl attempt $attempt/$retries: $url" - local curl_cmd="curl -fsSL --connect-timeout $connect_timeout --max-time $timeout" - [[ -n "$extra_opts" ]] && curl_cmd="$curl_cmd $extra_opts" + # Build curl command as array to avoid command injection via extra_opts + local -a curl_args=(curl -fsSL --connect-timeout "$connect_timeout" --max-time "$timeout") + [[ -n "$extra_opts" ]] && read -ra _extra <<<"$extra_opts" && curl_args+=("${_extra[@]}") if [[ "$output" == "-" ]]; then - if $curl_cmd "$url"; then + if "${curl_args[@]}" "$url"; then success=true break fi else - if $curl_cmd -o "$output" "$url"; then + if "${curl_args[@]}" -o "$output" "$url"; then success=true break fi @@ -153,15 +158,16 @@ curl_api_with_retry() { while [[ $attempt -le $retries ]]; do debug_log "curl API attempt $attempt/$retries: $url" - local curl_cmd="curl -fsSL --connect-timeout $connect_timeout --max-time $timeout -w '%{http_code}'" - [[ -n "$extra_opts" ]] && curl_cmd="$curl_cmd $extra_opts" + # Build curl command as array to avoid command injection via extra_opts + local -a curl_args=(curl -fsSL --connect-timeout "$connect_timeout" --max-time "$timeout" -w '%{http_code}') + [[ -n "$extra_opts" ]] && read -ra _extra <<<"$extra_opts" && curl_args+=("${_extra[@]}") if [[ -n "$body_file" ]]; then - http_code=$($curl_cmd -o "$body_file" "$url" 2>/dev/null) || true + http_code=$("${curl_args[@]}" -o "$body_file" "$url" 2>/dev/null) || true else # Capture body and http_code separately local tmp_body="/tmp/curl_api_body_$$" - http_code=$($curl_cmd -o "$tmp_body" "$url" 2>/dev/null) || true + http_code=$("${curl_args[@]}" -o "$tmp_body" "$url" 2>/dev/null) || true if [[ -f "$tmp_body" ]]; then cat "$tmp_body" rm -f "$tmp_body" @@ -304,7 +310,10 @@ edit_yaml_config() { return 1 fi - sed -i "s|^\([[:space:]]*${key}[[:space:]]*:\).*|\1 ${value}|" "$file" + # Escape sed metacharacters in value (| and &) to prevent injection + local escaped_value="${value//|/\\|}" + escaped_value="${escaped_value//&/\\&}" + sed -i "s|^\([[:space:]]*${key}[[:space:]]*:\).*|\1 ${escaped_value}|" "$file" } # ------------------------------------------------------------------------------ @@ -1687,10 +1696,6 @@ is_ubuntu() { [[ "$(get_os_info id)" == "ubuntu" ]] } -is_alpine() { - [[ "$(get_os_info id)" == "alpine" ]] -} - # ------------------------------------------------------------------------------ # Get Debian/Ubuntu major version # ------------------------------------------------------------------------------ @@ -2454,8 +2459,10 @@ start_timer() { end_timer() { local start_time="$1" local label="${2:-Operation}" - local end_time=$(date +%s) + local end_time + end_time=$(date +%s) local duration=$((end_time - start_time)) + echo "${label} took ${duration}s" } # ------------------------------------------------------------------------------ @@ -6939,9 +6946,11 @@ setup_mariadb_db() { msg_info "Setting up MariaDB Database" - $STD mariadb -u root -e "CREATE DATABASE \`$MARIADB_DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" - $STD mariadb -u root -e "CREATE USER '$MARIADB_DB_USER'@'localhost' IDENTIFIED BY '$MARIADB_DB_PASS';" - $STD mariadb -u root -e "GRANT ALL ON \`$MARIADB_DB_NAME\`.* TO '$MARIADB_DB_USER'@'localhost';" + # Use --defaults-extra-file to pass credentials safely and escape identifiers + # to prevent SQL injection via DB name / user / password + $STD mariadb -u root -e "CREATE DATABASE \`${MARIADB_DB_NAME//\`/\`\`}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" + $STD mariadb -u root -e "CREATE USER '${MARIADB_DB_USER//\'/\'\'}'@'localhost' IDENTIFIED BY '${MARIADB_DB_PASS//\'/\'\'}';" + $STD mariadb -u root -e "GRANT ALL ON \`${MARIADB_DB_NAME//\`/\`\`}\`.* TO '${MARIADB_DB_USER//\'/\'\'}'@'localhost';" # Optional extra grants if [[ -n "${MARIADB_DB_EXTRA_GRANTS:-}" ]]; then @@ -8571,8 +8580,14 @@ setup_postgresql_db() { fi msg_info "Setting up PostgreSQL Database" - $STD sudo -u postgres psql -c "CREATE ROLE $PG_DB_USER WITH LOGIN PASSWORD '$PG_DB_PASS';" - $STD sudo -u postgres psql -c "CREATE DATABASE $PG_DB_NAME WITH OWNER $PG_DB_USER ENCODING 'UTF8' TEMPLATE template0;" + # Escape single quotes in identifiers to prevent SQL injection + local _pg_user_escaped _pg_pass_escaped _pg_db_escaped + _pg_user_escaped="${PG_DB_USER//\'/\'\'}" + _pg_pass_escaped="${PG_DB_PASS//\'/\'\'}" + _pg_db_escaped="${PG_DB_NAME//\'/\'\'}" + + $STD sudo -u postgres psql -c "CREATE ROLE $_pg_user_escaped WITH LOGIN PASSWORD '$_pg_pass_escaped';" + $STD sudo -u postgres psql -c "CREATE DATABASE $_pg_db_escaped WITH OWNER $_pg_user_escaped ENCODING 'UTF8' TEMPLATE template0;" # Configure pg_cron database BEFORE creating the extension (must be set before pg_cron loads) if [[ -n "${PG_DB_EXTENSIONS:-}" ]] && [[ ",${PG_DB_EXTENSIONS//[[:space:]]/}," == *",pg_cron,"* ]]; then From d6d8d20c7666730d7be3882a8f0ef0dacc6291e3 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 09:38:01 +0000 Subject: [PATCH 091/245] Update CHANGELOG.md (#15739) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 161a3dfca..fd3880243 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -523,6 +523,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - fix(build.func): parse script status without jq dependency [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15729](https://github.com/community-scripts/ProxmoxVE/pull/15729)) + - #### 🔧 Refactor + + - tools.func: some improvements (sql injection / command injection / guard) [@MickLesk](https://github.com/MickLesk) ([#15661](https://github.com/community-scripts/ProxmoxVE/pull/15661)) + ## 2026-07-12 ### 🆕 New Scripts From 734bb75b126b940edcb69609ea98882e3f2656a9 Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Mon, 13 Jul 2026 11:56:12 +0200 Subject: [PATCH 092/245] fix storyteller release selection for multi-stream tags (#15736) Add optional tag prefix filtering to GitHub/GitLab release helpers and use web-v2 for Storyteller install/update so latest non-web tags no longer break deployment. --- ct/storyteller.sh | 4 +-- install/storyteller-install.sh | 2 +- misc/tools.func | 65 +++++++++++++++++++++++++++++----- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/ct/storyteller.sh b/ct/storyteller.sh index df2f915c9..0e49e0196 100644 --- a/ct/storyteller.sh +++ b/ct/storyteller.sh @@ -32,7 +32,7 @@ function update_script() { NODE_VERSION="24" NODE_MODULE="corepack,yarn" setup_nodejs - if check_for_gl_release "storyteller" "storyteller-platform/storyteller"; then + if check_for_gl_release "storyteller" "storyteller-platform/storyteller" "" "" "web-v2"; then msg_info "Stopping Service" systemctl stop storyteller msg_ok "Stopped Service" @@ -41,7 +41,7 @@ function update_script() { cp /opt/storyteller/.env /opt/storyteller_env.bak msg_ok "Backed up Data" - CLEAN_INSTALL=1 fetch_and_deploy_gl_release "storyteller" "storyteller-platform/storyteller" "tarball" "latest" "/opt/storyteller" + CLEAN_INSTALL=1 fetch_and_deploy_gl_release "storyteller" "storyteller-platform/storyteller" "tarball" "latest" "/opt/storyteller" "" "web-v2" msg_info "Restoring Configuration" mv /opt/storyteller_env.bak /opt/storyteller/.env diff --git a/install/storyteller-install.sh b/install/storyteller-install.sh index b3b343da6..1df32ec27 100644 --- a/install/storyteller-install.sh +++ b/install/storyteller-install.sh @@ -28,7 +28,7 @@ NODE_VERSION="24" NODE_MODULE="corepack,yarn" setup_nodejs fetch_and_deploy_gh_release "readium" "readium/cli" "prebuild" "latest" "/opt/readium" "readium_linux_$(arch_resolve "x86_64" "arm64").tar.gz" ln -sf /opt/readium/readium /usr/local/bin/readium -fetch_and_deploy_gl_release "storyteller" "storyteller-platform/storyteller" "tarball" "latest" "/opt/storyteller" +fetch_and_deploy_gl_release "storyteller" "storyteller-platform/storyteller" "tarball" "latest" "/opt/storyteller" "" "web-v2" msg_info "Setting up Storyteller" cd /opt/storyteller diff --git a/misc/tools.func b/misc/tools.func index 53486628b..4a35c695d 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -2833,6 +2833,7 @@ check_for_gh_release() { local source="$2" local pinned_version_in="${3:-}" # optional local pin_reason="${4:-}" # optional reason shown to user + local tag_prefix="${5:-}" # optional tag prefix filter (e.g. web-v2) local app_lc="" app_lc="$(echo "${app,,}" | tr -d ' ')" local current_file="$HOME/.${app_lc}" @@ -2888,7 +2889,7 @@ check_for_gh_release() { rm -f "$gh_check_json" fi - if [[ -z "$pinned_version_in" ]]; then + if [[ -z "$pinned_version_in" && -z "$tag_prefix" ]]; then http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o "$gh_check_json" \ -H 'Accept: application/vnd.github+json' \ -H 'X-GitHub-Api-Version: 2022-11-28' \ @@ -2916,7 +2917,7 @@ check_for_gh_release() { rm -f "$gh_check_json" fi - # If no releases yet (pinned version OR /latest failed), fetch up to 100 + # If no releases yet (pinned version, tag prefix, OR /latest failed), fetch up to 100 if [[ -z "$releases_json" ]]; then http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o "$gh_check_json" \ -H 'Accept: application/vnd.github+json' \ @@ -2954,9 +2955,18 @@ check_for_gh_release() { rm -f "$gh_check_json" fi - mapfile -t raw_tags < <(jq -r '.[] | select(.draft==false and .prerelease==false) | .tag_name' <<<"$releases_json") + if [[ -n "$tag_prefix" ]]; then + mapfile -t raw_tags < <(jq -r --arg p "$tag_prefix" \ + '.[] | select(.draft==false and .prerelease==false) | select(.tag_name | startswith($p)) | .tag_name' <<<"$releases_json") + else + mapfile -t raw_tags < <(jq -r '.[] | select(.draft==false and .prerelease==false) | .tag_name' <<<"$releases_json") + fi if ((${#raw_tags[@]} == 0)); then - msg_error "No stable releases found for ${app}" + if [[ -n "$tag_prefix" ]]; then + msg_error "No stable releases matching prefix '${tag_prefix}' found for ${app}" + else + msg_error "No stable releases found for ${app}" + fi return 250 fi @@ -3960,6 +3970,7 @@ fetch_and_deploy_gh_release() { local version="${var_appversion:-${4:-latest}}" local target="${5:-/opt/$app}" local asset_pattern="${6:-}" + local tag_prefix="${7:-}" # Validate app name to prevent /root/. directory issues if [[ -z "$app" ]]; then @@ -3989,7 +4000,13 @@ fetch_and_deploy_gh_release() { TOOLS_GH_REL_JSON="$gh_rel_json" local api_url="https://api.github.com/repos/$repo/releases" - [[ "$version" != "latest" ]] && api_url="$api_url/tags/$version" || api_url="$api_url/latest" + if [[ "$version" != "latest" ]]; then + api_url="$api_url/tags/$version" + elif [[ -n "$tag_prefix" ]]; then + api_url="$api_url?per_page=100" + else + api_url="$api_url/latest" + fi local header=() [[ -n "${GITHUB_TOKEN:-}" ]] && header=(-H "Authorization: token $GITHUB_TOKEN") @@ -4052,6 +4069,14 @@ fetch_and_deploy_gh_release() { local json tag_name json=$(<"$gh_rel_json") + if [[ "$version" == "latest" && -n "$tag_prefix" ]]; then + json=$(echo "$json" | jq --arg p "$tag_prefix" \ + '[.[] | select(.draft==false and .prerelease==false) | select(.tag_name | startswith($p))][0] // empty') + if [[ -z "$json" || "$json" == "null" ]]; then + msg_error "No stable release matching prefix '${tag_prefix}' found for $repo on GitHub" + return 1 + fi + fi tag_name=$(echo "$json" | jq -r '.tag_name // .name // empty') # Only strip leading 'v' when followed by a digit (e.g. v1.2.3), not words like "version/..." [[ "$tag_name" =~ ^v[0-9] ]] && version="${tag_name:1}" || version="$tag_name" @@ -9484,6 +9509,7 @@ check_for_gl_release() { local source="$2" local pinned_version_in="${3:-}" # optional local pin_reason="${4:-}" # optional reason shown to user + local tag_prefix="${5:-}" # optional tag prefix filter (e.g. web-v2) local app_lc="${app,,}" local current_file="$HOME/.${app_lc}" @@ -9560,9 +9586,18 @@ check_for_gl_release() { rm -f "$gl_check_json" fi - mapfile -t raw_tags < <(jq -r '.[] | .tag_name' <<<"$releases_json") + if [[ -n "$tag_prefix" ]]; then + mapfile -t raw_tags < <(jq -r --arg p "$tag_prefix" \ + '.[] | select(.tag_name | startswith($p)) | .tag_name' <<<"$releases_json") + else + mapfile -t raw_tags < <(jq -r '.[] | .tag_name' <<<"$releases_json") + fi if ((${#raw_tags[@]} == 0)); then - msg_error "No releases found for ${app} on GitLab" + if [[ -n "$tag_prefix" ]]; then + msg_error "No releases matching prefix '${tag_prefix}' found for ${app} on GitLab" + else + msg_error "No releases found for ${app} on GitLab" + fi return 250 fi @@ -9757,6 +9792,7 @@ fetch_and_deploy_gl_release() { local version="${var_appversion:-${4:-latest}}" local target="${5:-/opt/$app}" local asset_pattern="${6:-}" + local tag_prefix="${7:-}" if [[ -z "$app" ]]; then app="${repo##*/}" @@ -9788,6 +9824,8 @@ fetch_and_deploy_gl_release() { local api_url if [[ "$version" != "latest" ]]; then api_url="$api_base/$version" + elif [[ -n "$tag_prefix" ]]; then + api_url="$api_base?per_page=100&order_by=released_at&sort=desc" else api_url="$api_base?per_page=1&order_by=released_at&sort=desc" fi @@ -9842,9 +9880,18 @@ fetch_and_deploy_gl_release() { json=$(<"$gl_rel_json") if [[ "$version" == "latest" ]]; then - json=$(echo "$json" | jq '.[0] // empty') + if [[ -n "$tag_prefix" ]]; then + json=$(echo "$json" | jq --arg p "$tag_prefix" \ + '[.[] | select(.tag_name | startswith($p))][0] // empty') + else + json=$(echo "$json" | jq '.[0] // empty') + fi if [[ -z "$json" || "$json" == "null" ]]; then - msg_error "No releases found for $repo on GitLab" + if [[ -n "$tag_prefix" ]]; then + msg_error "No release matching prefix '${tag_prefix}' found for $repo on GitLab" + else + msg_error "No releases found for $repo on GitLab" + fi return 1 fi fi From 1521e131b5ecf7d6fea3b54f15d3fd2068da3f77 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 09:56:44 +0000 Subject: [PATCH 093/245] Update CHANGELOG.md (#15740) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd3880243..78b9a1ea3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -510,6 +510,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - fix storyteller release selection for stable web tags [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15736](https://github.com/community-scripts/ProxmoxVE/pull/15736)) - Docmost: Fix update procedure [@MickLesk](https://github.com/MickLesk) ([#15732](https://github.com/community-scripts/ProxmoxVE/pull/15732)) - fix(shinobi): remove obsolete --unsafe-perm npm flag [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15730](https://github.com/community-scripts/ProxmoxVE/pull/15730)) From 7596b95517bfc11fff8aa39e4e0d328f8559e2f5 Mon Sep 17 00:00:00 2001 From: mnavon Date: Mon, 13 Jul 2026 12:59:52 +0300 Subject: [PATCH 094/245] immich: use actual PostgreSQL version for VectorChord package lookup (#15705) * immich: use actual PostgreSQL version for VectorChord package lookup * fix: update PostgreSQL version variable for VectorChord package deployment --- ct/immich.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ct/immich.sh b/ct/immich.sh index fd3d60a94..af15f4e1e 100644 --- a/ct/immich.sh +++ b/ct/immich.sh @@ -125,6 +125,8 @@ EOF systemctl stop immich-ml msg_ok "Stopped Services" VCHORD_RELEASE="1.1.1" + PG_VERSION=$(ls /etc/postgresql/ 2>/dev/null | sort -V | tail -1) + PG_VERSION=${PG_VERSION:-16} [[ -f ~/.vchord_version ]] && mv ~/.vchord_version ~/.vectorchord if check_for_gh_release "VectorChord" "tensorchord/VectorChord" "${VCHORD_RELEASE}" "updated together with Immich after testing"; then # dead tuples in smart_search/face_search make the REINDEX below fail with @@ -132,7 +134,7 @@ EOF # while still on the old extension version, a post-upgrade vacuum errors instead $STD sudo -u postgres psql -d immich -c "VACUUM (ANALYZE) smart_search;" $STD sudo -u postgres psql -d immich -c "VACUUM (ANALYZE) face_search;" - fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" "${VCHORD_RELEASE}" "/tmp" "postgresql-16-vchord_*_$(arch_resolve).deb" + fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" "${VCHORD_RELEASE}" "/tmp" "postgresql-${PG_VERSION}-vchord_*_$(arch_resolve).deb" systemctl restart postgresql $STD sudo -u postgres psql -d immich -c "ALTER EXTENSION vector UPDATE;" $STD sudo -u postgres psql -d immich -c "ALTER EXTENSION vchord UPDATE;" From 666bdbd8c8d9eb2e737b6a8af32f89596bb05e4e Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 10:00:14 +0000 Subject: [PATCH 095/245] Update CHANGELOG.md (#15742) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78b9a1ea3..4aef1a085 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -510,6 +510,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - immich: use actual PostgreSQL version for VectorChord package lookup [@mnavon](https://github.com/mnavon) ([#15705](https://github.com/community-scripts/ProxmoxVE/pull/15705)) - fix storyteller release selection for stable web tags [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15736](https://github.com/community-scripts/ProxmoxVE/pull/15736)) - Docmost: Fix update procedure [@MickLesk](https://github.com/MickLesk) ([#15732](https://github.com/community-scripts/ProxmoxVE/pull/15732)) - fix(shinobi): remove obsolete --unsafe-perm npm flag [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15730](https://github.com/community-scripts/ProxmoxVE/pull/15730)) From bcaadc4dbd970b7628349062d4a71b12b056366e Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 13 Jul 2026 14:58:23 +0200 Subject: [PATCH 096/245] typo --- ct/docmost.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ct/docmost.sh b/ct/docmost.sh index a9727d6ad..1c6271c98 100644 --- a/ct/docmost.sh +++ b/ct/docmost.sh @@ -53,7 +53,7 @@ function update_script() { sed -i '/^@Module({$/i @Global()' /opt/docmost/apps/server/src/core/core.module.ts fi - msg_insfo "Configuring Docmost" + msg_info "Configuring Docmost" cd /opt/docmost $STD pnpm install --force $STD pnpm build From 1e3d0dedb39421faf3e415fb5fd7221f4b543cef Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Mon, 13 Jul 2026 15:09:56 +0200 Subject: [PATCH 097/245] Change sign-in URL to admin URL in affine.sh (#15741) --- ct/affine.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ct/affine.sh b/ct/affine.sh index ff8562073..c6f2849aa 100644 --- a/ct/affine.sh +++ b/ct/affine.sh @@ -124,4 +124,4 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" echo -e "${INFO}${YW}Access it using the following URL:${CL}" -echo -e "${GATEWAY}${BGN}http://${IP}:3010/sign-in${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:3010/admin${CL}" From 3c5a848d7da9bff3e97b84f76b4b38332a08245a Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 13:10:47 +0000 Subject: [PATCH 098/245] Update CHANGELOG.md (#15747) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4aef1a085..ae7b1893b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -510,6 +510,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - Change sign-in URL to admin URL in affine.sh [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15741](https://github.com/community-scripts/ProxmoxVE/pull/15741)) - immich: use actual PostgreSQL version for VectorChord package lookup [@mnavon](https://github.com/mnavon) ([#15705](https://github.com/community-scripts/ProxmoxVE/pull/15705)) - fix storyteller release selection for stable web tags [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15736](https://github.com/community-scripts/ProxmoxVE/pull/15736)) - Docmost: Fix update procedure [@MickLesk](https://github.com/MickLesk) ([#15732](https://github.com/community-scripts/ProxmoxVE/pull/15732)) From dbe2c9eb97ca75f883cfad0326840912022fe1c8 Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 17:39:10 +0200 Subject: [PATCH 099/245] Add leafwiki (ct) (#15748) Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com> --- ct/headers/leafwiki | 6 ++++ ct/leafwiki.sh | 57 +++++++++++++++++++++++++++++++++++++ install/leafwiki-install.sh | 55 +++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 ct/headers/leafwiki create mode 100644 ct/leafwiki.sh create mode 100644 install/leafwiki-install.sh diff --git a/ct/headers/leafwiki b/ct/headers/leafwiki new file mode 100644 index 000000000..dcfacbddf --- /dev/null +++ b/ct/headers/leafwiki @@ -0,0 +1,6 @@ + __ _____ ___ __ _ + / / ___ ____ _/ __/ | / (_) /__(_) + / / / _ \/ __ `/ /_ | | /| / / / //_/ / + / /___/ __/ /_/ / __/ | |/ |/ / / ,< / / +/_____/\___/\__,_/_/ |__/|__/_/_/|_/_/ + diff --git a/ct/leafwiki.sh b/ct/leafwiki.sh new file mode 100644 index 000000000..20633cb57 --- /dev/null +++ b/ct/leafwiki.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/perber/leafwiki + +APP="LeafWiki" +var_tags="${var_tags:-wiki;markdown;notes}" +var_cpu="${var_cpu:-1}" +var_ram="${var_ram:-512}" +var_disk="${var_disk:-4}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -f /usr/local/bin/leafwiki ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "leafwiki" "perber/leafwiki"; then + msg_info "Stopping Service" + systemctl stop leafwiki + msg_ok "Stopped Service" + + create_backup /opt/leafwiki/data + fetch_and_deploy_gh_release "leafwiki" "perber/leafwiki" "singlefile" "latest" "/usr/local/bin" "leafwiki-v*-linux-$(arch_resolve)" + restore_backup + + msg_info "Starting Service" + systemctl start leafwiki + msg_ok "Started Service" + msg_ok "Updated successfully!" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:8080${CL}" diff --git a/install/leafwiki-install.sh b/install/leafwiki-install.sh new file mode 100644 index 000000000..228ffc702 --- /dev/null +++ b/install/leafwiki-install.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/perber/leafwiki + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +fetch_and_deploy_gh_release "leafwiki" "perber/leafwiki" "singlefile" "latest" "/usr/local/bin" "leafwiki-v*-linux-$(arch_resolve)" + +msg_info "Configuring LeafWiki" +mkdir -p /opt/leafwiki/data +mkdir -p /etc/leafwiki +JWT_SECRET=$(openssl rand -hex 32) +ADMIN_PASS=$(openssl rand -base64 12 | tr -dc 'a-zA-Z0-9' | head -c12) +cat </etc/leafwiki/.env +LEAFWIKI_DATA_DIR=/opt/leafwiki/data +LEAFWIKI_HOST=0.0.0.0 +LEAFWIKI_PORT=8080 +LEAFWIKI_JWT_SECRET=${JWT_SECRET} +LEAFWIKI_ADMIN_PASSWORD=${ADMIN_PASS} +LEAFWIKI_ALLOW_INSECURE=true +EOF +msg_ok "Configured LeafWiki" + +msg_info "Creating Service" +cat </etc/systemd/system/leafwiki.service +[Unit] +Description=LeafWiki +After=network.target + +[Service] +Type=simple +User=root +EnvironmentFile=/etc/leafwiki/.env +ExecStart=/usr/local/bin/leafwiki +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now leafwiki +msg_ok "Created Service" + +motd_ssh +customize +cleanup_lxc From da627244073208059d52023525fc958b0c2294fb Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 15:41:02 +0000 Subject: [PATCH 100/245] Update CHANGELOG.md (#15749) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae7b1893b..0db03f2e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -504,12 +504,15 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-13 -### 🚀 Updated Scripts +### 🆕 New Scripts - - fix(hyperion): keep service running after container reboot [@TowyTowy](https://github.com/TowyTowy) ([#15653](https://github.com/community-scripts/ProxmoxVE/pull/15653)) + - LeafWiki ([#15748](https://github.com/community-scripts/ProxmoxVE/pull/15748)) + +### 🚀 Updated Scripts - #### 🐞 Bug Fixes + - fix(hyperion): keep service running after container reboot [@TowyTowy](https://github.com/TowyTowy) ([#15653](https://github.com/community-scripts/ProxmoxVE/pull/15653)) - Change sign-in URL to admin URL in affine.sh [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15741](https://github.com/community-scripts/ProxmoxVE/pull/15741)) - immich: use actual PostgreSQL version for VectorChord package lookup [@mnavon](https://github.com/mnavon) ([#15705](https://github.com/community-scripts/ProxmoxVE/pull/15705)) - fix storyteller release selection for stable web tags [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15736](https://github.com/community-scripts/ProxmoxVE/pull/15736)) From 5d57c328fb02ec272644ee35b5f3a154bcf4be8b Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 14 Jul 2026 03:32:29 -0400 Subject: [PATCH 101/245] [Upstream Fix] Immich: Fix loader priority (#15755) --- ct/immich.sh | 1 + install/immich-install.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/ct/immich.sh b/ct/immich.sh index af15f4e1e..e72c4b7fe 100644 --- a/ct/immich.sh +++ b/ct/immich.sh @@ -501,6 +501,7 @@ function compile_libvips() { $STD git clone https://github.com/libvips/libvips.git "$SOURCE" cd "$SOURCE" $STD git reset --hard "$LIBVIPS_REVISION" + $STD git apply "$BASE_DIR"/server/sources/libvips-patches/0001-put-other-loaders-ahead-of-dcrawload.patch $STD meson setup build --buildtype=release --libdir=lib -Dintrospection=disabled -Dtiff=disabled cd build $STD ninja install diff --git a/install/immich-install.sh b/install/immich-install.sh index 2aa611c61..b75d4a7f2 100644 --- a/install/immich-install.sh +++ b/install/immich-install.sh @@ -286,6 +286,7 @@ LIBVIPS_REVISION="e01a4797cabe77d457fdfa7d776b7a7e7ca6d6a7" $STD git clone https://github.com/libvips/libvips.git "$SOURCE" cd "$SOURCE" $STD git reset --hard "$LIBVIPS_REVISION" +$STD git apply "$BASE_DIR"/server/sources/libvips-patches/0001-put-other-loaders-ahead-of-dcrawload.patch $STD meson setup build --buildtype=release --libdir=lib -Dintrospection=disabled -Dtiff=disabled cd build $STD ninja install From 6f76cc043e15c461060c67a7d08115a4b7bb36e7 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 07:32:54 +0000 Subject: [PATCH 102/245] Update CHANGELOG.md (#15756) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0db03f2e1..3ecee9dd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -502,6 +502,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-14 + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - [Upstream Fix] Immich: Fix loader priority [@vhsdream](https://github.com/vhsdream) ([#15755](https://github.com/community-scripts/ProxmoxVE/pull/15755)) + ## 2026-07-13 ### 🆕 New Scripts From 171b954c7c429ed4ddda5fe8eed4474fc268e8ce Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Tue, 14 Jul 2026 12:00:22 +0200 Subject: [PATCH 103/245] fix(fileflows): handle update API failures and fix Node install (#14858) Server updates no longer abort on 401 or unreachable API; users can force deploy when security is enabled or the app is down. Node installs now pass --server during systemd setup, and Node updates skip the server-only API. --- ct/fileflows.sh | 112 +++++++++++++++++++++++------------ install/fileflows-install.sh | 7 ++- 2 files changed, 79 insertions(+), 40 deletions(-) diff --git a/ct/fileflows.sh b/ct/fileflows.sh index 473efd435..9e3a5cd7e 100644 --- a/ct/fileflows.sh +++ b/ct/fileflows.sh @@ -31,50 +31,86 @@ function update_script() { exit fi - update_available=$(curl -fsSL -X 'GET' "http://localhost:19200/api/status/update-available" -H 'accept: application/json' | jq .UpdateAvailable) - if [[ "${update_available}" == "true" ]]; then - msg_info "Stopping Service" - systemctl --all stop 'fileflows*' - msg_info "Stopped Service" + local proceed=false - msg_info "Creating Backup" - ls /opt/*.tar.gz &>/dev/null && rm -f /opt/*.tar.gz - backup_filename="/opt/${APP}_backup_$(date +%F).tar.gz" - tar -czf "$backup_filename" -C /opt/fileflows Data - msg_ok "Backup Created" - - # FileFlows tracks the latest release, whose .NET target can move (e.g. 8 -> 10); - # ensure the current ASP.NET Core Runtime so an existing install doesn't fail to - # start after updating to a newer .NET major version. - msg_info "Ensuring ASP.NET Core Runtime" - if [[ "$(arch_resolve)" == "arm64" ]]; then - if [[ ! -x /usr/lib/dotnet10/dotnet ]]; then - curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh - $STD bash /tmp/dotnet-install.sh --channel 10.0 --runtime aspnetcore --install-dir /usr/lib/dotnet10 - ln -sf /usr/lib/dotnet10/dotnet /usr/bin/dotnet - rm -f /tmp/dotnet-install.sh + if systemctl list-unit-files 'fileflows.service' --no-legend 2>/dev/null | grep -q '^fileflows\.service'; then + tmp=$(mktemp) + http_code=$(curl -sSL -X 'GET' "http://localhost:19200/api/status/update-available" -H 'accept: application/json' -o "$tmp" -w '%{http_code}' 2>/dev/null) || http_code="000" + if [[ "$http_code" == "200" ]]; then + update_available=$(jq -r '.UpdateAvailable // false' "$tmp" 2>/dev/null) + rm -f "$tmp" + if [[ "${update_available}" == "true" ]]; then + proceed=true + else + msg_ok "No update required. ${APP} is already at latest version" + exit + fi + else + rm -f "$tmp" + if [[ "$http_code" == "401" ]]; then + msg_warn "Could not check for updates: API returned 401 (security may be enabled)." + else + msg_warn "Could not check for updates: API unreachable (HTTP ${http_code})." + fi + if [[ "${FORCE_UPDATE:-}" == "1" ]]; then + proceed=true + else + read -r -p "${TAB3}Force update without version check? [y/N]: " CONFIRM + if [[ "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then + proceed=true + else + msg_error "Update aborted." + exit + fi fi - elif ! is_package_installed "aspnetcore-runtime-10.0"; then - $STD apt remove -y aspnetcore-runtime-8.0 aspnetcore-runtime-9.0 2>/dev/null || true - setup_deb822_repo \ - "microsoft" \ - "https://packages.microsoft.com/keys/microsoft-2025.asc" \ - "https://packages.microsoft.com/debian/13/prod/" \ - "trixie" - $STD apt install -y aspnetcore-runtime-10.0 fi - msg_ok "Ensured ASP.NET Core Runtime" - - fetch_and_deploy_from_url "https://fileflows.com/downloads/zip" "/opt/fileflows" - - msg_info "Starting Service" - systemctl --all start 'fileflows*' - msg_ok "Started Service" - msg_ok "Updated successfully!" else - msg_ok "No update required. ${APP} is already at latest version" + proceed=true fi + if [[ "$proceed" != "true" ]]; then + exit + fi + + msg_info "Stopping Service" + systemctl --all stop 'fileflows*' + msg_ok "Stopped Service" + + msg_info "Creating Backup" + ls /opt/*.tar.gz &>/dev/null && rm -f /opt/*.tar.gz + backup_filename="/opt/${APP}_backup_$(date +%F).tar.gz" + tar -czf "$backup_filename" -C /opt/fileflows Data + msg_ok "Backup Created" + + # FileFlows tracks the latest release, whose .NET target can move (e.g. 8 -> 10); + # ensure the current ASP.NET Core Runtime so an existing install doesn't fail to + # start after updating to a newer .NET major version. + msg_info "Ensuring ASP.NET Core Runtime" + if [[ "$(arch_resolve)" == "arm64" ]]; then + if [[ ! -x /usr/lib/dotnet10/dotnet ]]; then + curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh + $STD bash /tmp/dotnet-install.sh --channel 10.0 --runtime aspnetcore --install-dir /usr/lib/dotnet10 + ln -sf /usr/lib/dotnet10/dotnet /usr/bin/dotnet + rm -f /tmp/dotnet-install.sh + fi + elif ! is_package_installed "aspnetcore-runtime-10.0"; then + $STD apt remove -y aspnetcore-runtime-8.0 aspnetcore-runtime-9.0 2>/dev/null || true + setup_deb822_repo \ + "microsoft" \ + "https://packages.microsoft.com/keys/microsoft-2025.asc" \ + "https://packages.microsoft.com/debian/13/prod/" \ + "trixie" + $STD apt install -y aspnetcore-runtime-10.0 + fi + msg_ok "Ensured ASP.NET Core Runtime" + + fetch_and_deploy_from_url "https://fileflows.com/downloads/zip" "/opt/fileflows" + + msg_info "Starting Service" + systemctl --all start 'fileflows*' + msg_ok "Started Service" + msg_ok "Updated successfully!" + exit } diff --git a/install/fileflows-install.sh b/install/fileflows-install.sh index 50242be8a..14efb6582 100644 --- a/install/fileflows-install.sh +++ b/install/fileflows-install.sh @@ -55,9 +55,12 @@ if [[ "$install_server" =~ ^[Ss]$ ]]; then msg_ok "Installed FileFlows Server" else msg_info "Installing FileFlows Node" + read -r -p "${TAB3}Enter FileFlows Server URL (e.g. http://192.168.1.10:19200): " server_url + while [[ -z "${server_url// /}" ]]; do + read -r -p "${TAB3}Enter FileFlows Server URL (e.g. http://192.168.1.10:19200): " server_url + done cd /opt/fileflows/Node - $STD dotnet FileFlows.Node.dll - $STD dotnet FileFlows.Node.dll --systemd install --root true + $STD dotnet FileFlows.Node.dll --server "$server_url" --systemd install --root true systemctl enable -q --now fileflows-node msg_ok "Installed FileFlows Node" fi From b7a002cae496b9d340aa11cd455f3bc6bc077ec3 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 10:00:47 +0000 Subject: [PATCH 104/245] Update CHANGELOG.md (#15762) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ecee9dd7..234591e6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -508,6 +508,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - fix(fileflows): handle update API 401, force update, and Node install [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14858](https://github.com/community-scripts/ProxmoxVE/pull/14858)) - [Upstream Fix] Immich: Fix loader priority [@vhsdream](https://github.com/vhsdream) ([#15755](https://github.com/community-scripts/ProxmoxVE/pull/15755)) ## 2026-07-13 From 55ab97a020d6fb62bcb5634c602ad106417a013e Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Tue, 14 Jul 2026 12:02:10 +0200 Subject: [PATCH 105/245] Revert "fix(fileflows): handle update API failures and fix Node install (#14858)" (#15764) This reverts commit 171b954c7c429ed4ddda5fe8eed4474fc268e8ce. --- ct/fileflows.sh | 112 ++++++++++++----------------------- install/fileflows-install.sh | 7 +-- 2 files changed, 40 insertions(+), 79 deletions(-) diff --git a/ct/fileflows.sh b/ct/fileflows.sh index 9e3a5cd7e..473efd435 100644 --- a/ct/fileflows.sh +++ b/ct/fileflows.sh @@ -31,86 +31,50 @@ function update_script() { exit fi - local proceed=false + update_available=$(curl -fsSL -X 'GET' "http://localhost:19200/api/status/update-available" -H 'accept: application/json' | jq .UpdateAvailable) + if [[ "${update_available}" == "true" ]]; then + msg_info "Stopping Service" + systemctl --all stop 'fileflows*' + msg_info "Stopped Service" - if systemctl list-unit-files 'fileflows.service' --no-legend 2>/dev/null | grep -q '^fileflows\.service'; then - tmp=$(mktemp) - http_code=$(curl -sSL -X 'GET' "http://localhost:19200/api/status/update-available" -H 'accept: application/json' -o "$tmp" -w '%{http_code}' 2>/dev/null) || http_code="000" - if [[ "$http_code" == "200" ]]; then - update_available=$(jq -r '.UpdateAvailable // false' "$tmp" 2>/dev/null) - rm -f "$tmp" - if [[ "${update_available}" == "true" ]]; then - proceed=true - else - msg_ok "No update required. ${APP} is already at latest version" - exit - fi - else - rm -f "$tmp" - if [[ "$http_code" == "401" ]]; then - msg_warn "Could not check for updates: API returned 401 (security may be enabled)." - else - msg_warn "Could not check for updates: API unreachable (HTTP ${http_code})." - fi - if [[ "${FORCE_UPDATE:-}" == "1" ]]; then - proceed=true - else - read -r -p "${TAB3}Force update without version check? [y/N]: " CONFIRM - if [[ "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then - proceed=true - else - msg_error "Update aborted." - exit - fi + msg_info "Creating Backup" + ls /opt/*.tar.gz &>/dev/null && rm -f /opt/*.tar.gz + backup_filename="/opt/${APP}_backup_$(date +%F).tar.gz" + tar -czf "$backup_filename" -C /opt/fileflows Data + msg_ok "Backup Created" + + # FileFlows tracks the latest release, whose .NET target can move (e.g. 8 -> 10); + # ensure the current ASP.NET Core Runtime so an existing install doesn't fail to + # start after updating to a newer .NET major version. + msg_info "Ensuring ASP.NET Core Runtime" + if [[ "$(arch_resolve)" == "arm64" ]]; then + if [[ ! -x /usr/lib/dotnet10/dotnet ]]; then + curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh + $STD bash /tmp/dotnet-install.sh --channel 10.0 --runtime aspnetcore --install-dir /usr/lib/dotnet10 + ln -sf /usr/lib/dotnet10/dotnet /usr/bin/dotnet + rm -f /tmp/dotnet-install.sh fi + elif ! is_package_installed "aspnetcore-runtime-10.0"; then + $STD apt remove -y aspnetcore-runtime-8.0 aspnetcore-runtime-9.0 2>/dev/null || true + setup_deb822_repo \ + "microsoft" \ + "https://packages.microsoft.com/keys/microsoft-2025.asc" \ + "https://packages.microsoft.com/debian/13/prod/" \ + "trixie" + $STD apt install -y aspnetcore-runtime-10.0 fi + msg_ok "Ensured ASP.NET Core Runtime" + + fetch_and_deploy_from_url "https://fileflows.com/downloads/zip" "/opt/fileflows" + + msg_info "Starting Service" + systemctl --all start 'fileflows*' + msg_ok "Started Service" + msg_ok "Updated successfully!" else - proceed=true + msg_ok "No update required. ${APP} is already at latest version" fi - if [[ "$proceed" != "true" ]]; then - exit - fi - - msg_info "Stopping Service" - systemctl --all stop 'fileflows*' - msg_ok "Stopped Service" - - msg_info "Creating Backup" - ls /opt/*.tar.gz &>/dev/null && rm -f /opt/*.tar.gz - backup_filename="/opt/${APP}_backup_$(date +%F).tar.gz" - tar -czf "$backup_filename" -C /opt/fileflows Data - msg_ok "Backup Created" - - # FileFlows tracks the latest release, whose .NET target can move (e.g. 8 -> 10); - # ensure the current ASP.NET Core Runtime so an existing install doesn't fail to - # start after updating to a newer .NET major version. - msg_info "Ensuring ASP.NET Core Runtime" - if [[ "$(arch_resolve)" == "arm64" ]]; then - if [[ ! -x /usr/lib/dotnet10/dotnet ]]; then - curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh - $STD bash /tmp/dotnet-install.sh --channel 10.0 --runtime aspnetcore --install-dir /usr/lib/dotnet10 - ln -sf /usr/lib/dotnet10/dotnet /usr/bin/dotnet - rm -f /tmp/dotnet-install.sh - fi - elif ! is_package_installed "aspnetcore-runtime-10.0"; then - $STD apt remove -y aspnetcore-runtime-8.0 aspnetcore-runtime-9.0 2>/dev/null || true - setup_deb822_repo \ - "microsoft" \ - "https://packages.microsoft.com/keys/microsoft-2025.asc" \ - "https://packages.microsoft.com/debian/13/prod/" \ - "trixie" - $STD apt install -y aspnetcore-runtime-10.0 - fi - msg_ok "Ensured ASP.NET Core Runtime" - - fetch_and_deploy_from_url "https://fileflows.com/downloads/zip" "/opt/fileflows" - - msg_info "Starting Service" - systemctl --all start 'fileflows*' - msg_ok "Started Service" - msg_ok "Updated successfully!" - exit } diff --git a/install/fileflows-install.sh b/install/fileflows-install.sh index 14efb6582..50242be8a 100644 --- a/install/fileflows-install.sh +++ b/install/fileflows-install.sh @@ -55,12 +55,9 @@ if [[ "$install_server" =~ ^[Ss]$ ]]; then msg_ok "Installed FileFlows Server" else msg_info "Installing FileFlows Node" - read -r -p "${TAB3}Enter FileFlows Server URL (e.g. http://192.168.1.10:19200): " server_url - while [[ -z "${server_url// /}" ]]; do - read -r -p "${TAB3}Enter FileFlows Server URL (e.g. http://192.168.1.10:19200): " server_url - done cd /opt/fileflows/Node - $STD dotnet FileFlows.Node.dll --server "$server_url" --systemd install --root true + $STD dotnet FileFlows.Node.dll + $STD dotnet FileFlows.Node.dll --systemd install --root true systemctl enable -q --now fileflows-node msg_ok "Installed FileFlows Node" fi From 09ec7b32034035639b57e5efa62d39e3a7da09c4 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 10:02:33 +0000 Subject: [PATCH 106/245] Update CHANGELOG.md (#15765) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 234591e6e..d4c31f965 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -506,6 +506,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🚀 Updated Scripts + - Revert "fix(fileflows): handle update API 401, force update, and Node install" [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15764](https://github.com/community-scripts/ProxmoxVE/pull/15764)) + - #### 🐞 Bug Fixes - fix(fileflows): handle update API 401, force update, and Node install [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14858](https://github.com/community-scripts/ProxmoxVE/pull/14858)) From 63f219f14f1bd959075d5b478d43dfb332bc8e73 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Tue, 14 Jul 2026 12:44:19 +0200 Subject: [PATCH 107/245] Revise project eligibility criteria in request template Updated eligibility requirements for project requests in the discussion template, clarifying the criteria for self-hosting, repository stars, and project age. --- .../DISCUSSION_TEMPLATE/request-script.yml | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/.github/DISCUSSION_TEMPLATE/request-script.yml b/.github/DISCUSSION_TEMPLATE/request-script.yml index 64d694c97..c966e8747 100644 --- a/.github/DISCUSSION_TEMPLATE/request-script.yml +++ b/.github/DISCUSSION_TEMPLATE/request-script.yml @@ -12,13 +12,17 @@ body: Requests may be closed if the application is out of scope, abandoned, too new, not publicly verifiable, or not suitable for a reliable Proxmox VE Helper-Scripts integration. General requirements: - - The application should be self-hosted. - - The project should have an official public source repository. - - The project should provide official releases, tags, or release tarballs. - - The project should be actively maintained. - - The project should generally have at least 1,000 stars or a comparable public adoption signal. - - The latest official release or tag should not be older than 6 months. - - The project itself should be at least 6 months old. + - The application must be self-hosted. + - The project must have an official public source repository. + - The project must provide official releases, tags, or release tarballs. + - The project must be actively maintained. + - The official source repository must have at least 1,000 stars. + - The latest official release or tag must not be older than 6 months. + - The project itself must be at least 6 months old. + + Projects that do not meet these requirements may be closed without further evaluation. + + Exceptions to the 1,000-star requirement are rare and require a clearly verifiable, significant public adoption signal. - type: input id: application-name @@ -47,6 +51,35 @@ body: validations: required: true + - type: markdown + attributes: + value: | + ## ⚠️ Project Eligibility + + Before continuing, verify that the requested project meets the minimum requirements below. + + **Projects with fewer than 1,000 stars are generally not eligible for a script request.** + + Exceptions are only considered where there is a clearly verifiable, significant public adoption signal. + + - type: input + id: repository-stars + attributes: + label: Repository Stars + description: Enter the current number of stars of the official source repository. + placeholder: "e.g., 15,000" + validations: + required: true + + - type: checkboxes + id: minimum-stars + attributes: + label: Minimum Adoption Requirement + description: Confirm that you have verified the project's public adoption. + options: + - label: The official source repository has at least 1,000 stars. + required: true + - type: textarea id: app-description attributes: From c039ab2e62041163cb4d1ddef7e65a30f9b46f53 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Tue, 14 Jul 2026 12:45:49 +0200 Subject: [PATCH 108/245] Refactor input and checkbox fields for repository stars --- .../DISCUSSION_TEMPLATE/request-script.yml | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/DISCUSSION_TEMPLATE/request-script.yml b/.github/DISCUSSION_TEMPLATE/request-script.yml index c966e8747..a2cf93136 100644 --- a/.github/DISCUSSION_TEMPLATE/request-script.yml +++ b/.github/DISCUSSION_TEMPLATE/request-script.yml @@ -62,23 +62,23 @@ body: Exceptions are only considered where there is a clearly verifiable, significant public adoption signal. - - type: input - id: repository-stars - attributes: - label: Repository Stars - description: Enter the current number of stars of the official source repository. - placeholder: "e.g., 15,000" - validations: - required: true - - - type: checkboxes - id: minimum-stars - attributes: - label: Minimum Adoption Requirement - description: Confirm that you have verified the project's public adoption. - options: - - label: The official source repository has at least 1,000 stars. - required: true + - type: input + id: repository-stars + attributes: + label: Repository Stars + description: Enter the current number of stars of the official source repository. + placeholder: "e.g., 15,000" + validations: + required: true + + - type: checkboxes + id: minimum-stars + attributes: + label: Minimum Adoption Requirement + description: Confirm that you have verified the project's public adoption. + options: + - label: The official source repository has at least 1,000 stars. + required: true - type: textarea id: app-description From 103b420e30c299944661326a813fd8b2e388c2ff Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 11:08:23 +0000 Subject: [PATCH 109/245] Update CHANGELOG.md (#15771) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4c31f965..3ecee9dd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -506,11 +506,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🚀 Updated Scripts - - Revert "fix(fileflows): handle update API 401, force update, and Node install" [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15764](https://github.com/community-scripts/ProxmoxVE/pull/15764)) - - #### 🐞 Bug Fixes - - fix(fileflows): handle update API 401, force update, and Node install [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14858](https://github.com/community-scripts/ProxmoxVE/pull/14858)) - [Upstream Fix] Immich: Fix loader priority [@vhsdream](https://github.com/vhsdream) ([#15755](https://github.com/community-scripts/ProxmoxVE/pull/15755)) ## 2026-07-13 From ab3c9be482ce2715f7daee0209bc649f902b9176 Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Tue, 14 Jul 2026 13:58:22 +0200 Subject: [PATCH 110/245] fix(birdnet-go): match new upstream release asset naming (#15758) Upstream BirdNET-Go releases now suffix tarball names with the release date (e.g. birdnet-go-linux-amd64-20260713.tar.gz). Use a wildcard pattern so install and update can fetch the latest release without falling back to older nightlies. Fixes #15753 --- ct/birdnet-go.sh | 2 +- install/birdnet-go-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/birdnet-go.sh b/ct/birdnet-go.sh index 39db9ca1f..6319219f9 100644 --- a/ct/birdnet-go.sh +++ b/ct/birdnet-go.sh @@ -37,7 +37,7 @@ function update_script() { systemctl stop birdnet msg_ok "Stopped Service" - fetch_and_deploy_gh_release "birdnet" "tphakala/birdnet-go" "prebuild" "latest" "/opt/birdnet" "birdnet-go-linux-$(arch_resolve).tar.gz" + fetch_and_deploy_gh_release "birdnet" "tphakala/birdnet-go" "prebuild" "latest" "/opt/birdnet" "birdnet-go-linux-$(arch_resolve)*.tar.gz" msg_info "Deploying Binary" cp /opt/birdnet/birdnet-go /usr/local/bin/birdnet-go diff --git a/install/birdnet-go-install.sh b/install/birdnet-go-install.sh index b3dfcab8e..df0a96058 100644 --- a/install/birdnet-go-install.sh +++ b/install/birdnet-go-install.sh @@ -21,7 +21,7 @@ $STD apt install -y \ ffmpeg msg_ok "Installed Dependencies" -fetch_and_deploy_gh_release "birdnet" "tphakala/birdnet-go" "prebuild" "latest" "/opt/birdnet" "birdnet-go-linux-$(arch_resolve).tar.gz" +fetch_and_deploy_gh_release "birdnet" "tphakala/birdnet-go" "prebuild" "latest" "/opt/birdnet" "birdnet-go-linux-$(arch_resolve)*.tar.gz" msg_info "Setting up BirdNET-Go" cp /opt/birdnet/birdnet-go /usr/local/bin/birdnet-go From 9c586b94abac33fa8bc7e9e6189ee6bfe6196fda Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 11:58:44 +0000 Subject: [PATCH 111/245] Update CHANGELOG.md (#15774) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ecee9dd7..a5d921673 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -508,6 +508,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - BirdNET-Go: Match new upstream release asset naming [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15758](https://github.com/community-scripts/ProxmoxVE/pull/15758)) - [Upstream Fix] Immich: Fix loader priority [@vhsdream](https://github.com/vhsdream) ([#15755](https://github.com/community-scripts/ProxmoxVE/pull/15755)) ## 2026-07-13 From 7f430e15bb19febdde643a2efc3863bcdf227c36 Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:00:17 +0200 Subject: [PATCH 112/245] feat(silverbullet): add optional Runtime API install via Chromium (#15761) Adds an install-time prompt to optionally enable Silverbullet's Runtime API by installing Chromium and configuring SB_CHROME_PATH / SB_CHROME_DATA_DIR. --- install/silverbullet-install.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/install/silverbullet-install.sh b/install/silverbullet-install.sh index 6e26d9ccd..26f769c16 100644 --- a/install/silverbullet-install.sh +++ b/install/silverbullet-install.sh @@ -16,6 +16,17 @@ update_os fetch_and_deploy_gh_release "silverbullet" "silverbulletmd/silverbullet" "prebuild" "latest" "/opt/silverbullet/bin" "silverbullet-server-linux-$(arch_resolve "x86_64" "aarch64").zip" mkdir -p /opt/silverbullet/space +RUNTIME_API_ENV="" +read -rp "${TAB3}Enable Silverbullet Runtime API? Requires Chromium (~700MB). Uses ~200MB extra RAM. (y/N): " runtime_api_prompt +if [[ "${runtime_api_prompt,,}" =~ ^(y|yes)$ ]]; then + msg_info "Installing Chromium for Runtime API" + $STD apt install -y chromium + msg_ok "Installed Chromium for Runtime API" + RUNTIME_API_ENV=$'Environment=SB_CHROME_PATH=/usr/bin/chromium\nEnvironment=SB_CHROME_DATA_DIR=/opt/silverbullet/space/.chrome-data\n' + touch /opt/silverbullet/.runtime-api-enabled + msg_ok "Runtime API will be enabled" +fi + msg_info "Creating Service" cat </etc/systemd/system/silverbullet.service [Unit] @@ -25,6 +36,7 @@ After=syslog.target network.target [Service] User=root Type=simple +${RUNTIME_API_ENV} ExecStart=/opt/silverbullet/bin/silverbullet --hostname 0.0.0.0 --port 3000 /opt/silverbullet/space WorkingDirectory=/opt/silverbullet Restart=on-failure From e81220611617c3ea18d07d2584ef9ac7230b3435 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 12:00:40 +0000 Subject: [PATCH 113/245] Update CHANGELOG.md (#15775) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5d921673..993e216d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -511,6 +511,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - BirdNET-Go: Match new upstream release asset naming [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15758](https://github.com/community-scripts/ProxmoxVE/pull/15758)) - [Upstream Fix] Immich: Fix loader priority [@vhsdream](https://github.com/vhsdream) ([#15755](https://github.com/community-scripts/ProxmoxVE/pull/15755)) + - #### ✨ New Features + + - Silverbullet: Add optional Runtime API install via Chromium [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15761](https://github.com/community-scripts/ProxmoxVE/pull/15761)) + ## 2026-07-13 ### 🆕 New Scripts From 3f5453b609a3f1fba93ff174d1c340d38890c25c Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:01:16 +0200 Subject: [PATCH 114/245] FileFlows: Handle update API 401, force update, and Node install (#15766) * fix(fileflows): handle update API failures and fix Node install Server updates no longer abort on 401 or unreachable API; users can force deploy when security is enabled or the app is down. Node installs now pass --server during systemd setup, and Node updates skip the server-only API. * Update fileflows.sh --- ct/fileflows.sh | 109 +++++++++++++++++++++++------------ install/fileflows-install.sh | 7 ++- 2 files changed, 76 insertions(+), 40 deletions(-) diff --git a/ct/fileflows.sh b/ct/fileflows.sh index 473efd435..3f72cef69 100644 --- a/ct/fileflows.sh +++ b/ct/fileflows.sh @@ -31,50 +31,83 @@ function update_script() { exit fi - update_available=$(curl -fsSL -X 'GET' "http://localhost:19200/api/status/update-available" -H 'accept: application/json' | jq .UpdateAvailable) - if [[ "${update_available}" == "true" ]]; then - msg_info "Stopping Service" - systemctl --all stop 'fileflows*' - msg_info "Stopped Service" + local proceed=false - msg_info "Creating Backup" - ls /opt/*.tar.gz &>/dev/null && rm -f /opt/*.tar.gz - backup_filename="/opt/${APP}_backup_$(date +%F).tar.gz" - tar -czf "$backup_filename" -C /opt/fileflows Data - msg_ok "Backup Created" - - # FileFlows tracks the latest release, whose .NET target can move (e.g. 8 -> 10); - # ensure the current ASP.NET Core Runtime so an existing install doesn't fail to - # start after updating to a newer .NET major version. - msg_info "Ensuring ASP.NET Core Runtime" - if [[ "$(arch_resolve)" == "arm64" ]]; then - if [[ ! -x /usr/lib/dotnet10/dotnet ]]; then - curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh - $STD bash /tmp/dotnet-install.sh --channel 10.0 --runtime aspnetcore --install-dir /usr/lib/dotnet10 - ln -sf /usr/lib/dotnet10/dotnet /usr/bin/dotnet - rm -f /tmp/dotnet-install.sh + if systemctl list-unit-files 'fileflows.service' --no-legend 2>/dev/null | grep -q '^fileflows\.service'; then + tmp=$(mktemp) + http_code=$(curl -sSL -X 'GET' "http://localhost:19200/api/status/update-available" -H 'accept: application/json' -o "$tmp" -w '%{http_code}' 2>/dev/null) || http_code="000" + if [[ "$http_code" == "200" ]]; then + update_available=$(jq -r '.UpdateAvailable // false' "$tmp" 2>/dev/null) + rm -f "$tmp" + if [[ "${update_available}" == "true" ]]; then + proceed=true + else + msg_ok "No update required. ${APP} is already at latest version" + exit + fi + else + rm -f "$tmp" + if [[ "$http_code" == "401" ]]; then + msg_warn "Could not check for updates: API returned 401 (security may be enabled)." + else + msg_warn "Could not check for updates: API unreachable (HTTP ${http_code})." + fi + if [[ "${FORCE_UPDATE:-}" == "1" ]]; then + proceed=true + else + read -r -p "${TAB3}Force update without version check? [y/N]: " CONFIRM + if [[ "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then + proceed=true + else + msg_error "Update aborted." + exit + fi fi - elif ! is_package_installed "aspnetcore-runtime-10.0"; then - $STD apt remove -y aspnetcore-runtime-8.0 aspnetcore-runtime-9.0 2>/dev/null || true - setup_deb822_repo \ - "microsoft" \ - "https://packages.microsoft.com/keys/microsoft-2025.asc" \ - "https://packages.microsoft.com/debian/13/prod/" \ - "trixie" - $STD apt install -y aspnetcore-runtime-10.0 fi - msg_ok "Ensured ASP.NET Core Runtime" - - fetch_and_deploy_from_url "https://fileflows.com/downloads/zip" "/opt/fileflows" - - msg_info "Starting Service" - systemctl --all start 'fileflows*' - msg_ok "Started Service" - msg_ok "Updated successfully!" else - msg_ok "No update required. ${APP} is already at latest version" + proceed=true fi + if [[ "$proceed" != "true" ]]; then + exit + fi + + msg_info "Stopping Service" + systemctl --all stop 'fileflows*' + msg_ok "Stopped Service" + + msg_info "Creating Backup" + ls /opt/*.tar.gz &>/dev/null && rm -f /opt/*.tar.gz + backup_filename="/opt/${APP}_backup_$(date +%F).tar.gz" + tar -czf "$backup_filename" -C /opt/fileflows Data + msg_ok "Backup Created" + + msg_info "Ensuring ASP.NET Core Runtime" + if [[ "$(arch_resolve)" == "arm64" ]]; then + if [[ ! -x /usr/lib/dotnet10/dotnet ]]; then + curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh + $STD bash /tmp/dotnet-install.sh --channel 10.0 --runtime aspnetcore --install-dir /usr/lib/dotnet10 + ln -sf /usr/lib/dotnet10/dotnet /usr/bin/dotnet + rm -f /tmp/dotnet-install.sh + fi + elif ! is_package_installed "aspnetcore-runtime-10.0"; then + $STD apt remove -y aspnetcore-runtime-8.0 aspnetcore-runtime-9.0 2>/dev/null || true + setup_deb822_repo \ + "microsoft" \ + "https://packages.microsoft.com/keys/microsoft-2025.asc" \ + "https://packages.microsoft.com/debian/13/prod/" \ + "trixie" + $STD apt install -y aspnetcore-runtime-10.0 + fi + msg_ok "Ensured ASP.NET Core Runtime" + + fetch_and_deploy_from_url "https://fileflows.com/downloads/zip" "/opt/fileflows" + + msg_info "Starting Service" + systemctl --all start 'fileflows*' + msg_ok "Started Service" + msg_ok "Updated successfully!" + exit } diff --git a/install/fileflows-install.sh b/install/fileflows-install.sh index 50242be8a..14efb6582 100644 --- a/install/fileflows-install.sh +++ b/install/fileflows-install.sh @@ -55,9 +55,12 @@ if [[ "$install_server" =~ ^[Ss]$ ]]; then msg_ok "Installed FileFlows Server" else msg_info "Installing FileFlows Node" + read -r -p "${TAB3}Enter FileFlows Server URL (e.g. http://192.168.1.10:19200): " server_url + while [[ -z "${server_url// /}" ]]; do + read -r -p "${TAB3}Enter FileFlows Server URL (e.g. http://192.168.1.10:19200): " server_url + done cd /opt/fileflows/Node - $STD dotnet FileFlows.Node.dll - $STD dotnet FileFlows.Node.dll --systemd install --root true + $STD dotnet FileFlows.Node.dll --server "$server_url" --systemd install --root true systemctl enable -q --now fileflows-node msg_ok "Installed FileFlows Node" fi From 9055f4b34e2b5f08839c9e36c7b680f90763cb54 Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:01:40 +0200 Subject: [PATCH 115/245] fix(lychee): preserve uploads and ownership during update (#15768) The update script wiped public/uploads and did not re-apply www-data ownership, causing HTTP 500 after successful updates. Align with upstream upgrade steps and sibling Laravel scripts by backing up uploads/dist, restarting PHP-FPM, running full artisan cache cycle, and adding verbose diagnostics. Fixes #15763 --- ct/lychee.sh | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/ct/lychee.sh b/ct/lychee.sh index 887d1f3ac..7adfff87b 100644 --- a/ct/lychee.sh +++ b/ct/lychee.sh @@ -31,33 +31,38 @@ function update_script() { fi if check_for_gh_release "lychee" "LycheeOrg/Lychee"; then + PHP_VER=$(php -r 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;') + msg_info "Stopping Services" - systemctl stop caddy + systemctl stop caddy php${PHP_VER}-fpm msg_ok "Stopped Services" - msg_info "Backing up Data" - cp /opt/lychee/.env /opt/lychee.env.bak - cp -r /opt/lychee/storage /opt/lychee_storage_backup - msg_ok "Backed up Data" + create_backup /opt/lychee/.env \ + /opt/lychee/storage \ + /opt/lychee/public/uploads \ + /opt/lychee/public/dist CLEAN_INSTALL=1 fetch_and_deploy_gh_release "lychee" "LycheeOrg/Lychee" "prebuild" "latest" "/opt/lychee" "Lychee.zip" - msg_info "Restoring Data" - cp /opt/lychee.env.bak /opt/lychee/.env - rm -f /opt/lychee.env.bak - cp -r /opt/lychee_storage_backup/. /opt/lychee/storage - rm -rf /opt/lychee_storage_backup - msg_ok "Restored Data" + restore_backup msg_info "Updating Application" cd /opt/lychee $STD php artisan migrate --force + $STD php artisan config:clear + $STD php artisan cache:clear $STD php artisan optimize:clear - chmod -R 775 /opt/lychee/storage /opt/lychee/bootstrap/cache + $STD php artisan optimize + chown -R www-data:www-data /opt/lychee + chmod -R 775 /opt/lychee/storage /opt/lychee/bootstrap/cache \ + /opt/lychee/public/dist /opt/lychee/public/uploads + if [[ "${VERBOSE:-no}" = "yes" ]]; then + php artisan lychee:diagnostics || true + fi msg_ok "Updated Application" msg_info "Starting Services" - systemctl start caddy + systemctl start caddy php${PHP_VER}-fpm msg_ok "Started Services" msg_ok "Updated successfully!" fi From 254e720b4fe79af72e258e55660a6f554e48cf10 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 12:01:44 +0000 Subject: [PATCH 116/245] Update CHANGELOG.md (#15776) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 993e216d7..5df109bec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -508,6 +508,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - FileFlows: Handle update API 401, force update, and Node install [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15766](https://github.com/community-scripts/ProxmoxVE/pull/15766)) - BirdNET-Go: Match new upstream release asset naming [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15758](https://github.com/community-scripts/ProxmoxVE/pull/15758)) - [Upstream Fix] Immich: Fix loader priority [@vhsdream](https://github.com/vhsdream) ([#15755](https://github.com/community-scripts/ProxmoxVE/pull/15755)) From bb4e35f9886e6c94f0ac2baa7c77b9318c1deaf2 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 12:02:17 +0000 Subject: [PATCH 117/245] Update CHANGELOG.md (#15777) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5df109bec..e3a97ccb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -508,6 +508,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - Lychee: Preserve uploads and ownership during update [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15768](https://github.com/community-scripts/ProxmoxVE/pull/15768)) - FileFlows: Handle update API 401, force update, and Node install [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15766](https://github.com/community-scripts/ProxmoxVE/pull/15766)) - BirdNET-Go: Match new upstream release asset naming [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15758](https://github.com/community-scripts/ProxmoxVE/pull/15758)) - [Upstream Fix] Immich: Fix loader priority [@vhsdream](https://github.com/vhsdream) ([#15755](https://github.com/community-scripts/ProxmoxVE/pull/15755)) From 817ee347c7ab5134e59a8fbeee568e82dc37f6f2 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:08:14 +0200 Subject: [PATCH 118/245] Bump OpenCloud version to v7.2.2 (#15769) * Bump OpenCloud release version to v7.2.2 * Update OpenCloud version to v7.2.2 --- ct/opencloud.sh | 2 +- install/opencloud-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/opencloud.sh b/ct/opencloud.sh index b328d90ab..0ce6d9291 100644 --- a/ct/opencloud.sh +++ b/ct/opencloud.sh @@ -30,7 +30,7 @@ function update_script() { exit fi - RELEASE="v7.2.1" + RELEASE="v7.2.2" if check_for_gh_release "OpenCloud" "opencloud-eu/opencloud" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then msg_info "Stopping services" systemctl stop opencloud opencloud-wopi diff --git a/install/opencloud-install.sh b/install/opencloud-install.sh index 0dc635098..f3f1bc93b 100644 --- a/install/opencloud-install.sh +++ b/install/opencloud-install.sh @@ -64,7 +64,7 @@ $STD sudo -u cool coolconfig set-admin-password --user=admin --password="$COOLPA echo "$COOLPASS" >~/.coolpass msg_ok "Installed Collabora Online" -fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v7.2.1" "/usr/bin" "opencloud-*-linux-$(arch_resolve)" +fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v7.2.2" "/usr/bin" "opencloud-*-linux-$(arch_resolve)" mv /usr/bin/OpenCloud /usr/bin/opencloud msg_info "Configuring OpenCloud" From 9f8bc4b03d84329b21af7e9d2e364c1e367877b8 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 12:08:38 +0000 Subject: [PATCH 119/245] Update CHANGELOG.md (#15778) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3a97ccb4..28d868983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -515,6 +515,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### ✨ New Features + - Bump OpenCloud version to v7.2.2 [@MickLesk](https://github.com/MickLesk) ([#15769](https://github.com/community-scripts/ProxmoxVE/pull/15769)) - Silverbullet: Add optional Runtime API install via Chromium [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15761](https://github.com/community-scripts/ProxmoxVE/pull/15761)) ## 2026-07-13 From 670d972cc1342521ebaa59d715bd8bf5ca03ef7c Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:14:20 +0200 Subject: [PATCH 120/245] fix(wanderer): clean deploy and install plugins for v0.20.0 update (#15759) Use CLEAN_INSTALL with create_backup/restore_backup so stale v0.19.x source files no longer break go build after the integrations migration. Also set up the plugins directory and install official WASM bundles. --- ct/wanderer.sh | 13 +++++++++++-- install/wanderer-install.sh | 9 ++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ct/wanderer.sh b/ct/wanderer.sh index 432963379..bb0ec71cd 100644 --- a/ct/wanderer.sh +++ b/ct/wanderer.sh @@ -30,12 +30,14 @@ function update_script() { exit fi - if check_for_gh_release "wanderer" "Flomp/wanderer"; then + if check_for_gh_release "wanderer" "open-wanderer/wanderer"; then msg_info "Stopping service" systemctl stop wanderer-web msg_ok "Stopped service" - fetch_and_deploy_gh_release "wanderer" "open-wanderer/wanderer" "tarball" "latest" "/opt/wanderer/source" + create_backup /opt/wanderer/source/search + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "wanderer" "open-wanderer/wanderer" "tarball" "latest" "/opt/wanderer/source" + restore_backup msg_info "Updating wanderer" cd /opt/wanderer/source/db @@ -44,6 +46,13 @@ function update_script() { cd /opt/wanderer/source/web $STD npm ci $STD npm run build + mkdir -p /opt/wanderer/data/plugins + [[ -e /data/plugins ]] || ln -sfn /opt/wanderer/data/plugins /data/plugins + msg_info "Installing wanderer plugins" + for plugin in hammerhead komoot strava; do + fetch_and_deploy_gh_release "wanderer-plugin-${plugin}" "open-wanderer/wanderer" "prebuild" "${CHECK_UPDATE_RELEASE:-latest}" "/opt/wanderer/data/plugins" "wanderer-plugin-${plugin}.tar.gz" || msg_warn "Failed to install wanderer plugin: ${plugin}" + done + msg_ok "Installed wanderer plugins" msg_ok "Updated wanderer" msg_info "Starting service" diff --git a/install/wanderer-install.sh b/install/wanderer-install.sh index 3cebc9fef..6a8571bbf 100644 --- a/install/wanderer-install.sh +++ b/install/wanderer-install.sh @@ -20,7 +20,8 @@ if [[ "$(arch_resolve)" == "arm64" ]]; then else fetch_and_deploy_gh_release "meilisearch" "meilisearch/meilisearch" "binary" "latest" "/opt/wanderer/source/search" fi -mkdir -p /opt/wanderer/{source,data/pb_data,data/meili_data} +mkdir -p /opt/wanderer/{source,data/pb_data,data/meili_data,data/plugins} +[[ -e /data/plugins ]] || ln -sfn /opt/wanderer/data/plugins /data/plugins fetch_and_deploy_gh_release "wanderer" "open-wanderer/wanderer" "tarball" "latest" "/opt/wanderer/source" msg_info "Installing wanderer (patience)" @@ -32,6 +33,12 @@ $STD npm ci $STD npm run build msg_ok "Installed wanderer" +msg_info "Installing wanderer plugins" +for plugin in hammerhead komoot strava; do + fetch_and_deploy_gh_release "wanderer-plugin-${plugin}" "open-wanderer/wanderer" "prebuild" "latest" "/opt/wanderer/data/plugins" "wanderer-plugin-${plugin}.tar.gz" || msg_warn "Failed to install wanderer plugin: ${plugin}" +done +msg_ok "Installed wanderer plugins" + msg_info "Creating Service" MEILI_KEY=$(openssl rand -hex 32) POCKETBASE_KEY=$(openssl rand -hex 16) From 0f37abff3ce52a120fec946195861a7eff20d68d Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 12:14:44 +0000 Subject: [PATCH 121/245] Update CHANGELOG.md (#15779) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28d868983..bec04bb4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -508,6 +508,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - Wanderer: Clean deploy and install plugins for v0.20.0 update [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15759](https://github.com/community-scripts/ProxmoxVE/pull/15759)) - Lychee: Preserve uploads and ownership during update [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15768](https://github.com/community-scripts/ProxmoxVE/pull/15768)) - FileFlows: Handle update API 401, force update, and Node install [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15766](https://github.com/community-scripts/ProxmoxVE/pull/15766)) - BirdNET-Go: Match new upstream release asset naming [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15758](https://github.com/community-scripts/ProxmoxVE/pull/15758)) From 108c9dcf43c191a473d2910842cc3806f1ef86da Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:15:32 +0200 Subject: [PATCH 122/245] Add yuvomi (ct) (#15772) Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com> --- ct/headers/yuvomi | 6 ++++ ct/yuvomi.sh | 64 ++++++++++++++++++++++++++++++++++ install/yuvomi-install.sh | 72 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 ct/headers/yuvomi create mode 100644 ct/yuvomi.sh create mode 100644 install/yuvomi-install.sh diff --git a/ct/headers/yuvomi b/ct/headers/yuvomi new file mode 100644 index 000000000..3247d3dcc --- /dev/null +++ b/ct/headers/yuvomi @@ -0,0 +1,6 @@ +__ __ _ +\ \/ /_ ___ ______ ____ ___ (_) + \ / / / / | / / __ \/ __ `__ \/ / + / / /_/ /| |/ / /_/ / / / / / / / +/_/\__,_/ |___/\____/_/ /_/ /_/_/ + diff --git a/ct/yuvomi.sh b/ct/yuvomi.sh new file mode 100644 index 000000000..625a0aa61 --- /dev/null +++ b/ct/yuvomi.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/ulsklyc/yuvomi + +APP="Yuvomi" +var_tags="${var_tags:-family;planner;calendar}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-1024}" +var_disk="${var_disk:-8}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/yuvomi ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "yuvomi" "ulsklyc/yuvomi"; then + msg_info "Stopping Service" + systemctl stop yuvomi + msg_ok "Stopped Service" + + create_backup /opt/yuvomi/data /opt/yuvomi/.env + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "yuvomi" "ulsklyc/yuvomi" "tarball" + + msg_info "Installing Node.js Dependencies" + cd /opt/yuvomi + $STD npm ci --omit=dev + msg_ok "Installed Node.js Dependencies" + + restore_backup + + msg_info "Starting Service" + systemctl start yuvomi + msg_ok "Started Service" + msg_ok "Updated successfully!" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}" diff --git a/install/yuvomi-install.sh b/install/yuvomi-install.sh new file mode 100644 index 000000000..521049586 --- /dev/null +++ b/install/yuvomi-install.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/ulsklyc/yuvomi + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt install -y \ + python3 \ + make \ + g++ \ + libsqlcipher-dev +msg_ok "Installed Dependencies" + +NODE_VERSION="22" setup_nodejs + +fetch_and_deploy_gh_release "yuvomi" "ulsklyc/yuvomi" "tarball" + +msg_info "Installing Node.js Dependencies" +cd /opt/yuvomi +$STD npm ci --omit=dev +msg_ok "Installed Node.js Dependencies" + +msg_info "Configuring Yuvomi" +mkdir -p /opt/yuvomi/data /opt/yuvomi/backups +SESSION_SECRET=$(openssl rand -hex 32) +DB_ENCRYPT_KEY=$(openssl rand -hex 32) +cat </opt/yuvomi/.env +PORT=3000 +NODE_ENV=production +DB_PATH=/opt/yuvomi/data/yuvomi.db +DB_ENCRYPTION_KEY=${DB_ENCRYPT_KEY} +SESSION_SECRET=${SESSION_SECRET} +RATE_LIMIT_WINDOW_MS=60000 +RATE_LIMIT_MAX_ATTEMPTS=5 +RATE_LIMIT_BLOCK_DURATION_MS=900000 +EOF +msg_ok "Configured Yuvomi" + +msg_info "Creating Service" +cat </etc/systemd/system/yuvomi.service +[Unit] +Description=Yuvomi Family Planner +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/yuvomi +EnvironmentFile=/opt/yuvomi/.env +ExecStart=/usr/bin/node server/index.js +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now yuvomi +msg_ok "Created Service" + +motd_ssh +customize +cleanup_lxc From 2bffa47924a7b739ff1f6c4ff33d88c3e5c72588 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 12:16:01 +0000 Subject: [PATCH 123/245] Update CHANGELOG.md (#15780) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bec04bb4f..c9aad4a0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -504,6 +504,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-14 +### 🆕 New Scripts + + - Yuvomi ([#15772](https://github.com/community-scripts/ProxmoxVE/pull/15772)) + ### 🚀 Updated Scripts - #### 🐞 Bug Fixes From d4d482746b2334751d558bb569512934b07d1efa Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:16:10 +0200 Subject: [PATCH 124/245] Add grav (ct) (#15773) Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com> --- ct/grav.sh | 54 +++++++++++++++++++ ct/headers/grav | 6 +++ install/grav-install.sh | 111 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 ct/grav.sh create mode 100644 ct/headers/grav create mode 100644 install/grav-install.sh diff --git a/ct/grav.sh b/ct/grav.sh new file mode 100644 index 000000000..9271a029e --- /dev/null +++ b/ct/grav.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Raffaele (rafspiny) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://getgrav.org/ + +APP="Grav" +var_tags="${var_tags:-cms}" +var_cpu="${var_cpu:-1}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-8}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-no}" +var_unprivileged="${var_unprivileged:-1}" + + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d "/opt/grav" ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "grav" "getgrav/grav"; then + msg_info "Creating Backup" + cd /opt/grav + bin/grav backup -nq + msg_ok "Backup Created" + bin/gpm self-upgrade -y + cd - + chown -R www-data:www-data /opt/grav + msg_ok "Update Successful" + fi + exit +} + +start +build_container +description + +msg_ok "Completed successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:80${CL}" diff --git a/ct/headers/grav b/ct/headers/grav new file mode 100644 index 000000000..3e041ab1e --- /dev/null +++ b/ct/headers/grav @@ -0,0 +1,6 @@ + ______ + / ____/________ __ __ + / / __/ ___/ __ `/ | / / +/ /_/ / / / /_/ /| |/ / +\____/_/ \__,_/ |___/ + diff --git a/install/grav-install.sh b/install/grav-install.sh new file mode 100644 index 000000000..8b3c396cf --- /dev/null +++ b/install/grav-install.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Raffaele (rafspiny) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://getgrav.org/ + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt install -y \ + nginx \ + logrotate +msg_ok "Installed Dependencies" + +PHP_FPM="YES" setup_php + +fetch_and_deploy_gh_release "grav" "getgrav/grav" "prebuild" "latest" "/opt/grav" "grav-admin-v*zip" +chown -R www-data:www-data /opt/grav + +msg_info "Configuring Nginx" +PHP_VER=$(php -r 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;') +PHP_FPM_SOCK=$(find /run/php -maxdepth 1 -name "php*-fpm.sock" -type s | sort -V | tail -1) +unlink /etc/nginx/sites-enabled/default +rm -f /etc/nginx/sites-available/default +cat </etc/nginx/sites-available/grav +server { + listen 80; + server_name _; + root /opt/grav; + index index.html index.htm index.php; + + location / { + try_files \$uri \$uri/ /index.html /index.htm /index.php\$is_args\$args; + } + + ## Begin - Security + location ~* /(\.git|cache|bin|logs|backup|tests)/.*$ { return 403; } + location ~* /(system|vendor)/.*\.(txt|xml|md|html|json|yaml|yml|php|pl|py|cgi|twig|sh|bat)$ { return 403; } + location ~* /user/.*\.(txt|md|json|yaml|yml|php|pl|py|cgi|twig|sh|bat)$ { return 403; } + location ~ /(LICENSE\.txt|composer\.lock|composer\.json|nginx\.conf|web\.config|htaccess\.txt|\.htaccess) { return 403; } + ## End - Security + + ## Begin - API + location ^~ /api/ { + try_files \$uri \$uri/ /index.php\$is_args\$args; + } + ## End - API + + # deny all direct access to these sensitive user folders, whatever the file type + location ~* /user/(accounts|config|env)/.*$ { return 403; } + # allow public media uploads under user/data to be served directly; + # this must come before the user/data deny so it wins the match + location ~* /user/data/.*\.(jpe?g|png|gif|webp|avif|bmp|ico|mp4|webm|ogg|ogv|mov|mp3|wav|m4a|flac|pdf)$ { try_files \$uri =404; } + # deny everything else under user/data + location ~* /user/data/.*$ { return 403; } + + + ## Begin - Caching + location ~* ^/forms-basic-captcha-image.jpg$ { + try_files \$uri \$uri/ /index.php\$is_args\$args; + } + + location ~* \.(?:ico|css|js|gif|jpe?g|png)$ { + expires 30d; + add_header Vary Accept-Encoding; + log_not_found off; + } + + location ~* ^.+\.(?:css|cur|js|jpe?g|gif|htc|ico|png|html|xml|otf|ttf|eot|woff|woff2|svg)$ { + access_log off; + expires 30d; + add_header Cache-Control public; + tcp_nodelay off; + open_file_cache max=3000 inactive=120s; + open_file_cache_valid 45s; + open_file_cache_min_uses 2; + open_file_cache_errors off; + } + ## End - Caching + + location ~ ^(.+\.php)(.*)$ { + fastcgi_split_path_info ^(.+\.php)(.*)$; + if (!-f \$document_root\$fastcgi_script_name) { return 404; } + fastcgi_pass unix:${PHP_FPM_SOCK}; + fastcgi_index index.php; + include /etc/nginx/fastcgi_params; + fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; + } + + location ~ /\.ht { + deny all; + } +} +EOF +ln -sf /etc/nginx/sites-available/grav /etc/nginx/sites-enabled/grav +systemctl enable -q --now php${PHP_VER}-fpm +$STD nginx -t +systemctl enable -q --now nginx +$STD nginx -s reload +msg_ok "Configured Nginx" + +motd_ssh +customize +cleanup_lxc From a5b839f91fe1869fc64b217276639e964690cab8 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 12:16:30 +0000 Subject: [PATCH 125/245] Update CHANGELOG.md (#15781) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9aad4a0d..88c37eb3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -506,7 +506,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🆕 New Scripts - - Yuvomi ([#15772](https://github.com/community-scripts/ProxmoxVE/pull/15772)) + - Grav ([#15773](https://github.com/community-scripts/ProxmoxVE/pull/15773)) +- Yuvomi ([#15772](https://github.com/community-scripts/ProxmoxVE/pull/15772)) ### 🚀 Updated Scripts From ed29bb6f6206d007bd40c2038974b7dcf5ccbc31 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Tue, 14 Jul 2026 22:38:24 +0200 Subject: [PATCH 126/245] AFFiNE: Pin to v0.26.3 (#15782) * AFFiNE: Pin to v0.26.3 * Update GitHub release version to v0.26.3 --- ct/affine.sh | 5 +++-- install/affine-install.sh | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ct/affine.sh b/ct/affine.sh index c6f2849aa..236a225bd 100644 --- a/ct/affine.sh +++ b/ct/affine.sh @@ -30,14 +30,15 @@ function update_script() { exit fi - if check_for_gh_release "affine_app" "toeverything/AFFiNE"; then + RELEASE="v0.26.3" + if check_for_gh_release "affine_app" "toeverything/AFFiNE" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then msg_info "Stopping Services" systemctl stop affine-web affine-worker msg_ok "Stopped Services" create_backup /root/.affine/config /root/.affine/storage - CLEAN_INSTALL=1 fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "latest" "/opt/affine" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "${RELEASE}" "/opt/affine" msg_info "Rebuilding Application (Patience)" cd /opt/affine diff --git a/install/affine-install.sh b/install/affine-install.sh index 2e29234b6..4c15d2403 100644 --- a/install/affine-install.sh +++ b/install/affine-install.sh @@ -30,7 +30,7 @@ PG_DB_NAME="affine" PG_DB_USER="affine" setup_postgresql_db NODE_VERSION="22" setup_nodejs setup_rust -fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "latest" "/opt/affine" +fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "v0.26.3" "/opt/affine" msg_info "Setting up Directories" rm -rf /root/.affine From 80c4b04d83272f4fb8918d62319b070b86615c73 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 20:38:53 +0000 Subject: [PATCH 127/245] Update CHANGELOG.md (#15788) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88c37eb3a..dea512093 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -513,8 +513,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes - - Wanderer: Clean deploy and install plugins for v0.20.0 update [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15759](https://github.com/community-scripts/ProxmoxVE/pull/15759)) - Lychee: Preserve uploads and ownership during update [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15768](https://github.com/community-scripts/ProxmoxVE/pull/15768)) + - Wanderer: Clean deploy and install plugins for v0.20.0 update [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15759](https://github.com/community-scripts/ProxmoxVE/pull/15759)) - FileFlows: Handle update API 401, force update, and Node install [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15766](https://github.com/community-scripts/ProxmoxVE/pull/15766)) - BirdNET-Go: Match new upstream release asset naming [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15758](https://github.com/community-scripts/ProxmoxVE/pull/15758)) - [Upstream Fix] Immich: Fix loader priority [@vhsdream](https://github.com/vhsdream) ([#15755](https://github.com/community-scripts/ProxmoxVE/pull/15755)) @@ -524,6 +524,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Bump OpenCloud version to v7.2.2 [@MickLesk](https://github.com/MickLesk) ([#15769](https://github.com/community-scripts/ProxmoxVE/pull/15769)) - Silverbullet: Add optional Runtime API install via Chromium [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15761](https://github.com/community-scripts/ProxmoxVE/pull/15761)) + - #### 🔧 Refactor + + - AFFiNE: Pin to v0.26.3 [@MickLesk](https://github.com/MickLesk) ([#15782](https://github.com/community-scripts/ProxmoxVE/pull/15782)) + ## 2026-07-13 ### 🆕 New Scripts From 07e31eb5bce1d4bf0efd1601b1f5369e1cd49b4a Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Tue, 14 Jul 2026 22:54:55 +0200 Subject: [PATCH 128/245] Pangolin: Bump to 1.20.0 | BREAKING: Switch to PostgreSQL (#15682) * Pangolin: Bump to 1.20.0 and harden SQLite migrations Bump the default Pangolin version to 1.20.0 in both CT and install scripts. Update the CT upgrade path to validate required 1.20.0 schema objects, clear stale versionMigrations markers when needed, retry migrations once, and abort with a clear error if the schema is still incomplete to avoid a broken runtime. * extend migration check... * another try... * bump pangolin to PSQL * remove migration paths * remove old migrations * use create_backup and restore_backup * Block Pangolin SQLite upgrades Update the Pangolin CT upgrade path to fail fast when PostgreSQL is not installed. The script now explains that upgrades to Pangolin 1.20.0+ require PostgreSQL and that SQLite data cannot be migrated automatically. * fix env * Update pangolin.sh * Update pangolin-install.sh --- ct/pangolin.sh | 39 +++++++++++++++++-------------------- install/pangolin-install.sh | 21 +++++++++++++------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/ct/pangolin.sh b/ct/pangolin.sh index 08d604277..fe5b787a9 100644 --- a/ct/pangolin.sh +++ b/ct/pangolin.sh @@ -6,7 +6,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV # Source: https://pangolin.net/ | Github: https://github.com/fosrl/pangolin APP="Pangolin" -PANGOLIN_VERSION="${PANGOLIN_VERSION:-1.18.4}" +PANGOLIN_VERSION="${PANGOLIN_VERSION:-1.20.0}" var_tags="${var_tags:-proxy}" var_cpu="${var_cpu:-2}" var_ram="${var_ram:-4096}" @@ -33,6 +33,15 @@ function update_script() { ensure_dependencies build-essential python3 + if ! command -v psql &>/dev/null; then + msg_error "This installation uses SQLite and cannot be upgraded to Pangolin ${PANGOLIN_VERSION}." + echo -e "${INFO}${YW}Starting with Pangolin 1.20.0, PostgreSQL is required as the database backend.${CL}" + echo -e "${INFO}${YW}An automatic migration of your existing SQLite data is not supported.${CL}" + echo -e "${INFO}${YW}Please create a new LXC with the Pangolin install script, which sets up PostgreSQL automatically.${CL}" + echo -e "${INFO}${YW}Your current data is preserved in this container and can be manually migrated if needed.${CL}" + exit 1 + fi + NODE_VERSION="24" setup_nodejs if check_for_gh_release "pangolin" "fosrl/pangolin" "$PANGOLIN_VERSION" "Pinned to a tested release because Pangolin's schema changes have repeatedly broken unattended updates. To try a newer version at your own risk, run: 'export PANGOLIN_VERSION=' and re-run update. If it breaks, please open an issue at https://github.com/community-scripts/ProxmoxVE/issues with the error log."; then @@ -41,13 +50,8 @@ function update_script() { systemctl stop gerbil msg_info "Service stopped" - msg_info "Creating backup" - tar -czf /opt/pangolin_config_backup.tar.gz -C /opt/pangolin config - if [[ -f /opt/pangolin/config/db/db.sqlite ]]; then - cp -a /opt/pangolin/config/db/db.sqlite \ - "/opt/pangolin/config/db/db.sqlite.pre-${PANGOLIN_VERSION}-$(date +%Y%m%d-%H%M%S).bak" - fi - msg_ok "Created backup" + DB_URL=$(sed -n 's/.*connection_string: "\(.*\)".*/\1/p' /opt/pangolin/config/config.yml) + create_backup /opt/pangolin/config CLEAN_INSTALL=1 fetch_and_deploy_gh_release "pangolin" "fosrl/pangolin" "tarball" "$PANGOLIN_VERSION" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "gerbil" "fosrl/gerbil" "singlefile" "latest" "/usr/bin" "gerbil_linux_$(arch_resolve)" @@ -55,23 +59,21 @@ function update_script() { msg_info "Updating Pangolin" cd /opt/pangolin $STD npm ci - $STD npm run set:sqlite + $STD npm run set:pg $STD npm run set:oss rm -rf server/private - $STD npm run db:generate + DATABASE_URL="$DB_URL" $STD npm run db:generate $STD npm run build $STD npm run build:cli cp -R .next/standalone ./ + cp -r server/migrations ./dist/init chmod +x ./dist/cli.mjs cp server/db/names.json ./dist/names.json cp server/db/ios_models.json ./dist/ios_models.json cp server/db/mac_models.json ./dist/mac_models.json msg_ok "Updated Pangolin" - msg_info "Restoring config" - tar -xzf /opt/pangolin_config_backup.tar.gz -C /opt/pangolin --overwrite - rm -f /opt/pangolin_config_backup.tar.gz - msg_ok "Restored config" + restore_backup if ! grep -q '^ExecStartPre=/usr/bin/node dist/migrations.mjs' /etc/systemd/system/pangolin.service 2>/dev/null; then msg_info "Adding migration step to pangolin.service" @@ -82,13 +84,8 @@ function update_script() { msg_info "Running database migrations" cd /opt/pangolin - SQLITE_DB="/opt/pangolin/config/db/db.sqlite" - if [[ -f "$SQLITE_DB" ]]; then - if ! sqlite3 "$SQLITE_DB" ".tables" 2>/dev/null | tr ' ' '\n' | grep -qx "statusHistory"; then - sqlite3 "$SQLITE_DB" "DELETE FROM versionMigrations;" 2>/dev/null || true - fi - fi ENVIRONMENT=prod $STD node dist/migrations.mjs + msg_ok "Ran database migrations" msg_info "Updating Badger plugin version" @@ -112,4 +109,4 @@ description msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" echo -e "${INFO}${YW}Access it using the following URL:${CL}" -echo -e "${GATEWAY}${BGN}https://${CL}" +echo -e "${GATEWAY}${BGN}https:// or http://${IP}:3002${CL}" diff --git a/install/pangolin-install.sh b/install/pangolin-install.sh index ab3fc5095..0a8f008af 100644 --- a/install/pangolin-install.sh +++ b/install/pangolin-install.sh @@ -16,18 +16,19 @@ update_os msg_info "Installing Dependencies" $STD apt install -y \ build-essential \ - python3 \ - sqlite3 \ iptables msg_ok "Installed Dependencies" NODE_VERSION="24" setup_nodejs -PANGOLIN_VERSION="${PANGOLIN_VERSION:-1.18.4}" +PG_VERSION="17" setup_postgresql +PG_DB_NAME="pangolin" PG_DB_USER="pangolin" setup_postgresql_db +PANGOLIN_VERSION="${PANGOLIN_VERSION:-1.20.0}" fetch_and_deploy_gh_release "pangolin" "fosrl/pangolin" "tarball" "$PANGOLIN_VERSION" fetch_and_deploy_gh_release "gerbil" "fosrl/gerbil" "singlefile" "latest" "/usr/bin" "gerbil_linux_$(arch_resolve)" fetch_and_deploy_gh_release "traefik" "traefik/traefik" "prebuild" "latest" "/usr/bin" "traefik_v*_linux_$(arch_resolve).tar.gz" read -rp "${TAB3}Enter your Pangolin URL (ex: https://pangolin.example.com): " pango_url +[[ "$pango_url" != https://* && "$pango_url" != http://* ]] && pango_url="https://${pango_url}" read -rp "${TAB3}Enter your email address: " pango_email msg_info "Setup Pangolin" @@ -36,13 +37,14 @@ BADGER_VERSION=$(get_latest_github_release "fosrl/badger" "false") cd /opt/pangolin mkdir -p /opt/pangolin/config/{traefik,db,letsencrypt,logs} $STD npm ci -$STD npm run set:sqlite +$STD npm run set:pg $STD npm run set:oss rm -rf server/private -$STD npm run db:generate +DATABASE_URL="postgresql://pangolin:${PG_DB_PASS}@localhost:5432/pangolin" $STD npm run db:generate $STD npm run build $STD npm run build:cli cp -R .next/standalone ./ +cp -r server/migrations ./dist/init cat </usr/local/bin/pangctl #!/bin/sh @@ -74,6 +76,9 @@ flags: require_email_verification: false disable_signup_without_invite: false disable_user_create_org: false + +postgres: + connection_string: "postgresql://pangolin:${PG_DB_PASS}@localhost:5432/pangolin" EOF cat </opt/pangolin/config/traefik/traefik_config.yml @@ -181,7 +186,8 @@ http: servers: - url: "http://$LOCAL_IP:3000" EOF -$STD npm run db:push +export ENVIRONMENT=prod +$STD node dist/migrations.mjs . /etc/os-release if [ "$VERSION_CODENAME" = "trixie" ]; then @@ -197,7 +203,8 @@ msg_info "Creating Services" cat </etc/systemd/system/pangolin.service [Unit] Description=Pangolin Service -After=network.target +After=network.target postgresql.service +Wants=postgresql.service [Service] Type=simple From 2afea1239cce6876a11c45d300ca47c196774dc1 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 20:55:21 +0000 Subject: [PATCH 129/245] Update CHANGELOG.md (#15789) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dea512093..b87f350c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -524,6 +524,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Bump OpenCloud version to v7.2.2 [@MickLesk](https://github.com/MickLesk) ([#15769](https://github.com/community-scripts/ProxmoxVE/pull/15769)) - Silverbullet: Add optional Runtime API install via Chromium [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15761](https://github.com/community-scripts/ProxmoxVE/pull/15761)) + - #### 💥 Breaking Changes + + - Pangolin: Bump to 1.20.0 | BREAKING: Switch to PostgreSQL [@MickLesk](https://github.com/MickLesk) ([#15682](https://github.com/community-scripts/ProxmoxVE/pull/15682)) + - #### 🔧 Refactor - AFFiNE: Pin to v0.26.3 [@MickLesk](https://github.com/MickLesk) ([#15782](https://github.com/community-scripts/ProxmoxVE/pull/15782)) From c52a69e8e5b8680eed07037b0fbf1e7f0e5997fc Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:55:10 +1000 Subject: [PATCH 130/245] Nexterm (#15688) * Add nexterm (ct) * Remove architecture check from nexterm.sh Removed architecture check for dpkg. * Change var_arm64 default to 'yes' and update fetch commands * Fix license URL and update service creation messages * typo --------- Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com> Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com> --- ct/headers/nexterm | 6 +++ ct/nexterm.sh | 66 +++++++++++++++++++++++++++++ install/nexterm-install.sh | 85 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 ct/headers/nexterm create mode 100644 ct/nexterm.sh create mode 100644 install/nexterm-install.sh diff --git a/ct/headers/nexterm b/ct/headers/nexterm new file mode 100644 index 000000000..7d52bc561 --- /dev/null +++ b/ct/headers/nexterm @@ -0,0 +1,6 @@ + _ __ __ + / | / /__ _ __/ /____ _________ ___ + / |/ / _ \| |/_/ __/ _ \/ ___/ __ `__ \ + / /| / __/> /etc/nexterm-engine/config.yaml +server_host: "127.0.0.1" +server_port: 7800 +registration_token: "${LOCAL_ENGINE_TOKEN}" +tls: false +EOF +cat </etc/nexterm-server/server.env +NODE_ENV=production +SERVER_PORT=6989 +LOCAL_ENGINE_TOKEN=${LOCAL_ENGINE_TOKEN} +ENCRYPTION_KEY=${ENCRYPTION_KEY} +EOF +chmod 0640 /etc/nexterm-engine/config.yaml /etc/nexterm-server/server.env +msg_ok "Configured Nexterm" + +msg_info "Creating Services" +cat </etc/systemd/system/nexterm-server.service +[Unit] +Description=Nexterm Server +Documentation=https://docs.nexterm.dev/ +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/nexterm/data +EnvironmentFile=/etc/nexterm-server/server.env +ExecStart=/opt/nexterm/server/nexterm-server +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +cat </etc/systemd/system/nexterm-engine.service +[Unit] +Description=Nexterm Engine +Documentation=https://docs.nexterm.dev/ +After=network-online.target nexterm-server.service +Wants=network-online.target + +[Service] +Type=simple +User=root +WorkingDirectory=/etc/nexterm-engine +Environment=FREERDP_EXTENSION_PATH=/opt/nexterm/engine/lib/freerdp2 +Environment=LD_LIBRARY_PATH=/opt/nexterm/engine/lib +ExecStart=/opt/nexterm/engine/nexterm-engine +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now nexterm-server +sleep 5 +systemctl enable -q --now nexterm-engine +msg_ok "Created Services" + +motd_ssh +customize +cleanup_lxc From c99768869daff20a9c193c3c9099c9187a59abd2 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Wed, 15 Jul 2026 10:55:37 +0000 Subject: [PATCH 131/245] Update CHANGELOG.md (#15798) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b87f350c6..05c63577e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -502,6 +502,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-15 + +### 🆕 New Scripts + + - Nexterm ([#15688](https://github.com/community-scripts/ProxmoxVE/pull/15688)) + ## 2026-07-14 ### 🆕 New Scripts From 75a1da273f7b2c67b740ae76877bf87b47eb9604 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Wed, 15 Jul 2026 21:35:28 +0200 Subject: [PATCH 132/245] SnapOtter: refactor deployment and installation process (#15797) --- ct/snapotter.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ct/snapotter.sh b/ct/snapotter.sh index 2ebea2959..f0293ad1d 100644 --- a/ct/snapotter.sh +++ b/ct/snapotter.sh @@ -35,14 +35,12 @@ function update_script() { systemctl stop snapotter msg_ok "Stopped Service" - CLEAN_INSTALL=1 fetch_and_deploy_gh_release "snapotter" "snapotter-hq/SnapOtter" "tarball" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "snapotter" "snapotter-hq/SnapOtter" "prebuild" "latest" "/opt/snapotter" "snapotter-*-linux-amd64.tar.gz" msg_info "Updating SnapOtter" - cd /opt/snapotter - $STD npm pkg delete scripts.prepare - $STD pnpm install --frozen-lockfile - $STD pnpm --filter @snapotter/web build - sed -i 's/mediapipe==0.10.21/mediapipe>=0.10.21/' /opt/snapotter/docker/feature-manifest.json + $STD uv python install 3.11 + $STD uv venv --seed --python 3.11 /opt/snapotter_data/ai/venv + ln -sfn /opt/snapotter /app msg_ok "Updated SnapOtter" msg_info "Starting Service" From c759617379d0628fd21e11cdead9e9df5b7fa87b Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Wed, 15 Jul 2026 19:35:52 +0000 Subject: [PATCH 133/245] Update CHANGELOG.md (#15802) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05c63577e..03444fae6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -508,6 +508,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Nexterm ([#15688](https://github.com/community-scripts/ProxmoxVE/pull/15688)) +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - SnapOtter: refactor update process to prebuild [@MickLesk](https://github.com/MickLesk) ([#15797](https://github.com/community-scripts/ProxmoxVE/pull/15797)) + ## 2026-07-14 ### 🆕 New Scripts From 812267aeddab1ea1c93c040f492c493b2a1b8000 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Wed, 15 Jul 2026 21:36:13 +0200 Subject: [PATCH 134/245] 2fauth: minor fixes for 8.0.0 (#15795) --- ct/2fauth.sh | 1 + install/2fauth-install.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/ct/2fauth.sh b/ct/2fauth.sh index 506f140d8..5b5dc3eb7 100644 --- a/ct/2fauth.sh +++ b/ct/2fauth.sh @@ -60,6 +60,7 @@ function update_script() { php artisan 2fauth:install chown -R www-data: /opt/2fauth chmod -R 755 /opt/2fauth + $STD php artisan 2fauth:fix-passport-key-permissions $STD systemctl restart php8.4-fpm $STD systemctl restart nginx msg_ok "Configured 2FAuth" diff --git a/install/2fauth-install.sh b/install/2fauth-install.sh index 386b5c3de..61c8377ae 100644 --- a/install/2fauth-install.sh +++ b/install/2fauth-install.sh @@ -43,6 +43,7 @@ $STD php artisan migrate:refresh $STD php artisan passport:install -q -n $STD php artisan storage:link $STD php artisan config:cache +$STD php artisan 2fauth:fix-passport-key-permissions chown -R www-data: /opt/2fauth chmod -R 755 /opt/2fauth msg_ok "Setup 2fauth" From 66eff7ee87841c38aff0525fb8f268a6beab702a Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Wed, 15 Jul 2026 19:36:37 +0000 Subject: [PATCH 135/245] Update CHANGELOG.md (#15803) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03444fae6..8b1550036 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -512,6 +512,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - 2fauth: minor fixes for 8.0.0 [@MickLesk](https://github.com/MickLesk) ([#15795](https://github.com/community-scripts/ProxmoxVE/pull/15795)) - SnapOtter: refactor update process to prebuild [@MickLesk](https://github.com/MickLesk) ([#15797](https://github.com/community-scripts/ProxmoxVE/pull/15797)) ## 2026-07-14 From 74a233b8b901421b17852e8693b5411ff09135d5 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Wed, 15 Jul 2026 21:37:10 +0200 Subject: [PATCH 136/245] Default Docker setup to official repo (#15794) --- misc/tools.func | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/misc/tools.func b/misc/tools.func index 4a35c695d..82f87ffea 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -4663,20 +4663,20 @@ setup_composer() { # - Cleans up legacy repository files # # Usage: -# setup_docker # Uses distro package (recommended) -# USE_DOCKER_REPO=true setup_docker # Uses official Docker repo +# setup_docker # Uses official Docker repo (recommended) +# USE_DOCKER_REPO=false setup_docker # Uses distro docker.io package # DOCKER_PORTAINER="true" setup_docker # DOCKER_LOG_DRIVER="json-file" setup_docker # # Variables: -# USE_DOCKER_REPO - Set to "true" to use official Docker repository -# (default: false, uses distro docker.io package) +# USE_DOCKER_REPO - Set to "false" to use distro docker.io package +# (default: true, uses official Docker repository) # DOCKER_PORTAINER - Install Portainer CE (optional, "true" to enable) # DOCKER_LOG_DRIVER - Log driver (optional, default: "journald") # DOCKER_SKIP_UPDATES - Skip container update check (optional, "true" to skip) # # Features: -# - Uses stable distro packages by default +# - Uses official Docker repository by default # - Migrates from get.docker.com to repository-based installation # - Updates Docker Engine if newer version available # - Interactive per-container update prompt (Y/N, 60 s auto-no) @@ -4692,7 +4692,7 @@ _docker_is_noninteractive() { setup_docker() { local docker_installed=false local portainer_installed=false - local USE_DOCKER_REPO="${USE_DOCKER_REPO:-false}" + local USE_DOCKER_REPO="${USE_DOCKER_REPO:-true}" # Check if Docker is already installed if command -v docker &>/dev/null; then @@ -4707,7 +4707,7 @@ setup_docker() { msg_info "Portainer container detected" fi - # Scenario 1: Use distro repository (default, most stable) + # Scenario 1: Use distro repository (opt-out via USE_DOCKER_REPO=false) if [[ "$USE_DOCKER_REPO" != "true" && "$USE_DOCKER_REPO" != "TRUE" && "$USE_DOCKER_REPO" != "1" ]]; then # Install or upgrade Docker from distro repo From b36ad5c3a2db0c15a8df768e8e793ee51a776c4b Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Wed, 15 Jul 2026 19:37:39 +0000 Subject: [PATCH 137/245] Update CHANGELOG.md (#15804) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b1550036..08054a113 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -515,6 +515,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - 2fauth: minor fixes for 8.0.0 [@MickLesk](https://github.com/MickLesk) ([#15795](https://github.com/community-scripts/ProxmoxVE/pull/15795)) - SnapOtter: refactor update process to prebuild [@MickLesk](https://github.com/MickLesk) ([#15797](https://github.com/community-scripts/ProxmoxVE/pull/15797)) +### 💾 Core + + - #### 🔧 Refactor + + - tools.func: default Docker setup to official repo [@MickLesk](https://github.com/MickLesk) ([#15794](https://github.com/community-scripts/ProxmoxVE/pull/15794)) + ## 2026-07-14 ### 🆕 New Scripts From d23a2e64e7978d1318ff870927c2ac23cd7cedba Mon Sep 17 00:00:00 2001 From: MickLesk Date: Thu, 16 Jul 2026 09:01:53 +0200 Subject: [PATCH 138/245] migration snapotter --- ct/snapotter.sh | 50 ++++++++++++++++++++++++++++++++++-- install/snapotter-install.sh | 21 +++++++++++++-- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/ct/snapotter.sh b/ct/snapotter.sh index f0293ad1d..ce2323f8f 100644 --- a/ct/snapotter.sh +++ b/ct/snapotter.sh @@ -30,12 +30,58 @@ function update_script() { exit fi - if check_for_gh_release "snapotter" "snapotter-hq/SnapOtter"; then + NEEDS_V2_MIGRATION=false + grep -q '^DB_PATH=' /opt/snapotter_data/.env 2>/dev/null && NEEDS_V2_MIGRATION=true + UPDATE_AVAILABLE=false + check_for_gh_release "snapotter" "snapotter-hq/SnapOtter" && UPDATE_AVAILABLE=true + + if [[ "$NEEDS_V2_MIGRATION" == true || "$UPDATE_AVAILABLE" == true ]]; then msg_info "Stopping Service" systemctl stop snapotter msg_ok "Stopped Service" - CLEAN_INSTALL=1 fetch_and_deploy_gh_release "snapotter" "snapotter-hq/SnapOtter" "prebuild" "latest" "/opt/snapotter" "snapotter-*-linux-amd64.tar.gz" + PG_VERSION="17" setup_postgresql + if ! sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname = 'snapotter'" | grep -qx '1'; then + PG_DB_NAME="snapotter" PG_DB_USER="snapotter" setup_postgresql_db + else + PG_DB_NAME="snapotter" + PG_DB_USER="snapotter" + PG_DB_PASS=$(sed -n 's|^DATABASE_URL=postgres://snapotter:\([^@]*\)@.*|\1|p' /opt/snapotter_data/.env | head -n1) + if [[ -z "$PG_DB_PASS" ]]; then + msg_error "SnapOtter's PostgreSQL database exists, but its password is not available in /opt/snapotter_data/.env" + exit 1 + fi + fi + + msg_info "Installing Redis" + $STD apt install -y redis-server + if grep -q '^appendonly ' /etc/redis/redis.conf; then + sed -i 's/^appendonly .*/appendonly yes/' /etc/redis/redis.conf + else + echo 'appendonly yes' >>/etc/redis/redis.conf + fi + $STD systemctl enable --now redis-server + msg_ok "Installed Redis" + + msg_info "Migrating SnapOtter Configuration" + sed -i '/^DB_PATH=/d; /^DATABASE_URL=/d; /^REDIS_URL=/d; /^SQLITE_MIGRATE_PATH=/d' /opt/snapotter_data/.env + cat <>/opt/snapotter_data/.env +DATABASE_URL=postgres://${PG_DB_USER}:${PG_DB_PASS}@127.0.0.1:5432/${PG_DB_NAME} +REDIS_URL=redis://127.0.0.1:6379 +EOF + if [[ -f /opt/snapotter_data/snapotter.db ]]; then + echo 'SQLITE_MIGRATE_PATH=/opt/snapotter_data/snapotter.db' >>/opt/snapotter_data/.env + fi + if ! grep -q '^Requires=postgresql.service redis-server.service$' /etc/systemd/system/snapotter.service; then + sed -i '/^After=/c\After=network-online.target postgresql.service redis-server.service' /etc/systemd/system/snapotter.service + sed -i '/^\[Unit\]/a Wants=network-online.target\nRequires=postgresql.service redis-server.service' /etc/systemd/system/snapotter.service + fi + systemctl daemon-reload + msg_ok "Migrated SnapOtter Configuration" + + if [[ "$UPDATE_AVAILABLE" == true ]]; then + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "snapotter" "snapotter-hq/SnapOtter" "prebuild" "latest" "/opt/snapotter" "snapotter-*-linux-amd64.tar.gz" + fi msg_info "Updating SnapOtter" $STD uv python install 3.11 diff --git a/install/snapotter-install.sh b/install/snapotter-install.sh index 7878c441a..b8330b7ca 100644 --- a/install/snapotter-install.sh +++ b/install/snapotter-install.sh @@ -39,6 +39,19 @@ msg_ok "Installed Dependencies" PYTHON_VERSION="3.11" setup_uv NODE_VERSION="22" NODE_MODULE="pnpm" setup_nodejs +PG_VERSION="17" setup_postgresql +PG_DB_NAME="snapotter" PG_DB_USER="snapotter" setup_postgresql_db + +msg_info "Installing Redis" +$STD apt install -y redis-server +if grep -q '^appendonly ' /etc/redis/redis.conf; then + sed -i 's/^appendonly .*/appendonly yes/' /etc/redis/redis.conf +else + echo 'appendonly yes' >>/etc/redis/redis.conf +fi +$STD systemctl enable --now redis-server +msg_ok "Installed Redis" + fetch_and_deploy_gh_release "caire" "esimov/caire" "prebuild" "latest" "/usr/local/bin" "caire-*-linux-amd64.tar.gz" fetch_and_deploy_gh_release "snapotter" "snapotter-hq/SnapOtter" "prebuild" "latest" "/opt/snapotter" "snapotter-*-linux-amd64.tar.gz" @@ -61,7 +74,8 @@ mkdir -p /tmp/snapotter-workspace cat </opt/snapotter_data/.env PORT=1349 NODE_ENV=production -DB_PATH=/opt/snapotter_data/snapotter.db +DATABASE_URL=postgres://${PG_DB_USER}:${PG_DB_PASS}@127.0.0.1:5432/${PG_DB_NAME} +REDIS_URL=redis://127.0.0.1:6379 WORKSPACE_PATH=/tmp/snapotter-workspace FILES_STORAGE_PATH=/opt/snapotter_data/files PYTHON_VENV_PATH=/opt/snapotter_data/ai/venv @@ -85,7 +99,9 @@ PNPM_BIN="$(command -v pnpm)" cat </etc/systemd/system/snapotter.service [Unit] Description=SnapOtter Service -After=network.target +Wants=network-online.target +After=network-online.target postgresql.service redis-server.service +Requires=postgresql.service redis-server.service [Service] Type=simple @@ -99,6 +115,7 @@ RestartSec=5 [Install] WantedBy=multi-user.target EOF +systemctl daemon-reload systemctl enable -q --now snapotter msg_ok "Created Service" From 5144f8d0cc82cc05ce0ce4d17563c9be6aac2974 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 07:02:22 +0000 Subject: [PATCH 139/245] Update CHANGELOG.md (#15809) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08054a113..571d939bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -502,6 +502,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-16 + ## 2026-07-15 ### 🆕 New Scripts From c44789f5f6e734ad7f8c4cd5302da9a600802393 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 16 Jul 2026 03:30:38 -0400 Subject: [PATCH 140/245] Pin Immich to v3.0.3 (#15790) --- ct/immich.sh | 2 +- install/immich-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/immich.sh b/ct/immich.sh index e72c4b7fe..1ea66f467 100644 --- a/ct/immich.sh +++ b/ct/immich.sh @@ -110,7 +110,7 @@ EOF msg_ok "Image-processing libraries up to date" fi - RELEASE="v3.0.2" + RELEASE="v3.0.3" if check_for_gh_release "Immich" "immich-app/immich" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then if [[ $(cat ~/.immich) > "2.5.1" ]]; then msg_info "Enabling Maintenance Mode" diff --git a/install/immich-install.sh b/install/immich-install.sh index b75d4a7f2..688ae657e 100644 --- a/install/immich-install.sh +++ b/install/immich-install.sh @@ -312,7 +312,7 @@ ML_DIR="${APP_DIR}/machine-learning" GEO_DIR="${INSTALL_DIR}/geodata" mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache} -fetch_and_deploy_gh_release "Immich" "immich-app/immich" "tarball" "v3.0.2" "$SRC_DIR" +fetch_and_deploy_gh_release "Immich" "immich-app/immich" "tarball" "v3.0.3" "$SRC_DIR" PNPM_VERSION="$(jq -r '.packageManager | split("@")[1] | split("+")[0]' ${SRC_DIR}/package.json)" export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 NODE_VERSION="24" NODE_MODULE="corepack" setup_nodejs From b9f26d66ed5131bcded155ebb83784f303cf4355 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 07:31:00 +0000 Subject: [PATCH 141/245] Update CHANGELOG.md (#15810) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 571d939bb..07e93f2cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -504,6 +504,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-16 +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - Pin Immich to v3.0.3 [@vhsdream](https://github.com/vhsdream) ([#15790](https://github.com/community-scripts/ProxmoxVE/pull/15790)) + ## 2026-07-15 ### 🆕 New Scripts From d122341a470838e6ecc8d8fdc678b460ae1e1c6e Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 18:01:24 +1000 Subject: [PATCH 142/245] Add notediscovery (ct) (#15811) Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com> --- ct/headers/notediscovery | 6 +++ ct/notediscovery.sh | 64 ++++++++++++++++++++++++++++++++ install/notediscovery-install.sh | 51 +++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 ct/headers/notediscovery create mode 100644 ct/notediscovery.sh create mode 100644 install/notediscovery-install.sh diff --git a/ct/headers/notediscovery b/ct/headers/notediscovery new file mode 100644 index 000000000..df51d962d --- /dev/null +++ b/ct/headers/notediscovery @@ -0,0 +1,6 @@ + _ __ __ ____ _ + / | / /___ / /____ / __ \(_)_____________ _ _____ _______ __ + / |/ / __ \/ __/ _ \/ / / / / ___/ ___/ __ \ | / / _ \/ ___/ / / / + / /| / /_/ / /_/ __/ /_/ / (__ ) /__/ /_/ / |/ / __/ / / /_/ / +/_/ |_/\____/\__/\___/_____/_/____/\___/\____/|___/\___/_/ \__, / + /____/ diff --git a/ct/notediscovery.sh b/ct/notediscovery.sh new file mode 100644 index 000000000..3b15fd0c7 --- /dev/null +++ b/ct/notediscovery.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/gamosoft/NoteDiscovery + +APP="NoteDiscovery" +var_tags="${var_tags:-notes;wiki;knowledge-base}" +var_cpu="${var_cpu:-1}" +var_ram="${var_ram:-512}" +var_disk="${var_disk:-4}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/notediscovery ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "notediscovery" "gamosoft/NoteDiscovery"; then + msg_info "Stopping Service" + systemctl stop notediscovery + msg_ok "Stopped Service" + + create_backup /opt/notediscovery/data /opt/notediscovery/config.yaml + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "notediscovery" "gamosoft/NoteDiscovery" "tarball" + + msg_info "Syncing Dependencies" + cd /opt/notediscovery + $STD uv sync --no-dev + msg_ok "Synced Dependencies" + + restore_backup + + msg_info "Starting Service" + systemctl start notediscovery + msg_ok "Started Service" + msg_ok "Updated successfully!" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:8000${CL}" diff --git a/install/notediscovery-install.sh b/install/notediscovery-install.sh new file mode 100644 index 000000000..26687f8c6 --- /dev/null +++ b/install/notediscovery-install.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/gamosoft/NoteDiscovery + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +setup_uv + +fetch_and_deploy_gh_release "notediscovery" "gamosoft/NoteDiscovery" "tarball" + +msg_info "Installing Dependencies" +cd /opt/notediscovery +$STD uv sync --no-dev +msg_ok "Installed Dependencies" + +msg_info "Configuring NoteDiscovery" +mkdir -p /opt/notediscovery/data +msg_ok "Configured NoteDiscovery" + +msg_info "Creating Service" +cat </etc/systemd/system/notediscovery.service +[Unit] +Description=NoteDiscovery Knowledge Base +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/notediscovery +ExecStart=/opt/notediscovery/.venv/bin/python /opt/notediscovery/run.py +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now notediscovery +msg_ok "Created Service" + +motd_ssh +customize +cleanup_lxc From 9bb99c59c583d9c5306635da3a4365c79e82e460 Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 18:01:44 +1000 Subject: [PATCH 143/245] Beaverhabits (#15813) * Add beaverhabits (ct) * Update URL to include '/register' path --------- Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com> Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com> --- ct/beaverhabits.sh | 64 +++++++++++++++++++++++++++++++++ ct/headers/beaverhabits | 6 ++++ install/beaverhabits-install.sh | 53 +++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 ct/beaverhabits.sh create mode 100644 ct/headers/beaverhabits create mode 100644 install/beaverhabits-install.sh diff --git a/ct/beaverhabits.sh b/ct/beaverhabits.sh new file mode 100644 index 000000000..168be42d4 --- /dev/null +++ b/ct/beaverhabits.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/daya0576/beaverhabits + +APP="BeaverHabits" +var_tags="${var_tags:-habits;tracking;productivity}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-1024}" +var_disk="${var_disk:-4}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/beaverhabits ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "beaverhabits" "daya0576/beaverhabits"; then + msg_info "Stopping Service" + systemctl stop beaverhabits + msg_ok "Stopped Service" + + create_backup /opt/beaverhabits/.user + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "beaverhabits" "daya0576/beaverhabits" "tarball" + + msg_info "Syncing Dependencies" + cd /opt/beaverhabits + $STD uv sync --no-dev + msg_ok "Synced Dependencies" + + restore_backup + + msg_info "Starting Service" + systemctl start beaverhabits + msg_ok "Started Service" + msg_ok "Updated successfully!" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:8080/register{CL}" diff --git a/ct/headers/beaverhabits b/ct/headers/beaverhabits new file mode 100644 index 000000000..0a11d4242 --- /dev/null +++ b/ct/headers/beaverhabits @@ -0,0 +1,6 @@ + ____ __ __ __ _ __ + / __ )___ ____ __ _____ _____/ / / /___ _/ /_ (_) /______ + / __ / _ \/ __ `/ | / / _ \/ ___/ /_/ / __ `/ __ \/ / __/ ___/ + / /_/ / __/ /_/ /| |/ / __/ / / __ / /_/ / /_/ / / /_(__ ) +/_____/\___/\__,_/ |___/\___/_/ /_/ /_/\__,_/_.___/_/\__/____/ + diff --git a/install/beaverhabits-install.sh b/install/beaverhabits-install.sh new file mode 100644 index 000000000..f58f4003a --- /dev/null +++ b/install/beaverhabits-install.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/daya0576/beaverhabits + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +PYTHON_VERSION="3.14" setup_uv + +fetch_and_deploy_gh_release "beaverhabits" "daya0576/beaverhabits" "tarball" + +msg_info "Installing Dependencies" +cd /opt/beaverhabits +$STD uv sync --no-dev +msg_ok "Installed Dependencies" + +msg_info "Configuring BeaverHabits" +mkdir -p /opt/beaverhabits/.user +msg_ok "Configured BeaverHabits" + +msg_info "Creating Service" +cat </etc/systemd/system/beaverhabits.service +[Unit] +Description=BeaverHabits Habit Tracker +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/beaverhabits +Environment=HABITS_STORAGE=USER_DISK +Environment=NICEGUI_STORAGE_PATH=/opt/beaverhabits/.user/.nicegui +ExecStart=/opt/beaverhabits/.venv/bin/gunicorn beaverhabits.main:app --bind 0.0.0.0:8080 -w 1 -k uvicorn_worker.UvicornWorker --max-requests 10000 --log-level info +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now beaverhabits +msg_ok "Created Service" + +motd_ssh +customize +cleanup_lxc From 6d6d66eec6f5110a223b9689da8c25b8e9e8ce0a Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 08:01:53 +0000 Subject: [PATCH 144/245] Update CHANGELOG.md (#15814) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07e93f2cf..5b7b02e1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -504,6 +504,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-16 +### 🆕 New Scripts + + - Notediscovery ([#15811](https://github.com/community-scripts/ProxmoxVE/pull/15811)) + ### 🚀 Updated Scripts - #### 🐞 Bug Fixes From 775f1a98c219784fc1da25da0cd74dbe3db990e6 Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 18:02:13 +1000 Subject: [PATCH 145/245] Sync-In (#15812) * Add sync-in (ct) * remove empty lines --------- Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com> Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com> --- ct/headers/sync-in | 6 +++ ct/sync-in.sh | 65 ++++++++++++++++++++++++++++++ install/sync-in-install.sh | 82 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 ct/headers/sync-in create mode 100644 ct/sync-in.sh create mode 100644 install/sync-in-install.sh diff --git a/ct/headers/sync-in b/ct/headers/sync-in new file mode 100644 index 000000000..f5ae41c66 --- /dev/null +++ b/ct/headers/sync-in @@ -0,0 +1,6 @@ + _____ _ + / ___/__ ______ _____ (_)___ + \__ \/ / / / __ \/ ___/_____/ / __ \ + ___/ / /_/ / / / / /__/_____/ / / / / +/____/\__, /_/ /_/\___/ /_/_/ /_/ + /____/ diff --git a/ct/sync-in.sh b/ct/sync-in.sh new file mode 100644 index 000000000..4b43c6dd4 --- /dev/null +++ b/ct/sync-in.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/Sync-in/server + +APP="Sync-in" +var_tags="${var_tags:-files;sync;collaboration}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-20}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/sync-in/node_modules/@sync-in ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "sync-in" "Sync-in/server"; then + msg_info "Stopping Service" + systemctl stop sync-in + msg_ok "Stopped Service" + + msg_info "Updating Sync-in" + $STD npm install --prefix /opt/sync-in "@sync-in/server@${CHECK_UPDATE_RELEASE#v}" + msg_ok "Updated Sync-in" + + msg_info "Running Database Migrations" + cd /opt/sync-in + $STD npx sync-in-server migrate-db + msg_ok "Ran Database Migrations" + + VERSION=$(node -pe "require('/opt/sync-in/node_modules/@sync-in/server/package.json').version" 2>/dev/null || echo "") + [[ -n "$VERSION" ]] && echo "$VERSION" >~/.sync-in + + msg_info "Starting Service" + systemctl start sync-in + msg_ok "Started Service" + msg_ok "Updated successfully!" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:8080${CL}" diff --git a/install/sync-in-install.sh b/install/sync-in-install.sh new file mode 100644 index 000000000..0550fecca --- /dev/null +++ b/install/sync-in-install.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/Sync-in/server + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +NODE_VERSION="22" setup_nodejs +setup_mariadb +MARIADB_DB_NAME="sync_in" MARIADB_DB_USER="sync_in" setup_mariadb_db + +msg_info "Installing Sync-in" +mkdir -p /opt/sync-in/data +$STD npm install --prefix /opt/sync-in @sync-in/server +msg_ok "Installed Sync-in" + +msg_info "Configuring Sync-in" +ENCRYPT_KEY=$(openssl rand -hex 32) +ACCESS_SECRET=$(openssl rand -hex 32) +REFRESH_SECRET=$(openssl rand -hex 32) +cat </opt/sync-in/environment.yaml +server: + port: 8080 +mysql: + url: 'mysql://${MARIADB_DB_USER}:${MARIADB_DB_PASS}@localhost:3306/${MARIADB_DB_NAME}' +auth: + encryptionKey: '${ENCRYPT_KEY}' + token: + access: + secret: '${ACCESS_SECRET}' + refresh: + secret: '${REFRESH_SECRET}' +applications: + files: + dataPath: '/opt/sync-in/data' +EOF +msg_ok "Configured Sync-in" + +msg_info "Running Database Migrations" +cd /opt/sync-in +$STD npx sync-in-server migrate-db +msg_ok "Ran Database Migrations" + +msg_info "Creating Admin User" +cd /opt/sync-in +$STD npx sync-in-server create-user +msg_ok "Created Admin User" + +VERSION=$(node -pe "require('/opt/sync-in/node_modules/@sync-in/server/package.json').version" 2>/dev/null || echo "") +[[ -n "$VERSION" ]] && echo "$VERSION" >~/.sync-in + +msg_info "Creating Service" +cat </etc/systemd/system/sync-in.service +[Unit] +Description=Sync-in Server +After=network.target mariadb.service + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/sync-in +ExecStart=/opt/sync-in/node_modules/.bin/sync-in-server start +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now sync-in +msg_ok "Created Service" + +motd_ssh +customize +cleanup_lxc From 12dec08523df35d0a2ff82f83f9e676d4556e8b7 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 08:02:15 +0000 Subject: [PATCH 146/245] Update CHANGELOG.md (#15815) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b7b02e1a..46862da55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -506,7 +506,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🆕 New Scripts - - Notediscovery ([#15811](https://github.com/community-scripts/ProxmoxVE/pull/15811)) + - Beaverhabits ([#15813](https://github.com/community-scripts/ProxmoxVE/pull/15813)) +- Notediscovery ([#15811](https://github.com/community-scripts/ProxmoxVE/pull/15811)) ### 🚀 Updated Scripts From 04a84f505242ebf5c1ce1d91d0a6e928ea179ab5 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 10:28:25 +0200 Subject: [PATCH 147/245] Update CHANGELOG.md (#15816) Co-authored-by: github-actions[bot] Co-authored-by: Sam Heinz --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46862da55..f4262df4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -506,8 +506,9 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🆕 New Scripts + - Sync-In ([#15812](https://github.com/community-scripts/ProxmoxVE/pull/15812)) - Beaverhabits ([#15813](https://github.com/community-scripts/ProxmoxVE/pull/15813)) -- Notediscovery ([#15811](https://github.com/community-scripts/ProxmoxVE/pull/15811)) + - Notediscovery ([#15811](https://github.com/community-scripts/ProxmoxVE/pull/15811)) ### 🚀 Updated Scripts From 772430de7e101ddc47bbcd75de047550045e478a Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 08:28:51 +0000 Subject: [PATCH 148/245] Update CHANGELOG.md (#15818) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4262df4f..51cae93c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -507,8 +507,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🆕 New Scripts - Sync-In ([#15812](https://github.com/community-scripts/ProxmoxVE/pull/15812)) - - Beaverhabits ([#15813](https://github.com/community-scripts/ProxmoxVE/pull/15813)) - - Notediscovery ([#15811](https://github.com/community-scripts/ProxmoxVE/pull/15811)) +- Beaverhabits ([#15813](https://github.com/community-scripts/ProxmoxVE/pull/15813)) +- Notediscovery ([#15811](https://github.com/community-scripts/ProxmoxVE/pull/15811)) ### 🚀 Updated Scripts From e15db754a633e997b6ac6d4b7fb0b438bb122768 Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner Date: Thu, 16 Jul 2026 11:44:55 +0200 Subject: [PATCH 149/245] github: close PRs that do not follow the PR template Add a workflow that validates description, prerequisites, and type-of-change checkboxes, with exemptions for bots, maintainers, and the keep open label. --- .../workflows/close-invalid-pr-template.yml | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 .github/workflows/close-invalid-pr-template.yml diff --git a/.github/workflows/close-invalid-pr-template.yml b/.github/workflows/close-invalid-pr-template.yml new file mode 100644 index 000000000..ce4c9a1bb --- /dev/null +++ b/.github/workflows/close-invalid-pr-template.yml @@ -0,0 +1,163 @@ +name: Close PRs Missing Template + +on: + pull_request_target: + branches: ["main"] + types: [opened, edited, reopened, synchronize, labeled] + +jobs: + validate-pr-template: + if: github.repository == 'community-scripts/ProxmoxVE' + runs-on: ubuntu-latest + permissions: + pull-requests: write + issues: write + contents: read + steps: + - name: Close PR if it does not follow the PR template + uses: actions/github-script@v7 + with: + script: | + const pr = context.payload.pull_request; + const prNumber = pr.number; + const author = pr.user.login; + const owner = context.repo.owner; + const repo = context.repo.repo; + + const allowedBots = [ + "push-app-to-main[bot]", + "push-app-to-main", + "community-scripts-pr-app", + "github-actions[bot]", + "dependabot[bot]", + ]; + + if (allowedBots.includes(author) || author.endsWith("[bot]")) { + core.info(`PR #${prNumber} by bot "${author}" — skipping template validation.`); + return; + } + + const association = pr.author_association; + const exemptAssociations = ["OWNER", "MEMBER", "COLLABORATOR"]; + if (exemptAssociations.includes(association)) { + core.info(`PR #${prNumber} by ${association} "${author}" — skipping template validation.`); + return; + } + + const labels = pr.labels.map((label) => label.name); + const skipLabels = ["automated pr", "keep open"]; + + if (skipLabels.some((label) => labels.includes(label))) { + core.info(`PR #${prNumber} has a skip label (${labels.join(", ")}) — skipping template validation.`); + return; + } + + if (pr.draft) { + core.info(`PR #${prNumber} is a draft — skipping template validation.`); + return; + } + + const body = pr.body || ""; + const failures = []; + + const requiredSections = [ + "## ✍️ Description", + "## ✅ Prerequisites", + "## 🛠️ Type of Change", + ]; + + for (const section of requiredSections) { + if (!body.includes(section)) { + failures.push(`Missing required section: \`${section}\``); + } + } + + const descriptionMatch = body.match( + /## ✍️ Description\s*\n+([\s\S]*?)(?=\n## )/i + ); + const description = (descriptionMatch?.[1] || "").trim(); + if (!description) { + failures.push("The **Description** section is empty."); + } + + const prerequisiteCheckboxes = [ + "**Self-review completed**", + "**Tested thoroughly**", + "**No security risks**", + ]; + + for (const checkbox of prerequisiteCheckboxes) { + const escaped = checkbox.replace(/([.*+?^=!:${}()|[\]\/\\])/g, "\\$1"); + const regex = new RegExp(`- \\[(x|X)\\]\\s*${escaped}`, "i"); + if (!regex.test(body)) { + failures.push(`Prerequisite not checked: ${checkbox}`); + } + } + + const typeOfChangeCheckboxes = [ + "🐞 **Bug fix**", + "✨ **New feature**", + "💥 **Breaking change**", + "🆕 **New script**", + "🌍 **Website update**", + "🔧 **Refactoring / Code Cleanup**", + "📝 **Documentation update**", + ]; + + const hasTypeChecked = typeOfChangeCheckboxes.some((checkbox) => { + const escaped = checkbox.replace(/([.*+?^=!:${}()|[\]\/\\])/g, "\\$1"); + const regex = new RegExp(`- \\[(x|X)\\]\\s*${escaped}`, "i"); + return regex.test(body); + }); + + if (!hasTypeChecked) { + failures.push("At least one **Type of Change** checkbox must be checked."); + } + + if (failures.length === 0) { + core.info(`PR #${prNumber} follows the PR template.`); + return; + } + + core.info(`Closing PR #${prNumber} — template validation failed.`); + + const templateUrl = + "https://github.com/community-scripts/ProxmoxVE/blob/main/.github/pull_request_template.md"; + const failureList = failures.map((item) => `- ${item}`).join("\n"); + + const comment = [ + `👋 Hi @${author},`, + ``, + `This pull request was closed because it does not follow the [PR template](${templateUrl}).`, + ``, + `Please fix the following and open a new PR (or reopen this one after updating the description):`, + ``, + failureList, + ``, + `> Use the template sections, fill in the description, check all prerequisite boxes, and select at least one type of change.`, + ``, + `Maintainers can add the \`keep open\` label to exempt a PR from this check.`, + ``, + `Thank you for contributing! 🙏`, + ].join("\n"); + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: comment, + }); + + await github.rest.pulls.update({ + owner, + repo, + pull_number: prNumber, + state: "closed", + }); + + await github.rest.issues.addLabels({ + owner, + repo, + issue_number: prNumber, + labels: ["missing pr template"], + }); From 8655282c2dd0ced0be15bc37b07adbc7ef818fb0 Mon Sep 17 00:00:00 2001 From: soupy-boy <50962850+soupy-boy@users.noreply.github.com> Date: Fri, 17 Jul 2026 00:43:05 -0600 Subject: [PATCH 150/245] autoremove and autoclean after apt full-upgrade (#15831) --- tools/pve/update-lxcs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pve/update-lxcs.sh b/tools/pve/update-lxcs.sh index 52e9d2528..e083a4fc2 100644 --- a/tools/pve/update-lxcs.sh +++ b/tools/pve/update-lxcs.sh @@ -78,7 +78,7 @@ function update_container() { alpine) pct exec "$container" -- ash -c "apk -U upgrade" ;; archlinux) pct exec "$container" -- bash -c "pacman -Syyu --noconfirm" ;; fedora | rocky | centos | alma) pct exec "$container" -- bash -c "dnf -y update && dnf -y upgrade" ;; - ubuntu | debian | devuan) pct exec "$container" -- bash -c "apt-get update 2>/dev/null | grep 'packages.*upgraded'; apt list --upgradable 2>/dev/null | cat && apt-get -yq dist-upgrade 2>&1; rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED || true" ;; + ubuntu | debian | devuan) pct exec "$container" -- bash -c "apt-get update 2>/dev/null | grep 'packages.*upgraded'; apt list --upgradable 2>/dev/null | cat && apt-get -yq dist-upgrade 2>&1; apt-get -yq autoremove 2>&1; apt-get -yq autoclean 2>&1; rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED || true" ;; opensuse) pct exec "$container" -- bash -c "zypper ref && zypper --non-interactive dup" ;; esac } From a51e1f37f5c33909ebab38a43b0a19cea38a903b Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 06:43:31 +0000 Subject: [PATCH 151/245] Update CHANGELOG.md (#15836) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51cae93c6..a3b11f22a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -502,6 +502,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-17 + +### 🧰 Tools + + - #### ✨ New Features + + - update-lxc: autoremove and autoclean after apt full-upgrade [@soupy-boy](https://github.com/soupy-boy) ([#15831](https://github.com/community-scripts/ProxmoxVE/pull/15831)) + ## 2026-07-16 ### 🆕 New Scripts From 55002839fb966a65212995bdd5502fb1c7ee697c Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 17 Jul 2026 03:00:32 -0400 Subject: [PATCH 152/245] Pin Opencloud to v7.3.0 (#15826) --- ct/opencloud.sh | 2 +- install/opencloud-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/opencloud.sh b/ct/opencloud.sh index 0ce6d9291..51485fec3 100644 --- a/ct/opencloud.sh +++ b/ct/opencloud.sh @@ -30,7 +30,7 @@ function update_script() { exit fi - RELEASE="v7.2.2" + RELEASE="v7.3.0" if check_for_gh_release "OpenCloud" "opencloud-eu/opencloud" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then msg_info "Stopping services" systemctl stop opencloud opencloud-wopi diff --git a/install/opencloud-install.sh b/install/opencloud-install.sh index f3f1bc93b..d0cb26994 100644 --- a/install/opencloud-install.sh +++ b/install/opencloud-install.sh @@ -64,7 +64,7 @@ $STD sudo -u cool coolconfig set-admin-password --user=admin --password="$COOLPA echo "$COOLPASS" >~/.coolpass msg_ok "Installed Collabora Online" -fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v7.2.2" "/usr/bin" "opencloud-*-linux-$(arch_resolve)" +fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v7.3.0" "/usr/bin" "opencloud-*-linux-$(arch_resolve)" mv /usr/bin/OpenCloud /usr/bin/opencloud msg_info "Configuring OpenCloud" From 3f90af2a214d8bfc2ec9b1d27fcb2c7495fb3a01 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 07:00:56 +0000 Subject: [PATCH 153/245] Update CHANGELOG.md (#15839) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3b11f22a..836222dbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -504,6 +504,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-17 +### 🚀 Updated Scripts + + - #### ✨ New Features + + - Pin Opencloud to v7.3.0 [@vhsdream](https://github.com/vhsdream) ([#15826](https://github.com/community-scripts/ProxmoxVE/pull/15826)) + ### 🧰 Tools - #### ✨ New Features From 5d4eff049323476e96e192b5d9fde03c8ffecd52 Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Fri, 17 Jul 2026 11:59:05 +0200 Subject: [PATCH 154/245] fix(esphome): install libusb-1.0-0 for ESP-IDF native builds (#15838) ESPHome 2026.7.0 validates openocd-esp32 during native ESP-IDF setup, which requires libusb-1.0.so.0. Add the runtime package to install and update paths. Fixes #15835 --- ct/esphome.sh | 1 + install/esphome-install.sh | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ct/esphome.sh b/ct/esphome.sh index 4dcf1ea06..086be0e83 100644 --- a/ct/esphome.sh +++ b/ct/esphome.sh @@ -28,6 +28,7 @@ function update_script() { msg_error "No ${APP} Installation Found!" exit fi + ensure_dependencies libusb-1.0-0 msg_info "Stopping Service" systemctl stop esphome-device-builder 2>/dev/null || true diff --git a/install/esphome-install.sh b/install/esphome-install.sh index 1b5b7367d..02c46b155 100644 --- a/install/esphome-install.sh +++ b/install/esphome-install.sh @@ -14,7 +14,8 @@ network_check update_os msg_info "Installing Dependencies" -$STD apt install -y git +$STD apt install -y git \ + libusb-1.0-0 msg_ok "Installed Dependencies" PYTHON_VERSION="3.12" setup_uv From c991a7eccf5ab4fdf8c50ea4f2bbb6db42b4be9d Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:59:30 +0000 Subject: [PATCH 155/245] Update CHANGELOG.md (#15843) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 836222dbc..4f39a7fa8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -506,6 +506,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🚀 Updated Scripts + - #### 🐞 Bug Fixes + + - esphome: install libusb-1.0-0 for ESP-IDF native builds [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15838](https://github.com/community-scripts/ProxmoxVE/pull/15838)) + - #### ✨ New Features - Pin Opencloud to v7.3.0 [@vhsdream](https://github.com/vhsdream) ([#15826](https://github.com/community-scripts/ProxmoxVE/pull/15826)) From 271df3c3fb8a02c755470264d3693bfdd935589c Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:18:36 +0200 Subject: [PATCH 156/245] feat(build.func): notify users when already on a pinned script version (#15819) Query PocketBase pinned_version/pin_reason during LXC updates and show an informational message when the installed version matches the pin, so users know not to open issues for missing newer updates. --- misc/build.func | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/misc/build.func b/misc/build.func index 93fced258..53509780f 100644 --- a/misc/build.func +++ b/misc/build.func @@ -3753,18 +3753,19 @@ run_addon_updates() { } runtime_script_status_guard() { + local mode="${1:-}" local script_slug="${SCRIPT_SLUG:-${NSAPP:-}}" script_slug="$(echo "$script_slug" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')" [[ -z "$script_slug" ]] && return 0 - local api_url="https://db.community-scripts.org/api/collections/script_scripts/records?filter=(slug='${script_slug}')&perPage=1&fields=slug,is_disabled,is_deleted,disable_message,deleted_message" + local api_url="https://db.community-scripts.org/api/collections/script_scripts/records?filter=(slug='${script_slug}')&perPage=1&fields=slug,is_disabled,is_deleted,disable_message,deleted_message,pinned_version,pin_reason" local response if ! response=$(curl -fsSL --connect-timeout 2 --max-time 3 "$api_url" 2>/dev/null); then msg_warn "Script status check is unavailable. Continuing without status verification." return 0 fi - local is_deleted is_disabled deleted_message disable_message info_url + local is_deleted is_disabled deleted_message disable_message pinned_version pin_reason info_url if printf '%s' "$response" | grep -qE '"items":[[:space:]]*\[[[:space:]]*\]'; then return 0 fi @@ -3774,6 +3775,8 @@ runtime_script_status_guard() { is_disabled=$(printf '%s' "$response" | sed -n 's/.*"is_disabled"[[:space:]]*:[[:space:]]*\(true\|false\).*/\1/p' | head -1) deleted_message=$(printf '%s' "$response" | sed -n 's/.*"deleted_message"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) disable_message=$(printf '%s' "$response" | sed -n 's/.*"disable_message"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) + pinned_version=$(printf '%s' "$response" | sed -n 's/.*"pinned_version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) + pin_reason=$(printf '%s' "$response" | sed -n 's/.*"pin_reason"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) is_deleted=${is_deleted:-false} is_disabled=${is_disabled:-false} info_url="https://community-scripts.org/scripts/${script_slug}" @@ -3805,6 +3808,26 @@ runtime_script_status_guard() { return 1 fi + if [[ "$mode" == "update" && -n "$pinned_version" && -n "${NSAPP:-}" ]]; then + local current_file="$HOME/.${NSAPP}" + if [[ -f "$current_file" ]]; then + local installed pinned_clean installed_clean + installed="$(<"$current_file")" + pinned_clean="$pinned_version" + installed_clean="$installed" + [[ "$pinned_clean" =~ ^v[0-9] ]] && pinned_clean="${pinned_clean:1}" + [[ "$installed_clean" =~ ^v[0-9] ]] && installed_clean="${installed_clean:1}" + if [[ "$installed_clean" == "$pinned_clean" ]]; then + if [[ -n "$pin_reason" ]]; then + msg_info "You are already on the pinned version (${pinned_version}). ${pin_reason}" + else + msg_info "You are already on the pinned version (${pinned_version}). No newer update is offered intentionally — please do not open an issue unless you see an actual error." + fi + msg_info "More info: ${info_url}" + fi + fi + fi + return 0 } @@ -3820,7 +3843,7 @@ runtime_script_status_guard() { start() { source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) if command -v pveversion >/dev/null 2>&1; then - runtime_script_status_guard || return 0 + runtime_script_status_guard install || return 0 install_script || return 0 return 0 elif [ ! -z ${PHS_SILENT+x} ] && [[ "${PHS_SILENT}" == "1" ]]; then @@ -3828,7 +3851,7 @@ start() { set_std_mode ensure_profile_loaded get_lxc_ip - runtime_script_status_guard || return 0 + runtime_script_status_guard update || return 0 update_script run_addon_updates update_motd_ip @@ -3839,7 +3862,7 @@ start() { set_std_mode ensure_profile_loaded get_lxc_ip - runtime_script_status_guard || return 0 + runtime_script_status_guard update || return 0 update_script run_addon_updates update_motd_ip @@ -3869,7 +3892,7 @@ start() { esac ensure_profile_loaded get_lxc_ip - runtime_script_status_guard || return 0 + runtime_script_status_guard update || return 0 update_script run_addon_updates update_motd_ip From f119e8782a74484ae2bfd84801d212a43cd814a2 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 10:18:59 +0000 Subject: [PATCH 157/245] Update CHANGELOG.md (#15844) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f39a7fa8..e16f9052e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -514,6 +514,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Pin Opencloud to v7.3.0 [@vhsdream](https://github.com/vhsdream) ([#15826](https://github.com/community-scripts/ProxmoxVE/pull/15826)) +### 💾 Core + + - #### ✨ New Features + + - feat(build.func): notify users when already on a pinned script version [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15819](https://github.com/community-scripts/ProxmoxVE/pull/15819)) + ### 🧰 Tools - #### ✨ New Features From 7bf45d5b6601e5b8896cd2a2ebbf0fa3105a1055 Mon Sep 17 00:00:00 2001 From: MickLesk Date: Fri, 17 Jul 2026 12:49:24 +0200 Subject: [PATCH 158/245] fix stupid branch delete bot --- .github/workflows/delete-merged-branches.yml | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/delete-merged-branches.yml b/.github/workflows/delete-merged-branches.yml index aafaf2b44..09a9f8ab1 100644 --- a/.github/workflows/delete-merged-branches.yml +++ b/.github/workflows/delete-merged-branches.yml @@ -91,6 +91,30 @@ jobs: let skipped = 0; for (const branch of candidates) { + // A branch name can be reused after an earlier PR was merged. Never delete a + // branch while it is the head of a current open PR, even if it is also a + // candidate from an older merged PR. + try { + const { data: openPrs } = await github.rest.pulls.list({ + owner, + repo, + state: "open", + head: `${owner}:${branch}`, + per_page: 1, + }); + + if (openPrs.length > 0) { + console.log(`Skipped "${branch}" (head of open PR #${openPrs[0].number})`); + skipped++; + continue; + } + } catch (error) { + // Do not risk deleting a branch if GitHub cannot confirm it has no open PR. + console.log(`Failed to check open PRs for "${branch}": ${error.message}`); + skipped++; + continue; + } + // Confirm the branch still exists and isn't protected. let branchData; try { From abc31499a2228db9b6cbfee457703d85544c9452 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:52:57 +0200 Subject: [PATCH 159/245] n8n: unpin / use latest release (#15817) * n8n: unpin / use latest release startup issue is fixed, so unpin and set to latest release * Update n8n installation to latest version --- ct/n8n.sh | 2 +- install/n8n-install.sh | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ct/n8n.sh b/ct/n8n.sh index 8f9cb483b..658a19b6c 100644 --- a/ct/n8n.sh +++ b/ct/n8n.sh @@ -45,7 +45,7 @@ EOF systemctl daemon-reload fi - $STD npm install -g n8n@2.27.5 + $STD npm install -g n8n@latest systemctl restart n8n msg_ok "Updated n8n" msg_ok "Updated successfully!" diff --git a/install/n8n-install.sh b/install/n8n-install.sh index 8ddf37d0b..c6f0d421a 100644 --- a/install/n8n-install.sh +++ b/install/n8n-install.sh @@ -16,7 +16,6 @@ update_os msg_info "Installing Dependencies" $STD apt install -y \ build-essential \ - python3 \ python3-setuptools \ graphicsmagick msg_ok "Installed Dependencies" @@ -24,7 +23,7 @@ msg_ok "Installed Dependencies" NODE_VERSION="24" setup_nodejs msg_info "Installing n8n (Patience)" -$STD npm install -g n8n@2.27.5 +$STD npm install -g n8n@latest msg_ok "Installed n8n" msg_info "Creating Service" From 373ae7e143ce9d4411cb43e28133134b3098c606 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:53:05 +0200 Subject: [PATCH 160/245] MongoDB: Implement kernel version check and patch (#15821) --- misc/tools.func | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/misc/tools.func b/misc/tools.func index 82f87ffea..c80a879d8 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -7431,6 +7431,18 @@ setup_mongodb() { mkdir -p /var/lib/mongodb chown -R mongodb:mongodb /var/lib/mongodb + local KERNEL_VERSION MONGO_MAJOR + KERNEL_VERSION=$(uname -r | cut -d- -f1) + MONGO_MAJOR="${MONGO_VERSION%%.*}" + if ((MONGO_MAJOR >= 8)) && [[ "$(printf '%s\n' "6.19" "$KERNEL_VERSION" | sort -V | head -n1)" == "6.19" ]]; then + mkdir -p /etc/systemd/system/mongod.service.d + cat </etc/systemd/system/mongod.service.d/rseq.conf +[Service] +Environment=GLIBC_TUNABLES=glibc.pthread.rseq=1 +EOF + systemctl daemon-reload + fi + $STD systemctl enable mongod || { msg_warn "Failed to enable mongod service" } From 7c7d40cfe3f4a22137e087738f04f0fd3cff5407 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:53:13 +0200 Subject: [PATCH 161/245] tools.func: enhance rbenv with profile updates / bundle in bashrc (#15822) * tools.func: enhance rbenv with profile updates / bundle in bashrc Added checks to update shell profile files for rbenv integration and removed redundant profile setup code. * Refactor Ruby version installation script * Fix comment formatting in tools.func --- misc/tools.func | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/misc/tools.func b/misc/tools.func index c80a879d8..adb7a5ac4 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -8689,6 +8689,7 @@ setup_postgresql_db() { export PG_DB_USER export PG_DB_PASS } + # ------------------------------------------------------------------------------ # Installs rbenv and ruby-build, installs Ruby and optionally Rails. # @@ -8708,8 +8709,26 @@ setup_ruby() { local RBENV_DIR="$HOME/.rbenv" local RBENV_BIN="$RBENV_DIR/bin/rbenv" local PROFILE_FILE="$HOME/.profile" + local BASH_PROFILE_FILE="$HOME/.bash_profile" + local BASHRC_FILE="$HOME/.bashrc" local TMP_DIR=$(mktemp -d) + if ! grep -q 'rbenv init' "$PROFILE_FILE" 2>/dev/null; then + cat <<'EOF' >>"$PROFILE_FILE" +export PATH="$HOME/.rbenv/bin:$PATH" +eval "$(rbenv init -)" +EOF + fi + if ! grep -q '.rbenv/shims' "$PROFILE_FILE" 2>/dev/null; then + echo 'export PATH="$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH"' >>"$PROFILE_FILE" + fi + if [[ -f "$BASH_PROFILE_FILE" ]] && ! grep -q '.rbenv/shims' "$BASH_PROFILE_FILE"; then + echo 'export PATH="$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH"' >>"$BASH_PROFILE_FILE" + fi + if [[ -f "$BASHRC_FILE" ]] && ! grep -q '.rbenv/shims' "$BASHRC_FILE"; then + echo 'export PATH="$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH"' >>"$BASHRC_FILE" + fi + # Get currently installed Ruby version local CURRENT_RUBY_VERSION="" if [[ -x "$RBENV_BIN" ]]; then From 853f5e868a231519da977c04b01dedc7d1360e25 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 10:53:20 +0000 Subject: [PATCH 162/245] Update CHANGELOG.md (#15846) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e16f9052e..0721bdd1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -512,6 +512,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### ✨ New Features + - n8n: unpin / use latest release [@MickLesk](https://github.com/MickLesk) ([#15817](https://github.com/community-scripts/ProxmoxVE/pull/15817)) - Pin Opencloud to v7.3.0 [@vhsdream](https://github.com/vhsdream) ([#15826](https://github.com/community-scripts/ProxmoxVE/pull/15826)) ### 💾 Core @@ -520,6 +521,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - feat(build.func): notify users when already on a pinned script version [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15819](https://github.com/community-scripts/ProxmoxVE/pull/15819)) + - #### 💥 Breaking Changes + + - MongoDB: Implement kernel version check and patch [@MickLesk](https://github.com/MickLesk) ([#15821](https://github.com/community-scripts/ProxmoxVE/pull/15821)) + ### 🧰 Tools - #### ✨ New Features From 8f2b68ed7e577f362390330f85f9c1aeeda86b12 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 10:53:42 +0000 Subject: [PATCH 163/245] Update CHANGELOG.md (#15847) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0721bdd1e..9471d1a73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -519,6 +519,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### ✨ New Features + - tools.func: enhance rbenv with profile updates / bundle in bashrc [@MickLesk](https://github.com/MickLesk) ([#15822](https://github.com/community-scripts/ProxmoxVE/pull/15822)) - feat(build.func): notify users when already on a pinned script version [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15819](https://github.com/community-scripts/ProxmoxVE/pull/15819)) - #### 💥 Breaking Changes From 79cee47df6682d044f53b8683bebe272af02696f Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Fri, 17 Jul 2026 14:29:59 +0200 Subject: [PATCH 164/245] SFTPGo: Update APT Repo & Re-Enable Script (#15829) * SFTPGo: Update APT Repo & Re-Enable Script * Update sftpgo.sh --- ct/sftpgo.sh | 6 ++++++ install/sftpgo-install.sh | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ct/sftpgo.sh b/ct/sftpgo.sh index d96f013d2..5c6a79adf 100644 --- a/ct/sftpgo.sh +++ b/ct/sftpgo.sh @@ -28,6 +28,12 @@ function update_script() { msg_error "No ${APP} Installation Found!" exit fi + + setup_deb822_repo \ + "sftpgo" \ + "https://oss.sftpgo.com/apt/gpg.key" \ + "https://oss.sftpgo.com/apt" \ + "trixie" msg_info "Updating SFTPGo" $STD apt update diff --git a/install/sftpgo-install.sh b/install/sftpgo-install.sh index d27d4f761..5547d2e59 100644 --- a/install/sftpgo-install.sh +++ b/install/sftpgo-install.sh @@ -19,8 +19,8 @@ msg_ok "Installed Dependencies" setup_deb822_repo \ "sftpgo" \ - "https://ftp.osuosl.org/pub/sftpgo/apt/gpg.key" \ - "https://ftp.osuosl.org/pub/sftpgo/apt" \ + "https://oss.sftpgo.com/apt/gpg.key" \ + "https://oss.sftpgo.com/apt" \ "trixie" msg_info "Installing SFTPGo" From e7557c235541c56752f345baa6ab6b3b8708c36b Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:30:21 +0000 Subject: [PATCH 165/245] Update CHANGELOG.md (#15849) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9471d1a73..eeccce0b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -515,6 +515,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - n8n: unpin / use latest release [@MickLesk](https://github.com/MickLesk) ([#15817](https://github.com/community-scripts/ProxmoxVE/pull/15817)) - Pin Opencloud to v7.3.0 [@vhsdream](https://github.com/vhsdream) ([#15826](https://github.com/community-scripts/ProxmoxVE/pull/15826)) + - #### 🔧 Refactor + + - SFTPGo: Update APT Repo & Re-Enable Script [@MickLesk](https://github.com/MickLesk) ([#15829](https://github.com/community-scripts/ProxmoxVE/pull/15829)) + ### 💾 Core - #### ✨ New Features From 2ab4a31dd1fa9c40662a8f2761c7d9a8872e8d6f Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 14:30:27 +0200 Subject: [PATCH 166/245] OxiCloud (#15823) * Add oxicloud (ct) * Update ct/oxicloud.sh --------- Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com> Co-authored-by: Sam Heinz --- ct/headers/oxicloud | 6 +++ ct/oxicloud.sh | 85 +++++++++++++++++++++++++++++++++++ install/oxicloud-install.sh | 88 +++++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 ct/headers/oxicloud create mode 100644 ct/oxicloud.sh create mode 100644 install/oxicloud-install.sh diff --git a/ct/headers/oxicloud b/ct/headers/oxicloud new file mode 100644 index 000000000..b48c6ee29 --- /dev/null +++ b/ct/headers/oxicloud @@ -0,0 +1,6 @@ + ____ _ ________ __ + / __ \_ __(_) ____/ /___ __ ______/ / + / / / / |/_/ / / / / __ \/ / / / __ / +/ /_/ /> /etc/oxicloud/.env +chmod 600 /etc/oxicloud/.env +msg_ok "Configured OxiCloud" + +msg_info "Creating OxiCloud Service" +cat </etc/systemd/system/oxicloud.service +[Unit] +Description=OxiCloud Service +After=network.target postgresql.service +Requires=postgresql.service + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/oxicloud +EnvironmentFile=/etc/oxicloud/.env +ExecStart=/usr/local/bin/oxicloud +Restart=always +RestartSec=5 +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now oxicloud +msg_ok "Created OxiCloud Service" + +motd_ssh +customize +cleanup_lxc From 13d7bf6c7807fcfa17b348801bd88c227c5a44e0 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:30:43 +0000 Subject: [PATCH 167/245] Update CHANGELOG.md (#15850) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eeccce0b8..799803123 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -504,6 +504,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-17 +### 🆕 New Scripts + + - OxiCloud ([#15823](https://github.com/community-scripts/ProxmoxVE/pull/15823)) + ### 🚀 Updated Scripts - #### 🐞 Bug Fixes From ff192c45304745f786091593e22633923c9da911 Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 14:30:55 +0200 Subject: [PATCH 169/245] Invidious (#15824) * Add invidious (ct) * Update install/invidious-install.sh * Update install/invidious-install.sh * Update install/invidious-install.sh * Update ct/invidious.sh * Update ct/invidious.sh --------- Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com> Co-authored-by: Sam Heinz --- ct/headers/invidious | 6 ++ ct/invidious.sh | 77 ++++++++++++++++++++++ install/invidious-install.sh | 121 +++++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 ct/headers/invidious create mode 100644 ct/invidious.sh create mode 100644 install/invidious-install.sh diff --git a/ct/headers/invidious b/ct/headers/invidious new file mode 100644 index 000000000..c858744dd --- /dev/null +++ b/ct/headers/invidious @@ -0,0 +1,6 @@ + ____ _ ___ + / _/___ _ __(_)___/ (_)___ __ _______ + / // __ \ | / / / __ / / __ \/ / / / ___/ + _/ // / / / |/ / / /_/ / / /_/ / /_/ (__ ) +/___/_/ /_/|___/_/\__,_/_/\____/\__,_/____/ + diff --git a/ct/invidious.sh b/ct/invidious.sh new file mode 100644 index 000000000..b3b68a632 --- /dev/null +++ b/ct/invidious.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: vhsdream +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/iv-org/invidious + +APP="Invidious" +var_tags="${var_tags:-streaming}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-4096}" +var_disk="${var_disk:-20}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/invidious ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "Invidious" "iv-org/invidious"; then + msg_info "Stopping services" + $STD systemctl stop invidious-companion invidious + msg_ok "Stopped services" + + create_backup /opt/invidious/config/config.yml + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Invidious" "iv-org/invidious" "tarball" "latest" "/opt/invidious" + if check_for_gh_release "Invidious-Companion" "iv-org/invidious-companion"; then + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Invidious-Companion" "iv-org/invidious-companion" "prebuild" "latest" "/opt/invidious-companion" "invidious_companion-$(arch_resolve x86_64 aarch64)-unknown-linux-gnu.tar.gz" + fi + + msg_info "Rebuilding Invidious" + cd /opt/invidious + INVIDIOUS_VERSION="$(cat ~/.invidious 2>/dev/null || echo "unknown")" + INVIDIOUS_VERSION="${INVIDIOUS_VERSION#v}" + sed -i \ + -e "s~^\(\s*CURRENT_BRANCH\s*=\).*~\1 \"master\"~" \ + -e "s~^\(\s*CURRENT_COMMIT\s*=\).*~\1 \"\"~" \ + -e "s~^\(\s*CURRENT_VERSION\s*=\).*~\1 \"${INVIDIOUS_VERSION}\"~" \ + -e "s~^\(\s*CURRENT_TAG\s*=\).*~\1 \"${INVIDIOUS_VERSION}\"~" \ + -e "s~^\(\s*ASSET_COMMIT\s*=\).*~\1 \"\"~" \ + src/invidious.cr + $STD make + msg_ok "Rebuilt Invidious" + + restore_backup + + msg_info "Starting services" + $STD systemctl start invidious invidious-companion + msg_ok "Started services" + msg_ok "Updated successfully!" + fi + exit +} + +start +build_container +description + +msg_ok "Completed successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}" diff --git a/install/invidious-install.sh b/install/invidious-install.sh new file mode 100644 index 000000000..798b09e92 --- /dev/null +++ b/install/invidious-install.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: vhsdream +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/iv-org/invidious + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt install -y \ + build-essential \ + git \ + pkg-config \ + libssl-dev \ + libxml2-dev \ + libyaml-dev \ + libgmp-dev \ + libreadline-dev \ + librsvg2-bin \ + libsqlite3-dev \ + zlib1g-dev \ + libpcre2-dev \ + libevent-dev \ + fonts-open-sans +msg_ok "Installed Dependencies" + +if [[ "$(arch_resolve amd64 arm64)" == "amd64" ]]; then + setup_deb822_repo "crystal" "https://download.opensuse.org/repositories/devel:/languages:/crystal/Debian_13/Release.key" "https://download.opensuse.org/repositories/devel:/languages:/crystal/Debian_13/" "./" + $STD apt install -y crystal +else + fetch_and_deploy_gh_release "Crystal" "crystal-lang/crystal" "prebuild" "latest" "/opt/crystal" "crystal-*-linux-aarch64-bundled.tar.gz" + ln -sf /opt/crystal/bin/crystal /usr/local/bin/crystal + ln -sf /opt/crystal/bin/shards /usr/local/bin/shards +fi + +PG_VERSION="17" setup_postgresql +PG_DB_NAME="invidious" PG_DB_USER="invidious" setup_postgresql_db +fetch_and_deploy_gh_release "Invidious" "iv-org/invidious" "tarball" "latest" "/opt/invidious" +fetch_and_deploy_gh_release "Invidious Companion" "iv-org/invidious-companion" "prebuild" "latest" "/opt/invidious-companion" "invidious_companion-$(arch_resolve x86_64 aarch64)-unknown-linux-gnu.tar.gz" + +msg_info "Building Invidious" +cd /opt/invidious +INVIDIOUS_VERSION="$(cat ~/.invidious 2>/dev/null || echo "unknown")" +INVIDIOUS_VERSION="${INVIDIOUS_VERSION#v}" +sed -i \ + -e "s~^\(\s*CURRENT_BRANCH\s*=\).*~\1 \"master\"~" \ + -e "s~^\(\s*CURRENT_COMMIT\s*=\).*~\1 \"\"~" \ + -e "s~^\(\s*CURRENT_VERSION\s*=\).*~\1 \"${INVIDIOUS_VERSION}\"~" \ + -e "s~^\(\s*CURRENT_TAG\s*=\).*~\1 \"${INVIDIOUS_VERSION}\"~" \ + -e "s~^\(\s*ASSET_COMMIT\s*=\).*~\1 \"\"~" \ + src/invidious.cr +$STD make +msg_ok "Built Invidious" + +msg_info "Configuring Invidious" +SECRET_KEY="$(openssl rand -hex 8)" +HMAC_KEY="$(openssl rand -hex 32)" +sed -e '\~^db:~,\~dbname:~d' \ + -e "s~^#database_.*~database_url: postgres://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}~" \ + -e 's~^#check_tables.*~check_tables: true~' \ + -e 's~^#invidious_companion:~invidious_companion:~' \ + -e 's~^# - private_~ - private_~' \ + -e "s~^#invidious_companion_key:.*~invidious_companion_key: \"${SECRET_KEY}\"~" \ + -e "s~^hmac_key:.*~hmac_key: \"${HMAC_KEY}\"~" \ + /opt/invidious/config/config.example.yml >/opt/invidious/config/config.yml +chmod 600 /opt/invidious/config/config.yml + +cat </etc/logrotate.d/invidious.logrotate +/opt/invidious/invidious.log { + rotate 4 + weekly + notifempty + missingok + compress + minsize 1048576 +} +EOF +chmod 0644 /etc/logrotate.d/invidious.logrotate +msg_ok "Configured Invidious" + +msg_info "Migrating database" +$STD ./invidious --migrate +msg_ok "Migrated database" + +msg_info "Configuring services" +sed -e 's|^User=invidious|User=root|' \ + -e 's|^Group=invidious|Group=root|' \ + -e 's|/home/invidious/invidious|/opt/invidious|g' \ + /opt/invidious/invidious.service >/etc/systemd/system/invidious.service +mkdir -p /var/tmp/youtubei.js +cat </etc/systemd/system/invidious-companion.service +[Unit] +Description=Invidious Companion +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/invidious-companion +Environment=SERVER_SECRET_KEY=${SECRET_KEY} +Environment=CACHE_DIRECTORY=/var/tmp/youtubei.js +ExecStart=/opt/invidious-companion/invidious_companion +Restart=always +RestartSec=2s + +[Install] +WantedBy=multi-user.target +EOF +systemctl -q enable --now invidious invidious-companion +msg_ok "Configured services" + +motd_ssh +customize +cleanup_lxc From b1259e3749cd1340d735a9617ba9151c4027301b Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:31:05 +0000 Subject: [PATCH 170/245] Update CHANGELOG.md (#15852) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 799803123..51e416806 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -506,7 +506,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🆕 New Scripts - - OxiCloud ([#15823](https://github.com/community-scripts/ProxmoxVE/pull/15823)) + - Invidious ([#15824](https://github.com/community-scripts/ProxmoxVE/pull/15824)) +- OxiCloud ([#15823](https://github.com/community-scripts/ProxmoxVE/pull/15823)) ### 🚀 Updated Scripts From d2ecb9f44c3f3aa57980d9c23c84c8556e387b79 Mon Sep 17 00:00:00 2001 From: Austin Date: Fri, 17 Jul 2026 15:02:47 -0400 Subject: [PATCH 172/245] CLIProxyAPI: fix update deleting config.yaml (#15834) --- ct/cliproxyapi.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ct/cliproxyapi.sh b/ct/cliproxyapi.sh index 9eb49a1a6..40f9f2b1f 100644 --- a/ct/cliproxyapi.sh +++ b/ct/cliproxyapi.sh @@ -36,8 +36,12 @@ function update_script() { systemctl stop cliproxyapi msg_ok "Stopped CLIProxyAPI" + create_backup /opt/cliproxyapi/config.yaml + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "cliproxyapi" "router-for-me/CLIProxyAPI" "prebuild" "latest" "/opt/cliproxyapi" "CLIProxyAPI_*_linux_$(arch_resolve "amd64" "aarch64").tar.gz" + restore_backup + msg_info "Starting CLIProxyAPI" systemctl start cliproxyapi msg_ok "Started CLIProxyAPI" From 29552c6e2ead168ed296fdd2a61a158144b3401b Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 19:03:14 +0000 Subject: [PATCH 173/245] Update CHANGELOG.md (#15859) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51e416806..c09d83fab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -513,6 +513,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - CLIProxyAPI: fix update deleting config.yaml [@austinpilz](https://github.com/austinpilz) ([#15834](https://github.com/community-scripts/ProxmoxVE/pull/15834)) - esphome: install libusb-1.0-0 for ESP-IDF native builds [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15838](https://github.com/community-scripts/ProxmoxVE/pull/15838)) - #### ✨ New Features From b2936ff9ce1e819653eb3ea6081c511e7cbc3c3f Mon Sep 17 00:00:00 2001 From: TowyTowy <85077986+TowyTowy@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:04:31 +0200 Subject: [PATCH 174/245] fix(apache-guacamole): detect installed extensions during update (#15841) --- ct/apache-guacamole.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ct/apache-guacamole.sh b/ct/apache-guacamole.sh index bbd9673cc..89f1b973b 100644 --- a/ct/apache-guacamole.sh +++ b/ct/apache-guacamole.sh @@ -146,7 +146,7 @@ function update_script() { # Check and upgrade optional extensions # TOTP Extension - if [[ -f /etc/guacamole/extensions/guacamole-auth-totp-*.jar ]]; then + if compgen -G "/etc/guacamole/extensions/guacamole-auth-totp-*.jar" >/dev/null; then msg_info "Updating TOTP Extension" rm -f /etc/guacamole/extensions/guacamole-auth-totp-*.jar curl_download "/tmp/guacamole-auth-totp.tar.gz" "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-totp-${LATEST_SERVER}.tar.gz" @@ -158,7 +158,7 @@ function update_script() { fi # DUO Extension - if [[ -f /etc/guacamole/extensions/guacamole-auth-duo-*.jar ]]; then + if compgen -G "/etc/guacamole/extensions/guacamole-auth-duo-*.jar" >/dev/null; then msg_info "Updating DUO Extension" rm -f /etc/guacamole/extensions/guacamole-auth-duo-*.jar curl_download "/tmp/guacamole-auth-duo.tar.gz" "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-duo-${LATEST_SERVER}.tar.gz" @@ -170,7 +170,7 @@ function update_script() { fi # LDAP Extension - if [[ -f /etc/guacamole/extensions/guacamole-auth-ldap-*.jar ]]; then + if compgen -G "/etc/guacamole/extensions/guacamole-auth-ldap-*.jar" >/dev/null; then msg_info "Updating LDAP Extension" rm -f /etc/guacamole/extensions/guacamole-auth-ldap-*.jar curl_download "/tmp/guacamole-auth-ldap.tar.gz" "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-ldap-${LATEST_SERVER}.tar.gz" @@ -182,7 +182,7 @@ function update_script() { fi # Quick Connect Extension - if [[ -f /etc/guacamole/extensions/guacamole-auth-quickconnect-*.jar ]]; then + if compgen -G "/etc/guacamole/extensions/guacamole-auth-quickconnect-*.jar" >/dev/null; then msg_info "Updating Quick Connect Extension" rm -f /etc/guacamole/extensions/guacamole-auth-quickconnect-*.jar curl_download "/tmp/guacamole-auth-quickconnect.tar.gz" "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-quickconnect-${LATEST_SERVER}.tar.gz" @@ -194,7 +194,7 @@ function update_script() { fi # History Recording Storage Extension - if [[ -f /etc/guacamole/extensions/guacamole-history-recording-storage-*.jar ]]; then + if compgen -G "/etc/guacamole/extensions/guacamole-history-recording-storage-*.jar" >/dev/null; then msg_info "Updating History Recording Storage Extension" rm -f /etc/guacamole/extensions/guacamole-history-recording-storage-*.jar curl_download "/tmp/guacamole-history-recording-storage.tar.gz" "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-history-recording-storage-${LATEST_SERVER}.tar.gz" From b5360882c90946d92d5faea0f85dbf7b10c5d8fe Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 19:04:58 +0000 Subject: [PATCH 175/245] Update CHANGELOG.md (#15860) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c09d83fab..14b0f895e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -513,6 +513,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - apache-guacamole: detect installed extensions during update [@TowyTowy](https://github.com/TowyTowy) ([#15841](https://github.com/community-scripts/ProxmoxVE/pull/15841)) - CLIProxyAPI: fix update deleting config.yaml [@austinpilz](https://github.com/austinpilz) ([#15834](https://github.com/community-scripts/ProxmoxVE/pull/15834)) - esphome: install libusb-1.0-0 for ESP-IDF native builds [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15838](https://github.com/community-scripts/ProxmoxVE/pull/15838)) From f75b0a8b0e423c8c743ae9c3730ec98b9d94d159 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:05:10 +0200 Subject: [PATCH 176/245] AFFiNE: Bump to 0.27.0 (#15848) --- ct/affine.sh | 11 +++++++---- install/affine-install.sh | 10 ++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/ct/affine.sh b/ct/affine.sh index 236a225bd..1480c2a99 100644 --- a/ct/affine.sh +++ b/ct/affine.sh @@ -30,17 +30,19 @@ function update_script() { exit fi - RELEASE="v0.26.3" + RELEASE="v0.27.0" if check_for_gh_release "affine_app" "toeverything/AFFiNE" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then msg_info "Stopping Services" systemctl stop affine-web affine-worker msg_ok "Stopped Services" + ensure_dependencies cmake + create_backup /root/.affine/config /root/.affine/storage CLEAN_INSTALL=1 fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "${RELEASE}" "/opt/affine" - msg_info "Rebuilding Application (Patience)" + msg_info "Rebuilding Application (Patience ~25 mins, don't close the console!)" cd /opt/affine source /root/.profile export PATH="/root/.cargo/bin:/root/.rbenv/shims:$PATH" @@ -51,11 +53,12 @@ function update_script() { export VITE_CORE_COMMIT_SHA=$(cat ~/.affine_app) # Initialize git repo (required for build process) + export HUSKY=0 $STD git init -q $STD git config user.email "build@local" $STD git config user.name "Build" $STD git add -A - $STD git commit -q -m "update" + $STD git commit -q -m "update" --no-verify --allow-empty # Force Turbo to run sequentially mkdir -p /opt/affine/.turbo @@ -66,7 +69,7 @@ function update_script() { TURBO $STD corepack enable - $STD corepack prepare yarn@4.12.0 --activate + $STD corepack prepare yarn@4.13.0 --activate $STD yarn config set enableTelemetry 0 export NODE_OPTIONS="--max-old-space-size=2048" diff --git a/install/affine-install.sh b/install/affine-install.sh index 4c15d2403..50144d4e0 100644 --- a/install/affine-install.sh +++ b/install/affine-install.sh @@ -22,7 +22,8 @@ $STD apt install -y \ libssl-dev \ libjemalloc2 \ redis-server \ - nginx + nginx \ + cmake msg_ok "Installed Dependencies" PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql @@ -30,7 +31,7 @@ PG_DB_NAME="affine" PG_DB_USER="affine" setup_postgresql_db NODE_VERSION="22" setup_nodejs setup_rust -fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "v0.26.3" "/opt/affine" +fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "v0.27.0" "/opt/affine" msg_info "Setting up Directories" rm -rf /root/.affine @@ -59,11 +60,12 @@ export PATH="/root/.cargo/bin:$PATH" export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 export VITE_CORE_COMMIT_SHA=$(cat ~/.affine_app) # # Initialize git repo (required for build process) +export HUSKY=0 $STD git init -q $STD git config user.email "build@local" $STD git config user.name "Build" $STD git add -A -$STD git commit -q -m "initial" +$STD git commit -q -m "update" --no-verify --allow-empty mkdir -p /opt/affine/.turbo cat </opt/affine/.turbo/config.json { @@ -71,7 +73,7 @@ cat </opt/affine/.turbo/config.json } TURBO $STD corepack enable -$STD corepack prepare yarn@4.12.0 --activate +$STD corepack prepare yarn@4.13.0 --activate $STD yarn config set enableTelemetry 0 export NODE_OPTIONS="--max-old-space-size=4096" export TSC_COMPILE_ON_ERROR=true From 0b15e1950019e693c096dc687760142d14523212 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 19:05:36 +0000 Subject: [PATCH 177/245] Update CHANGELOG.md (#15861) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14b0f895e..81d72a7b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -519,6 +519,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### ✨ New Features + - AFFiNE: Bump to 0.27.0 [@MickLesk](https://github.com/MickLesk) ([#15848](https://github.com/community-scripts/ProxmoxVE/pull/15848)) - n8n: unpin / use latest release [@MickLesk](https://github.com/MickLesk) ([#15817](https://github.com/community-scripts/ProxmoxVE/pull/15817)) - Pin Opencloud to v7.3.0 [@vhsdream](https://github.com/vhsdream) ([#15826](https://github.com/community-scripts/ProxmoxVE/pull/15826)) From 78990277f2488b045d1d02d3c406edfbbbb924ce Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:13:19 +0200 Subject: [PATCH 178/245] Fix DocuSeal missing Leptonica deps on install and update (#15858) * Initial plan * Fix DocuSeal leptonica dependencies --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- ct/docuseal.sh | 2 ++ install/docuseal-install.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ct/docuseal.sh b/ct/docuseal.sh index d856d1694..9fbdca313 100644 --- a/ct/docuseal.sh +++ b/ct/docuseal.sh @@ -35,6 +35,8 @@ function update_script() { systemctl stop docuseal docuseal-sidekiq msg_ok "Stopped Services" + ensure_dependencies libleptonica-dev libleptonica6 + create_backup /opt/docuseal/.env \ /opt/docuseal/data diff --git a/install/docuseal-install.sh b/install/docuseal-install.sh index 82c89bfc6..e502256e3 100644 --- a/install/docuseal-install.sh +++ b/install/docuseal-install.sh @@ -23,6 +23,8 @@ $STD apt install -y \ libreadline-dev \ zlib1g-dev \ libffi-dev \ + libleptonica-dev \ + libleptonica6 \ libvips42 \ libvips-dev \ libheif1 \ From c0a327dad8de829d571c9a44b4d5c602e453dc48 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 19:13:41 +0000 Subject: [PATCH 179/245] Update CHANGELOG.md (#15862) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81d72a7b2..d6aa7f1e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -513,6 +513,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - Fix DocuSeal missing Leptonica deps on install and update [@Copilot](https://github.com/Copilot) ([#15858](https://github.com/community-scripts/ProxmoxVE/pull/15858)) - apache-guacamole: detect installed extensions during update [@TowyTowy](https://github.com/TowyTowy) ([#15841](https://github.com/community-scripts/ProxmoxVE/pull/15841)) - CLIProxyAPI: fix update deleting config.yaml [@austinpilz](https://github.com/austinpilz) ([#15834](https://github.com/community-scripts/ProxmoxVE/pull/15834)) - esphome: install libusb-1.0-0 for ESP-IDF native builds [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15838](https://github.com/community-scripts/ProxmoxVE/pull/15838)) From 3f7228f9c6c53a65db7dd08a846cf4514606756a Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:16:15 +0200 Subject: [PATCH 180/245] fix(webtrees): initialize database schema before admin user creation (#15837) PR #14818 replaced the setup wizard curl with CLI commands but omitted the schema migration step, causing fresh installs to fail when creating the admin user. Trigger schema init via HTTP after config-ini. Fixes #15828 --- install/webtrees-install.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/install/webtrees-install.sh b/install/webtrees-install.sh index c2be2e79e..69b735e46 100644 --- a/install/webtrees-install.sh +++ b/install/webtrees-install.sh @@ -47,6 +47,8 @@ msg_ok "Configured Caddy" msg_info "Automating Webtrees Setup" cd /opt/webtrees +mkdir -p /opt/webtrees/data +chown -R www-data:www-data /opt/webtrees/data WT_ADMIN_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c15) $STD sudo -u www-data php /opt/webtrees/index.php config-ini \ --dbhost=127.0.0.1 \ @@ -56,6 +58,15 @@ $STD sudo -u www-data php /opt/webtrees/index.php config-ini \ --dbname=webtrees \ --tblpfx=wt_ \ --base-url="http://${LOCAL_IP}" +msg_info "Initializing Webtrees database schema" +for i in {1..15}; do + if curl -sf "http://127.0.0.1/" >/dev/null 2>&1; then + break + fi + sleep 2 +done +$STD mariadb -u webtrees -p"${MARIADB_DB_PASS}" -h 127.0.0.1 webtrees -e "SHOW TABLES LIKE 'wt_user';" | grep -q wt_user +msg_ok "Initialized Webtrees database schema" $STD sudo -u www-data php /opt/webtrees/index.php user Admin \ --create \ --real-name="Administrator" \ From c24bba00ded0fd9b6ebcde69477786ec825910d3 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 19:16:42 +0000 Subject: [PATCH 181/245] Update CHANGELOG.md (#15863) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6aa7f1e6..ab484bb31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -513,6 +513,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - webtrees: initialize database schema before admin user creation [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15837](https://github.com/community-scripts/ProxmoxVE/pull/15837)) - Fix DocuSeal missing Leptonica deps on install and update [@Copilot](https://github.com/Copilot) ([#15858](https://github.com/community-scripts/ProxmoxVE/pull/15858)) - apache-guacamole: detect installed extensions during update [@TowyTowy](https://github.com/TowyTowy) ([#15841](https://github.com/community-scripts/ProxmoxVE/pull/15841)) - CLIProxyAPI: fix update deleting config.yaml [@austinpilz](https://github.com/austinpilz) ([#15834](https://github.com/community-scripts/ProxmoxVE/pull/15834)) From 7f1b0ead93e011757dd52b07846060db9ff56e95 Mon Sep 17 00:00:00 2001 From: Sir106 Date: Sat, 18 Jul 2026 22:19:31 +0200 Subject: [PATCH 182/245] [tools.update-lxcs] feat: optional reporting success/failures to heathchecks.io (or others) (#15701) * feat: add task monitoring option via e.g. healthchecks.io. To be configured via PING variable in config file. * attach logfile on failure to healthcheck.io message * fixed error status when updating lxc even if finished successful --------- Co-authored-by: Sir106 --- tools/pve/cron-update-lxcs.sh | 11 ++++++-- tools/pve/update-lxcs-cron.sh | 48 ++++++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/tools/pve/cron-update-lxcs.sh b/tools/pve/cron-update-lxcs.sh index c97975c44..437c7e472 100644 --- a/tools/pve/cron-update-lxcs.sh +++ b/tools/pve/cron-update-lxcs.sh @@ -116,6 +116,9 @@ add() { # Add container IDs to exclude from updates (comma-separated): # EXCLUDE=100,101,102 EXCLUDE= + +# Healthchecks.io Ping URL (optional) +# PING_URL= CONF ok "Created config ${CONF_FILE}" fi @@ -235,9 +238,11 @@ view_cron_config() { fi if [[ -f "$CONF_FILE" ]]; then echo -e " \e[36mConfig file:\e[0m ${CONF_FILE}" - local excludes + local excludes ping_url excludes=$(grep -oP '^\s*EXCLUDE\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null || true) + ping_url=$(grep -oP '^\s*PING_URL\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null | tr -d '"' | tr -d "'" || true) echo -e " \e[36mExcluded:\e[0m ${excludes:-(none)}" + echo -e " \e[36mPing URL:\e[0m ${ping_url:-(none)}" echo "" echo -e " \e[90m--- ${CONF_FILE} ---\e[0m" cat "$CONF_FILE" @@ -284,9 +289,11 @@ show_status() { fi if [[ -f "$CONF_FILE" ]]; then - local excludes + local excludes ping_url excludes=$(grep -oP '^\s*EXCLUDE\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null || echo "(none)") + ping_url=$(grep -oP '^\s*PING_URL\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null | tr -d '"' | tr -d "'" || echo "(none)") echo -e " \e[36mExcluded:\e[0m ${excludes:-"(none)"}" + echo -e " \e[36mPing URL:\e[0m ${ping_url:-"(none)"}" fi if [[ -f "$LOG_FILE" ]]; then diff --git a/tools/pve/update-lxcs-cron.sh b/tools/pve/update-lxcs-cron.sh index d7abc4cae..0e021944a 100644 --- a/tools/pve/update-lxcs-cron.sh +++ b/tools/pve/update-lxcs-cron.sh @@ -11,14 +11,15 @@ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin CONF_FILE="/etc/update-lxcs.conf" - -echo -e "\n $(date)" +LOG_FILE="/var/log/update-lxcs-cron.log" +PING_URL="" # Collect excluded containers from arguments excluded_containers=("$@") -# Merge exclusions from config file if it exists +# Merge exclusions and healthchecks URL from config file if it exists if [[ -f "$CONF_FILE" ]]; then + PING_URL=$(grep -oP '^\s*PING_URL\s*=\s*\K.+' "$CONF_FILE" 2>/dev/null | tr -d '"' | tr -d "'" || true) conf_exclude=$(grep -oP '^\s*EXCLUDE\s*=\s*\K[0-9,]+' "$CONF_FILE" 2>/dev/null || true) IFS=',' read -ra conf_ids <<<"$conf_exclude" for id in "${conf_ids[@]}"; do @@ -27,6 +28,17 @@ if [[ -f "$CONF_FILE" ]]; then done fi +# Overwrite logfile on each run when healthchecks is used +if [[ -n "$PING_URL" ]]; then + true > "$LOG_FILE" +fi + +if [[ -n "$PING_URL" ]]; then + curl -fsS -m 10 --retry 5 "${PING_URL}/start" -o /dev/null 2>/dev/null || true +fi + +echo -e "\n $(date)" + function update_container() { local container=$1 local name @@ -38,12 +50,36 @@ function update_container() { alpine) pct exec "$container" -- ash -c "apk -U upgrade" ;; archlinux) pct exec "$container" -- bash -c "pacman -Syyu --noconfirm" ;; fedora | rocky | centos | alma) pct exec "$container" -- bash -c "dnf -y update && dnf -y upgrade" ;; - ubuntu | debian | devuan) pct exec "$container" -- bash -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::='--force-confold' dist-upgrade -y; rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED" ;; + ubuntu | debian | devuan) pct exec "$container" -- bash -c "apt-get update; DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::='--force-confold' dist-upgrade -y; status=\$?; rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED || true; exit \$status" ;; opensuse) pct exec "$container" -- bash -c "zypper ref && zypper --non-interactive dup" ;; *) echo " [Warn] Unknown OS type '$os' for container $container, skipping" ;; esac } +update_status=0 + +# Define exit handler to send healthchecks.io status (with logfile on failure/success) +function exit_handler() { + local exit_code=$? + if [[ -n "$PING_URL" ]]; then + sync + if [[ $exit_code -ne 0 || $update_status -ne 0 ]]; then + if [[ -f "$LOG_FILE" ]]; then + curl -fsS -m 10 --retry 5 --data-binary @"$LOG_FILE" "${PING_URL}/fail" -o /dev/null 2>/dev/null || true + else + curl -fsS -m 10 --retry 5 "${PING_URL}/fail" -o /dev/null 2>/dev/null || true + fi + else + if [[ -f "$LOG_FILE" ]]; then + curl -fsS -m 10 --retry 5 --data-binary @"$LOG_FILE" "$PING_URL" -o /dev/null 2>/dev/null || true + else + curl -fsS -m 10 --retry 5 "$PING_URL" -o /dev/null 2>/dev/null || true + fi + fi + fi +} +trap exit_handler EXIT + for container in $(pct list | awk '{if(NR>1) print $1}'); do excluded=false for excluded_container in "${excluded_containers[@]}"; do @@ -65,7 +101,7 @@ for container in $(pct list | awk '{if(NR>1) print $1}'); do echo -e "[Info] Starting $container" pct start "$container" sleep 5 - update_container "$container" || echo " [Error] Update failed for $container" + update_container "$container" || { echo " [Error] Update failed for $container"; update_status=1; } # check if patchmon agent is present in container and run a report if found if pct exec "$container" -- [ -e "/usr/local/bin/patchmon-agent" ]; then echo -e "${BL}[Info]${GN} patchmon-agent found in ${BL} $container ${CL}, triggering report. \n" @@ -74,7 +110,7 @@ for container in $(pct list | awk '{if(NR>1) print $1}'); do echo -e "[Info] Shutting down $container" pct shutdown "$container" --timeout 60 & elif [ "$status" == "status: running" ]; then - update_container "$container" || echo " [Error] Update failed for $container" + update_container "$container" || { echo " [Error] Update failed for $container"; update_status=1; } # check if patchmon agent is present in container and run a report if found if pct exec "$container" -- [ -e "/usr/local/bin/patchmon-agent" ]; then echo -e "${BL}[Info]${GN} patchmon-agent found in ${BL} $container ${CL}, triggering report. \n" From 09c85021fc000ab151201a3b699edc00be7f062c Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 20:19:59 +0000 Subject: [PATCH 183/245] Update CHANGELOG.md (#15877) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab484bb31..b9b1f82b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -502,6 +502,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-18 + +### 🧰 Tools + + - #### ✨ New Features + + - [tools.update-lxcs] feat: optional reporting success/failures to heathchecks.io (or others) [@sir106](https://github.com/sir106) ([#15701](https://github.com/community-scripts/ProxmoxVE/pull/15701)) + ## 2026-07-17 ### 🆕 New Scripts From eb5a5b2cb769681fec7c27d761d9286d83969e4b Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Sat, 18 Jul 2026 23:21:19 +0200 Subject: [PATCH 184/245] add configurable host CA inheritance for LXC bootstrap (#15840) Introduce host CA certificate propagation in the shared LXC build flow so containers can trust enterprise/private PKI roots during early package bootstrap. Add an advanced-install toggle with default auto behavior so unattended installs remain seamless while interactive users can explicitly opt out. Co-authored-by: Michel Roegl-Brunner --- misc/build.func | 143 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 136 insertions(+), 7 deletions(-) diff --git a/misc/build.func b/misc/build.func index 53509780f..f22692d42 100644 --- a/misc/build.func +++ b/misc/build.func @@ -1009,6 +1009,7 @@ base_settings() { APT_CACHER=${var_apt_cacher:-""} APT_CACHER_IP=${var_apt_cacher_ip:-""} + INHERIT_HOST_CA="${var_inherit_host_ca:-auto}" # Runtime check: Verify APT cacher is reachable if configured if [[ -n "$APT_CACHER_IP" && "$APT_CACHER" == "yes" ]]; then @@ -1088,7 +1089,7 @@ load_vars_file() { # Allowed var_* keys local VAR_WHITELIST=( - var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_keyctl + var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_inherit_host_ca var_keyctl var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_searchdomain @@ -1285,6 +1286,12 @@ load_vars_file() { continue fi ;; + var_inherit_host_ca) + if [[ "$var_val" != "yes" && "$var_val" != "no" && "$var_val" != "auto" ]]; then + msg_warn "Invalid host CA inheritance value '$var_val' in $file (must be yes/no/auto), ignoring" + continue + fi + ;; var_container_storage | var_template_storage) # Validate that the storage exists and is active on the current node local _storage_status @@ -1324,7 +1331,7 @@ default_var_settings() { # Allowed var_* keys (alphabetically sorted) # Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique) local VAR_WHITELIST=( - var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_keyctl + var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_inherit_host_ca var_keyctl var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage @@ -1407,6 +1414,7 @@ var_ssh=no # HTTP/HTTPS proxy (optional - for networks requiring a proxy) # var_http_proxy=http://proxy.local:8080 # var_http_no_proxy=localhost,127.0.0.1,.local +# var_inherit_host_ca=auto # Features/Tags/verbosity var_fuse=no @@ -1507,7 +1515,7 @@ get_app_defaults_path() { if ! declare -p VAR_WHITELIST >/dev/null 2>&1; then # Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique) declare -ag VAR_WHITELIST=( - var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_keyctl + var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_inherit_host_ca var_keyctl var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_searchdomain @@ -1657,6 +1665,7 @@ _build_current_app_vars_tmp() { _apt_cacher_ip="${APT_CACHER_IP:-}" _http_proxy="${HTTP_PROXY:-${var_http_proxy:-}}" _http_no_proxy="${HTTP_NO_PROXY:-${var_http_no_proxy:-}}" + _inherit_host_ca="${INHERIT_HOST_CA:-${var_inherit_host_ca:-auto}}" _fuse="${ENABLE_FUSE:-no}" _tun="${ENABLE_TUN:-no}" _gpu="${ENABLE_GPU:-no}" @@ -1710,6 +1719,7 @@ _build_current_app_vars_tmp() { [ -n "$_apt_cacher_ip" ] && echo "var_apt_cacher_ip=$(_sanitize_value "$_apt_cacher_ip")" [ -n "$_http_proxy" ] && echo "var_http_proxy=$(_sanitize_value "$_http_proxy")" [ -n "$_http_no_proxy" ] && echo "var_http_no_proxy=$(_sanitize_value "$_http_no_proxy")" + [ -n "$_inherit_host_ca" ] && echo "var_inherit_host_ca=$(_sanitize_value "$_inherit_host_ca")" [ -n "$_fuse" ] && echo "var_fuse=$(_sanitize_value "$_fuse")" [ -n "$_tun" ] && echo "var_tun=$(_sanitize_value "$_tun")" @@ -1874,7 +1884,7 @@ advanced_settings() { TAGS="community-script${var_tags:+;${var_tags}}" fi local STEP=1 - local MAX_STEP=30 + local MAX_STEP=31 # Store values for back navigation - inherit from var_* app defaults local _ct_type="${var_unprivileged:-1}" @@ -1896,6 +1906,7 @@ advanced_settings() { local _apt_cacher_ip="${var_apt_cacher_ip:-}" local _http_proxy="${var_http_proxy:-}" local _http_no_proxy="${var_http_no_proxy:-}" + local _inherit_host_ca="${var_inherit_host_ca:-auto}" local _mtu="${var_mtu:-}" local _sd="${var_searchdomain:-}" local _ns="${var_ns:-}" @@ -2725,9 +2736,47 @@ advanced_settings() { ;; # ═══════════════════════════════════════════════════════════════════════════ - # STEP 25: Container Timezone + # STEP 25: Host CA Inheritance # ═══════════════════════════════════════════════════════════════════════════ 25) + local host_ca_count=0 + local host_ca_dir="/usr/local/share/ca-certificates" + local cert + shopt -s nullglob + for cert in "$host_ca_dir"/*.crt; do + host_ca_count=$((host_ca_count + 1)) + done + shopt -u nullglob + + if [[ $host_ca_count -eq 0 ]]; then + _inherit_host_ca="auto" + ((STEP++)) + continue + fi + + local host_ca_default_flag="" + [[ "$_inherit_host_ca" == "no" ]] && host_ca_default_flag="--defaultno" + if whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ + --title "HOST CA INHERITANCE" \ + --ok-button "Next" --cancel-button "Back" \ + $host_ca_default_flag \ + --yesno "\nInherit host CA certificates into this container?\n\nDetected on host: ${host_ca_count} certificate(s) in:\n${host_ca_dir}\n\nRecommended for private PKI / TLS-inspection environments.\n\n(App default: ${var_inherit_host_ca:-auto})" 16 72; then + _inherit_host_ca="yes" + else + if [ $? -eq 1 ]; then + _inherit_host_ca="no" + else + ((STEP--)) + continue + fi + fi + ((STEP++)) + ;; + + # ═══════════════════════════════════════════════════════════════════════════ + # STEP 26: Container Timezone + # ═══════════════════════════════════════════════════════════════════════════ + 26) local tz_hint="$_ct_timezone" [[ -z "$tz_hint" ]] && tz_hint="(empty - will use host timezone)" @@ -2750,9 +2799,9 @@ advanced_settings() { ;; # ═══════════════════════════════════════════════════════════════════════════ - # STEP 26: Container Protection + # STEP 27: Container Protection # ═══════════════════════════════════════════════════════════════════════════ - 26) + 27) local protect_default_flag="--defaultno" [[ "$_protect_ct" == "yes" || "$_protect_ct" == "1" ]] && protect_default_flag="" @@ -2904,6 +2953,7 @@ Leave empty to skip." local apt_display="${_apt_cacher:-no}" [[ "$_apt_cacher" == "yes" && -n "$_apt_cacher_ip" ]] && apt_display="$_apt_cacher_ip" local http_proxy_display="${_http_proxy:-(none)}" + local inherit_ca_display="${_inherit_host_ca:-auto}" local post_install_display="${_post_install:-(none)}" local post_install_warn="" @@ -2934,6 +2984,7 @@ Advanced: Timezone: $tz_display APT Cacher: $apt_display HTTP Proxy: $http_proxy_display + Inherit Host CAs: $inherit_ca_display Verbose: $_verbose Post-Install Script: ${post_install_display}${post_install_warn}" @@ -2979,6 +3030,7 @@ Advanced: APT_CACHER_IP="$_apt_cacher_ip" HTTP_PROXY="$_http_proxy" HTTP_NO_PROXY="$_http_no_proxy" + INHERIT_HOST_CA="$_inherit_host_ca" VERBOSE="$_verbose" var_post_install="$_post_install" @@ -2997,6 +3049,7 @@ Advanced: var_sdn_vnet="$_sdn_vnet" var_http_proxy="$_http_proxy" var_http_no_proxy="$_http_no_proxy" + var_inherit_host_ca="$_inherit_host_ca" # Format optional values [[ -n "$_mtu" ]] && MTU=",mtu=$_mtu" || MTU="" @@ -3945,6 +3998,81 @@ EOF msg_ok "Applied HTTP proxy in container" } +# ------------------------------------------------------------------------------ +# _apply_host_ca_certs_in_container() +# +# - Copies administrator-provided CA certificates from the Proxmox host into the +# container before base package bootstrap +# - Source: /usr/local/share/ca-certificates/*.crt (Debian convention) +# - Refreshes the container trust store when update-ca-certificates is available +# - No-op when no host certificates are present; failures are non-fatal +# ------------------------------------------------------------------------------ +_apply_host_ca_certs_in_container() { + local host_ca_dir="/usr/local/share/ca-certificates" + [[ -z "${CTID:-}" ]] && return 0 + local inherit_host_ca="${INHERIT_HOST_CA:-${var_inherit_host_ca:-auto}}" + + local -a host_certs=() + local cert + shopt -s nullglob + for cert in "$host_ca_dir"/*.crt; do + host_certs+=("$cert") + done + shopt -u nullglob + + [[ ${#host_certs[@]} -eq 0 ]] && return 0 + + case "${inherit_host_ca,,}" in + no | false | 0 | off) + msg_info "Skipping host CA inheritance by configuration" + return 0 + ;; + esac + + msg_info "Inheriting host CA certificates into container" + + local found=${#host_certs[@]} + local copied=0 + local skipped=0 + local cert_name + + pct exec "$CTID" -- mkdir -p /usr/local/share/ca-certificates >/dev/null 2>&1 || { + msg_warn "Failed to create CA certificate directory in container" + return 0 + } + + for cert in "${host_certs[@]}"; do + cert_name="$(basename "$cert")" + if [[ ! -r "$cert" || "$cert_name" != *.crt ]]; then + msg_warn "Skipping invalid or unreadable host CA certificate: ${cert_name}" + skipped=$((skipped + 1)) + continue + fi + + if pct push "$CTID" "$cert" "/usr/local/share/ca-certificates/${cert_name}" >/dev/null 2>&1; then + pct exec "$CTID" -- chmod 644 "/usr/local/share/ca-certificates/${cert_name}" >/dev/null 2>&1 || true + copied=$((copied + 1)) + else + msg_warn "Failed to push host CA certificate: ${cert_name}" + skipped=$((skipped + 1)) + fi + done + + if [[ $copied -eq 0 ]]; then + msg_warn "No host CA certificates were copied (${found} found, ${skipped} skipped)" + return 0 + fi + + local refresh_shell="bash" + [[ "$var_os" == "alpine" ]] && refresh_shell="ash" + + if pct exec "$CTID" -- "$refresh_shell" -c 'command -v update-ca-certificates >/dev/null 2>&1 && update-ca-certificates' >/dev/null 2>&1; then + msg_ok "Inherited ${copied} host CA certificate(s) and updated trust store (${skipped} skipped)" + else + msg_warn "Copied ${copied} host CA certificate(s), but trust store update failed or update-ca-certificates is unavailable (${skipped} skipped)" + fi +} + # ------------------------------------------------------------------------------ # build_container() # @@ -4565,6 +4693,7 @@ EOF local install_exit_code=0 _apply_http_proxy_in_container + _apply_host_ca_certs_in_container # Continue with standard container setup if [ "$var_os" == "alpine" ]; then From 658aad229ae262256d4565c2d62d99653b2e6d78 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 21:21:41 +0000 Subject: [PATCH 185/245] Update CHANGELOG.md (#15878) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9b1f82b2..e41f26298 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -504,6 +504,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-18 +### 💾 Core + + - #### ✨ New Features + + - core: add configurable host CA inheritance during bootstrap [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15840](https://github.com/community-scripts/ProxmoxVE/pull/15840)) + ### 🧰 Tools - #### ✨ New Features From 38ed344e0a80e5f7e8a91b71e26cec51c84e5347 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Sun, 19 Jul 2026 00:10:06 +0200 Subject: [PATCH 186/245] tools.func: Safe Delete Directorys & Update PYTHON_VERSION with setup_uv (#15870) --- misc/tools.func | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/misc/tools.func b/misc/tools.func index adb7a5ac4..64669fad1 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -2544,7 +2544,7 @@ fetch_and_deploy_gh_tag() { mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${target:?}/"* + find "${target:?}" -mindepth 1 -delete fi tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { @@ -2737,7 +2737,7 @@ fetch_and_deploy_gl_tag() { mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${target:?}/"* + find "${target:?}" -mindepth 1 -delete fi tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { @@ -3472,7 +3472,7 @@ fetch_and_deploy_codeberg_release() { mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${target:?}/"* + find "${target:?}" -mindepth 1 -delete fi tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { @@ -3575,7 +3575,7 @@ fetch_and_deploy_codeberg_release() { mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${target:?}/"* + find "${target:?}" -mindepth 1 -delete fi tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { @@ -3694,7 +3694,7 @@ fetch_and_deploy_codeberg_release() { unpack_tmp=$(mktemp -d) mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${target:?}/"* + find "${target:?}" -mindepth 1 -delete fi if [[ "$filename" == *.zip ]]; then @@ -4112,7 +4112,7 @@ fetch_and_deploy_gh_release() { mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${target:?}/"* + find "${target:?}" -mindepth 1 -delete fi tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { @@ -4292,7 +4292,7 @@ fetch_and_deploy_gh_release() { unpack_tmp=$(mktemp -d) mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${target:?}/"* + find "${target:?}" -mindepth 1 -delete fi if [[ "$filename" == *.zip ]]; then @@ -7157,7 +7157,7 @@ setup_meilisearch() { MEILI_DB_PATH="${MEILI_DB_PATH:-/var/lib/meilisearch/data}" msg_info "Removing old MeiliSearch database for migration" - rm -rf "${MEILI_DB_PATH:?}"/* + find "${MEILI_DB_PATH:?}" -mindepth 1 -delete # Import dump using CLI flag (this is the supported method) local DUMP_FILE="${MEILI_DUMP_DIR}/${DUMP_UID}.dump" @@ -9131,6 +9131,16 @@ setup_uv() { msg_ok "uvx wrapper installed" fi + # Install specific Python version if requested (even when uv is already up to date) + if [[ -n "${PYTHON_VERSION:-}" ]]; then + msg_info "Installing Python $PYTHON_VERSION via uv" + $STD uv python install "$PYTHON_VERSION" || { + msg_error "Failed to install Python $PYTHON_VERSION" + return 150 + } + msg_ok "Python $PYTHON_VERSION installed" + fi + return 0 fi @@ -9390,7 +9400,7 @@ fetch_and_deploy_from_url() { mkdir -p "$directory" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${directory:?}/"* + find "${directory:?}" -mindepth 1 -delete fi local unpack_tmp @@ -9966,7 +9976,7 @@ fetch_and_deploy_gl_release() { mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${target:?}/"* + find "${target:?}" -mindepth 1 -delete fi tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { @@ -10128,7 +10138,7 @@ fetch_and_deploy_gl_release() { unpack_tmp=$(mktemp -d) mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${target:?}/"* + find "${target:?}" -mindepth 1 -delete fi if [[ "$filename" == *.zip ]]; then From 3242b9a2d158a614b28ee5be877b3d7fa641363f Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 22:10:27 +0000 Subject: [PATCH 187/245] Update CHANGELOG.md (#15879) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e41f26298..18ab9de36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -510,6 +510,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - core: add configurable host CA inheritance during bootstrap [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15840](https://github.com/community-scripts/ProxmoxVE/pull/15840)) + - #### 🔧 Refactor + + - tools.func: Safe Delete Directorys & Update PYTHON_VERSION with setup_uv [@MickLesk](https://github.com/MickLesk) ([#15870](https://github.com/community-scripts/ProxmoxVE/pull/15870)) + ### 🧰 Tools - #### ✨ New Features From e7f6a6d4cdf048e9b19b700e7dd217f94a54dcaf Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 00:17:24 +0000 Subject: [PATCH 188/245] Archive old changelog entries (#15883) Co-authored-by: github-actions[bot] --- .github/changelogs/2026/07.md | 170 ++++++++++++++++++++++++++++++++++ CHANGELOG.md | 131 +------------------------- 2 files changed, 175 insertions(+), 126 deletions(-) diff --git a/.github/changelogs/2026/07.md b/.github/changelogs/2026/07.md index 2ecd58f89..36a2207bc 100644 --- a/.github/changelogs/2026/07.md +++ b/.github/changelogs/2026/07.md @@ -1,3 +1,173 @@ +## 2026-07-18 + +### 💾 Core + + - #### ✨ New Features + + - core: add configurable host CA inheritance during bootstrap [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15840](https://github.com/community-scripts/ProxmoxVE/pull/15840)) + + - #### 🔧 Refactor + + - tools.func: Safe Delete Directorys & Update PYTHON_VERSION with setup_uv [@MickLesk](https://github.com/MickLesk) ([#15870](https://github.com/community-scripts/ProxmoxVE/pull/15870)) + +### 🧰 Tools + + - #### ✨ New Features + + - [tools.update-lxcs] feat: optional reporting success/failures to heathchecks.io (or others) [@sir106](https://github.com/sir106) ([#15701](https://github.com/community-scripts/ProxmoxVE/pull/15701)) + +## 2026-07-17 + +### 🆕 New Scripts + + - Invidious ([#15824](https://github.com/community-scripts/ProxmoxVE/pull/15824)) +- OxiCloud ([#15823](https://github.com/community-scripts/ProxmoxVE/pull/15823)) + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - webtrees: initialize database schema before admin user creation [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15837](https://github.com/community-scripts/ProxmoxVE/pull/15837)) + - Fix DocuSeal missing Leptonica deps on install and update [@Copilot](https://github.com/Copilot) ([#15858](https://github.com/community-scripts/ProxmoxVE/pull/15858)) + - apache-guacamole: detect installed extensions during update [@TowyTowy](https://github.com/TowyTowy) ([#15841](https://github.com/community-scripts/ProxmoxVE/pull/15841)) + - CLIProxyAPI: fix update deleting config.yaml [@austinpilz](https://github.com/austinpilz) ([#15834](https://github.com/community-scripts/ProxmoxVE/pull/15834)) + - esphome: install libusb-1.0-0 for ESP-IDF native builds [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15838](https://github.com/community-scripts/ProxmoxVE/pull/15838)) + + - #### ✨ New Features + + - AFFiNE: Bump to 0.27.0 [@MickLesk](https://github.com/MickLesk) ([#15848](https://github.com/community-scripts/ProxmoxVE/pull/15848)) + - n8n: unpin / use latest release [@MickLesk](https://github.com/MickLesk) ([#15817](https://github.com/community-scripts/ProxmoxVE/pull/15817)) + - Pin Opencloud to v7.3.0 [@vhsdream](https://github.com/vhsdream) ([#15826](https://github.com/community-scripts/ProxmoxVE/pull/15826)) + + - #### 🔧 Refactor + + - SFTPGo: Update APT Repo & Re-Enable Script [@MickLesk](https://github.com/MickLesk) ([#15829](https://github.com/community-scripts/ProxmoxVE/pull/15829)) + +### 💾 Core + + - #### ✨ New Features + + - tools.func: enhance rbenv with profile updates / bundle in bashrc [@MickLesk](https://github.com/MickLesk) ([#15822](https://github.com/community-scripts/ProxmoxVE/pull/15822)) + - feat(build.func): notify users when already on a pinned script version [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15819](https://github.com/community-scripts/ProxmoxVE/pull/15819)) + + - #### 💥 Breaking Changes + + - MongoDB: Implement kernel version check and patch [@MickLesk](https://github.com/MickLesk) ([#15821](https://github.com/community-scripts/ProxmoxVE/pull/15821)) + +### 🧰 Tools + + - #### ✨ New Features + + - update-lxc: autoremove and autoclean after apt full-upgrade [@soupy-boy](https://github.com/soupy-boy) ([#15831](https://github.com/community-scripts/ProxmoxVE/pull/15831)) + +## 2026-07-16 + +### 🆕 New Scripts + + - Sync-In ([#15812](https://github.com/community-scripts/ProxmoxVE/pull/15812)) +- Beaverhabits ([#15813](https://github.com/community-scripts/ProxmoxVE/pull/15813)) +- Notediscovery ([#15811](https://github.com/community-scripts/ProxmoxVE/pull/15811)) + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - Pin Immich to v3.0.3 [@vhsdream](https://github.com/vhsdream) ([#15790](https://github.com/community-scripts/ProxmoxVE/pull/15790)) + +## 2026-07-15 + +### 🆕 New Scripts + + - Nexterm ([#15688](https://github.com/community-scripts/ProxmoxVE/pull/15688)) + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - 2fauth: minor fixes for 8.0.0 [@MickLesk](https://github.com/MickLesk) ([#15795](https://github.com/community-scripts/ProxmoxVE/pull/15795)) + - SnapOtter: refactor update process to prebuild [@MickLesk](https://github.com/MickLesk) ([#15797](https://github.com/community-scripts/ProxmoxVE/pull/15797)) + +### 💾 Core + + - #### 🔧 Refactor + + - tools.func: default Docker setup to official repo [@MickLesk](https://github.com/MickLesk) ([#15794](https://github.com/community-scripts/ProxmoxVE/pull/15794)) + +## 2026-07-14 + +### 🆕 New Scripts + + - Grav ([#15773](https://github.com/community-scripts/ProxmoxVE/pull/15773)) +- Yuvomi ([#15772](https://github.com/community-scripts/ProxmoxVE/pull/15772)) + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - Lychee: Preserve uploads and ownership during update [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15768](https://github.com/community-scripts/ProxmoxVE/pull/15768)) + - Wanderer: Clean deploy and install plugins for v0.20.0 update [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15759](https://github.com/community-scripts/ProxmoxVE/pull/15759)) + - FileFlows: Handle update API 401, force update, and Node install [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15766](https://github.com/community-scripts/ProxmoxVE/pull/15766)) + - BirdNET-Go: Match new upstream release asset naming [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15758](https://github.com/community-scripts/ProxmoxVE/pull/15758)) + - [Upstream Fix] Immich: Fix loader priority [@vhsdream](https://github.com/vhsdream) ([#15755](https://github.com/community-scripts/ProxmoxVE/pull/15755)) + + - #### ✨ New Features + + - Bump OpenCloud version to v7.2.2 [@MickLesk](https://github.com/MickLesk) ([#15769](https://github.com/community-scripts/ProxmoxVE/pull/15769)) + - Silverbullet: Add optional Runtime API install via Chromium [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15761](https://github.com/community-scripts/ProxmoxVE/pull/15761)) + + - #### 💥 Breaking Changes + + - Pangolin: Bump to 1.20.0 | BREAKING: Switch to PostgreSQL [@MickLesk](https://github.com/MickLesk) ([#15682](https://github.com/community-scripts/ProxmoxVE/pull/15682)) + + - #### 🔧 Refactor + + - AFFiNE: Pin to v0.26.3 [@MickLesk](https://github.com/MickLesk) ([#15782](https://github.com/community-scripts/ProxmoxVE/pull/15782)) + +## 2026-07-13 + +### 🆕 New Scripts + + - LeafWiki ([#15748](https://github.com/community-scripts/ProxmoxVE/pull/15748)) + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - fix(hyperion): keep service running after container reboot [@TowyTowy](https://github.com/TowyTowy) ([#15653](https://github.com/community-scripts/ProxmoxVE/pull/15653)) + - Change sign-in URL to admin URL in affine.sh [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15741](https://github.com/community-scripts/ProxmoxVE/pull/15741)) + - immich: use actual PostgreSQL version for VectorChord package lookup [@mnavon](https://github.com/mnavon) ([#15705](https://github.com/community-scripts/ProxmoxVE/pull/15705)) + - fix storyteller release selection for stable web tags [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15736](https://github.com/community-scripts/ProxmoxVE/pull/15736)) + - Docmost: Fix update procedure [@MickLesk](https://github.com/MickLesk) ([#15732](https://github.com/community-scripts/ProxmoxVE/pull/15732)) + - fix(shinobi): remove obsolete --unsafe-perm npm flag [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15730](https://github.com/community-scripts/ProxmoxVE/pull/15730)) + + - #### 💥 Breaking Changes + + - reitti: update to v5 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15635](https://github.com/community-scripts/ProxmoxVE/pull/15635)) + +### 💾 Core + + - #### 🐞 Bug Fixes + + - fix(build.func): parse script status without jq dependency [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15729](https://github.com/community-scripts/ProxmoxVE/pull/15729)) + + - #### 🔧 Refactor + + - tools.func: some improvements (sql injection / command injection / guard) [@MickLesk](https://github.com/MickLesk) ([#15661](https://github.com/community-scripts/ProxmoxVE/pull/15661)) + +## 2026-07-12 + +### 🆕 New Scripts + + - AFFiNE ([#15690](https://github.com/community-scripts/ProxmoxVE/pull/15690)) + +### 🚀 Updated Scripts + + - Immich: Bump version to 3.0.2 [@vhsdream](https://github.com/vhsdream) ([#15668](https://github.com/community-scripts/ProxmoxVE/pull/15668)) + +### ❔ Uncategorized + + - fix(immich): correct Python indentation error in ct/immich.sh heredoc patch [@Copilot](https://github.com/Copilot) ([#15723](https://github.com/community-scripts/ProxmoxVE/pull/15723)) + ## 2026-07-11 ### 🆕 New Scripts diff --git a/CHANGELOG.md b/CHANGELOG.md index 18ab9de36..e97facb0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,9 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit + + + @@ -90,7 +93,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
-

July (11 entries)

+

July (18 entries)

[View July 2026 Changelog](.github/changelogs/2026/07.md) @@ -1153,128 +1156,4 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - chore(ct): sync coredns defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#15182](https://github.com/community-scripts/ProxmoxVE/pull/15182)) - chore(ct): sync gatus defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#15184](https://github.com/community-scripts/ProxmoxVE/pull/15184)) -- chore(ct): sync bitmagnet defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#15183](https://github.com/community-scripts/ProxmoxVE/pull/15183)) - -## 2026-06-18 - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - flowise: add deps / uv / python 3.11 [@MickLesk](https://github.com/MickLesk) ([#15177](https://github.com/community-scripts/ProxmoxVE/pull/15177)) - - - #### 💥 Breaking Changes - - - refactor: crafty-controller [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15178](https://github.com/community-scripts/ProxmoxVE/pull/15178)) - -## 2026-06-17 - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - kasm: fix release detection [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15151](https://github.com/community-scripts/ProxmoxVE/pull/15151)) - - - #### ✨ New Features - - - trek: update install and upgrade workflow for v3.1.0 [@MickLesk](https://github.com/MickLesk) ([#15165](https://github.com/community-scripts/ProxmoxVE/pull/15165)) - - - #### 💥 Breaking Changes - - - TREK: Pin version [@tremor021](https://github.com/tremor021) ([#15156](https://github.com/community-scripts/ProxmoxVE/pull/15156)) - - - #### 🔧 Refactor - - - chore(paperless-ngx): pin version to prevent v3 update [@tomfrenzel](https://github.com/tomfrenzel) ([#15171](https://github.com/community-scripts/ProxmoxVE/pull/15171)) - -### 🧰 Tools - - - #### 🐞 Bug Fixes - - - immich public proxy: replace npm install with npm ci for consistent dependency installation [@MickLesk](https://github.com/MickLesk) ([#15166](https://github.com/community-scripts/ProxmoxVE/pull/15166)) - -## 2026-06-16 - -### 🆕 New Scripts - - - Feishin ([#15130](https://github.com/community-scripts/ProxmoxVE/pull/15130)) -- Kiwix ([#15131](https://github.com/community-scripts/ProxmoxVE/pull/15131)) -- Add runtime status guard and deleted script stubs [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15125](https://github.com/community-scripts/ProxmoxVE/pull/15125)) - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - fix(degoog): use localhost for valkey url [@ethan-hgwr](https://github.com/ethan-hgwr) ([#15149](https://github.com/community-scripts/ProxmoxVE/pull/15149)) - - Fix InvoiceShelf install/update Yarn package manager mismatch [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15141](https://github.com/community-scripts/ProxmoxVE/pull/15141)) - - fix storyteller install failure with yarn 4 corepack [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15140](https://github.com/community-scripts/ProxmoxVE/pull/15140)) - - fix: generate policy-compliant OpenObserve root password [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15137](https://github.com/community-scripts/ProxmoxVE/pull/15137)) - -## 2026-06-15 - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - Watcharr: Clean install on update [@tremor021](https://github.com/tremor021) ([#15119](https://github.com/community-scripts/ProxmoxVE/pull/15119)) - - Vaultwarden: extend version check for VaultWarden update [@MickLesk](https://github.com/MickLesk) ([#15105](https://github.com/community-scripts/ProxmoxVE/pull/15105)) - - - #### ✨ New Features - - - degoog: add curl-impersonate to script [@MickLesk](https://github.com/MickLesk) ([#15117](https://github.com/community-scripts/ProxmoxVE/pull/15117)) - -### 💾 Core - - - #### ✨ New Features - - - tools.func: extend mesa-vulkan-drivers and vulkan-tools to installation for ARC GPU's [@MickLesk](https://github.com/MickLesk) ([#15106](https://github.com/community-scripts/ProxmoxVE/pull/15106)) - - - #### 🔧 Refactor - - - core: improve mirror selection and error handling [@MickLesk](https://github.com/MickLesk) ([#15108](https://github.com/community-scripts/ProxmoxVE/pull/15108)) - - core: implement gateway validation for DHCP and static networks [@MickLesk](https://github.com/MickLesk) ([#15107](https://github.com/community-scripts/ProxmoxVE/pull/15107)) - -## 2026-06-14 - -### 🚀 Updated Scripts - - - #### 🐞 Bug Fixes - - - Iinvoiceninja: fix nginx setup assets port [@MickLesk](https://github.com/MickLesk) ([#15090](https://github.com/community-scripts/ProxmoxVE/pull/15090)) - - CheckMK: remove stale backup site before creating new backup during update [@MickLesk](https://github.com/MickLesk) ([#15088](https://github.com/community-scripts/ProxmoxVE/pull/15088)) - - - #### 🔧 Refactor - - - Refactor: Implement backup functions for scripts C-D [@tremor021](https://github.com/tremor021) ([#15096](https://github.com/community-scripts/ProxmoxVE/pull/15096)) - -## 2026-06-13 - -### 🆕 New Scripts - - - BookOrbit ([#15080](https://github.com/community-scripts/ProxmoxVE/pull/15080)) - -### 🚀 Updated Scripts - - - Update authentik version to 2026.5.3 [@thieneret](https://github.com/thieneret) ([#15093](https://github.com/community-scripts/ProxmoxVE/pull/15093)) - - - #### 🐞 Bug Fixes - - - Immich: Update image-processing libraries [@vhsdream](https://github.com/vhsdream) ([#15082](https://github.com/community-scripts/ProxmoxVE/pull/15082)) - - HomeBox: Support v0.26.0 [@tomfrenzel](https://github.com/tomfrenzel) ([#15086](https://github.com/community-scripts/ProxmoxVE/pull/15086)) - - - #### 🔧 Refactor - - - Refactor: Implement backup functions for scripts A-B [@tremor021](https://github.com/tremor021) ([#15075](https://github.com/community-scripts/ProxmoxVE/pull/15075)) - -## 2026-06-12 - -### 🆕 New Scripts - - - Twenty ([#15047](https://github.com/community-scripts/ProxmoxVE/pull/15047)) -- Alpine-Cinny ([#15044](https://github.com/community-scripts/ProxmoxVE/pull/15044)) - -### 💾 Core - - - #### ✨ New Features - - - [core] Implement backup and restore functions [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15067](https://github.com/community-scripts/ProxmoxVE/pull/15067)) \ No newline at end of file +- chore(ct): sync bitmagnet defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#15183](https://github.com/community-scripts/ProxmoxVE/pull/15183)) \ No newline at end of file From c07dc4a4c39dd2719c5e32a479c52679fe8fa238 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 00:17:46 +0000 Subject: [PATCH 189/245] Update CHANGELOG.md (#15884) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e97facb0a..2b3332fdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -505,6 +505,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
+## 2026-07-19 + ## 2026-07-18 ### 💾 Core From bbd5a3f522a90f38369abc72f186605825c57ad5 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Sun, 19 Jul 2026 09:41:52 +0200 Subject: [PATCH 190/245] Revert "add configurable host CA inheritance for LXC bootstrap (#15840)" (#15886) This reverts commit eb5a5b2cb769681fec7c27d761d9286d83969e4b. --- misc/build.func | 143 +++--------------------------------------------- 1 file changed, 7 insertions(+), 136 deletions(-) diff --git a/misc/build.func b/misc/build.func index f22692d42..53509780f 100644 --- a/misc/build.func +++ b/misc/build.func @@ -1009,7 +1009,6 @@ base_settings() { APT_CACHER=${var_apt_cacher:-""} APT_CACHER_IP=${var_apt_cacher_ip:-""} - INHERIT_HOST_CA="${var_inherit_host_ca:-auto}" # Runtime check: Verify APT cacher is reachable if configured if [[ -n "$APT_CACHER_IP" && "$APT_CACHER" == "yes" ]]; then @@ -1089,7 +1088,7 @@ load_vars_file() { # Allowed var_* keys local VAR_WHITELIST=( - var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_inherit_host_ca var_keyctl + var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_keyctl var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_searchdomain @@ -1286,12 +1285,6 @@ load_vars_file() { continue fi ;; - var_inherit_host_ca) - if [[ "$var_val" != "yes" && "$var_val" != "no" && "$var_val" != "auto" ]]; then - msg_warn "Invalid host CA inheritance value '$var_val' in $file (must be yes/no/auto), ignoring" - continue - fi - ;; var_container_storage | var_template_storage) # Validate that the storage exists and is active on the current node local _storage_status @@ -1331,7 +1324,7 @@ default_var_settings() { # Allowed var_* keys (alphabetically sorted) # Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique) local VAR_WHITELIST=( - var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_inherit_host_ca var_keyctl + var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_keyctl var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage @@ -1414,7 +1407,6 @@ var_ssh=no # HTTP/HTTPS proxy (optional - for networks requiring a proxy) # var_http_proxy=http://proxy.local:8080 # var_http_no_proxy=localhost,127.0.0.1,.local -# var_inherit_host_ca=auto # Features/Tags/verbosity var_fuse=no @@ -1515,7 +1507,7 @@ get_app_defaults_path() { if ! declare -p VAR_WHITELIST >/dev/null 2>&1; then # Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique) declare -ag VAR_WHITELIST=( - var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_inherit_host_ca var_keyctl + var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_keyctl var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_searchdomain @@ -1665,7 +1657,6 @@ _build_current_app_vars_tmp() { _apt_cacher_ip="${APT_CACHER_IP:-}" _http_proxy="${HTTP_PROXY:-${var_http_proxy:-}}" _http_no_proxy="${HTTP_NO_PROXY:-${var_http_no_proxy:-}}" - _inherit_host_ca="${INHERIT_HOST_CA:-${var_inherit_host_ca:-auto}}" _fuse="${ENABLE_FUSE:-no}" _tun="${ENABLE_TUN:-no}" _gpu="${ENABLE_GPU:-no}" @@ -1719,7 +1710,6 @@ _build_current_app_vars_tmp() { [ -n "$_apt_cacher_ip" ] && echo "var_apt_cacher_ip=$(_sanitize_value "$_apt_cacher_ip")" [ -n "$_http_proxy" ] && echo "var_http_proxy=$(_sanitize_value "$_http_proxy")" [ -n "$_http_no_proxy" ] && echo "var_http_no_proxy=$(_sanitize_value "$_http_no_proxy")" - [ -n "$_inherit_host_ca" ] && echo "var_inherit_host_ca=$(_sanitize_value "$_inherit_host_ca")" [ -n "$_fuse" ] && echo "var_fuse=$(_sanitize_value "$_fuse")" [ -n "$_tun" ] && echo "var_tun=$(_sanitize_value "$_tun")" @@ -1884,7 +1874,7 @@ advanced_settings() { TAGS="community-script${var_tags:+;${var_tags}}" fi local STEP=1 - local MAX_STEP=31 + local MAX_STEP=30 # Store values for back navigation - inherit from var_* app defaults local _ct_type="${var_unprivileged:-1}" @@ -1906,7 +1896,6 @@ advanced_settings() { local _apt_cacher_ip="${var_apt_cacher_ip:-}" local _http_proxy="${var_http_proxy:-}" local _http_no_proxy="${var_http_no_proxy:-}" - local _inherit_host_ca="${var_inherit_host_ca:-auto}" local _mtu="${var_mtu:-}" local _sd="${var_searchdomain:-}" local _ns="${var_ns:-}" @@ -2736,47 +2725,9 @@ advanced_settings() { ;; # ═══════════════════════════════════════════════════════════════════════════ - # STEP 25: Host CA Inheritance + # STEP 25: Container Timezone # ═══════════════════════════════════════════════════════════════════════════ 25) - local host_ca_count=0 - local host_ca_dir="/usr/local/share/ca-certificates" - local cert - shopt -s nullglob - for cert in "$host_ca_dir"/*.crt; do - host_ca_count=$((host_ca_count + 1)) - done - shopt -u nullglob - - if [[ $host_ca_count -eq 0 ]]; then - _inherit_host_ca="auto" - ((STEP++)) - continue - fi - - local host_ca_default_flag="" - [[ "$_inherit_host_ca" == "no" ]] && host_ca_default_flag="--defaultno" - if whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ - --title "HOST CA INHERITANCE" \ - --ok-button "Next" --cancel-button "Back" \ - $host_ca_default_flag \ - --yesno "\nInherit host CA certificates into this container?\n\nDetected on host: ${host_ca_count} certificate(s) in:\n${host_ca_dir}\n\nRecommended for private PKI / TLS-inspection environments.\n\n(App default: ${var_inherit_host_ca:-auto})" 16 72; then - _inherit_host_ca="yes" - else - if [ $? -eq 1 ]; then - _inherit_host_ca="no" - else - ((STEP--)) - continue - fi - fi - ((STEP++)) - ;; - - # ═══════════════════════════════════════════════════════════════════════════ - # STEP 26: Container Timezone - # ═══════════════════════════════════════════════════════════════════════════ - 26) local tz_hint="$_ct_timezone" [[ -z "$tz_hint" ]] && tz_hint="(empty - will use host timezone)" @@ -2799,9 +2750,9 @@ advanced_settings() { ;; # ═══════════════════════════════════════════════════════════════════════════ - # STEP 27: Container Protection + # STEP 26: Container Protection # ═══════════════════════════════════════════════════════════════════════════ - 27) + 26) local protect_default_flag="--defaultno" [[ "$_protect_ct" == "yes" || "$_protect_ct" == "1" ]] && protect_default_flag="" @@ -2953,7 +2904,6 @@ Leave empty to skip." local apt_display="${_apt_cacher:-no}" [[ "$_apt_cacher" == "yes" && -n "$_apt_cacher_ip" ]] && apt_display="$_apt_cacher_ip" local http_proxy_display="${_http_proxy:-(none)}" - local inherit_ca_display="${_inherit_host_ca:-auto}" local post_install_display="${_post_install:-(none)}" local post_install_warn="" @@ -2984,7 +2934,6 @@ Advanced: Timezone: $tz_display APT Cacher: $apt_display HTTP Proxy: $http_proxy_display - Inherit Host CAs: $inherit_ca_display Verbose: $_verbose Post-Install Script: ${post_install_display}${post_install_warn}" @@ -3030,7 +2979,6 @@ Advanced: APT_CACHER_IP="$_apt_cacher_ip" HTTP_PROXY="$_http_proxy" HTTP_NO_PROXY="$_http_no_proxy" - INHERIT_HOST_CA="$_inherit_host_ca" VERBOSE="$_verbose" var_post_install="$_post_install" @@ -3049,7 +2997,6 @@ Advanced: var_sdn_vnet="$_sdn_vnet" var_http_proxy="$_http_proxy" var_http_no_proxy="$_http_no_proxy" - var_inherit_host_ca="$_inherit_host_ca" # Format optional values [[ -n "$_mtu" ]] && MTU=",mtu=$_mtu" || MTU="" @@ -3998,81 +3945,6 @@ EOF msg_ok "Applied HTTP proxy in container" } -# ------------------------------------------------------------------------------ -# _apply_host_ca_certs_in_container() -# -# - Copies administrator-provided CA certificates from the Proxmox host into the -# container before base package bootstrap -# - Source: /usr/local/share/ca-certificates/*.crt (Debian convention) -# - Refreshes the container trust store when update-ca-certificates is available -# - No-op when no host certificates are present; failures are non-fatal -# ------------------------------------------------------------------------------ -_apply_host_ca_certs_in_container() { - local host_ca_dir="/usr/local/share/ca-certificates" - [[ -z "${CTID:-}" ]] && return 0 - local inherit_host_ca="${INHERIT_HOST_CA:-${var_inherit_host_ca:-auto}}" - - local -a host_certs=() - local cert - shopt -s nullglob - for cert in "$host_ca_dir"/*.crt; do - host_certs+=("$cert") - done - shopt -u nullglob - - [[ ${#host_certs[@]} -eq 0 ]] && return 0 - - case "${inherit_host_ca,,}" in - no | false | 0 | off) - msg_info "Skipping host CA inheritance by configuration" - return 0 - ;; - esac - - msg_info "Inheriting host CA certificates into container" - - local found=${#host_certs[@]} - local copied=0 - local skipped=0 - local cert_name - - pct exec "$CTID" -- mkdir -p /usr/local/share/ca-certificates >/dev/null 2>&1 || { - msg_warn "Failed to create CA certificate directory in container" - return 0 - } - - for cert in "${host_certs[@]}"; do - cert_name="$(basename "$cert")" - if [[ ! -r "$cert" || "$cert_name" != *.crt ]]; then - msg_warn "Skipping invalid or unreadable host CA certificate: ${cert_name}" - skipped=$((skipped + 1)) - continue - fi - - if pct push "$CTID" "$cert" "/usr/local/share/ca-certificates/${cert_name}" >/dev/null 2>&1; then - pct exec "$CTID" -- chmod 644 "/usr/local/share/ca-certificates/${cert_name}" >/dev/null 2>&1 || true - copied=$((copied + 1)) - else - msg_warn "Failed to push host CA certificate: ${cert_name}" - skipped=$((skipped + 1)) - fi - done - - if [[ $copied -eq 0 ]]; then - msg_warn "No host CA certificates were copied (${found} found, ${skipped} skipped)" - return 0 - fi - - local refresh_shell="bash" - [[ "$var_os" == "alpine" ]] && refresh_shell="ash" - - if pct exec "$CTID" -- "$refresh_shell" -c 'command -v update-ca-certificates >/dev/null 2>&1 && update-ca-certificates' >/dev/null 2>&1; then - msg_ok "Inherited ${copied} host CA certificate(s) and updated trust store (${skipped} skipped)" - else - msg_warn "Copied ${copied} host CA certificate(s), but trust store update failed or update-ca-certificates is unavailable (${skipped} skipped)" - fi -} - # ------------------------------------------------------------------------------ # build_container() # @@ -4693,7 +4565,6 @@ EOF local install_exit_code=0 _apply_http_proxy_in_container - _apply_host_ca_certs_in_container # Continue with standard container setup if [ "$var_os" == "alpine" ]; then From 8c7da1e036ad04618ffbb0b1861e7e4d50e8aab4 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 07:42:15 +0000 Subject: [PATCH 191/245] Update CHANGELOG.md (#15887) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b3332fdf..7ee82801f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -507,6 +507,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-19 +### 💾 Core + + - Revert "core: add configurable host CA inheritance during bootstrap" [@MickLesk](https://github.com/MickLesk) ([#15886](https://github.com/community-scripts/ProxmoxVE/pull/15886)) + ## 2026-07-18 ### 💾 Core From b2898debce3cecec3f2787164cabce4179a585b7 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 19 Jul 2026 05:16:44 -0400 Subject: [PATCH 192/245] [FIX] BookOrbit: add missing `restore_backup` during update (#15881) - Otherwise the `.env` file is not restored and the sed command fails --- ct/bookorbit.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ct/bookorbit.sh b/ct/bookorbit.sh index 7b0e95c13..b955ddd5a 100644 --- a/ct/bookorbit.sh +++ b/ct/bookorbit.sh @@ -53,6 +53,7 @@ function update_script() { mkdir -p /opt/bookorbit/server/migrations cp -r /opt/bookorbit/server/src/db/migrations/. /opt/bookorbit/server/migrations/ chmod +x /opt/bookorbit/server/bin/kepubify/* + restore_backup APP_VER=$(cat ~/.bookorbit) sed -i "s/^APP_VERSION=.*/APP_VERSION=v$APP_VER/" /opt/bookorbit/.env msg_ok "Rebuilt Application" From beacf9e43af8488322944e64b21ec1f4329935c5 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 09:17:11 +0000 Subject: [PATCH 193/245] Update CHANGELOG.md (#15892) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ee82801f..f3d5c185b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -507,6 +507,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ## 2026-07-19 +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - [FIX] BookOrbit: add missing `restore_backup` during update [@vhsdream](https://github.com/vhsdream) ([#15881](https://github.com/community-scripts/ProxmoxVE/pull/15881)) + ### 💾 Core - Revert "core: add configurable host CA inheritance during bootstrap" [@MickLesk](https://github.com/MickLesk) ([#15886](https://github.com/community-scripts/ProxmoxVE/pull/15886)) From 8f9c4eb13ba859292c27bb41af31d784f13ef48e Mon Sep 17 00:00:00 2001 From: thieneret <123479547+thieneret@users.noreply.github.com> Date: Sun, 19 Jul 2026 13:21:14 +0200 Subject: [PATCH 194/245] update authentik to 2026.5.5 (#15855) --- ct/authentik.sh | 7 ++++--- install/authentik-install.sh | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ct/authentik.sh b/ct/authentik.sh index c8b99db82..ec597f15c 100644 --- a/ct/authentik.sh +++ b/ct/authentik.sh @@ -38,13 +38,14 @@ function update_script() { NODE_VERSION="24" setup_nodejs setup_go - UV_PYTHON_INSTALL_DIR="/usr/local/bin" PYTHON_VERSION="3.14.3" setup_uv + $STD uv cache clean + UV_PYTHON_INSTALL_DIR="/usr/local/bin" PYTHON_VERSION="3.14.6" setup_uv RUST_PROFILE="minimal" RUST_TOOLCHAIN="stable" setup_rust setup_yq - AUTHENTIK_VERSION="version/2026.5.3" + AUTHENTIK_VERSION="version/2026.5.5" # Source: https://github.com/goauthentik/fips/blob/main/Makefile#L26 - XMLSEC_VERSION="1.3.11" + XMLSEC_VERSION="1.3.12" if check_for_gh_release "geoipupdate" "maxmind/geoipupdate"; then fetch_and_deploy_gh_release "geoipupdate" "maxmind/geoipupdate" "binary" diff --git a/install/authentik-install.sh b/install/authentik-install.sh index 13e4fbe3d..02f89c922 100644 --- a/install/authentik-install.sh +++ b/install/authentik-install.sh @@ -54,12 +54,12 @@ NODE_VERSION="24" setup_nodejs setup_yq setup_go RUST_PROFILE="minimal" RUST_TOOLCHAIN="stable" setup_rust -UV_PYTHON_INSTALL_DIR="/usr/local/bin" PYTHON_VERSION="3.14.3" setup_uv +UV_PYTHON_INSTALL_DIR="/usr/local/bin" PYTHON_VERSION="3.14.6" setup_uv PG_VERSION="17" setup_postgresql PG_DB_NAME="authentik" PG_DB_USER="authentik" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db -XMLSEC_VERSION="1.3.11" -AUTHENTIK_VERSION="version/2026.5.3" +XMLSEC_VERSION="1.3.12" +AUTHENTIK_VERSION="version/2026.5.5" fetch_and_deploy_gh_release "xmlsec" "lsh123/xmlsec" "tarball" "${XMLSEC_VERSION}" "/opt/xmlsec" fetch_and_deploy_gh_release "authentik" "goauthentik/authentik" "tarball" "${AUTHENTIK_VERSION}" "/opt/authentik" fetch_and_deploy_gh_release "geoipupdate" "maxmind/geoipupdate" "binary" From 8f0083850e466b2609acf54196ca4190cf32b618 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 11:21:43 +0000 Subject: [PATCH 195/245] Update CHANGELOG.md (#15896) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3d5c185b..b7a4ce291 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -511,6 +511,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - update authentik to 2026.5.5 [@thieneret](https://github.com/thieneret) ([#15855](https://github.com/community-scripts/ProxmoxVE/pull/15855)) - [FIX] BookOrbit: add missing `restore_backup` during update [@vhsdream](https://github.com/vhsdream) ([#15881](https://github.com/community-scripts/ProxmoxVE/pull/15881)) ### 💾 Core From 787e27a4acf73ff21bca566623363e80c64510c3 Mon Sep 17 00:00:00 2001 From: Sam Heinz Date: Sun, 19 Jul 2026 22:02:56 +1000 Subject: [PATCH 196/245] change trek repo to liketrek/TREK (#15893) --- ct/trek.sh | 8 ++++---- install/trek-install.sh | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ct/trek.sh b/ct/trek.sh index be958f75f..9df637780 100644 --- a/ct/trek.sh +++ b/ct/trek.sh @@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV # Copyright (c) 2021-2026 community-scripts ORG # Author: MickLesk (CanbiZ) # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://github.com/mauriceboe/TREK +# Source: https://github.com/liketrek/TREK APP="TREK" var_tags="${var_tags:-travel;planning;collaboration}" @@ -32,7 +32,7 @@ function update_script() { NODE_VERSION="24" setup_nodejs - if check_for_gh_release "trek" "mauriceboe/TREK"; then + if check_for_gh_release "trek" "liketrek/TREK"; then MIGRATION=0 grep -qF "ExecStart=/usr/bin/node --import tsx src/index.ts" \ /etc/systemd/system/trek.service && MIGRATION=1 @@ -47,7 +47,7 @@ function update_script() { /opt/trek/data \ /opt/trek/uploads - CLEAN_INSTALL=1 fetch_and_deploy_gh_release "trek" "mauriceboe/TREK" "tarball" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "trek" "liketrek/TREK" "tarball" msg_info "Building TREK" cd /opt/trek @@ -79,7 +79,7 @@ function update_script() { cat </etc/systemd/system/trek.service [Unit] Description=TREK Travel Planner -Documentation=https://github.com/mauriceboe/TREK +Documentation=https://github.com/liketrek/TREK After=network-online.target Wants=network-online.target diff --git a/install/trek-install.sh b/install/trek-install.sh index c189afc1b..1161ce73a 100644 --- a/install/trek-install.sh +++ b/install/trek-install.sh @@ -3,7 +3,7 @@ # Copyright (c) 2021-2026 community-scripts ORG # Author: MickLesk (CanbiZ) # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://github.com/mauriceboe/TREK +# Source: https://github.com/liketrek/TREK source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" color @@ -20,7 +20,7 @@ $STD apt install -y \ msg_ok "Installed Dependencies" NODE_VERSION="24" setup_nodejs -fetch_and_deploy_gh_release "trek" "mauriceboe/TREK" "tarball" +fetch_and_deploy_gh_release "trek" "liketrek/TREK" "tarball" msg_info "Setup TREK" cd /opt/trek @@ -78,7 +78,7 @@ msg_info "Creating Service" cat </etc/systemd/system/trek.service [Unit] Description=TREK Travel Planner -Documentation=https://github.com/mauriceboe/TREK +Documentation=https://github.com/liketrek/TREK After=network-online.target Wants=network-online.target From 0dbea508d3f12cb1039b8221917958670b145b52 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 12:03:22 +0000 Subject: [PATCH 197/245] Update CHANGELOG.md (#15898) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7a4ce291..c3ecd3284 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -511,6 +511,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - change trek repo to liketrek/TREK [@asylumexp](https://github.com/asylumexp) ([#15893](https://github.com/community-scripts/ProxmoxVE/pull/15893)) - update authentik to 2026.5.5 [@thieneret](https://github.com/thieneret) ([#15855](https://github.com/community-scripts/ProxmoxVE/pull/15855)) - [FIX] BookOrbit: add missing `restore_backup` during update [@vhsdream](https://github.com/vhsdream) ([#15881](https://github.com/community-scripts/ProxmoxVE/pull/15881)) From e425d9c02cc62397a0353eed10126b8aefa47daf Mon Sep 17 00:00:00 2001 From: tdn131 <32997056+tdn131@users.noreply.github.com> Date: Sun, 19 Jul 2026 14:52:42 +0200 Subject: [PATCH 198/245] Update OPNsense from 26.1 to 26.7 (#15895) --- vm/opnsense-vm.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/opnsense-vm.sh b/vm/opnsense-vm.sh index 3b18e3b74..4d15f25be 100644 --- a/vm/opnsense-vm.sh +++ b/vm/opnsense-vm.sh @@ -24,7 +24,7 @@ RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" METHOD="" NSAPP="opnsense-vm" var_os="opnsense" -var_version="26.1" +var_version="26.7" # GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//') GEN_MAC_LAN=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//') @@ -814,7 +814,7 @@ if [ -n "$WAN_BRG" ]; then msg_ok "WAN interface added" sleep 5 # Brief pause after adding network interface fi -send_line_to_vm "sh ./opnsense-bootstrap.sh.in -y -f -r 26.1" +send_line_to_vm "sh ./opnsense-bootstrap.sh.in -y -f -r 26.7" msg_ok "OPNsense VM is being installed, do not close the terminal, or the installation will fail." #We need to wait for the OPNsense build proccess to finish, this takes a few minutes sleep 1000 From a1058256be2fd1a3568441ac93e2cc48257d9647 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 12:53:02 +0000 Subject: [PATCH 199/245] Update CHANGELOG.md (#15899) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3ecd3284..f9386336b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -515,6 +515,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - update authentik to 2026.5.5 [@thieneret](https://github.com/thieneret) ([#15855](https://github.com/community-scripts/ProxmoxVE/pull/15855)) - [FIX] BookOrbit: add missing `restore_backup` during update [@vhsdream](https://github.com/vhsdream) ([#15881](https://github.com/community-scripts/ProxmoxVE/pull/15881)) + - #### ✨ New Features + + - Update OPNsense from 26.1 to 26.7 [@tdn131](https://github.com/tdn131) ([#15895](https://github.com/community-scripts/ProxmoxVE/pull/15895)) + ### 💾 Core - Revert "core: add configurable host CA inheritance during bootstrap" [@MickLesk](https://github.com/MickLesk) ([#15886](https://github.com/community-scripts/ProxmoxVE/pull/15886)) From b098501a3751c366ce794d8b968acdcea4f675d5 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Sun, 19 Jul 2026 14:53:46 +0200 Subject: [PATCH 200/245] tools.func: centralize deploy tail + trap-based tmpdir cleanup (#15872) * tools.func: replace rm -rf with find for safer directory cleanup * tools.func: replace rm -rf with find for safer directory cleanup * refactor(tools.func): centralize deploy tail + trap-based tmpdir cleanup Extract the duplicated post-download logic of the fetch_and_deploy_* helpers into two shared functions and switch per-branch cleanup to a single RETURN trap. - _deploy_source_tarball: shared source-tarball tail (6 call sites) - _deploy_unpacked_archive: shared prebuild-archive tail (3 call sites) - RETURN trap per function guarantees tmpdir/unpack_tmp cleanup on every return path, replacing ~40 manual `rm -rf "$tmpdir"` lines - CLEAN_INSTALL now lives in the helpers instead of 12 copies Behavior-preserving except: codeberg prebuild gains .txz support and uses helper return codes; from_url resets shopt on error paths. * Add _download_source_tarball with retry/validation Introduce `_download_source_tarball` helper that validates gzip integrity after download and retries up to 3 times. This guards against truncated-but-valid-HTTP responses from GitHub/GitLab/Codeberg on-the-fly archive generation. Replace ad-hoc curl/curl_download calls in fetch_and_deploy_* functions with the new helper. Also remove redundant tmpdir cleanup before early returns (tmpdir is cleaned up at function exit). * Fix Manyfold Ruby setup home initialization Create the `manyfold` service user before calling `setup_ruby` so `/home/manyfold` exists when rbenv profile snippets are written. Also harden `setup_ruby` by creating `$HOME` if missing, preventing profile-write failures for installers that pass a home directory before creating the user. * Update install/manyfold-install.sh --------- Co-authored-by: Sam Heinz --- install/manyfold-install.sh | 3 +- misc/tools.func | 510 +++++++++++++----------------------- 2 files changed, 177 insertions(+), 336 deletions(-) diff --git a/install/manyfold-install.sh b/install/manyfold-install.sh index dfc43b49e..0a025b1cf 100644 --- a/install/manyfold-install.sh +++ b/install/manyfold-install.sh @@ -31,13 +31,14 @@ NODE_VERSION="24" NODE_MODULE="corepack,yarn" setup_nodejs fetch_and_deploy_gh_release "manyfold" "manyfold3d/manyfold" "tarball" "latest" "/opt/manyfold/app" +useradd -m -s /usr/bin/bash manyfold + RUBY_INSTALL_VERSION=$(cat /opt/manyfold/app/.ruby-version) RUBY_VERSION=${RUBY_INSTALL_VERSION} RUBY_INSTALL_RAILS="true" HOME=/home/manyfold setup_ruby msg_info "Configuring Manyfold" YARN_VERSION=$(grep '"packageManager":' /opt/manyfold/app/package.json | sed -E 's/.*"(yarn@[0-9\.]+)".*/\1/') RELEASE=$(get_latest_github_release "manyfold3d/manyfold") -useradd -m -s /usr/bin/bash manyfold cat </opt/manyfold/.env export APP_VERSION=${RELEASE} export GUID=1002 diff --git a/misc/tools.func b/misc/tools.func index 64669fad1..cc5e66162 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -2483,6 +2483,150 @@ verify_gpg_fingerprint() { return 65 } +# ------------------------------------------------------------------------------ +# _download_source_tarball [curl args...] +# +# Downloads a source .tar.gz to and verifies the gzip stream is complete +# before returning. Source forges (GitHub/GitLab/Codeberg) build these archives +# on the fly; for large repos the response is occasionally a truncated-but- +# cleanly-closed gzip that curl accepts as success (HTTP 200) and which then +# fails at extraction time. We validate with `gzip -t` and re-download on +# failure, and abort stalled transfers (--speed-time) so a hung generation +# retries instead of blocking for minutes. Extra args pass through to curl +# (e.g. auth headers like -H "PRIVATE-TOKEN: ..."). +# +# Returns: 0 on success, 250 on persistent failure. +# ------------------------------------------------------------------------------ +_download_source_tarball() { + local url="$1" dest="$2" + shift 2 + local attempt max=3 + for ((attempt = 1; attempt <= max; attempt++)); do + if curl --connect-timeout 15 --max-time 900 --speed-limit 1024 --speed-time 60 \ + -fsSL "$@" -o "$dest" "$url" && gzip -t "$dest" 2>/dev/null; then + return 0 + fi + rm -f "$dest" + ((attempt < max)) && { + msg_warn "Source archive download failed or incomplete (attempt ${attempt}/${max}), retrying..." + sleep $((attempt * 3)) + } + done + return 250 +} + +# ------------------------------------------------------------------------------ +# _deploy_source_tarball +# +# Shared tail for the *source tarball* modes of the fetch_and_deploy_* helpers +# (GitHub/GitLab/Codeberg archive tarballs that contain a single top-level +# directory). Extracts into , then copies the contents +# of that top-level directory into . +# +# - Honors CLEAN_INSTALL=1 (wipes first, dotfiles included). +# - Does NOT own : the caller creates it and is responsible for its +# cleanup (typically via a RETURN trap on its tmpdir). +# - cp failures are non-fatal here, matching the previous inline behavior. +# +# Returns: 0 on success (or non-fatal cp failure), 251 on extraction failure. +# ------------------------------------------------------------------------------ +_deploy_source_tarball() { + local tarball="$1" target="$2" workdir="$3" + + mkdir -p "$target" + if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then + find "${target:?}" -mindepth 1 -delete + fi + + tar --no-same-owner -xzf "$tarball" -C "$workdir" || { + msg_error "Failed to extract tarball" + return 251 + } + + local unpack_dir + unpack_dir=$(find "$workdir" -mindepth 1 -maxdepth 1 -type d | head -n1) + + shopt -s dotglob nullglob + cp -r "$unpack_dir"/* "$target/" + shopt -u dotglob nullglob + return 0 +} + +# ------------------------------------------------------------------------------ +# _deploy_unpacked_archive +# +# Shared tail for the *prebuild* modes of the fetch_and_deploy_*_release helpers +# (release assets shipped as .zip / .tar.* / .tgz / .txz). Extracts the archive +# into , then copies its payload into . If the archive contains +# a single top-level directory, that directory is stripped (its contents land +# directly in ); otherwise the archive contents are copied as-is. +# +# - Honors CLEAN_INSTALL=1 (wipes first, dotfiles included). +# - Does NOT own : the caller creates it and cleans it up. +# +# Returns: 0 on success, 65 on unsupported format, 251 on extraction failure, +# 252 on copy failure / empty archive. +# ------------------------------------------------------------------------------ +_deploy_unpacked_archive() { + local archive="$1" target="$2" workdir="$3" + local filename="${archive##*/}" + + mkdir -p "$target" + if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then + find "${target:?}" -mindepth 1 -delete + fi + + if [[ "$filename" == *.zip ]]; then + ensure_dependencies unzip + unzip -q "$archive" -d "$workdir" || { + msg_error "Failed to extract ZIP archive" + return 251 + } + elif [[ "$filename" == *.tar.* || "$filename" == *.tgz || "$filename" == *.txz ]]; then + tar --no-same-owner -xf "$archive" -C "$workdir" || { + msg_error "Failed to extract TAR archive" + return 251 + } + else + msg_error "Unsupported archive format: $filename" + return 65 + fi + + local top_entries inner_dir + top_entries=$(find "$workdir" -mindepth 1 -maxdepth 1) + if [[ "$(echo "$top_entries" | wc -l)" -eq 1 && -d "$top_entries" ]]; then + inner_dir="$top_entries" + shopt -s dotglob nullglob + if compgen -G "$inner_dir/*" >/dev/null; then + cp -r "$inner_dir"/* "$target/" || { + msg_error "Failed to copy contents from $inner_dir to $target" + shopt -u dotglob nullglob + return 252 + } + else + msg_error "Inner directory is empty: $inner_dir" + shopt -u dotglob nullglob + return 252 + fi + shopt -u dotglob nullglob + else + shopt -s dotglob nullglob + if compgen -G "$workdir/*" >/dev/null; then + cp -r "$workdir"/* "$target/" || { + msg_error "Failed to copy contents to $target" + shopt -u dotglob nullglob + return 252 + } + else + msg_error "Unpacked archive is empty" + shopt -u dotglob nullglob + return 252 + fi + shopt -u dotglob nullglob + fi + return 0 +} + # ------------------------------------------------------------------------------ # Fetches and deploys a GitHub tag-based source tarball. # @@ -2531,36 +2675,19 @@ fetch_and_deploy_gh_tag() { local tmpdir tmpdir=$(mktemp -d) || return 1 + trap 'rm -rf "$tmpdir"' RETURN local tarball_url="https://github.com/${repo}/archive/refs/tags/${version}.tar.gz" local filename="${app_lc}-${version}.tar.gz" msg_info "Fetching GitHub tag: ${app} (${version})" - download_file "$tarball_url" "$tmpdir/$filename" || { + _download_source_tarball "$tarball_url" "$tmpdir/$filename" || { msg_error "Download failed: $tarball_url" - rm -rf "$tmpdir" return 7 } - mkdir -p "$target" - if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - find "${target:?}" -mindepth 1 -delete - fi + _deploy_source_tarball "$tmpdir/$filename" "$target" "$tmpdir" || return 251 - tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { - msg_error "Failed to extract tarball" - rm -rf "$tmpdir" - return 251 - } - - local unpack_dir - unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1) - - shopt -s dotglob nullglob - cp -r "$unpack_dir"/* "$target/" - shopt -u dotglob nullglob - - rm -rf "$tmpdir" echo "$version" >"$version_file" msg_ok "Deployed ${app} ${version} to ${target}" return 0 @@ -2725,35 +2852,18 @@ fetch_and_deploy_gl_tag() { local tmpdir tmpdir=$(mktemp -d) || return 1 + trap 'rm -rf "$tmpdir"' RETURN local filename="${app_lc}-${version_safe}.tar.gz" msg_info "Fetching GitLab tag: ${app} (${resolved_tag})" - curl $download_timeout -fsSL "${header[@]}" -o "$tmpdir/$filename" "$tarball_url" || { + _download_source_tarball "$tarball_url" "$tmpdir/$filename" "${header[@]}" || { msg_error "Download failed: $tarball_url" - rm -rf "$tmpdir" return 7 } - mkdir -p "$target" - if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - find "${target:?}" -mindepth 1 -delete - fi + _deploy_source_tarball "$tmpdir/$filename" "$target" "$tmpdir" || return 251 - tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { - msg_error "Failed to extract tarball" - rm -rf "$tmpdir" - return 251 - } - - local unpack_dir - unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1) - - shopt -s dotglob nullglob - cp -r "$unpack_dir"/* "$target/" - shopt -u dotglob nullglob - - rm -rf "$tmpdir" echo "$resolved_tag" >"$version_file" msg_ok "Deployed ${app} ${resolved_tag} to ${target}" return 0 @@ -3450,6 +3560,7 @@ fetch_and_deploy_codeberg_release() { local tmpdir tmpdir=$(mktemp -d) || return 252 + trap 'rm -rf "$tmpdir"' RETURN msg_info "Fetching Codeberg tag: $app ($tag_name)" @@ -3460,37 +3571,19 @@ fetch_and_deploy_codeberg_release() { # Codeberg archive URL format: https://codeberg.org/{owner}/{repo}/archive/{tag}.tar.gz local archive_url="https://codeberg.org/$repo/archive/${tag_name}.tar.gz" - if curl_download "$tmpdir/$filename" "$archive_url"; then + if _download_source_tarball "$archive_url" "$tmpdir/$filename"; then download_success=true fi if [[ "$download_success" != "true" ]]; then msg_error "Download failed for $app ($tag_name)" - rm -rf "$tmpdir" return 250 fi - mkdir -p "$target" - if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - find "${target:?}" -mindepth 1 -delete - fi - - tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { - msg_error "Failed to extract tarball" - rm -rf "$tmpdir" - return 251 - } - - local unpack_dir - unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1) - - shopt -s dotglob nullglob - cp -r "$unpack_dir"/* "$target/" - shopt -u dotglob nullglob + _deploy_source_tarball "$tmpdir/$filename" "$target" "$tmpdir" || return 251 echo "$version" >"$version_file" msg_ok "Deployed: $app ($version)" - rm -rf "$tmpdir" return 0 fi @@ -3509,7 +3602,7 @@ fetch_and_deploy_codeberg_release() { local codeberg_rel_json codeberg_rel_json=$(mktemp /tmp/tools-codeberg-rel-XXXXXX) || return 73 - trap 'rm -f "$codeberg_rel_json"' RETURN + trap 'rm -f "$codeberg_rel_json"; rm -rf "${tmpdir:-}" "${unpack_tmp:-}"' RETURN local attempt=0 success=false resp http_code @@ -3563,32 +3656,16 @@ fetch_and_deploy_codeberg_release() { # Codeberg archive URL format local archive_url="https://codeberg.org/$repo/archive/${tag_name}.tar.gz" - if curl_download "$tmpdir/$filename" "$archive_url"; then + if _download_source_tarball "$archive_url" "$tmpdir/$filename"; then download_success=true fi if [[ "$download_success" != "true" ]]; then msg_error "Download failed for $app ($tag_name)" - rm -rf "$tmpdir" return 250 fi - mkdir -p "$target" - if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - find "${target:?}" -mindepth 1 -delete - fi - - tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { - msg_error "Failed to extract tarball" - rm -rf "$tmpdir" - return 251 - } - local unpack_dir - unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1) - - shopt -s dotglob nullglob - cp -r "$unpack_dir"/* "$target/" - shopt -u dotglob nullglob + _deploy_source_tarball "$tmpdir/$filename" "$target" "$tmpdir" || return 251 ### Binary Mode ### elif [[ "$mode" == "binary" ]]; then @@ -3636,14 +3713,12 @@ fetch_and_deploy_codeberg_release() { if [[ -z "$url_match" ]]; then msg_error "No suitable .deb asset found for $app" - rm -rf "$tmpdir" return 252 fi filename="${url_match##*/}" curl_download "$tmpdir/$filename" "$url_match" || { msg_error "Download failed: $url_match" - rm -rf "$tmpdir" return 250 } @@ -3651,7 +3726,6 @@ fetch_and_deploy_codeberg_release() { $STD apt install -y "$tmpdir/$filename" || { $STD dpkg -i "$tmpdir/$filename" || { _diagnose_deb_failure "$tmpdir/$filename" - rm -rf "$tmpdir" return 100 } } @@ -3662,7 +3736,6 @@ fetch_and_deploy_codeberg_release() { pattern="${pattern#\"}" [[ -z "$pattern" ]] && { msg_error "Mode 'prebuild' requires 6th parameter (asset filename pattern)" - rm -rf "$tmpdir" return 65 } @@ -3679,77 +3752,18 @@ fetch_and_deploy_codeberg_release() { [[ -z "$asset_url" ]] && { msg_error "No asset matching '$pattern' found" - rm -rf "$tmpdir" return 252 } filename="${asset_url##*/}" curl_download "$tmpdir/$filename" "$asset_url" || { msg_error "Download failed: $asset_url" - rm -rf "$tmpdir" return 250 } local unpack_tmp unpack_tmp=$(mktemp -d) - mkdir -p "$target" - if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - find "${target:?}" -mindepth 1 -delete - fi - - if [[ "$filename" == *.zip ]]; then - ensure_dependencies unzip - unzip -q "$tmpdir/$filename" -d "$unpack_tmp" || { - msg_error "Failed to extract ZIP archive" - rm -rf "$tmpdir" "$unpack_tmp" - return 251 - } - elif [[ "$filename" == *.tar.* || "$filename" == *.tgz ]]; then - tar --no-same-owner -xf "$tmpdir/$filename" -C "$unpack_tmp" || { - msg_error "Failed to extract TAR archive" - rm -rf "$tmpdir" "$unpack_tmp" - return 251 - } - else - msg_error "Unsupported archive format: $filename" - rm -rf "$tmpdir" "$unpack_tmp" - return 251 - fi - - local top_dirs - top_dirs=$(find "$unpack_tmp" -mindepth 1 -maxdepth 1 -type d | wc -l) - local top_entries inner_dir - top_entries=$(find "$unpack_tmp" -mindepth 1 -maxdepth 1) - if [[ "$(echo "$top_entries" | wc -l)" -eq 1 && -d "$top_entries" ]]; then - inner_dir="$top_entries" - shopt -s dotglob nullglob - if compgen -G "$inner_dir/*" >/dev/null; then - cp -r "$inner_dir"/* "$target/" || { - msg_error "Failed to copy contents from $inner_dir to $target" - rm -rf "$tmpdir" "$unpack_tmp" - return 252 - } - else - msg_error "Inner directory is empty: $inner_dir" - rm -rf "$tmpdir" "$unpack_tmp" - return 252 - fi - shopt -u dotglob nullglob - else - shopt -s dotglob nullglob - if compgen -G "$unpack_tmp/*" >/dev/null; then - cp -r "$unpack_tmp"/* "$target/" || { - msg_error "Failed to copy contents to $target" - rm -rf "$tmpdir" "$unpack_tmp" - return 252 - } - else - msg_error "Unpacked archive is empty" - rm -rf "$tmpdir" "$unpack_tmp" - return 252 - fi - shopt -u dotglob nullglob - fi + _deploy_unpacked_archive "$tmpdir/$filename" "$target" "$unpack_tmp" || return ### Singlefile Mode ### elif [[ "$mode" == "singlefile" ]]; then @@ -3757,7 +3771,6 @@ fetch_and_deploy_codeberg_release() { pattern="${pattern#\"}" [[ -z "$pattern" ]] && { msg_error "Mode 'singlefile' requires 6th parameter (asset filename pattern)" - rm -rf "$tmpdir" return 65 } @@ -3774,7 +3787,6 @@ fetch_and_deploy_codeberg_release() { [[ -z "$asset_url" ]] && { msg_error "No asset matching '$pattern' found" - rm -rf "$tmpdir" return 252 } @@ -3787,7 +3799,6 @@ fetch_and_deploy_codeberg_release() { curl_download "$target/$target_file" "$asset_url" || { msg_error "Download failed: $asset_url" - rm -rf "$tmpdir" return 250 } @@ -3797,13 +3808,11 @@ fetch_and_deploy_codeberg_release() { else msg_error "Unknown mode: $mode" - rm -rf "$tmpdir" return 65 fi echo "$version" >"$version_file" msg_ok "Deployed: $app ($version)" - rm -rf "$tmpdir" } # ------------------------------------------------------------------------------ @@ -4090,6 +4099,7 @@ fetch_and_deploy_gh_release() { local tmpdir tmpdir=$(mktemp -d) || return 1 + trap 'rm -rf "$tmpdir" "${unpack_tmp:-}"' RETURN local filename="" url="" msg_info "Fetching GitHub release: $app ($version)" @@ -4104,28 +4114,12 @@ fetch_and_deploy_gh_release() { local direct_tarball_url="https://github.com/$repo/archive/refs/tags/$tag_name.tar.gz" filename="${app_lc}-${version_safe}.tar.gz" - curl_download "$tmpdir/$filename" "$direct_tarball_url" || { + _download_source_tarball "$direct_tarball_url" "$tmpdir/$filename" || { msg_error "Download failed: $direct_tarball_url" - rm -rf "$tmpdir" return 250 } - mkdir -p "$target" - if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - find "${target:?}" -mindepth 1 -delete - fi - - tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { - msg_error "Failed to extract tarball" - rm -rf "$tmpdir" - return 251 - } - local unpack_dir - unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1) - - shopt -s dotglob nullglob - cp -r "$unpack_dir"/* "$target/" - shopt -u dotglob nullglob + _deploy_source_tarball "$tmpdir/$filename" "$target" "$tmpdir" || return 251 ### Binary Mode ### elif [[ "$mode" == "binary" ]]; then @@ -4210,14 +4204,12 @@ fetch_and_deploy_gh_release() { if [[ -z "$url_match" ]]; then msg_error "No suitable .deb asset found for $app" - rm -rf "$tmpdir" return 252 fi filename="${url_match##*/}" curl_download "$tmpdir/$filename" "$url_match" || { msg_error "Download failed: $url_match" - rm -rf "$tmpdir" return 250 } @@ -4230,7 +4222,6 @@ fetch_and_deploy_gh_release() { DEBIAN_FRONTEND=noninteractive SYSTEMD_OFFLINE=1 $STD apt install -y $dpkg_opts "$tmpdir/$filename" || { SYSTEMD_OFFLINE=1 $STD dpkg -i "$tmpdir/$filename" || { _diagnose_deb_failure "$tmpdir/$filename" - rm -rf "$tmpdir" return 100 } } @@ -4241,7 +4232,6 @@ fetch_and_deploy_gh_release() { pattern="${pattern#\"}" [[ -z "$pattern" ]] && { msg_error "Mode 'prebuild' requires 6th parameter (asset filename pattern)" - rm -rf "$tmpdir" return 65 } @@ -4277,79 +4267,18 @@ fetch_and_deploy_gh_release() { [[ -z "$asset_url" ]] && { msg_error "No asset matching '$pattern' found" - rm -rf "$tmpdir" return 252 } filename="${asset_url##*/}" curl_download "$tmpdir/$filename" "$asset_url" || { msg_error "Download failed: $asset_url" - rm -rf "$tmpdir" return 250 } local unpack_tmp unpack_tmp=$(mktemp -d) - mkdir -p "$target" - if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - find "${target:?}" -mindepth 1 -delete - fi - - if [[ "$filename" == *.zip ]]; then - ensure_dependencies unzip - unzip -q "$tmpdir/$filename" -d "$unpack_tmp" || { - msg_error "Failed to extract ZIP archive" - rm -rf "$tmpdir" "$unpack_tmp" - return 251 - } - elif [[ "$filename" == *.tar.* || "$filename" == *.tgz || "$filename" == *.txz ]]; then - tar --no-same-owner -xf "$tmpdir/$filename" -C "$unpack_tmp" || { - msg_error "Failed to extract TAR archive" - rm -rf "$tmpdir" "$unpack_tmp" - return 251 - } - else - msg_error "Unsupported archive format: $filename" - rm -rf "$tmpdir" "$unpack_tmp" - return 65 - fi - - local top_dirs - top_dirs=$(find "$unpack_tmp" -mindepth 1 -maxdepth 1 -type d | wc -l) - local top_entries inner_dir - top_entries=$(find "$unpack_tmp" -mindepth 1 -maxdepth 1) - if [[ "$(echo "$top_entries" | wc -l)" -eq 1 && -d "$top_entries" ]]; then - # Strip leading folder - inner_dir="$top_entries" - shopt -s dotglob nullglob - if compgen -G "$inner_dir/*" >/dev/null; then - cp -r "$inner_dir"/* "$target/" || { - msg_error "Failed to copy contents from $inner_dir to $target" - rm -rf "$tmpdir" "$unpack_tmp" - return 252 - } - else - msg_error "Inner directory is empty: $inner_dir" - rm -rf "$tmpdir" "$unpack_tmp" - return 252 - fi - shopt -u dotglob nullglob - else - # Copy all contents - shopt -s dotglob nullglob - if compgen -G "$unpack_tmp/*" >/dev/null; then - cp -r "$unpack_tmp"/* "$target/" || { - msg_error "Failed to copy contents to $target" - rm -rf "$tmpdir" "$unpack_tmp" - return 252 - } - else - msg_error "Unpacked archive is empty" - rm -rf "$tmpdir" "$unpack_tmp" - return 252 - fi - shopt -u dotglob nullglob - fi + _deploy_unpacked_archive "$tmpdir/$filename" "$target" "$unpack_tmp" || return ### Singlefile Mode ### elif [[ "$mode" == "singlefile" ]]; then @@ -4357,7 +4286,6 @@ fetch_and_deploy_gh_release() { pattern="${pattern#\"}" [[ -z "$pattern" ]] && { msg_error "Mode 'singlefile' requires 6th parameter (asset filename pattern)" - rm -rf "$tmpdir" return 65 } @@ -4392,7 +4320,6 @@ fetch_and_deploy_gh_release() { fi [[ -z "$asset_url" ]] && { msg_error "No asset matching '$pattern' found" - rm -rf "$tmpdir" return 252 } @@ -4405,7 +4332,6 @@ fetch_and_deploy_gh_release() { curl_download "$target/$target_file" "$asset_url" || { msg_error "Download failed: $asset_url" - rm -rf "$tmpdir" return 250 } @@ -4415,13 +4341,11 @@ fetch_and_deploy_gh_release() { else msg_error "Unknown mode: $mode" - rm -rf "$tmpdir" return 65 fi echo "$version" >"$version_file" msg_ok "Deployed: $app ($version)" - rm -rf "$tmpdir" } # ------------------------------------------------------------------------------ @@ -8713,6 +8637,11 @@ setup_ruby() { local BASHRC_FILE="$HOME/.bashrc" local TMP_DIR=$(mktemp -d) + # Ensure HOME exists: callers may pass a not-yet-created home (e.g. a service + # user that is created later in the install), so the profile writes below do + # not fail on a missing directory. + mkdir -p "$HOME" + if ! grep -q 'rbenv init' "$PROFILE_FILE" 2>/dev/null; then cat <<'EOF' >>"$PROFILE_FILE" export PATH="$HOME/.rbenv/bin:$PATH" @@ -9343,10 +9272,10 @@ fetch_and_deploy_from_url() { msg_error "Failed to create temporary directory" return 252 } + trap 'rm -rf "$tmpdir" "${unpack_tmp:-}"' RETURN curl -fsSL -o "$tmpdir/$filename" "$url" || { msg_error "Download failed: $url" - rm -rf "$tmpdir" return 250 } @@ -9366,7 +9295,6 @@ fetch_and_deploy_from_url() { archive_type="tar" else msg_error "Unsupported or unknown archive type: $file_desc" - rm -rf "$tmpdir" return 65 fi @@ -9379,19 +9307,16 @@ fetch_and_deploy_from_url() { $STD apt install -y "$tmpdir/$filename" || { $STD dpkg -i "$tmpdir/$filename" || { _diagnose_deb_failure "$tmpdir/$filename" - rm -rf "$tmpdir" return 100 } } - rm -rf "$tmpdir" msg_ok "Successfully installed .deb package" return 0 fi if [[ -z "$directory" ]]; then msg_error "Directory parameter is required for archive extraction" - rm -rf "$tmpdir" return 65 fi @@ -9410,13 +9335,11 @@ fetch_and_deploy_from_url() { ensure_dependencies unzip unzip -q "$tmpdir/$filename" -d "$unpack_tmp" || { msg_error "Failed to extract ZIP archive" - rm -rf "$tmpdir" "$unpack_tmp" return 251 } elif [[ "$archive_type" == "tar" ]]; then tar --no-same-owner -xf "$tmpdir/$filename" -C "$unpack_tmp" || { msg_error "Failed to extract TAR archive" - rm -rf "$tmpdir" "$unpack_tmp" return 251 } fi @@ -9430,12 +9353,12 @@ fetch_and_deploy_from_url() { if compgen -G "$inner_dir/*" >/dev/null; then cp -r "$inner_dir"/* "$directory/" || { msg_error "Failed to copy contents from $inner_dir to $directory" - rm -rf "$tmpdir" "$unpack_tmp" + shopt -u dotglob nullglob return 252 } else msg_error "Inner directory is empty: $inner_dir" - rm -rf "$tmpdir" "$unpack_tmp" + shopt -u dotglob nullglob return 252 fi shopt -u dotglob nullglob @@ -9444,18 +9367,17 @@ fetch_and_deploy_from_url() { if compgen -G "$unpack_tmp/*" >/dev/null; then cp -r "$unpack_tmp"/* "$directory/" || { msg_error "Failed to copy contents to $directory" - rm -rf "$tmpdir" "$unpack_tmp" + shopt -u dotglob nullglob return 252 } else msg_error "Unpacked archive is empty" - rm -rf "$tmpdir" "$unpack_tmp" + shopt -u dotglob nullglob return 252 fi shopt -u dotglob nullglob fi - rm -rf "$tmpdir" "$unpack_tmp" msg_ok "Successfully deployed archive to $directory" return 0 } @@ -9856,7 +9778,7 @@ fetch_and_deploy_gl_release() { local gl_rel_json gl_rel_json=$(mktemp /tmp/tools-gl-rel-XXXXXX) || return 73 - trap 'rm -f "$gl_rel_json"' RETURN + trap 'rm -f "$gl_rel_json"; rm -rf "${tmpdir:-}" "${unpack_tmp:-}"' RETURN local repo_encoded repo_encoded=$(printf '%s' "$repo" | sed 's|/|%2F|g') @@ -9968,28 +9890,12 @@ fetch_and_deploy_gl_release() { local direct_tarball_url="https://gitlab.com/$repo/-/archive/$tag_name/${app_lc}-${version_safe}.tar.gz" filename="${app_lc}-${version_safe}.tar.gz" - curl $download_timeout -fsSL "${header[@]}" -o "$tmpdir/$filename" "$direct_tarball_url" || { + _download_source_tarball "$direct_tarball_url" "$tmpdir/$filename" "${header[@]}" || { msg_error "Download failed: $direct_tarball_url" - rm -rf "$tmpdir" return 1 } - mkdir -p "$target" - if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - find "${target:?}" -mindepth 1 -delete - fi - - tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { - msg_error "Failed to extract tarball" - rm -rf "$tmpdir" - return 1 - } - local unpack_dir - unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1) - - shopt -s dotglob nullglob - cp -r "$unpack_dir"/* "$target/" - shopt -u dotglob nullglob + _deploy_source_tarball "$tmpdir/$filename" "$target" "$tmpdir" || return 1 ### Binary Mode ### elif [[ "$mode" == "binary" ]]; then @@ -10059,14 +9965,12 @@ fetch_and_deploy_gl_release() { if [[ -z "$url_match" ]]; then msg_error "No suitable .deb asset found for $app" - rm -rf "$tmpdir" return 1 fi filename="${url_match##*/}" curl $download_timeout -fsSL "${header[@]}" -o "$tmpdir/$filename" "$url_match" || { msg_error "Download failed: $url_match" - rm -rf "$tmpdir" return 1 } @@ -10077,7 +9981,6 @@ fetch_and_deploy_gl_release() { DEBIAN_FRONTEND=noninteractive SYSTEMD_OFFLINE=1 $STD apt install -y $dpkg_opts "$tmpdir/$filename" || { SYSTEMD_OFFLINE=1 $STD dpkg -i "$tmpdir/$filename" || { _diagnose_deb_failure "$tmpdir/$filename" - rm -rf "$tmpdir" return 1 } } @@ -10088,7 +9991,6 @@ fetch_and_deploy_gl_release() { pattern="${pattern#\"}" [[ -z "$pattern" ]] && { msg_error "Mode 'prebuild' requires 6th parameter (asset filename pattern)" - rm -rf "$tmpdir" return 1 } @@ -10123,75 +10025,18 @@ fetch_and_deploy_gl_release() { [[ -z "$asset_url" ]] && { msg_error "No asset matching '$pattern' found" - rm -rf "$tmpdir" return 1 } filename="${asset_url##*/}" curl $download_timeout -fsSL "${header[@]}" -o "$tmpdir/$filename" "$asset_url" || { msg_error "Download failed: $asset_url" - rm -rf "$tmpdir" return 1 } local unpack_tmp unpack_tmp=$(mktemp -d) - mkdir -p "$target" - if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - find "${target:?}" -mindepth 1 -delete - fi - - if [[ "$filename" == *.zip ]]; then - ensure_dependencies unzip - unzip -q "$tmpdir/$filename" -d "$unpack_tmp" || { - msg_error "Failed to extract ZIP archive" - rm -rf "$tmpdir" "$unpack_tmp" - return 1 - } - elif [[ "$filename" == *.tar.* || "$filename" == *.tgz || "$filename" == *.txz ]]; then - tar --no-same-owner -xf "$tmpdir/$filename" -C "$unpack_tmp" || { - msg_error "Failed to extract TAR archive" - rm -rf "$tmpdir" "$unpack_tmp" - return 1 - } - else - msg_error "Unsupported archive format: $filename" - rm -rf "$tmpdir" "$unpack_tmp" - return 1 - fi - - local top_entries inner_dir - top_entries=$(find "$unpack_tmp" -mindepth 1 -maxdepth 1) - if [[ "$(echo "$top_entries" | wc -l)" -eq 1 && -d "$top_entries" ]]; then - inner_dir="$top_entries" - shopt -s dotglob nullglob - if compgen -G "$inner_dir/*" >/dev/null; then - cp -r "$inner_dir"/* "$target/" || { - msg_error "Failed to copy contents from $inner_dir to $target" - rm -rf "$tmpdir" "$unpack_tmp" - return 1 - } - else - msg_error "Inner directory is empty: $inner_dir" - rm -rf "$tmpdir" "$unpack_tmp" - return 1 - fi - shopt -u dotglob nullglob - else - shopt -s dotglob nullglob - if compgen -G "$unpack_tmp/*" >/dev/null; then - cp -r "$unpack_tmp"/* "$target/" || { - msg_error "Failed to copy contents to $target" - rm -rf "$tmpdir" "$unpack_tmp" - return 1 - } - else - msg_error "Unpacked archive is empty" - rm -rf "$tmpdir" "$unpack_tmp" - return 1 - fi - shopt -u dotglob nullglob - fi + _deploy_unpacked_archive "$tmpdir/$filename" "$target" "$unpack_tmp" || return ### Singlefile Mode ### elif [[ "$mode" == "singlefile" ]]; then @@ -10199,7 +10044,6 @@ fetch_and_deploy_gl_release() { pattern="${pattern#\"}" [[ -z "$pattern" ]] && { msg_error "Mode 'singlefile' requires 6th parameter (asset filename pattern)" - rm -rf "$tmpdir" return 1 } @@ -10234,7 +10078,6 @@ fetch_and_deploy_gl_release() { [[ -z "$asset_url" ]] && { msg_error "No asset matching '$pattern' found" - rm -rf "$tmpdir" return 1 } @@ -10247,7 +10090,6 @@ fetch_and_deploy_gl_release() { curl $download_timeout -fsSL "${header[@]}" -o "$target/$target_file" "$asset_url" || { msg_error "Download failed: $asset_url" - rm -rf "$tmpdir" return 1 } @@ -10257,13 +10099,11 @@ fetch_and_deploy_gl_release() { else msg_error "Unknown mode: $mode" - rm -rf "$tmpdir" return 1 fi echo "$version" >"$version_file" msg_ok "Deployed: $app ($version)" - rm -rf "$tmpdir" } # ------------------------------------------------------------------------------ From d81c9f3ed2827b24d03dc807cdf215750b5e2f1f Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 12:54:11 +0000 Subject: [PATCH 201/245] Update CHANGELOG.md (#15900) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9386336b..99aa845ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -517,6 +517,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### ✨ New Features + - tools.func: centralize deploy tail + trap-based tmpdir cleanup [@MickLesk](https://github.com/MickLesk) ([#15872](https://github.com/community-scripts/ProxmoxVE/pull/15872)) - Update OPNsense from 26.1 to 26.7 [@tdn131](https://github.com/tdn131) ([#15895](https://github.com/community-scripts/ProxmoxVE/pull/15895)) ### 💾 Core From e1ce55b547a70405704d5669fd33e5e5890e2bde Mon Sep 17 00:00:00 2001 From: TowyTowy <85077986+TowyTowy@users.noreply.github.com> Date: Sun, 19 Jul 2026 19:01:41 +0200 Subject: [PATCH 202/245] fix(build.func): expand glob in SSH key "Scan Folder/Glob" so it can find keys (#15873) Co-authored-by: Claude Co-authored-by: Sam Heinz --- misc/build.func | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/misc/build.func b/misc/build.func index 53509780f..6c5d20bfc 100644 --- a/misc/build.func +++ b/misc/build.func @@ -3600,9 +3600,9 @@ configure_ssh_settings() { glob_path=$(whiptail --backtitle "$backtitle" \ --inputbox "Enter a folder or glob to scan (e.g. /root/.ssh/*.pub)" 10 72 --title "Scan Folder/Glob" 3>&1 1>&2 2>&3) if [[ -n "$glob_path" ]]; then - shopt -s nullglob - read -r -a _scan_files <<<"$glob_path" - shopt -u nullglob + [[ -d "$glob_path" ]] && glob_path="${glob_path%/}/*" + local -a _scan_files + mapfile -t _scan_files < <(compgen -G "$glob_path") if [[ "${#_scan_files[@]}" -gt 0 ]]; then ssh_build_choices_from_files "${_scan_files[@]}" if [[ "$COUNT" -gt 0 ]]; then From 026fd25e7ac9a30cb3fbecde649183c6cc3f1c48 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:02:04 +0000 Subject: [PATCH 203/245] Update CHANGELOG.md (#15904) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99aa845ce..00f6294f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -524,6 +524,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Revert "core: add configurable host CA inheritance during bootstrap" [@MickLesk](https://github.com/MickLesk) ([#15886](https://github.com/community-scripts/ProxmoxVE/pull/15886)) + - #### 🐞 Bug Fixes + + - fix(build.func): expand glob in SSH key "Scan Folder/Glob" so it can find keys [@TowyTowy](https://github.com/TowyTowy) ([#15873](https://github.com/community-scripts/ProxmoxVE/pull/15873)) + ## 2026-07-18 ### 💾 Core From 3042cd5cee902f3ddc21f74a4ec2321394bd6fff Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Mon, 20 Jul 2026 10:29:05 +0200 Subject: [PATCH 204/245] fix(wanderer): use PocketBase-relative plugin symlink in unprivileged LXC (#15911) The /data/plugins symlink fails in default unprivileged containers with Operation not permitted. Link plugins via /opt/wanderer/source/db/data/plugins instead so PluginDir() can discover them without root-level symlinks. Fixes #15799 --- ct/wanderer.sh | 4 ++-- install/wanderer-install.sh | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ct/wanderer.sh b/ct/wanderer.sh index bb0ec71cd..e0b3ed0be 100644 --- a/ct/wanderer.sh +++ b/ct/wanderer.sh @@ -46,8 +46,8 @@ function update_script() { cd /opt/wanderer/source/web $STD npm ci $STD npm run build - mkdir -p /opt/wanderer/data/plugins - [[ -e /data/plugins ]] || ln -sfn /opt/wanderer/data/plugins /data/plugins + mkdir -p /opt/wanderer/data/plugins /opt/wanderer/source/db/data + [[ -e /opt/wanderer/source/db/data/plugins ]] || ln -sfn /opt/wanderer/data/plugins /opt/wanderer/source/db/data/plugins msg_info "Installing wanderer plugins" for plugin in hammerhead komoot strava; do fetch_and_deploy_gh_release "wanderer-plugin-${plugin}" "open-wanderer/wanderer" "prebuild" "${CHECK_UPDATE_RELEASE:-latest}" "/opt/wanderer/data/plugins" "wanderer-plugin-${plugin}.tar.gz" || msg_warn "Failed to install wanderer plugin: ${plugin}" diff --git a/install/wanderer-install.sh b/install/wanderer-install.sh index 6a8571bbf..ae8514c6b 100644 --- a/install/wanderer-install.sh +++ b/install/wanderer-install.sh @@ -21,8 +21,9 @@ else fetch_and_deploy_gh_release "meilisearch" "meilisearch/meilisearch" "binary" "latest" "/opt/wanderer/source/search" fi mkdir -p /opt/wanderer/{source,data/pb_data,data/meili_data,data/plugins} -[[ -e /data/plugins ]] || ln -sfn /opt/wanderer/data/plugins /data/plugins fetch_and_deploy_gh_release "wanderer" "open-wanderer/wanderer" "tarball" "latest" "/opt/wanderer/source" +mkdir -p /opt/wanderer/source/db/data +[[ -e /opt/wanderer/source/db/data/plugins ]] || ln -sfn /opt/wanderer/data/plugins /opt/wanderer/source/db/data/plugins msg_info "Installing wanderer (patience)" cd /opt/wanderer/source/db From a6a608614f10e5a34eb5aeb61e6ada47d28d2cc7 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 08:29:28 +0000 Subject: [PATCH 205/245] Update CHANGELOG.md (#15916) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00f6294f1..e6571b4b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -505,6 +505,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-20 + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - fix(wanderer): use PocketBase-relative plugin symlink in unprivileged LXC [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15911](https://github.com/community-scripts/ProxmoxVE/pull/15911)) + ## 2026-07-19 ### 🚀 Updated Scripts From 31b70249976cb550375f1405a339d9641e4285f0 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:43:34 +0200 Subject: [PATCH 206/245] Fix Omada package version extraction (#15908) Update both `ct/omada.sh` and `install/omada-install.sh` to parse the Omada version directly from the `_v..._linux` segment of the Debian filename. This removes the old dependency on a timestamp suffix format and ensures `.omada` gets a valid version when TP-Link package naming varies. --- ct/omada.sh | 2 +- install/omada-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/omada.sh b/ct/omada.sh index 0c0c74811..f03e04cb3 100644 --- a/ct/omada.sh +++ b/ct/omada.sh @@ -43,7 +43,7 @@ function update_script() { grep -o 'https://static\.tp-link\.com/upload/software/[^"]*linux_x64[^"]*\.deb' | head -n1) OMADA_PKG=$(basename "${OMADA_URL}") - VERSION=$(sed -n 's/.*_v\([0-9.]*\)_.*_\([0-9]\{14\}\)\.deb$/\1-\2/p' <<<"${OMADA_PKG}") + VERSION=$(sed -n 's/.*_v\([0-9.]*\)_linux.*/\1/p' <<<"${OMADA_PKG}") CURRENT_VERSION=$(cat $HOME/.omada 2>/dev/null || echo "0") diff --git a/install/omada-install.sh b/install/omada-install.sh index 9b6f42a02..ea66e4b74 100644 --- a/install/omada-install.sh +++ b/install/omada-install.sh @@ -42,7 +42,7 @@ OMADA_PKG=$(basename "${OMADA_URL}") curl_download "${OMADA_PKG}" "${OMADA_URL}" $STD dpkg -i "${OMADA_PKG}" rm -rf "${OMADA_PKG}" -VERSION=$(sed -n 's/.*_v\([0-9.]*\)_.*_\([0-9]\{14\}\)\.deb$/\1-\2/p' <<<"${OMADA_PKG}") +VERSION=$(sed -n 's/.*_v\([0-9.]*\)_linux.*/\1/p' <<<"${OMADA_PKG}") echo "${VERSION}" >$HOME/.omada msg_ok "Installed Omada Controller" From d6cd545e988fbcc918be44238517b8bf68d7be2b Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 09:43:57 +0000 Subject: [PATCH 207/245] Update CHANGELOG.md (#15920) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6571b4b5..0a641ccf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -511,6 +511,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - Omada: fix package version extraction [@MickLesk](https://github.com/MickLesk) ([#15908](https://github.com/community-scripts/ProxmoxVE/pull/15908)) - fix(wanderer): use PocketBase-relative plugin symlink in unprivileged LXC [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15911](https://github.com/community-scripts/ProxmoxVE/pull/15911)) ## 2026-07-19 From 9ea82fa99258e24128b87f92051956f8f42c98d3 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:46:33 +0200 Subject: [PATCH 208/245] core: Improve GPU detection and mapping logic (#15918) Refactor GPU detection logic to map DRI nodes to their owning GPUs based on vendor IDs. Update messages for detected Intel and AMD GPUs. --- misc/build.func | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/misc/build.func b/misc/build.func index 6c5d20bfc..ca33a36f8 100644 --- a/misc/build.func +++ b/misc/build.func @@ -4233,27 +4233,31 @@ $PCT_OPTIONS_STRING" return 0 fi - # Check for Intel GPU - look for Intel vendor ID [8086] - if grep -q "\[8086:" <<<"$pci_vga_info"; then - msg_custom "🎮" "${BL}" "Detected Intel GPU" - if [[ -d /dev/dri ]]; then - for d in /dev/dri/renderD* /dev/dri/card*; do - [[ -e "$d" ]] && INTEL_DEVICES+=("$d") - done - fi + # Map each DRI render/card node to its owning GPU via the PCI vendor ID + # exposed in sysfs (/sys/class/drm//device/vendor). This is required + # on multi-GPU hosts: globbing every /dev/dri node onto the first detected + # vendor would pass through *both* GPUs and skip the selection prompt. + if [[ -d /dev/dri ]]; then + for d in /dev/dri/renderD* /dev/dri/card*; do + [[ -e "$d" ]] || continue + local node vendor + node=$(basename "$d") + vendor=$(cat "/sys/class/drm/${node}/device/vendor" 2>/dev/null || true) + case "$vendor" in + 0x8086) INTEL_DEVICES+=("$d") ;; # Intel + 0x1002 | 0x1022) AMD_DEVICES+=("$d") ;; # AMD/ATI + 0x10de) ;; # NVIDIA - handled via /dev/nvidia* below + *) msg_debug "Unmapped GPU vendor '${vendor:-unknown}' for $d" ;; + esac + done fi - # Check for AMD GPU - look for AMD vendor IDs [1002] (AMD/ATI) or [1022] (AMD) - if grep -qE "\[1002:|\[1022:" <<<"$pci_vga_info"; then - msg_custom "🎮" "${RD}" "Detected AMD GPU" - if [[ -d /dev/dri ]]; then - # Only add if not already claimed by Intel - if [[ ${#INTEL_DEVICES[@]} -eq 0 ]]; then - for d in /dev/dri/renderD* /dev/dri/card* /dev/kfd; do - [[ -e "$d" ]] && AMD_DEVICES+=("$d") - done - fi - fi + [[ ${#INTEL_DEVICES[@]} -gt 0 ]] && msg_custom "🎮" "${BL}" "Detected Intel GPU" + [[ ${#AMD_DEVICES[@]} -gt 0 ]] && msg_custom "🎮" "${RD}" "Detected AMD GPU" + + # AMD compute (ROCm) additionally needs /dev/kfd alongside the render nodes + if [[ ${#AMD_DEVICES[@]} -gt 0 && -e /dev/kfd ]]; then + AMD_DEVICES+=("/dev/kfd") fi # Check for NVIDIA GPU - look for NVIDIA vendor ID [10de] From beeb497519c643936dfb7558eae3b04cbfb855cd Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 09:46:56 +0000 Subject: [PATCH 209/245] Update CHANGELOG.md (#15922) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a641ccf6..a8ca47c30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -514,6 +514,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Omada: fix package version extraction [@MickLesk](https://github.com/MickLesk) ([#15908](https://github.com/community-scripts/ProxmoxVE/pull/15908)) - fix(wanderer): use PocketBase-relative plugin symlink in unprivileged LXC [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15911](https://github.com/community-scripts/ProxmoxVE/pull/15911)) +### 💾 Core + + - #### 🔧 Refactor + + - core: Improve GPU detection and mapping logic [@MickLesk](https://github.com/MickLesk) ([#15918](https://github.com/community-scripts/ProxmoxVE/pull/15918)) + ## 2026-07-19 ### 🚀 Updated Scripts From 2c13cb6a382dda067b5c1d574006921c3c5eb90a Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:53:27 +0200 Subject: [PATCH 210/245] Meilisearch : use dumpless Meilisearch upgrades (#15921) --- misc/tools.func | 168 ++++++++++++++---------------------------------- 1 file changed, 50 insertions(+), 118 deletions(-) diff --git a/misc/tools.func b/misc/tools.func index cc5e66162..af82098dc 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -6981,7 +6981,7 @@ setup_meilisearch() { CURRENT_VERSION=$(/usr/bin/meilisearch --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) || CURRENT_VERSION="0.0.0" NEW_VERSION="${CHECK_UPDATE_RELEASE#v}" - # Extract major.minor for comparison (Meilisearch requires dump/restore between minor versions) + # Extract major.minor for comparison (Meilisearch changes its on-disk DB format between minor versions) local CURRENT_MAJOR_MINOR NEW_MAJOR_MINOR CURRENT_MAJOR_MINOR=$(echo "$CURRENT_VERSION" | cut -d. -f1,2) NEW_MAJOR_MINOR=$(echo "$NEW_VERSION" | cut -d. -f1,2) @@ -6993,140 +6993,72 @@ setup_meilisearch() { msg_info "MeiliSearch version change detected (${CURRENT_VERSION} → ${NEW_VERSION}), preparing data migration" fi - # Read config values for dump/restore - local MEILI_HOST MEILI_PORT MEILI_MASTER_KEY MEILI_DUMP_DIR + # Read connection + storage paths for the in-place (dumpless) upgrade + local MEILI_HOST MEILI_PORT MEILI_DB_PATH MEILI_HOST="${MEILISEARCH_HOST:-127.0.0.1}" MEILI_PORT="${MEILISEARCH_PORT:-7700}" - MEILI_DUMP_DIR="${MEILISEARCH_DUMP_DIR:-/var/lib/meilisearch/dumps}" - MEILI_MASTER_KEY=$(grep -E "^master_key\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ' || true) + MEILI_DB_PATH=$(grep -E "^db_path\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ' || true) + MEILI_DB_PATH="${MEILI_DB_PATH:-/var/lib/meilisearch/data}" - # Create dump before update if migration is needed - local DUMP_UID="" - if [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -n "$MEILI_MASTER_KEY" ]]; then - msg_info "Creating MeiliSearch data dump before upgrade" + systemctl stop meilisearch - # Trigger dump creation - local DUMP_RESPONSE - DUMP_RESPONSE=$(curl -s -X POST "http://${MEILI_HOST}:${MEILI_PORT}/dumps" \ - -H "Authorization: Bearer ${MEILI_MASTER_KEY}" \ - -H "Content-Type: application/json" 2>/dev/null) || true - - # The initial response only contains taskUid, not dumpUid - # dumpUid is only available after the task completes - local TASK_UID - TASK_UID=$(echo "$DUMP_RESPONSE" | grep -oP '"taskUid":\s*\K[0-9]+' || true) - - if [[ -n "$TASK_UID" ]]; then - msg_info "Waiting for dump task ${TASK_UID} to complete..." - local MAX_WAIT=120 - local WAITED=0 - local TASK_RESULT="" - - while [[ $WAITED -lt $MAX_WAIT ]]; do - TASK_RESULT=$(curl -s "http://${MEILI_HOST}:${MEILI_PORT}/tasks/${TASK_UID}" \ - -H "Authorization: Bearer ${MEILI_MASTER_KEY}" 2>/dev/null) || true - - local TASK_STATUS - TASK_STATUS=$(echo "$TASK_RESULT" | grep -oP '"status":\s*"\K[^"]+' || true) - - if [[ "$TASK_STATUS" == "succeeded" ]]; then - # Extract dumpUid from the completed task details - DUMP_UID=$(echo "$TASK_RESULT" | grep -oP '"dumpUid":\s*"\K[^"]+' || true) - if [[ -n "$DUMP_UID" ]]; then - msg_ok "MeiliSearch dump created successfully: ${DUMP_UID}" - else - msg_warn "Dump task succeeded but could not extract dumpUid" - fi - break - elif [[ "$TASK_STATUS" == "failed" ]]; then - local ERROR_MSG - ERROR_MSG=$(echo "$TASK_RESULT" | grep -oP '"message":\s*"\K[^"]+' || echo "Unknown error") - msg_warn "MeiliSearch dump failed: ${ERROR_MSG}" - break - fi - sleep 2 - WAITED=$((WAITED + 2)) - done - - if [[ $WAITED -ge $MAX_WAIT ]]; then - msg_warn "MeiliSearch dump timed out after ${MAX_WAIT}s" - fi - else - msg_warn "Could not trigger MeiliSearch dump (no taskUid in response)" - msg_info "Response was: ${DUMP_RESPONSE:-empty}" - fi - fi - - if [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -z "$DUMP_UID" ]]; then - msg_error "MeiliSearch migration requires a successful dump before upgrade" - msg_error "Ensure the service is running and master_key is configured, or set MEILISEARCH_SKIP_MIGRATION=1 to force (data loss risk)" - if [[ "${MEILISEARCH_SKIP_MIGRATION:-}" != "1" ]]; then + # Safety backup of the data dir before any in-place migration. + # Dumpless upgrade mutates the DB in place and cannot be rolled back on + # failure, so keep a tarball to restore from. (No master_key/API needed.) + local MEILI_BACKUP="" + if [[ "$NEEDS_MIGRATION" == "true" ]]; then + MEILI_BACKUP="/var/lib/meilisearch/pre-upgrade-${CURRENT_VERSION}.tar.gz" + msg_info "Backing up data dir before upgrade → ${MEILI_BACKUP}" + if ! tar -czf "$MEILI_BACKUP" -C "$MEILI_DB_PATH" . 2>/dev/null; then + msg_error "MeiliSearch data backup failed — aborting upgrade to avoid data loss" + systemctl start meilisearch return 100 fi - msg_warn "MEILISEARCH_SKIP_MIGRATION=1 — proceeding without dump (manual reindex may be required)" + msg_ok "Backup created: ${MEILI_BACKUP}" fi - # Stop service and update binary - systemctl stop meilisearch + # Replace the binary if [[ "$(arch_resolve)" == "arm64" ]]; then fetch_and_deploy_gh_release "meilisearch" "meilisearch/meilisearch" "singlefile" "latest" "/usr/bin" "meilisearch-linux-aarch64" else fetch_and_deploy_gh_release "meilisearch" "meilisearch/meilisearch" "binary" fi - # If migration needed and dump was created, remove old data and import dump - if [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -n "$DUMP_UID" ]]; then - local MEILI_DB_PATH - MEILI_DB_PATH=$(grep -E "^db_path\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ' || true) - MEILI_DB_PATH="${MEILI_DB_PATH:-/var/lib/meilisearch/data}" + if [[ "$NEEDS_MIGRATION" == "true" ]]; then + # One-time in-place migration via --experimental-dumpless-upgrade. + # Meilisearch migrates the on-disk DB during this startup; subsequent + # normal (systemd) starts run without the flag. + msg_info "Migrating data in place (dumpless upgrade ${CURRENT_VERSION} → ${NEW_VERSION})" + /usr/bin/meilisearch --config-file-path /etc/meilisearch.toml --experimental-dumpless-upgrade >/dev/null 2>&1 & + local MEILI_PID=$! - msg_info "Removing old MeiliSearch database for migration" - find "${MEILI_DB_PATH:?}" -mindepth 1 -delete - - # Import dump using CLI flag (this is the supported method) - local DUMP_FILE="${MEILI_DUMP_DIR}/${DUMP_UID}.dump" - if [[ -f "$DUMP_FILE" ]]; then - msg_info "Importing dump: ${DUMP_FILE}" - - # Start meilisearch with --import-dump flag - # This is a one-time import that happens during startup - /usr/bin/meilisearch --config-file-path /etc/meilisearch.toml --import-dump "$DUMP_FILE" >/dev/null 2>&1 & - local MEILI_PID=$! - - # Wait for meilisearch to become healthy (import happens during startup) - msg_info "Waiting for MeiliSearch to import and start..." - local MAX_WAIT=300 - local WAITED=0 - while [[ $WAITED -lt $MAX_WAIT ]]; do - if curl -sf "http://${MEILI_HOST}:${MEILI_PORT}/health" &>/dev/null; then - msg_ok "MeiliSearch is healthy after import" - break - fi - # Check if process is still running - if ! kill -0 $MEILI_PID 2>/dev/null; then - msg_warn "MeiliSearch process exited during import" - break - fi - sleep 3 - WAITED=$((WAITED + 3)) - done - - # Stop the manual process - kill $MEILI_PID 2>/dev/null || true - wait $MEILI_PID 2>/dev/null || true - sleep 2 - - # Start via systemd for proper management - systemctl start meilisearch - - if systemctl is-active --quiet meilisearch; then - msg_ok "MeiliSearch migrated successfully" - else - msg_warn "MeiliSearch failed to start after migration - check logs with: journalctl -u meilisearch" + local MAX_WAIT=300 + local WAITED=0 + local MIGRATED=false + while [[ $WAITED -lt $MAX_WAIT ]]; do + if curl -sf "http://${MEILI_HOST}:${MEILI_PORT}/health" &>/dev/null; then + MIGRATED=true + break fi + # Bail early if the migration process died + if ! kill -0 $MEILI_PID 2>/dev/null; then + msg_warn "MeiliSearch process exited during migration" + break + fi + sleep 3 + WAITED=$((WAITED + 3)) + done + + # Stop the one-shot migration process and hand over to systemd + kill $MEILI_PID 2>/dev/null || true + wait $MEILI_PID 2>/dev/null || true + sleep 2 + systemctl start meilisearch + + if [[ "$MIGRATED" == "true" ]] && systemctl is-active --quiet meilisearch; then + msg_ok "MeiliSearch migrated successfully (backup kept at ${MEILI_BACKUP})" else - msg_warn "Dump file not found: ${DUMP_FILE}" - systemctl start meilisearch + msg_error "MeiliSearch migration failed. Restore with: systemctl stop meilisearch; rm -rf ${MEILI_DB_PATH:?}/*; tar -xzf ${MEILI_BACKUP} -C ${MEILI_DB_PATH}; then reinstall the previous version" fi else systemctl start meilisearch From b6a8ca1a3a85f32618b65b2ee5d565c0984e5b79 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 09:53:51 +0000 Subject: [PATCH 211/245] Update CHANGELOG.md (#15923) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8ca47c30..ef27f7d43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -516,6 +516,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 💾 Core + - #### ✨ New Features + + - Meilisearch : use dumpless Meilisearch upgrades [@MickLesk](https://github.com/MickLesk) ([#15921](https://github.com/community-scripts/ProxmoxVE/pull/15921)) + - #### 🔧 Refactor - core: Improve GPU detection and mapping logic [@MickLesk](https://github.com/MickLesk) ([#15918](https://github.com/community-scripts/ProxmoxVE/pull/15918)) From fa9377cd4533a7223eda7c47b427c769f2c8feb7 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:54:04 +0200 Subject: [PATCH 212/245] Zammad : bind Elasticsearch to 127.0.0.1 (#15909) --- install/zammad-install.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/install/zammad-install.sh b/install/zammad-install.sh index 1cd56f63b..750f30214 100644 --- a/install/zammad-install.sh +++ b/install/zammad-install.sh @@ -32,6 +32,7 @@ sed -i 's/^#\{0,2\} *-Xms[0-9]*g.*/-Xms2g/' /etc/elasticsearch/jvm.options sed -i 's/^#\{0,2\} *-Xmx[0-9]*g.*/-Xmx2g/' /etc/elasticsearch/jvm.options cat </etc/elasticsearch/elasticsearch.yml discovery.type: single-node +network.host: 127.0.0.1 xpack.security.enabled: false bootstrap.memory_lock: false EOF @@ -40,7 +41,7 @@ systemctl daemon-reload systemctl enable -q elasticsearch systemctl restart -q elasticsearch for i in $(seq 1 30); do - if curl -s http://localhost:9200 >/dev/null 2>&1; then + if curl -s http://127.0.0.1:9200 >/dev/null 2>&1; then break fi sleep 2 @@ -55,7 +56,7 @@ setup_deb822_repo \ "$(get_os_info version_id)" \ "main" $STD apt install -y zammad -$STD zammad run rails r "Setting.set('es_url', 'http://localhost:9200')" +$STD zammad run rails r "Setting.set('es_url', 'http://127.0.0.1:9200')" $STD zammad run rake zammad:searchindex:rebuild msg_ok "Installed Zammad" From 1dba4eb2eef0f2f71dc764a8948fa18015f57323 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 09:54:29 +0000 Subject: [PATCH 213/245] Update CHANGELOG.md (#15924) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef27f7d43..0544fb282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -511,6 +511,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - Zammad : bind Elasticsearch to 127.0.0.1 [@MickLesk](https://github.com/MickLesk) ([#15909](https://github.com/community-scripts/ProxmoxVE/pull/15909)) - Omada: fix package version extraction [@MickLesk](https://github.com/MickLesk) ([#15908](https://github.com/community-scripts/ProxmoxVE/pull/15908)) - fix(wanderer): use PocketBase-relative plugin symlink in unprivileged LXC [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15911](https://github.com/community-scripts/ProxmoxVE/pull/15911)) From f8cc69e2447b813cf16e68d3f0f4c7f1c2c019d6 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:55:01 +0200 Subject: [PATCH 214/245] Gotify: Migration to v3 (#15912) --- ct/gotify.sh | 24 ++++++++++++++++++++++++ install/gotify-install.sh | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/ct/gotify.sh b/ct/gotify.sh index 0615a2342..cf15fc124 100644 --- a/ct/gotify.sh +++ b/ct/gotify.sh @@ -36,6 +36,30 @@ function update_script() { fetch_and_deploy_gh_release "gotify" "gotify/server" "prebuild" "latest" "/opt/gotify" "gotify-linux-$(arch_resolve).zip" chmod +x /opt/gotify/gotify-linux-$(arch_resolve) + if [[ ! -f /opt/gotify/gotify-server.env ]]; then + gotify_old_config="" + for f in /opt/gotify/config.yml /etc/gotify/config.yml; do + [[ -f "$f" ]] && gotify_old_config="$f" && break + done + if [[ -n "$gotify_old_config" ]]; then + msg_info "Migrating ${gotify_old_config} to env format (Gotify 3.x)" + if /opt/gotify/gotify-linux-$(arch_resolve) migrate-config "$gotify_old_config" >/opt/gotify/gotify-server.env 2>/dev/null; then + mv "$gotify_old_config" "${gotify_old_config}.bak" + msg_ok "Migrated config to /opt/gotify/gotify-server.env (backup: ${gotify_old_config}.bak)" + else + rm -f /opt/gotify/gotify-server.env + msg_warn "Config migration failed — left ${gotify_old_config} in place, review manually" + fi + fi + fi + + if ! grep -qE '^ExecStart=.* serve' /etc/systemd/system/gotify.service 2>/dev/null; then + msg_info "Migrating service to serve subcommand (Gotify 3.x)" + sed -i -E 's|^(ExecStart=/opt/gotify/.*gotify-linux-[^ ]+)$|\1 serve|' /etc/systemd/system/gotify.service + systemctl daemon-reload + msg_ok "Migrated service to serve subcommand" + fi + msg_info "Starting Service" systemctl start gotify msg_ok "Started Service" diff --git a/install/gotify-install.sh b/install/gotify-install.sh index 44444c74f..c9623be69 100644 --- a/install/gotify-install.sh +++ b/install/gotify-install.sh @@ -27,7 +27,7 @@ After=network.target Type=simple User=root WorkingDirectory=/opt/gotify -ExecStart=/opt/gotify/./gotify-linux-$(arch_resolve) +ExecStart=/opt/gotify/gotify-linux-$(arch_resolve) serve Restart=always RestartSec=3 From a61dc9c585b002c216b86aeb137afaeaacfbe9cb Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 09:55:26 +0000 Subject: [PATCH 215/245] Update CHANGELOG.md (#15925) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0544fb282..8df890164 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -515,6 +515,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Omada: fix package version extraction [@MickLesk](https://github.com/MickLesk) ([#15908](https://github.com/community-scripts/ProxmoxVE/pull/15908)) - fix(wanderer): use PocketBase-relative plugin symlink in unprivileged LXC [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15911](https://github.com/community-scripts/ProxmoxVE/pull/15911)) + - #### 💥 Breaking Changes + + - Gotify: Migration to v3 [@MickLesk](https://github.com/MickLesk) ([#15912](https://github.com/community-scripts/ProxmoxVE/pull/15912)) + ### 💾 Core - #### ✨ New Features From 5b4e5263299bc0055bc43dda506c930719fe5893 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:57:41 +0200 Subject: [PATCH 216/245] tools.func: add support for extracting 7z archives (#15919) --- misc/tools.func | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/misc/tools.func b/misc/tools.func index af82098dc..1cc7dc257 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -2587,6 +2587,16 @@ _deploy_unpacked_archive() { msg_error "Failed to extract TAR archive" return 251 } + elif [[ "$filename" == *.7z ]]; then + if [[ -f /etc/alpine-release ]]; then + ensure_dependencies 7zip + else + ensure_dependencies p7zip-full + fi + 7z x -y -o"$workdir" "$archive" >/dev/null 2>&1 || { + msg_error "Failed to extract 7z archive" + return 251 + } else msg_error "Unsupported archive format: $filename" return 65 From f15e9c320bdbb866f121eb3043867822eaf2414a Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 09:58:10 +0000 Subject: [PATCH 217/245] Update CHANGELOG.md (#15926) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8df890164..9ca9a991a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -523,6 +523,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### ✨ New Features + - tools.func: add support for extracting 7z archives [@MickLesk](https://github.com/MickLesk) ([#15919](https://github.com/community-scripts/ProxmoxVE/pull/15919)) - Meilisearch : use dumpless Meilisearch upgrades [@MickLesk](https://github.com/MickLesk) ([#15921](https://github.com/community-scripts/ProxmoxVE/pull/15921)) - #### 🔧 Refactor From 8505d284295b99cbee5f90cffaf66d553f182efc Mon Sep 17 00:00:00 2001 From: MickLesk Date: Mon, 20 Jul 2026 12:15:57 +0200 Subject: [PATCH 218/245] Set explicit Elasticsearch paths Define `path.data` and `path.logs` in the Zammad install script's Elasticsearch config so the service uses the expected data and log directories when running in the single-node local setup. --- install/zammad-install.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/install/zammad-install.sh b/install/zammad-install.sh index 750f30214..20777142c 100644 --- a/install/zammad-install.sh +++ b/install/zammad-install.sh @@ -31,6 +31,8 @@ $STD apt install -y elasticsearch sed -i 's/^#\{0,2\} *-Xms[0-9]*g.*/-Xms2g/' /etc/elasticsearch/jvm.options sed -i 's/^#\{0,2\} *-Xmx[0-9]*g.*/-Xmx2g/' /etc/elasticsearch/jvm.options cat </etc/elasticsearch/elasticsearch.yml +path.data: /var/lib/elasticsearch +path.logs: /var/log/elasticsearch discovery.type: single-node network.host: 127.0.0.1 xpack.security.enabled: false From e925e29966aaf294d59265b175cf2465956fc8f0 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:39:29 +0200 Subject: [PATCH 219/245] RomM: use backup helpers in update / clear folder (#15915) * RomM: use backup helpers in update / clear folder Replace manual .env backup/restore with create_backup and restore_backup helpers, and add CLEAN_INSTALL=1 flag to fetch_and_deploy_gh_release. * add screenscraper env * add rom_patcher * add ruffle and emulatorJS --- ct/romm.sh | 27 ++++++++++++++++++++++----- install/romm-install.sh | 17 +++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/ct/romm.sh b/ct/romm.sh index 7a34a8e75..eb05d2168 100644 --- a/ct/romm.sh +++ b/ct/romm.sh @@ -37,18 +37,29 @@ function update_script() { systemctl stop romm-backend romm-worker romm-scheduler romm-watcher msg_ok "Stopped Services" - msg_info "Backing up configuration" - cp /opt/romm/.env /opt/romm/.env.backup - msg_ok "Backed up configuration" + create_backup /opt/romm/.env + BACKUP_DIR=/opt/romm-players.backup create_backup \ + /opt/romm/frontend/dist/assets/emulatorjs \ + /opt/romm/frontend/dist/assets/ruffle - fetch_and_deploy_gh_release "romm" "rommapp/romm" "tarball" "latest" "/opt/romm" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "romm" "rommapp/romm" "tarball" "latest" "/opt/romm" + + restore_backup msg_info "Updating ROMM" - cp /opt/romm/.env.backup /opt/romm/.env cd /opt/romm $STD uv sync --all-extras cd /opt/romm/backend $STD uv run alembic upgrade head + if [[ -f /opt/romm/backend/utils/rom_patcher/package.json ]]; then + cd /opt/romm/backend/utils/rom_patcher + $STD npm install --ignore-scripts --no-audit --no-fund + if [[ -d node_modules/rom-patcher/rom-patcher-js ]]; then + rm -rf rom-patcher-js + cp -r node_modules/rom-patcher/rom-patcher-js ./rom-patcher-js + fi + rm -rf node_modules + fi cd /opt/romm/frontend $STD npm install $STD npm run build @@ -73,6 +84,12 @@ function update_script() { msg_ok "Started Services" msg_ok "Updated successfully" fi + + if check_for_gh_release "EmulatorJS" "EmulatorJS/EmulatorJS" "v4.2.3"; then + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "EmulatorJS" "EmulatorJS/EmulatorJS" "prebuild" "v4.2.3" "/opt/romm/frontend/dist/assets/emulatorjs" "4.2.3.7z" + systemctl restart romm-backend romm-worker romm-scheduler romm-watcher + msg_ok "Updated EmulatorJS successfully" + fi exit } diff --git a/install/romm-install.sh b/install/romm-install.sh index bf126dea0..d88410082 100644 --- a/install/romm-install.sh +++ b/install/romm-install.sh @@ -134,6 +134,8 @@ else fi fetch_and_deploy_gh_release "romm" "rommapp/romm" "tarball" +fetch_and_deploy_gh_release "ruffle" "ruffle-rs/ruffle" "prebuild" "latest" "/opt/romm/frontend/dist/assets/ruffle" "ruffle-*-web-selfhosted.zip" +fetch_and_deploy_gh_release "EmulatorJS" "EmulatorJS/EmulatorJS" "prebuild" "v4.2.3" "/opt/romm/frontend/dist/assets/emulatorjs" "4.2.3.7z" msg_info "Creating environment file" sed -i 's/^supervised no/supervised systemd/' /etc/redis/redis.conf @@ -159,6 +161,9 @@ ROMM_AUTH_SECRET_KEY=$AUTH_SECRET_KEY DISABLE_DOWNLOAD_ENDPOINT_AUTH=false DISABLE_CSRF_PROTECTION=false +SCREENSCRAPER_DEV_ID= +SCREENSCRAPER_DEV_PASSWORD= + ENABLE_RESCAN_ON_FILESYSTEM_CHANGE=true RESCAN_ON_FILESYSTEM_CHANGE_DELAY=5 @@ -181,6 +186,18 @@ cd /opt/romm/backend $STD uv run alembic upgrade head msg_ok "Set up RomM Backend" +if [[ -f /opt/romm/backend/utils/rom_patcher/package.json ]]; then + msg_info "Building ROM Patcher helper" + cd /opt/romm/backend/utils/rom_patcher + $STD npm install --ignore-scripts --no-audit --no-fund + if [[ -d node_modules/rom-patcher/rom-patcher-js ]]; then + rm -rf rom-patcher-js + cp -r node_modules/rom-patcher/rom-patcher-js ./rom-patcher-js + fi + rm -rf node_modules + msg_ok "Built ROM Patcher helper" +fi + msg_info "Setting up RomM Frontend" cd /opt/romm/frontend $STD npm install From 640865356458d3daa6bb860e883fadfd8b263e74 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:39:57 +0000 Subject: [PATCH 220/245] Update CHANGELOG.md (#15928) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ca9a991a..81c5b70d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -511,6 +511,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - RomM: use backup helpers in update / clear folder [@MickLesk](https://github.com/MickLesk) ([#15915](https://github.com/community-scripts/ProxmoxVE/pull/15915)) - Zammad : bind Elasticsearch to 127.0.0.1 [@MickLesk](https://github.com/MickLesk) ([#15909](https://github.com/community-scripts/ProxmoxVE/pull/15909)) - Omada: fix package version extraction [@MickLesk](https://github.com/MickLesk) ([#15908](https://github.com/community-scripts/ProxmoxVE/pull/15908)) - fix(wanderer): use PocketBase-relative plugin symlink in unprivileged LXC [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15911](https://github.com/community-scripts/ProxmoxVE/pull/15911)) From 0d3ee851d06535fecc2620e16f1eb5f4b130b2e2 Mon Sep 17 00:00:00 2001 From: Tobias <96661824+CrazyWolf13@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:20:54 +0200 Subject: [PATCH 221/245] fix: vikunja: asset selection (#15929) Co-authored-by: Claude Opus 4.8 (1M context) --- ct/vikunja.sh | 2 +- install/vikunja-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/vikunja.sh b/ct/vikunja.sh index 37dbecbdf..71fc47380 100644 --- a/ct/vikunja.sh +++ b/ct/vikunja.sh @@ -65,7 +65,7 @@ function update_script() { systemctl stop vikunja msg_ok "Stopped Service" - fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" + fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "latest" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb" $STD systemctl daemon-reload msg_info "Starting Service" diff --git a/install/vikunja-install.sh b/install/vikunja-install.sh index 98f27824f..6495068bf 100644 --- a/install/vikunja-install.sh +++ b/install/vikunja-install.sh @@ -13,7 +13,7 @@ setting_up_container network_check update_os -fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" +fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "latest" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb" msg_info "Setting up Vikunja" sed -i 's|^# \(service:\)|\1|' /etc/vikunja/config.yml From 9028029ea06a9b0266f6d461d0a6d91f1dc82ff6 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 15:21:26 +0000 Subject: [PATCH 222/245] Update CHANGELOG.md (#15931) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81c5b70d1..6f2bf507c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -511,6 +511,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - fix: vikunja: asset selection [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15929](https://github.com/community-scripts/ProxmoxVE/pull/15929)) - RomM: use backup helpers in update / clear folder [@MickLesk](https://github.com/MickLesk) ([#15915](https://github.com/community-scripts/ProxmoxVE/pull/15915)) - Zammad : bind Elasticsearch to 127.0.0.1 [@MickLesk](https://github.com/MickLesk) ([#15909](https://github.com/community-scripts/ProxmoxVE/pull/15909)) - Omada: fix package version extraction [@MickLesk](https://github.com/MickLesk) ([#15908](https://github.com/community-scripts/ProxmoxVE/pull/15908)) From 3b8f57672e19de3f973b7219c52546483f297b37 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:57:16 +0200 Subject: [PATCH 223/245] AFFiNE: Bump version to v0.27.2 (#15930) --- ct/affine.sh | 2 +- install/affine-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/affine.sh b/ct/affine.sh index 1480c2a99..911f51f61 100644 --- a/ct/affine.sh +++ b/ct/affine.sh @@ -30,7 +30,7 @@ function update_script() { exit fi - RELEASE="v0.27.0" + RELEASE="v0.27.2" if check_for_gh_release "affine_app" "toeverything/AFFiNE" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then msg_info "Stopping Services" systemctl stop affine-web affine-worker diff --git a/install/affine-install.sh b/install/affine-install.sh index 50144d4e0..2d6a7d7b2 100644 --- a/install/affine-install.sh +++ b/install/affine-install.sh @@ -31,7 +31,7 @@ PG_DB_NAME="affine" PG_DB_USER="affine" setup_postgresql_db NODE_VERSION="22" setup_nodejs setup_rust -fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "v0.27.0" "/opt/affine" +fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "v0.27.2" "/opt/affine" msg_info "Setting up Directories" rm -rf /root/.affine From aa8352bfd53b77b6768c10e2b27b166afd5a25b4 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 15:57:41 +0000 Subject: [PATCH 224/245] Update CHANGELOG.md (#15932) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f2bf507c..d4a593152 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -517,6 +517,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Omada: fix package version extraction [@MickLesk](https://github.com/MickLesk) ([#15908](https://github.com/community-scripts/ProxmoxVE/pull/15908)) - fix(wanderer): use PocketBase-relative plugin symlink in unprivileged LXC [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15911](https://github.com/community-scripts/ProxmoxVE/pull/15911)) + - #### ✨ New Features + + - AFFiNE: Bump version to v0.27.2 [@MickLesk](https://github.com/MickLesk) ([#15930](https://github.com/community-scripts/ProxmoxVE/pull/15930)) + - #### 💥 Breaking Changes - Gotify: Migration to v3 [@MickLesk](https://github.com/MickLesk) ([#15912](https://github.com/community-scripts/ProxmoxVE/pull/15912)) From a5a0b90643ed5a5a81bddbbd4b63e778ec36b90e Mon Sep 17 00:00:00 2001 From: MickLesk Date: Mon, 20 Jul 2026 19:56:29 +0200 Subject: [PATCH 225/245] hotfix: preserve .env --- misc/tools.func | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/misc/tools.func b/misc/tools.func index 1cc7dc257..b31ae72d3 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -2523,7 +2523,9 @@ _download_source_tarball() { # directory). Extracts into , then copies the contents # of that top-level directory into . # -# - Honors CLEAN_INSTALL=1 (wipes first, dotfiles included). +# - Honors CLEAN_INSTALL=1 (wipes first, but PRESERVES dotfiles +# like .env — update scripts rely on config dotfiles surviving the wipe; +# deleting them broke every "backup → deploy → source .env" update flow). # - Does NOT own : the caller creates it and is responsible for its # cleanup (typically via a RETURN trap on its tmpdir). # - cp failures are non-fatal here, matching the previous inline behavior. @@ -2535,7 +2537,7 @@ _deploy_source_tarball() { mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - find "${target:?}" -mindepth 1 -delete + rm -rf "${target:?}/"* fi tar --no-same-owner -xzf "$tarball" -C "$workdir" || { @@ -2561,7 +2563,8 @@ _deploy_source_tarball() { # a single top-level directory, that directory is stripped (its contents land # directly in ); otherwise the archive contents are copied as-is. # -# - Honors CLEAN_INSTALL=1 (wipes first, dotfiles included). +# - Honors CLEAN_INSTALL=1 (wipes first, but PRESERVES dotfiles +# like .env — update scripts rely on config dotfiles surviving the wipe). # - Does NOT own : the caller creates it and cleans it up. # # Returns: 0 on success, 65 on unsupported format, 251 on extraction failure, @@ -2573,7 +2576,7 @@ _deploy_unpacked_archive() { mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - find "${target:?}" -mindepth 1 -delete + rm -rf "${target:?}/"* fi if [[ "$filename" == *.zip ]]; then @@ -9266,8 +9269,10 @@ fetch_and_deploy_from_url() { mkdir -p "$directory" + # CLEAN_INSTALL wipe PRESERVES dotfiles (.env etc.) — update scripts rely on + # config dotfiles surviving the wipe if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - find "${directory:?}" -mindepth 1 -delete + rm -rf "${directory:?}/"* fi local unpack_tmp From bd834f690a358e0a69f43130247ee93f96fffeea Mon Sep 17 00:00:00 2001 From: MickLesk Date: Mon, 20 Jul 2026 20:23:05 +0200 Subject: [PATCH 226/245] Fix CLEAN_INSTALL to wipe dotfiles too CLEAN_INSTALL now removes dotfiles (e.g. .env) along with other files, using `find -mindepth 1 -delete` instead of `rm -rf *`. Update scripts for affine, nametag, and postiz are updated to explicitly back up and restore .env (via create_backup/restore_backup or cp) BEFORE the build step that sources it, rather than relying on the wipe preserving dotfiles. --- ct/affine.sh | 13 ++++++++++--- ct/nametag.sh | 3 +++ ct/postiz.sh | 6 ++++-- misc/tools.func | 19 +++++++++---------- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/ct/affine.sh b/ct/affine.sh index 911f51f61..b910afe5d 100644 --- a/ct/affine.sh +++ b/ct/affine.sh @@ -38,10 +38,19 @@ function update_script() { ensure_dependencies cmake - create_backup /root/.affine/config /root/.affine/storage + create_backup /opt/affine/.env /root/.affine/config /root/.affine/storage CLEAN_INSTALL=1 fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "${RELEASE}" "/opt/affine" + # Restore BEFORE the build: CLEAN_INSTALL wiped /opt/affine including .env, + # and the build below sources it + restore_backup + + if [[ ! -f /opt/affine/.env ]]; then + msg_error "/opt/affine/.env is missing (lost by an earlier update). Recreate it before retrying — see the AFFiNE install script for the expected variables." + exit 1 + fi + msg_info "Rebuilding Application (Patience ~25 mins, don't close the console!)" cd /opt/affine source /root/.profile @@ -111,8 +120,6 @@ TURBO set -a && source /opt/affine/.env && set +a $STD node ./scripts/self-host-predeploy.js - restore_backup - msg_info "Starting Services" systemctl start affine-web affine-worker msg_ok "Started Services" diff --git a/ct/nametag.sh b/ct/nametag.sh index 9346a80f7..69fd34777 100644 --- a/ct/nametag.sh +++ b/ct/nametag.sh @@ -42,6 +42,9 @@ function update_script() { CLEAN_INSTALL=1 fetch_and_deploy_gh_release "nametag" "mattogodoy/nametag" "tarball" "latest" "/opt/nametag" + # Restore .env BEFORE the build: CLEAN_INSTALL wiped it and the build sources it + cp /opt/nametag.env.bak /opt/nametag/.env + msg_info "Rebuilding Application" cd /opt/nametag $STD npm ci diff --git a/ct/postiz.sh b/ct/postiz.sh index dc004abb5..bf488bf98 100644 --- a/ct/postiz.sh +++ b/ct/postiz.sh @@ -41,9 +41,12 @@ function update_script() { CLEAN_INSTALL=1 fetch_and_deploy_gh_release "postiz" "gitroomhq/postiz-app" "tarball" + # Restore BEFORE the build: CLEAN_INSTALL wiped /opt/postiz including .env, + # and the build below sources it + restore_backup + msg_info "Building Application" cd /opt/postiz - cp /opt/postiz_env.bak /opt/postiz/.env set -a && source /opt/postiz/.env && set +a export NODE_OPTIONS="--max-old-space-size=4096" $STD pnpm install @@ -57,7 +60,6 @@ function update_script() { msg_ok "Ran Database Migrations" mkdir -p /opt/postiz/uploads - restore_backup msg_info "Starting Services" systemctl start postiz-backend postiz-frontend postiz-orchestrator diff --git a/misc/tools.func b/misc/tools.func index b31ae72d3..a45667e66 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -2523,9 +2523,9 @@ _download_source_tarball() { # directory). Extracts into , then copies the contents # of that top-level directory into . # -# - Honors CLEAN_INSTALL=1 (wipes first, but PRESERVES dotfiles -# like .env — update scripts rely on config dotfiles surviving the wipe; -# deleting them broke every "backup → deploy → source .env" update flow). +# - Honors CLEAN_INSTALL=1 (wipes first, dotfiles included — back +# up config dotfiles like .env via create_backup and call restore_backup +# BEFORE any build step that sources them). # - Does NOT own : the caller creates it and is responsible for its # cleanup (typically via a RETURN trap on its tmpdir). # - cp failures are non-fatal here, matching the previous inline behavior. @@ -2537,7 +2537,7 @@ _deploy_source_tarball() { mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${target:?}/"* + find "${target:?}" -mindepth 1 -delete fi tar --no-same-owner -xzf "$tarball" -C "$workdir" || { @@ -2563,8 +2563,9 @@ _deploy_source_tarball() { # a single top-level directory, that directory is stripped (its contents land # directly in ); otherwise the archive contents are copied as-is. # -# - Honors CLEAN_INSTALL=1 (wipes first, but PRESERVES dotfiles -# like .env — update scripts rely on config dotfiles surviving the wipe). +# - Honors CLEAN_INSTALL=1 (wipes first, dotfiles included — back +# up config dotfiles like .env via create_backup and call restore_backup +# BEFORE any build step that sources them). # - Does NOT own : the caller creates it and cleans it up. # # Returns: 0 on success, 65 on unsupported format, 251 on extraction failure, @@ -2576,7 +2577,7 @@ _deploy_unpacked_archive() { mkdir -p "$target" if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${target:?}/"* + find "${target:?}" -mindepth 1 -delete fi if [[ "$filename" == *.zip ]]; then @@ -9269,10 +9270,8 @@ fetch_and_deploy_from_url() { mkdir -p "$directory" - # CLEAN_INSTALL wipe PRESERVES dotfiles (.env etc.) — update scripts rely on - # config dotfiles surviving the wipe if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then - rm -rf "${directory:?}/"* + find "${directory:?}" -mindepth 1 -delete fi local unpack_tmp From b889e8d05e740291be93a8d213dcba70540816ce Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:23:30 +0000 Subject: [PATCH 227/245] Update CHANGELOG.md (#15935) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4a593152..caa12192b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -511,8 +511,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes - - fix: vikunja: asset selection [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15929](https://github.com/community-scripts/ProxmoxVE/pull/15929)) - RomM: use backup helpers in update / clear folder [@MickLesk](https://github.com/MickLesk) ([#15915](https://github.com/community-scripts/ProxmoxVE/pull/15915)) + - fix: vikunja: asset selection [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15929](https://github.com/community-scripts/ProxmoxVE/pull/15929)) - Zammad : bind Elasticsearch to 127.0.0.1 [@MickLesk](https://github.com/MickLesk) ([#15909](https://github.com/community-scripts/ProxmoxVE/pull/15909)) - Omada: fix package version extraction [@MickLesk](https://github.com/MickLesk) ([#15908](https://github.com/community-scripts/ProxmoxVE/pull/15908)) - fix(wanderer): use PocketBase-relative plugin symlink in unprivileged LXC [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15911](https://github.com/community-scripts/ProxmoxVE/pull/15911)) From 6f04a9787f7b54d543f83fa76d687950bb14468e Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 20 Jul 2026 20:32:36 +0200 Subject: [PATCH 228/245] core-refactor: single-reporter telemetry rewrite (#15933) Overhaul the telemetry system to enforce a single-reporter model where only the HOST sends terminal statuses (success/failed/aborted) to the API. Containers now write local artifact files (.failed flag + .errinfo) that the host picks up after lxc-attach returns, preventing the race condition where a metadata-less container payload would win over the full host payload. Key changes: - Add TELEMETRY_CONTEXT=container export in install.func/alpine-install.func to mark container context before error handling starts - Introduce _is_container_context() heuristic and _container_write_failure() artifact writer in error_handler.func - Refactor api.func: unified _tm_payload() builder (full metadata on every send), _tm_send() curl wrapper, _tm_enabled() gate, telemetry_collect_sysinfo() cached collector - Add structured .errinfo capture in silent() (core.func) using byte-offset to extract exactly the failing command's output - Pull .errinfo from container in build.func after lxc-attach for precise error traces - Add categorize_error(), telemetry_new_attempt(), detect_arm(), REPO_SLUG tracking - Signal exits (129/130/143) now report as 'aborted' instead of 'failed' - Remove post_update_to_api_extended() (superseded by unified _tm_payload) - Export REPO_SOURCE, REPO_SLUG, TELEMETRY_PLATFORM into container environment --- misc/alpine-install.func | 6 +- misc/api.func | 1378 +++++++++++++++----------------------- misc/build.func | 34 + misc/core.func | 37 + misc/error_handler.func | 404 +++++------ misc/install.func | 10 +- misc/vm-core.func | 6 +- 7 files changed, 820 insertions(+), 1055 deletions(-) diff --git a/misc/alpine-install.func b/misc/alpine-install.func index 893817a1f..695a55b1d 100644 --- a/misc/alpine-install.func +++ b/misc/alpine-install.func @@ -6,6 +6,10 @@ if ! command -v curl >/dev/null 2>&1; then apk update && apk add curl >/dev/null 2>&1 fi +# Mark container context BEFORE error handling starts: error_handler/on_exit +# must write local failure artifacts instead of talking to the telemetry API +# (the host is the single telemetry reporter). +export TELEMETRY_CONTEXT="container" source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) load_functions @@ -41,7 +45,7 @@ post_progress_to_api() { curl -fsS -m 5 -X POST "https://telemetry.community-scripts.org/telemetry" \ -H "Content-Type: application/json" \ - -d "{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"lxc\",\"nsapp\":\"${app:-unknown}\",\"status\":\"${progress_status}\"}" &>/dev/null || true + -d "{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"lxc\",\"nsapp\":\"${app:-unknown}\",\"status\":\"${progress_status}\",\"platform\":\"${TELEMETRY_PLATFORM:-}\",\"repo_source\":\"${REPO_SOURCE:-}\",\"repo_slug\":\"${REPO_SLUG:-}\"}" &>/dev/null || true } # This function enables IPv6 if it's not disabled and sets verbose mode diff --git a/misc/api.func b/misc/api.func index 899c6dfda..d413feed9 100644 --- a/misc/api.func +++ b/misc/api.func @@ -9,38 +9,53 @@ # Provides functions for sending anonymous telemetry data via the community # telemetry ingest service at telemetry.community-scripts.org. # -# Features: -# - Container/VM creation statistics -# - Installation success/failure tracking -# - Error code mapping and reporting -# - Privacy-respecting anonymous telemetry +# DESIGN PRINCIPLES: +# 1. SINGLE REPORTER: only the HOST sends terminal statuses (success/failed/ +# aborted). Containers never curl the telemetry endpoint for terminal +# events - they write local artifact files (.failed flag + .errinfo) that +# the host picks up. This prevents the "first terminal event wins" race +# on the server from persisting a metadata-less container payload and +# discarding the full host payload. +# 2. FULL PAYLOAD, ALWAYS: every send includes the complete system metadata +# (os, pve version, arch, cpu, gpu, ram, repo attribution). No more +# minimal payloads that create empty records. +# 3. FOCUSED ERROR TRACE: the error field contains exactly the output of the +# command that failed (captured by silent() via byte offset), prefixed +# with "exit_code=N | | at line L: ". Not a 120KB +# log dump, not the wrong phase of the log. +# 4. IDEMPOTENT FINALIZE: post_update_to_api() sends exactly one terminal +# status per execution, no matter how many traps fire. # # Usage: # source <(curl -fsSL .../api.func) -# post_to_api # Report LXC container creation -# post_to_api_vm # Report VM creation -# post_update_to_api # Report installation status +# post_to_api # Report LXC container creation ("installing") +# post_to_api_vm # Report VM creation ("installing") +# post_progress_to_api # Progress ping ("validation"/"configuring") +# post_update_to_api # Final status ("done"/"failed"/"aborted") # # Privacy: -# - Only anonymous statistics (no personal data) +# - Only anonymous statistics (no personal data, IPs are anonymized) # - User can opt-out via DIAGNOSTICS=no # - Random UUID for session tracking only -# - Data retention: 30 days # # ============================================================================== # ============================================================================== # Telemetry Configuration # ============================================================================== -TELEMETRY_URL="https://telemetry.community-scripts.org/telemetry" +TELEMETRY_URL="${TELEMETRY_URL:-https://telemetry.community-scripts.org/telemetry}" -# Timeout for telemetry requests (seconds) -# Progress pings (validation/configuring) use the short timeout +# Timeout for progress pings (seconds) TELEMETRY_TIMEOUT=5 -# Final status updates (success/failed) use the longer timeout -# PocketBase may need more time under load (FindRecord + UpdateRecord) +# Timeout for final status updates (they carry the error trace) STATUS_TIMEOUT=10 +# Max size of the error trace sent to the API (bytes) and max line count. +# Keep this SMALL and FOCUSED - the goal is "exactly the messages from the +# moment of failure", not the whole installation log. +TELEMETRY_ERROR_MAX_LINES=60 +TELEMETRY_ERROR_MAX_BYTES=10240 + # ============================================================================== # SECTION 0: REPOSITORY SOURCE DETECTION # ============================================================================== @@ -54,64 +69,75 @@ STATUS_TIMEOUT=10 # * "ProxmoxVE" — official community-scripts/ProxmoxVE (production) # * "ProxmoxVED" — official community-scripts/ProxmoxVED (development) # * "external" — any fork or unknown source -# - Fallback: "ProxmoxVED" (CI sed transforms ProxmoxVED → ProxmoxVE on promotion) -# - Sets and exports REPO_SOURCE global variable -# - Skips detection if REPO_SOURCE is already set (e.g., by environment) +# - Additionally sets REPO_SLUG to the real "owner/repo" string +# - Fallback: "ProxmoxVE" (this file lives in the production repo) +# - Skips detection if REPO_SOURCE is already set (e.g., exported by the host +# into the container environment) # ------------------------------------------------------------------------------ detect_repo_source() { - # Allow explicit override via environment - [[ -n "${REPO_SOURCE:-}" ]] && return 0 + # Allow explicit override via environment (also how the container inherits + # the host's attribution instead of re-detecting) + if [[ -n "${REPO_SOURCE:-}" ]]; then + if [[ -z "${REPO_SLUG:-}" ]]; then + case "$REPO_SOURCE" in + ProxmoxVE) REPO_SLUG="community-scripts/ProxmoxVE" ;; + ProxmoxVED) REPO_SLUG="community-scripts/ProxmoxVED" ;; + esac + export REPO_SLUG + fi + return 0 + fi local content="" owner_repo="" # Method 1: Read from /proc/$$/cmdline # When invoked via: bash -c "$(curl -fsSL https://.../ct/app.sh)" - # the full CT/VM script content is in /proc/$$/cmdline (same PID through source chain) if [[ -r /proc/$$/cmdline ]]; then content=$(tr '\0' ' ' /dev/null) || true fi - # Method 2: Read from the original script file (bash ct/app.sh / bash vm/app.sh) + # Method 2: Read from the original script file (bash ct/app.sh) if [[ -z "$content" ]] || ! echo "$content" | grep -qE 'githubusercontent\.com|community-scripts\.org' 2>/dev/null; then if [[ -f "$0" ]] && [[ "$0" != *bash* ]]; then content=$(head -10 "$0" 2>/dev/null) || true fi fi - # Extract owner/repo from URL patterns found in the script content if [[ -n "$content" ]]; then - # GitHub raw URL: raw.githubusercontent.com/OWNER/REPO/... owner_repo=$(echo "$content" | grep -oE 'raw\.githubusercontent\.com/[^/]+/[^/]+' | head -1 | sed 's|raw\.githubusercontent\.com/||') || true - - # Gitea URL: git.community-scripts.org/OWNER/REPO/... if [[ -z "$owner_repo" ]]; then owner_repo=$(echo "$content" | grep -oE 'git\.community-scripts\.org/[^/]+/[^/]+' | head -1 | sed 's|git\.community-scripts\.org/||') || true fi fi - # Map detected owner/repo to canonical repo_source value case "$owner_repo" in - community-scripts/ProxmoxVE) REPO_SOURCE="ProxmoxVE" ;; - community-scripts/ProxmoxVED) REPO_SOURCE="ProxmoxVED" ;; - "") - # No URL detected — use hardcoded fallback - # This value must match the repo: ProxmoxVE for production, ProxmoxVED for dev + community-scripts/ProxmoxVE) REPO_SOURCE="ProxmoxVE" + REPO_SLUG="community-scripts/ProxmoxVE" + ;; + community-scripts/ProxmoxVED) + REPO_SOURCE="ProxmoxVED" + REPO_SLUG="community-scripts/ProxmoxVED" + ;; + "") + # No URL detected — hardcoded fallback (production repo) + REPO_SOURCE="ProxmoxVE" + REPO_SLUG="community-scripts/ProxmoxVE" ;; *) - # Fork or unknown repo REPO_SOURCE="external" + REPO_SLUG="$owner_repo" ;; esac - export REPO_SOURCE + export REPO_SOURCE REPO_SLUG } # Run detection immediately when api.func is sourced detect_repo_source # ============================================================================== -# SECTION 1: ERROR CODE DESCRIPTIONS +# SECTION 1: ERROR CODE DESCRIPTIONS & CATEGORIES # ============================================================================== # ------------------------------------------------------------------------------ @@ -120,22 +146,6 @@ detect_repo_source # - Maps numeric exit codes to human-readable error descriptions # - Canonical source of truth for ALL exit code mappings # - Used by both api.func (telemetry) and error_handler.func (error display) -# - Supports: -# * Generic/Shell errors (1-3, 10, 124-132, 134, 137, 139, 141, 143-146) -# * curl/wget errors (4-8, 16, 18, 22-28, 30, 32-36, 39, 44-48, 51-52, 55-57, 59, 61, 63, 75, 78-79, 92, 95) -# * Package manager errors (APT, DPKG: 100-102, 255) -# * Script Validation & Setup (103-123) -# * BSD sysexits (64-78) -# * Systemd/Service errors (150-154) -# * Python/pip/uv errors (160-162) -# * PostgreSQL errors (170-173) -# * MySQL/MariaDB errors (180-183) -# * MongoDB errors (190-193) -# * Proxmox custom codes (200-231) -# * Tools & Addon Scripts (232-238) -# * Node.js/npm errors (239, 243, 245-249) -# * Application Install/Update errors (250-254) -# - Returns description string for given exit code # ------------------------------------------------------------------------------ explain_exit_code() { local code="$1" @@ -146,7 +156,7 @@ explain_exit_code() { 3) echo "General syntax or argument error" ;; 10) echo "Docker / privileged mode required (unsupported environment)" ;; - # --- curl / wget errors (commonly seen in downloads) --- + # --- curl / wget errors --- 4) echo "curl: Feature not supported or protocol error" ;; 5) echo "curl: Could not resolve proxy" ;; 6) echo "curl: DNS resolution failed (could not resolve host)" ;; @@ -254,6 +264,7 @@ explain_exit_code() { 152) echo "Permission denied (EACCES)" ;; 153) echo "Build/compile failed (make/gcc/cmake)" ;; 154) echo "Node.js: Native addon build failed (node-gyp)" ;; + # --- Python / pip / uv (160-162) --- 160) echo "Python: Virtualenv / uv environment missing or broken" ;; 161) echo "Python: Dependency resolution failed" ;; @@ -338,30 +349,62 @@ explain_exit_code() { esac } +# ------------------------------------------------------------------------------ +# categorize_error() +# +# - Maps exit codes to error categories for dashboard grouping +# - Can be overridden via ERROR_CATEGORY_OVERRIDE (log-based subclassification) +# ------------------------------------------------------------------------------ +categorize_error() { + if [[ -n "${ERROR_CATEGORY_OVERRIDE:-}" ]]; then + echo "$ERROR_CATEGORY_OVERRIDE" + return + fi + + local code="$1" + case "$code" in + 6 | 7 | 22 | 35) echo "network" ;; + 10) echo "config" ;; + 28 | 124 | 211) echo "timeout" ;; + 214 | 217 | 219 | 224) echo "storage" ;; + 100 | 101 | 102 | 127 | 160 | 161 | 162 | 255) echo "dependency" ;; + 126 | 152) echo "permission" ;; + 128 | 203 | 204 | 205 | 206 | 207 | 208) echo "config" ;; + 200 | 209 | 210 | 212 | 213 | 215 | 216 | 218 | 220 | 221 | 222 | 223 | 225 | 231) echo "proxmox" ;; + 150 | 151 | 153 | 154) echo "service" ;; + 170 | 171 | 172 | 173 | 180 | 181 | 182 | 183 | 190 | 191 | 192 | 193) echo "database" ;; + 243 | 245 | 246 | 247 | 248 | 249) echo "runtime" ;; + 129 | 130 | 143) echo "user_aborted" ;; + 134 | 137) echo "resource" ;; + 139 | 141) echo "signal" ;; + 1 | 2) echo "shell" ;; + *) echo "unknown" ;; + esac +} + +# ============================================================================== +# SECTION 2: JSON & LOG HELPERS +# ============================================================================== + # ------------------------------------------------------------------------------ # json_escape() # # - Escapes a string for safe JSON embedding # - Strips ANSI escape sequences and non-printable control characters -# - Handles backslashes, quotes, newlines, tabs, and carriage returns # - Uses jq when available (guaranteed correct), falls back to awk # ------------------------------------------------------------------------------ json_escape() { local input - # Pipeline: strip ANSI → remove control chars → escape for JSON input=$(printf '%s' "$1" | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' | tr -d '\000-\010\013\014\016-\037\177\r') - # Prefer jq: guaranteed correct JSON string encoding (handles all edge cases) if command -v jq &>/dev/null; then - # jq -Rs reads raw stdin as string, outputs JSON-encoded string with quotes. - # We strip the surrounding quotes since the heredoc adds them. printf '%s' "$input" | jq -Rs '.' | sed 's/^"//;s/"$//' return fi - # Fallback: character-by-character processing with awk (avoids gsub replacement pitfalls) + # Fallback: character-by-character processing with awk printf '%s' "$input" | awk ' BEGIN { ORS="" } @@ -378,140 +421,220 @@ json_escape() { } # ------------------------------------------------------------------------------ -# get_error_text() +# _tm_clean_log() # -# - Returns last 20 lines of the active log (INSTALL_LOG or BUILD_LOG) -# - Falls back to combined log or BUILD_LOG if primary is not accessible -# - Handles container paths that don't exist on the host +# - stdin filter: strips ANSI/CR, anonymizes IPs (GDPR), drops pure +# progress-noise lines (apt/dpkg download and unpack chatter) # ------------------------------------------------------------------------------ -get_error_text() { - local logfile="" - if declare -f get_active_logfile >/dev/null 2>&1; then - logfile=$(get_active_logfile) - elif [[ -n "${INSTALL_LOG:-}" ]]; then - logfile="$INSTALL_LOG" - elif [[ -n "${BUILD_LOG:-}" ]]; then - logfile="$BUILD_LOG" - fi - - # If logfile is inside container (e.g. /root/.install-*), try the host copy - if [[ -n "$logfile" && ! -s "$logfile" ]]; then - # Try combined log: /tmp/--.log - if [[ -n "${CTID:-}" && -n "${SESSION_ID:-}" ]]; then - local combined_log="/tmp/${NSAPP:-lxc}-${CTID}-${SESSION_ID}.log" - if [[ -s "$combined_log" ]]; then - logfile="$combined_log" - fi - fi - fi - - # Also try BUILD_LOG as fallback if primary log is empty/missing - if [[ -z "$logfile" || ! -s "$logfile" ]] && [[ -n "${BUILD_LOG:-}" && -s "${BUILD_LOG}" ]]; then - logfile="$BUILD_LOG" - fi - - # Try SILENT_LOGFILE as last resort (captures $STD command output) - if [[ -z "$logfile" || ! -s "$logfile" ]] && [[ -n "${SILENT_LOGFILE:-}" && -s "${SILENT_LOGFILE}" ]]; then - logfile="$SILENT_LOGFILE" - fi - - if [[ -n "$logfile" && -s "$logfile" ]]; then - tail -n 20 "$logfile" 2>/dev/null | sed 's/\r$//' | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' - fi +_tm_clean_log() { + sed 's/\r$//' | + sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' | + sed -E 's/([0-9]{1,3}\.)[0-9]{1,3}\.[0-9]{1,3}/\1x.x/g' | + grep -avE '^(Get:|Hit:|Ign:|Fetched |Reading package lists|Reading state information|Building dependency tree|Selecting previously|Preparing to unpack|Unpacking |Processing triggers for|\(Reading database|[0-9]+%[[:space:]]*\[)' | + grep -avE '^[[:space:]]*$' || true } # ------------------------------------------------------------------------------ -# get_full_log() +# _tm_pick_logfile() # -# - Returns the FULL installation log (build + install combined) -# - Calls ensure_log_on_host() to pull container log if needed -# - Strips ANSI escape codes and carriage returns -# - Truncates to max_bytes (default: 120KB) to stay within API limits -# - Used for the error telemetry field (full trace instead of 20 lines) +# - Returns the most specific available log file (combined → INSTALL_LOG → +# BUILD_LOG → SILENT_LOGFILE). Never downgrades a present log. +# ------------------------------------------------------------------------------ +_tm_pick_logfile() { + local candidate + for candidate in \ + "${combined_log:-}" \ + "/tmp/install-${SESSION_ID:-}-combined.log" \ + "/tmp/${NSAPP:-lxc}-${CTID:-}-${SESSION_ID:-}.log" \ + "${INSTALL_LOG:-}" \ + "${BUILD_LOG:-}" \ + "${SILENT_LOGFILE:-}"; do + if [[ -n "$candidate" && -s "$candidate" ]]; then + echo "$candidate" + return 0 + fi + done + return 0 +} + +# ------------------------------------------------------------------------------ +# get_error_log() +# +# - Returns the last N (default 50) RELEVANT lines of the active log +# - Fallback error source when no .errinfo capture exists +# ------------------------------------------------------------------------------ +get_error_log() { + local max_lines="${1:-50}" + local logfile + + if declare -f ensure_log_on_host >/dev/null 2>&1; then + ensure_log_on_host 2>/dev/null || true + fi + + logfile=$(_tm_pick_logfile) + [[ -z "$logfile" || ! -s "$logfile" ]] && return 0 + + _tm_clean_log <"$logfile" | tail -n "$max_lines" +} + +# ------------------------------------------------------------------------------ +# get_error_text() (legacy compatibility) +# +# - Returns last 20 relevant lines of the active log +# ------------------------------------------------------------------------------ +get_error_text() { + get_error_log 20 +} + +# ------------------------------------------------------------------------------ +# get_full_log() (legacy compatibility - dev/debug use only) +# +# - Returns the full log, ANSI-stripped and IP-anonymized, capped at max_bytes # ------------------------------------------------------------------------------ get_full_log() { - local max_bytes="${1:-122880}" # 120KB default - local logfile="" - - # Ensure logs are available on host (pulls from container if needed) + local max_bytes="${1:-122880}" + local logfile if declare -f ensure_log_on_host >/dev/null 2>&1; then - ensure_log_on_host + ensure_log_on_host 2>/dev/null || true fi + logfile=$(_tm_pick_logfile) + [[ -z "$logfile" || ! -s "$logfile" ]] && return 0 + sed 's/\r$//' "$logfile" 2>/dev/null | + sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' | + sed -E 's/([0-9]{1,3}\.)[0-9]{1,3}\.[0-9]{1,3}/\1x.x/g' | + head -c "$max_bytes" +} - # Try combined log first (most complete) - if [[ -n "${CTID:-}" && -n "${SESSION_ID:-}" ]]; then - local combined_log="/tmp/${NSAPP:-lxc}-${CTID}-${SESSION_ID}.log" - if [[ -s "$combined_log" ]]; then - logfile="$combined_log" +# ============================================================================== +# SECTION 3: STRUCTURED ERROR CAPTURE (.errinfo protocol) +# ============================================================================== +# +# When a command run via silent() fails, silent() writes ".errinfo": +# +# EXIT_CODE= +# LINE= +# COMMAND= +# --- OUTPUT --- +# +# +# error_handler() writes the same file for non-silent failures (best effort: +# tail of the active log). The HOST reads this file (pulling it from the +# container if needed) and builds the telemetry error field from it. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# _tm_find_errinfo() +# +# - Locates the newest .errinfo file for this session +# - Honors TELEMETRY_ERRINFO override (set by the host after pulling the +# container's copy) +# ------------------------------------------------------------------------------ +_tm_find_errinfo() { + local candidate + for candidate in \ + "${TELEMETRY_ERRINFO:-}" \ + "/tmp/.errinfo-${SESSION_ID:-none}" \ + "${INSTALL_LOG:-/nonexistent}.errinfo" \ + "${BUILD_LOG:-/nonexistent}.errinfo"; do + if [[ -n "$candidate" && -s "$candidate" ]]; then + echo "$candidate" + return 0 fi - fi + done + return 1 +} - # Fall back to INSTALL_LOG - if [[ -z "$logfile" || ! -s "$logfile" ]]; then - if [[ -n "${INSTALL_LOG:-}" && -s "${INSTALL_LOG}" ]]; then - logfile="$INSTALL_LOG" - fi - fi - - # Fall back to BUILD_LOG - if [[ -z "$logfile" || ! -s "$logfile" ]]; then - if [[ -n "${BUILD_LOG:-}" && -s "${BUILD_LOG}" ]]; then - logfile="$BUILD_LOG" - fi - fi - - # Fall back to SILENT_LOGFILE (captures $STD command output) - if [[ -z "$logfile" || ! -s "$logfile" ]]; then - if [[ -n "${SILENT_LOGFILE:-}" && -s "${SILENT_LOGFILE}" ]]; then - logfile="$SILENT_LOGFILE" - fi - fi - - if [[ -n "$logfile" && -s "$logfile" ]]; then - # Strip ANSI codes, carriage returns, and anonymize IP addresses (GDPR) - sed 's/\r$//' "$logfile" 2>/dev/null | - sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' | - sed -E 's/([0-9]{1,3}\.)[0-9]{1,3}\.[0-9]{1,3}/\1x.x/g' | - head -c "$max_bytes" - fi +# ------------------------------------------------------------------------------ +# write_errinfo() +# +# - Writes a structured .errinfo file next to the given logfile +# - Arguments: +# * $1: target file path +# * $2: exit_code +# * $3: line number +# * $4: command (flattened to one line, truncated) +# * stdin: output segment of the failing command +# ------------------------------------------------------------------------------ +write_errinfo() { + local target="$1" exit_code="$2" line="$3" command="$4" + command=$(printf '%s' "$command" | tr '\n' ' ' | head -c 300) + { + echo "EXIT_CODE=${exit_code}" + echo "LINE=${line}" + echo "COMMAND=${command}" + echo "--- OUTPUT ---" + _tm_clean_log | tail -n "${TELEMETRY_ERROR_MAX_LINES}" | head -c "${TELEMETRY_ERROR_MAX_BYTES}" + } >"$target" 2>/dev/null || true } # ------------------------------------------------------------------------------ # build_error_string() # -# - Builds a structured error string for telemetry reporting -# - Format: "exit_code= | \n---\n" -# - If no log lines available, returns just the explanation +# - Builds the final structured error string for telemetry: +# "exit_code=N | | at line L: \n---\n" +# - Sources, in priority order: +# 1. .errinfo file (exact output of the failing command) +# 2. FAILED_COMMAND/FAILED_LINE globals + filtered log tail +# 3. Explanation only # - Arguments: -# * $1: exit_code (numeric) -# * $2: log_text (optional, output from get_error_text) -# - Returns structured error string via stdout +# * $1: exit_code +# * $2: log_text (optional override for the output section) # ------------------------------------------------------------------------------ build_error_string() { local exit_code="${1:-1}" local log_text="${2:-}" - local explanation + local explanation location="" cmd="" line="" errinfo="" + + # Prefer the structured capture from the failure moment + if errinfo=$(_tm_find_errinfo); then + local captured_code + captured_code=$(sed -n 's/^EXIT_CODE=//p' "$errinfo" | head -1) + line=$(sed -n 's/^LINE=//p' "$errinfo" | head -1) + cmd=$(sed -n 's/^COMMAND=//p' "$errinfo" | head -1) + # Only trust the capture when it matches the reported failure (or the + # reported code is the generic 1 that bash propagates upward) + if [[ -n "$captured_code" && ("$captured_code" == "$exit_code" || "$exit_code" == "1" || "$exit_code" == "255") ]]; then + exit_code="$captured_code" + if [[ -z "$log_text" ]]; then + log_text=$(awk 'found{print} /^--- OUTPUT ---$/{found=1}' "$errinfo") + fi + else + cmd="" line="" + fi + fi + + # Fall back to globals exported by silent()/error_handler + [[ -z "$cmd" && -n "${FAILED_COMMAND:-}" ]] && cmd="${FAILED_COMMAND}" + [[ -z "$line" && -n "${FAILED_LINE:-}" ]] && line="${FAILED_LINE}" + explanation=$(explain_exit_code "$exit_code") + if [[ -n "$cmd" ]]; then + if [[ -n "$line" ]]; then + location=$(printf ' | at line %s: %s' "$line" "$cmd") + else + location=$(printf ' | command: %s' "$cmd") + fi + fi + + # Last-resort output: filtered tail of the active log + if [[ -z "$log_text" ]]; then + log_text=$(get_error_log 40) || true + fi + if [[ -n "$log_text" ]]; then - # Structured format: header + separator + log lines - printf 'exit_code=%s | %s\n---\n%s' "$exit_code" "$explanation" "$log_text" + printf 'exit_code=%s | %s%s\n---\n%s' "$exit_code" "$explanation" "$location" "$log_text" else - # No log available - just the explanation with exit code - printf 'exit_code=%s | %s' "$exit_code" "$explanation" + printf 'exit_code=%s | %s%s' "$exit_code" "$explanation" "$location" fi } # ============================================================================== -# SECTION 2: TELEMETRY FUNCTIONS +# SECTION 4: SYSTEM INFO COLLECTION (collected once, sent with EVERY payload) # ============================================================================== # ------------------------------------------------------------------------------ -# detect_gpu() -# -# - Detects GPU vendor, model, and passthrough type -# - Sets GPU_VENDOR, GPU_MODEL, and GPU_PASSTHROUGH globals -# - Used for GPU analytics +# detect_gpu() - GPU vendor, model, passthrough type # ------------------------------------------------------------------------------ detect_gpu() { GPU_VENDOR="unknown" @@ -522,10 +645,8 @@ detect_gpu() { gpu_line=$(lspci 2>/dev/null | grep -iE "VGA|3D|Display" | head -1 || true) if [[ -n "$gpu_line" ]]; then - # Extract model: everything after the colon, clean up GPU_MODEL=$(echo "$gpu_line" | sed 's/.*: //' | sed 's/ (rev .*)$//' | cut -c1-64) - # Detect vendor and passthrough type if echo "$gpu_line" | grep -qi "Intel"; then GPU_VENDOR="intel" GPU_PASSTHROUGH="igpu" @@ -546,11 +667,7 @@ detect_gpu() { } # ------------------------------------------------------------------------------ -# detect_cpu() -# -# - Detects CPU vendor and model -# - Sets CPU_VENDOR (intel/amd/arm/unknown) and CPU_MODEL globals -# - Used for CPU analytics +# detect_cpu() - CPU vendor and model # ------------------------------------------------------------------------------ detect_cpu() { CPU_VENDOR="unknown" @@ -564,14 +681,12 @@ detect_cpu() { GenuineIntel) CPU_VENDOR="intel" ;; AuthenticAMD) CPU_VENDOR="amd" ;; *) - # ARM doesn't have vendor_id, check for CPU implementer if grep -qi "CPU implementer" /proc/cpuinfo 2>/dev/null; then CPU_VENDOR="arm" fi ;; esac - # Extract model name and clean it up CPU_MODEL=$(grep -m1 "model name" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^ *//' | sed 's/(R)//g' | sed 's/(TM)//g' | sed 's/ */ /g' | cut -c1-64 || true) fi @@ -579,22 +694,13 @@ detect_cpu() { } # ------------------------------------------------------------------------------ -# detect_ram() -# -# - Detects RAM speed using dmidecode -# - Sets RAM_SPEED global (e.g., "4800" for DDR5-4800) -# - Requires root access for dmidecode -# - Returns empty if not available or if speed is "Unknown" (nested VMs) +# detect_ram() - RAM speed via dmidecode (empty in nested VMs) # ------------------------------------------------------------------------------ detect_ram() { RAM_SPEED="" if command -v dmidecode &>/dev/null; then - # Get configured memory speed (actual running speed) - # Use || true to handle "Unknown" values in nested VMs (no numeric match) RAM_SPEED=$(dmidecode -t memory 2>/dev/null | grep -m1 "Configured Memory Speed:" | grep -oE "[0-9]+" | head -1) || true - - # Fallback to Speed: if Configured not available if [[ -z "$RAM_SPEED" ]]; then RAM_SPEED=$(dmidecode -t memory 2>/dev/null | grep -m1 "Speed:" | grep -oE "[0-9]+" | head -1) || true fi @@ -604,287 +710,265 @@ detect_ram() { } # ------------------------------------------------------------------------------ -# post_to_api() -# -# - Sends LXC container creation statistics to telemetry ingest service -# - Only executes if: -# * curl is available -# * DIAGNOSTICS=yes -# * RANDOM_UUID is set -# - Payload includes: -# * Container type, disk size, CPU cores, RAM -# * OS type and version -# * Application name (NSAPP) -# * Installation method -# * PVE version -# * Status: "installing" -# * Random UUID for session tracking -# - Anonymous telemetry (no personal data) -# - Never blocks or fails script execution +# detect_arm() - true when running on arm64 hardware # ------------------------------------------------------------------------------ -post_to_api() { - # Prevent duplicate submissions (post_to_api is called from multiple places) - [[ "${POST_TO_API_DONE:-}" == "true" ]] && return 0 +detect_arm() { + HAS_ARM="false" + case "$(dpkg --print-architecture 2>/dev/null || uname -m)" in + arm64 | aarch64) HAS_ARM="true" ;; + esac + export HAS_ARM +} - # Silent fail - telemetry should never break scripts - command -v curl &>/dev/null || { - [[ "${DEV_MODE:-}" == "true" ]] && echo "[DEBUG] curl not found, skipping" >&2 - return 0 - } - [[ "${DIAGNOSTICS:-no}" == "no" ]] && { - [[ "${DEV_MODE:-}" == "true" ]] && echo "[DEBUG] DIAGNOSTICS=no, skipping" >&2 - return 0 - } - [[ -z "${RANDOM_UUID:-}" ]] && { - [[ "${DEV_MODE:-}" == "true" ]] && echo "[DEBUG] RANDOM_UUID empty, skipping" >&2 - return 0 - } +# ------------------------------------------------------------------------------ +# telemetry_collect_sysinfo() +# +# - Collects ALL system metadata exactly once (cached via _TM_SYSINFO_DONE) +# - Sets: CPU_VENDOR, CPU_MODEL, GPU_VENDOR, GPU_MODEL, GPU_PASSTHROUGH, +# RAM_SPEED, HAS_ARM, TM_ARCH, TM_PVE_VERSION, TM_PLATFORM +# ------------------------------------------------------------------------------ +telemetry_collect_sysinfo() { + [[ "${_TM_SYSINFO_DONE:-}" == "true" ]] && return 0 - [[ "${DEV_MODE:-}" == "true" ]] && echo "[DEBUG] post_to_api() DIAGNOSTICS=$DIAGNOSTICS RANDOM_UUID=$RANDOM_UUID NSAPP=$NSAPP" >&2 + [[ -z "${GPU_VENDOR:-}" ]] && detect_gpu + [[ -z "${CPU_VENDOR:-}" ]] && detect_cpu + [[ -z "${RAM_SPEED+x}" ]] && detect_ram + [[ -z "${HAS_ARM:-}" ]] && detect_arm - # Set type for later status updates (preserve if already set, e.g. turnkey) - TELEMETRY_TYPE="${TELEMETRY_TYPE:-lxc}" + TM_ARCH="$(dpkg --print-architecture 2>/dev/null || uname -m || echo unknown)" - local pve_version="" + # Virtualization platform: pve (Proxmox VE) or incus. + # Containers inherit TELEMETRY_PLATFORM from the host environment. + TM_PLATFORM="${TELEMETRY_PLATFORM:-}" + TM_PVE_VERSION="" if command -v pveversion &>/dev/null; then - pve_version=$(pveversion 2>/dev/null | awk -F'[/ ]' '{print $2}') || true + TM_PVE_VERSION=$(pveversion 2>/dev/null | awk -F'[/ ]' '{print $2}') || true + TM_PLATFORM="${TM_PLATFORM:-pve}" + elif command -v incus &>/dev/null; then + TM_PVE_VERSION="incus-$(incus version 2>/dev/null | head -1 | awk '{print $NF}')" || true + TM_PLATFORM="${TM_PLATFORM:-incus}" fi - # Detect GPU if not already set - if [[ -z "${GPU_VENDOR:-}" ]]; then - detect_gpu + _TM_SYSINFO_DONE=true + export TM_ARCH TM_PVE_VERSION TM_PLATFORM _TM_SYSINFO_DONE +} + +# ============================================================================== +# SECTION 5: PAYLOAD BUILDER & SENDER +# ============================================================================== + +# ------------------------------------------------------------------------------ +# _tm_enabled() +# +# - Central gate: curl present, DIAGNOSTICS=yes, RANDOM_UUID set +# ------------------------------------------------------------------------------ +_tm_enabled() { + command -v curl &>/dev/null || return 1 + [[ "${DIAGNOSTICS:-no}" == "no" ]] && return 1 + [[ -z "${RANDOM_UUID:-}" ]] && return 1 + return 0 +} + +# ------------------------------------------------------------------------------ +# _tm_payload() +# +# - Builds the COMPLETE JSON payload. Every send (installing, progress ping, +# final status) carries the full metadata so no record is ever empty, +# regardless of which event the server persists. +# - Arguments: +# * $1: status +# * $2: exit_code (optional, default 0) +# * $3: error text (optional, raw - will be JSON-escaped here) +# ------------------------------------------------------------------------------ +_tm_payload() { + local status="$1" + local exit_code="${2:-0}" + local error_raw="${3:-}" + + telemetry_collect_sysinfo + + # Numeric sanitation (server rejects out-of-range values) + [[ ! "$exit_code" =~ ^[0-9]+$ ]] && exit_code=1 + ((exit_code > 255)) && exit_code=255 + + local disk_size="${DISK_SIZE:-0}" + disk_size="${disk_size%G}" + [[ ! "$disk_size" =~ ^[0-9]+$ ]] && disk_size=0 + + local duration=0 + if [[ -n "${INSTALL_START_TIME:-}" ]]; then + duration=$(($(date +%s) - INSTALL_START_TIME)) + ((duration < 0)) && duration=0 + ((duration > 86400)) && duration=86400 fi - local gpu_vendor="${GPU_VENDOR:-unknown}" - local gpu_model + + local error_json="" error_category="" + if [[ -n "$error_raw" ]]; then + error_json=$(json_escape "$error_raw") + error_category=$(categorize_error "$exit_code") + fi + + local gpu_model cpu_model gpu_model=$(json_escape "${GPU_MODEL:-}") - local gpu_passthrough="${GPU_PASSTHROUGH:-unknown}" - - # Detect CPU if not already set - if [[ -z "${CPU_VENDOR:-}" ]]; then - detect_cpu - fi - local cpu_vendor="${CPU_VENDOR:-unknown}" - local cpu_model cpu_model=$(json_escape "${CPU_MODEL:-}") - # Detect RAM if not already set - if [[ -z "${RAM_SPEED:-}" ]]; then - detect_ram - fi - local ram_speed="${RAM_SPEED:-}" - - local JSON_PAYLOAD - JSON_PAYLOAD=$( - cat <&2 - [[ "${DEV_MODE:-}" == "true" ]] && echo "[DEBUG] Payload: $JSON_PAYLOAD" >&2 +# ------------------------------------------------------------------------------ +# _tm_send() +# +# - Single curl wrapper for all telemetry sends +# - Arguments: +# * $1: JSON payload +# * $2: timeout seconds (default TELEMETRY_TIMEOUT) +# * $3: attempts (default 1) +# - Returns 0 on HTTP 2xx, 1 otherwise. Never raises errors. +# ------------------------------------------------------------------------------ +_tm_send() { + local payload="$1" + local timeout="${2:-$TELEMETRY_TIMEOUT}" + local attempts="${3:-1}" + local http_code attempt - # Send initial "installing" record with retry. - # This record MUST exist for all subsequent updates to succeed. - local http_code="" attempt - local _post_success=false - for attempt in 1 2 3; do + for ((attempt = 1; attempt <= attempts; attempt++)); do if [[ "${DEV_MODE:-}" == "true" ]]; then - http_code=$(curl -sS -w "%{http_code}" -m "${TELEMETRY_TIMEOUT}" -X POST "${TELEMETRY_URL}" \ - -H "Content-Type: application/json" \ - -d "$JSON_PAYLOAD" -o /dev/stderr 2>&1) || http_code="000" - echo "[DEBUG] post_to_api attempt $attempt HTTP=$http_code" >&2 - else - http_code=$(curl -sS -w "%{http_code}" -m "${TELEMETRY_TIMEOUT}" -X POST "${TELEMETRY_URL}" \ - -H "Content-Type: application/json" \ - -d "$JSON_PAYLOAD" -o /dev/null 2>/dev/null) || http_code="000" + echo "[DEBUG] telemetry POST (attempt ${attempt}/${attempts}): $payload" >&2 fi + http_code=$(curl -sS -w "%{http_code}" -m "$timeout" -X POST "${TELEMETRY_URL}" \ + -H "Content-Type: application/json" \ + -d "$payload" -o /dev/null 2>/dev/null) || http_code="000" + [[ "${DEV_MODE:-}" == "true" ]] && echo "[DEBUG] telemetry HTTP=${http_code}" >&2 if [[ "$http_code" =~ ^2[0-9]{2}$ ]]; then - _post_success=true - break + return 0 fi - [[ "$attempt" -lt 3 ]] && sleep 1 + ((attempt < attempts)) && sleep 1 done + return 1 +} - # Only mark done if at least one attempt succeeded. - # If all 3 failed, POST_TO_API_DONE stays false so post_update_to_api - # and on_exit() know the initial record was never created. - # The server has fallback logic to create a new record on status updates, - # so subsequent calls can still succeed even without the initial record. - POST_TO_API_DONE=${_post_success} +# ============================================================================== +# SECTION 6: PUBLIC TELEMETRY API +# ============================================================================== + +# ------------------------------------------------------------------------------ +# post_to_api() +# +# - Sends the initial "installing" record for LXC container creation +# - Full metadata payload; retried up to 3x +# - Idempotent per execution (POST_TO_API_DONE) +# ------------------------------------------------------------------------------ +post_to_api() { + [[ "${POST_TO_API_DONE:-}" == "true" ]] && return 0 + _tm_enabled || return 0 + + TELEMETRY_TYPE="${TELEMETRY_TYPE:-lxc}" + + local payload + payload=$(_tm_payload "installing") + + if _tm_send "$payload" "$TELEMETRY_TIMEOUT" 3; then + POST_TO_API_DONE=true + else + POST_TO_API_DONE=false + fi } # ------------------------------------------------------------------------------ # post_to_api_vm() # -# - Sends VM creation statistics to telemetry ingest service -# - Reads DIAGNOSTICS from /usr/local/community-scripts/diagnostics file -# - Payload differences from LXC: -# * ct_type=2 (VM instead of LXC) -# * type="vm" -# * Disk size without 'G' suffix -# - Includes hardware detection: CPU, GPU, RAM speed -# - Only executes if DIAGNOSTICS=yes and RANDOM_UUID is set -# - Never blocks or fails script execution +# - Sends the initial "installing" record for VM creation +# - Reads DIAGNOSTICS from /usr/local/community-scripts/diagnostics # ------------------------------------------------------------------------------ post_to_api_vm() { - # Read diagnostics setting from file + [[ "${POST_TO_API_DONE:-}" == "true" ]] && return 0 + if [[ -f /usr/local/community-scripts/diagnostics ]]; then DIAGNOSTICS=$(grep -i "^DIAGNOSTICS=" /usr/local/community-scripts/diagnostics 2>/dev/null | awk -F'=' '{print $2}') || true fi - # Silent fail - telemetry should never break scripts - command -v curl &>/dev/null || return 0 - [[ "${DIAGNOSTICS:-no}" == "no" ]] && return 0 - [[ -z "${RANDOM_UUID:-}" ]] && return 0 + _tm_enabled || return 0 - # Set type for later status updates TELEMETRY_TYPE="vm" + CT_TYPE=2 - local pve_version="" - if command -v pveversion &>/dev/null; then - pve_version=$(pveversion 2>/dev/null | awk -F'[/ ]' '{print $2}') || true + local payload + payload=$(_tm_payload "installing") + + if _tm_send "$payload" "$TELEMETRY_TIMEOUT" 3; then + POST_TO_API_DONE=true + else + POST_TO_API_DONE=false fi - - # Detect GPU if not already set - if [[ -z "${GPU_VENDOR:-}" ]]; then - detect_gpu - fi - local gpu_vendor="${GPU_VENDOR:-unknown}" - local gpu_model - gpu_model=$(json_escape "${GPU_MODEL:-}") - local gpu_passthrough="${GPU_PASSTHROUGH:-unknown}" - - # Detect CPU if not already set - if [[ -z "${CPU_VENDOR:-}" ]]; then - detect_cpu - fi - local cpu_vendor="${CPU_VENDOR:-unknown}" - local cpu_model - cpu_model=$(json_escape "${CPU_MODEL:-}") - - # Detect RAM if not already set - if [[ -z "${RAM_SPEED:-}" ]]; then - detect_ram - fi - local ram_speed="${RAM_SPEED:-}" - - # Remove 'G' suffix from disk size - local DISK_SIZE_API="${DISK_SIZE%G}" - - local JSON_PAYLOAD - JSON_PAYLOAD=$( - cat </dev/null) || http_code="000" - if [[ "$http_code" =~ ^2[0-9]{2}$ ]]; then - _post_success=true - break - fi - [[ "$attempt" -lt 3 ]] && sleep 1 - done - - POST_TO_API_DONE=${_post_success} } # ------------------------------------------------------------------------------ # post_progress_to_api() # -# - Lightweight progress ping from host or container -# - Updates the existing telemetry record status -# - Arguments: -# * $1: status (optional, default: "configuring") -# Valid values: "validation", "configuring" -# - Signals that the installation is actively progressing (not stuck) -# - Fire-and-forget: never blocks or fails the script -# - Only executes if DIAGNOSTICS=yes and RANDOM_UUID is set -# - Can be called multiple times safely +# - Progress ping ("validation" / "configuring") +# - Sends the FULL payload (not a minimal one) so that even if the server +# ever has to fall back to a progress row, it carries all metadata +# - Fire-and-forget, single attempt # ------------------------------------------------------------------------------ post_progress_to_api() { - command -v curl &>/dev/null || return 0 - [[ "${DIAGNOSTICS:-no}" == "no" ]] && return 0 - [[ -z "${RANDOM_UUID:-}" ]] && return 0 + _tm_enabled || return 0 local progress_status="${1:-configuring}" - local app_name="${NSAPP:-${app:-unknown}}" - local telemetry_type="${TELEMETRY_TYPE:-lxc}" - - curl -fsS -m 5 -X POST "${TELEMETRY_URL:-https://telemetry.community-scripts.org/telemetry}" \ - -H "Content-Type: application/json" \ - -d "{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"${telemetry_type}\",\"nsapp\":\"${app_name}\",\"status\":\"${progress_status}\"}" &>/dev/null || true + local payload + payload=$(_tm_payload "$progress_status") + _tm_send "$payload" "$TELEMETRY_TIMEOUT" 1 || true } # ------------------------------------------------------------------------------ # post_update_to_api() # -# - Reports installation completion status to telemetry ingest service -# - Prevents duplicate submissions via POST_UPDATE_DONE flag +# - Reports the FINAL installation status. This is the single most important +# telemetry event - it must carry full metadata AND the focused error trace. # - Arguments: -# * $1: status ("done" or "failed") -# * $2: exit_code (numeric, default: 1 for failed, 0 for done) -# - Payload includes: -# * Final status (mapped: "done"→"success", "failed"→"failed") -# * Error description via explain_exit_code() -# * Numeric exit code -# - Only executes once per session -# - Never blocks or fails script execution +# * $1: status ("done"/"success" | "failed" | "aborted") +# * $2: exit_code (numeric; "none" → 0) +# * $3: "force" to bypass the duplicate guard (new information available) +# - Signal exit codes (129/130/143) are reported as "aborted", not "failed" +# - Idempotent via POST_UPDATE_DONE # ------------------------------------------------------------------------------ post_update_to_api() { - # Silent fail - telemetry should never break scripts command -v curl &>/dev/null || return 0 - # Support "force" mode (3rd arg) to bypass duplicate check for retries after cleanup + local status="${1:-failed}" + local raw_exit_code="${2:-1}" local force="${3:-}" + POST_UPDATE_DONE=${POST_UPDATE_DONE:-false} if [[ "$POST_UPDATE_DONE" == "true" && "$force" != "force" ]]; then return 0 @@ -893,326 +977,114 @@ post_update_to_api() { [[ "${DIAGNOSTICS:-no}" == "no" ]] && return 0 [[ -z "${RANDOM_UUID:-}" ]] && return 0 - local status="${1:-failed}" - local raw_exit_code="${2:-1}" - local exit_code=0 error="" pb_status error_category="" + local exit_code=0 + if [[ "$raw_exit_code" =~ ^[0-9]+$ ]]; then + exit_code="$raw_exit_code" + elif [[ "$raw_exit_code" == "none" ]]; then + exit_code=0 + else + exit_code=1 + fi - # Get GPU info (if detected) - local gpu_vendor="${GPU_VENDOR:-unknown}" - local gpu_model - gpu_model=$(json_escape "${GPU_MODEL:-}") - local gpu_passthrough="${GPU_PASSTHROUGH:-unknown}" - - # Get CPU info (if detected) - local cpu_vendor="${CPU_VENDOR:-unknown}" - local cpu_model - cpu_model=$(json_escape "${CPU_MODEL:-}") - - # Get RAM info (if detected) - local ram_speed="${RAM_SPEED:-}" - - # Map status to telemetry values: installing, success, failed, unknown + local pb_status error_raw="" case "$status" in done | success) pb_status="success" exit_code=0 - error="" - error_category="" + ;; + aborted) + pb_status="aborted" ;; failed) - pb_status="failed" + # Signal-based exits are user aborts, not installation failures + case "$exit_code" in + 129 | 130 | 143) pb_status="aborted" ;; + *) pb_status="failed" ;; + esac ;; *) pb_status="unknown" ;; esac - # For failed/unknown status, resolve exit code and error description - local short_error="" medium_error="" - if [[ "$pb_status" == "failed" ]] || [[ "$pb_status" == "unknown" ]]; then - if [[ "$raw_exit_code" =~ ^[0-9]+$ ]]; then - exit_code="$raw_exit_code" - else - exit_code=1 - fi - # Get full installation log for error field - local log_text="" - log_text=$(get_full_log 122880) || true # 120KB max - if [[ -z "$log_text" ]]; then - # Fallback to last 20 lines - log_text=$(get_error_text) - fi - local full_error - full_error=$(build_error_string "$exit_code" "$log_text") - error=$(json_escape "$full_error") - short_error=$(json_escape "$(explain_exit_code "$exit_code")") - error_category=$(categorize_error "$exit_code") - [[ -z "$error" ]] && error="Unknown error" - - # Build medium error for attempt 2: explanation + last 100 log lines (≤16KB) - # This is the critical middle ground between full 120KB log and generic-only description - local medium_log="" - medium_log=$(get_full_log 16384) || true # 16KB max - if [[ -z "$medium_log" ]]; then - medium_log=$(get_error_text) || true - fi - local medium_full - medium_full=$(build_error_string "$exit_code" "$medium_log") - medium_error=$(json_escape "$medium_full") - [[ -z "$medium_error" ]] && medium_error="$short_error" + if [[ "$pb_status" == "failed" || "$pb_status" == "unknown" ]]; then + error_raw=$(build_error_string "$exit_code") + elif [[ "$pb_status" == "aborted" ]]; then + # Short context line only - no log dump for user aborts + error_raw="exit_code=${exit_code} | $(explain_exit_code "$exit_code")" + ERROR_CATEGORY_OVERRIDE="${ERROR_CATEGORY_OVERRIDE:-user_aborted}" fi - # Calculate duration if timer was started - local duration=0 - if [[ -n "${INSTALL_START_TIME:-}" ]]; then - duration=$(($(date +%s) - INSTALL_START_TIME)) - fi + local payload + payload=$(_tm_payload "$pb_status" "$exit_code" "$error_raw") - # Get PVE version - local pve_version="" - if command -v pveversion &>/dev/null; then - pve_version=$(pveversion 2>/dev/null | awk -F'[/ ]' '{print $2}') || true - fi - - local http_code="" - - # Strip 'G' suffix from disk size (VMs set DISK_SIZE=32G) - local DISK_SIZE_API="${DISK_SIZE:-0}" - DISK_SIZE_API="${DISK_SIZE_API%G}" - [[ ! "$DISK_SIZE_API" =~ ^[0-9]+$ ]] && DISK_SIZE_API=0 - - # ── Attempt 1: Full payload with complete error text (includes full log) ── - local JSON_PAYLOAD - JSON_PAYLOAD=$( - cat </dev/null) || http_code="000" - - if [[ "$http_code" =~ ^2[0-9]{2}$ ]]; then + if _tm_send "$payload" "$STATUS_TIMEOUT" 2; then POST_UPDATE_DONE=true return 0 fi - # ── Attempt 2: Medium error text (truncated log ≤16KB instead of full 120KB) ── - sleep 1 - local RETRY_PAYLOAD - RETRY_PAYLOAD=$( - cat </dev/null) || http_code="000" - - if [[ "$http_code" =~ ^2[0-9]{2}$ ]]; then - POST_UPDATE_DONE=true - return 0 + # Retry with a smaller error trace (in case the payload was the problem) + if [[ -n "$error_raw" ]]; then + local short_error + short_error="exit_code=${exit_code} | $(explain_exit_code "$exit_code")" + [[ -n "${FAILED_COMMAND:-}" ]] && short_error+=" | at line ${FAILED_LINE:-?}: $(printf '%s' "$FAILED_COMMAND" | head -c 200)" + payload=$(_tm_payload "$pb_status" "$exit_code" "$short_error") + if _tm_send "$payload" "$STATUS_TIMEOUT" 2; then + POST_UPDATE_DONE=true + return 0 + fi fi - # ── Attempt 3: Minimal payload with medium error (bare minimum to set status) ── - sleep 2 - local MINIMAL_PAYLOAD - MINIMAL_PAYLOAD=$( - cat </dev/null) || http_code="000" - - if [[ "$http_code" =~ ^2[0-9]{2}$ ]]; then - POST_UPDATE_DONE=true - return 0 - fi - - # All 3 attempts failed — do NOT set POST_UPDATE_DONE=true. - # This allows the EXIT trap (on_exit in error_handler.func) to retry. - # No infinite loop risk: EXIT trap fires exactly once. +# ------------------------------------------------------------------------------ +# telemetry_new_attempt() +# +# - Resets telemetry state for a RETRY of the same session (recovery menu: +# rebuild, OOM retry, DNS retry, APT repair). Each attempt becomes its own +# execution on the server (the previous one keeps its terminal status). +# ------------------------------------------------------------------------------ +telemetry_new_attempt() { + EXECUTION_ID="$(cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "${RANDOM_UUID}-r$RANDOM")" + POST_TO_API_DONE=false + POST_UPDATE_DONE=false + unset FAILED_COMMAND FAILED_LINE ERROR_CATEGORY_OVERRIDE TELEMETRY_ERRINFO + export EXECUTION_ID } # ============================================================================== -# SECTION 3: EXTENDED TELEMETRY FUNCTIONS +# SECTION 7: TIMERS # ============================================================================== -# ------------------------------------------------------------------------------ -# categorize_error() -# -# - Maps exit codes to error categories for better analytics -# - Categories: network, storage, dependency, permission, timeout, config, resource, unknown -# - Used to group errors in dashboard -# ------------------------------------------------------------------------------ -categorize_error() { - # Allow build.func to override category based on log analysis (exit code 1 subclassification) - if [[ -n "${ERROR_CATEGORY_OVERRIDE:-}" ]]; then - echo "$ERROR_CATEGORY_OVERRIDE" - return - fi - - local code="$1" - case "$code" in - # Network errors (curl/wget) - 6 | 7 | 22 | 35) echo "network" ;; - - # Docker / Privileged mode required - 10) echo "config" ;; - - # Timeout errors - 28 | 124 | 211) echo "timeout" ;; - - # Storage errors (Proxmox storage) - 214 | 217 | 219 | 224) echo "storage" ;; - - # Dependency/Package errors (APT, DPKG, pip, commands) - 100 | 101 | 102 | 127 | 160 | 161 | 162 | 255) echo "dependency" ;; - - # Permission errors - 126 | 152) echo "permission" ;; - - # Configuration errors (Proxmox config, invalid args) - 128 | 203 | 204 | 205 | 206 | 207 | 208) echo "config" ;; - - # Proxmox container/template errors - 200 | 209 | 210 | 212 | 213 | 215 | 216 | 218 | 220 | 221 | 222 | 223 | 225 | 231) echo "proxmox" ;; - - # Service/Systemd errors - 150 | 151 | 153 | 154) echo "service" ;; - - # Database errors (PostgreSQL, MySQL, MongoDB) - 170 | 171 | 172 | 173 | 180 | 181 | 182 | 183 | 190 | 191 | 192 | 193) echo "database" ;; - - # Node.js / JavaScript runtime errors - 243 | 245 | 246 | 247 | 248 | 249) echo "runtime" ;; - - # Python environment errors - # (already covered: 160-162 under dependency) - - # Aborted by user (SIGHUP=terminal closed, SIGINT=Ctrl+C, SIGTERM=killed) - 129 | 130 | 143) echo "user_aborted" ;; - - # Resource errors (OOM, SIGKILL, SIGABRT) - 134 | 137) echo "resource" ;; - - # Signal/Process errors (SIGPIPE, SIGSEGV) - 139 | 141) echo "signal" ;; - - # Shell errors (general error, syntax error) - 1 | 2) echo "shell" ;; - - # Default - truly unknown - *) echo "unknown" ;; - esac -} - -# ------------------------------------------------------------------------------ -# start_install_timer() -# -# - Captures start time for installation duration tracking -# - Call at the beginning of installation -# - Sets INSTALL_START_TIME global variable -# ------------------------------------------------------------------------------ start_install_timer() { INSTALL_START_TIME=$(date +%s) export INSTALL_START_TIME } -# ------------------------------------------------------------------------------ -# get_install_duration() -# -# - Returns elapsed seconds since start_install_timer() was called -# - Returns 0 if timer was not started -# ------------------------------------------------------------------------------ get_install_duration() { if [[ -z "${INSTALL_START_TIME:-}" ]]; then echo "0" return fi - local now=$(date +%s) + local now + now=$(date +%s) echo $((now - INSTALL_START_TIME)) } +# ============================================================================== +# SECTION 8: TOOLS & ADDON TELEMETRY +# ============================================================================== + # ------------------------------------------------------------------------------ -# _telemetry_report_exit() -# -# - Internal handler called by EXIT trap set in init_tool_telemetry() -# - Determines success/failure from exit code and reports via appropriate API -# - Arguments: -# * $1: exit_code from the script +# _telemetry_report_exit() - EXIT trap handler set by init_tool_telemetry() # ------------------------------------------------------------------------------ _telemetry_report_exit() { local ec="${1:-0}" local status="success" [[ "$ec" -ne 0 ]] && status="failed" - # Lazy name resolution: use explicit name, fall back to $APP, then "unknown" local name="${TELEMETRY_TOOL_NAME:-${APP:-unknown}}" if [[ "${TELEMETRY_TOOL_TYPE:-pve}" == "addon" ]]; then @@ -1226,17 +1098,9 @@ _telemetry_report_exit() { # init_tool_telemetry() # # - One-line telemetry setup for tools/addon scripts -# - Reads DIAGNOSTICS from /usr/local/community-scripts/diagnostics -# (persisted on PVE host during first build, and inside containers by install.func) -# - Starts install timer for duration tracking -# - Sets EXIT trap to automatically report success/failure on script exit # - Arguments: # * $1: tool_name (optional, falls back to $APP at exit time) # * $2: type ("pve" for PVE host scripts, "addon" for container addons) -# - Usage: -# source <(curl -fsSL .../misc/api.func) 2>/dev/null || true -# init_tool_telemetry "post-pve-install" "pve" -# init_tool_telemetry "" "addon" # uses $APP at exit time # ------------------------------------------------------------------------------ init_tool_telemetry() { local name="${1:-}" @@ -1245,26 +1109,17 @@ init_tool_telemetry() { [[ -n "$name" ]] && TELEMETRY_TOOL_NAME="$name" TELEMETRY_TOOL_TYPE="$type" - # Read diagnostics opt-in/opt-out if [[ -f /usr/local/community-scripts/diagnostics ]]; then DIAGNOSTICS=$(grep -i "^DIAGNOSTICS=" /usr/local/community-scripts/diagnostics 2>/dev/null | awk -F'=' '{print $2}') || true fi start_install_timer - # EXIT trap: automatically report telemetry when script ends trap '_telemetry_report_exit "$?"' EXIT } # ------------------------------------------------------------------------------ -# post_tool_to_api() -# -# - Reports tool usage to telemetry -# - Arguments: -# * $1: tool_name (e.g., "microcode", "lxc-update", "post-pve-install") -# * $2: status ("success" or "failed") -# * $3: exit_code (optional, default: 0 for success, 1 for failed) -# - For PVE host tools, not container installations +# post_tool_to_api() - PVE host tool usage report # ------------------------------------------------------------------------------ post_tool_to_api() { command -v curl &>/dev/null || return 0 @@ -1276,34 +1131,25 @@ post_tool_to_api() { local error="" error_category="" local uuid duration - # Generate UUID for this tool execution uuid=$(cat /proc/sys/kernel/random/uuid 2>/dev/null || uuidgen 2>/dev/null || echo "tool-$(date +%s)") duration=$(get_install_duration) - # Map status [[ "$status" == "done" ]] && status="success" if [[ "$status" == "failed" ]]; then [[ ! "$exit_code" =~ ^[0-9]+$ ]] && exit_code=1 - local error_text="" - error_text=$(get_error_text) - local full_error - full_error=$(build_error_string "$exit_code" "$error_text") - error=$(json_escape "$full_error") + error=$(json_escape "$(build_error_string "$exit_code")") error_category=$(categorize_error "$exit_code") fi - local pve_version="" - if command -v pveversion &>/dev/null; then - pve_version=$(pveversion 2>/dev/null | awk -F'[/ ]' '{print $2}') || true - fi + telemetry_collect_sysinfo local JSON_PAYLOAD JSON_PAYLOAD=$( cat </dev/null || true + _tm_send "$JSON_PAYLOAD" "$TELEMETRY_TIMEOUT" 1 || true } # ------------------------------------------------------------------------------ -# post_addon_to_api() -# -# - Reports addon installation to telemetry -# - Arguments: -# * $1: addon_name (e.g., "filebrowser", "netdata") -# * $2: status ("success" or "failed") -# * $3: exit_code (optional) -# - For addons installed inside containers +# post_addon_to_api() - Addon installation report (runs inside containers) # ------------------------------------------------------------------------------ post_addon_to_api() { command -v curl &>/dev/null || return 0 @@ -1342,24 +1181,17 @@ post_addon_to_api() { local error="" error_category="" local uuid duration - # Generate UUID for this addon installation uuid=$(cat /proc/sys/kernel/random/uuid 2>/dev/null || uuidgen 2>/dev/null || echo "addon-$(date +%s)") duration=$(get_install_duration) - # Map status [[ "$status" == "done" ]] && status="success" if [[ "$status" == "failed" ]]; then [[ ! "$exit_code" =~ ^[0-9]+$ ]] && exit_code=1 - local error_text="" - error_text=$(get_error_text) - local full_error - full_error=$(build_error_string "$exit_code" "$error_text") - error=$(json_escape "$full_error") + error=$(json_escape "$(build_error_string "$exit_code")") error_category=$(categorize_error "$exit_code") fi - # Detect OS info local os_type="" os_version="" if [[ -f /etc/os-release ]]; then os_type=$(grep "^ID=" /etc/os-release | cut -d= -f2 | tr -d '"' || true) @@ -1371,7 +1203,7 @@ post_addon_to_api() { cat </dev/null || true -} - -# ------------------------------------------------------------------------------ -# post_update_to_api_extended() -# -# - Extended version of post_update_to_api with duration, GPU, and error category -# - Same arguments as post_update_to_api: -# * $1: status ("done" or "failed") -# * $2: exit_code (numeric) -# - Automatically includes: -# * Install duration (if start_install_timer was called) -# * Error category (for failed status) -# * GPU info (if detect_gpu was called) -# ------------------------------------------------------------------------------ -post_update_to_api_extended() { - # Silent fail - telemetry should never break scripts - command -v curl &>/dev/null || return 0 - - # Prevent duplicate submissions - POST_UPDATE_DONE=${POST_UPDATE_DONE:-false} - [[ "$POST_UPDATE_DONE" == "true" ]] && return 0 - - [[ "${DIAGNOSTICS:-no}" == "no" ]] && return 0 - [[ -z "${RANDOM_UUID:-}" ]] && return 0 - - local status="${1:-failed}" - local raw_exit_code="${2:-1}" - local exit_code=0 error="" pb_status error_category="" - local duration gpu_vendor gpu_passthrough - - # Get duration - duration=$(get_install_duration) - - # Get GPU info (if detected) - gpu_vendor="${GPU_VENDOR:-}" - gpu_passthrough="${GPU_PASSTHROUGH:-}" - - # Map status to telemetry values - case "$status" in - done | success) - pb_status="success" - exit_code=0 - error="" - error_category="" - ;; - failed) - pb_status="failed" - ;; - *) - pb_status="unknown" - ;; - esac - - # For failed/unknown status, resolve exit code and error description - if [[ "$pb_status" == "failed" ]] || [[ "$pb_status" == "unknown" ]]; then - if [[ "$raw_exit_code" =~ ^[0-9]+$ ]]; then - exit_code="$raw_exit_code" - else - exit_code=1 - fi - local error_text="" - error_text=$(get_error_text) - local full_error - full_error=$(build_error_string "$exit_code" "$error_text") - error=$(json_escape "$full_error") - error_category=$(categorize_error "$exit_code") - [[ -z "$error" ]] && error="Unknown error" - fi - - local JSON_PAYLOAD - JSON_PAYLOAD=$( - cat </dev/null) || http_code="000" - - if [[ "$http_code" =~ ^2[0-9]{2}$ ]]; then - POST_UPDATE_DONE=true - return 0 - fi - - # Retry with minimal payload - sleep 1 - http_code=$(curl -sS -w "%{http_code}" -m "${STATUS_TIMEOUT}" -X POST "${TELEMETRY_URL}" \ - -H "Content-Type: application/json" \ - -d "{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"${TELEMETRY_TYPE:-lxc}\",\"nsapp\":\"${NSAPP:-unknown}\",\"status\":\"${pb_status}\",\"exit_code\":${exit_code},\"install_duration\":${duration:-0}}" \ - -o /dev/null 2>/dev/null) || http_code="000" - - if [[ "$http_code" =~ ^2[0-9]{2}$ ]]; then - POST_UPDATE_DONE=true - return 0 - fi - - # Do NOT set POST_UPDATE_DONE=true — let EXIT trap retry + _tm_send "$JSON_PAYLOAD" "$TELEMETRY_TIMEOUT" 1 || true } diff --git a/misc/build.func b/misc/build.func index ca33a36f8..0a8319cbd 100644 --- a/misc/build.func +++ b/misc/build.func @@ -4072,6 +4072,11 @@ build_container() { export RANDOM_UUID="$RANDOM_UUID" export EXECUTION_ID="$EXECUTION_ID" export SESSION_ID="$SESSION_ID" + # Repo attribution + platform for container-side progress pings (the + # container inherits the host's detection instead of re-detecting) + export REPO_SOURCE="${REPO_SOURCE:-}" + export REPO_SLUG="${REPO_SLUG:-}" + export TELEMETRY_PLATFORM="pve" export CACHER="$APT_CACHER" export CACHER_IP="$APT_CACHER_IP" if [[ -n "${HTTP_PROXY:-}" ]]; then @@ -4895,6 +4900,16 @@ EOF # Point INSTALL_LOG to combined log so get_full_log() finds it INSTALL_LOG="$combined_log" fi + + # Pull the structured error capture (.errinfo) from the container. + # It contains EXACTLY the output of the command that failed (written by + # silent()/error_handler inside the container) and is the primary source + # for the telemetry error trace - instead of a generic log tail. + local host_errinfo="/tmp/.errinfo-${SESSION_ID}" + if timeout 8 pct pull "$CTID" "/root/.install-${SESSION_ID}.log.errinfo" "$host_errinfo" 2>/dev/null && [[ -s "$host_errinfo" ]]; then + TELEMETRY_ERRINFO="$host_errinfo" + export TELEMETRY_ERRINFO + fi fi # Defense-in-depth: Ensure error handling stays disabled during recovery. @@ -5170,6 +5185,8 @@ EOF echo -e " Verbose: ${GN}enabled${CL}" echo "" msg_info "Restarting installation..." + # New telemetry execution for the retry (previous one keeps its "failed") + declare -f telemetry_new_attempt &>/dev/null && telemetry_new_attempt # Re-run build_container build_container return $? @@ -5209,6 +5226,10 @@ EOF echo "" msg_info "Re-running installation script..." + # New telemetry execution for the in-place retry + declare -f telemetry_new_attempt &>/dev/null && telemetry_new_attempt + declare -f post_to_api &>/dev/null && post_to_api 2>/dev/null || true + # Re-run install script in existing container (don't destroy/recreate) set +Eeuo pipefail trap - ERR @@ -5272,6 +5293,7 @@ EOF echo -e " Verbose: ${GN}enabled${CL}" echo "" msg_info "Restarting installation..." + declare -f telemetry_new_attempt &>/dev/null && telemetry_new_attempt build_container return $? fi @@ -5301,6 +5323,7 @@ EOF echo -e " Verbose: ${GN}enabled${CL}" echo "" msg_info "Restarting installation..." + declare -f telemetry_new_attempt &>/dev/null && telemetry_new_attempt build_container return $? fi @@ -5325,6 +5348,7 @@ EOF echo -e " Verbose: ${GN}enabled${CL}" echo "" msg_info "Restarting installation..." + declare -f telemetry_new_attempt &>/dev/null && telemetry_new_attempt build_container return $? fi @@ -6999,6 +7023,16 @@ ensure_log_on_host() { rm -f "$temp_log" fi fi + # Also pull the structured error capture (.errinfo) so the telemetry error + # trace shows the failing command's exact output (signal-exit paths reach + # this via on_exit before/instead of the recovery flow) + if [[ -z "${TELEMETRY_ERRINFO:-}" || ! -s "${TELEMETRY_ERRINFO:-}" ]]; then + local host_errinfo="/tmp/.errinfo-${SESSION_ID}" + if timeout 8 pct pull "$CTID" "/root/.install-${SESSION_ID}.log.errinfo" "$host_errinfo" 2>/dev/null && [[ -s "$host_errinfo" ]]; then + TELEMETRY_ERRINFO="$host_errinfo" + export TELEMETRY_ERRINFO + fi + fi if [[ -s "$combined_log" ]]; then INSTALL_LOG="$combined_log" fi diff --git a/misc/core.func b/misc/core.func index adf5a68d9..383938e42 100644 --- a/misc/core.func +++ b/misc/core.func @@ -546,6 +546,12 @@ silent() { set +Eeuo pipefail trap - ERR + # Byte offset BEFORE the command runs - everything the log grows by is + # exactly this command's output (used for the .errinfo telemetry capture) + local start_bytes=0 + [[ -f "$logfile" ]] && start_bytes=$(stat -c%s "$logfile" 2>/dev/null || echo 0) + [[ ! "$start_bytes" =~ ^[0-9]+$ ]] && start_bytes=0 + "$@" >>"$logfile" 2>&1 local rc=$? @@ -567,12 +573,43 @@ silent() { export _SILENT_FAILED_LINE="$caller_line" export _SILENT_FAILED_LOG="$logfile" + # ── Structured error capture (.errinfo) for telemetry ── + # Extract exactly THIS command's output (from the recorded byte offset), + # strip ANSI/progress noise, keep the last 60 lines. The host builds the + # telemetry error trace from this file (pulled from the container on + # failure). Self-contained - containers don't source api.func. + { + local flat_cmd + flat_cmd=$(printf '%s' "$cmd" | tr '\n' ' ' | head -c 300) + echo "EXIT_CODE=${rc}" + echo "LINE=${caller_line}" + echo "COMMAND=${flat_cmd}" + echo "--- OUTPUT ---" + if [[ -s "$logfile" ]]; then + local segment + segment=$(tail -c +"$((start_bytes + 1))" "$logfile" 2>/dev/null | + sed 's/\r$//' | + sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' | + grep -avE '^(Get:|Hit:|Ign:|Fetched |Reading package lists|Reading state information|Building dependency tree|Selecting previously|Preparing to unpack|Unpacking |Processing triggers for|\(Reading database|[0-9]+%[[:space:]]*\[)' | + grep -avE '^[[:space:]]*$' | + tail -n 60) + # If the noise filter swallowed everything, fall back to the raw tail + if [[ -z "$segment" ]]; then + segment=$(tail -c +"$((start_bytes + 1))" "$logfile" 2>/dev/null | + sed 's/\r$//' | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' | tail -n 60) + fi + printf '%s' "$segment" | head -c 10240 + fi + } >"${logfile}.errinfo" 2>/dev/null || true + return "$rc" fi # Clear stale flags on success (prevents false positives if a previous # $STD cmd || true failed and a later non-silent command triggers error_handler) unset _SILENT_FAILED_RC _SILENT_FAILED_CMD _SILENT_FAILED_LINE _SILENT_FAILED_LOG 2>/dev/null || true + # Also drop a stale .errinfo from a previously tolerated failure ($STD cmd || true) + rm -f "${logfile}.errinfo" 2>/dev/null || true } # ------------------------------------------------------------------------------ diff --git a/misc/error_handler.func b/misc/error_handler.func index cb1f012ed..2a6ec8fb3 100644 --- a/misc/error_handler.func +++ b/misc/error_handler.func @@ -7,12 +7,17 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # ------------------------------------------------------------------------------ # -# Provides comprehensive error handling and signal management for all scripts. -# Includes: -# - Exit code explanations (shell, package managers, databases, custom codes) -# - Error handler with detailed logging -# - Signal handlers (EXIT, INT, TERM) -# - Initialization function for trap setup +# Provides error handling and signal management for all scripts. +# +# TELEMETRY CONTRACT: +# - HOST context: this file reports terminal statuses via post_update_to_api +# (full metadata + focused error trace). +# - CONTAINER context: this file NEVER talks to the telemetry API. It writes +# two local artifacts that the host picks up after lxc-attach returns: +# /root/.install-.failed → exit code (flag file) +# /root/.install-.log.errinfo → structured error capture +# This guarantees the server only ever sees ONE terminal event per +# execution - the host's complete one. # # Usage: # source <(curl -fsSL .../error_handler.func) @@ -21,15 +26,14 @@ # ------------------------------------------------------------------------------ # ============================================================================== -# SECTION 1: EXIT CODE EXPLANATIONS +# SECTION 1: EXIT CODE EXPLANATIONS (fallback) # ============================================================================== # ------------------------------------------------------------------------------ # explain_exit_code() # -# - Canonical version is defined in api.func (sourced before this file) -# - This section only provides a fallback if api.func was not loaded -# - See api.func SECTION 1 for the authoritative exit code mappings +# - Canonical version lives in api.func (sourced before this file on the host) +# - This fallback covers the container context where api.func is not sourced # ------------------------------------------------------------------------------ if ! declare -f explain_exit_code &>/dev/null; then explain_exit_code() { @@ -94,8 +98,6 @@ if ! declare -f explain_exit_code &>/dev/null; then 100) echo "APT: Package manager error (broken packages / dependency problems)" ;; 101) echo "APT: Configuration error (bad sources.list, malformed config)" ;; 102) echo "APT: Lock held by another process (dpkg/apt still running)" ;; - - # --- Script Validation & Setup (103-123) --- 103) echo "Validation: Shell is not Bash" ;; 104) echo "Validation: Not running as root (or invoked via sudo)" ;; 105) echo "Validation: Proxmox VE version not supported" ;; @@ -177,9 +179,8 @@ if ! declare -f explain_exit_code &>/dev/null; then 223) echo "Proxmox: Template not available after download" ;; 224) echo "Proxmox: PBS storage is for backups only" ;; 225) echo "Proxmox: No template available for OS/Version" ;; + 226) echo "Proxmox: VM disk import or post-creation setup failed" ;; 231) echo "Proxmox: LXC stack upgrade failed" ;; - - # --- Tools & Addon Scripts (232-238) --- 232) echo "Tools: Wrong execution environment (run on PVE host, not inside LXC)" ;; 233) echo "Tools: Application not installed (update prerequisite missing)" ;; 234) echo "Tools: No LXC containers found or available" ;; @@ -187,7 +188,6 @@ if ! declare -f explain_exit_code &>/dev/null; then 236) echo "Tools: Required hardware not detected" ;; 237) echo "Tools: Dependency package installation failed" ;; 238) echo "Tools: OS or distribution not supported for this addon" ;; - 239) echo "npm/Node.js: Unexpected runtime error or dependency failure" ;; 243) echo "Node.js: Out of memory (JavaScript heap out of memory)" ;; 245) echo "Node.js: Invalid command-line option" ;; @@ -195,14 +195,11 @@ if ! declare -f explain_exit_code &>/dev/null; then 247) echo "Node.js: Fatal internal error" ;; 248) echo "Node.js: Invalid C++ addon / N-API failure" ;; 249) echo "npm/pnpm/yarn: Unknown fatal error" ;; - - # --- Application Install/Update Errors (250-254) --- 250) echo "App: Download failed or version not determined" ;; 251) echo "App: File extraction failed (corrupt or incomplete archive)" ;; 252) echo "App: Required file or resource not found" ;; 253) echo "App: Data migration required — update aborted" ;; 254) echo "App: User declined prompt or input timed out" ;; - 255) echo "DPKG: Fatal internal error" ;; *) echo "Unknown error" ;; esac @@ -210,24 +207,98 @@ if ! declare -f explain_exit_code &>/dev/null; then fi # ============================================================================== -# SECTION 2: ERROR HANDLERS +# SECTION 2: CONTEXT DETECTION & CONTAINER ARTIFACTS +# ============================================================================== + +# ------------------------------------------------------------------------------ +# _is_container_context() +# +# - Returns 0 (true) when running INSIDE the LXC container being installed +# - TELEMETRY_CONTEXT can override the heuristic ("host" / "container"); +# install.func sets TELEMETRY_CONTEXT=container during bootstrap +# ------------------------------------------------------------------------------ +_is_container_context() { + case "${TELEMETRY_CONTEXT:-}" in + container) return 0 ;; + host) return 1 ;; + esac + # Proxmox/Incus tooling exists only on the host + command -v pveversion &>/dev/null && return 1 + command -v pct &>/dev/null && return 1 + command -v incus &>/dev/null && return 1 + # systemd-detect-virt reports lxc inside containers + if command -v systemd-detect-virt &>/dev/null; then + case "$(systemd-detect-virt -c 2>/dev/null)" in + lxc | lxc-libvirt | openvz) return 0 ;; + esac + fi + # PCT_OSTYPE is exported into the install environment by the host + [[ -n "${PCT_OSTYPE:-}" ]] && return 0 + return 1 +} + +# ------------------------------------------------------------------------------ +# _container_write_failure() +# +# - Writes the failure artifacts inside the container for the host to pick up: +# * flag file with the exit code +# * .errinfo capture (if silent() has not already written a better one) +# * copy of the install log +# - This REPLACES any direct telemetry send from the container +# - Arguments: $1 = exit_code, $2 = command (optional), $3 = line (optional) +# ------------------------------------------------------------------------------ +_container_write_failure() { + local exit_code="${1:-1}" + local command="${2:-}" + local line="${3:-}" + local sid="${SESSION_ID:-error}" + + # Flag file with exit code (host reads this after lxc-attach returns) + echo "$exit_code" >"/root/.install-${sid}.failed" 2>/dev/null || true + + # Keep the install log where the host expects it + if [[ -n "${INSTALL_LOG:-}" && -f "${INSTALL_LOG}" && "${INSTALL_LOG}" != "/root/.install-${sid}.log" ]]; then + cp "${INSTALL_LOG}" "/root/.install-${sid}.log" 2>/dev/null || true + fi + + # Structured error capture (skip if silent() already wrote the exact + # output segment of the failing command - that one is always better). + # Self-contained: api.func is NOT sourced inside containers. + local errinfo="${INSTALL_LOG:-/root/.install-${sid}.log}.errinfo" + if [[ ! -s "$errinfo" ]]; then + local flat_cmd + flat_cmd=$(printf '%s' "${command:-unknown}" | tr '\n' ' ' | head -c 300) + { + echo "EXIT_CODE=${exit_code}" + echo "LINE=${line:-0}" + echo "COMMAND=${flat_cmd}" + echo "--- OUTPUT ---" + if [[ -n "${INSTALL_LOG:-}" && -s "${INSTALL_LOG}" ]]; then + tail -n 80 "${INSTALL_LOG}" 2>/dev/null | + sed 's/\r$//' | + sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' | + grep -avE '^(Get:|Hit:|Ign:|Fetched |Reading package lists|Reading state information|Building dependency tree|Selecting previously|Preparing to unpack|Unpacking |Processing triggers for|\(Reading database|[0-9]+%[[:space:]]*\[)' | + grep -avE '^[[:space:]]*$' | + tail -n 60 | head -c 10240 + fi + } >"$errinfo" 2>/dev/null || true + fi +} + +# ============================================================================== +# SECTION 3: ERROR HANDLER # ============================================================================== # ------------------------------------------------------------------------------ # error_handler() # # - Main error handler triggered by ERR trap -# - Arguments: exit_code, command, line_number -# - Behavior: -# * Returns silently if exit_code is 0 (success) -# * Sources explain_exit_code() for detailed error description -# * Displays error message with: -# - Line number where error occurred -# - Exit code with explanation -# - Command that failed -# * Shows last 20 lines of SILENT_LOGFILE if available -# * Copies log to container /root for later inspection -# * Exits with original exit code +# - Displays error message with line number, exit code, explanation, command +# - Shows last 20 lines of the active log +# - Emits actionable hints for common failure patterns (OOM, APT, network...) +# - HOST: reports "failed" to telemetry (full payload via api.func) +# - CONTAINER: writes failure artifacts, sends nothing +# - Exits with original exit code # ------------------------------------------------------------------------------ error_handler() { local exit_code=${1:-$?} @@ -237,12 +308,10 @@ error_handler() { command="${command//\$STD/}" # If error originated from silent(), use its captured metadata - # This provides the actual command and line number instead of "silent ..." if [[ -n "${_SILENT_FAILED_RC:-}" ]]; then exit_code="$_SILENT_FAILED_RC" command="$_SILENT_FAILED_CMD" line_number="$_SILENT_FAILED_LINE" - # Clear flags to prevent stale data on subsequent errors unset _SILENT_FAILED_RC _SILENT_FAILED_CMD _SILENT_FAILED_LINE fi @@ -250,8 +319,12 @@ error_handler() { return 0 fi - # Stop spinner and restore cursor FIRST — before any output - # This prevents spinner text overlapping with error messages + # Export the failure location so telemetry can include the "where" + FAILED_COMMAND="$command" + FAILED_LINE="$line_number" + export FAILED_COMMAND FAILED_LINE + + # Stop spinner and restore cursor FIRST - before any output if declare -f stop_spinner >/dev/null 2>&1; then stop_spinner 2>/dev/null || true fi @@ -259,18 +332,18 @@ error_handler() { local explanation explanation="$(explain_exit_code "$exit_code")" - - # ALWAYS report failure to API immediately - don't wait for container checks - # This ensures we capture failures that occur before/after container exists - if declare -f post_update_to_api &>/dev/null; then - post_update_to_api "failed" "$exit_code" 2>/dev/null || true - else - # Container context: post_update_to_api not available (api.func not sourced) - # Send status directly via curl so container failures are never lost - _send_abort_telemetry "$exit_code" 2>/dev/null || true + if [[ "$explanation" == curl:* && ! "$command" =~ (^|[[:space:]])([^[:space:]]*/)?curl([[:space:]]|$) ]]; then + explanation="Command failed with exit status ${exit_code}" fi - # Use msg_error if available, fallback to echo + # ── Telemetry / failure artifacts ── + if _is_container_context; then + _container_write_failure "$exit_code" "$command" "$line_number" + elif declare -f post_update_to_api &>/dev/null; then + post_update_to_api "failed" "$exit_code" 2>/dev/null || true + fi + + # ── Display ── if declare -f msg_error >/dev/null 2>&1; then msg_error "in line ${line_number}: exit code ${exit_code} (${explanation}): while executing command ${command}" else @@ -288,8 +361,7 @@ error_handler() { } >>"$DEBUG_LOGFILE" fi - # Get active log file (BUILD_LOG or INSTALL_LOG) - # Prefer silent()'s logfile when available (contains the actual command output) + # Get active log file (prefer silent()'s logfile when available) local active_log="" if [[ -n "${_SILENT_FAILED_LOG:-}" && -s "${_SILENT_FAILED_LOG}" ]]; then active_log="$_SILENT_FAILED_LOG" @@ -300,21 +372,17 @@ error_handler() { active_log="$SILENT_LOGFILE" fi - # If active_log points to a container-internal path that doesn't exist on host, - # fall back to BUILD_LOG (host-side log) if [[ -n "$active_log" && ! -s "$active_log" && -n "${BUILD_LOG:-}" && -s "${BUILD_LOG}" ]]; then active_log="$BUILD_LOG" fi - # Show last log lines if available if [[ -n "$active_log" && -s "$active_log" ]]; then echo -e "\n${TAB}--- Last 20 lines of log ---" tail -n 20 "$active_log" echo -e "${TAB}-----------------------------------\n" fi - # Detect probable Node.js heap OOM and print actionable guidance. - # This avoids generic SIGABRT/SIGKILL confusion for frontend build failures. + # ── Node.js heap OOM detection with actionable guidance ── local node_oom_detected="false" local node_build_context="false" if [[ "$command" =~ (npm|pnpm|yarn|node|vite|turbo) ]]; then @@ -331,7 +399,6 @@ error_handler() { if [[ "$node_oom_detected" == "true" ]] || { [[ "$node_build_context" == "true" ]] && [[ "$exit_code" =~ ^(134|137)$ ]]; }; then local heap_hint_mb="" - # If explicitly configured, prefer the current value for troubleshooting output. if [[ -n "${NODE_OPTIONS:-}" ]] && [[ "${NODE_OPTIONS}" =~ max-old-space-size=([0-9]+) ]]; then heap_hint_mb="${BASH_REMATCH[1]}" elif [[ -n "${var_ram:-}" ]] && [[ "${var_ram}" =~ ^[0-9]+$ ]]; then @@ -358,14 +425,13 @@ error_handler() { fi fi - # ── Log-pattern analysis: detect common failure causes and emit actionable hints ── + # ── Log-pattern analysis: actionable hints for common failure causes ── if [[ -n "$active_log" && -s "$active_log" ]]; then local _log_tail _log_tail=$(tail -n 60 "$active_log" 2>/dev/null || true) # 1. APT/dpkg dependency conflict if echo "$_log_tail" | grep -qE "Depends:|depends on.*but.*not installed|broken packages|unmet dep|dependency problems"; then - # Check for PostgreSQL-specific version mismatch (most actionable) local _pg_conflict _pg_conflict=$(echo "$_log_tail" | grep -oE 'postgresql-[0-9]+ but.*installed' | head -1 || true) if [[ -n "$_pg_conflict" ]]; then @@ -386,7 +452,7 @@ error_handler() { msg_warn "Hint: A repository GPG key may be missing, expired, or the keyring file is not yet present (/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc etc.)." msg_warn "Hint: Install the 'postgresql-common' package first, or re-add the repository with its correct signing key." fi - # 3. Network / DNS failure during apt-get or curl + # 3. Network / DNS failure elif echo "$_log_tail" | grep -qE "Could not resolve|Failed to fetch|Unable to connect|Name or service not known|Network is unreachable|curl.*resolve"; then if declare -f msg_warn >/dev/null 2>&1; then msg_warn "Network or DNS failure detected." @@ -407,17 +473,12 @@ error_handler() { fi fi - # Detect context: Container (INSTALL_LOG set + inside container /root) vs Host - if [[ -n "${INSTALL_LOG:-}" && -f "${INSTALL_LOG:-}" && -d /root ]]; then - # CONTAINER CONTEXT: Copy log and create flag file for host - local container_log="/root/.install-${SESSION_ID:-error}.log" - cp "${INSTALL_LOG}" "$container_log" 2>/dev/null || true - - # Create error flag file with exit code for host detection - echo "$exit_code" >"/root/.install-${SESSION_ID:-error}.failed" 2>/dev/null || true - # Log path is shown by host as combined log - no need to show container path + # ── Context-specific cleanup ── + if _is_container_context; then + # Container: artifacts already written above; nothing more to do + : else - # HOST CONTEXT: Show local log path and offer container cleanup + # HOST: show log path and offer container cleanup if [[ -n "$active_log" && -s "$active_log" ]]; then if declare -f msg_custom >/dev/null 2>&1; then msg_custom "📋" "${YW}" "Full log: ${active_log}" @@ -435,7 +496,6 @@ error_handler() { echo -en "${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}" fi - # Read user response local response="" if read -t 60 -r response; then if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then @@ -476,12 +536,6 @@ error_handler() { echo -e "${GN}✔${CL} Container ${CTID} removed" fi fi - - # Force one final status update attempt after cleanup - # This ensures status is updated even if the first attempt failed (e.g., HTTP 400) - if declare -f post_update_to_api &>/dev/null; then - post_update_to_api "failed" "$exit_code" "force" - fi fi fi @@ -489,106 +543,33 @@ error_handler() { } # ============================================================================== -# SECTION 3: TELEMETRY & CLEANUP HELPERS FOR SIGNAL HANDLERS +# SECTION 4: TELEMETRY & CLEANUP HELPERS FOR SIGNAL HANDLERS # ============================================================================== # ------------------------------------------------------------------------------ -# _send_abort_telemetry() +# _send_abort_telemetry() (compatibility name) # -# - Sends failure/abort status to telemetry API -# - Works in BOTH host context (post_update_to_api available) and -# container context (only curl available, api.func not sourced) -# - Container context is critical: without this, container-side failures -# and signal exits are never reported, leaving records stuck in -# "installing" or "configuring" forever +# - HOST: reports via post_update_to_api (signals map to "aborted" there) +# - CONTAINER: writes failure artifacts instead of sending anything # - Arguments: $1 = exit_code # ------------------------------------------------------------------------------ _send_abort_telemetry() { local exit_code="${1:-1}" - # Try full API function first (host context - api.func sourced) + if _is_container_context; then + _container_write_failure "$exit_code" + return 0 + fi if declare -f post_update_to_api &>/dev/null; then post_update_to_api "failed" "$exit_code" 2>/dev/null || true - return fi - # Fallback: direct curl (container context - api.func NOT sourced) - # This is the ONLY way containers can report failures to telemetry - command -v curl &>/dev/null || return 0 - [[ "${DIAGNOSTICS:-no}" == "no" ]] && return 0 - [[ -z "${RANDOM_UUID:-}" ]] && return 0 - - # Collect last 200 log lines for error diagnosis (best-effort) - # Container context has no get_full_log(), so we gather as much as possible - local error_text="" - local logfile="" - if [[ -n "${INSTALL_LOG:-}" && -s "${INSTALL_LOG}" ]]; then - logfile="${INSTALL_LOG}" - elif [[ -n "${SILENT_LOGFILE:-}" && -s "${SILENT_LOGFILE}" ]]; then - logfile="${SILENT_LOGFILE}" - fi - - if [[ -n "$logfile" ]]; then - error_text=$(tail -n 200 "$logfile" 2>/dev/null | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\\/\\\\/g; s/"/\\"/g; s/\r//g' | tr '\n' '|' | sed 's/|$//' | head -c 16384 | tr -d '\000-\010\013\014\016-\037\177') || true - fi - - # Prepend exit code explanation header (like build_error_string does on host) - local explanation="" - if declare -f explain_exit_code &>/dev/null; then - explanation=$(explain_exit_code "$exit_code" 2>/dev/null) || true - fi - if [[ -n "$explanation" && -n "$error_text" ]]; then - error_text="exit_code=${exit_code} | ${explanation}|---|${error_text}" - elif [[ -n "$explanation" && -z "$error_text" ]]; then - error_text="exit_code=${exit_code} | ${explanation}" - fi - - # Calculate duration if start time is available - local duration="" - if [[ -n "${DIAGNOSTICS_START_TIME:-}" ]]; then - duration=$(($(date +%s) - DIAGNOSTICS_START_TIME)) - fi - - # Categorize error if function is available (may not be in minimal container context) - local error_category="" - if declare -f categorize_error &>/dev/null; then - error_category=$(categorize_error "$exit_code" 2>/dev/null) || true - fi - - # Build JSON payload with error context - local payload - payload="{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"${TELEMETRY_TYPE:-lxc}\",\"nsapp\":\"${NSAPP:-${app:-unknown}}\",\"status\":\"failed\",\"exit_code\":${exit_code}" - [[ -n "$error_text" ]] && payload="${payload},\"error\":\"${error_text}\"" - [[ -n "$error_category" ]] && payload="${payload},\"error_category\":\"${error_category}\"" - [[ -n "$duration" ]] && payload="${payload},\"duration\":${duration}" - payload="${payload}}" - - local api_url="${TELEMETRY_URL:-https://telemetry.community-scripts.org/telemetry}" - - # 2 attempts (retry once on failure) — original had no retry - local attempt - for attempt in 1 2; do - if curl -fsS -m 5 -X POST "$api_url" \ - -H "Content-Type: application/json" \ - -d "$payload" &>/dev/null; then - return 0 - fi - [[ $attempt -eq 1 ]] && sleep 1 - done return 0 } # ------------------------------------------------------------------------------ # _stop_container_if_installing() # -# - Stops the LXC container if we're in the install phase +# - Stops the LXC container if we're in the install phase (host only) # - Prevents orphaned container processes when the host exits due to a signal -# (SSH disconnect, Ctrl+C, SIGTERM) — without this, the container keeps -# running and may send "configuring" status AFTER the host already sent -# "failed", leaving records permanently stuck in "configuring" -# - Only acts when: -# * CONTAINER_INSTALLING flag is set (during lxc-attach in build_container) -# * CTID is set (container was created) -# * pct command is available (we're on the Proxmox host, not inside a container) -# - Does NOT destroy the container — just stops it for potential debugging # ------------------------------------------------------------------------------ _stop_container_if_installing() { [[ "${CONTAINER_INSTALLING:-}" == "true" ]] || return 0 @@ -598,51 +579,47 @@ _stop_container_if_installing() { } # ============================================================================== -# SECTION 4: SIGNAL HANDLERS +# SECTION 5: SIGNAL HANDLERS # ============================================================================== # ------------------------------------------------------------------------------ # on_exit() # # - EXIT trap handler — runs on EVERY script termination -# - Catches orphaned "installing"/"configuring" records: -# * If post_to_api sent "installing" but post_update_to_api never ran -# * Reports final status to prevent records stuck forever -# - Best-effort log collection for failed installs -# - Stops orphaned container processes on failure -# - Cleans up lock files +# - CONTAINER: ensures failure artifacts exist on non-zero exit (this also +# covers silent()'s direct `exit $rc`, which bypasses the ERR trap) +# - HOST: catches executions that never sent a final status: +# * non-zero exit → "failed" (signal codes map to "aborted") +# * zero exit with an "installing" record but no final → "aborted" +# (e.g. user cancelled a whiptail dialog, script exited cleanly) # ------------------------------------------------------------------------------ on_exit() { local exit_code=$? - # Report orphaned telemetry records - # Two scenarios handled: - # 1. POST_TO_API_DONE=true but POST_UPDATE_DONE=false: Record was created but - # never got a final status update → send abort/done now. - # 2. POST_TO_API_DONE=false but DIAGNOSTICS=yes: Initial post failed (server - # unreachable/timeout), but the server has fallback create-on-update logic, - # so a status update can still create the record. Worth one last try. - if [[ "${POST_UPDATE_DONE:-}" != "true" ]]; then - if [[ "${POST_TO_API_DONE:-}" == "true" || "${DIAGNOSTICS:-no}" == "yes" ]]; then + if _is_container_context; then + if [[ $exit_code -ne 0 ]]; then + _container_write_failure "$exit_code" "${FAILED_COMMAND:-}" "${FAILED_LINE:-}" + fi + else + if [[ "${POST_UPDATE_DONE:-}" != "true" ]] && declare -f post_update_to_api >/dev/null 2>&1; then if [[ $exit_code -ne 0 ]]; then - _send_abort_telemetry "$exit_code" - elif [[ "${INSTALL_COMPLETE:-}" == "true" ]] && declare -f post_update_to_api >/dev/null 2>&1; then - # Only report success if the install was explicitly marked complete. - # Without this guard, early bailouts (e.g. user cancelled) with exit 0 - # would be falsely reported as successful installations. - post_update_to_api "done" "0" 2>/dev/null || true + post_update_to_api "failed" "$exit_code" 2>/dev/null || true + elif [[ "${POST_TO_API_DONE:-}" == "true" ]]; then + # Clean exit but no success was ever reported: the user backed out + # somewhere. Report as aborted so the record doesn't stay "installing". + post_update_to_api "aborted" "0" 2>/dev/null || true fi fi - fi - # Best-effort log collection on failure (non-critical, telemetry already sent) - if [[ $exit_code -ne 0 ]] && declare -f ensure_log_on_host >/dev/null 2>&1; then - ensure_log_on_host 2>/dev/null || true - fi + # Best-effort log collection on failure + if [[ $exit_code -ne 0 ]] && declare -f ensure_log_on_host >/dev/null 2>&1; then + ensure_log_on_host 2>/dev/null || true + fi - # Stop orphaned container if we're in the install phase and exiting with error - if [[ $exit_code -ne 0 ]]; then - _stop_container_if_installing + # Stop orphaned container if we're in the install phase + if [[ $exit_code -ne 0 ]]; then + _stop_container_if_installing + fi fi [[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile" @@ -650,21 +627,19 @@ on_exit() { } # ------------------------------------------------------------------------------ -# on_interrupt() -# -# - SIGINT (Ctrl+C) trap handler -# - Reports status FIRST (time-critical: container may be dying) -# - Stops orphaned container to prevent "configuring" ghost records -# - Exits with code 130 (128 + SIGINT=2) +# on_interrupt() - SIGINT (Ctrl+C) # ------------------------------------------------------------------------------ on_interrupt() { - # Stop spinner and restore cursor before any output if declare -f stop_spinner >/dev/null 2>&1; then stop_spinner 2>/dev/null || true fi printf "\e[?25h" 2>/dev/null || true - _send_abort_telemetry "130" + if _is_container_context; then + _container_write_failure "130" + elif declare -f post_update_to_api &>/dev/null; then + post_update_to_api "aborted" "130" 2>/dev/null || true + fi _stop_container_if_installing if declare -f msg_error >/dev/null 2>&1; then msg_error "Interrupted by user (SIGINT)" 2>/dev/null || true @@ -675,21 +650,19 @@ on_interrupt() { } # ------------------------------------------------------------------------------ -# on_terminate() -# -# - SIGTERM trap handler -# - Reports status FIRST (time-critical: process being killed) -# - Stops orphaned container to prevent "configuring" ghost records -# - Exits with code 143 (128 + SIGTERM=15) +# on_terminate() - SIGTERM # ------------------------------------------------------------------------------ on_terminate() { - # Stop spinner and restore cursor before any output if declare -f stop_spinner >/dev/null 2>&1; then stop_spinner 2>/dev/null || true fi printf "\e[?25h" 2>/dev/null || true - _send_abort_telemetry "143" + if _is_container_context; then + _container_write_failure "143" + elif declare -f post_update_to_api &>/dev/null; then + post_update_to_api "aborted" "143" 2>/dev/null || true + fi _stop_container_if_installing if declare -f msg_error >/dev/null 2>&1; then msg_error "Terminated by signal (SIGTERM)" 2>/dev/null || true @@ -700,45 +673,32 @@ on_terminate() { } # ------------------------------------------------------------------------------ -# on_hangup() -# -# - SIGHUP trap handler (SSH disconnect, terminal closed) -# - CRITICAL: This was previously MISSING from catch_errors(), causing -# container processes to become orphans on SSH disconnect — the #1 cause -# of records stuck in "installing" and "configuring" states -# - Reports status via direct curl (terminal is already closed, no output) -# - Stops orphaned container to prevent ghost records -# - Exits with code 129 (128 + SIGHUP=1) +# on_hangup() - SIGHUP (SSH disconnect, terminal closed) # ------------------------------------------------------------------------------ on_hangup() { - # Stop spinner (no cursor restore needed — terminal is already gone) if declare -f stop_spinner >/dev/null 2>&1; then stop_spinner 2>/dev/null || true fi - _send_abort_telemetry "129" + if _is_container_context; then + _container_write_failure "129" + elif declare -f post_update_to_api &>/dev/null; then + post_update_to_api "aborted" "129" 2>/dev/null || true + fi _stop_container_if_installing exit 129 } # ============================================================================== -# SECTION 5: INITIALIZATION +# SECTION 6: INITIALIZATION # ============================================================================== # ------------------------------------------------------------------------------ # catch_errors() # # - Initializes error handling and signal traps -# - Enables strict error handling: -# * set -Ee: Exit on error, inherit ERR trap in functions -# * set -o pipefail: Pipeline fails if any command fails -# * set -u: (optional) Exit on undefined variable (if STRICT_UNSET=1) -# - Sets up traps: -# * ERR → error_handler (script errors) -# * EXIT → on_exit (any termination — cleanup + orphan detection) -# * INT → on_interrupt (Ctrl+C) -# * TERM → on_terminate (kill / systemd stop) -# * HUP → on_hangup (SSH disconnect / terminal closed) +# - set -Ee -o pipefail (+ set -u when STRICT_UNSET=1) +# - Traps: ERR → error_handler, EXIT → on_exit, INT/TERM/HUP → signal handlers # - Call this function early in every script # ------------------------------------------------------------------------------ catch_errors() { diff --git a/misc/install.func b/misc/install.func index a178a1ab3..48d8b07be 100644 --- a/misc/install.func +++ b/misc/install.func @@ -32,6 +32,11 @@ if ! command -v curl >/dev/null 2>&1; then apt update >/dev/null 2>&1 apt install -y curl >/dev/null 2>&1 fi +# Mark container context BEFORE error handling starts: error_handler/on_exit +# must write local failure artifacts instead of talking to the telemetry API +# (the host is the single telemetry reporter). +export TELEMETRY_CONTEXT="container" + source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) load_functions @@ -65,9 +70,12 @@ post_progress_to_api() { local progress_status="${1:-configuring}" + # Progress pings are the ONLY telemetry a container sends (terminal statuses + # are reported by the host). Include execution_id + platform + repo + # attribution (exported by the host) so the server can correlate and filter. curl -fsS -m 5 -X POST "https://telemetry.community-scripts.org/telemetry" \ -H "Content-Type: application/json" \ - -d "{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"lxc\",\"nsapp\":\"${app:-unknown}\",\"status\":\"${progress_status}\"}" &>/dev/null || true + -d "{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"lxc\",\"nsapp\":\"${app:-unknown}\",\"status\":\"${progress_status}\",\"platform\":\"${TELEMETRY_PLATFORM:-}\",\"repo_source\":\"${REPO_SOURCE:-}\",\"repo_slug\":\"${REPO_SLUG:-}\"}" &>/dev/null || true } # ============================================================================== diff --git a/misc/vm-core.func b/misc/vm-core.func index da9ee5584..d6303264e 100644 --- a/misc/vm-core.func +++ b/misc/vm-core.func @@ -573,8 +573,10 @@ cleanup() { if [[ $exit_code -ne 0 ]]; then post_update_to_api "failed" "$exit_code" else - # Exited cleanly but description()/success was never called — shouldn't happen - post_update_to_api "failed" "1" + # Exited cleanly but description()/success was never called: the user + # backed out of a dialog. Report as aborted - NOT "failed 1" (which + # produced meaningless 'General error' records with no error text). + post_update_to_api "aborted" "0" fi fi fi From 1cfddc4c9c28243c455a20fab3ef5d423ffc9d80 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:33:05 +0000 Subject: [PATCH 229/245] Update CHANGELOG.md (#15936) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index caa12192b..c4927060f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -529,6 +529,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### ✨ New Features + - core: refactor to single-reporter telemetry and better error_handling [@MickLesk](https://github.com/MickLesk) ([#15933](https://github.com/community-scripts/ProxmoxVE/pull/15933)) - tools.func: add support for extracting 7z archives [@MickLesk](https://github.com/MickLesk) ([#15919](https://github.com/community-scripts/ProxmoxVE/pull/15919)) - Meilisearch : use dumpless Meilisearch upgrades [@MickLesk](https://github.com/MickLesk) ([#15921](https://github.com/community-scripts/ProxmoxVE/pull/15921)) From e45d4c63495edd6979da849e0912e63aede4554d Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:52:18 +0200 Subject: [PATCH 230/245] Pangolin: Bump Version to 1.21.0 (#15938) --- ct/pangolin.sh | 2 +- install/pangolin-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/pangolin.sh b/ct/pangolin.sh index fe5b787a9..542c9c510 100644 --- a/ct/pangolin.sh +++ b/ct/pangolin.sh @@ -6,7 +6,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV # Source: https://pangolin.net/ | Github: https://github.com/fosrl/pangolin APP="Pangolin" -PANGOLIN_VERSION="${PANGOLIN_VERSION:-1.20.0}" +PANGOLIN_VERSION="${PANGOLIN_VERSION:-1.21.0}" var_tags="${var_tags:-proxy}" var_cpu="${var_cpu:-2}" var_ram="${var_ram:-4096}" diff --git a/install/pangolin-install.sh b/install/pangolin-install.sh index 0a8f008af..50b662851 100644 --- a/install/pangolin-install.sh +++ b/install/pangolin-install.sh @@ -22,7 +22,7 @@ msg_ok "Installed Dependencies" NODE_VERSION="24" setup_nodejs PG_VERSION="17" setup_postgresql PG_DB_NAME="pangolin" PG_DB_USER="pangolin" setup_postgresql_db -PANGOLIN_VERSION="${PANGOLIN_VERSION:-1.20.0}" +PANGOLIN_VERSION="${PANGOLIN_VERSION:-1.21.0}" fetch_and_deploy_gh_release "pangolin" "fosrl/pangolin" "tarball" "$PANGOLIN_VERSION" fetch_and_deploy_gh_release "gerbil" "fosrl/gerbil" "singlefile" "latest" "/usr/bin" "gerbil_linux_$(arch_resolve)" fetch_and_deploy_gh_release "traefik" "traefik/traefik" "prebuild" "latest" "/usr/bin" "traefik_v*_linux_$(arch_resolve).tar.gz" From d8efbd04d8a805be05b3b47e8101439c2e55fcd2 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:52:39 +0000 Subject: [PATCH 231/245] Update CHANGELOG.md (#15945) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4927060f..7432a363c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -505,6 +505,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-21 + +### 🚀 Updated Scripts + + - #### ✨ New Features + + - Pangolin: Bump Version to 1.21.0 [@MickLesk](https://github.com/MickLesk) ([#15938](https://github.com/community-scripts/ProxmoxVE/pull/15938)) + ## 2026-07-20 ### 🚀 Updated Scripts From bd3e3bd5f9fb44bc9c3e8b5ac0d030ca321a2f1a Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:52:51 +0200 Subject: [PATCH 232/245] Standardize CT update backup handling (#15937) --- ct/affine.sh | 2 -- ct/alpine-cinny.sh | 9 ++------- ct/dispatcharr.sh | 28 +++------------------------- ct/fladder.sh | 14 ++------------ ct/flatnotes.sh | 16 ++++------------ ct/fluid-calendar.sh | 4 ++-- ct/ghostfolio.sh | 6 ++++-- ct/gogs.sh | 11 ++--------- ct/grist.sh | 15 ++++----------- ct/homebox.sh | 4 ++++ ct/homelable.sh | 21 ++++----------------- ct/homepage.sh | 17 ++++------------- ct/hoodik.sh | 9 ++------- ct/igotify.sh | 9 ++------- ct/immichframe.sh | 9 ++------- ct/investbrain.sh | 15 ++++----------- ct/invoiceninja.sh | 14 ++------------ ct/invoiceshelf.sh | 12 ++---------- ct/joplin-server.sh | 4 ++-- ct/jotty.sh | 12 ++---------- ct/kan.sh | 9 ++------- ct/kima-hub.sh | 11 ++--------- ct/kitchenowl.sh | 12 ++---------- ct/koel.sh | 14 ++------------ ct/leantime.sh | 16 +++++++--------- ct/librechat.sh | 22 ++++++---------------- ct/linkding.sh | 11 ++--------- ct/linkwarden.sh | 12 ++++-------- ct/lobehub.sh | 9 ++------- ct/mail-archiver.sh | 10 ++-------- ct/manyfold.sh | 15 ++++++--------- ct/matomo.sh | 20 ++------------------ ct/meilisearch.sh | 7 +++---- ct/metube.sh | 18 ++++-------------- ct/nametag.sh | 15 ++------------- ct/overseerr.sh | 8 +++----- ct/ownfoil.sh | 11 +++-------- ct/paperclip.sh | 8 ++------ ct/papra.sh | 13 ++++--------- ct/patchmon.sh | 4 ++++ ct/postiz.sh | 2 -- ct/powerdns.sh | 10 +++------- ct/radicale.sh | 9 ++------- ct/reactive-resume.sh | 5 +++-- ct/rustypaste.sh | 11 ++--------- ct/scanopy.sh | 9 +++------ ct/shelfmark.sh | 4 ++-- ct/shlink.sh | 12 ++---------- ct/slskd.sh | 21 ++++++--------------- ct/solidtime.sh | 12 ++---------- ct/soulsync.sh | 10 +++------- ct/sparkyfitness.sh | 17 +++-------------- ct/spliit.sh | 9 ++------- ct/spoolman.sh | 10 ++++------ ct/storyteller.sh | 8 ++------ ct/tandoor.sh | 11 ++++------- ct/tautulli.sh | 13 +++---------- ct/teable.sh | 8 ++------ ct/teddycloud.sh | 9 ++------- ct/termix.sh | 13 +++---------- ct/tianji.sh | 11 ++++------- ct/transmute.sh | 13 +++---------- ct/tubearchivist.sh | 7 +++---- ct/umami.sh | 4 ++-- ct/umlautadaptarr.sh | 4 ++-- ct/wallabag.sh | 9 ++------- ct/wealthfolio.sh | 13 +++---------- ct/web-check.sh | 8 ++------ ct/webtrees.sh | 9 ++------- ct/wishlist.sh | 16 +++------------- ct/writefreely.sh | 12 ++---------- ct/xyops.sh | 13 +++---------- ct/yamtrack.sh | 11 +++-------- ct/yourls.sh | 11 +++-------- ct/zerobyte.sh | 11 +++-------- ct/zigbee2mqtt.sh | 10 +++++----- 76 files changed, 215 insertions(+), 626 deletions(-) diff --git a/ct/affine.sh b/ct/affine.sh index b910afe5d..4ccf2c51f 100644 --- a/ct/affine.sh +++ b/ct/affine.sh @@ -42,8 +42,6 @@ function update_script() { CLEAN_INSTALL=1 fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "${RELEASE}" "/opt/affine" - # Restore BEFORE the build: CLEAN_INSTALL wiped /opt/affine including .env, - # and the build below sources it restore_backup if [[ ! -f /opt/affine/.env ]]; then diff --git a/ct/alpine-cinny.sh b/ct/alpine-cinny.sh index 17a6019ae..0e25792d9 100644 --- a/ct/alpine-cinny.sh +++ b/ct/alpine-cinny.sh @@ -30,16 +30,11 @@ function update_script() { fi if check_for_gh_release "cinny" "cinnyapp/cinny"; then - msg_info "Backing up Configuration" - cp /opt/cinny/config.json /opt/cinny_config.json.bak - msg_ok "Backed up Configuration" + create_backup /opt/cinny/config.json CLEAN_INSTALL=1 fetch_and_deploy_gh_release "cinny" "cinnyapp/cinny" "prebuild" "latest" "/opt/cinny" "cinny-*.tar.gz" - msg_info "Restoring Configuration" - cp /opt/cinny_config.json.bak /opt/cinny/config.json - rm -f /opt/cinny_config.json.bak - msg_ok "Restored Configuration" + restore_backup msg_info "Restarting nginx" $STD rc-service nginx restart diff --git a/ct/dispatcharr.sh b/ct/dispatcharr.sh index 1c523eaf8..09ecbcab1 100644 --- a/ct/dispatcharr.sh +++ b/ct/dispatcharr.sh @@ -116,21 +116,10 @@ EOF msg_info "Creating Backup" BACKUP_FILE="/opt/dispatcharr_backup_$(date +%F_%H-%M-%S).tar.gz" - if [[ -f /opt/dispatcharr/.env ]]; then - cp /opt/dispatcharr/.env /tmp/dispatcharr.env.backup - fi if [[ -f /opt/dispatcharr/start-gunicorn.sh ]]; then rm -f /opt/dispatcharr/start-gunicorn.sh fi - if [[ -f /opt/dispatcharr/start-celery.sh ]]; then - cp /opt/dispatcharr/start-celery.sh /tmp/start-celery.sh.backup - fi - if [[ -f /opt/dispatcharr/start-celerybeat.sh ]]; then - cp /opt/dispatcharr/start-celerybeat.sh /tmp/start-celerybeat.sh.backup - fi - if [[ -f /opt/dispatcharr/start-daphne.sh ]]; then - cp /opt/dispatcharr/start-daphne.sh /tmp/start-daphne.sh.backup - fi + create_backup /opt/dispatcharr/.env /opt/dispatcharr/start-celery.sh /opt/dispatcharr/start-celerybeat.sh /opt/dispatcharr/start-daphne.sh if [[ -f /opt/dispatcharr/.env ]]; then set -o allexport source /opt/dispatcharr/.env @@ -145,20 +134,9 @@ EOF CLEAN_INSTALL=1 fetch_and_deploy_gh_release "dispatcharr" "Dispatcharr/Dispatcharr" "tarball" - msg_info "Updating Dispatcharr Backend" - if [[ -f /tmp/dispatcharr.env.backup ]]; then - mv /tmp/dispatcharr.env.backup /opt/dispatcharr/.env - fi - if [[ -f /tmp/start-celery.sh.backup ]]; then - mv /tmp/start-celery.sh.backup /opt/dispatcharr/start-celery.sh - fi - if [[ -f /tmp/start-celerybeat.sh.backup ]]; then - mv /tmp/start-celerybeat.sh.backup /opt/dispatcharr/start-celerybeat.sh - fi - if [[ -f /tmp/start-daphne.sh.backup ]]; then - mv /tmp/start-daphne.sh.backup /opt/dispatcharr/start-daphne.sh - fi + restore_backup + msg_info "Updating Dispatcharr Backend" if ! grep -q "DJANGO_SECRET_KEY" /opt/dispatcharr/.env; then DJANGO_SECRET=$(openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | cut -c1-50) echo "DJANGO_SECRET_KEY=$DJANGO_SECRET" >>/opt/dispatcharr/.env diff --git a/ct/fladder.sh b/ct/fladder.sh index 4a7d4ca3d..b9812bd08 100644 --- a/ct/fladder.sh +++ b/ct/fladder.sh @@ -35,21 +35,11 @@ function update_script() { systemctl stop nginx msg_ok "Stopped Service" - if [[ -f /opt/fladder/assets/config/config.json ]]; then - msg_info "Backing up configuration" - cp /opt/fladder/assets/config/config.json /tmp/fladder_config.json.bak - msg_ok "Configuration backed up" - fi + create_backup /opt/fladder/assets/config/config.json CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Fladder" "DonutWare/Fladder" "prebuild" "latest" "/opt/fladder" "Fladder-Web-*.zip" - if [[ -f /tmp/fladder_config.json.bak ]]; then - msg_info "Restoring configuration" - mkdir -p /opt/fladder/assets/config - cp /tmp/fladder_config.json.bak /opt/fladder/assets/config/config.json - rm -f /tmp/fladder_config.json.bak - msg_ok "Configuration restored" - fi + restore_backup msg_info "Starting Service" systemctl start nginx diff --git a/ct/flatnotes.sh b/ct/flatnotes.sh index 3f48dc326..0ff537636 100644 --- a/ct/flatnotes.sh +++ b/ct/flatnotes.sh @@ -34,12 +34,11 @@ function update_script() { systemctl stop flatnotes msg_ok "Stopped Service" - msg_info "Backing up Configuration and Data" - cp /opt/flatnotes/.env /opt/flatnotes.env - cp -r /opt/flatnotes/data /opt/flatnotes_data_backup - msg_ok "Backed up Configuration and Data" + create_backup /opt/flatnotes/.env /opt/flatnotes/data - fetch_and_deploy_gh_release "flatnotes" "dullage/flatnotes" "tarball" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "flatnotes" "dullage/flatnotes" "tarball" + + restore_backup msg_info "Updating Flatnotes" cd /opt/flatnotes/client @@ -52,13 +51,6 @@ function update_script() { $STD /usr/local/bin/uv sync msg_ok "Updated Flatnotes" - msg_info "Restoring Configuration and Data" - cp /opt/flatnotes.env /opt/flatnotes/.env - cp -r /opt/flatnotes_data_backup/. /opt/flatnotes/data - rm -f /opt/flatnotes.env - rm -r /opt/flatnotes_data_backup - msg_ok "Restored Configuration and Data" - msg_info "Starting Service" systemctl start flatnotes msg_ok "Started Service" diff --git a/ct/fluid-calendar.sh b/ct/fluid-calendar.sh index a28554c74..7807e069b 100644 --- a/ct/fluid-calendar.sh +++ b/ct/fluid-calendar.sh @@ -38,9 +38,9 @@ function update_script() { systemctl stop fluid-calendar msg_info "Stopped Service" - cp /opt/fluid-calendar/.env /opt/fluid.env + create_backup /opt/fluid-calendar/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "fluid-calendar" "dotnetfactory/fluid-calendar" "tarball" - mv /opt/fluid.env /opt/fluid-calendar/.env + restore_backup msg_info "Updating Fluid Calendar" cd /opt/fluid-calendar diff --git a/ct/ghostfolio.sh b/ct/ghostfolio.sh index 919099fae..149bf0824 100644 --- a/ct/ghostfolio.sh +++ b/ct/ghostfolio.sh @@ -41,13 +41,15 @@ function update_script() { --exclude="ghostfolio/node_modules" \ --exclude="ghostfolio/dist" \ ghostfolio - mv /opt/ghostfolio/.env /opt/env.backup msg_ok "Backup Created" + create_backup /opt/ghostfolio/.env + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "ghostfolio" "ghostfolio/ghostfolio" "tarball" "latest" "/opt/ghostfolio" + restore_backup + msg_info "Updating Ghostfolio" - mv /opt/env.backup /opt/ghostfolio/.env sed -i -E '/^DATABASE_URL=/ s/[?&]sslmode=prefer//g' /opt/ghostfolio/.env cd /opt/ghostfolio $STD npm ci diff --git a/ct/gogs.sh b/ct/gogs.sh index d00561852..6bdbd730c 100644 --- a/ct/gogs.sh +++ b/ct/gogs.sh @@ -35,18 +35,11 @@ function update_script() { systemctl stop gogs msg_ok "Stopped Service" - msg_info "Backing up Data" - cp -r /opt/gogs/custom /opt/gogs_custom_backup - cp -r /opt/gogs/data /opt/gogs_data_backup - msg_ok "Backed up Data" + create_backup /opt/gogs/custom /opt/gogs/data CLEAN_INSTALL=1 fetch_and_deploy_gh_release "gogs" "gogs/gogs" "prebuild" "latest" "/opt/gogs" "gogs_*_linux_$(arch_resolve).tar.gz" - msg_info "Restoring Data" - cp -r /opt/gogs_custom_backup/. /opt/gogs/custom - cp -r /opt/gogs_data_backup/. /opt/gogs/data - rm -rf /opt/gogs_custom_backup /opt/gogs_data_backup - msg_ok "Restored Data" + restore_backup msg_info "Starting Service" systemctl start gogs diff --git a/ct/grist.sh b/ct/grist.sh index 832f58717..cc6a81321 100644 --- a/ct/grist.sh +++ b/ct/grist.sh @@ -37,21 +37,14 @@ function update_script() { systemctl stop grist msg_ok "Stopped Service" - msg_info "Creating backup" - rm -rf /opt/grist_bak - mv /opt/grist /opt/grist_bak - msg_ok "Backup created" + create_backup /opt/grist/.env /opt/grist/docs /opt/grist/grist-sessions.db /opt/grist/landing.db - fetch_and_deploy_gh_release "grist" "gristlabs/grist-core" "tarball" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "grist" "gristlabs/grist-core" "tarball" + + restore_backup msg_info "Updating Grist" mkdir -p /opt/grist/docs - cp -n /opt/grist_bak/.env /opt/grist/.env - if ls /opt/grist_bak/docs/* &>/dev/null; then - cp -r /opt/grist_bak/docs/* /opt/grist/docs/ - fi - [[ -f /opt/grist_bak/grist-sessions.db ]] && cp /opt/grist_bak/grist-sessions.db /opt/grist/grist-sessions.db - [[ -f /opt/grist_bak/landing.db ]] && cp /opt/grist_bak/landing.db /opt/grist/landing.db cd /opt/grist $STD yarn install $STD yarn run build:prod diff --git a/ct/homebox.sh b/ct/homebox.sh index 3d956ee8d..600dc3197 100644 --- a/ct/homebox.sh +++ b/ct/homebox.sh @@ -39,8 +39,12 @@ function update_script() { systemctl stop homebox msg_ok "Stopped Service" + create_backup /opt/homebox/.env /opt/homebox/.data + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "homebox" "sysadminsmedia/homebox" "prebuild" "latest" "/opt/homebox" "homebox_Linux_$(arch_resolve "x86_64" "arm64").tar.gz" chmod +x /opt/homebox/homebox + + restore_backup [ -f /opt/.env ] && mv /opt/.env /opt/homebox/.env [ -d /opt/.data ] && mv /opt/.data /opt/homebox/.data diff --git a/ct/homelable.sh b/ct/homelable.sh index 61104b54c..5f7d6c1dd 100644 --- a/ct/homelable.sh +++ b/ct/homelable.sh @@ -35,16 +35,12 @@ function update_script() { systemctl stop homelable msg_ok "Stopped Service" - msg_info "Backing up Configuration and Data" - cp /opt/homelable/backend/.env /opt/homelable.env.bak - cp -r /opt/homelable/data /opt/homelable_data_bak - if [[ -f /opt/homelable/mcp/.env ]]; then - cp -a /opt/homelable/mcp/.env /opt/homelable-mcp.env.bak - fi - msg_ok "Backed up Configuration and Data" + create_backup /opt/homelable/backend/.env /opt/homelable/data /opt/homelable/mcp/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "homelable" "Pouzor/homelable" "tarball" "latest" "/opt/homelable" + restore_backup + msg_info "Updating Python Dependencies" cd /opt/homelable/backend $STD uv venv --clear /opt/homelable/backend/.venv @@ -57,17 +53,8 @@ function update_script() { $STD npm run build msg_ok "Rebuilt Frontend" - msg_info "Restoring Configuration and Data" - cp /opt/homelable.env.bak /opt/homelable/backend/.env - cp -r /opt/homelable_data_bak/. /opt/homelable/data/ - rm -f /opt/homelable.env.bak - rm -rf /opt/homelable_data_bak - msg_ok "Restored Configuration and Data" - - if [[ -f /opt/homelable-mcp.env.bak ]]; then + if [[ -f /opt/homelable/mcp/.env ]]; then msg_info "Restoring MCP Server" - cp -a /opt/homelable-mcp.env.bak /opt/homelable/mcp/.env - rm -f /opt/homelable-mcp.env.bak MCP_OWNER=$(stat -c '%U' /opt/homelable/mcp/.env) cd /opt/homelable/mcp $STD uv venv --clear /opt/homelable/mcp/.venv diff --git a/ct/homepage.sh b/ct/homepage.sh index eea6599de..44f31271a 100644 --- a/ct/homepage.sh +++ b/ct/homepage.sh @@ -37,20 +37,12 @@ function update_script() { systemctl stop homepage msg_ok "Stopped service" - msg_info "Creating Backup" - cp /opt/homepage/.env /opt/homepage.env - cp -r /opt/homepage/config /opt/homepage_config_backup - [[ -d /opt/homepage/public/images ]] && cp -r /opt/homepage/public/images /opt/homepage_images_backup - [[ -d /opt/homepage/public/icons ]] && cp -r /opt/homepage/public/icons /opt/homepage_icons_backup - msg_ok "Created Backup" + create_backup /opt/homepage/.env /opt/homepage/config + BACKUP_DIR=/opt/homepage-assets.backup create_backup /opt/homepage/public/images /opt/homepage/public/icons CLEAN_INSTALL=1 fetch_and_deploy_gh_release "homepage" "gethomepage/homepage" "tarball" - msg_info "Restoring Backup" - mv /opt/homepage.env /opt/homepage - rm -rf /opt/homepage/config - mv /opt/homepage_config_backup /opt/homepage/config - msg_ok "Restored Backup" + restore_backup msg_info "Updating Homepage (Patience)" RELEASE=$(get_latest_github_release "gethomepage/homepage") @@ -63,8 +55,7 @@ function update_script() { export NEXT_PUBLIC_BUILDTIME=$(curl -fsSL https://api.github.com/repos/gethomepage/homepage/releases/latest | jq -r '.published_at') export NEXT_TELEMETRY_DISABLED=1 $STD pnpm build - [[ -d /opt/homepage_images_backup ]] && mv /opt/homepage_images_backup /opt/homepage/public/images - [[ -d /opt/homepage_icons_backup ]] && mv /opt/homepage_icons_backup /opt/homepage/public/icons + BACKUP_DIR=/opt/homepage-assets.backup restore_backup msg_ok "Updated Homepage" msg_info "Starting service" diff --git a/ct/hoodik.sh b/ct/hoodik.sh index c81e3f32f..375403caf 100644 --- a/ct/hoodik.sh +++ b/ct/hoodik.sh @@ -36,16 +36,11 @@ function update_script() { systemctl stop hoodik msg_ok "Stopped Service" - msg_info "Backing up Configuration" - cp /opt/hoodik/.env /opt/hoodik.env.bak - msg_ok "Backed up Configuration" + create_backup /opt/hoodik/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "hoodik" "hudikhq/hoodik" "prebuild" "latest" "/opt/hoodik" "*$(arch_resolve "x86_64" "arm64").tar.gz" - msg_info "Restoring Configuration" - cp /opt/hoodik.env.bak /opt/hoodik/.env - rm -f /opt/hoodik.env.bak - msg_ok "Restored Configuration" + restore_backup msg_info "Starting Service" systemctl start hoodik diff --git a/ct/igotify.sh b/ct/igotify.sh index aad49d7fe..90eb43c73 100644 --- a/ct/igotify.sh +++ b/ct/igotify.sh @@ -35,16 +35,11 @@ function update_script() { systemctl stop igotify msg_ok "Stopped Service" - msg_info "Backing up Configuration" - cp /opt/igotify/.env /opt/igotify.env.bak - msg_ok "Backed up Configuration" + create_backup /opt/igotify/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "igotify" "androidseb25/iGotify-Notification-Assistent" "prebuild" "latest" "/opt/igotify" "iGotify-Notification-Service-$(arch_resolve)-v*.zip" - msg_info "Restoring Configuration" - cp /opt/igotify.env.bak /opt/igotify/.env - rm -f /opt/igotify.env.bak - msg_ok "Restored Configuration" + restore_backup msg_info "Starting Service" systemctl start igotify diff --git a/ct/immichframe.sh b/ct/immichframe.sh index 3abf19051..aae6885e4 100644 --- a/ct/immichframe.sh +++ b/ct/immichframe.sh @@ -35,9 +35,7 @@ function update_script() { systemctl stop immichframe msg_ok "Stopped Service" - msg_info "Backing up Configuration" - cp -r /opt/immichframe/Config /tmp/immichframe_config.bak - msg_ok "Backed up Configuration" + create_backup /opt/immichframe/Config CLEAN_INSTALL=1 fetch_and_deploy_gh_release "immichframe" "immichFrame/ImmichFrame" "tarball" "latest" "/tmp/immichframe" @@ -57,11 +55,8 @@ function update_script() { rm -rf /tmp/immichframe msg_ok "Setup ImmichFrame" - msg_info "Restoring Configuration" - cp -r /tmp/immichframe_config.bak/* /opt/immichframe/Config/ - rm -rf /tmp/immichframe_config.bak + restore_backup chown -R immichframe:immichframe /opt/immichframe - msg_ok "Restored Configuration" msg_info "Starting Service" diff --git a/ct/investbrain.sh b/ct/investbrain.sh index 0c2f48310..d0d9615fb 100644 --- a/ct/investbrain.sh +++ b/ct/investbrain.sh @@ -41,20 +41,14 @@ function update_script() { NODE_VERSION="22" setup_nodejs PG_VERSION="17" setup_postgresql - msg_info "Creating Backup" - rm -f /opt/.env.backup - rm -rf /opt/investbrain_backup - cp /opt/investbrain/.env /opt/.env.backup - cp -r /opt/investbrain/storage /opt/investbrain_backup - msg_ok "Created Backup" + create_backup /opt/investbrain/.env /opt/investbrain/storage - fetch_and_deploy_gh_release "Investbrain" "investbrainapp/investbrain" "tarball" "latest" "/opt/investbrain" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Investbrain" "investbrainapp/investbrain" "tarball" "latest" "/opt/investbrain" + + restore_backup msg_info "Updating Investbrain" cd /opt/investbrain - rm -rf /opt/investbrain/storage - cp /opt/.env.backup /opt/investbrain/.env - cp -r /opt/investbrain_backup/ /opt/investbrain/storage export COMPOSER_ALLOW_SUPERUSER=1 $STD /usr/local/bin/composer install --no-interaction --no-dev --optimize-autoloader $STD npm install @@ -69,7 +63,6 @@ function update_script() { $STD php artisan event:cache chown -R www-data:www-data /opt/investbrain chmod -R 775 /opt/investbrain/storage /opt/investbrain/bootstrap/cache - rm -rf /opt/.env.backup /opt/investbrain_backup msg_ok "Updated Investbrain" msg_info "Starting Services" diff --git a/ct/invoiceninja.sh b/ct/invoiceninja.sh index 79fcc2500..34cb88110 100644 --- a/ct/invoiceninja.sh +++ b/ct/invoiceninja.sh @@ -35,21 +35,11 @@ function update_script() { systemctl stop supervisor nginx php8.4-fpm msg_ok "Stopped Services" - msg_info "Creating Backup" - mkdir -p /tmp/invoiceninja_backup - cp /opt/invoiceninja/.env /tmp/invoiceninja_backup/ - cp -r /opt/invoiceninja/storage /tmp/invoiceninja_backup/ 2>/dev/null || true - cp -r /opt/invoiceninja/public/storage /tmp/invoiceninja_backup/public_storage 2>/dev/null || true - msg_ok "Created Backup" + create_backup /opt/invoiceninja/.env /opt/invoiceninja/storage /opt/invoiceninja/public/storage CLEAN_INSTALL=1 fetch_and_deploy_gh_release "invoiceninja" "invoiceninja/invoiceninja" "prebuild" "latest" "/opt/invoiceninja" "invoiceninja.tar.gz" - msg_info "Restoring Data" - cp /tmp/invoiceninja_backup/.env /opt/invoiceninja/ - cp -r /tmp/invoiceninja_backup/storage/* /opt/invoiceninja/storage/ 2>/dev/null || true - cp -r /tmp/invoiceninja_backup/public_storage/* /opt/invoiceninja/public/storage/ 2>/dev/null || true - rm -rf /tmp/invoiceninja_backup - msg_ok "Restored Data" + restore_backup msg_info "Running Migrations" cd /opt/invoiceninja diff --git a/ct/invoiceshelf.sh b/ct/invoiceshelf.sh index 5d2faa82d..fc5ae60f7 100644 --- a/ct/invoiceshelf.sh +++ b/ct/invoiceshelf.sh @@ -35,19 +35,11 @@ function update_script() { systemctl stop caddy msg_ok "Stopped Services" - msg_info "Backing up Data" - cp /opt/invoiceshelf/.env /opt/invoiceshelf.env.bak - cp -r /opt/invoiceshelf/storage /opt/invoiceshelf_storage_backup - msg_ok "Backed up Data" + create_backup /opt/invoiceshelf/.env /opt/invoiceshelf/storage CLEAN_INSTALL=1 fetch_and_deploy_gh_release "invoiceshelf" "InvoiceShelf/InvoiceShelf" "tarball" - msg_info "Restoring Data" - cp /opt/invoiceshelf.env.bak /opt/invoiceshelf/.env - rm -f /opt/invoiceshelf.env.bak - cp -r /opt/invoiceshelf_storage_backup/. /opt/invoiceshelf/storage - rm -rf /opt/invoiceshelf_storage_backup - msg_ok "Restored Data" + restore_backup msg_info "Updating Application" cd /opt/invoiceshelf diff --git a/ct/joplin-server.sh b/ct/joplin-server.sh index 3f229a517..6a6b99d89 100644 --- a/ct/joplin-server.sh +++ b/ct/joplin-server.sh @@ -36,9 +36,9 @@ function update_script() { systemctl stop joplin-server msg_ok "Stopped Services" - cp /opt/joplin-server/.env /opt + create_backup /opt/joplin-server/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "joplin-server" "laurent22/joplin" "tarball" - mv /opt/.env /opt/joplin-server + restore_backup msg_info "Updating Joplin-Server" cd /opt/joplin-server diff --git a/ct/jotty.sh b/ct/jotty.sh index af0e610d0..f59cf1da4 100644 --- a/ct/jotty.sh +++ b/ct/jotty.sh @@ -35,20 +35,12 @@ function update_script() { systemctl stop jotty msg_ok "Stopped Service" - msg_info "Backing up configuration & data" - cp /opt/jotty/.env /opt/app.env - [[ -d /opt/jotty/data ]] && mv /opt/jotty/data /opt/data - [[ -d /opt/jotty/config ]] && mv /opt/jotty/config /opt/config - msg_ok "Backed up configuration & data" + create_backup /opt/jotty/.env /opt/jotty/data /opt/jotty/config NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs CLEAN_INSTALL=1 fetch_and_deploy_gh_release "jotty" "fccview/jotty" "prebuild" "latest" "/opt/jotty" "jotty_*_prebuild.tar.gz" - msg_info "Restoring configuration & data" - mv /opt/app.env /opt/jotty/.env - [[ -d /opt/data ]] && mv /opt/data /opt/jotty/data - [[ -d /opt/config ]] && cp -a /opt/config/* /opt/jotty/config && rm -rf /opt/config - msg_ok "Restored configuration & data" + restore_backup msg_info "Starting Service" systemctl start jotty diff --git a/ct/kan.sh b/ct/kan.sh index 1817ab674..9dbd9da70 100644 --- a/ct/kan.sh +++ b/ct/kan.sh @@ -35,16 +35,11 @@ function update_script() { systemctl stop kan msg_ok "Stopped Service" - msg_info "Backing up Data" - cp /opt/kan/.env /opt/kan.env.bak - msg_ok "Backed up Data" + create_backup /opt/kan/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_tag "kan" "kanbn/kan" "latest" - msg_info "Restoring Configuration" - cp /opt/kan.env.bak /opt/kan/.env - rm -f /opt/kan.env.bak - msg_ok "Restored Configuration" + restore_backup msg_info "Building Application" cd /opt/kan diff --git a/ct/kima-hub.sh b/ct/kima-hub.sh index d43eead41..aa4d81654 100644 --- a/ct/kima-hub.sh +++ b/ct/kima-hub.sh @@ -37,18 +37,11 @@ function update_script() { systemctl stop kima-frontend kima-backend kima-analyzer kima-analyzer-clap msg_ok "Stopped Services" - msg_info "Backing up Data" - cp /opt/kima-hub/backend/.env /opt/kima-hub-backend-env.bak - cp /opt/kima-hub/frontend/.env /opt/kima-hub-frontend-env.bak - msg_ok "Backed up Data" + create_backup /opt/kima-hub/backend/.env /opt/kima-hub/frontend/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "kima-hub" "Chevron7Locked/kima-hub" "tarball" - msg_info "Restoring Data" - cp /opt/kima-hub-backend-env.bak /opt/kima-hub/backend/.env - cp /opt/kima-hub-frontend-env.bak /opt/kima-hub/frontend/.env - rm -f /opt/kima-hub-backend-env.bak /opt/kima-hub-frontend-env.bak - msg_ok "Restored Data" + restore_backup msg_info "Rebuilding Backend" cd /opt/kima-hub/backend diff --git a/ct/kitchenowl.sh b/ct/kitchenowl.sh index 362f29b2d..3ff4621c5 100644 --- a/ct/kitchenowl.sh +++ b/ct/kitchenowl.sh @@ -35,22 +35,14 @@ function update_script() { systemctl stop kitchenowl msg_ok "Stopped Service" - msg_info "Creating Backup" - mkdir -p /opt/kitchenowl_backup - cp -r /opt/kitchenowl/data /opt/kitchenowl_backup/ - cp -f /opt/kitchenowl/kitchenowl.env /opt/kitchenowl_backup/ - msg_ok "Created Backup" + create_backup /opt/kitchenowl/data /opt/kitchenowl/kitchenowl.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "kitchenowl" "TomBursch/kitchenowl" "tarball" "latest" "/opt/kitchenowl" rm -rf /opt/kitchenowl/web CLEAN_INSTALL=1 fetch_and_deploy_gh_release "kitchenowl-web" "TomBursch/kitchenowl" "prebuild" "latest" "/opt/kitchenowl/web" "kitchenowl_Web.tar.gz" - msg_info "Restoring data" + restore_backup sed -i 's/default=True/default=False/' /opt/kitchenowl/backend/wsgi.py - cp -r /opt/kitchenowl_backup/data /opt/kitchenowl/ - cp -f /opt/kitchenowl_backup/kitchenowl.env /opt/kitchenowl/ - rm -rf /opt/kitchenowl_backup - msg_ok "Restored data" msg_info "Updating KitchenOwl" cd /opt/kitchenowl/backend diff --git a/ct/koel.sh b/ct/koel.sh index 6936266c6..95878158e 100644 --- a/ct/koel.sh +++ b/ct/koel.sh @@ -35,21 +35,11 @@ function update_script() { systemctl stop nginx php8.4-fpm msg_ok "Stopped Services" - msg_info "Creating Backup" - mkdir -p /tmp/koel_backup - cp /opt/koel/.env /tmp/koel_backup/ - cp -r /opt/koel/storage /tmp/koel_backup/ 2>/dev/null || true - cp -r /opt/koel/public/img /tmp/koel_backup/ 2>/dev/null || true - msg_ok "Created Backup" + create_backup /opt/koel/.env /opt/koel/storage /opt/koel/public/img CLEAN_INSTALL=1 fetch_and_deploy_gh_release "koel" "koel/koel" "prebuild" "latest" "/opt/koel" "koel-*.tar.gz" - msg_info "Restoring Data" - cp /tmp/koel_backup/.env /opt/koel/ - cp -r /tmp/koel_backup/storage/* /opt/koel/storage/ 2>/dev/null || true - cp -r /tmp/koel_backup/img/* /opt/koel/public/img/ 2>/dev/null || true - rm -rf /tmp/koel_backup - msg_ok "Restored Data" + restore_backup msg_info "Running Migrations" cd /opt/koel diff --git a/ct/leantime.sh b/ct/leantime.sh index 2a0404078..d72610673 100644 --- a/ct/leantime.sh +++ b/ct/leantime.sh @@ -34,20 +34,18 @@ function update_script() { msg_info "Creating Backup" mariadb-dump leantime >"/opt/leantime_db_backup_$(date +%F).sql" tar -czf "/opt/leantime_backup_$(date +%F).tar.gz" "/opt/leantime" - mv /opt/leantime /opt/leantime_bak msg_ok "Backup Created" - fetch_and_deploy_gh_release "leantime" "Leantime/leantime" "prebuild" "latest" "/opt/leantime" Leantime*.tar.gz + create_backup /opt/leantime/config/.env - msg_info "Restoring Config & Permissions" - mv /opt/leantime_bak/config/.env /opt/leantime/config/.env + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "leantime" "Leantime/leantime" "prebuild" "latest" "/opt/leantime" Leantime*.tar.gz + + restore_backup + + msg_info "Setting Permissions" chown -R www-data:www-data "/opt/leantime" chmod -R 750 "/opt/leantime" - msg_ok "Restored Config & Permissions" - - msg_info "Removing Backup" - rm -rf /opt/leantime_bak - msg_ok "Removed Backup" + msg_ok "Set Permissions" msg_ok "Updated successfully!" fi exit diff --git a/ct/librechat.sh b/ct/librechat.sh index d6d62cca2..49fe16d58 100644 --- a/ct/librechat.sh +++ b/ct/librechat.sh @@ -35,12 +35,12 @@ function update_script() { systemctl stop librechat rag-api msg_ok "Stopped Services" - msg_info "Backing up Configuration" - cp /opt/librechat/.env /opt/librechat.env.bak - msg_ok "Backed up Configuration" + create_backup /opt/librechat/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_tag "librechat" "danny-avila/LibreChat" + restore_backup + msg_info "Installing Dependencies" cd /opt/librechat $STD npm ci @@ -52,11 +52,6 @@ function update_script() { $STD npm cache clean --force msg_ok "Built Frontend" - msg_info "Restoring Configuration" - cp /opt/librechat.env.bak /opt/librechat/.env - rm -f /opt/librechat.env.bak - msg_ok "Restored Configuration" - msg_info "Starting Services" systemctl start rag-api librechat msg_ok "Started Services" @@ -68,22 +63,17 @@ function update_script() { systemctl stop rag-api msg_ok "Stopped RAG API" - msg_info "Backing up RAG API Configuration" - cp /opt/rag-api/.env /opt/rag-api.env.bak - msg_ok "Backed up RAG API Configuration" + create_backup /opt/rag-api/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "rag-api" "danny-avila/rag_api" "tarball" + restore_backup + msg_info "Updating RAG API Dependencies" cd /opt/rag-api $STD .venv/bin/pip install -r requirements.lite.txt msg_ok "Updated RAG API Dependencies" - msg_info "Restoring RAG API Configuration" - cp /opt/rag-api.env.bak /opt/rag-api/.env - rm -f /opt/rag-api.env.bak - msg_ok "Restored RAG API Configuration" - msg_info "Starting RAG API" systemctl start rag-api msg_ok "Started RAG API" diff --git a/ct/linkding.sh b/ct/linkding.sh index b0ae20025..242194075 100644 --- a/ct/linkding.sh +++ b/ct/linkding.sh @@ -35,19 +35,12 @@ function update_script() { systemctl stop nginx linkding linkding-tasks msg_ok "Stopped Services" - msg_info "Backing up Data" - cp -r /opt/linkding/data /opt/linkding_data_backup - cp /opt/linkding/.env /opt/linkding_env_backup - msg_ok "Backed up Data" + create_backup /opt/linkding/data /opt/linkding/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "linkding" "sissbruecker/linkding" "tarball" - msg_info "Restoring Data" - cp -r /opt/linkding_data_backup/. /opt/linkding/data - cp /opt/linkding_env_backup /opt/linkding/.env - rm -rf /opt/linkding_data_backup /opt/linkding_env_backup + restore_backup ln -sf /usr/lib/$(arch_resolve "x86_64-linux-gnu" "aarch64-linux-gnu")/mod_icu.so /opt/linkding/libicu.so - msg_ok "Restored Data" msg_info "Updating LinkDing" cd /opt/linkding diff --git a/ct/linkwarden.sh b/ct/linkwarden.sh index 6fb08596b..13b92a01a 100644 --- a/ct/linkwarden.sh +++ b/ct/linkwarden.sh @@ -35,13 +35,11 @@ function update_script() { RUST_CRATES="monolith" setup_rust - msg_info "Backing up data" - mv /opt/linkwarden/.env /opt/.env - [ -d /opt/linkwarden/data ] && mv /opt/linkwarden/data /opt/data.bak - rm -rf /opt/linkwarden - msg_ok "Backed up data" + create_backup /opt/linkwarden/.env /opt/linkwarden/data - fetch_and_deploy_gh_release "linkwarden" "linkwarden/linkwarden" "tarball" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "linkwarden" "linkwarden/linkwarden" "tarball" + + restore_backup msg_info "Updating Linkwarden" cd /opt/linkwarden @@ -60,11 +58,9 @@ function update_script() { $STD yarn $STD npx playwright install-deps $STD npx playwright install - mv /opt/.env /opt/linkwarden/.env $STD yarn prisma:generate $STD yarn web:build $STD yarn prisma:deploy - [ -d /opt/data.bak ] && mv /opt/data.bak /opt/linkwarden/data rm -rf ~/.cargo/registry ~/.cargo/git ~/.cargo/.package-cache rm -rf /root/.cache/yarn rm -rf /opt/linkwarden/.next/cache diff --git a/ct/lobehub.sh b/ct/lobehub.sh index 1a856e428..241c85b4e 100644 --- a/ct/lobehub.sh +++ b/ct/lobehub.sh @@ -35,16 +35,11 @@ function update_script() { systemctl stop lobehub msg_ok "Stopped Services" - msg_info "Backing up Data" - cp /opt/lobehub/.env /opt/lobehub.env.bak - msg_ok "Backed up Data" + create_backup /opt/lobehub/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "lobehub" "lobehub/lobehub" "tarball" - msg_info "Restoring Configuration" - cp /opt/lobehub.env.bak /opt/lobehub/.env - rm -f /opt/lobehub.env.bak - msg_ok "Restored Configuration" + restore_backup msg_info "Building Application" cd /opt/lobehub diff --git a/ct/mail-archiver.sh b/ct/mail-archiver.sh index 944ed4336..b6796f432 100644 --- a/ct/mail-archiver.sh +++ b/ct/mail-archiver.sh @@ -36,10 +36,7 @@ function update_script() { systemctl stop mail-archiver msg_ok "Stopped Mail-Archiver" - msg_info "Creating Backup" - cp /opt/mail-archiver/appsettings.json /opt/mail-archiver/.env /opt/ - [[ -d /opt/mail-archiver/DataProtection-Keys ]] && cp -r /opt/mail-archiver/DataProtection-Keys /opt - msg_ok "Created Backup" + create_backup /opt/mail-archiver/appsettings.json /opt/mail-archiver/.env /opt/mail-archiver/DataProtection-Keys CLEAN_INSTALL=1 fetch_and_deploy_gh_release "mail-archiver" "s1t5/mail-archiver" "tarball" @@ -51,10 +48,7 @@ function update_script() { rm -rf /opt/mail-archiver-build msg_ok "Updated Mail-Archiver" - msg_info "Restoring Backup" - cp /opt/appsettings.json /opt/.env /opt/mail-archiver - [[ -d /opt/DataProtection-Keys ]] && cp -r /opt/DataProtection-Keys /opt/mail-archiver/ - msg_ok "Restored Backup" + restore_backup msg_info "Starting Mail-Archiver" systemctl start mail-archiver diff --git a/ct/manyfold.sh b/ct/manyfold.sh index 52c9b76c3..c1161b262 100644 --- a/ct/manyfold.sh +++ b/ct/manyfold.sh @@ -39,13 +39,15 @@ function update_script() { msg_info "Backing up Data" CURRENT_VERSION=$(grep -oP 'APP_VERSION=\K[^ ]+' /opt/manyfold/.env || echo "unknown") - cp -r /opt/manyfold/app/storage /opt/manyfold_storage_backup 2>/dev/null || true - cp -r /opt/manyfold/app/tmp /opt/manyfold_tmp_backup 2>/dev/null || true $STD tar -czf "/opt/manyfold_${CURRENT_VERSION}_backup.tar.gz" -C /opt/manyfold app msg_ok "Backed up Data" + create_backup /opt/manyfold/app/storage /opt/manyfold/app/tmp + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "manyfold" "manyfold3d/manyfold" "tarball" "latest" "/opt/manyfold/app" + restore_backup + msg_info "Configuring Manyfold" RUBY_INSTALL_VERSION=$(cat /opt/manyfold/app/.ruby-version) YARN_VERSION=$(grep '"packageManager":' /opt/manyfold/app/package.json | sed -E 's/.*"(yarn@[0-9\.]+)".*/\1/') @@ -55,14 +57,9 @@ function update_script() { RUBY_VERSION=${RUBY_INSTALL_VERSION} RUBY_INSTALL_RAILS="true" HOME=/home/manyfold setup_ruby - msg_info "Restoring Data" - rm -rf /opt/manyfold/app/{storage,tmp} - cp -r /opt/manyfold_storage_backup /opt/manyfold/app/storage 2>/dev/null || true - cp -r /opt/manyfold_tmp_backup /opt/manyfold/app/tmp 2>/dev/null || true + msg_info "Setting Permissions" chown -R manyfold:manyfold {/home/manyfold,/opt/manyfold} - chown -R manyfold:manyfold /opt/manyfold/app/storage /opt/manyfold/app/tmp /opt/manyfold/app/config - rm -rf /opt/manyfold_storage_backup /opt/manyfold_tmp_backup - msg_ok "Restored Data" + msg_ok "Set Permissions" msg_info "Installing Manyfold" diff --git a/ct/matomo.sh b/ct/matomo.sh index c2407600f..a1013e850 100644 --- a/ct/matomo.sh +++ b/ct/matomo.sh @@ -35,11 +35,7 @@ function update_script() { systemctl stop caddy msg_ok "Stopped Services" - msg_info "Backing up Data" - [[ -f /opt/matomo/config/config.ini.php ]] && cp /opt/matomo/config/config.ini.php /opt/matomo_config.bak - [[ -d /opt/matomo/misc/user ]] && cp -r /opt/matomo/misc/user /opt/matomo_user_backup - [[ -f /root/matomo.creds ]] && cp /root/matomo.creds /opt/matomo_db_creds.bak - msg_ok "Backed up Data" + create_backup /opt/matomo/config/config.ini.php /opt/matomo/misc/user /root/matomo.creds CLEAN_INSTALL=1 fetch_and_deploy_gh_release "matomo" "matomo-org/matomo" "prebuild" "latest" "/opt/matomo" "matomo-*.zip" @@ -53,20 +49,8 @@ function update_script() { chmod -R 755 /opt/matomo/tmp msg_ok "Set up Matomo" - msg_info "Restoring Data" - if [[ -f /opt/matomo_config.bak ]]; then - mkdir -p /opt/matomo/config - cp /opt/matomo_config.bak /opt/matomo/config/config.ini.php - fi - if [[ -d /opt/matomo_user_backup ]]; then - mkdir -p /opt/matomo/misc/user - cp -r /opt/matomo_user_backup/. /opt/matomo/misc/user - fi - [[ -f /opt/matomo_db_creds.bak ]] && cp /opt/matomo_db_creds.bak /root/matomo.creds - rm -f /opt/matomo_config.bak /opt/matomo_db_creds.bak - rm -rf /opt/matomo_user_backup + restore_backup chown -R www-data:www-data /opt/matomo - msg_ok "Restored Data" if [[ -f /opt/matomo/console ]]; then msg_info "Running Matomo database upgrade" diff --git a/ct/meilisearch.sh b/ct/meilisearch.sh index 110ba457e..cea79da6d 100644 --- a/ct/meilisearch.sh +++ b/ct/meilisearch.sh @@ -33,14 +33,13 @@ function update_script() { systemctl stop meilisearch-ui msg_ok "Stopped Meilisearch-UI" - cp /opt/meilisearch-ui/.env.local /tmp/.env.local.bak - rm -rf /opt/meilisearch-ui - fetch_and_deploy_gh_release "meilisearch-ui" "riccox/meilisearch-ui" "tarball" + create_backup /opt/meilisearch-ui/.env.local + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "meilisearch-ui" "riccox/meilisearch-ui" "tarball" + restore_backup msg_info "Configuring Meilisearch-UI" cd /opt/meilisearch-ui sed -i 's|const hash = execSync("git rev-parse HEAD").toString().trim();|const hash = "unknown";|' /opt/meilisearch-ui/vite.config.ts - mv /tmp/.env.local.bak /opt/meilisearch-ui/.env.local $STD pnpm install msg_ok "Configured Meilisearch-UI" diff --git a/ct/metube.sh b/ct/metube.sh index b00f4e833..71d767e5b 100644 --- a/ct/metube.sh +++ b/ct/metube.sh @@ -48,14 +48,11 @@ function update_script() { systemctl stop metube msg_ok "Stopped Service" - msg_info "Backing up Old Installation" - if [[ -d /opt/metube_bak ]]; then - rm -rf /opt/metube_bak - fi - mv /opt/metube /opt/metube_bak - msg_ok "Backup created" + create_backup /opt/metube/.env - fetch_and_deploy_gh_release "metube" "alexta69/metube" "tarball" "latest" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "metube" "alexta69/metube" "tarball" "latest" + + restore_backup msg_info "Building Frontend" cd /opt/metube/ui @@ -75,13 +72,6 @@ function update_script() { $STD uv sync msg_ok "Installed Backend" - msg_info "Restoring .env" - if [[ -f /opt/metube_bak/.env ]]; then - cp /opt/metube_bak/.env /opt/metube/.env - fi - rm -rf /opt/metube_bak - msg_ok "Restored .env" - if grep -q 'pipenv' /etc/systemd/system/metube.service; then msg_info "Patching systemd Service" cat </etc/systemd/system/metube.service diff --git a/ct/nametag.sh b/ct/nametag.sh index 69fd34777..b20f3f01b 100644 --- a/ct/nametag.sh +++ b/ct/nametag.sh @@ -35,15 +35,11 @@ function update_script() { systemctl stop nametag msg_ok "Stopped Service" - msg_info "Backing up Data" - cp /opt/nametag/.env /opt/nametag.env.bak - cp -r /opt/nametag/data /opt/nametag_data_bak - msg_ok "Backed up Data" + create_backup /opt/nametag/.env /opt/nametag/data CLEAN_INSTALL=1 fetch_and_deploy_gh_release "nametag" "mattogodoy/nametag" "tarball" "latest" "/opt/nametag" - # Restore .env BEFORE the build: CLEAN_INSTALL wiped it and the build sources it - cp /opt/nametag.env.bak /opt/nametag/.env + restore_backup msg_info "Rebuilding Application" cd /opt/nametag @@ -57,13 +53,6 @@ function update_script() { cp -r /opt/nametag/public /opt/nametag/.next/standalone/public msg_ok "Rebuilt Application" - msg_info "Restoring Data" - cp /opt/nametag.env.bak /opt/nametag/.env - cp -r /opt/nametag_data_bak/. /opt/nametag/data/ - rm -f /opt/nametag.env.bak - rm -rf /opt/nametag_data_bak - msg_ok "Restored Data" - msg_info "Running Migrations" cd /opt/nametag $STD npx prisma migrate deploy diff --git a/ct/overseerr.sh b/ct/overseerr.sh index 431f24231..2f3ff6d25 100644 --- a/ct/overseerr.sh +++ b/ct/overseerr.sh @@ -61,18 +61,16 @@ EOF systemctl stop overseerr msg_ok "Service stopped" - msg_info "Creating backup" - mv /opt/overseerr/config /opt/config_backup - msg_ok "Backup created" + create_backup /opt/overseerr/config fetch_and_deploy_gh_release "overseerr" "sct/overseerr" "tarball" - rm -rf /opt/overseerr/config + + restore_backup msg_info "Configuring ${APP} (Patience)" cd /opt/overseerr $STD yarn install $STD yarn build - mv /opt/config_backup /opt/overseerr/config msg_ok "Configured ${APP}" msg_info "Starting Service" diff --git a/ct/ownfoil.sh b/ct/ownfoil.sh index 6144dd7ab..8a1750bfb 100644 --- a/ct/ownfoil.sh +++ b/ct/ownfoil.sh @@ -35,23 +35,18 @@ function update_script() { systemctl stop ownfoil msg_ok "Stopped Service" - msg_info "Backing up Data" - cp -r /opt/ownfoil/app/config /opt/ownfoil_data_backup - msg_ok "Backed up Data" + create_backup /opt/ownfoil/app/config CLEAN_INSTALL=1 fetch_and_deploy_gh_release "ownfoil" "a1ex4/ownfoil" "tarball" + restore_backup + msg_info "Installing Dependencies" cd /opt/ownfoil $STD source .venv/bin/activate $STD uv pip install -r requirements.txt msg_ok "Installed Dependencies" - msg_info "Restoring Data" - cp -r /opt/ownfoil_data_backup /opt/ownfoil/app/config - rm -rf /opt/ownfoil_data_backup - msg_ok "Restored Data" - msg_info "Starting Service" systemctl start ownfoil msg_ok "Started Service" diff --git a/ct/paperclip.sh b/ct/paperclip.sh index 10c27de23..e888b1599 100644 --- a/ct/paperclip.sh +++ b/ct/paperclip.sh @@ -35,15 +35,11 @@ function update_script() { systemctl stop paperclip msg_ok "Stopped Service" - msg_info "Backing up Configuration" - cp /opt/paperclip-ai/.env /opt/paperclip.env.bak - msg_ok "Backed up Configuration" + create_backup /opt/paperclip-ai/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "paperclip-ai" "paperclipai/paperclip" "tarball" - msg_info "Restoring Configuration" - mv /opt/paperclip.env.bak /opt/paperclip-ai/.env - msg_ok "Restored Configuration" + restore_backup msg_info "Rebuilding Paperclip" cd /opt/paperclip-ai diff --git a/ct/papra.sh b/ct/papra.sh index 9e4fed221..81102942b 100644 --- a/ct/papra.sh +++ b/ct/papra.sh @@ -35,22 +35,18 @@ function update_script() { systemctl stop papra msg_ok "Stopped Service" - msg_info "Backing up Configuration" - if [[ -f /opt/papra/apps/papra-server/.env ]]; then - cp /opt/papra/apps/papra-server/.env /opt/papra_env.bak - fi - msg_ok "Backed up Configuration" + create_backup /opt/papra/apps/papra-server/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "papra" "papra-hq/papra" "tarball" + restore_backup + pnpm_version=$(grep -oP '"packageManager":\s*"pnpm@\K[^"]+' /opt/papra/package.json) NODE_VERSION="26" NODE_MODULE="pnpm@$pnpm_version" setup_nodejs msg_info "Building Application" cd /opt/papra - if [[ -f /opt/papra_env.bak ]]; then - cp /opt/papra_env.bak /opt/papra/apps/papra-server/.env - else + if [[ ! -f /opt/papra/apps/papra-server/.env ]]; then msg_warn ".env missing, regenerating from defaults" LOCAL_IP=$(hostname -I | awk '{print $1}') cat </opt/papra/apps/papra-server/.env @@ -74,7 +70,6 @@ EOF $STD pnpm --filter "@papra/app-client..." run build $STD pnpm --filter "@papra/app-server..." run build ln -sf /opt/papra/apps/papra-client/dist /opt/papra/apps/papra-server/public - rm -f /opt/papra_env.bak msg_ok "Built Application" msg_info "Starting Service" diff --git a/ct/patchmon.sh b/ct/patchmon.sh index 87fe75464..a8eebfe4d 100644 --- a/ct/patchmon.sh +++ b/ct/patchmon.sh @@ -72,9 +72,13 @@ EOF msg_ok "Migration complete!" fi + create_backup /opt/patchmon/.env + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "PatchMon" "PatchMon/PatchMon" "singlefile" "latest" "/opt/patchmon" "patchmon-server-linux-$(arch_resolve)" mv /opt/patchmon/PatchMon /opt/patchmon/patchmon-server + restore_backup + msg_info "Fetching PatchMon agent binaries" RELEASE=$(get_latest_github_release "PatchMon/PatchMon") [[ ! -d /opt/patchmon/agents ]] && mkdir -p /opt/patchmon/agents diff --git a/ct/postiz.sh b/ct/postiz.sh index bf488bf98..e74bef7fe 100644 --- a/ct/postiz.sh +++ b/ct/postiz.sh @@ -41,8 +41,6 @@ function update_script() { CLEAN_INSTALL=1 fetch_and_deploy_gh_release "postiz" "gitroomhq/postiz-app" "tarball" - # Restore BEFORE the build: CLEAN_INSTALL wiped /opt/postiz including .env, - # and the build below sources it restore_backup msg_info "Building Application" diff --git a/ct/powerdns.sh b/ct/powerdns.sh index f6dd45e70..a41fec84c 100644 --- a/ct/powerdns.sh +++ b/ct/powerdns.sh @@ -36,18 +36,14 @@ function update_script() { msg_ok "Updated PowerDNS" if check_for_gh_release "poweradmin" "poweradmin/poweradmin"; then - msg_info "Backing up Configuration" - cp /opt/poweradmin/config/settings.php /opt/poweradmin_settings.php.bak - cp /opt/poweradmin/powerdns.db /opt/poweradmin_powerdns.db.bak - msg_ok "Backed up Configuration" + create_backup /opt/poweradmin/config/settings.php /opt/poweradmin/powerdns.db CLEAN_INSTALL=1 fetch_and_deploy_gh_release "poweradmin" "poweradmin/poweradmin" "tarball" + restore_backup + msg_info "Updating Poweradmin" - cp /opt/poweradmin_settings.php.bak /opt/poweradmin/config/settings.php - cp /opt/poweradmin_powerdns.db.bak /opt/poweradmin/powerdns.db rm -rf /opt/poweradmin/install - rm -f /opt/poweradmin_settings.php.bak /opt/poweradmin_powerdns.db.bak chown -R www-data:pdns /opt/poweradmin chmod 775 /opt/poweradmin chown pdns:pdns /opt/poweradmin/powerdns.db diff --git a/ct/radicale.sh b/ct/radicale.sh index 98106b5d2..048379ef2 100644 --- a/ct/radicale.sh +++ b/ct/radicale.sh @@ -34,17 +34,12 @@ function update_script() { systemctl stop radicale msg_ok "Stopped service" - msg_info "Backing up users file" - cp /opt/radicale/users /opt/radicale_users_backup - msg_ok "Backed up users file" + create_backup /opt/radicale/users PYTHON_VERSION="3.13" setup_uv CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Radicale" "Kozea/Radicale" "tarball" "latest" "/opt/radicale" - msg_info "Restoring users file" - rm -f /opt/radicale/users - mv /opt/radicale_users_backup /opt/radicale/users - msg_ok "Restored users file" + restore_backup if grep -q 'start.sh' /etc/systemd/system/radicale.service; then sed -i -e '/^Description/i[Unit]' \ diff --git a/ct/reactive-resume.sh b/ct/reactive-resume.sh index e1da974db..04e376c8a 100644 --- a/ct/reactive-resume.sh +++ b/ct/reactive-resume.sh @@ -36,10 +36,12 @@ function update_script() { ensure_dependencies git - cp /opt/reactive-resume/.env /opt/reactive-resume.env.bak + create_backup /opt/reactive-resume/.env NODE_VERSION="24" NODE_MODULE="corepack" setup_nodejs CLEAN_INSTALL=1 fetch_and_deploy_gh_release "reactive-resume" "amruthpillai/reactive-resume" "tarball" "latest" "/opt/reactive-resume" + restore_backup + msg_info "Updating Reactive Resume (Patience)" cd /opt/reactive-resume export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 @@ -49,7 +51,6 @@ function update_script() { export NODE_ENV="production" $STD pnpm install --frozen-lockfile $STD pnpm run build - mv /opt/reactive-resume.env.bak /opt/reactive-resume/.env msg_ok "Updated Reactive Resume" msg_info "Updating Service" diff --git a/ct/rustypaste.sh b/ct/rustypaste.sh index d62ae7812..33b705fd4 100644 --- a/ct/rustypaste.sh +++ b/ct/rustypaste.sh @@ -35,18 +35,11 @@ function update_script() { systemctl stop rustypaste msg_ok "Stopped Services" - msg_info "Creating Backup" - tar -czf "/opt/rustypaste_backup_$(date +%F).tar.gz" /opt/rustypaste/upload 2>/dev/null || true - cp /opt/rustypaste/config.toml /tmp/rustypaste_config.toml.bak - msg_ok "Backup Created" + create_backup /opt/rustypaste/upload /opt/rustypaste/config.toml CLEAN_INSTALL=1 fetch_and_deploy_gh_release "rustypaste" "orhun/rustypaste" "prebuild" "latest" "/opt/rustypaste" "*x86_64-unknown-linux-gnu.tar.gz" - msg_info "Restoring Data" - mv /tmp/rustypaste_config.toml.bak /opt/rustypaste/config.toml - tar -xzf "/opt/rustypaste_backup_$(date +%F).tar.gz" -C /opt/rustypaste/upload 2>/dev/null || true - rm -rf /opt/rustypaste_backup_$(date +%F).tar.gz - msg_ok "Restored Data" + restore_backup msg_info "Starting Services" systemctl start rustypaste diff --git a/ct/scanopy.sh b/ct/scanopy.sh index e290dc367..f669bd75d 100644 --- a/ct/scanopy.sh +++ b/ct/scanopy.sh @@ -36,19 +36,16 @@ function update_script() { [[ -f /etc/systemd/system/scanopy-daemon.service ]] && systemctl stop scanopy-daemon msg_ok "Stopped services" - msg_info "Backing up configurations" - cp /opt/scanopy/.env /opt/scanopy.env - [[ -f /opt/scanopy/oidc.toml ]] && cp /opt/scanopy/oidc.toml /opt/scanopy.oidc.toml - msg_ok "Backed up configurations" + create_backup /opt/scanopy/.env /opt/scanopy/oidc.toml CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Scanopy" "scanopy/scanopy" "tarball" "latest" "/opt/scanopy" + restore_backup + ensure_dependencies pkg-config libssl-dev TOOLCHAIN="$(grep "channel" /opt/scanopy/backend/rust-toolchain.toml | awk -F\" '{print $2}')" RUST_TOOLCHAIN=$TOOLCHAIN setup_rust - [[ -f /opt/scanopy.env ]] && mv /opt/scanopy.env /opt/scanopy/.env - [[ -f /opt/scanopy.oidc.toml ]] && mv /opt/scanopy.oidc.toml /opt/scanopy/oidc.toml if ! grep -q "PUBLIC_URL" /opt/scanopy/.env; then sed -i "\|_PATH=|a\\scanopy_PUBLIC_URL=http://${LOCAL_IP}:60072" /opt/scanopy/.env fi diff --git a/ct/shelfmark.sh b/ct/shelfmark.sh index 25ce77236..e0ecbf45d 100644 --- a/ct/shelfmark.sh +++ b/ct/shelfmark.sh @@ -52,11 +52,12 @@ function update_script() { msg_ok "Updated FlareSolverr" fi - cp /opt/shelfmark/start.sh /opt/start.sh.bak + create_backup /opt/shelfmark/start.sh if command -v chromedriver &>/dev/null; then $STD apt remove -y chromium-driver fi CLEAN_INSTALL=1 fetch_and_deploy_gh_release "shelfmark" "calibrain/shelfmark" "tarball" "latest" "/opt/shelfmark" + restore_backup RELEASE_VERSION=$(cat "$HOME/.shelfmark") msg_info "Updating Shelfmark" @@ -74,7 +75,6 @@ function update_script() { else $STD uv sync --active --locked --no-default-groups fi - mv /opt/start.sh.bak /opt/shelfmark/start.sh msg_ok "Updated Shelfmark" msg_info "Starting Service(s)" diff --git a/ct/shlink.sh b/ct/shlink.sh index a9238fe49..df9f68e1e 100644 --- a/ct/shlink.sh +++ b/ct/shlink.sh @@ -35,19 +35,11 @@ function update_script() { systemctl stop shlink msg_ok "Stopped Service" - msg_info "Backing up Data" - cp /opt/shlink/.env /opt/shlink.env.bak - cp -r /opt/shlink/data /opt/shlink_data_backup - msg_ok "Backed up Data" + create_backup /opt/shlink/.env /opt/shlink/data CLEAN_INSTALL=1 fetch_and_deploy_gh_release "shlink" "shlinkio/shlink" "prebuild" "latest" "/opt/shlink" "shlink*_php8.5_dist.zip" - msg_info "Restoring Data" - cp /opt/shlink.env.bak /opt/shlink/.env - rm -f /opt/shlink.env.bak - cp -r /opt/shlink_data_backup/. /opt/shlink/data - rm -rf /opt/shlink_data_backup - msg_ok "Restored Data" + restore_backup msg_info "Updating Application" cd /opt/shlink diff --git a/ct/slskd.sh b/ct/slskd.sh index f3c34e412..e5e63bacb 100644 --- a/ct/slskd.sh +++ b/ct/slskd.sh @@ -36,19 +36,17 @@ function update_script() { [[ -f /etc/systemd/system/soularr.service ]] && systemctl stop soularr.timer soularr.service msg_ok "Stopped Service(s)" - msg_info "Backing up config" - cp /opt/slskd/config/slskd.yml /opt/slskd.yml.bak - msg_ok "Backed up config" + create_backup /opt/slskd/config/slskd.yml CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Slskd" "slskd/slskd" "prebuild" "latest" "/opt/slskd" "slskd-*-linux-$(arch_resolve "x64" "arm64").zip" - msg_info "Restoring config" - mv /opt/slskd.yml.bak /opt/slskd/config/slskd.yml + restore_backup + msg_info "Migrating config" # Migrate 0.25.0 breaking config key renames sed -i 's/^global:/transfers:/' /opt/slskd/config/slskd.yml sed -i 's/^integration:/integrations:/' /opt/slskd/config/slskd.yml - msg_ok "Restored config" + msg_ok "Migrated config" msg_info "Starting Service(s)" systemctl start slskd @@ -63,13 +61,11 @@ function update_script() { msg_ok "Stopped Timer and Service" fi - msg_info "Backing up Soularr config" - cp /opt/soularr/config.ini /opt/soularr_config.ini.bak - cp /opt/soularr/run.sh /opt/soularr_run.sh.bak - msg_ok "Backed up Soularr config" + create_backup /opt/soularr/config.ini /opt/soularr/run.sh PYTHON_VERSION="3.11" setup_uv CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Soularr" "mrusse/soularr" "tarball" "latest" "/opt/soularr" + restore_backup msg_info "Updating Soularr" cd /opt/soularr $STD uv venv -c venv @@ -78,11 +74,6 @@ function update_script() { deactivate msg_ok "Updated Soularr" - msg_info "Restoring Soularr config" - mv /opt/soularr_config.ini.bak /opt/soularr/config.ini - mv /opt/soularr_run.sh.bak /opt/soularr/run.sh - msg_ok "Restored Soularr config" - msg_info "Starting Soularr Timer" systemctl restart soularr.timer msg_ok "Started Soularr Timer" diff --git a/ct/solidtime.sh b/ct/solidtime.sh index e5675c178..f003086af 100644 --- a/ct/solidtime.sh +++ b/ct/solidtime.sh @@ -35,19 +35,11 @@ function update_script() { systemctl stop caddy msg_ok "Stopped Services" - msg_info "Backing up Data" - cp /opt/solidtime/.env /opt/solidtime.env.bak - cp -r /opt/solidtime/storage /opt/solidtime_storage_backup - msg_ok "Backed up Data" + create_backup /opt/solidtime/.env /opt/solidtime/storage CLEAN_INSTALL=1 fetch_and_deploy_gh_release "solidtime" "solidtime-io/solidtime" "tarball" - msg_info "Restoring Data" - cp /opt/solidtime.env.bak /opt/solidtime/.env - rm -f /opt/solidtime.env.bak - cp -r /opt/solidtime_storage_backup/. /opt/solidtime/storage - rm -rf /opt/solidtime_storage_backup - msg_ok "Restored Data" + restore_backup msg_info "Updating Application" cd /opt/solidtime diff --git a/ct/soulsync.sh b/ct/soulsync.sh index 6f016e56b..7a9d4d9c4 100644 --- a/ct/soulsync.sh +++ b/ct/soulsync.sh @@ -37,13 +37,12 @@ function update_script() { systemctl stop soulsync msg_ok "Stopped Service" - msg_info "Backing up Data" - mv /opt/soulsync/config /opt/soulsync-config.bak - mv /opt/soulsync/data /opt/soulsync-data.bak - msg_ok "Backed up Data" + create_backup /opt/soulsync/config /opt/soulsync/data CLEAN_INSTALL=1 fetch_and_deploy_gh_release "soulsync" "Nezreka/SoulSync" "tarball" + restore_backup + msg_info "Updating Python Dependencies" cd /opt/soulsync $STD uv venv --clear /opt/soulsync/.venv --python 3.11 @@ -56,9 +55,6 @@ function update_script() { $STD npm run build msg_ok "Built WebUI" - mv /opt/soulsync-config.bak /opt/soulsync/config - mv /opt/soulsync-data.bak /opt/soulsync/data - msg_info "Starting Service" systemctl start soulsync msg_ok "Started Service" diff --git a/ct/sparkyfitness.sh b/ct/sparkyfitness.sh index 98694622b..bed3befc5 100644 --- a/ct/sparkyfitness.sh +++ b/ct/sparkyfitness.sh @@ -35,18 +35,12 @@ function update_script() { systemctl stop sparkyfitness-server nginx msg_ok "Stopped Services" - msg_info "Backing up data" - mkdir -p /opt/sparkyfitness_backup - if [[ -d /opt/sparkyfitness/SparkyFitnessServer/uploads ]]; then - cp -r /opt/sparkyfitness/SparkyFitnessServer/uploads /opt/sparkyfitness_backup/ - fi - if [[ -d /opt/sparkyfitness/SparkyFitnessServer/backup ]]; then - cp -r /opt/sparkyfitness/SparkyFitnessServer/backup /opt/sparkyfitness_backup/ - fi - msg_ok "Backed up data" + create_backup /opt/sparkyfitness/SparkyFitnessServer/uploads /opt/sparkyfitness/SparkyFitnessServer/backup CLEAN_INSTALL=1 fetch_and_deploy_gh_release "sparkyfitness" "CodeWithCJ/SparkyFitness" "tarball" + restore_backup + PNPM_VERSION="$(jq -r '.packageManager | split("@")[1]' /opt/sparkyfitness/package.json)" NODE_VERSION="25" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs @@ -96,11 +90,6 @@ EOF systemctl daemon-reload msg_ok "Refreshed SparkyFitness Service" - msg_info "Restoring data" - cp -r /opt/sparkyfitness_backup/. /opt/sparkyfitness/SparkyFitnessServer/ - rm -rf /opt/sparkyfitness_backup - msg_ok "Restored data" - msg_info "Starting Services" $STD systemctl start sparkyfitness-server nginx msg_ok "Started Services" diff --git a/ct/spliit.sh b/ct/spliit.sh index d039b75d9..4b72e26f6 100755 --- a/ct/spliit.sh +++ b/ct/spliit.sh @@ -35,16 +35,11 @@ function update_script() { systemctl stop spliit msg_ok "Stopped Service" - msg_info "Backing up Configuration" - rm -f /opt/spliit.env.bak - cp /opt/spliit/.env /opt/spliit.env.bak - msg_ok "Backed up Configuration" + create_backup /opt/spliit/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "spliit" "spliit-app/spliit" "tarball" - msg_info "Restoring Configuration" - cp /opt/spliit.env.bak /opt/spliit/.env - msg_ok "Restored Configuration" + restore_backup msg_info "Building Application" cd /opt/spliit diff --git a/ct/spoolman.sh b/ct/spoolman.sh index c3c1a02b4..d7a9e15c9 100644 --- a/ct/spoolman.sh +++ b/ct/spoolman.sh @@ -36,18 +36,16 @@ function update_script() { systemctl stop spoolman msg_ok "Stopped Service" - msg_info "Creating Backup" - [ -d /opt/spoolman_bak ] && rm -rf /opt/spoolman_bak - mv /opt/spoolman /opt/spoolman_bak - msg_ok "Created Backup" + create_backup /opt/spoolman/.env - fetch_and_deploy_gh_release "spoolman" "Donkie/Spoolman" "prebuild" "latest" "/opt/spoolman" "spoolman.zip" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "spoolman" "Donkie/Spoolman" "prebuild" "latest" "/opt/spoolman" "spoolman.zip" + + restore_backup msg_info "Updating Spoolman" cd /opt/spoolman $STD uv sync --locked --no-install-project $STD uv sync --locked - cp /opt/spoolman_bak/.env /opt/spoolman sed -i 's|^ExecStart=.*|ExecStart=/usr/bin/bash /opt/spoolman/scripts/start.sh|' /etc/systemd/system/spoolman.service msg_ok "Updated Spoolman" diff --git a/ct/storyteller.sh b/ct/storyteller.sh index 0e49e0196..34c32a681 100644 --- a/ct/storyteller.sh +++ b/ct/storyteller.sh @@ -37,15 +37,11 @@ function update_script() { systemctl stop storyteller msg_ok "Stopped Service" - msg_info "Backing up Data" - cp /opt/storyteller/.env /opt/storyteller_env.bak - msg_ok "Backed up Data" + create_backup /opt/storyteller/.env CLEAN_INSTALL=1 fetch_and_deploy_gl_release "storyteller" "storyteller-platform/storyteller" "tarball" "latest" "/opt/storyteller" "" "web-v2" - msg_info "Restoring Configuration" - mv /opt/storyteller_env.bak /opt/storyteller/.env - msg_ok "Restored Configuration" + restore_backup msg_info "Rebuilding Storyteller" cd /opt/storyteller diff --git a/ct/tandoor.sh b/ct/tandoor.sh index b59803783..797061984 100644 --- a/ct/tandoor.sh +++ b/ct/tandoor.sh @@ -43,17 +43,15 @@ function update_script() { systemctl stop tandoor msg_ok "Stopped Service" - msg_info "Creating Backup" - mv /opt/tandoor /opt/tandoor.bak - msg_ok "Backup Created" + create_backup /opt/tandoor/config /opt/tandoor/api /opt/tandoor/mediafiles /opt/tandoor/staticfiles /opt/tandoor/.env NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs PYTHON_VERSION="3.13" setup_uv - fetch_and_deploy_gh_release "tandoor" "TandoorRecipes/recipes" "tarball" "latest" "/opt/tandoor" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "tandoor" "TandoorRecipes/recipes" "tarball" "latest" "/opt/tandoor" + + restore_backup msg_info "Updating Tandoor" - cp -r /opt/tandoor.bak/{config,api,mediafiles,staticfiles} /opt/tandoor/ - mv /opt/tandoor.bak/.env /opt/tandoor/.env cd /opt/tandoor $STD uv venv --clear .venv --python=python3 $STD uv pip install -r requirements.txt --python .venv/bin/python @@ -69,7 +67,6 @@ EOF cd /opt/tandoor $STD /opt/tandoor/.venv/bin/python manage.py migrate $STD /opt/tandoor/.venv/bin/python manage.py collectstatic --no-input - rm -rf /opt/tandoor.bak msg_ok "Updated Tandoor" msg_info "Starting Service" diff --git a/ct/tautulli.sh b/ct/tautulli.sh index 631c22733..841b5c79f 100644 --- a/ct/tautulli.sh +++ b/ct/tautulli.sh @@ -36,13 +36,12 @@ function update_script() { systemctl stop tautulli msg_ok "Stopped Service" - msg_info "Backing up config and database" - cp /opt/Tautulli/config.ini /opt/tautulli_config.ini.backup - cp /opt/Tautulli/tautulli.db /opt/tautulli.db.backup - msg_ok "Backed up config and database" + create_backup /opt/Tautulli/config.ini /opt/Tautulli/tautulli.db CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Tautulli" "Tautulli/Tautulli" "tarball" + restore_backup + msg_info "Updating Tautulli" cd /opt/Tautulli TAUTULLI_VERSION=$(get_latest_github_release "Tautulli/Tautulli" "false") @@ -55,12 +54,6 @@ function update_script() { $STD uv pip install "setuptools<81" msg_ok "Updated Tautulli" - msg_info "Restoring config and database" - cp /opt/tautulli_config.ini.backup /opt/Tautulli/config.ini - cp /opt/tautulli.db.backup /opt/Tautulli/tautulli.db - rm -f /opt/{tautulli_config.ini.backup,tautulli.db.backup} - msg_ok "Restored config and database" - msg_info "Starting Service" systemctl start tautulli msg_ok "Started Service" diff --git a/ct/teable.sh b/ct/teable.sh index 9588461fa..cd5281396 100644 --- a/ct/teable.sh +++ b/ct/teable.sh @@ -36,15 +36,11 @@ function update_script() { systemctl stop teable msg_ok "Stopped Service" - msg_info "Backing up Configuration" - cp /opt/teable/.env /opt/teable.env.bak - msg_ok "Backed up Configuration" + create_backup /opt/teable/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "teable" "teableio/teable" "tarball" - msg_info "Restoring Configuration" - mv /opt/teable.env.bak /opt/teable/.env - msg_ok "Restored Configuration" + restore_backup msg_info "Rebuilding Teable" cd /opt/teable diff --git a/ct/teddycloud.sh b/ct/teddycloud.sh index a0216d678..240edc533 100644 --- a/ct/teddycloud.sh +++ b/ct/teddycloud.sh @@ -34,16 +34,11 @@ function update_script() { systemctl stop teddycloud msg_ok "Stopped Service" - msg_info "Creating backup" - mv /opt/teddycloud /opt/teddycloud_bak - msg_ok "Backup created" + create_backup /opt/teddycloud/certs /opt/teddycloud/config /opt/teddycloud/data CLEAN_INSTALL=1 fetch_and_deploy_gh_release "teddycloud" "toniebox-reverse-engineering/teddycloud" "prebuild" "latest" "/opt/teddycloud" "teddycloud.amd64.release*.zip" - msg_info "Restoring data" - cp -R /opt/teddycloud_bak/certs /opt/teddycloud_bak/config /opt/teddycloud_bak/data /opt/teddycloud - rm -rf /opt/teddycloud_bak - msg_ok "Data restored" + restore_backup msg_info "Starting Service" systemctl start teddycloud diff --git a/ct/termix.sh b/ct/termix.sh index 28404f8ca..dbcb768b8 100644 --- a/ct/termix.sh +++ b/ct/termix.sh @@ -143,13 +143,12 @@ EOF fi msg_ok "Migrated Configuration" - msg_info "Backing up Data" - cp -r /opt/termix/data /opt/termix_data_backup - cp -r /opt/termix/uploads /opt/termix_uploads_backup - msg_ok "Backed up Data" + create_backup /opt/termix/data /opt/termix/uploads CLEAN_INSTALL=1 fetch_and_deploy_gh_release "termix" "Termix-SSH/Termix" "tarball" + restore_backup + msg_info "Recreating Directories" mkdir -p /opt/termix/html \ /opt/termix/nginx \ @@ -177,12 +176,6 @@ EOF $STD npm cache clean --force msg_ok "Set up Production Dependencies" - msg_info "Restoring Data" - cp -r /opt/termix_data_backup /opt/termix/data - cp -r /opt/termix_uploads_backup /opt/termix/uploads - rm -rf /opt/termix_data_backup /opt/termix_uploads_backup - msg_ok "Restored Data" - msg_info "Updating Frontend Files" rm -rf /opt/termix/html/* cp -r /opt/termix/dist/* /opt/termix/html/ 2>/dev/null || true diff --git a/ct/tianji.sh b/ct/tianji.sh index c1888724a..e62b3e94a 100644 --- a/ct/tianji.sh +++ b/ct/tianji.sh @@ -36,12 +36,11 @@ function update_script() { systemctl stop tianji msg_ok "Stopped Service" - msg_info "Backing up data" - cp /opt/tianji/src/server/.env /opt/.env - mv /opt/tianji /opt/tianji_bak - msg_ok "Backed up data" + create_backup /opt/tianji/src/server/.env - fetch_and_deploy_gh_release "tianji" "msgbyte/tianji" "tarball" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "tianji" "msgbyte/tianji" "tarball" + + restore_backup msg_info "Updating Tianji" cd /opt/tianji @@ -52,10 +51,8 @@ function update_script() { mkdir -p ./src/server/public cp -r ./geo ./src/server/public $STD pnpm build:server - mv /opt/.env /opt/tianji/src/server/.env cd src/server $STD pnpm db:migrate:apply - rm -rf /opt/tianji_bak rm -rf /opt/tianji/src/client rm -rf /opt/tianji/website rm -rf /opt/tianji/reporter diff --git a/ct/transmute.sh b/ct/transmute.sh index 4b107744d..9a93a7d68 100644 --- a/ct/transmute.sh +++ b/ct/transmute.sh @@ -40,13 +40,12 @@ function update_script() { systemctl stop transmute msg_ok "Stopped Service" - msg_info "Backing up Data" - cp /opt/transmute/backend/.env /opt/transmute.env.bak - cp -r /opt/transmute/data /opt/transmute_data_bak - msg_ok "Backed up Data" + create_backup /opt/transmute/backend/.env /opt/transmute/data CLEAN_INSTALL=1 fetch_and_deploy_gh_release "transmute" "transmute-app/transmute" "tarball" + restore_backup + msg_info "Updating Python Dependencies" cd /opt/transmute $STD uv venv --clear /opt/transmute/.venv @@ -59,12 +58,6 @@ function update_script() { $STD npm run build msg_ok "Rebuilt Frontend" - msg_info "Restoring Data" - cp /opt/transmute.env.bak /opt/transmute/backend/.env - cp -r /opt/transmute_data_bak/. /opt/transmute/data/ - rm -f /opt/transmute.env.bak - rm -rf /opt/transmute_data_bak - msg_ok "Restored Data" msg_info "Starting Service" systemctl start transmute diff --git a/ct/tubearchivist.sh b/ct/tubearchivist.sh index 9cb445b4a..099e42373 100644 --- a/ct/tubearchivist.sh +++ b/ct/tubearchivist.sh @@ -35,12 +35,12 @@ function update_script() { systemctl stop tubearchivist tubearchivist-celery tubearchivist-beat msg_ok "Stopped Services" - msg_info "Backing up Data" - cp /opt/tubearchivist/.env /opt/tubearchivist_env.bak - msg_ok "Backed up Data" + create_backup /opt/tubearchivist/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "tubearchivist" "tubearchivist/tubearchivist" "tarball" + restore_backup + msg_info "Rebuilding Tube Archivist" cd /opt/tubearchivist/frontend $STD npm install @@ -56,7 +56,6 @@ function update_script() { msg_ok "Rebuilt Tube Archivist" msg_info "Restoring Configuration" - mv /opt/tubearchivist_env.bak /opt/tubearchivist/.env sed -i 's|^TA_APP_DIR=/opt/tubearchivist$|TA_APP_DIR=/opt/tubearchivist/backend|' /opt/tubearchivist/.env sed -i 's|^TA_CACHE_DIR=/opt/tubearchivist/cache$|TA_CACHE_DIR=/cache|' /opt/tubearchivist/.env sed -i 's|^TA_MEDIA_DIR=/opt/tubearchivist/media$|TA_MEDIA_DIR=/youtube|' /opt/tubearchivist/.env diff --git a/ct/umami.sh b/ct/umami.sh index e612ca36f..5b3a0d21d 100644 --- a/ct/umami.sh +++ b/ct/umami.sh @@ -34,9 +34,9 @@ function update_script() { systemctl stop umami msg_ok "Stopped Service" - mv /opt/umami/.env /opt/.env.bak + create_backup /opt/umami/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "umami" "umami-software/umami" "tarball" - mv /opt/.env.bak /opt/umami/.env + restore_backup msg_info "Updating Umami" cd /opt/umami diff --git a/ct/umlautadaptarr.sh b/ct/umlautadaptarr.sh index 4d234e311..7ff93ba55 100644 --- a/ct/umlautadaptarr.sh +++ b/ct/umlautadaptarr.sh @@ -34,9 +34,9 @@ function update_script() { systemctl stop umlautadaptarr msg_ok "Stopped Service" - cp /opt/UmlautAdaptarr/appsettings.json /opt/UmlautAdaptarr/appsettings.json.bak + create_backup /opt/UmlautAdaptarr/appsettings.json fetch_and_deploy_gh_release "UmlautAdaptarr" "PCJones/Umlautadaptarr" "prebuild" "latest" "/opt/UmlautAdaptarr" "linux-x64.zip" - cp /opt/UmlautAdaptarr/appsettings.json.bak /opt/UmlautAdaptarr/appsettings.json + restore_backup msg_info "Starting Service" systemctl start umlautadaptarr diff --git a/ct/wallabag.sh b/ct/wallabag.sh index 40fbc066b..79e648432 100644 --- a/ct/wallabag.sh +++ b/ct/wallabag.sh @@ -38,16 +38,11 @@ function update_script() { systemctl stop nginx php8.3-fpm msg_ok "Stopped Services" - msg_info "Creating Backup" - cp /opt/wallabag/app/config/parameters.yml /tmp/wallabag_parameters.yml.bak - msg_ok "Created Backup" + create_backup /opt/wallabag/app/config/parameters.yml CLEAN_INSTALL=1 fetch_and_deploy_gh_release "wallabag" "wallabag/wallabag" "prebuild" "latest" "/opt/wallabag" "wallabag-*.tar.gz" - msg_info "Restoring Configuration" - cp /tmp/wallabag_parameters.yml.bak /opt/wallabag/app/config/parameters.yml - rm -f /tmp/wallabag_parameters.yml.bak - msg_ok "Restored Configuration" + restore_backup msg_info "Running Migrations" cd /opt/wallabag diff --git a/ct/wealthfolio.sh b/ct/wealthfolio.sh index ee672c795..859d496fa 100644 --- a/ct/wealthfolio.sh +++ b/ct/wealthfolio.sh @@ -39,19 +39,12 @@ function update_script() { systemctl stop wealthfolio msg_ok "Stopped Service" - msg_info "Backing up Data" - cp -r /opt/wealthfolio_data /opt/wealthfolio_data_backup - cp /opt/wealthfolio/.env /opt/wealthfolio_env_backup - msg_ok "Backed up Data" + create_backup /opt/wealthfolio_data /opt/wealthfolio/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "wealthfolio" "wealthfolio/wealthfolio" "prebuild" "latest" "/opt/wealthfolio" "wealthfolio-server-*-linux-amd64.tar.gz" - install -m 755 /opt/wealthfolio/wealthfolio-server /usr/local/bin/wealthfolio-server - msg_info "Restoring Data" - cp -r /opt/wealthfolio_data_backup/. /opt/wealthfolio_data - cp /opt/wealthfolio_env_backup /opt/wealthfolio/.env - rm -rf /opt/wealthfolio_data_backup /opt/wealthfolio_env_backup - msg_ok "Restored Data" + restore_backup + install -m 755 /opt/wealthfolio/wealthfolio-server /usr/local/bin/wealthfolio-server msg_info "Starting Service" systemctl start wealthfolio diff --git a/ct/web-check.sh b/ct/web-check.sh index d664014ac..0bd4fe4c2 100644 --- a/ct/web-check.sh +++ b/ct/web-check.sh @@ -34,16 +34,12 @@ function update_script() { systemctl stop web-check msg_ok "Stopped Service" - msg_info "Creating backup" - mv /opt/web-check/.env /opt - msg_ok "Created backup" + create_backup /opt/web-check/.env NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs CLEAN_INSTALL=1 fetch_and_deploy_gh_release "web-check" "Lissy93/web-check" "tarball" - msg_info "Restoring backup" - mv /opt/.env /opt/web-check - msg_ok "Restored backup" + restore_backup msg_info "Building Web-Check" cd /opt/web-check diff --git a/ct/webtrees.sh b/ct/webtrees.sh index d0fc40009..76d06b310 100644 --- a/ct/webtrees.sh +++ b/ct/webtrees.sh @@ -36,17 +36,12 @@ function update_script() { systemctl stop caddy php${PHP_VER}-fpm msg_ok "Stopped Service" - msg_info "Backing up Data" - cp -r /opt/webtrees/data /opt/webtrees_data_backup - msg_ok "Backed up Data" + create_backup /opt/webtrees/data CLEAN_INSTALL=1 fetch_and_deploy_gh_release "webtrees" "fisharebest/webtrees" "prebuild" "latest" "/opt/webtrees" "webtrees-*.zip" - msg_info "Restoring Data" - cp -r /opt/webtrees_data_backup/. /opt/webtrees/data - rm -rf /opt/webtrees_data_backup + restore_backup chown -R www-data:www-data /opt/webtrees - msg_ok "Restored Data" msg_info "Starting Service" systemctl start caddy php${PHP_VER}-fpm diff --git a/ct/wishlist.sh b/ct/wishlist.sh index 4aa4b2153..795320867 100644 --- a/ct/wishlist.sh +++ b/ct/wishlist.sh @@ -35,16 +35,13 @@ function update_script() { systemctl stop wishlist msg_ok "Stopped Service" - msg_info "Creating Backup" - mkdir -p /opt/wishlist-backup - cp /opt/wishlist/.env /opt/wishlist-backup/.env - cp -a /opt/wishlist/uploads /opt/wishlist-backup - cp -a /opt/wishlist/data /opt/wishlist-backup - msg_ok "Created Backup" + create_backup /opt/wishlist/.env /opt/wishlist/uploads /opt/wishlist/data CLEAN_INSTALL=1 fetch_and_deploy_gh_release "wishlist" "cmintey/wishlist" "tarball" LATEST_APP_VERSION=$(get_latest_github_release "cmintey/wishlist") + restore_backup + msg_info "Updating Wishlist" cd /opt/wishlist $STD pnpm install --frozen-lockfile @@ -56,13 +53,6 @@ function update_script() { $STD pnpm run build $STD pnpm prune --prod chmod +x /opt/wishlist/entrypoint.sh - - msg_info "Restoring Backup" - cp /opt/wishlist-backup/.env /opt/wishlist/.env - cp -a /opt/wishlist-backup/uploads /opt/wishlist - cp -a /opt/wishlist-backup/data /opt/wishlist - rm -rf /opt/wishlist-backup - msg_ok "Restored Backup" msg_ok "Updated Wishlist" msg_info "Starting Service" diff --git a/ct/writefreely.sh b/ct/writefreely.sh index c38b805c5..5fa50b097 100644 --- a/ct/writefreely.sh +++ b/ct/writefreely.sh @@ -35,19 +35,11 @@ function update_script() { systemctl stop writefreely msg_ok "Stopped Services" - msg_info "Creating Backup" - mkdir -p /tmp/writefreely_backup - cp /opt/writefreely/keys /tmp/writefreely_backup/ 2>/dev/null - cp /opt/writefreely/config.ini /tmp/writefreely_backup/ 2>/dev/null - msg_ok "Created Backup" + create_backup /opt/writefreely/keys /opt/writefreely/config.ini CLEAN_INSTALL=1 fetch_and_deploy_gh_release "writefreely" "writefreely/writefreely" "prebuild" "latest" "/opt/writefreely" "writefreely_*_linux_$(arch_resolve).tar.gz" - msg_info "Restoring Data" - cp /tmp/writefreely_backup/config.ini /opt/writefreely/ 2>/dev/null - cp /tmp/writefreely_backup/keys/* /opt/writefreely/keys/ 2>/dev/null - rm -rf /tmp/writefreely_backup - msg_ok "Restored Data" + restore_backup msg_info "Running Post-Update Tasks" cd /opt/writefreely diff --git a/ct/xyops.sh b/ct/xyops.sh index 2768a39ae..71e1cd0b5 100644 --- a/ct/xyops.sh +++ b/ct/xyops.sh @@ -35,13 +35,12 @@ function update_script() { systemctl stop xyops msg_ok "Stopped Service" - msg_info "Backing up Data" - cp -r /opt/xyops/data /opt/xyops_data_backup - cp -r /opt/xyops/conf /opt/xyops_conf_backup - msg_ok "Backed up Data" + create_backup /opt/xyops/data /opt/xyops/conf CLEAN_INSTALL=1 fetch_and_deploy_gh_release "xyops" "pixlcore/xyops" "tarball" + restore_backup + msg_info "Rebuilding Application" cd /opt/xyops $STD npm install @@ -49,12 +48,6 @@ function update_script() { chmod 644 /opt/xyops/node_modules/useragent-ng/lib/regexps.js msg_ok "Rebuilt Application" - msg_info "Restoring Data" - cp -r /opt/xyops_data_backup/. /opt/xyops/data - cp -r /opt/xyops_conf_backup/. /opt/xyops/conf - rm -rf /opt/xyops_data_backup /opt/xyops_conf_backup - msg_ok "Restored Data" - msg_info "Starting Service" systemctl start xyops msg_ok "Started Service" diff --git a/ct/yamtrack.sh b/ct/yamtrack.sh index 1537d8329..a33c45311 100644 --- a/ct/yamtrack.sh +++ b/ct/yamtrack.sh @@ -36,22 +36,17 @@ function update_script() { systemctl stop yamtrack yamtrack-celery msg_ok "Stopped Services" - msg_info "Backing up Data" - cp /opt/yamtrack/src/.env /opt/yamtrack_env.bak - msg_ok "Backed up Data" + create_backup /opt/yamtrack/src/.env CLEAN_INSTALL=1 fetch_and_deploy_gh_release "yamtrack" "FuzzyGrim/Yamtrack" "tarball" + restore_backup + msg_info "Installing Python Dependencies" cd /opt/yamtrack $STD uv sync --locked msg_ok "Installed Python Dependencies" - msg_info "Restoring Data" - cp /opt/yamtrack_env.bak /opt/yamtrack/src/.env - rm -f /opt/yamtrack_env.bak - msg_ok "Restored Data" - msg_info "Updating Yamtrack" cd /opt/yamtrack/src $STD /opt/yamtrack/.venv/bin/python manage.py migrate diff --git a/ct/yourls.sh b/ct/yourls.sh index 212290816..7dca65f6e 100644 --- a/ct/yourls.sh +++ b/ct/yourls.sh @@ -35,17 +35,12 @@ function update_script() { systemctl stop nginx msg_ok "Stopped Service" - msg_info "Backing up Configuration" - cp -r /opt/yourls/user /opt/yourls_user.bak - msg_ok "Backed up Configuration" + create_backup /opt/yourls/user CLEAN_INSTALL=1 fetch_and_deploy_gh_release "yourls" "YOURLS/YOURLS" "tarball" - chown -R www-data:www-data /opt/yourls - msg_info "Restoring Configuration" - cp -r /opt/yourls_user.bak/. /opt/yourls/user/ - rm -rf /opt/yourls_user.bak - msg_ok "Restored Configuration" + restore_backup + chown -R www-data:www-data /opt/yourls msg_info "Starting Service" systemctl start nginx diff --git a/ct/zerobyte.sh b/ct/zerobyte.sh index 1f65eeeea..ce86155b1 100644 --- a/ct/zerobyte.sh +++ b/ct/zerobyte.sh @@ -35,14 +35,14 @@ function update_script() { systemctl stop zerobyte msg_ok "Stopped Service" - msg_info "Backing up Configuration" - cp /opt/zerobyte/.env /opt/zerobyte.env.bak - msg_ok "Backed up Configuration" + create_backup /opt/zerobyte/.env ensure_dependencies git NODE_VERSION="24" setup_nodejs CLEAN_INSTALL=1 fetch_and_deploy_gh_release "zerobyte" "nicotsx/zerobyte" "tarball" + restore_backup + msg_info "Building Zerobyte" export NODE_OPTIONS="--max-old-space-size=3072" cd /opt/zerobyte @@ -50,11 +50,6 @@ function update_script() { $STD node ./node_modules/vite/bin/vite.js build msg_ok "Built Zerobyte" - msg_info "Restoring Configuration" - cp /opt/zerobyte.env.bak /opt/zerobyte/.env - rm -f /opt/zerobyte.env.bak - msg_ok "Restored Configuration" - msg_info "Starting Service" systemctl start zerobyte msg_ok "Started Service" diff --git a/ct/zigbee2mqtt.sh b/ct/zigbee2mqtt.sh index 2520d7d7b..714090477 100644 --- a/ct/zigbee2mqtt.sh +++ b/ct/zigbee2mqtt.sh @@ -37,24 +37,24 @@ function update_script() { msg_info "Creating Backup" ensure_dependencies zstd - mkdir -p /opt/{backups,z2m_backup} + mkdir -p /opt/backups BACKUP_VERSION="$(<"$HOME/.zigbee2mqtt")" BACKUP_FILE="/opt/backups/${APP}_backup_${BACKUP_VERSION}.tar.zst" $STD tar -cf - -C /opt zigbee2mqtt | zstd -q -o "$BACKUP_FILE" ls -t /opt/backups/${APP}_backup_*.tar.zst 2>/dev/null | tail -n +6 | xargs -r rm -f - mv /opt/zigbee2mqtt/data /opt/z2m_backup/data msg_ok "Backup Created (${BACKUP_VERSION})" + create_backup /opt/zigbee2mqtt/data + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Zigbee2MQTT" "Koenkk/zigbee2mqtt" "tarball" "latest" "/opt/zigbee2mqtt" + restore_backup + msg_info "Updating Zigbee2MQTT" - rm -rf /opt/zigbee2mqtt/data - mv /opt/z2m_backup/data /opt/zigbee2mqtt cd /opt/zigbee2mqtt grep -q "^packageImportMethod" ./pnpm-workspace.yaml 2>/dev/null || echo "packageImportMethod: hardlink" >>./pnpm-workspace.yaml $STD pnpm install --frozen-lockfile $STD pnpm build - rm -rf /opt/z2m_backup msg_ok "Updated Zigbee2MQTT" msg_info "Starting Service" From 71d69ea156837e244e30d668b3f29b49d92ec608 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:53:10 +0000 Subject: [PATCH 233/245] Update CHANGELOG.md (#15946) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7432a363c..80b3556b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -513,6 +513,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Pangolin: Bump Version to 1.21.0 [@MickLesk](https://github.com/MickLesk) ([#15938](https://github.com/community-scripts/ProxmoxVE/pull/15938)) + - #### 🔧 Refactor + + - Standardize CT update backup handling [@MickLesk](https://github.com/MickLesk) ([#15937](https://github.com/community-scripts/ProxmoxVE/pull/15937)) + ## 2026-07-20 ### 🚀 Updated Scripts From 3f7283ab6699772fab3f3021182a61d74e10a883 Mon Sep 17 00:00:00 2001 From: MickLesk Date: Tue, 21 Jul 2026 22:49:58 +0200 Subject: [PATCH 234/245] Clear RETURN traps after temp cleanup Updates temp-file and temp-dir cleanup traps in `misc/tools.func` to unset the `RETURN` trap after running cleanup. This prevents stale RETURN traps from leaking into later function returns and avoids repeated or unintended cleanup behavior in nested helper flows. --- misc/tools.func | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/misc/tools.func b/misc/tools.func index a45667e66..77143b413 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -2689,7 +2689,7 @@ fetch_and_deploy_gh_tag() { local tmpdir tmpdir=$(mktemp -d) || return 1 - trap 'rm -rf "$tmpdir"' RETURN + trap 'rm -rf "$tmpdir"; trap - RETURN' RETURN local tarball_url="https://github.com/${repo}/archive/refs/tags/${version}.tar.gz" local filename="${app_lc}-${version}.tar.gz" @@ -2866,7 +2866,7 @@ fetch_and_deploy_gl_tag() { local tmpdir tmpdir=$(mktemp -d) || return 1 - trap 'rm -rf "$tmpdir"' RETURN + trap 'rm -rf "$tmpdir"; trap - RETURN' RETURN local filename="${app_lc}-${version_safe}.tar.gz" msg_info "Fetching GitLab tag: ${app} (${resolved_tag})" @@ -2974,7 +2974,7 @@ check_for_gh_release() { local gh_check_json="" gh_check_json=$(mktemp /tmp/tools-gh-check-XXXXXX) || return 73 - trap 'rm -f "${gh_check_json:-}"' RETURN + trap 'rm -f "${gh_check_json:-}"; trap - RETURN' RETURN # Build auth header if token is available local header_args=() @@ -3574,7 +3574,7 @@ fetch_and_deploy_codeberg_release() { local tmpdir tmpdir=$(mktemp -d) || return 252 - trap 'rm -rf "$tmpdir"' RETURN + trap 'rm -rf "$tmpdir"; trap - RETURN' RETURN msg_info "Fetching Codeberg tag: $app ($tag_name)" @@ -3616,7 +3616,7 @@ fetch_and_deploy_codeberg_release() { local codeberg_rel_json codeberg_rel_json=$(mktemp /tmp/tools-codeberg-rel-XXXXXX) || return 73 - trap 'rm -f "$codeberg_rel_json"; rm -rf "${tmpdir:-}" "${unpack_tmp:-}"' RETURN + trap 'rm -f "$codeberg_rel_json"; rm -rf "${tmpdir:-}" "${unpack_tmp:-}"; trap - RETURN' RETURN local attempt=0 success=false resp http_code @@ -4113,7 +4113,7 @@ fetch_and_deploy_gh_release() { local tmpdir tmpdir=$(mktemp -d) || return 1 - trap 'rm -rf "$tmpdir" "${unpack_tmp:-}"' RETURN + trap 'rm -rf "$tmpdir" "${unpack_tmp:-}"; trap - RETURN' RETURN local filename="" url="" msg_info "Fetching GitHub release: $app ($version)" @@ -9218,7 +9218,7 @@ fetch_and_deploy_from_url() { msg_error "Failed to create temporary directory" return 252 } - trap 'rm -rf "$tmpdir" "${unpack_tmp:-}"' RETURN + trap 'rm -rf "$tmpdir" "${unpack_tmp:-}"; trap - RETURN' RETURN curl -fsSL -o "$tmpdir/$filename" "$url" || { msg_error "Download failed: $url" @@ -9434,7 +9434,7 @@ check_for_gl_release() { local gl_check_json gl_check_json=$(mktemp /tmp/tools-gl-check-XXXXXX) || return 73 - trap 'rm -f "$gl_check_json"' RETURN + trap 'rm -f "$gl_check_json"; trap - RETURN' RETURN local repo_encoded repo_encoded=$(printf '%s' "$source" | sed 's|/|%2F|g') @@ -9724,7 +9724,7 @@ fetch_and_deploy_gl_release() { local gl_rel_json gl_rel_json=$(mktemp /tmp/tools-gl-rel-XXXXXX) || return 73 - trap 'rm -f "$gl_rel_json"; rm -rf "${tmpdir:-}" "${unpack_tmp:-}"' RETURN + trap 'rm -f "$gl_rel_json"; rm -rf "${tmpdir:-}" "${unpack_tmp:-}"; trap - RETURN' RETURN local repo_encoded repo_encoded=$(printf '%s' "$repo" | sed 's|/|%2F|g') From e0df8a80bfef92f1cf4719f487b74525030a5dad Mon Sep 17 00:00:00 2001 From: MickLesk Date: Tue, 21 Jul 2026 23:27:22 +0200 Subject: [PATCH 235/245] Don't destroy container on install-recovery menu read failure read -t returns >128 on a real timeout, but a lower/plain error code on a genuine read failure (e.g. broken/closed stdin, I/O error) - these were treated identically as "no response", so a user whose keystroke failed to be captured (e.g. a transient stdin I/O error) got their container silently destroyed instead of kept. Only auto-remove on an actual timeout; on a hard read failure, keep the container (reversible) and tell the user how to remove it manually. --- misc/build.func | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/misc/build.func b/misc/build.func index 0a8319cbd..29c88ed88 100644 --- a/misc/build.func +++ b/misc/build.func @@ -5140,7 +5140,10 @@ EOF echo -en "${YW}Select option [1-${max_option}] (default: 1, auto-remove in 60s): ${CL}" local response="" - if read -t 60 -r response; then + local read_rc + read -t 60 -r response + read_rc=$? + if [[ $read_rc -eq 0 ]]; then case "${response:-1}" in 1) # Remove container @@ -5359,13 +5362,20 @@ EOF fi ;; esac - else + elif [[ $read_rc -gt 128 ]]; then # Timeout - auto-remove echo "" msg_info "No response - removing container ${CTID}" pct stop "$CTID" &>/dev/null || true pct destroy "$CTID" &>/dev/null || true msg_ok "Container ${CTID} removed" + else + # read itself failed (e.g. broken/closed stdin, I/O error) rather than + # timing out - don't guess and destroy the container on a read we + # couldn't actually capture; keep it since that's the reversible choice. + echo "" + msg_error "Could not read your response (stdin error) - keeping container ${CTID} for safety." + msg_error "Remove it manually if not needed: pct destroy ${CTID}" fi # Force one final status update attempt after cleanup From fe01d670f6ca297fb45f40cac048832fc9b07b3e Mon Sep 17 00:00:00 2001 From: MickLesk Date: Tue, 21 Jul 2026 23:32:19 +0200 Subject: [PATCH 236/245] Don't destroy container on error_handler recovery-prompt read failure Same bug as build.func's install-recovery menu: this "Remove broken container?" prompt treated a hard read failure (broken/closed stdin, I/O error) identically to a real 60s timeout, defaulting to pct destroy either way. Only auto-remove on an actual timeout (read_rc > 128); on a genuine read failure, keep the container instead of guessing and destroying it. --- misc/error_handler.func | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/misc/error_handler.func b/misc/error_handler.func index 2a6ec8fb3..f0d909a92 100644 --- a/misc/error_handler.func +++ b/misc/error_handler.func @@ -497,7 +497,10 @@ error_handler() { fi local response="" - if read -t 60 -r response; then + local read_rc + read -t 60 -r response + read_rc=$? + if [[ $read_rc -eq 0 ]]; then if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then echo "" if declare -f msg_info >/dev/null 2>&1; then @@ -520,7 +523,7 @@ error_handler() { echo -e "${YW}Container ${CTID} kept for debugging${CL}" fi fi - else + elif [[ $read_rc -gt 128 ]]; then # Timeout - auto-remove echo "" if declare -f msg_info >/dev/null 2>&1; then @@ -535,6 +538,18 @@ error_handler() { else echo -e "${GN}✔${CL} Container ${CTID} removed" fi + else + # read itself failed (e.g. broken/closed stdin, I/O error) rather than + # timing out - don't guess and destroy the container on a read we + # couldn't actually capture; keep it since that's the reversible choice. + echo "" + if declare -f msg_error >/dev/null 2>&1; then + msg_error "Could not read your response (stdin error) - keeping container ${CTID} for safety." + msg_error "Remove it manually if not needed: pct destroy ${CTID}" + else + echo -e "${YW}Could not read your response (stdin error) - keeping container ${CTID} for safety.${CL}" + echo -e "${YW}Remove it manually if not needed: pct destroy ${CTID}${CL}" + fi fi fi fi From b2d54f2a7238da57f378d6c1da6207814043fa29 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Wed, 22 Jul 2026 08:18:01 +0200 Subject: [PATCH 237/245] Nametag: fix missing tailwindcss module (#15955) * Fix Nametag update failing with missing tailwindcss module npm ci during update ran with devDependencies omitted, likely because NODE_ENV=production was already present in the environment by then (npm's documented default: omit=dev when NODE_ENV=production). Since @tailwindcss/postcss is a devDependency, the subsequent `npm run build` failed with "Cannot find module '@tailwindcss/postcss'". Force devDeps to be installed regardless of NODE_ENV via --include=dev. * Apply --include=dev to fresh installs too, for parity with update fix Couldn't confirm within this repo why devDependencies would only be omitted on update and not on a fresh install - create_backup/ restore_backup are plain file copies and nothing in tools.func sets NODE_ENV or writes an .npmrc. Since npm ci runs before .env is sourced in both scripts, apply the same explicit --include=dev to the installer as defense-in-depth against the same class of failure. --- ct/nametag.sh | 2 +- install/nametag-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ct/nametag.sh b/ct/nametag.sh index b20f3f01b..01fa08b45 100644 --- a/ct/nametag.sh +++ b/ct/nametag.sh @@ -43,7 +43,7 @@ function update_script() { msg_info "Rebuilding Application" cd /opt/nametag - $STD npm ci + $STD npm ci --include=dev set -a source /opt/nametag/.env set +a diff --git a/install/nametag-install.sh b/install/nametag-install.sh index 8f952153b..4c285a2cf 100644 --- a/install/nametag-install.sh +++ b/install/nametag-install.sh @@ -20,7 +20,7 @@ fetch_and_deploy_gh_release "nametag" "mattogodoy/nametag" "tarball" "latest" "/ msg_info "Setting up Application" cd /opt/nametag -$STD npm ci +$STD npm ci --include=dev DATABASE_URL="postgresql://${PG_DB_USER}:${PG_DB_PASS}@127.0.0.1:5432/${PG_DB_NAME}" $STD npx prisma generate DATABASE_URL="postgresql://${PG_DB_USER}:${PG_DB_PASS}@127.0.0.1:5432/${PG_DB_NAME}" $STD npx prisma migrate deploy msg_ok "Set up Application" From e4d0e743e44d746d54d707f64dc79e15df4d3343 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Wed, 22 Jul 2026 08:18:12 +0200 Subject: [PATCH 238/245] Preserve default mongod.conf when configuring Anytype replica set (#15954) Overwriting /etc/mongod.conf with only the replication block wiped out storage.dbPath from the mongodb-org package default, so mongod fell back to its compiled-in /data/db path, which was never created. Append the replication section instead of replacing the file. --- install/anytype-server-install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/anytype-server-install.sh b/install/anytype-server-install.sh index 44357de95..8c36f0288 100644 --- a/install/anytype-server-install.sh +++ b/install/anytype-server-install.sh @@ -16,7 +16,7 @@ update_os setup_mongodb msg_info "Configuring MongoDB Replica Set" -cat </etc/mongod.conf +cat <>/etc/mongod.conf replication: replSetName: "rs0" From a339c08bca0fbd0a4a8742c55022e3672ae7c7dc Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Wed, 22 Jul 2026 08:18:21 +0200 Subject: [PATCH 239/245] InvoiceNinja: preserve and Re-download snappdf Chromium (#15956) * Re-download snappdf Chromium after Invoice Ninja updates update_script() redeploys /opt/invoiceninja via CLEAN_INSTALL, which wipes vendor/beganovich/snappdf/versions. That path isn't covered by create_backup/restore_backup, so the Chromium binary snappdf needs for PDF generation was missing after every update, breaking PDFs (#15942). Re-run the same "vendor/bin/snappdf download" step the install script already does, right after the backup is restored. * Back up snappdf's Chromium download to avoid re-fetching on every update vendor/bin/snappdf download is idempotent: it exits immediately without downloading if versions/revision.txt already exists, and PDF generation doesn't check that version against the installed snappdf package - it just uses whatever's in versions/. So the cached Chromium build survives just fine across an update via the existing backup/restore mechanism. Add vendor/beganovich/snappdf/versions to create_backup/restore_backup; keep the snappdf download call only as a safety net for when the backup doesn't have it yet (e.g. the first update after this fix ships). * Remove explanatory comment --- ct/invoiceninja.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ct/invoiceninja.sh b/ct/invoiceninja.sh index 34cb88110..d24034c66 100644 --- a/ct/invoiceninja.sh +++ b/ct/invoiceninja.sh @@ -35,12 +35,18 @@ function update_script() { systemctl stop supervisor nginx php8.4-fpm msg_ok "Stopped Services" - create_backup /opt/invoiceninja/.env /opt/invoiceninja/storage /opt/invoiceninja/public/storage + create_backup /opt/invoiceninja/.env /opt/invoiceninja/storage /opt/invoiceninja/public/storage /opt/invoiceninja/vendor/beganovich/snappdf/versions CLEAN_INSTALL=1 fetch_and_deploy_gh_release "invoiceninja" "invoiceninja/invoiceninja" "prebuild" "latest" "/opt/invoiceninja" "invoiceninja.tar.gz" restore_backup + msg_info "Verifying Chromium for PDF Generation" + cd /opt/invoiceninja + $STD ./vendor/bin/snappdf download + chown -R www-data:www-data /opt/invoiceninja/vendor/beganovich/snappdf/versions + msg_ok "Verified Chromium for PDF Generation" + msg_info "Running Migrations" cd /opt/invoiceninja $STD php artisan migrate --force From 04dbf976720df11433f31382c1d86e42a3383e7d Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Wed, 22 Jul 2026 06:18:22 +0000 Subject: [PATCH 240/245] Update CHANGELOG.md (#15962) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80b3556b3..d1fa6df9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -505,6 +505,15 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit +## 2026-07-22 + +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - Anytype: preserve default mongod.conf when configuring Anytype replica set [@MickLesk](https://github.com/MickLesk) ([#15954](https://github.com/community-scripts/ProxmoxVE/pull/15954)) + - Nametag: fix missing tailwindcss module [@MickLesk](https://github.com/MickLesk) ([#15955](https://github.com/community-scripts/ProxmoxVE/pull/15955)) + ## 2026-07-21 ### 🚀 Updated Scripts From 6b068bc9bfdb34d3e36f050095fe6f80e2a4c96a Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Wed, 22 Jul 2026 06:18:42 +0000 Subject: [PATCH 241/245] Update CHANGELOG.md (#15963) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1fa6df9e..d02fb7130 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -511,6 +511,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - #### 🐞 Bug Fixes + - InvoiceNinja: preserve and Re-download snappdf Chromium [@MickLesk](https://github.com/MickLesk) ([#15956](https://github.com/community-scripts/ProxmoxVE/pull/15956)) - Anytype: preserve default mongod.conf when configuring Anytype replica set [@MickLesk](https://github.com/MickLesk) ([#15954](https://github.com/community-scripts/ProxmoxVE/pull/15954)) - Nametag: fix missing tailwindcss module [@MickLesk](https://github.com/MickLesk) ([#15955](https://github.com/community-scripts/ProxmoxVE/pull/15955)) From d5f9db35f3d4bca4220e567fcb9a2f13ecfa5a3d Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Wed, 22 Jul 2026 08:55:32 +0200 Subject: [PATCH 242/245] core: add OS mismatch guard for container updates (#15948) * core: add OS mismatch guard for container updates Introduces `check_container_os_guard()` to compare the container's `/etc/os-release` against the script's recommended `var_os`/`var_version` before running updates. On mismatch, interactive runs now prompt to continue (default no), while silent/headless runs abort to avoid partial breakage on unsupported bases. A bypass flag (`var_ignore_os_mismatch=1|yes|true|on`) was added, and the guard is wired into all update entry paths in `start()`. * Refine OS mismatch update guidance Updates the OS version mismatch prompts in `check_container_os_guard()` to recommend upgrading the existing container OS to the target release before rerunning the update, instead of recreating the container. The skip/error path now uses the same guidance while still documenting `var_ignore_os_mismatch=1` as an override. * Add persistent OS mismatch bypass option Enhances `check_container_os_guard` to support a persistent opt-out for OS version mismatch checks. The prompt now uses a 3-option whiptail menu (cancel, continue once, continue and remember), and stores ignored targets in `/root/.helper-scripts-ignoreOSupdate` so users are re-prompted when a newer recommended OS appears. Messaging was also tightened to explicitly warn that bypassing may break updates and is unsupported. * switch to /usr/local --- misc/build.func | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/misc/build.func b/misc/build.func index 29c88ed88..9b12cc564 100644 --- a/misc/build.func +++ b/misc/build.func @@ -3831,6 +3831,78 @@ runtime_script_status_guard() { return 0 } +# ------------------------------------------------------------------------------ +# check_container_os_guard() +# +# - Compares the container OS (/etc/os-release) with the script's recommended +# var_os/var_version before running update_script +# - On mismatch: interactive runs ask whether to continue (default: no); +# headless runs (PHS_SILENT=1 / no tty) abort instead of updating on an +# unsupported base and leaving the app broken mid-update +# - Bypass via var_ignore_os_mismatch=1|yes|true|on (still warns, but continues) +# ------------------------------------------------------------------------------ +check_container_os_guard() { + local rec_os="${var_os:-}" rec_ver="${var_version:-}" + rec_os="${rec_os,,}" + [[ -z "$rec_os" || -z "$rec_ver" ]] && return 0 + [[ -r /etc/os-release ]] || return 0 + + local cur_os cur_ver + cur_os="$(. /etc/os-release 2>/dev/null; echo "${ID:-}")" + cur_ver="$(. /etc/os-release 2>/dev/null; echo "${VERSION_ID:-}")" + cur_os="${cur_os,,}" + [[ -z "$cur_os" || -z "$cur_ver" ]] && return 0 + + # Exact version or prefix on a dot boundary (e.g. alpine 3.22 matches 3.22.1) + if [[ "$cur_os" == "$rec_os" ]] && [[ "$cur_ver" == "$rec_ver" || "$cur_ver" == "$rec_ver".* ]]; then + return 0 + fi + + case "${var_ignore_os_mismatch:-}" in + 1 | yes | true | on) + msg_warn "Container OS is ${cur_os} ${cur_ver} but the script recommends ${rec_os} ${rec_ver} — continuing via var_ignore_os_mismatch (may break, no support)." + return 0 + ;; + esac + + # Persistent opt-out: stores the ignored target version, so the question + # comes back once the script targets a newer OS again + local ignore_file="/usr/local/community-scripts/ignore-os-mismatch" + if [[ -f "$ignore_file" && "$(cat "$ignore_file" 2>/dev/null)" == "${rec_os} ${rec_ver}" ]]; then + msg_warn "Container OS is ${cur_os} ${cur_ver} but the script recommends ${rec_os} ${rec_ver} — continuing (previously ignored via ${ignore_file}, may break, no support)." + return 0 + fi + + if [[ "${PHS_SILENT:-0}" != "1" ]] && command -v whiptail &>/dev/null && [ -t 0 ] && [[ "$TERM" != "dumb" ]]; then + local choice + choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "OS VERSION MISMATCH" --menu \ + "This container runs ${cur_os} ${cur_ver}, but this script now targets ${rec_os} ${rec_ver}.\n\nUpdating on the older base OS may fail or leave ${APP:-the application} broken (e.g. required runtime versions are not available).\n\nRecommended: upgrade the container OS to ${rec_os} ${rec_ver} first, then run this update again.\n\nIf you continue anyway, it may break — no support is provided in that case.\n\nContinue anyway?" \ + 20 70 3 \ + "1" "No (cancel update)" \ + "2" "Yes (continue this time)" \ + "3" "Yes (continue and don't ask again)" \ + --nocancel --default-item "1" 3>&1 1>&2 2>&3) + case "$choice" in + 2) + msg_warn "Continuing update on ${cur_os} ${cur_ver} despite recommended ${rec_os} ${rec_ver} — may break, no support." + return 0 + ;; + 3) + mkdir -p "${ignore_file%/*}" + echo "${rec_os} ${rec_ver}" >"$ignore_file" + msg_warn "Continuing update on ${cur_os} ${cur_ver}; OS check for ${rec_os} ${rec_ver} disabled via ${ignore_file} — may break, no support." + return 0 + ;; + esac + msg_error "Update cancelled: container OS ${cur_os} ${cur_ver} does not match the recommended ${rec_os} ${rec_ver}." + return 1 + fi + + msg_error "Container OS ${cur_os} ${cur_ver} does not match the recommended ${rec_os} ${rec_ver} — skipping update." + msg_error "Upgrade the container OS to ${rec_os} ${rec_ver} first, then run this update again — or bypass this check (may break, no support) with: echo \"${rec_os} ${rec_ver}\" > ${ignore_file}" + return 1 +} + # ------------------------------------------------------------------------------ # start() # @@ -3852,6 +3924,7 @@ start() { ensure_profile_loaded get_lxc_ip runtime_script_status_guard update || return 0 + check_container_os_guard || return 0 update_script run_addon_updates update_motd_ip @@ -3863,6 +3936,7 @@ start() { ensure_profile_loaded get_lxc_ip runtime_script_status_guard update || return 0 + check_container_os_guard || return 0 update_script run_addon_updates update_motd_ip @@ -3893,6 +3967,7 @@ start() { ensure_profile_loaded get_lxc_ip runtime_script_status_guard update || return 0 + check_container_os_guard || return 0 update_script run_addon_updates update_motd_ip From 56e2170f6c1f0a8f32d86f6f1f5dbb23d371f5b7 Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Wed, 22 Jul 2026 06:55:57 +0000 Subject: [PATCH 243/245] Update CHANGELOG.md (#15964) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d02fb7130..2b421991c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -515,6 +515,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Anytype: preserve default mongod.conf when configuring Anytype replica set [@MickLesk](https://github.com/MickLesk) ([#15954](https://github.com/community-scripts/ProxmoxVE/pull/15954)) - Nametag: fix missing tailwindcss module [@MickLesk](https://github.com/MickLesk) ([#15955](https://github.com/community-scripts/ProxmoxVE/pull/15955)) +### 💾 Core + + - #### ✨ New Features + + - core: add OS mismatch guard for container updates [@MickLesk](https://github.com/MickLesk) ([#15948](https://github.com/community-scripts/ProxmoxVE/pull/15948)) + ## 2026-07-21 ### 🚀 Updated Scripts From 0576b7c61f7d6fac081f497fe3135c8d23e1902b Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Wed, 22 Jul 2026 08:59:05 +0200 Subject: [PATCH 244/245] OPNSense: Bump FreeBSD to 15 and OPNSense to 26.7 (#15943) * OPNSense: Bump FreeBSD to 15 and OPNSense to 26.7 * fix user feedback * fix typo * fix url for image * Replace fixed OPNsense wait with screen polling Swap the hardcoded 1000-second sleep for an adaptive loop that watches VM console screendump hashes and proceeds after sustained stability. The new logic enforces a minimum 5-minute wait, checks every 30 seconds, and caps total wait at 40 minutes to handle slower hosts or screendump failures more reliably. * Harden OPNsense build wait detection Improves VM install completion detection by encapsulating screendump hashing in a helper, clearing stale dump files, and trying both `qm monitor` and `pvesh` monitor paths. The stability check now tolerates alternating A/B frames from a blinking login cursor instead of requiring one identical frame. It also adds elapsed-time progress output and a safe fallback to a fixed 12-minute wait when screendumps are unavailable, avoiding false completion or endless polling. --- vm/opnsense-vm.sh | 102 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 19 deletions(-) diff --git a/vm/opnsense-vm.sh b/vm/opnsense-vm.sh index 4d15f25be..32fd6f076 100644 --- a/vm/opnsense-vm.sh +++ b/vm/opnsense-vm.sh @@ -25,6 +25,7 @@ METHOD="" NSAPP="opnsense-vm" var_os="opnsense" var_version="26.7" +FREEBSD_MAJOR="15" # GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//') GEN_MAC_LAN=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//') @@ -490,7 +491,7 @@ function advanced_settings() { fi echo -e "${DGN}Using LAN GATEWAY ADDRESS: ${BGN}$LAN_GW${CL}" fi - if NETMASK=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN netmmask (24 for example)" 8 58 $NETMASK --title "LAN NETMASK" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then + if NETMASK=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN netmask (24 for example)" 8 58 $NETMASK --title "LAN NETMASK" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then if [ -z $NETMASK ]; then echo -e "${DGN}Netmask needs to be set if ip is not dhcp${CL}" fi @@ -558,7 +559,7 @@ function advanced_settings() { else exit-script fi - if WAN_NETMASK=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN netmmask (24 for example)" 8 58 $WAN_NETMASK --title "WAN NETMASK" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then + if WAN_NETMASK=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN netmask (24 for example)" 8 58 $WAN_NETMASK --title "WAN NETMASK" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then if [ -z $WAN_NETMASK ]; then echo -e "${DGN}WAN Netmask needs to be set if ip is not dhcp${CL}" fi @@ -574,7 +575,7 @@ function advanced_settings() { else exit-script fi - if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN MAC Address" 8 58 $GEN_MAC --title "WAN MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then + if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN MAC Address" 8 58 $GEN_MAC --title "LAN MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then if [ -z $MAC1 ]; then MAC="$GEN_MAC" else @@ -585,7 +586,7 @@ function advanced_settings() { exit-script fi - if MAC2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN MAC Address" 8 58 $GEN_MAC_LAN --title "LAN MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then + if MAC2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN MAC Address" 8 58 $GEN_MAC_LAN --title "WAN MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then if [ -z $MAC2 ]; then WAN_MAC="$GEN_MAC_LAN" else @@ -652,23 +653,26 @@ fi msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location." msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}." msg_info "Retrieving the URL for the OPNsense Qcow2 Disk Image" -# Use latest stable FreeBSD amd64 qcow2 VM image (generic, not UFS/ZFS) +# Use latest stable FreeBSD amd64 qcow2 VM image matching FREEBSD_MAJOR RELEASE_LIST="$(curl -s https://download.freebsd.org/releases/VM-IMAGES/ | - grep -Eo '[0-9]+\.[0-9]+-RELEASE' | + grep -Eo "${FREEBSD_MAJOR}\.[0-9]+-RELEASE" | sort -Vr | uniq)" URL="" FREEBSD_VER="" for ver in $RELEASE_LIST; do - candidate="https://download.freebsd.org/releases/VM-IMAGES/${ver}/amd64/Latest/FreeBSD-${ver}-amd64.qcow2.xz" - if curl -fsI "$candidate" >/dev/null 2>&1; then - FREEBSD_VER="$ver" - URL="$candidate" - break - fi + # FreeBSD 15+ publishes separate -ufs/-zfs images instead of a generic one + for variant in "" "-ufs" "-zfs"; do + candidate="https://download.freebsd.org/releases/VM-IMAGES/${ver}/amd64/Latest/FreeBSD-${ver}-amd64${variant}.qcow2.xz" + if curl -fsI "$candidate" >/dev/null 2>&1; then + FREEBSD_VER="$ver" + URL="$candidate" + break 2 + fi + done done if [ -z "$URL" ]; then - msg_error "Could not find generic FreeBSD amd64 qcow2 image (non-UFS/ZFS)." + msg_error "Could not find a FreeBSD ${FREEBSD_MAJOR}.x amd64 qcow2 image." exit 115 fi msg_ok "Download URL: ${CL}${BL}${URL}${CL}" @@ -768,7 +772,7 @@ DESCRIPTION=$( cat < - Logo + Logo

OPNsense VM

@@ -814,10 +818,70 @@ if [ -n "$WAN_BRG" ]; then msg_ok "WAN interface added" sleep 5 # Brief pause after adding network interface fi -send_line_to_vm "sh ./opnsense-bootstrap.sh.in -y -f -r 26.7" +# FreeBSD 15+ VM images ship the base system as pkgbase packages; the bootstrap's +# "delete all packages" step would remove the running base system (/bin/rm etc.) +# and brick the VM. Deregister them from the pkg db first - the files stay in +# place and OPNsense replaces base and kernel with its own sets afterwards. +send_line_to_vm "echo \"PRAGMA foreign_keys=ON; DELETE FROM packages WHERE name LIKE 'FreeBSD-%';\" | pkg shell" +sleep 5 +send_line_to_vm "sh ./opnsense-bootstrap.sh.in -y -f -r ${var_version}" msg_ok "OPNsense VM is being installed, do not close the terminal, or the installation will fail." -#We need to wait for the OPNsense build proccess to finish, this takes a few minutes -sleep 1000 +# The bootstrap ends with an automatic reboot into OPNsense. While it runs the +# console keeps changing (download progress, package installs); once the VM has +# settled at the login prompt the screen stays static. Poll a screendump hash +# and continue after 3 minutes without change, bounded by a floor (the build +# never finishes faster) and a ceiling for slow machines. If no screendump can +# be captured at all, fall back to a fixed wait. +SCREEN_PPM="${TEMP_DIR}/screen-${VMID}.ppm" + +function screen_hash() { + # Remove the previous dump first: a stale file from an earlier successful + # dump must not simulate a static screen when later dumps start failing. + # Note: "qm monitor" is unusable here - its readline attaches to /dev/tty + # even with piped stdin and captures the terminal, so use the API instead. + rm -f "$SCREEN_PPM" + timeout 10 pvesh create /nodes/$(hostname -s)/qemu/$VMID/monitor --command "screendump ${SCREEN_PPM}" >/dev/null 2>&1 || true + md5sum "$SCREEN_PPM" 2>/dev/null | cut -d' ' -f1 || true +} + +build_elapsed=300 +build_stable=0 +screen_ok=0 +hash_a="" +hash_b="" +sleep 300 +while [ $build_stable -lt 6 ] && [ $build_elapsed -lt 2400 ]; do + sleep 30 + build_elapsed=$((build_elapsed + 30)) + new_hash=$(screen_hash) + if [ -n "$new_hash" ]; then + screen_ok=1 + # The login prompt cursor may blink: a screen alternating between the same + # two frames (A/B/A/B) counts as stable, anything new resets the counter + if [ "$new_hash" = "$hash_a" ] || [ "$new_hash" = "$hash_b" ]; then + build_stable=$((build_stable + 1)) + else + build_stable=0 + fi + else + build_stable=0 + fi + hash_b="$hash_a" + hash_a="$new_hash" + if [ -n "$new_hash" ]; then + echo -e "${DGN}Waiting for OPNsense build: ${YW}$((build_elapsed / 60))min elapsed, screen ${new_hash:0:8}, stable ${build_stable}/6${CL}" + else + echo -e "${DGN}Waiting for OPNsense build: ${YW}$((build_elapsed / 60))min elapsed, screendump failed${CL}" + fi + # No working screendump after several attempts: fixed wait instead + if [ $screen_ok -eq 0 ] && [ $build_elapsed -ge 480 ]; then + msg_error "Console screendump not available on this system - falling back to a fixed wait (12 minutes)." + sleep 720 + build_elapsed=$((build_elapsed + 720)) + break + fi +done +msg_ok "OPNsense build finished after $((build_elapsed / 60)) minutes" send_line_to_vm "root" send_line_to_vm "opnsense" send_line_to_vm "2" @@ -855,8 +919,8 @@ if [ -n "$WAN_BRG" ] && [ "$WAN_IP_ADDR" != "" ]; then send_line_to_vm "2" send_line_to_vm "n" send_line_to_vm "${WAN_IP_ADDR}" - send_line_to_vm "${NETMASK}" - send_line_to_vm "${LAN_GW}" + send_line_to_vm "${WAN_NETMASK}" + send_line_to_vm "${WAN_GW}" send_line_to_vm "n" send_line_to_vm " " send_line_to_vm "n" From 737d99ec9dfb13b1a5b6c8600e7d7cc3e6d257fc Mon Sep 17 00:00:00 2001 From: "community-scripts-pr-app[bot]" <189241966+community-scripts-pr-app[bot]@users.noreply.github.com> Date: Wed, 22 Jul 2026 06:59:28 +0000 Subject: [PATCH 245/245] Update CHANGELOG.md (#15965) Co-authored-by: github-actions[bot] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b421991c..b34836b94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -515,6 +515,10 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit - Anytype: preserve default mongod.conf when configuring Anytype replica set [@MickLesk](https://github.com/MickLesk) ([#15954](https://github.com/community-scripts/ProxmoxVE/pull/15954)) - Nametag: fix missing tailwindcss module [@MickLesk](https://github.com/MickLesk) ([#15955](https://github.com/community-scripts/ProxmoxVE/pull/15955)) + - #### ✨ New Features + + - OPNSense: Bump FreeBSD to 15 and OPNSense to 26.7 [@MickLesk](https://github.com/MickLesk) ([#15943](https://github.com/community-scripts/ProxmoxVE/pull/15943)) + ### 💾 Core - #### ✨ New Features