Compare commits

..

6 Commits

Author SHA1 Message Date
CanbiZ (MickLesk)
d84770e215 chore(ct,tools): sync Source headers with install/ and add Github links to addon scripts 2026-02-24 14:36:19 +01:00
CanbiZ (MickLesk)
8deb4401b1 revert: restore misc/build.func and misc/core.func to main state
These error-handler fixes belong to fix/error-handler-recovery, not to
this sources-only branch.
2026-02-24 14:30:07 +01:00
CanbiZ (MickLesk)
b1edd80a96 chore(install): add Github source links to all fetch_and_deploy scripts
77 additional install scripts had fetch_and_deploy_gh_release calls but
no GitHub link in the Source header. Merged the primary app repo into
the Source header as:
  # Source: https://website.com/ | Github: https://github.com/OWNER/REPO

Where multiple fetch_and_deploy calls existed (app + dependency), the
primary app repo was selected:
- ersatztv: ErsatzTV/ErsatzTV (not ffmpeg)
- firefly: firefly-iii/firefly-iii (not data-importer)
- komga: gotson/komga (not kepubify dep)
- sabnzbd: sabnzbd/sabnzbd (not par2cmdline-turbo dep)
- signoz: SigNoz/signoz (not otel-collector)
- tunarr: chrisbenincasa/tunarr (not ffmpeg dep)

Also fixed cosmos-install.sh double https:// in Source URL.

Skipped: autocaliweb (source already on codeberg, GitHub repos are deps only)
2026-02-24 14:28:45 +01:00
CanbiZ (MickLesk)
da422b1036 chore(install): add Github source links to all setup_nodejs scripts
52 install scripts had a project website in '# Source:' but no GitHub
link. Merged the GitHub repo URL into the Source header as:
  # Source: https://website.com/ | Github: https://github.com/OWNER/REPO

Repos sourced from fetch_and_deploy_gh_release calls, get_latest_github_release
calls, or known project repos for npm/pip installed apps.

Two scripts (fumadocs, pve-scripts-local) had no Source line at all —
added one. Shinobi skipped (GitLab-only, no GitHub repo).
2026-02-24 14:21:43 +01:00
CanbiZ (MickLesk)
7bb14b4d22 Update build.func 2026-02-24 14:03:09 +01:00
CanbiZ (MickLesk)
75c0b1bfc9 fix(error-handler): prevent silent() from re-enabling error handling during recovery
Root cause: silent() (core.func) unconditionally calls set -Eeuo pipefail
and trap 'error_handler' ERR after every command. When build_container()
intentionally disables error handling for its recovery section, any
intermediate call through silent()/ re-enables it. This causes the
grep/sed pipeline for missing_cmd extraction to trigger error_handler
(grep returns exit code 1 on no match + pipefail = fatal).

Fixes:
1. silent(): Save errexit state before disabling, only restore if it was
   active. Callers that intentionally disabled error handling (e.g.
   build_container recovery) are no longer silently re-enabled.

2. build.func: Add || true to missing_cmd grep pipeline as defense-in-depth
   against pipeline failure propagation.

3. build.func: Add explicit set +Eeuo pipefail / trap - ERR after
   post_update_to_api() call, before error classification grep/sed section.

4. build.func: Remove stale global combined_log variable from variables()
   that used a different path format (/tmp/install-SESSION-combined.log)
   than the actual local variable (/tmp/NSAPP-CTID-SESSION.log). The global
   was never written to and caused confusion when error_handler displayed it.
2026-02-24 13:51:27 +01:00
151 changed files with 2004 additions and 5350 deletions

250
.github/changelogs/2026/02.md generated vendored
View File

@@ -1,253 +1,3 @@
## 2026-02-28
### 🚀 Updated Scripts
- Update Reactive Resume install script with useful .env information for reverse proxy setup [@Mazianni](https://github.com/Mazianni) ([#12401](https://github.com/community-scripts/ProxmoxVE/pull/12401))
- #### 🐞 Bug Fixes
- gramps-web: install addons (FilterRules) for relationship diagram [@MickLesk](https://github.com/MickLesk) ([#12387](https://github.com/community-scripts/ProxmoxVE/pull/12387))
- [Fix] Immich: Change `sed` command to fully replace line in postgresql.conf [@vhsdream](https://github.com/vhsdream) ([#12429](https://github.com/community-scripts/ProxmoxVE/pull/12429))
- [FIX] Immich: fix Openvino memory leak during OCR; improve HW-accelerated ML performance [@vhsdream](https://github.com/vhsdream) ([#12426](https://github.com/community-scripts/ProxmoxVE/pull/12426))
- Fix default tag for ioBroker LXC install [@josefglatz](https://github.com/josefglatz) ([#12423](https://github.com/community-scripts/ProxmoxVE/pull/12423))
- Ombi: Add database.json [@hraphael](https://github.com/hraphael) ([#12412](https://github.com/community-scripts/ProxmoxVE/pull/12412))
- Dawarich: add missing build deps and handle seed failure [@MickLesk](https://github.com/MickLesk) ([#12410](https://github.com/community-scripts/ProxmoxVE/pull/12410))
- pangolin: increase hdd to 10G [@MickLesk](https://github.com/MickLesk) ([#12409](https://github.com/community-scripts/ProxmoxVE/pull/12409))
- #### ✨ New Features
- BookLore: add additional JVM flags [@vhsdream](https://github.com/vhsdream) ([#12421](https://github.com/community-scripts/ProxmoxVE/pull/12421))
### 🗑️ Deleted Scripts
- Delete Palmr [@vhsdream](https://github.com/vhsdream) ([#12399](https://github.com/community-scripts/ProxmoxVE/pull/12399))
### 💾 Core
- #### 🐞 Bug Fixes
- core: read from /dev/tty in all interactive prompts | fix empty or cropped logs due build process [@MickLesk](https://github.com/MickLesk) ([#12406](https://github.com/community-scripts/ProxmoxVE/pull/12406))
## 2026-02-27
### 🆕 New Scripts
- Strapi ([#12320](https://github.com/community-scripts/ProxmoxVE/pull/12320))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- TrueNAS VM: filter out new nightlies with MASTER [@juronja](https://github.com/juronja) ([#12355](https://github.com/community-scripts/ProxmoxVE/pull/12355))
### 💾 Core
- #### ✨ New Features
- core: graceful fallback for apt-get update failures [@MickLesk](https://github.com/MickLesk) ([#12386](https://github.com/community-scripts/ProxmoxVE/pull/12386))
- core: Improve error outputs across core functions [@MickLesk](https://github.com/MickLesk) ([#12378](https://github.com/community-scripts/ProxmoxVE/pull/12378))
## 2026-02-26
### 🆕 New Scripts
- Kima-Hub ([#12319](https://github.com/community-scripts/ProxmoxVE/pull/12319))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- tools.func: update glx alternatives / nvidia alternative if nvidia glx are missing [@MickLesk](https://github.com/MickLesk) ([#12372](https://github.com/community-scripts/ProxmoxVE/pull/12372))
- hotfix: overseer version [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12366](https://github.com/community-scripts/ProxmoxVE/pull/12366))
- #### ✨ New Features
- Add ffmpeg for booklore (ffprobe) [@MickLesk](https://github.com/MickLesk) ([#12371](https://github.com/community-scripts/ProxmoxVE/pull/12371))
- [QOL] Immich: add warning regarding library compilation time [@vhsdream](https://github.com/vhsdream) ([#12345](https://github.com/community-scripts/ProxmoxVE/pull/12345))
### 🧰 Tools
- #### 🐞 Bug Fixes
- Improves adguardhome-sync addon when running on alpine LXCs [@Darkangeel-hd](https://github.com/Darkangeel-hd) ([#12362](https://github.com/community-scripts/ProxmoxVE/pull/12362))
- #### ✨ New Features
- Add Alpine support and improve Tailscale install [@MickLesk](https://github.com/MickLesk) ([#12370](https://github.com/community-scripts/ProxmoxVE/pull/12370))
### 📚 Documentation
- fix wrong link on contributions README.md [@Darkangeel-hd](https://github.com/Darkangeel-hd) ([#12363](https://github.com/community-scripts/ProxmoxVE/pull/12363))
### 📂 Github
- github: add workflow to autom. close unauthorized new-script PRs [@MickLesk](https://github.com/MickLesk) ([#12356](https://github.com/community-scripts/ProxmoxVE/pull/12356))
## 2026-02-25
### 🆕 New Scripts
- Zerobyte ([#12321](https://github.com/community-scripts/ProxmoxVE/pull/12321))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix: overseer migration [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12340](https://github.com/community-scripts/ProxmoxVE/pull/12340))
- add: vikunja: daemon reload [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12323](https://github.com/community-scripts/ProxmoxVE/pull/12323))
- opnsense-VM: Use ip link to verify bridge existence [@MickLesk](https://github.com/MickLesk) ([#12329](https://github.com/community-scripts/ProxmoxVE/pull/12329))
- wger: Use $http_host for proxy Host header [@MickLesk](https://github.com/MickLesk) ([#12327](https://github.com/community-scripts/ProxmoxVE/pull/12327))
- Passbolt: Update Nginx config `client_max_body_size` [@tremor021](https://github.com/tremor021) ([#12313](https://github.com/community-scripts/ProxmoxVE/pull/12313))
- Zammad: configure Elasticsearch before zammad start [@MickLesk](https://github.com/MickLesk) ([#12308](https://github.com/community-scripts/ProxmoxVE/pull/12308))
- #### 🔧 Refactor
- OpenProject: Various fixes [@tremor021](https://github.com/tremor021) ([#12246](https://github.com/community-scripts/ProxmoxVE/pull/12246))
### 💾 Core
- #### 🐞 Bug Fixes
- Fix detection of ssh keys [@1-tempest](https://github.com/1-tempest) ([#12230](https://github.com/community-scripts/ProxmoxVE/pull/12230))
- #### ✨ New Features
- tools.func: Improve GitHub/Codeberg API error handling and error output [@MickLesk](https://github.com/MickLesk) ([#12330](https://github.com/community-scripts/ProxmoxVE/pull/12330))
- #### 🔧 Refactor
- core: remove duplicate traps, consolidate error handling and harden signal traps [@MickLesk](https://github.com/MickLesk) ([#12316](https://github.com/community-scripts/ProxmoxVE/pull/12316))
### 📂 Github
- github: improvements for node drift wf [@MickLesk](https://github.com/MickLesk) ([#12309](https://github.com/community-scripts/ProxmoxVE/pull/12309))
## 2026-02-24
### 🚀 Updated Scripts
- several scripts: add additional github link in source [@MickLesk](https://github.com/MickLesk) ([#12282](https://github.com/community-scripts/ProxmoxVE/pull/12282))
- adds further documentation during the installation script. [@d12rio](https://github.com/d12rio) ([#12248](https://github.com/community-scripts/ProxmoxVE/pull/12248))
- #### 🐞 Bug Fixes
- [Fix] PatchMon: remove VITE_API_URL from frontend env [@vhsdream](https://github.com/vhsdream) ([#12294](https://github.com/community-scripts/ProxmoxVE/pull/12294))
- fix(searxng): remove orphaned fi causing syntax error [@mark-jeffrey](https://github.com/mark-jeffrey) ([#12283](https://github.com/community-scripts/ProxmoxVE/pull/12283))
- Refactor n8n [@MickLesk](https://github.com/MickLesk) ([#12264](https://github.com/community-scripts/ProxmoxVE/pull/12264))
- Firefly: PHP bump [@tremor021](https://github.com/tremor021) ([#12247](https://github.com/community-scripts/ProxmoxVE/pull/12247))
- #### ✨ New Features
- Databasus: add mariadb path for mysql/mariadb backups | add mongodb database tools [@MickLesk](https://github.com/MickLesk) ([#12259](https://github.com/community-scripts/ProxmoxVE/pull/12259))
- make searxng updateable [@shtefko](https://github.com/shtefko) ([#12207](https://github.com/community-scripts/ProxmoxVE/pull/12207))
- #### 💥 Breaking Changes
- fix: wealthfolio for v3 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11765](https://github.com/community-scripts/ProxmoxVE/pull/11765))
- #### 🔧 Refactor
- bump various scripts from Node 22 to 24 [@MickLesk](https://github.com/MickLesk) ([#12265](https://github.com/community-scripts/ProxmoxVE/pull/12265))
### 💾 Core
- #### 🐞 Bug Fixes
- core: fix broken "command not found" after err_trap [@MickLesk](https://github.com/MickLesk) ([#12280](https://github.com/community-scripts/ProxmoxVE/pull/12280))
- #### ✨ New Features
- tools.func: add get_latest_gh_tag helper function [@MickLesk](https://github.com/MickLesk) ([#12261](https://github.com/community-scripts/ProxmoxVE/pull/12261))
### 🧰 Tools
- Arcane ([#12263](https://github.com/community-scripts/ProxmoxVE/pull/12263))
### 📂 Github
- github: add weekly Node.js version drift check workflow [@MickLesk](https://github.com/MickLesk) ([#12267](https://github.com/community-scripts/ProxmoxVE/pull/12267))
- add: workflow to close stale PRs [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12243](https://github.com/community-scripts/ProxmoxVE/pull/12243))
## 2026-02-23
### 🆕 New Scripts
- SeaweedFS ([#12220](https://github.com/community-scripts/ProxmoxVE/pull/12220))
- Sonobarr ([#12221](https://github.com/community-scripts/ProxmoxVE/pull/12221))
- SparkyFitness ([#12185](https://github.com/community-scripts/ProxmoxVE/pull/12185))
- Frigate v16.4 [@MickLesk](https://github.com/MickLesk) ([#11887](https://github.com/community-scripts/ProxmoxVE/pull/11887))
### 🚀 Updated Scripts
- #### ✨ New Features
- memos: unpin version due new release artifacts [@MickLesk](https://github.com/MickLesk) ([#12224](https://github.com/community-scripts/ProxmoxVE/pull/12224))
- core: Enhance signal handling, reported "status" and logs [@MickLesk](https://github.com/MickLesk) ([#12216](https://github.com/community-scripts/ProxmoxVE/pull/12216))
- #### 🔧 Refactor
- booklore v2: embed frontend, bump Java to 25, remove nginx [@MickLesk](https://github.com/MickLesk) ([#12223](https://github.com/community-scripts/ProxmoxVE/pull/12223))
### 🗑️ Deleted Scripts
- Remove: Huntarr (deprecated & Security) [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12226](https://github.com/community-scripts/ProxmoxVE/pull/12226))
### 💾 Core
- #### 🔧 Refactor
- core: Improve error handling and logging for LXC builds [@MickLesk](https://github.com/MickLesk) ([#12208](https://github.com/community-scripts/ProxmoxVE/pull/12208))
### 🌐 Website
- #### 🐞 Bug Fixes
- calibre-web: update default credentials [@LaevaertK](https://github.com/LaevaertK) ([#12201](https://github.com/community-scripts/ProxmoxVE/pull/12201))
- #### 📝 Script Information
- chore: update Frigate documentation and website URLs [@JohnICB](https://github.com/JohnICB) ([#12218](https://github.com/community-scripts/ProxmoxVE/pull/12218))
## 2026-02-22
### 🆕 New Scripts
- Gramps-Web ([#12157](https://github.com/community-scripts/ProxmoxVE/pull/12157))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix: Apache Guacamole - bump to Temurin JDK 17 to resolve Debian 13 (Trixie) install failure [@Copilot](https://github.com/Copilot) ([#12161](https://github.com/community-scripts/ProxmoxVE/pull/12161))
- Docker-VM: add error handling for virt-customize finalization [@MickLesk](https://github.com/MickLesk) ([#12127](https://github.com/community-scripts/ProxmoxVE/pull/12127))
- [Fix] Sure: add Sidekiq service [@vhsdream](https://github.com/vhsdream) ([#12186](https://github.com/community-scripts/ProxmoxVE/pull/12186))
- #### ✨ New Features
- Refactor & Bump to v2: Plex [@MickLesk](https://github.com/MickLesk) ([#12179](https://github.com/community-scripts/ProxmoxVE/pull/12179))
- #### 🔧 Refactor
- karakeep: bump to node 24 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12183](https://github.com/community-scripts/ProxmoxVE/pull/12183))
### 💾 Core
- #### ✨ New Features
- tools.func: add GitHub API rate-limit detection and GITHUB_TOKEN support [@MickLesk](https://github.com/MickLesk) ([#12176](https://github.com/community-scripts/ProxmoxVE/pull/12176))
### 🧰 Tools
- CR*NMASTER ([#12065](https://github.com/community-scripts/ProxmoxVE/pull/12065))
- #### 🔧 Refactor
- Update package management commands in clean-lxcs.sh [@heinemannj](https://github.com/heinemannj) ([#12166](https://github.com/community-scripts/ProxmoxVE/pull/12166))
### ❔ Uncategorized
- calibre-web: Update logo URL [@MickLesk](https://github.com/MickLesk) ([#12178](https://github.com/community-scripts/ProxmoxVE/pull/12178))
## 2026-02-21 ## 2026-02-21
### 🚀 Updated Scripts ### 🚀 Updated Scripts

View File

@@ -13,7 +13,7 @@ permissions:
jobs: jobs:
check-node-versions: check-node-versions:
if: github.repository == 'community-scripts/ProxmoxVE' if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: coolify-runner runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repository - name: Checkout Repository
@@ -110,94 +110,22 @@ jobs:
} }
# Extract Node major from engines.node in package.json # Extract Node major from engines.node in package.json
# Sets: ENGINES_NODE_RAW (raw string), ENGINES_MIN_MAJOR, ENGINES_IS_MINIMUM # Sets: ENGINES_NODE_RAW (raw string), ENGINES_MIN_MAJOR
extract_engines_node() { extract_engines_node() {
local content="$1" local content="$1"
ENGINES_NODE_RAW="" ENGINES_NODE_RAW=""
ENGINES_MIN_MAJOR="" ENGINES_MIN_MAJOR=""
ENGINES_IS_MINIMUM="false"
ENGINES_NODE_RAW=$(echo "$content" | jq -r '.engines.node // empty' 2>/dev/null || echo "") ENGINES_NODE_RAW=$(echo "$content" | jq -r '.engines.node // empty' 2>/dev/null || echo "")
if [[ -z "$ENGINES_NODE_RAW" ]]; then if [[ -z "$ENGINES_NODE_RAW" ]]; then
return return
fi fi
# Detect if constraint is a minimum (>=, ^) vs exact pinning
if [[ "$ENGINES_NODE_RAW" =~ ^(\>=|\^|\~) ]]; then
ENGINES_IS_MINIMUM="true"
fi
# Extract the first number (major) from the constraint # Extract the first number (major) from the constraint
# Handles: ">=24.13.1", "^22", ">=18.0.0", ">=18.15.0 <19 || ^20", etc. # Handles: ">=24.13.1", "^22", ">=18.0.0", ">=18.15.0 <19 || ^20", etc.
ENGINES_MIN_MAJOR=$(echo "$ENGINES_NODE_RAW" | grep -oP '\d+' | head -1 || echo "") ENGINES_MIN_MAJOR=$(echo "$ENGINES_NODE_RAW" | grep -oP '\d+' | head -1 || echo "")
} }
# Check if our_version satisfies an engines.node constraint
# Returns 0 if satisfied, 1 if not
# Usage: version_satisfies_engines "22" ">=18.0.0" "true"
version_satisfies_engines() {
local our="$1"
local min_major="$2"
local is_minimum="$3"
if [[ -z "$min_major" || -z "$our" ]]; then
return 1
fi
if [[ "$is_minimum" == "true" ]]; then
# >= or ^ constraint: our version must be >= min_major
if [[ "$our" -ge "$min_major" ]]; then
return 0
fi
fi
return 1
}
# Search for files in subdirectories via GitHub API tree
# Usage: find_repo_file "owner/repo" "branch" "filename" => sets REPLY to raw URL or empty
find_repo_file() {
local repo="$1"
local branch="$2"
local filename="$3"
REPLY=""
# Try root first (fast)
local root_url="https://raw.githubusercontent.com/${repo}/${branch}/${filename}"
if curl -sfI "$root_url" >/dev/null 2>&1; then
REPLY="$root_url"
return
fi
# Search via GitHub API tree (recursive)
local tree_url="https://api.github.com/repos/${repo}/git/trees/${branch}?recursive=1"
local tree_json
tree_json=$(curl -sf -H "Authorization: token $GH_TOKEN" "$tree_url" 2>/dev/null || echo "")
if [[ -z "$tree_json" ]]; then
return
fi
# Find first matching path (prefer shorter/root-level paths)
local match_path
match_path=$(echo "$tree_json" | jq -r --arg fn "$filename" \
'.tree[]? | select(.path | endswith("/" + $fn) or . == $fn) | .path' 2>/dev/null \
| sort | head -1 || echo "")
if [[ -n "$match_path" ]]; then
REPLY="https://raw.githubusercontent.com/${repo}/${branch}/${match_path}"
fi
}
# Extract Node major from .nvmrc or .node-version
# Sets: NVMRC_NODE_MAJOR
extract_nvmrc_node() {
local content="$1"
NVMRC_NODE_MAJOR=""
# .nvmrc/.node-version typically has: "v22.9.0", "22", "lts/iron", etc.
local ver
ver=$(echo "$content" | tr -d '[:space:]' | grep -oP '^v?\K[0-9]+' | head -1 || echo "")
NVMRC_NODE_MAJOR="$ver"
}
# Collect results # Collect results
declare -a issue_scripts=() declare -a issue_scripts=()
declare -a report_lines=() declare -a report_lines=()
@@ -214,12 +142,8 @@ jobs:
total=$((total + 1)) total=$((total + 1))
slug=$(basename "$script" | sed 's/-install\.sh$//') slug=$(basename "$script" | sed 's/-install\.sh$//')
# Extract Source URL (GitHub only) from the "# Source:" line # Extract Source URL (GitHub only)
# Supports both: source_url=$(head -20 "$script" | grep -oP '(?<=# Source: )https://github\.com/[^\s]+' | head -1 || echo "")
# # Source: https://github.com/owner/repo
# # Source: https://example.com | Github: https://github.com/owner/repo
# NOTE: Must filter for "# Source:" line first to avoid matching the License URL
source_url=$(head -20 "$script" | grep -i '# Source:' | grep -oP 'https://github\.com/[^\s|]+' | head -1 || echo "")
if [[ -z "$source_url" ]]; then if [[ -z "$source_url" ]]; then
report_lines+=("| \`$slug\` | — | — | — | — | ⏭️ No GitHub source |") report_lines+=("| \`$slug\` | — | — | — | — | ⏭️ No GitHub source |")
continue continue
@@ -243,23 +167,12 @@ jobs:
fi fi
fi fi
# Determine default branch via GitHub API (fast, single call) # Fetch upstream Dockerfile
detected_branch=""
api_default=$(curl -sf -H "Authorization: token $GH_TOKEN" \
"https://api.github.com/repos/${repo}" 2>/dev/null \
| jq -r '.default_branch // empty' 2>/dev/null || echo "")
if [[ -n "$api_default" ]]; then
detected_branch="$api_default"
else
detected_branch="main"
fi
# Fetch upstream Dockerfile (root + subdirectories)
df_content="" df_content=""
find_repo_file "$repo" "$detected_branch" "Dockerfile" for branch in main master dev; do
if [[ -n "$REPLY" ]]; then df_content=$(curl -sf "https://raw.githubusercontent.com/${repo}/${branch}/Dockerfile" 2>/dev/null || echo "")
df_content=$(curl -sf "$REPLY" 2>/dev/null || echo "") [[ -n "$df_content" ]] && break
fi done
DF_NODE_MAJOR="" DF_NODE_MAJOR=""
DF_SOURCE="" DF_SOURCE=""
@@ -267,35 +180,19 @@ jobs:
extract_dockerfile_node "$df_content" extract_dockerfile_node "$df_content"
fi fi
# Fetch upstream package.json (root + subdirectories) # Fetch upstream package.json
pkg_content="" pkg_content=""
find_repo_file "$repo" "$detected_branch" "package.json" for branch in main master dev; do
if [[ -n "$REPLY" ]]; then pkg_content=$(curl -sf "https://raw.githubusercontent.com/${repo}/${branch}/package.json" 2>/dev/null || echo "")
pkg_content=$(curl -sf "$REPLY" 2>/dev/null || echo "") [[ -n "$pkg_content" ]] && break
fi done
ENGINES_NODE_RAW="" ENGINES_NODE_RAW=""
ENGINES_MIN_MAJOR="" ENGINES_MIN_MAJOR=""
ENGINES_IS_MINIMUM="false"
if [[ -n "$pkg_content" ]]; then if [[ -n "$pkg_content" ]]; then
extract_engines_node "$pkg_content" extract_engines_node "$pkg_content"
fi fi
# Fallback: check .nvmrc or .node-version
NVMRC_NODE_MAJOR=""
if [[ -z "$DF_NODE_MAJOR" && -z "$ENGINES_MIN_MAJOR" ]]; then
for nvmfile in .nvmrc .node-version; do
find_repo_file "$repo" "$detected_branch" "$nvmfile"
if [[ -n "$REPLY" ]]; then
nvmrc_content=$(curl -sf "$REPLY" 2>/dev/null || echo "")
if [[ -n "$nvmrc_content" ]]; then
extract_nvmrc_node "$nvmrc_content"
[[ -n "$NVMRC_NODE_MAJOR" ]] && break
fi
fi
done
fi
# Determine upstream recommended major version # Determine upstream recommended major version
upstream_major="" upstream_major=""
upstream_hint="" upstream_hint=""
@@ -306,9 +203,6 @@ jobs:
elif [[ -n "$ENGINES_MIN_MAJOR" ]]; then elif [[ -n "$ENGINES_MIN_MAJOR" ]]; then
upstream_major="$ENGINES_MIN_MAJOR" upstream_major="$ENGINES_MIN_MAJOR"
upstream_hint="engines: $ENGINES_NODE_RAW" upstream_hint="engines: $ENGINES_NODE_RAW"
elif [[ -n "$NVMRC_NODE_MAJOR" ]]; then
upstream_major="$NVMRC_NODE_MAJOR"
upstream_hint=".nvmrc/.node-version"
fi fi
# Build display values # Build display values
@@ -320,23 +214,13 @@ jobs:
if [[ "$our_version" == "dynamic" ]]; then if [[ "$our_version" == "dynamic" ]]; then
status="🔄 Dynamic" status="🔄 Dynamic"
elif [[ "$our_version" == "unset" ]]; then elif [[ "$our_version" == "unset" ]]; then
if [[ -n "$upstream_major" ]]; then status="⚠️ NODE_VERSION not set"
status="⚠️ NODE_VERSION not set (upstream=$upstream_major via $upstream_hint)"
else
status="⚠️ NODE_VERSION not set (no upstream info found)"
fi
issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo") issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo")
drift_count=$((drift_count + 1)) drift_count=$((drift_count + 1))
elif [[ -n "$upstream_major" && "$our_version" != "$upstream_major" ]]; then elif [[ -n "$upstream_major" && "$our_version" != "$upstream_major" ]]; then
# Check if engines.node is a minimum constraint that our version satisfies status="🔸 Drift → upstream=$upstream_major ($upstream_hint)"
if [[ -z "$DF_NODE_MAJOR" && "$ENGINES_IS_MINIMUM" == "true" ]] && \ issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo")
version_satisfies_engines "$our_version" "$ENGINES_MIN_MAJOR" "$ENGINES_IS_MINIMUM"; then drift_count=$((drift_count + 1))
status="✅ (engines: $ENGINES_NODE_RAW — ours: $our_version satisfies)"
else
status="🔸 Drift → upstream=$upstream_major ($upstream_hint)"
issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo")
drift_count=$((drift_count + 1))
fi
fi fi
report_lines+=("| \`$slug\` | $our_version | $engines_display | $dockerfile_display | [$repo](https://github.com/$repo) | $status |") report_lines+=("| \`$slug\` | $our_version | $engines_display | $dockerfile_display | [$repo](https://github.com/$repo) | $status |")

View File

@@ -1,119 +0,0 @@
name: Close Unauthorized New Script PRs
on:
pull_request_target:
branches: ["main"]
types: [opened, labeled]
jobs:
check-new-script:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: coolify-runner
permissions:
pull-requests: write
contents: read
steps:
- name: Close PR if unauthorized new script submission
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
const prNumber = pr.number;
const author = pr.user.login;
const authorType = pr.user.type; // "User" or "Bot"
const owner = context.repo.owner;
const repo = context.repo.repo;
// --- Only act on PRs with the "new script" label ---
const labels = pr.labels.map(l => l.name);
if (!labels.includes("new script")) {
core.info(`PR #${prNumber} does not have "new script" label — skipping.`);
return;
}
// --- Allow our bots ---
const allowedBots = [
"push-app-to-main[bot]",
"push-app-to-main",
];
if (allowedBots.includes(author)) {
core.info(`PR #${prNumber} by allowed bot "${author}" — skipping.`);
return;
}
// --- Check if author is a member of the contributor team ---
const teamSlug = "contributor";
let isMember = false;
try {
const { status } = await github.rest.teams.getMembershipForUserInOrg({
org: owner,
team_slug: teamSlug,
username: author,
});
// status 200 means the user is a member (active or pending)
isMember = true;
} catch (error) {
if (error.status === 404) {
isMember = false;
} else {
core.warning(`Could not check team membership for ${author}: ${error.message}`);
// Fallback: check org membership
try {
await github.rest.orgs.checkMembershipForUser({
org: owner,
username: author,
});
isMember = true;
} catch {
isMember = false;
}
}
}
if (isMember) {
core.info(`PR #${prNumber} by contributor "${author}" — skipping.`);
return;
}
// --- Unauthorized: close the PR with a comment ---
core.info(`Closing PR #${prNumber} by "${author}" — not a contributor or allowed bot.`);
const comment = [
`👋 Hi @${author},`,
``,
`Thank you for your interest in contributing a new script!`,
``,
`However, **new scripts must first be submitted to our development repository** for testing and review before they can be merged here.`,
``,
`> 🛑 New scripts must be submitted to [**ProxmoxVED**](https://github.com/community-scripts/ProxmoxVED) for testing.`,
`> PRs without prior testing will be closed.`,
``,
`Please open your PR at **https://github.com/community-scripts/ProxmoxVED** instead.`,
`Once your script has been tested and approved there, it will be pushed to this repository automatically.`,
``,
`This PR will now be closed. Thank you for understanding! 🙏`,
].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",
});
// Add a label to indicate why it was closed
await github.rest.issues.addLabels({
owner,
repo,
issue_number: prNumber,
labels: ["not a script issue"],
});

View File

@@ -21,9 +21,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
<details> <details>
<summary><h2>📜 History</h2></summary> <summary><h2>📜 History</h2></summary>
@@ -33,7 +30,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
<details> <details>
<summary><h4>February (28 entries)</h4></summary> <summary><h4>February (21 entries)</h4></summary>
[View February 2026 Changelog](.github/changelogs/2026/02.md) [View February 2026 Changelog](.github/changelogs/2026/02.md)
@@ -410,198 +407,27 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details> </details>
## 2026-03-02
### 🆕 New Scripts
- Profilarr ([#12441](https://github.com/community-scripts/ProxmoxVE/pull/12441))
### 🚀 Updated Scripts
- #### 💥 Breaking Changes
- Migrate: DokPloy, Komodo, Coolify, Dockge, Runtipi to Addons [@MickLesk](https://github.com/MickLesk) ([#12275](https://github.com/community-scripts/ProxmoxVE/pull/12275))
### 💾 Core
- #### ✨ New Features
- tools.func: Improve stability with retry logic, caching, and debug mode [@MickLesk](https://github.com/MickLesk) ([#10351](https://github.com/community-scripts/ProxmoxVE/pull/10351))
- #### 🔧 Refactor
- core: standardize exit codes and add mappings [@MickLesk](https://github.com/MickLesk) ([#12467](https://github.com/community-scripts/ProxmoxVE/pull/12467))
### 🌐 Website
- frontend: improve detail view badges, addon texts, and HTML title [@MickLesk](https://github.com/MickLesk) ([#12461](https://github.com/community-scripts/ProxmoxVE/pull/12461))
## 2026-03-01
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Sparkyfitness: use pnpm [@tomfrenzel](https://github.com/tomfrenzel) ([#12445](https://github.com/community-scripts/ProxmoxVE/pull/12445))
- OpenArchiver: Fix installation [@tremor021](https://github.com/tremor021) ([#12447](https://github.com/community-scripts/ProxmoxVE/pull/12447))
## 2026-02-28
### 🚀 Updated Scripts
- Update Reactive Resume install script with useful .env information for reverse proxy setup [@Mazianni](https://github.com/Mazianni) ([#12401](https://github.com/community-scripts/ProxmoxVE/pull/12401))
- #### 🐞 Bug Fixes
- gramps-web: install addons (FilterRules) for relationship diagram [@MickLesk](https://github.com/MickLesk) ([#12387](https://github.com/community-scripts/ProxmoxVE/pull/12387))
- [Fix] Immich: Change `sed` command to fully replace line in postgresql.conf [@vhsdream](https://github.com/vhsdream) ([#12429](https://github.com/community-scripts/ProxmoxVE/pull/12429))
- [FIX] Immich: fix Openvino memory leak during OCR; improve HW-accelerated ML performance [@vhsdream](https://github.com/vhsdream) ([#12426](https://github.com/community-scripts/ProxmoxVE/pull/12426))
- Fix default tag for ioBroker LXC install [@josefglatz](https://github.com/josefglatz) ([#12423](https://github.com/community-scripts/ProxmoxVE/pull/12423))
- Ombi: Add database.json [@hraphael](https://github.com/hraphael) ([#12412](https://github.com/community-scripts/ProxmoxVE/pull/12412))
- Dawarich: add missing build deps and handle seed failure [@MickLesk](https://github.com/MickLesk) ([#12410](https://github.com/community-scripts/ProxmoxVE/pull/12410))
- pangolin: increase hdd to 10G [@MickLesk](https://github.com/MickLesk) ([#12409](https://github.com/community-scripts/ProxmoxVE/pull/12409))
- #### ✨ New Features
- BookLore: add additional JVM flags [@vhsdream](https://github.com/vhsdream) ([#12421](https://github.com/community-scripts/ProxmoxVE/pull/12421))
### 🗑️ Deleted Scripts
- Delete Palmr [@vhsdream](https://github.com/vhsdream) ([#12399](https://github.com/community-scripts/ProxmoxVE/pull/12399))
### 💾 Core
- #### 🐞 Bug Fixes
- core: read from /dev/tty in all interactive prompts | fix empty or cropped logs due build process [@MickLesk](https://github.com/MickLesk) ([#12406](https://github.com/community-scripts/ProxmoxVE/pull/12406))
## 2026-02-27
### 🆕 New Scripts
- Strapi ([#12320](https://github.com/community-scripts/ProxmoxVE/pull/12320))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- TrueNAS VM: filter out new nightlies with MASTER [@juronja](https://github.com/juronja) ([#12355](https://github.com/community-scripts/ProxmoxVE/pull/12355))
### 💾 Core
- #### ✨ New Features
- core: graceful fallback for apt-get update failures [@MickLesk](https://github.com/MickLesk) ([#12386](https://github.com/community-scripts/ProxmoxVE/pull/12386))
- core: Improve error outputs across core functions [@MickLesk](https://github.com/MickLesk) ([#12378](https://github.com/community-scripts/ProxmoxVE/pull/12378))
## 2026-02-26
### 🆕 New Scripts
- Kima-Hub ([#12319](https://github.com/community-scripts/ProxmoxVE/pull/12319))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- tools.func: update glx alternatives / nvidia alternative if nvidia glx are missing [@MickLesk](https://github.com/MickLesk) ([#12372](https://github.com/community-scripts/ProxmoxVE/pull/12372))
- hotfix: overseer version [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12366](https://github.com/community-scripts/ProxmoxVE/pull/12366))
- #### ✨ New Features
- Add ffmpeg for booklore (ffprobe) [@MickLesk](https://github.com/MickLesk) ([#12371](https://github.com/community-scripts/ProxmoxVE/pull/12371))
- [QOL] Immich: add warning regarding library compilation time [@vhsdream](https://github.com/vhsdream) ([#12345](https://github.com/community-scripts/ProxmoxVE/pull/12345))
### 🧰 Tools
- #### 🐞 Bug Fixes
- Improves adguardhome-sync addon when running on alpine LXCs [@Darkangeel-hd](https://github.com/Darkangeel-hd) ([#12362](https://github.com/community-scripts/ProxmoxVE/pull/12362))
- #### ✨ New Features
- Add Alpine support and improve Tailscale install [@MickLesk](https://github.com/MickLesk) ([#12370](https://github.com/community-scripts/ProxmoxVE/pull/12370))
### 📚 Documentation
- fix wrong link on contributions README.md [@Darkangeel-hd](https://github.com/Darkangeel-hd) ([#12363](https://github.com/community-scripts/ProxmoxVE/pull/12363))
### 📂 Github
- github: add workflow to autom. close unauthorized new-script PRs [@MickLesk](https://github.com/MickLesk) ([#12356](https://github.com/community-scripts/ProxmoxVE/pull/12356))
## 2026-02-25
### 🆕 New Scripts
- Zerobyte ([#12321](https://github.com/community-scripts/ProxmoxVE/pull/12321))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix: overseer migration [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12340](https://github.com/community-scripts/ProxmoxVE/pull/12340))
- add: vikunja: daemon reload [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12323](https://github.com/community-scripts/ProxmoxVE/pull/12323))
- opnsense-VM: Use ip link to verify bridge existence [@MickLesk](https://github.com/MickLesk) ([#12329](https://github.com/community-scripts/ProxmoxVE/pull/12329))
- wger: Use $http_host for proxy Host header [@MickLesk](https://github.com/MickLesk) ([#12327](https://github.com/community-scripts/ProxmoxVE/pull/12327))
- Passbolt: Update Nginx config `client_max_body_size` [@tremor021](https://github.com/tremor021) ([#12313](https://github.com/community-scripts/ProxmoxVE/pull/12313))
- Zammad: configure Elasticsearch before zammad start [@MickLesk](https://github.com/MickLesk) ([#12308](https://github.com/community-scripts/ProxmoxVE/pull/12308))
- #### 🔧 Refactor
- OpenProject: Various fixes [@tremor021](https://github.com/tremor021) ([#12246](https://github.com/community-scripts/ProxmoxVE/pull/12246))
### 💾 Core
- #### 🐞 Bug Fixes
- Fix detection of ssh keys [@1-tempest](https://github.com/1-tempest) ([#12230](https://github.com/community-scripts/ProxmoxVE/pull/12230))
- #### ✨ New Features
- tools.func: Improve GitHub/Codeberg API error handling and error output [@MickLesk](https://github.com/MickLesk) ([#12330](https://github.com/community-scripts/ProxmoxVE/pull/12330))
- #### 🔧 Refactor
- core: remove duplicate traps, consolidate error handling and harden signal traps [@MickLesk](https://github.com/MickLesk) ([#12316](https://github.com/community-scripts/ProxmoxVE/pull/12316))
### 📂 Github
- github: improvements for node drift wf [@MickLesk](https://github.com/MickLesk) ([#12309](https://github.com/community-scripts/ProxmoxVE/pull/12309))
## 2026-02-24 ## 2026-02-24
### 🚀 Updated Scripts ### 🚀 Updated Scripts
- several scripts: add additional github link in source [@MickLesk](https://github.com/MickLesk) ([#12282](https://github.com/community-scripts/ProxmoxVE/pull/12282)) - adds further documentation during the installation script. [@d12rio](https://github.com/d12rio) ([#12248](https://github.com/community-scripts/ProxmoxVE/pull/12248))
- adds further documentation during the installation script. [@d12rio](https://github.com/d12rio) ([#12248](https://github.com/community-scripts/ProxmoxVE/pull/12248))
- #### 🐞 Bug Fixes - #### 🐞 Bug Fixes
- [Fix] PatchMon: remove VITE_API_URL from frontend env [@vhsdream](https://github.com/vhsdream) ([#12294](https://github.com/community-scripts/ProxmoxVE/pull/12294))
- fix(searxng): remove orphaned fi causing syntax error [@mark-jeffrey](https://github.com/mark-jeffrey) ([#12283](https://github.com/community-scripts/ProxmoxVE/pull/12283))
- Refactor n8n [@MickLesk](https://github.com/MickLesk) ([#12264](https://github.com/community-scripts/ProxmoxVE/pull/12264)) - Refactor n8n [@MickLesk](https://github.com/MickLesk) ([#12264](https://github.com/community-scripts/ProxmoxVE/pull/12264))
- Firefly: PHP bump [@tremor021](https://github.com/tremor021) ([#12247](https://github.com/community-scripts/ProxmoxVE/pull/12247)) - Firefly: PHP bump [@tremor021](https://github.com/tremor021) ([#12247](https://github.com/community-scripts/ProxmoxVE/pull/12247))
- #### ✨ New Features - #### ✨ New Features
- Databasus: add mariadb path for mysql/mariadb backups | add mongodb database tools [@MickLesk](https://github.com/MickLesk) ([#12259](https://github.com/community-scripts/ProxmoxVE/pull/12259))
- make searxng updateable [@shtefko](https://github.com/shtefko) ([#12207](https://github.com/community-scripts/ProxmoxVE/pull/12207)) - make searxng updateable [@shtefko](https://github.com/shtefko) ([#12207](https://github.com/community-scripts/ProxmoxVE/pull/12207))
- #### 💥 Breaking Changes
- fix: wealthfolio for v3 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11765](https://github.com/community-scripts/ProxmoxVE/pull/11765))
- #### 🔧 Refactor - #### 🔧 Refactor
- bump various scripts from Node 22 to 24 [@MickLesk](https://github.com/MickLesk) ([#12265](https://github.com/community-scripts/ProxmoxVE/pull/12265)) - bump various scripts from Node 22 to 24 [@MickLesk](https://github.com/MickLesk) ([#12265](https://github.com/community-scripts/ProxmoxVE/pull/12265))
### 💾 Core ### 💾 Core
- #### 🐞 Bug Fixes
- core: fix broken "command not found" after err_trap [@MickLesk](https://github.com/MickLesk) ([#12280](https://github.com/community-scripts/ProxmoxVE/pull/12280))
- #### ✨ New Features - #### ✨ New Features
- tools.func: add get_latest_gh_tag helper function [@MickLesk](https://github.com/MickLesk) ([#12261](https://github.com/community-scripts/ProxmoxVE/pull/12261)) - tools.func: add get_latest_gh_tag helper function [@MickLesk](https://github.com/MickLesk) ([#12261](https://github.com/community-scripts/ProxmoxVE/pull/12261))
@@ -1382,4 +1208,241 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- #### ✨ New Features - #### ✨ New Features
- [tools] Add `fetch_and_deploy_from_url()` [@tremor021](https://github.com/tremor021) ([#11376](https://github.com/community-scripts/ProxmoxVE/pull/11376)) - [tools] Add `fetch_and_deploy_from_url()` [@tremor021](https://github.com/tremor021) ([#11376](https://github.com/community-scripts/ProxmoxVE/pull/11376))
- core: php - improve module handling and prevent installation failures [@MickLesk](https://github.com/MickLesk) ([#11358](https://github.com/community-scripts/ProxmoxVE/pull/11358)) - core: php - improve module handling and prevent installation failures [@MickLesk](https://github.com/MickLesk) ([#11358](https://github.com/community-scripts/ProxmoxVE/pull/11358))
## 2026-01-29
### 🆕 New Scripts
- Alpine-Valkey [@MickLesk](https://github.com/MickLesk) ([#11320](https://github.com/community-scripts/ProxmoxVE/pull/11320))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Immich: Pin version to 2.5.2 [@vhsdream](https://github.com/vhsdream) ([#11335](https://github.com/community-scripts/ProxmoxVE/pull/11335))
- Kollection: Update to php 8.5 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11315](https://github.com/community-scripts/ProxmoxVE/pull/11315))
- Notifiarr: change installation check from apt to systemd service [@MickLesk](https://github.com/MickLesk) ([#11319](https://github.com/community-scripts/ProxmoxVE/pull/11319))
- #### ✨ New Features
- [FEAT] Immich: Enable Maintenance Mode before update [@vhsdream](https://github.com/vhsdream) ([#11342](https://github.com/community-scripts/ProxmoxVE/pull/11342))
- jellyfin: add logrotate instead of reducing log level [@MickLesk](https://github.com/MickLesk) ([#11326](https://github.com/community-scripts/ProxmoxVE/pull/11326))
- core: Add config file handling options | Fix Vikunja update with interactive overwrite [@MickLesk](https://github.com/MickLesk) ([#11317](https://github.com/community-scripts/ProxmoxVE/pull/11317))
- Immich: v2.5.0 [@vhsdream](https://github.com/vhsdream) ([#11240](https://github.com/community-scripts/ProxmoxVE/pull/11240))
- #### 💥 Breaking Changes
- fix: vikunja v1 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11308](https://github.com/community-scripts/ProxmoxVE/pull/11308))
- #### 🔧 Refactor
- Refactor: Byparr [@vhsdream](https://github.com/vhsdream) ([#11338](https://github.com/community-scripts/ProxmoxVE/pull/11338))
- cloudflare: Remove deprecated DNS-over-HTTPS proxy option [@MickLesk](https://github.com/MickLesk) ([#11068](https://github.com/community-scripts/ProxmoxVE/pull/11068))
### 💾 Core
- #### 🐞 Bug Fixes
- build.func: Replace storage variable with searchdomain variable [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11322](https://github.com/community-scripts/ProxmoxVE/pull/11322))
### 📂 Github
- Add workflow to lock closed issues [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11316](https://github.com/community-scripts/ProxmoxVE/pull/11316))
## 2026-01-28
### 🆕 New Scripts
- nodecast-tv ([#11287](https://github.com/community-scripts/ProxmoxVE/pull/11287))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Ubuntu 25.04 VM - Change default start from yes to no [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11292](https://github.com/community-scripts/ProxmoxVE/pull/11292))
- #### ✨ New Features
- various scripts: use setup_meilisearch function [@MickLesk](https://github.com/MickLesk) ([#11259](https://github.com/community-scripts/ProxmoxVE/pull/11259))
- #### 🔧 Refactor
- Refactor: NPMPlus / Default Login [@MickLesk](https://github.com/MickLesk) ([#11262](https://github.com/community-scripts/ProxmoxVE/pull/11262))
### 💾 Core
- #### 🐞 Bug Fixes
- core: sed patch for ram [@lavacano](https://github.com/lavacano) ([#11285](https://github.com/community-scripts/ProxmoxVE/pull/11285))
- Fix installer loop caused by invalid whiptail menu separator [@Mesteriis](https://github.com/Mesteriis) ([#11237](https://github.com/community-scripts/ProxmoxVE/pull/11237))
- core: fix Debian 13 LXC template root ownership bug [@MickLesk](https://github.com/MickLesk) ([#11277](https://github.com/community-scripts/ProxmoxVE/pull/11277))
- tools.func: prevent systemd-tmpfiles failure in unprivileged LXC during deb install [@MickLesk](https://github.com/MickLesk) ([#11271](https://github.com/community-scripts/ProxmoxVE/pull/11271))
- tools.func: fix php "wait_for" hint [@MickLesk](https://github.com/MickLesk) ([#11254](https://github.com/community-scripts/ProxmoxVE/pull/11254))
- #### ✨ New Features
- core: update dynamic values in LXC profile on update_motd_ip [@MickLesk](https://github.com/MickLesk) ([#11268](https://github.com/community-scripts/ProxmoxVE/pull/11268))
- tools.func: add new function - setup_meilisearch [@MickLesk](https://github.com/MickLesk) ([#11258](https://github.com/community-scripts/ProxmoxVE/pull/11258))
### 📂 Github
- github: add GitHub-based versions.json updater [@MickLesk](https://github.com/MickLesk) ([#10021](https://github.com/community-scripts/ProxmoxVE/pull/10021))
### 🌐 Website
- #### ✨ New Features
- Frontend: use github-versions.json for version display [@MickLesk](https://github.com/MickLesk) ([#11281](https://github.com/community-scripts/ProxmoxVE/pull/11281))
- #### 📝 Script Information
- fix: homarr: conf location [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11253](https://github.com/community-scripts/ProxmoxVE/pull/11253))
## 2026-01-27
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Immich: update libraw [@vhsdream](https://github.com/vhsdream) ([#11233](https://github.com/community-scripts/ProxmoxVE/pull/11233))
- #### ✨ New Features
- grist: enable optional enterprise features toggle [@MickLesk](https://github.com/MickLesk) ([#11239](https://github.com/community-scripts/ProxmoxVE/pull/11239))
- #### 🔧 Refactor
- Termix: use nginx.conf from upstream repo [@MickLesk](https://github.com/MickLesk) ([#11228](https://github.com/community-scripts/ProxmoxVE/pull/11228))
### 💾 Core
- #### ✨ New Features
- feat: add NVIDIA driver install prompt for GPU-enabled containers [@devdecrux](https://github.com/devdecrux) ([#11184](https://github.com/community-scripts/ProxmoxVE/pull/11184))
### 📚 Documentation
- doc setup_deb822_repo arg order [@chrnie](https://github.com/chrnie) ([#11215](https://github.com/community-scripts/ProxmoxVE/pull/11215))
- changelog: archive old entries to year/month files [@MickLesk](https://github.com/MickLesk) ([#11225](https://github.com/community-scripts/ProxmoxVE/pull/11225))
## 2026-01-26
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Ghost: Fix missing dependency [@tremor021](https://github.com/tremor021) ([#11196](https://github.com/community-scripts/ProxmoxVE/pull/11196))
- tracearr: fix install check and update node to version 24 [@durzo](https://github.com/durzo) ([#11188](https://github.com/community-scripts/ProxmoxVE/pull/11188))
- #### ✨ New Features
- jotty: full refactor / prebuild package [@MickLesk](https://github.com/MickLesk) ([#11059](https://github.com/community-scripts/ProxmoxVE/pull/11059))
- #### 💥 Breaking Changes
- Termix: Fixing Nginx configuration for 1.11.0 installs (read description for fix!) [@8b1th3r0](https://github.com/8b1th3r0) ([#11207](https://github.com/community-scripts/ProxmoxVE/pull/11207))
### 💾 Core
- #### 🐞 Bug Fixes
- core: refine cleanup_lxc to safely clear caches [@MickLesk](https://github.com/MickLesk) ([#11197](https://github.com/community-scripts/ProxmoxVE/pull/11197))
- #### ✨ New Features
- core: add nesting warning for systemd-based distributions [@MickLesk](https://github.com/MickLesk) ([#11208](https://github.com/community-scripts/ProxmoxVE/pull/11208))
### 🧰 Tools
- #### 🐞 Bug Fixes
- jellystat: correct WorkingDirectory to /backend [@MickLesk](https://github.com/MickLesk) ([#11201](https://github.com/community-scripts/ProxmoxVE/pull/11201))
## 2026-01-25
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- [FIX] Tautulli: ensure virtualenv is recreated during update; backup tautulli.db [@vhsdream](https://github.com/vhsdream) ([#11182](https://github.com/community-scripts/ProxmoxVE/pull/11182))
- [Fix] Pangolin: ensure additional JSON files are in place [@vhsdream](https://github.com/vhsdream) ([#11183](https://github.com/community-scripts/ProxmoxVE/pull/11183))
- Manyfold: fix permissions error [@vhsdream](https://github.com/vhsdream) ([#11165](https://github.com/community-scripts/ProxmoxVE/pull/11165))
- Termix: recreate nginx dirs and backup uploads on update [@MickLesk](https://github.com/MickLesk) ([#11169](https://github.com/community-scripts/ProxmoxVE/pull/11169))
- Deluge: correct service paths to /usr/local/bin [@MickLesk](https://github.com/MickLesk) ([#11170](https://github.com/community-scripts/ProxmoxVE/pull/11170))
- #### ✨ New Features
- Karakeep: Add the FFmpeg option to the installation script [@vonhyou](https://github.com/vonhyou) ([#11157](https://github.com/community-scripts/ProxmoxVE/pull/11157))
- apt-cacher-ng: add avahi-daemon for mDNS service discovery [@MickLesk](https://github.com/MickLesk) ([#11140](https://github.com/community-scripts/ProxmoxVE/pull/11140))
## 2026-01-24
### 🆕 New Scripts
- Manyfold ([#11143](https://github.com/community-scripts/ProxmoxVE/pull/11143))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- elementsynapse: correct parameter order in fetch_and_deploy_gh_release [@MickLesk](https://github.com/MickLesk) ([#11145](https://github.com/community-scripts/ProxmoxVE/pull/11145))
- leantime: fix backup file naming [@MickLesk](https://github.com/MickLesk) ([#11137](https://github.com/community-scripts/ProxmoxVE/pull/11137))
- [Hotfix] Element Synapse [@vhsdream](https://github.com/vhsdream) ([#11135](https://github.com/community-scripts/ProxmoxVE/pull/11135))
- authelia: use POSIX-safe arithmetic to avoid exit code 1 with set -e in subshells [@MickLesk](https://github.com/MickLesk) ([#11125](https://github.com/community-scripts/ProxmoxVE/pull/11125))
- Bitmagnet: PostgreSQL and environment variable fixes [@tremor021](https://github.com/tremor021) ([#11119](https://github.com/community-scripts/ProxmoxVE/pull/11119))
- Spoolman: move to uv [@vhsdream](https://github.com/vhsdream) ([#11121](https://github.com/community-scripts/ProxmoxVE/pull/11121))
- #### 🔧 Refactor
- bump crafty-controller to debian 13 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11094](https://github.com/community-scripts/ProxmoxVE/pull/11094))
- Netbox: Refactor [@vhsdream](https://github.com/vhsdream) ([#11126](https://github.com/community-scripts/ProxmoxVE/pull/11126))
- Flatnotes: Standard enforcing [@tremor021](https://github.com/tremor021) ([#11109](https://github.com/community-scripts/ProxmoxVE/pull/11109))
### 💾 Core
- #### 🐞 Bug Fixes
- nvidia: use versioned nvidia-utils package for Ubuntu fallback [@MickLesk](https://github.com/MickLesk) ([#11139](https://github.com/community-scripts/ProxmoxVE/pull/11139))
### 🌐 Website
- #### 📝 Script Information
- Byparr: Add config file path to website [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11120](https://github.com/community-scripts/ProxmoxVE/pull/11120))
## 2026-01-23
### 🆕 New Scripts
- Tracearr ([#11079](https://github.com/community-scripts/ProxmoxVE/pull/11079))
- Dawarich ([#11075](https://github.com/community-scripts/ProxmoxVE/pull/11075))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix: homarr: more ram [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11102](https://github.com/community-scripts/ProxmoxVE/pull/11102))
- plant-it: re-add JWT_SECRET [@MickLesk](https://github.com/MickLesk) ([#11098](https://github.com/community-scripts/ProxmoxVE/pull/11098))
- Tautulli: fix config backup and restore logic [@MickLesk](https://github.com/MickLesk) ([#11099](https://github.com/community-scripts/ProxmoxVE/pull/11099))
- Scanopy: remove integrated daemon script [@vhsdream](https://github.com/vhsdream) ([#11100](https://github.com/community-scripts/ProxmoxVE/pull/11100))
- fix: reitti start nginx [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11095](https://github.com/community-scripts/ProxmoxVE/pull/11095))
- add: uptime-kuma: chromium [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11081](https://github.com/community-scripts/ProxmoxVE/pull/11081))
- fix(install): Add typing_extensions to SearXNG Python dependencies [@ZarenOFF](https://github.com/ZarenOFF) ([#11074](https://github.com/community-scripts/ProxmoxVE/pull/11074))
- #### ✨ New Features
- Bump various scripts to Debian 13 (Trixie) [@MickLesk](https://github.com/MickLesk) ([#11093](https://github.com/community-scripts/ProxmoxVE/pull/11093))
- several scripts: bump default Alpine version to 3.23 [@MickLesk](https://github.com/MickLesk) ([#11082](https://github.com/community-scripts/ProxmoxVE/pull/11082))
- PDM: avoid installing useless package [@LongQT-sea](https://github.com/LongQT-sea) ([#10833](https://github.com/community-scripts/ProxmoxVE/pull/10833))
- #### 🔧 Refactor
- FHEM: Bump to Debian 13 [@tremor021](https://github.com/tremor021) ([#11061](https://github.com/community-scripts/ProxmoxVE/pull/11061))
- Duplicati: Bump to Debian 13 [@tremor021](https://github.com/tremor021) ([#11060](https://github.com/community-scripts/ProxmoxVE/pull/11060))
### 💾 Core
- #### ✨ New Features
- core: add IPv6 fallback support to get_current_ip functions | add check for SSH_KEYS_FILE in user_defaults [@MickLesk](https://github.com/MickLesk) ([#11067](https://github.com/community-scripts/ProxmoxVE/pull/11067))

View File

@@ -19,46 +19,44 @@ variables
color color
catch_errors catch_errors
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/komodo.sh"
function update_script() { function update_script() {
if [[ ! -d /opt/komodo ]]; then [[ -d /opt/komodo ]] || {
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi }
msg_warn "⚠️ ${APP} has been migrated to an addon script." msg_info "Updating ${APP}"
echo "" COMPOSE_FILE=$(find /opt/komodo -maxdepth 1 -type f -name '*.compose.yaml' ! -name 'compose.env' | head -n1)
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:" if [[ -z "$COMPOSE_FILE" ]]; then
echo -e "${TAB}${TAB}${GN}update_komodo${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}" msg_error "No valid compose file found in /opt/komodo!"
echo "" exit
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM fi
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then COMPOSE_BASENAME=$(basename "$COMPOSE_FILE")
msg_warn "Migration skipped. The old update will continue to work for now."
msg_info "Updating ${APP} (legacy)" if [[ "$COMPOSE_BASENAME" == "sqlite.compose.yaml" || "$COMPOSE_BASENAME" == "postgres.compose.yaml" ]]; then
COMPOSE_FILE=$(find /opt/komodo -maxdepth 1 -type f -name '*.compose.yaml' ! -name 'compose.env' | head -n1) msg_error "❌ Detected outdated Komodo setup using SQLite or PostgreSQL (FerretDB v1)."
if [[ -z "$COMPOSE_FILE" ]]; then echo -e "${YW}This configuration is no longer supported since Komodo v1.18.0.${CL}"
msg_error "No valid compose file found in /opt/komodo!" echo -e "${YW}Please follow the migration guide:${CL}"
exit 1 echo -e "${BGN}https://github.com/community-scripts/ProxmoxVE/discussions/5689${CL}\n"
fi
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env pull
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env up -d
msg_ok "Updated ${APP}"
exit exit
fi fi
msg_info "Migrating update function" BACKUP_FILE="/opt/komodo/${COMPOSE_BASENAME}.bak_$(date +%Y%m%d_%H%M%S)"
cat <<'MIGRATION_EOF' >/usr/bin/update cp "$COMPOSE_FILE" "$BACKUP_FILE" || {
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/komodo.sh)" msg_error "Failed to create backup of ${COMPOSE_BASENAME}!"
MIGRATION_EOF exit
chmod +x /usr/bin/update }
GITHUB_URL="https://raw.githubusercontent.com/moghtech/komodo/main/compose/${COMPOSE_BASENAME}"
ln -sf /usr/bin/update /usr/bin/update_komodo 2>/dev/null || true if ! curl -fsSL "$GITHUB_URL" -o "$COMPOSE_FILE"; then
msg_ok "Migration complete" msg_error "Failed to download ${COMPOSE_BASENAME} from GitHub!"
mv "$BACKUP_FILE" "$COMPOSE_FILE"
msg_info "Running addon update" exit
type=update bash <(curl -fsSL "${ADDON_SCRIPT}") fi
exit $STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env pull
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env up -d
msg_ok "Updated Alpine-Komodo"
msg_ok "Updated successfully!"
exit 0
} }
start start

View File

@@ -34,7 +34,6 @@ function update_script() {
NODE_VERSION="22" setup_nodejs NODE_VERSION="22" setup_nodejs
setup_mariadb setup_mariadb
setup_yq setup_yq
ensure_dependencies ffmpeg
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop booklore systemctl stop booklore
@@ -91,7 +90,7 @@ function update_script() {
echo "SERVER_PORT=6060" >>/opt/booklore_storage/.env echo "SERVER_PORT=6060" >>/opt/booklore_storage/.env
fi fi
sed -i 's|ExecStart=.*|ExecStart=/usr/bin/java -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+UseCompactObjectHeaders -XX:MaxRAMPercentage=75.0 -XX:+ExitOnOutOfMemoryError -jar /opt/booklore/dist/app.jar|' /etc/systemd/system/booklore.service sed -i 's|ExecStart=/usr/bin/java -jar|ExecStart=/usr/bin/java -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+UseCompactObjectHeaders -jar|' /etc/systemd/system/booklore.service
systemctl daemon-reload systemctl daemon-reload
msg_info "Starting Service" msg_info "Starting Service"

View File

@@ -19,8 +19,6 @@ variables
color color
catch_errors catch_errors
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/coolify.sh"
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
@@ -31,31 +29,10 @@ function update_script() {
exit exit
fi fi
msg_warn "⚠️ ${APP} has been migrated to an addon script." msg_info "Updating Coolify"
echo "" $STD bash <(curl -fsSL https://cdn.coollabs.io/coolify/install.sh)
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:" msg_ok "Updated Coolify"
echo -e "${TAB}${TAB}${GN}update_coolify${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}" msg_ok "Updated successfully!"
echo ""
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then
msg_warn "Migration skipped. The old update will continue to work for now."
msg_info "Updating ${APP} (legacy)"
$STD bash <(curl -fsSL https://cdn.coollabs.io/coolify/install.sh)
msg_ok "Updated ${APP}"
exit
fi
msg_info "Migrating update function"
cat <<'MIGRATION_EOF' >/usr/bin/update
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/coolify.sh)"
MIGRATION_EOF
chmod +x /usr/bin/update
ln -sf /usr/bin/update /usr/bin/update_coolify 2>/dev/null || true
msg_ok "Migration complete"
msg_info "Running addon update"
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
exit exit
} }

View File

@@ -38,31 +38,6 @@ function update_script() {
cp /opt/databasus/.env /opt/databasus.env.bak cp /opt/databasus/.env /opt/databasus.env.bak
msg_ok "Backed up Configuration" msg_ok "Backed up Configuration"
msg_info "Ensuring Database Clients"
# Create PostgreSQL version symlinks for compatibility
for v in 12 13 14 15 16 18; do
ln -sf /usr/lib/postgresql/17 /usr/lib/postgresql/$v
done
# Install MongoDB Database Tools via direct .deb (no APT repo for Debian 13)
if ! command -v mongodump &>/dev/null; then
[[ "$(get_os_info id)" == "ubuntu" ]] && MONGO_DIST="ubuntu2204" || MONGO_DIST="debian12"
fetch_and_deploy_from_url "https://fastdl.mongodb.org/tools/db/mongodb-database-tools-${MONGO_DIST}-x86_64-100.14.1.deb"
fi
[[ -f /usr/bin/mongodump ]] && ln -sf /usr/bin/mongodump /usr/local/mongodb-database-tools/bin/mongodump
[[ -f /usr/bin/mongorestore ]] && ln -sf /usr/bin/mongorestore /usr/local/mongodb-database-tools/bin/mongorestore
# Create MariaDB and MySQL client symlinks for compatibility
ensure_dependencies mariadb-client
mkdir -p /usr/local/mariadb-{10.6,12.1}/bin /usr/local/mysql-{5.7,8.0,8.4,9}/bin /usr/local/mongodb-database-tools/bin
for dir in /usr/local/mariadb-{10.6,12.1}/bin; do
ln -sf /usr/bin/mariadb-dump "$dir/mariadb-dump"
ln -sf /usr/bin/mariadb "$dir/mariadb"
done
for dir in /usr/local/mysql-{5.7,8.0,8.4,9}/bin; do
ln -sf /usr/bin/mariadb-dump "$dir/mysqldump"
ln -sf /usr/bin/mariadb "$dir/mysql"
done
msg_ok "Ensured Database Clients"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "databasus" "databasus/databasus" "tarball" "latest" "/opt/databasus" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "databasus" "databasus/databasus" "tarball" "latest" "/opt/databasus"
msg_info "Updating Databasus" msg_info "Updating Databasus"
@@ -74,7 +49,6 @@ function update_script() {
$STD /root/go/bin/swag init -g cmd/main.go -o swagger $STD /root/go/bin/swag init -g cmd/main.go -o swagger
$STD env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o databasus ./cmd/main.go $STD env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o databasus ./cmd/main.go
mv /opt/databasus/backend/databasus /opt/databasus/databasus mv /opt/databasus/backend/databasus /opt/databasus/databasus
mkdir -p /opt/databasus/ui/build
cp -r /opt/databasus/frontend/dist/* /opt/databasus/ui/build/ cp -r /opt/databasus/frontend/dist/* /opt/databasus/ui/build/
cp -r /opt/databasus/backend/migrations /opt/databasus/ cp -r /opt/databasus/backend/migrations /opt/databasus/
chown -R postgres:postgres /opt/databasus chown -R postgres:postgres /opt/databasus

View File

@@ -29,8 +29,6 @@ function update_script() {
exit exit
fi fi
ensure_dependencies libgeos++-dev libxml2-dev libxslt-dev libjemalloc-dev
if check_for_gh_release "dawarich" "Freika/dawarich"; then if check_for_gh_release "dawarich" "Freika/dawarich"; then
msg_info "Stopping Services" msg_info "Stopping Services"
systemctl stop dawarich-web dawarich-worker systemctl stop dawarich-web dawarich-worker

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 tteck # Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster) | Migration: MickLesk (CanbiZ) # Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://dockge.kuma.pet/ # Source: https://dockge.kuma.pet/
@@ -19,45 +19,26 @@ variables
color color
catch_errors catch_errors
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dockge.sh"
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources check_container_resources
if [[ ! -d /opt/dockge ]]; then if [[ ! -d /opt/dockge ]]; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
msg_warn "⚠️ ${APP} has been migrated to an addon script." msg_info "Updating base system"
echo "" $STD apt update
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:" $STD apt upgrade -y
echo -e "${TAB}${TAB}${GN}update_dockge${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}" msg_ok "Base system updated"
echo ""
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then
msg_warn "Migration skipped. The old update will continue to work for now."
msg_info "Updating ${APP} (legacy)"
cd /opt/dockge
$STD docker compose pull
$STD docker compose up -d
msg_ok "Updated ${APP}"
exit
fi
msg_info "Migrating update function" msg_info "Updating Dockge"
cat <<'MIGRATION_EOF' >/usr/bin/update cd /opt/dockge
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dockge.sh)" $STD docker compose pull
MIGRATION_EOF $STD docker compose up -d
chmod +x /usr/bin/update msg_ok "Updated Dockge"
msg_ok "Updated successfully!"
ln -sf /usr/bin/update /usr/bin/update_dockge 2>/dev/null || true
msg_ok "Migration complete"
msg_info "Running addon update"
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
exit exit
} }

View File

@@ -19,8 +19,6 @@ variables
color color
catch_errors catch_errors
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dokploy.sh"
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
@@ -31,31 +29,10 @@ function update_script() {
exit exit
fi fi
msg_warn "⚠️ ${APP} has been migrated to an addon script." msg_info "Updating Dokploy"
echo "" curl -sSL https://dokploy.com/install.sh | $STD bash -s update
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:" msg_ok "Updated Dokploy"
echo -e "${TAB}${TAB}${GN}update_dokploy${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}" msg_ok "Updated successfully!"
echo ""
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then
msg_warn "Migration skipped. The old update will continue to work for now."
msg_info "Updating ${APP} (legacy)"
curl -sSL https://dokploy.com/install.sh | $STD bash -s update
msg_ok "Updated ${APP}"
exit
fi
msg_info "Migrating update function"
cat <<'MIGRATION_EOF' >/usr/bin/update
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dokploy.sh)"
MIGRATION_EOF
chmod +x /usr/bin/update
ln -sf /usr/bin/update /usr/bin/update_dokploy 2>/dev/null || true
msg_ok "Migration complete"
msg_info "Running addon update"
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
exit exit
} }

View File

@@ -51,23 +51,11 @@ function update_script() {
cd /opt/gramps-web-api cd /opt/gramps-web-api
GRAMPS_API_CONFIG=/opt/gramps-web/config/config.cfg \ GRAMPS_API_CONFIG=/opt/gramps-web/config/config.cfg \
ALEMBIC_CONFIG=/opt/gramps-web-api/alembic.ini \ ALEMBIC_CONFIG=/opt/gramps-web-api/alembic.ini \
GRAMPSHOME=/opt/gramps-web/data \ GRAMPSHOME=/opt/gramps-web/data/gramps \
GRAMPS_DATABASE_PATH=/opt/gramps-web/data/gramps/grampsdb \ GRAMPS_DATABASE_PATH=/opt/gramps-web/data/gramps/grampsdb \
$STD /opt/gramps-web/venv/bin/python3 -m gramps_webapi user migrate $STD /opt/gramps-web/venv/bin/python3 -m gramps_webapi user migrate
msg_ok "Applied Database Migration" msg_ok "Applied Database Migration"
msg_info "Updating Gramps Addons"
GRAMPS_VERSION=$(/opt/gramps-web/venv/bin/python3 -c "import gramps.version; print('%s%s' % (gramps.version.VERSION_TUPLE[0], gramps.version.VERSION_TUPLE[1]))" 2>/dev/null || echo "60")
GRAMPS_PLUGINS_DIR="/opt/gramps-web/data/gramps/gramps${GRAMPS_VERSION}/plugins"
mkdir -p "$GRAMPS_PLUGINS_DIR"
$STD wget -q https://github.com/gramps-project/addons/archive/refs/heads/master.zip -O /tmp/gramps-addons.zip
for addon in FilterRules JSON; do
unzip -p /tmp/gramps-addons.zip "addons-master/gramps${GRAMPS_VERSION}/download/${addon}.addon.tgz" |
tar -xz -C "$GRAMPS_PLUGINS_DIR"
done
rm -f /tmp/gramps-addons.zip
msg_ok "Updated Gramps Addons"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start gramps-web systemctl start gramps-web
msg_ok "Started Service" msg_ok "Started Service"

View File

@@ -1,6 +0,0 @@
__ __ _ __ __ __
/ //_/(_)___ ___ ____ _ / / / /_ __/ /_
/ ,< / / __ `__ \/ __ `/_____/ /_/ / / / / __ \
/ /| |/ / / / / / / /_/ /_____/ __ / /_/ / /_/ /
/_/ |_/_/_/ /_/ /_/\__,_/ /_/ /_/\__,_/_.___/

6
ct/headers/palmr Normal file
View File

@@ -0,0 +1,6 @@
____ __
/ __ \____ _/ /___ ___ _____
/ /_/ / __ `/ / __ `__ \/ ___/
/ ____/ /_/ / / / / / / / /
/_/ \__,_/_/_/ /_/ /_/_/

View File

@@ -1,6 +0,0 @@
____ _____ __
/ __ \_________ / __(_) /___ ___________
/ /_/ / ___/ __ \/ /_/ / / __ `/ ___/ ___/
/ ____/ / / /_/ / __/ / / /_/ / / / /
/_/ /_/ \____/_/ /_/_/\__,_/_/ /_/

View File

@@ -1,6 +0,0 @@
_____ __ _
/ ___// /__________ _____ (_)
\__ \/ __/ ___/ __ `/ __ \/ /
___/ / /_/ / / /_/ / /_/ / /
/____/\__/_/ \__,_/ .___/_/
/_/

View File

@@ -1,6 +0,0 @@
_____ __ __
/__ / ___ _________ / /_ __ __/ /____
/ / / _ \/ ___/ __ \/ __ \/ / / / __/ _ \
/ /__/ __/ / / /_/ / /_/ / /_/ / /_/ __/
/____/\___/_/ \____/_.___/\__, /\__/\___/
/____/

View File

@@ -72,9 +72,9 @@ EOF
SOURCE_DIR=${STAGING_DIR}/image-source SOURCE_DIR=${STAGING_DIR}/image-source
cd /tmp cd /tmp
if [[ -f ~/.intel_version ]]; then if [[ -f ~/.intel_version ]]; then
curl -fsSLO https://raw.githubusercontent.com/immich-app/immich/refs/heads/main/machine-learning/Dockerfile curl -fsSLO https://raw.githubusercontent.com/immich-app/base-images/refs/heads/main/server/Dockerfile
readarray -t INTEL_URLS < <( readarray -t INTEL_URLS < <(
sed -n "/intel-[igc|opencl]/p" ./Dockerfile | awk '{print $3}' sed -n "/intel-[igc|opencl]/p" ./Dockerfile | awk '{print $2}'
sed -n "/libigdgmm12/p" ./Dockerfile | awk '{print $3}' sed -n "/libigdgmm12/p" ./Dockerfile | awk '{print $3}'
) )
INTEL_RELEASE="$(grep "intel-opencl-icd_" ./Dockerfile | awk -F '_' '{print $2}')" INTEL_RELEASE="$(grep "intel-opencl-icd_" ./Dockerfile | awk -F '_' '{print $2}')"
@@ -97,7 +97,7 @@ EOF
if [[ -f ~/.immich_library_revisions ]]; then if [[ -f ~/.immich_library_revisions ]]; then
libraries=("libjxl" "libheif" "libraw" "imagemagick" "libvips") libraries=("libjxl" "libheif" "libraw" "imagemagick" "libvips")
cd "$BASE_DIR" cd "$BASE_DIR"
msg_warn "Checking for updates to custom image-processing libraries (recompile time: 2-15min per library)" msg_info "Checking for updates to custom image-processing libraries"
$STD git pull $STD git pull
for library in "${libraries[@]}"; do for library in "${libraries[@]}"; do
compile_"$library" compile_"$library"
@@ -214,9 +214,9 @@ EOF
export VIRTUAL_ENV="${ML_DIR}"/ml-venv export VIRTUAL_ENV="${ML_DIR}"/ml-venv
if [[ -f ~/.openvino ]]; then if [[ -f ~/.openvino ]]; then
msg_info "Updating HW-accelerated machine-learning" msg_info "Updating HW-accelerated machine-learning"
$STD uv add --no-sync --optional openvino onnxruntime-openvino==1.24.1 --active -n -p python3.13 --managed-python $STD uv add --no-sync --optional openvino onnxruntime-openvino==1.20.0 --active -n -p python3.12 --managed-python
$STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p python3.13 --managed-python $STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p python3.12 --managed-python
patchelf --clear-execstack "${VIRTUAL_ENV}/lib/python3.13/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-313-x86_64-linux-gnu.so" patchelf --clear-execstack "${VIRTUAL_ENV}/lib/python3.12/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-312-x86_64-linux-gnu.so"
msg_ok "Updated HW-accelerated machine-learning" msg_ok "Updated HW-accelerated machine-learning"
else else
msg_info "Updating machine-learning" msg_info "Updating machine-learning"

View File

@@ -6,7 +6,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
# Source: https://www.iobroker.net/#en/intro | Github: https://github.com/ioBroker/ioBroker.js-controller # Source: https://www.iobroker.net/#en/intro | Github: https://github.com/ioBroker/ioBroker.js-controller
APP="ioBroker" APP="ioBroker"
var_tags="${var_tags:-automation}" var_tags="${var_tags:-automtation}"
var_cpu="${var_cpu:-2}" var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}" var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}" var_disk="${var_disk:-8}"

View File

@@ -28,7 +28,7 @@ function update_script() {
exit exit
fi fi
NODE_VERSION="24" NODE_MODULE="yarn,npm,pm2" setup_nodejs NODE_VERSION=24 NODE_MODULE="yarn,npm,pm2" setup_nodejs
if check_for_gh_release "joplin-server" "laurent22/joplin"; then if check_for_gh_release "joplin-server" "laurent22/joplin"; then
msg_info "Stopping Services" msg_info "Stopping Services"

View File

@@ -1,79 +0,0 @@
#!/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/Chevron7Locked/kima-hub
APP="Kima-Hub"
var_tags="${var_tags:-music;streaming;media}"
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_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/kima-hub ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "kima-hub" "Chevron7Locked/kima-hub"; then
msg_info "Stopping Services"
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"
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"
msg_info "Rebuilding Backend"
cd /opt/kima-hub/backend
$STD npm install
$STD npm run build
$STD npx prisma generate
$STD npx prisma migrate deploy
msg_ok "Rebuilt Backend"
msg_info "Rebuilding Frontend"
cd /opt/kima-hub/frontend
$STD npm install
$STD npm run build
msg_ok "Rebuilt Frontend"
msg_info "Starting Services"
systemctl start kima-backend kima-frontend kima-analyzer kima-analyzer-clap
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 "${TAB}${GATEWAY}${BGN}http://${IP}:3030${CL}"

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG # Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ) # Author: MickLesk
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://komo.do/ # Source: https://komo.do/
@@ -19,49 +19,49 @@ variables
color color
catch_errors catch_errors
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/komodo.sh"
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources check_container_resources
if [[ ! -d /opt/komodo ]]; then [[ -d /opt/komodo ]] || {
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit 1
}
msg_info "Updating Komodo"
COMPOSE_FILE=$(find /opt/komodo -maxdepth 1 -type f -name '*.compose.yaml' ! -name 'compose.env' | head -n1)
if [[ -z "$COMPOSE_FILE" ]]; then
msg_error "No valid compose file found in /opt/komodo!"
exit 1
fi
COMPOSE_BASENAME=$(basename "$COMPOSE_FILE")
if [[ "$COMPOSE_BASENAME" == "sqlite.compose.yaml" || "$COMPOSE_BASENAME" == "postgres.compose.yaml" ]]; then
msg_error "❌ Detected outdated Komodo setup using SQLite or PostgreSQL (FerretDB v1)."
echo -e "${YW}This configuration is no longer supported since Komodo v1.18.0.${CL}"
echo -e "${YW}Please follow the migration guide:${CL}"
echo -e "${BGN}https://github.com/community-scripts/ProxmoxVE/discussions/5689${CL}\n"
exit 1
fi fi
msg_warn "⚠️ ${APP} has been migrated to an addon script." BACKUP_FILE="/opt/komodo/${COMPOSE_BASENAME}.bak_$(date +%Y%m%d_%H%M%S)"
echo "" cp "$COMPOSE_FILE" "$BACKUP_FILE" || {
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:" msg_error "Failed to create backup of ${COMPOSE_BASENAME}!"
echo -e "${TAB}${TAB}${GN}update_komodo${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}" exit 1
echo "" }
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM GITHUB_URL="https://raw.githubusercontent.com/moghtech/komodo/main/compose/${COMPOSE_BASENAME}"
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then if ! curl -fsSL "$GITHUB_URL" -o "$COMPOSE_FILE"; then
msg_warn "Migration skipped. The old update will continue to work for now." msg_error "Failed to download ${COMPOSE_BASENAME} from GitHub!"
msg_info "Updating ${APP} (legacy)" mv "$BACKUP_FILE" "$COMPOSE_FILE"
COMPOSE_FILE=$(find /opt/komodo -maxdepth 1 -type f -name '*.compose.yaml' ! -name 'compose.env' | head -n1) exit 1
if [[ -z "$COMPOSE_FILE" ]]; then
msg_error "No valid compose file found in /opt/komodo!"
exit 1
fi
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env pull
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env up -d
msg_ok "Updated ${APP}"
exit
fi fi
if ! grep -qxF 'COMPOSE_KOMODO_BACKUPS_PATH=/etc/komodo/backups' /opt/komodo/compose.env; then
msg_info "Migrating update function" sed -i '/^COMPOSE_KOMODO_IMAGE_TAG=latest$/a COMPOSE_KOMODO_BACKUPS_PATH=/etc/komodo/backups' /opt/komodo/compose.env
cat <<'MIGRATION_EOF' >/usr/bin/update fi
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/komodo.sh)" $STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env pull
MIGRATION_EOF $STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env up -d
chmod +x /usr/bin/update msg_ok "Updated Komodo"
ln -sf /usr/bin/update /usr/bin/update_komodo 2>/dev/null || true
msg_ok "Migration complete"
msg_info "Running addon update"
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
exit exit
} }

View File

@@ -36,7 +36,6 @@ function update_script() {
[[ -f /opt/ombi/Ombi.db ]] && mv /opt/ombi/Ombi.db /opt [[ -f /opt/ombi/Ombi.db ]] && mv /opt/ombi/Ombi.db /opt
[[ -f /opt/ombi/OmbiExternal.db ]] && mv /opt/ombi/OmbiExternal.db /opt [[ -f /opt/ombi/OmbiExternal.db ]] && mv /opt/ombi/OmbiExternal.db /opt
[[ -f /opt/ombi/OmbiSettings.db ]] && mv /opt/ombi/OmbiSettings.db /opt [[ -f /opt/ombi/OmbiSettings.db ]] && mv /opt/ombi/OmbiSettings.db /opt
[[ -f /opt/ombi/database.json ]] && mv /opt/ombi/database.json /opt
msg_ok "Backup created" msg_ok "Backup created"
rm -rf /opt/ombi rm -rf /opt/ombi
@@ -44,7 +43,6 @@ function update_script() {
[[ -f /opt/Ombi.db ]] && mv /opt/Ombi.db /opt/ombi [[ -f /opt/Ombi.db ]] && mv /opt/Ombi.db /opt/ombi
[[ -f /opt/OmbiExternal.db ]] && mv /opt/OmbiExternal.db /opt/ombi [[ -f /opt/OmbiExternal.db ]] && mv /opt/OmbiExternal.db /opt/ombi
[[ -f /opt/OmbiSettings.db ]] && mv /opt/OmbiSettings.db /opt/ombi [[ -f /opt/OmbiSettings.db ]] && mv /opt/OmbiSettings.db /opt/ombi
[[ -f /opt/database.json ]] && mv /opt/database.json /opt/ombi
msg_info "Starting Service" msg_info "Starting Service"
systemctl start ombi systemctl start ombi

View File

@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}" var_ram="${var_ram:-4096}"
var_disk="${var_disk:-8}" var_disk="${var_disk:-8}"
var_os="${var_os:-debian}" var_os="${var_os:-debian}"
var_version="${var_version:-13}" var_version="${var_version:-12}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
header_info "$APP" header_info "$APP"
@@ -27,11 +27,10 @@ function update_script() {
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
msg_info "Updating ${APP}"
msg_info "Updating OpenProject"
$STD apt update $STD apt update
$STD apt install --only-upgrade -y openproject $STD apt install --only-upgrade -y openproject
msg_ok "Updated OpenProject" msg_ok "Updated ${APP}"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
exit exit
} }

View File

@@ -28,7 +28,7 @@ function update_script() {
exit exit
fi fi
if [[ -f "$HOME/.overseerr" ]] && [[ "$(printf '%s\n' "1.35.0" "$(cat "$HOME/.overseerr")" | sort -V | head -n1)" == "1.35.0" ]]; then if [[ -f "$HOME/.overseerr" ]] && [[ "$(cat "$HOME/.overseerr")" == "1.34.0" ]]; then
echo echo
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Overseerr v1.34.0 detected." echo "Overseerr v1.34.0 detected."

75
ct/palmr.sh Normal file
View File

@@ -0,0 +1,75 @@
#!/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/kyantech/Palmr
APP="Palmr"
var_tags="${var_tags:-files}"
var_cpu="${var_cpu:-4}"
var_ram="${var_ram:-6144}"
var_disk="${var_disk:-6}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
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/palmr_data ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "palmr" "kyantech/Palmr"; then
msg_info "Stopping Services"
systemctl stop palmr-frontend palmr-backend
msg_ok "Stopped Services"
cp /opt/palmr/apps/server/.env /opt/palmr.env
rm -rf /opt/palmr
fetch_and_deploy_gh_release "Palmr" "kyantech/Palmr" "tarball" "latest" "/opt/palmr"
PNPM="$(jq -r '.packageManager' /opt/palmr/package.json)"
NODE_VERSION="24" NODE_MODULE="$PNPM" setup_nodejs
msg_info "Updating ${APP}"
cd /opt/palmr/apps/server
mv /opt/palmr.env /opt/palmr/apps/server/.env
$STD pnpm install
$STD npx prisma generate
$STD npx prisma migrate deploy
$STD npx prisma db push
$STD pnpm build
cd /opt/palmr/apps/web
export NODE_ENV=production
export NEXT_TELEMETRY_DISABLED=1
mv ./.env.example ./.env
$STD pnpm install
$STD pnpm build
chown -R palmr:palmr /opt/palmr_data /opt/palmr
msg_ok "Updated ${APP}"
msg_info "Starting Services"
systemctl start palmr-backend palmr-frontend
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 "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"

View File

@@ -9,7 +9,7 @@ APP="Pangolin"
var_tags="${var_tags:-proxy}" var_tags="${var_tags:-proxy}"
var_cpu="${var_cpu:-2}" var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}" var_ram="${var_ram:-4096}"
var_disk="${var_disk:-10}" var_disk="${var_disk:-5}"
var_os="${var_os:-debian}" var_os="${var_os:-debian}"
var_version="${var_version:-13}" var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
@@ -29,8 +29,6 @@ function update_script() {
exit exit
fi fi
ensure_dependencies build-essential python3
NODE_VERSION="24" setup_nodejs NODE_VERSION="24" setup_nodejs
if check_for_gh_release "pangolin" "fosrl/pangolin"; then if check_for_gh_release "pangolin" "fosrl/pangolin"; then

View File

@@ -51,10 +51,13 @@ function update_script() {
msg_info "Updating PatchMon" msg_info "Updating PatchMon"
VERSION=$(get_latest_github_release "PatchMon/PatchMon") VERSION=$(get_latest_github_release "PatchMon/PatchMon")
PROTO="$(sed -n '/SERVER_PROTOCOL/s/[^=]*=//p' /opt/backend.env)"
HOST="$(sed -n '/SERVER_HOST/s/[^=]*=//p' /opt/backend.env)"
SERVER_PORT="$(sed -n '/SERVER_PORT/s/[^=]*=//p' /opt/backend.env)" SERVER_PORT="$(sed -n '/SERVER_PORT/s/[^=]*=//p' /opt/backend.env)"
[[ "$PROTO" == "http" ]] && PORT=":3001"
sed -i 's/PORT=3399/PORT=3001/' /opt/backend.env sed -i 's/PORT=3399/PORT=3001/' /opt/backend.env
sed -i -e "s/VERSION=.*/VERSION=$VERSION/" \ sed -i -e "s/VERSION=.*/VERSION=$VERSION/" \
-e '/^VITE_API_URL/d' /opt/frontend.env -e "\|VITE_API_URL=|s|http.*|${PROTO:-http}://${HOST:-$LOCAL_IP}${PORT:-}/api/v1|" /opt/frontend.env
export NODE_ENV=production export NODE_ENV=production
cd /opt/patchmon cd /opt/patchmon
$STD npm install --no-audit --no-fund --no-save --ignore-scripts $STD npm install --no-audit --no-fund --no-save --ignore-scripts

View File

@@ -1,85 +0,0 @@
#!/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: michelroegl-brunner
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/Dictionarry-Hub/profilarr
APP="Profilarr"
var_tags="${var_tags:-arr;radarr;sonarr;config}"
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_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/profilarr ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "profilarr" "Dictionarry-Hub/profilarr"; then
msg_info "Stopping Service"
systemctl stop profilarr
msg_ok "Stopped Service"
msg_info "Backing up Data"
if [[ -d /config ]]; then
cp -r /config /opt/profilarr_config_backup
fi
msg_ok "Backed up Data"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "profilarr" "Dictionarry-Hub/profilarr" "tarball"
msg_info "Installing Python Dependencies"
cd /opt/profilarr/backend
$STD uv venv /opt/profilarr/backend/.venv
sed 's/==/>=/g' requirements.txt >requirements-relaxed.txt
$STD uv pip install --python /opt/profilarr/backend/.venv/bin/python -r requirements-relaxed.txt
rm -f requirements-relaxed.txt
msg_ok "Installed Python Dependencies"
msg_info "Building Frontend"
if [[ -d /opt/profilarr/frontend ]]; then
cd /opt/profilarr/frontend
$STD npm install
$STD npm run build
cp -r dist /opt/profilarr/backend/app/static
fi
msg_ok "Built Frontend"
msg_info "Restoring Data"
if [[ -d /opt/profilarr_config_backup ]]; then
mkdir -p /config
cp -r /opt/profilarr_config_backup/. /config/
rm -rf /opt/profilarr_config_backup
fi
msg_ok "Restored Data"
msg_info "Starting Service"
systemctl start profilarr
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}:6868${CL}"

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 tteck # Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster) | Migration: MickLesk (CanbiZ) # Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://runtipi.io/ # Source: https://runtipi.io/
@@ -19,43 +19,16 @@ variables
color color
catch_errors catch_errors
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/runtipi.sh"
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources check_container_resources
if [[ ! -d /opt/runtipi ]]; then if [[ ! -d /opt/runtipi ]]; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
cd /opt/runtipi && ./runtipi-cli update latest
msg_warn "⚠️ ${APP} has been migrated to an addon script." msg_ok "Updated successfully!"
echo ""
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:"
echo -e "${TAB}${TAB}${GN}update_runtipi${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}"
echo ""
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then
msg_warn "Migration skipped. The old update will continue to work for now."
msg_info "Updating ${APP} (legacy)"
cd /opt/runtipi && ./runtipi-cli update latest
msg_ok "Updated ${APP}"
exit
fi
msg_info "Migrating update function"
cat <<'MIGRATION_EOF' >/usr/bin/update
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/runtipi.sh)"
MIGRATION_EOF
chmod +x /usr/bin/update
ln -sf /usr/bin/update /usr/bin/update_runtipi 2>/dev/null || true
msg_ok "Migration complete"
msg_info "Running addon update"
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
exit exit
} }

View File

@@ -52,6 +52,7 @@ function update_script() {
systemctl start searxng systemctl start searxng
msg_ok "Started Services" msg_ok "Started Services"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi
exit exit
} }
start start

View File

@@ -29,6 +29,8 @@ function update_script() {
exit exit
fi fi
NODE_VERSION="25" setup_nodejs
if check_for_gh_release "sparkyfitness" "CodeWithCJ/SparkyFitness"; then if check_for_gh_release "sparkyfitness" "CodeWithCJ/SparkyFitness"; then
msg_info "Stopping Services" msg_info "Stopping Services"
systemctl stop sparkyfitness-server nginx systemctl stop sparkyfitness-server nginx
@@ -46,9 +48,6 @@ function update_script() {
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "sparkyfitness" "CodeWithCJ/SparkyFitness" "tarball" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "sparkyfitness" "CodeWithCJ/SparkyFitness" "tarball"
PNPM_VERSION="$(jq -r '.packageManager | split("@")[1]' /opt/sparkyfitness/package.json)"
NODE_VERSION="25" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs
msg_info "Updating Sparky Fitness Backend" msg_info "Updating Sparky Fitness Backend"
cd /opt/sparkyfitness/SparkyFitnessServer cd /opt/sparkyfitness/SparkyFitnessServer
$STD npm install $STD npm install
@@ -56,8 +55,8 @@ function update_script() {
msg_info "Updating Sparky Fitness Frontend (Patience)" msg_info "Updating Sparky Fitness Frontend (Patience)"
cd /opt/sparkyfitness/SparkyFitnessFrontend cd /opt/sparkyfitness/SparkyFitnessFrontend
$STD pnpm install $STD npm install
$STD pnpm run build $STD npm run build
cp -a /opt/sparkyfitness/SparkyFitnessFrontend/dist/. /var/www/sparkyfitness/ cp -a /opt/sparkyfitness/SparkyFitnessFrontend/dist/. /var/www/sparkyfitness/
msg_ok "Updated Sparky Fitness Frontend" msg_ok "Updated Sparky Fitness Frontend"

View File

@@ -1,61 +0,0 @@
#!/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: pespinel
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://strapi.io/
APP="Strapi"
var_tags="${var_tags:-cms}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
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/strapi.service ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
NODE_VERSION="24" setup_nodejs
msg_info "Stopping Strapi"
systemctl stop strapi
msg_ok "Stopped Strapi"
msg_info "Updating Strapi"
cd /opt/strapi
$STD npx @strapi/upgrade minor --yes
msg_ok "Updated Strapi"
msg_info "Building Strapi"
export NODE_OPTIONS="--max-old-space-size=3072"
$STD npm run build
msg_ok "Built Strapi"
msg_info "Starting Strapi"
systemctl start strapi
msg_ok "Started Strapi"
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 "${TAB}${GATEWAY}${BGN}http://${IP}:1337${CL}"

View File

@@ -65,7 +65,6 @@ function update_script() {
msg_ok "Stopped Service" msg_ok "Stopped Service"
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary"
$STD systemctl daemon-reload
msg_info "Starting Service" msg_info "Starting Service"
systemctl start vikunja systemctl start vikunja

View File

@@ -43,15 +43,16 @@ function update_script() {
msg_info "Building Frontend (patience)" msg_info "Building Frontend (patience)"
cd /opt/wealthfolio cd /opt/wealthfolio
export BUILD_TARGET=web
$STD pnpm install --frozen-lockfile $STD pnpm install --frozen-lockfile
$STD pnpm --filter frontend... build $STD pnpm tsc
$STD pnpm vite build
msg_ok "Built Frontend" msg_ok "Built Frontend"
msg_info "Building Backend (patience)" msg_info "Building Backend (patience)"
cd /opt/wealthfolio/src-server
source ~/.cargo/env source ~/.cargo/env
$STD cargo build --release --manifest-path apps/server/Cargo.toml $STD cargo build --release --manifest-path Cargo.toml
cp /opt/wealthfolio/target/release/wealthfolio-server /usr/local/bin/wealthfolio-server cp /opt/wealthfolio/src-server/target/release/wealthfolio-server /usr/local/bin/wealthfolio-server
chmod +x /usr/local/bin/wealthfolio-server chmod +x /usr/local/bin/wealthfolio-server
msg_ok "Built Backend" msg_ok "Built Backend"
@@ -62,7 +63,7 @@ function update_script() {
msg_ok "Restored Data" msg_ok "Restored Data"
msg_info "Cleaning Up" msg_info "Cleaning Up"
rm -rf /opt/wealthfolio/target rm -rf /opt/wealthfolio/src-server/target
rm -rf /root/.cargo/registry rm -rf /root/.cargo/registry
rm -rf /opt/wealthfolio/node_modules rm -rf /opt/wealthfolio/node_modules
msg_ok "Cleaned Up" msg_ok "Cleaned Up"

View File

@@ -1,71 +0,0 @@
#!/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: community-scripts
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/nicotsx/zerobyte
APP="Zerobyte"
var_tags="${var_tags:-backup;encryption;restic}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-6144}"
var_disk="${var_disk:-10}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
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/zerobyte ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "zerobyte" "nicotsx/zerobyte"; then
msg_info "Stopping Service"
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"
NODE_VERSION="24" setup_nodejs
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "zerobyte" "nicotsx/zerobyte" "tarball"
msg_info "Building Zerobyte"
export NODE_OPTIONS="--max-old-space-size=3072"
cd /opt/zerobyte
$STD bun install
$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"
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}:4096${CL}"

View File

@@ -29,7 +29,7 @@ function update_script() {
fi fi
if check_for_gh_release "Zigbee2MQTT" "Koenkk/zigbee2mqtt"; then if check_for_gh_release "Zigbee2MQTT" "Koenkk/zigbee2mqtt"; then
NODE_VERSION="24" NODE_MODULE="pnpm@$(curl -fsSL https://raw.githubusercontent.com/Koenkk/zigbee2mqtt/master/package.json | jq -r '.packageManager | split("@")[1]')" setup_nodejs NODE_VERSION=24 NODE_MODULE="pnpm@$(curl -fsSL https://raw.githubusercontent.com/Koenkk/zigbee2mqtt/master/package.json | jq -r '.packageManager | split("@")[1]')" setup_nodejs
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop zigbee2mqtt systemctl stop zigbee2mqtt
msg_ok "Stopped Service" msg_ok "Stopped Service"

View File

@@ -175,7 +175,7 @@ All scripts and configurations must follow our coding standards to ensure consis
### Available Guides ### Available Guides
- **[CONTRIBUTING.md](CONTRIBUTING.md)** - Essential coding standards and best practices - **[CONTRIBUTING.md](CONTRIBUTING.md)** - Essential coding standards and best practices
- **[CODE-AUDIT.md](CODE-AUDIT.md)** - Code review checklist and audit procedures - **[CODE_AUDIT.md](CODE_AUDIT.md)** - Code review checklist and audit procedures
- **[GUIDE.md](GUIDE.md)** - Comprehensive contribution guide - **[GUIDE.md](GUIDE.md)** - Comprehensive contribution guide
- **[HELPER_FUNCTIONS.md](HELPER_FUNCTIONS.md)** - Reference for all tools.func helper functions - **[HELPER_FUNCTIONS.md](HELPER_FUNCTIONS.md)** - Reference for all tools.func helper functions
- **Container Scripts** - `/ct/` templates and guidelines - **Container Scripts** - `/ct/` templates and guidelines

View File

@@ -1,56 +1,52 @@
{ {
"name": "Coolify", "name": "Coolify",
"slug": "coolify", "slug": "coolify",
"categories": [ "categories": [
3 3
], ],
"date_created": "2025-12-09", "date_created": "2025-12-09",
"type": "addon", "type": "ct",
"updateable": true, "updateable": true,
"privileged": false, "privileged": false,
"interface_port": 8000, "interface_port": 8000,
"documentation": "https://coolify.io/docs", "documentation": "https://coolify.io/docs",
"website": "https://coolify.io/", "config_path": "/data/coolify",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/coolify.webp", "website": "https://coolify.io/",
"config_path": "/data/coolify", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/coolify.webp",
"description": "Coolify is an open-source & self-hostable alternative to Heroku, Netlify, and Vercel. It helps you manage your servers, applications, and databases on your own hardware with Docker. Deploy any application from Git repositories, Docker images, or use pre-built templates.", "description": "Coolify is an open-source & self-hostable alternative to Heroku, Netlify, and Vercel. It helps you manage your servers, applications, and databases on your own hardware with Docker. Deploy any application from Git repositories, Docker images, or use pre-built templates.",
"install_methods": [ "install_methods": [
{ {
"type": "default", "type": "default",
"script": "tools/addon/coolify.sh", "script": "ct/coolify.sh",
"resources": { "resources": {
"cpu": null, "cpu": 2,
"ram": null, "ram": 4096,
"hdd": null, "hdd": 30,
"os": null, "os": "Debian",
"version": null "version": "13"
} }
} }
], ],
"default_credentials": { "default_credentials": {
"username": null, "username": null,
"password": null "password": null
},
"notes": [
{
"text": "This is an addon script intended to be used on top of an existing Docker container.",
"type": "info"
}, },
{ "notes": [
"text": "Execute within an existing LXC console (Debian / Ubuntu / Alpine supported)", {
"type": "info" "text": "Initial setup will be done via the web interface on first access.",
}, "type": "info"
{ },
"text": "Initial setup will be done via the web interface on first access.", {
"type": "info" "text": "Coolify has built-in auto-updates. You can configure update frequency in Settings.",
}, "type": "info"
{ },
"text": "Coolify has built-in auto-updates. You can configure update frequency in Settings.", {
"type": "info" "text": "Coolify requires SSH access to manage deployments. SSH is enabled automatically.",
}, "type": "info"
{ },
"text": "To update via CLI, run the addon script again and select Update, or use: bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/coolify.sh)", {
"type": "info" "text": "This container uses Docker-in-Docker (nesting) for application deployments.",
} "type": "warning"
] }
]
} }

View File

@@ -5,25 +5,25 @@
3 3
], ],
"date_created": "2024-05-02", "date_created": "2024-05-02",
"type": "addon", "type": "ct",
"updateable": true, "updateable": true,
"privileged": false, "privileged": false,
"interface_port": 5001, "interface_port": 5001,
"documentation": null, "documentation": null,
"website": "https://github.com/louislam/dockge", "website": "https://github.com/louislam/dockge",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/dockge.webp", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/dockge.webp",
"config_path": "/opt/dockge/compose.yaml", "config_path": "",
"description": "Dockge is a fancy, easy-to-use and reactive self-hosted docker compose.yaml stack-oriented manager.", "description": "Dockge is a fancy, easy-to-use and reactive self-hosted docker compose.yaml stack-oriented manager.",
"install_methods": [ "install_methods": [
{ {
"type": "default", "type": "default",
"script": "tools/addon/dockge.sh", "script": "ct/dockge.sh",
"resources": { "resources": {
"cpu": null, "cpu": 2,
"ram": null, "ram": 2048,
"hdd": null, "hdd": 18,
"os": null, "os": "debian",
"version": null "version": "13"
} }
} }
], ],
@@ -33,16 +33,12 @@
}, },
"notes": [ "notes": [
{ {
"text": "This is an addon script intended to be used on top of an existing Docker container.", "text": "Options to add Immich and/or Home Assistant",
"type": "info" "type": "info"
}, },
{ {
"text": "Execute within an existing LXC console (Debian / Ubuntu / Alpine supported)", "text": "If the LXC is created Privileged, the script will automatically set up USB passthrough.",
"type": "info" "type": "warning"
},
{
"text": "To update, run the addon script again and select Update, or use: bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dockge.sh)",
"type": "info"
} }
] ]
} }

View File

@@ -1,56 +1,48 @@
{ {
"name": "Dokploy", "name": "Dokploy",
"slug": "dokploy", "slug": "dokploy",
"categories": [ "categories": [
3 3
], ],
"date_created": "2025-12-09", "date_created": "2025-12-09",
"type": "addon", "type": "ct",
"updateable": true, "updateable": true,
"privileged": true, "privileged": true,
"interface_port": 3000, "interface_port": 3000,
"documentation": "https://docs.dokploy.com/", "documentation": "https://docs.dokploy.com/",
"website": "https://dokploy.com/", "config_path": "/etc/dokploy",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/png/dokploy.png", "website": "https://dokploy.com/",
"config_path": "/etc/dokploy", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/png/dokploy.png",
"description": "Dokploy is a free, self-hostable Platform as a Service (PaaS) that simplifies the deployment and management of applications and databases. Built with Docker and Traefik, it offers features like automatic SSL, Docker Compose support, database backups, and a real-time monitoring dashboard.", "description": "Dokploy is a free, self-hostable Platform as a Service (PaaS) that simplifies the deployment and management of applications and databases. Built with Docker and Traefik, it offers features like automatic SSL, Docker Compose support, database backups, and a real-time monitoring dashboard.",
"install_methods": [ "install_methods": [
{ {
"type": "default", "type": "default",
"script": "tools/addon/dokploy.sh", "script": "ct/dokploy.sh",
"resources": { "resources": {
"cpu": null, "cpu": 2,
"ram": null, "ram": 2048,
"hdd": null, "hdd": 10,
"os": null, "os": "Debian",
"version": null "version": "13"
} }
} }
], ],
"default_credentials": { "default_credentials": {
"username": null, "username": null,
"password": null "password": null
},
"notes": [
{
"text": "This is an addon script intended to be used on top of an existing Docker container.",
"type": "info"
}, },
{ "notes": [
"text": "Execute within an existing LXC console (Debian / Ubuntu / Alpine supported)", {
"type": "info" "text": "Initial setup will be done via the web interface on first access.",
}, "type": "info"
{ },
"text": "Initial setup will be done via the web interface on first access.", {
"type": "info" "text": "Dokploy has built-in auto-updates via the web interface.",
}, "type": "info"
{ },
"text": "Dokploy has built-in auto-updates via the web interface.", {
"type": "info" "text": "This container uses Docker-in-Docker (nesting) for application deployments.",
}, "type": "warning"
{ }
"text": "To update via CLI, run the addon script again and select Update, or use: bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dokploy.sh)", ]
"type": "info"
}
]
} }

View File

@@ -1,5 +1,5 @@
{ {
"generated": "2026-03-02T12:12:21Z", "generated": "2026-02-24T12:15:44Z",
"versions": [ "versions": [
{ {
"slug": "2fauth", "slug": "2fauth",
@@ -18,9 +18,9 @@
{ {
"slug": "adguardhome-sync", "slug": "adguardhome-sync",
"repo": "bakito/adguardhome-sync", "repo": "bakito/adguardhome-sync",
"version": "v0.9.0", "version": "v0.8.2",
"pinned": false, "pinned": false,
"date": "2026-02-27T18:37:37Z" "date": "2025-10-24T17:13:47Z"
}, },
{ {
"slug": "adventurelog", "slug": "adventurelog",
@@ -39,9 +39,9 @@
{ {
"slug": "ampache", "slug": "ampache",
"repo": "ampache/ampache", "repo": "ampache/ampache",
"version": "7.9.1", "version": "7.9.0",
"pinned": false, "pinned": false,
"date": "2026-02-25T08:52:58Z" "date": "2026-02-19T07:01:25Z"
}, },
{ {
"slug": "argus", "slug": "argus",
@@ -109,16 +109,16 @@
{ {
"slug": "bazarr", "slug": "bazarr",
"repo": "morpheus65535/bazarr", "repo": "morpheus65535/bazarr",
"version": "v1.5.6", "version": "v1.5.5",
"pinned": false, "pinned": false,
"date": "2026-02-26T11:33:11Z" "date": "2026-02-01T18:00:34Z"
}, },
{ {
"slug": "bentopdf", "slug": "bentopdf",
"repo": "alam00000/bentopdf", "repo": "alam00000/bentopdf",
"version": "v2.4.0", "version": "v2.3.1",
"pinned": false, "pinned": false,
"date": "2026-03-01T14:25:43Z" "date": "2026-02-21T09:04:27Z"
}, },
{ {
"slug": "beszel", "slug": "beszel",
@@ -144,23 +144,23 @@
{ {
"slug": "blocky", "slug": "blocky",
"repo": "0xERR0R/blocky", "repo": "0xERR0R/blocky",
"version": "v0.29.0", "version": "v0.28.2",
"pinned": false, "pinned": false,
"date": "2026-02-27T15:48:56Z" "date": "2025-11-18T05:51:46Z"
}, },
{ {
"slug": "booklore", "slug": "booklore",
"repo": "booklore-app/BookLore", "repo": "booklore-app/BookLore",
"version": "v2.0.5", "version": "v2.0.1",
"pinned": false, "pinned": false,
"date": "2026-03-01T16:13:13Z" "date": "2026-02-24T04:15:33Z"
}, },
{ {
"slug": "bookstack", "slug": "bookstack",
"repo": "BookStackApp/BookStack", "repo": "BookStackApp/BookStack",
"version": "v25.12.8", "version": "v25.12.7",
"pinned": false, "pinned": false,
"date": "2026-02-27T10:33:14Z" "date": "2026-02-19T23:36:55Z"
}, },
{ {
"slug": "byparr", "slug": "byparr",
@@ -200,9 +200,9 @@
{ {
"slug": "cleanuparr", "slug": "cleanuparr",
"repo": "Cleanuparr/Cleanuparr", "repo": "Cleanuparr/Cleanuparr",
"version": "v2.7.6", "version": "v2.7.4",
"pinned": false, "pinned": false,
"date": "2026-02-27T19:32:02Z" "date": "2026-02-23T18:41:16Z"
}, },
{ {
"slug": "cloudreve", "slug": "cloudreve",
@@ -214,9 +214,9 @@
{ {
"slug": "comfyui", "slug": "comfyui",
"repo": "comfyanonymous/ComfyUI", "repo": "comfyanonymous/ComfyUI",
"version": "v0.15.1", "version": "v0.14.2",
"pinned": false, "pinned": false,
"date": "2026-02-26T22:01:35Z" "date": "2026-02-18T06:12:02Z"
}, },
{ {
"slug": "commafeed", "slug": "commafeed",
@@ -242,9 +242,9 @@
{ {
"slug": "cosmos", "slug": "cosmos",
"repo": "azukaar/Cosmos-Server", "repo": "azukaar/Cosmos-Server",
"version": "v0.21.6", "version": "v0.20.2",
"pinned": false, "pinned": false,
"date": "2026-02-28T22:00:49Z" "date": "2026-01-24T00:12:39Z"
}, },
{ {
"slug": "cronicle", "slug": "cronicle",
@@ -270,16 +270,16 @@
{ {
"slug": "databasus", "slug": "databasus",
"repo": "databasus/databasus", "repo": "databasus/databasus",
"version": "v3.16.4", "version": "v3.16.2",
"pinned": false, "pinned": false,
"date": "2026-03-01T08:20:17Z" "date": "2026-02-22T21:10:12Z"
}, },
{ {
"slug": "dawarich", "slug": "dawarich",
"repo": "Freika/dawarich", "repo": "Freika/dawarich",
"version": "1.3.1", "version": "1.2.0",
"pinned": false, "pinned": false,
"date": "2026-02-27T19:47:40Z" "date": "2026-02-15T22:33:56Z"
}, },
{ {
"slug": "discopanel", "slug": "discopanel",
@@ -291,9 +291,9 @@
{ {
"slug": "dispatcharr", "slug": "dispatcharr",
"repo": "Dispatcharr/Dispatcharr", "repo": "Dispatcharr/Dispatcharr",
"version": "v0.20.1", "version": "v0.19.0",
"pinned": false, "pinned": false,
"date": "2026-02-26T21:38:19Z" "date": "2026-02-10T21:18:10Z"
}, },
{ {
"slug": "docmost", "slug": "docmost",
@@ -312,9 +312,9 @@
{ {
"slug": "domain-monitor", "slug": "domain-monitor",
"repo": "Hosteroid/domain-monitor", "repo": "Hosteroid/domain-monitor",
"version": "v1.1.4", "version": "v1.1.3",
"pinned": false, "pinned": false,
"date": "2026-03-02T09:25:01Z" "date": "2026-02-11T15:48:18Z"
}, },
{ {
"slug": "donetick", "slug": "donetick",
@@ -361,16 +361,16 @@
{ {
"slug": "endurain", "slug": "endurain",
"repo": "endurain-project/endurain", "repo": "endurain-project/endurain",
"version": "v0.17.6", "version": "v0.17.4",
"pinned": false, "pinned": false,
"date": "2026-02-27T23:08:50Z" "date": "2026-02-11T04:54:22Z"
}, },
{ {
"slug": "ersatztv", "slug": "ersatztv",
"repo": "ErsatzTV/ErsatzTV", "repo": "ErsatzTV/ErsatzTV",
"version": "v26.3.0", "version": "v26.2.0",
"pinned": false, "pinned": false,
"date": "2026-02-24T21:36:34Z" "date": "2026-02-02T20:54:26Z"
}, },
{ {
"slug": "excalidraw", "slug": "excalidraw",
@@ -382,9 +382,9 @@
{ {
"slug": "firefly", "slug": "firefly",
"repo": "firefly-iii/firefly-iii", "repo": "firefly-iii/firefly-iii",
"version": "v6.5.1", "version": "v6.5.0",
"pinned": false, "pinned": false,
"date": "2026-02-27T20:55:55Z" "date": "2026-02-23T19:19:00Z"
}, },
{ {
"slug": "fladder", "slug": "fladder",
@@ -438,9 +438,9 @@
{ {
"slug": "ghostfolio", "slug": "ghostfolio",
"repo": "ghostfolio/ghostfolio", "repo": "ghostfolio/ghostfolio",
"version": "2.245.0", "version": "2.243.0",
"pinned": false, "pinned": false,
"date": "2026-03-01T09:09:57Z" "date": "2026-02-23T19:31:36Z"
}, },
{ {
"slug": "gitea", "slug": "gitea",
@@ -452,9 +452,9 @@
{ {
"slug": "gitea-mirror", "slug": "gitea-mirror",
"repo": "RayLabsHQ/gitea-mirror", "repo": "RayLabsHQ/gitea-mirror",
"version": "v3.11.0", "version": "v3.9.4",
"pinned": false, "pinned": false,
"date": "2026-03-02T10:19:59Z" "date": "2026-02-24T06:17:56Z"
}, },
{ {
"slug": "glance", "slug": "glance",
@@ -480,9 +480,9 @@
{ {
"slug": "gotify", "slug": "gotify",
"repo": "gotify/server", "repo": "gotify/server",
"version": "v2.9.1", "version": "v2.9.0",
"pinned": false, "pinned": false,
"date": "2026-02-28T19:07:07Z" "date": "2026-02-13T15:22:31Z"
}, },
{ {
"slug": "gramps-web", "slug": "gramps-web",
@@ -494,9 +494,9 @@
{ {
"slug": "grist", "slug": "grist",
"repo": "gristlabs/grist-core", "repo": "gristlabs/grist-core",
"version": "v1.7.11", "version": "v1.7.10",
"pinned": false, "pinned": false,
"date": "2026-02-27T17:13:50Z" "date": "2026-01-12T20:50:50Z"
}, },
{ {
"slug": "grocy", "slug": "grocy",
@@ -550,9 +550,9 @@
{ {
"slug": "homarr", "slug": "homarr",
"repo": "homarr-labs/homarr", "repo": "homarr-labs/homarr",
"version": "v1.54.0", "version": "v1.53.2",
"pinned": false, "pinned": false,
"date": "2026-02-27T19:38:50Z" "date": "2026-02-20T19:41:55Z"
}, },
{ {
"slug": "homebox", "slug": "homebox",
@@ -606,16 +606,16 @@
{ {
"slug": "invoiceninja", "slug": "invoiceninja",
"repo": "invoiceninja/invoiceninja", "repo": "invoiceninja/invoiceninja",
"version": "v5.12.69", "version": "v5.12.66",
"pinned": false, "pinned": false,
"date": "2026-02-26T22:23:32Z" "date": "2026-02-24T09:12:50Z"
}, },
{ {
"slug": "jackett", "slug": "jackett",
"repo": "Jackett/Jackett", "repo": "Jackett/Jackett",
"version": "v0.24.1247", "version": "v0.24.1193",
"pinned": false, "pinned": false,
"date": "2026-03-02T05:56:37Z" "date": "2026-02-24T05:58:04Z"
}, },
{ {
"slug": "jellystat", "slug": "jellystat",
@@ -627,16 +627,16 @@
{ {
"slug": "joplin-server", "slug": "joplin-server",
"repo": "laurent22/joplin", "repo": "laurent22/joplin",
"version": "v3.5.13", "version": "v3.5.12",
"pinned": false, "pinned": false,
"date": "2026-02-25T21:19:11Z" "date": "2026-01-17T14:20:33Z"
}, },
{ {
"slug": "jotty", "slug": "jotty",
"repo": "fccview/jotty", "repo": "fccview/jotty",
"version": "1.21.0", "version": "1.20.0",
"pinned": false, "pinned": false,
"date": "2026-03-02T11:08:54Z" "date": "2026-02-12T09:23:30Z"
}, },
{ {
"slug": "kapowarr", "slug": "kapowarr",
@@ -666,19 +666,12 @@
"pinned": false, "pinned": false,
"date": "2026-02-20T09:19:45Z" "date": "2026-02-20T09:19:45Z"
}, },
{
"slug": "kima-hub",
"repo": "Chevron7Locked/kima-hub",
"version": "v1.6.0",
"pinned": false,
"date": "2026-03-02T05:43:31Z"
},
{ {
"slug": "kimai", "slug": "kimai",
"repo": "kimai/kimai", "repo": "kimai/kimai",
"version": "2.51.0", "version": "2.49.0",
"pinned": false, "pinned": false,
"date": "2026-03-01T15:56:56Z" "date": "2026-02-15T20:40:19Z"
}, },
{ {
"slug": "kitchenowl", "slug": "kitchenowl",
@@ -718,9 +711,9 @@
{ {
"slug": "kubo", "slug": "kubo",
"repo": "ipfs/kubo", "repo": "ipfs/kubo",
"version": "v0.40.1", "version": "v0.39.0",
"pinned": false, "pinned": false,
"date": "2026-02-27T17:58:22Z" "date": "2025-11-27T03:47:38Z"
}, },
{ {
"slug": "kutt", "slug": "kutt",
@@ -753,9 +746,9 @@
{ {
"slug": "libretranslate", "slug": "libretranslate",
"repo": "LibreTranslate/LibreTranslate", "repo": "LibreTranslate/LibreTranslate",
"version": "v1.9.4", "version": "v1.9.3",
"pinned": false, "pinned": false,
"date": "2026-02-24T17:06:05Z" "date": "2026-02-21T19:08:33Z"
}, },
{ {
"slug": "lidarr", "slug": "lidarr",
@@ -795,9 +788,9 @@
{ {
"slug": "lubelogger", "slug": "lubelogger",
"repo": "hargata/lubelog", "repo": "hargata/lubelog",
"version": "v1.6.1", "version": "v1.6.0",
"pinned": false, "pinned": false,
"date": "2026-02-26T20:01:24Z" "date": "2026-02-10T20:16:32Z"
}, },
{ {
"slug": "mafl", "slug": "mafl",
@@ -816,9 +809,9 @@
{ {
"slug": "mail-archiver", "slug": "mail-archiver",
"repo": "s1t5/mail-archiver", "repo": "s1t5/mail-archiver",
"version": "2602.4", "version": "2602.3",
"pinned": false, "pinned": false,
"date": "2026-02-26T08:43:01Z" "date": "2026-02-22T20:24:18Z"
}, },
{ {
"slug": "managemydamnlife", "slug": "managemydamnlife",
@@ -830,9 +823,9 @@
{ {
"slug": "manyfold", "slug": "manyfold",
"repo": "manyfold3d/manyfold", "repo": "manyfold3d/manyfold",
"version": "v0.133.1", "version": "v0.132.1",
"pinned": false, "pinned": false,
"date": "2026-02-26T15:50:34Z" "date": "2026-02-09T22:02:28Z"
}, },
{ {
"slug": "mealie", "slug": "mealie",
@@ -851,9 +844,9 @@
{ {
"slug": "mediamtx", "slug": "mediamtx",
"repo": "bluenviron/mediamtx", "repo": "bluenviron/mediamtx",
"version": "v1.16.3", "version": "v1.16.2",
"pinned": false, "pinned": false,
"date": "2026-03-01T15:49:12Z" "date": "2026-02-22T17:31:41Z"
}, },
{ {
"slug": "meilisearch", "slug": "meilisearch",
@@ -872,9 +865,9 @@
{ {
"slug": "metube", "slug": "metube",
"repo": "alexta69/metube", "repo": "alexta69/metube",
"version": "2026.02.27", "version": "2026.02.22",
"pinned": false, "pinned": false,
"date": "2026-02-27T11:47:02Z" "date": "2026-02-22T00:58:45Z"
}, },
{ {
"slug": "miniflux", "slug": "miniflux",
@@ -942,9 +935,9 @@
{ {
"slug": "nightscout", "slug": "nightscout",
"repo": "nightscout/cgm-remote-monitor", "repo": "nightscout/cgm-remote-monitor",
"version": "v15.0.5", "version": "15.0.3",
"pinned": false, "pinned": false,
"date": "2026-03-01T21:22:37Z" "date": "2025-05-08T22:12:34Z"
}, },
{ {
"slug": "nocodb", "slug": "nocodb",
@@ -956,9 +949,9 @@
{ {
"slug": "nodebb", "slug": "nodebb",
"repo": "NodeBB/NodeBB", "repo": "NodeBB/NodeBB",
"version": "v4.9.1", "version": "v4.8.1",
"pinned": false, "pinned": false,
"date": "2026-03-01T20:52:43Z" "date": "2026-01-28T14:19:11Z"
}, },
{ {
"slug": "nodecast-tv", "slug": "nodecast-tv",
@@ -970,9 +963,9 @@
{ {
"slug": "oauth2-proxy", "slug": "oauth2-proxy",
"repo": "oauth2-proxy/oauth2-proxy", "repo": "oauth2-proxy/oauth2-proxy",
"version": "v7.14.3", "version": "v7.14.2",
"pinned": false, "pinned": false,
"date": "2026-02-26T14:10:21Z" "date": "2026-01-18T00:26:09Z"
}, },
{ {
"slug": "ombi", "slug": "ombi",
@@ -984,9 +977,9 @@
{ {
"slug": "open-archiver", "slug": "open-archiver",
"repo": "LogicLabs-OU/OpenArchiver", "repo": "LogicLabs-OU/OpenArchiver",
"version": "v0.4.2", "version": "v0.4.1",
"pinned": false, "pinned": false,
"date": "2026-02-24T20:47:40Z" "date": "2026-01-17T12:24:31Z"
}, },
{ {
"slug": "opencloud", "slug": "opencloud",
@@ -1002,13 +995,6 @@
"pinned": false, "pinned": false,
"date": "2026-02-03T09:00:43Z" "date": "2026-02-03T09:00:43Z"
}, },
{
"slug": "openproject",
"repo": "jemalloc/jemalloc",
"version": "5.3.0",
"pinned": false,
"date": "2022-05-06T19:14:21Z"
},
{ {
"slug": "ots", "slug": "ots",
"repo": "Luzifer/ots", "repo": "Luzifer/ots",
@@ -1037,12 +1023,19 @@
"pinned": false, "pinned": false,
"date": "2025-02-24T19:47:06Z" "date": "2025-02-24T19:47:06Z"
}, },
{
"slug": "palmr",
"repo": "kyantech/Palmr",
"version": "v3.3.2-beta",
"pinned": false,
"date": "2025-12-10T05:42:43Z"
},
{ {
"slug": "pangolin", "slug": "pangolin",
"repo": "fosrl/pangolin", "repo": "fosrl/pangolin",
"version": "1.16.2", "version": "1.15.4",
"pinned": false, "pinned": false,
"date": "2026-02-28T20:35:52Z" "date": "2026-02-13T23:01:29Z"
}, },
{ {
"slug": "paperless-ai", "slug": "paperless-ai",
@@ -1054,16 +1047,16 @@
{ {
"slug": "paperless-gpt", "slug": "paperless-gpt",
"repo": "icereed/paperless-gpt", "repo": "icereed/paperless-gpt",
"version": "v0.25.1", "version": "v0.25.0",
"pinned": false, "pinned": false,
"date": "2026-02-26T14:50:11Z" "date": "2026-02-16T08:31:48Z"
}, },
{ {
"slug": "paperless-ngx", "slug": "paperless-ngx",
"repo": "paperless-ngx/paperless-ngx", "repo": "paperless-ngx/paperless-ngx",
"version": "v2.20.9", "version": "v2.20.8",
"pinned": false, "pinned": false,
"date": "2026-02-28T10:17:35Z" "date": "2026-02-22T01:40:54Z"
}, },
{ {
"slug": "patchmon", "slug": "patchmon",
@@ -1124,9 +1117,9 @@
{ {
"slug": "planka", "slug": "planka",
"repo": "plankanban/planka", "repo": "plankanban/planka",
"version": "v2.0.3", "version": "v2.0.2",
"pinned": false, "pinned": false,
"date": "2026-03-01T16:03:23Z" "date": "2026-02-23T17:47:15Z"
}, },
{ {
"slug": "plant-it", "slug": "plant-it",
@@ -1156,13 +1149,6 @@
"pinned": false, "pinned": false,
"date": "2025-11-12T07:10:14Z" "date": "2025-11-12T07:10:14Z"
}, },
{
"slug": "profilarr",
"repo": "Dictionarry-Hub/profilarr",
"version": "v1.1.4",
"pinned": false,
"date": "2026-01-29T14:57:25Z"
},
{ {
"slug": "projectsend", "slug": "projectsend",
"repo": "projectsend/projectsend", "repo": "projectsend/projectsend",
@@ -1173,9 +1159,9 @@
{ {
"slug": "prometheus", "slug": "prometheus",
"repo": "prometheus/prometheus", "repo": "prometheus/prometheus",
"version": "v3.10.0", "version": "v3.9.1",
"pinned": false, "pinned": false,
"date": "2026-02-26T01:19:51Z" "date": "2026-01-07T17:05:53Z"
}, },
{ {
"slug": "prometheus-alertmanager", "slug": "prometheus-alertmanager",
@@ -1222,9 +1208,9 @@
{ {
"slug": "pulse", "slug": "pulse",
"repo": "rcourtman/Pulse", "repo": "rcourtman/Pulse",
"version": "v5.1.16", "version": "v5.1.13",
"pinned": false, "pinned": false,
"date": "2026-03-01T23:13:09Z" "date": "2026-02-22T12:40:41Z"
}, },
{ {
"slug": "pve-scripts-local", "slug": "pve-scripts-local",
@@ -1271,9 +1257,9 @@
{ {
"slug": "radicale", "slug": "radicale",
"repo": "Kozea/Radicale", "repo": "Kozea/Radicale",
"version": "v3.6.1", "version": "v3.6.0",
"pinned": false, "pinned": false,
"date": "2026-02-24T06:36:23Z" "date": "2026-01-10T06:56:46Z"
}, },
{ {
"slug": "rclone", "slug": "rclone",
@@ -1285,9 +1271,9 @@
{ {
"slug": "rdtclient", "slug": "rdtclient",
"repo": "rogerfar/rdt-client", "repo": "rogerfar/rdt-client",
"version": "v2.0.125", "version": "v2.0.124",
"pinned": false, "pinned": false,
"date": "2026-03-01T18:29:10Z" "date": "2026-02-24T03:18:03Z"
}, },
{ {
"slug": "reactive-resume", "slug": "reactive-resume",
@@ -1299,9 +1285,9 @@
{ {
"slug": "recyclarr", "slug": "recyclarr",
"repo": "recyclarr/recyclarr", "repo": "recyclarr/recyclarr",
"version": "v8.3.2", "version": "v8.2.1",
"pinned": false, "pinned": false,
"date": "2026-02-25T22:39:51Z" "date": "2026-02-22T19:19:49Z"
}, },
{ {
"slug": "reitti", "slug": "reitti",
@@ -1348,9 +1334,9 @@
{ {
"slug": "scanopy", "slug": "scanopy",
"repo": "scanopy/scanopy", "repo": "scanopy/scanopy",
"version": "v0.14.10", "version": "v0.14.7",
"pinned": false, "pinned": false,
"date": "2026-02-28T21:05:12Z" "date": "2026-02-23T01:36:44Z"
}, },
{ {
"slug": "scraparr", "slug": "scraparr",
@@ -1376,16 +1362,16 @@
{ {
"slug": "seerr", "slug": "seerr",
"repo": "seerr-team/seerr", "repo": "seerr-team/seerr",
"version": "v3.1.0", "version": "v3.0.1",
"pinned": false, "pinned": false,
"date": "2026-02-27T17:25:29Z" "date": "2026-02-14T19:30:24Z"
}, },
{ {
"slug": "semaphore", "slug": "semaphore",
"repo": "semaphoreui/semaphore", "repo": "semaphoreui/semaphore",
"version": "v2.17.15", "version": "v2.17.12",
"pinned": false, "pinned": false,
"date": "2026-02-28T09:04:40Z" "date": "2026-02-20T09:16:50Z"
}, },
{ {
"slug": "shelfmark", "slug": "shelfmark",
@@ -1397,9 +1383,9 @@
{ {
"slug": "signoz", "slug": "signoz",
"repo": "SigNoz/signoz-otel-collector", "repo": "SigNoz/signoz-otel-collector",
"version": "v0.144.2", "version": "v0.142.1",
"pinned": false, "pinned": false,
"date": "2026-02-26T05:57:26Z" "date": "2026-02-21T18:04:07Z"
}, },
{ {
"slug": "silverbullet", "slug": "silverbullet",
@@ -1411,9 +1397,9 @@
{ {
"slug": "slskd", "slug": "slskd",
"repo": "slskd/slskd", "repo": "slskd/slskd",
"version": "0.24.5", "version": "0.24.4",
"pinned": false, "pinned": false,
"date": "2026-03-01T04:00:42Z" "date": "2026-02-16T16:50:17Z"
}, },
{ {
"slug": "snipeit", "slug": "snipeit",
@@ -1425,9 +1411,9 @@
{ {
"slug": "snowshare", "slug": "snowshare",
"repo": "TuroYT/snowshare", "repo": "TuroYT/snowshare",
"version": "v1.3.8", "version": "v1.3.7",
"pinned": false, "pinned": false,
"date": "2026-03-02T07:43:42Z" "date": "2026-02-23T15:51:39Z"
}, },
{ {
"slug": "sonarr", "slug": "sonarr",
@@ -1488,9 +1474,9 @@
{ {
"slug": "sure", "slug": "sure",
"repo": "we-promise/sure", "repo": "we-promise/sure",
"version": "v0.6.8", "version": "chart-v0.6.8-alpha.13",
"pinned": false, "pinned": false,
"date": "2026-02-28T12:55:36Z" "date": "2026-02-20T11:15:15Z"
}, },
{ {
"slug": "tandoor", "slug": "tandoor",
@@ -1558,16 +1544,16 @@
{ {
"slug": "traccar", "slug": "traccar",
"repo": "traccar/traccar", "repo": "traccar/traccar",
"version": "v6.12.2", "version": "v6.12.1",
"pinned": false, "pinned": false,
"date": "2026-02-27T15:08:36Z" "date": "2026-02-22T18:47:37Z"
}, },
{ {
"slug": "tracearr", "slug": "tracearr",
"repo": "connorgallopo/Tracearr", "repo": "connorgallopo/Tracearr",
"version": "v1.4.19", "version": "v1.4.18",
"pinned": false, "pinned": false,
"date": "2026-02-28T21:25:47Z" "date": "2026-02-15T19:55:40Z"
}, },
{ {
"slug": "tracktor", "slug": "tracktor",
@@ -1586,9 +1572,9 @@
{ {
"slug": "trilium", "slug": "trilium",
"repo": "TriliumNext/Trilium", "repo": "TriliumNext/Trilium",
"version": "v0.102.0", "version": "v0.101.3",
"pinned": false, "pinned": false,
"date": "2026-03-01T20:37:40Z" "date": "2026-01-08T18:05:22Z"
}, },
{ {
"slug": "trip", "slug": "trip",
@@ -1607,9 +1593,9 @@
{ {
"slug": "tunarr", "slug": "tunarr",
"repo": "chrisbenincasa/tunarr", "repo": "chrisbenincasa/tunarr",
"version": "v1.1.18", "version": "v1.1.16",
"pinned": false, "pinned": false,
"date": "2026-02-26T22:09:44Z" "date": "2026-02-23T21:24:47Z"
}, },
{ {
"slug": "uhf", "slug": "uhf",
@@ -1635,9 +1621,9 @@
{ {
"slug": "upgopher", "slug": "upgopher",
"repo": "wanetty/upgopher", "repo": "wanetty/upgopher",
"version": "v1.14.0", "version": "v1.13.0",
"pinned": false, "pinned": false,
"date": "2026-02-24T22:43:34Z" "date": "2026-01-16T20:26:34Z"
}, },
{ {
"slug": "upsnap", "slug": "upsnap",
@@ -1663,16 +1649,16 @@
{ {
"slug": "victoriametrics", "slug": "victoriametrics",
"repo": "VictoriaMetrics/VictoriaMetrics", "repo": "VictoriaMetrics/VictoriaMetrics",
"version": "v1.137.0", "version": "v1.136.0",
"pinned": false, "pinned": false,
"date": "2026-03-02T10:09:29Z" "date": "2026-02-16T13:17:50Z"
}, },
{ {
"slug": "vikunja", "slug": "vikunja",
"repo": "go-vikunja/vikunja", "repo": "go-vikunja/vikunja",
"version": "v2.1.0", "version": "v1.1.0",
"pinned": false, "pinned": false,
"date": "2026-02-27T14:26:53Z" "date": "2026-02-09T10:34:29Z"
}, },
{ {
"slug": "wallabag", "slug": "wallabag",
@@ -1691,9 +1677,9 @@
{ {
"slug": "wanderer", "slug": "wanderer",
"repo": "meilisearch/meilisearch", "repo": "meilisearch/meilisearch",
"version": "v1.37.0", "version": "v1.36.0",
"pinned": false, "pinned": false,
"date": "2026-03-02T09:16:36Z" "date": ""
}, },
{ {
"slug": "warracker", "slug": "warracker",
@@ -1726,9 +1712,9 @@
{ {
"slug": "wealthfolio", "slug": "wealthfolio",
"repo": "afadil/wealthfolio", "repo": "afadil/wealthfolio",
"version": "v3.0.0", "version": "v2.1.0",
"pinned": false, "pinned": false,
"date": "2026-02-24T22:37:05Z" "date": "2025-12-01T21:57:36Z"
}, },
{ {
"slug": "web-check", "slug": "web-check",
@@ -1761,9 +1747,9 @@
{ {
"slug": "wizarr", "slug": "wizarr",
"repo": "wizarrrr/wizarr", "repo": "wizarrrr/wizarr",
"version": "v2026.2.1", "version": "v2026.2.0",
"pinned": false, "pinned": false,
"date": "2026-02-25T01:07:56Z" "date": "2026-02-23T19:25:28Z"
}, },
{ {
"slug": "writefreely", "slug": "writefreely",
@@ -1782,23 +1768,16 @@
{ {
"slug": "yubal", "slug": "yubal",
"repo": "guillevc/yubal", "repo": "guillevc/yubal",
"version": "v0.6.2", "version": "v0.6.1",
"pinned": false, "pinned": false,
"date": "2026-02-24T15:15:46Z" "date": "2026-02-18T23:24:16Z"
},
{
"slug": "zerobyte",
"repo": "restic/restic",
"version": "v0.18.1",
"pinned": false,
"date": "2025-09-21T18:24:38Z"
}, },
{ {
"slug": "zigbee2mqtt", "slug": "zigbee2mqtt",
"repo": "Koenkk/zigbee2mqtt", "repo": "Koenkk/zigbee2mqtt",
"version": "2.9.1", "version": "2.8.0",
"pinned": false, "pinned": false,
"date": "2026-03-02T11:16:46Z" "date": "2026-02-01T19:27:25Z"
}, },
{ {
"slug": "zipline", "slug": "zipline",
@@ -1810,16 +1789,16 @@
{ {
"slug": "zitadel", "slug": "zitadel",
"repo": "zitadel/zitadel", "repo": "zitadel/zitadel",
"version": "v4.12.0", "version": "v4.11.0",
"pinned": false, "pinned": false,
"date": "2026-03-02T08:16:10Z" "date": "2026-02-16T09:48:38Z"
}, },
{ {
"slug": "zoraxy", "slug": "zoraxy",
"repo": "tobychui/zoraxy", "repo": "tobychui/zoraxy",
"version": "v3.3.2-rc2", "version": "v3.3.2-rc1",
"pinned": false, "pinned": false,
"date": "2026-02-27T03:31:25Z" "date": "2026-02-15T02:16:17Z"
}, },
{ {
"slug": "zwave-js-ui", "slug": "zwave-js-ui",

View File

@@ -51,10 +51,6 @@
{ {
"text": "Logs: `/var/log/immich`", "text": "Logs: `/var/log/immich`",
"type": "info" "type": "info"
},
{
"text": "During first install, 5 custom libraries need to be compiled from source. Depending on your CPU, this can take anywhere between 15 minutes and 2 hours. Please be patient. Touch grass or something.",
"type": "warning"
} }
] ]
} }

View File

@@ -1,48 +0,0 @@
{
"name": "Kima-Hub",
"slug": "kima-hub",
"categories": [
13
],
"date_created": "2026-02-26",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 3030,
"documentation": "https://github.com/Chevron7Locked/kima-hub#readme",
"website": "https://github.com/Chevron7Locked/kima-hub",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/kima-hub.webp",
"config_path": "/opt/kima-hub/backend/.env",
"description": "Self-hosted, on-demand audio streaming platform with AI-powered vibe matching, mood detection, smart playlists, and Lidarr/Audiobookshelf integration.",
"install_methods": [
{
"type": "default",
"script": "ct/kima-hub.sh",
"resources": {
"cpu": 4,
"ram": 8192,
"hdd": 20,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "First user to register becomes the administrator.",
"type": "info"
},
{
"text": "Mount your music library to /music in the container.",
"type": "warning"
},
{
"text": "Audio analysis (mood/vibe detection) requires significant RAM (2-4GB per worker).",
"type": "info"
}
]
}

View File

@@ -5,7 +5,7 @@
3 3
], ],
"date_created": "2025-01-01", "date_created": "2025-01-01",
"type": "addon", "type": "ct",
"updateable": true, "updateable": true,
"privileged": false, "privileged": false,
"interface_port": 9120, "interface_port": 9120,
@@ -17,13 +17,24 @@
"install_methods": [ "install_methods": [
{ {
"type": "default", "type": "default",
"script": "tools/addon/komodo.sh", "script": "ct/komodo.sh",
"resources": { "resources": {
"cpu": null, "cpu": 2,
"ram": null, "ram": 2048,
"hdd": null, "hdd": 10,
"os": null, "os": "debian",
"version": null "version": "13"
}
},
{
"type": "alpine",
"script": "ct/alpine-komodo.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 10,
"os": "alpine",
"version": "3.23"
} }
} }
], ],
@@ -33,19 +44,7 @@
}, },
"notes": [ "notes": [
{ {
"text": "This is an addon script intended to be used on top of an existing Docker container.", "text": "For admin username and password type `cat ~/komodo.creds` inside LXC.",
"type": "info"
},
{
"text": "Execute within an existing LXC console (Debian / Ubuntu / Alpine supported)",
"type": "info"
},
{
"text": "For admin username and password, run: cat ~/komodo.creds",
"type": "info"
},
{
"text": "To update, run the addon script again and select Update, or use: bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/komodo.sh)",
"type": "info" "type": "info"
} }
] ]

View File

@@ -23,7 +23,7 @@
"ram": 4096, "ram": 4096,
"hdd": 8, "hdd": 8,
"os": "Debian", "os": "Debian",
"version": "13" "version": "12"
} }
} }
], ],
@@ -31,10 +31,5 @@
"username": "admin", "username": "admin",
"password": "admin" "password": "admin"
}, },
"notes": [ "notes": []
{
"text": "If you want to update from v15.x to v17.x, please read `https://www.openproject.org/docs/installation-and-operations/operation/upgrading/#major-upgrades` before doing so.",
"type": "warning"
}
]
} }

View File

@@ -0,0 +1,45 @@
{
"name": "Palmr",
"slug": "palmr",
"categories": [
11
],
"date_created": "2025-08-08",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 3000,
"disable": true,
"documentation": "https://palmr.kyantech.com.br/docs/3.1-beta",
"config_path": "/opt/palmr/apps/server/.env, /opt/palmr/apps/web/.env",
"website": "https://palmr.kyantech.com.br/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/palmr.webp",
"description": "Palmr is a fast and secure platform for sharing files, built with performance and privacy in mind.",
"install_methods": [
{
"type": "default",
"script": "ct/palmr.sh",
"resources": {
"cpu": 4,
"ram": 6144,
"hdd": 6,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "To use a bind mount for storage, create symlinks to your mount for both `uploads` and `temp-uploads` in `/opt/palmr_data`, and uncomment `CUSTOM_PATH` to add the path to your bind mount",
"type": "info"
},
{
"text": "To use Palmr with a reverse proxy, uncomment `SECURE_SITE` in `/opt/palmr/apps/server/.env`",
"type": "info"
}
]
}

View File

@@ -21,7 +21,7 @@
"resources": { "resources": {
"cpu": 2, "cpu": 2,
"ram": 4096, "ram": 4096,
"hdd": 10, "hdd": 5,
"os": "Debian", "os": "Debian",
"version": "13" "version": "13"
} }

View File

@@ -1,35 +0,0 @@
{
"name": "Profilarr",
"slug": "profilarr",
"categories": [
14
],
"date_created": "2026-03-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 6868,
"documentation": "https://github.com/Dictionarry-Hub/profilarr#readme",
"website": "https://github.com/Dictionarry-Hub/profilarr",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/profilarr.webp",
"config_path": "/config",
"description": "Profilarr is a configuration management platform for Radarr and Sonarr that simplifies importing, syncing, and managing quality profiles, custom formats, and release profiles.",
"install_methods": [
{
"type": "default",
"script": "ct/profilarr.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -5,25 +5,25 @@
2 2
], ],
"date_created": "2024-05-02", "date_created": "2024-05-02",
"type": "addon", "type": "ct",
"updateable": true, "updateable": true,
"privileged": false, "privileged": false,
"interface_port": 80, "interface_port": 80,
"documentation": "https://runtipi.io/docs/introduction", "documentation": "https://runtipi.io/docs/introduction",
"website": "https://runtipi.io/", "website": "https://runtipi.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/runtipi.webp", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/runtipi.webp",
"config_path": "/opt/runtipi/state/settings.json", "config_path": "opt/runtipi/state/settings.json",
"description": "Runtipi lets you install all your favorite self-hosted apps without the hassle of configuring and managing each service. One-click installs and updates for more than 180 popular apps.", "description": "Runtipi lets you install all your favorite self-hosted apps without the hassle of configuring and managing each service. One-click installs and updates for more than 180 popular apps.",
"install_methods": [ "install_methods": [
{ {
"type": "default", "type": "default",
"script": "tools/addon/runtipi.sh", "script": "ct/runtipi.sh",
"resources": { "resources": {
"cpu": null, "cpu": 2,
"ram": null, "ram": 2048,
"hdd": null, "hdd": 8,
"os": null, "os": "debian",
"version": null "version": "13"
} }
} }
], ],
@@ -32,21 +32,9 @@
"password": null "password": null
}, },
"notes": [ "notes": [
{
"text": "This is an addon script intended to be used on top of an existing Docker container.",
"type": "info"
},
{
"text": "Execute within an existing LXC console (Debian / Ubuntu only)",
"type": "info"
},
{ {
"text": "WARNING: Installation sources scripts outside of Community Scripts repo. Please check the source before installing.", "text": "WARNING: Installation sources scripts outside of Community Scripts repo. Please check the source before installing.",
"type": "warning" "type": "warning"
},
{
"text": "To update via CLI, run the addon script again and select Update, or use: bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/runtipi.sh)",
"type": "info"
} }
] ]
} }

View File

@@ -1,48 +0,0 @@
{
"name": "Strapi",
"slug": "strapi",
"categories": [
12
],
"date_created": "2026-02-27",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 1337,
"documentation": "https://docs.strapi.io/",
"website": "https://strapi.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/strapi.webp",
"config_path": "/opt/strapi/.env",
"description": "Strapi is a leading open-source headless CMS that enables developers to build powerful APIs quickly. It features a flexible content structure with customizable content types, supporting both REST and GraphQL APIs. The intuitive admin panel allows non-technical users to manage content easily, while developers can extend functionality through plugins. Built on Node.js, Strapi offers role-based access control, media library management, and internationalization support out of the box.",
"install_methods": [
{
"type": "default",
"script": "ct/strapi.sh",
"resources": {
"cpu": 2,
"ram": 4096,
"hdd": 8,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "First-time setup requires creating an admin account at http://IP:1337/admin",
"type": "info"
},
{
"text": "Default installation uses SQLite. For production use, consider configuring PostgreSQL or MySQL.",
"type": "info"
},
{
"text": "Building the admin panel requires 4GB RAM. Container may take 10-15 minutes to fully initialize.",
"type": "warning"
}
]
}

View File

@@ -1,40 +0,0 @@
{
"name": "Zerobyte",
"slug": "zerobyte",
"categories": [
7
],
"date_created": "2026-02-25",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 4096,
"documentation": "https://github.com/nicotsx/zerobyte#readme",
"website": "https://github.com/nicotsx/zerobyte",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/zerobyte.webp",
"config_path": "/opt/zerobyte/.env",
"description": "Zerobyte is a backup automation tool built on top of Restic that provides a modern web interface to schedule, manage, and monitor encrypted backups across multiple storage backends including NFS, SMB, WebDAV, SFTP, S3, and local directories.",
"install_methods": [
{
"type": "default",
"script": "ct/zerobyte.sh",
"resources": {
"cpu": 2,
"ram": 6144,
"hdd": 10,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "For remote mount support (NFS, SMB, WebDAV, SFTP), enable FUSE device passthrough on the LXC container. (FUSE is pre-configured)",
"type": "info"
}
]
}

View File

@@ -19,9 +19,8 @@ export function getDisplayValueFromType(type: string) {
case "vm": case "vm":
return "VM"; return "VM";
case "pve": case "pve":
return "PVE";
case "addon": case "addon":
return "ADDON"; return "";
default: default:
return ""; return "";
} }
@@ -37,9 +36,10 @@ export function LatestScripts({
onPageChange: (page: number) => void; onPageChange: (page: number) => void;
}) { }) {
const latestScripts = useMemo(() => { const latestScripts = useMemo(() => {
if (!items) return []; if (!items)
return [];
const scripts = items.flatMap((category) => category.scripts || []); const scripts = items.flatMap(category => category.scripts || []);
// Filter out duplicates by slug // Filter out duplicates by slug
const uniqueScriptsMap = new Map<string, Script>(); const uniqueScriptsMap = new Map<string, Script>();
@@ -97,7 +97,7 @@ export function LatestScripts({
</div> </div>
)} )}
<div className="min-w flex w-full flex-row flex-wrap gap-4"> <div className="min-w flex w-full flex-row flex-wrap gap-4">
{latestScripts.slice(startIndex, endIndex).map((script) => ( {latestScripts.slice(startIndex, endIndex).map(script => (
<Card key={script.slug} className="min-w-[250px] flex-1 flex-grow bg-accent/30"> <Card key={script.slug} className="min-w-[250px] flex-1 flex-grow bg-accent/30">
<CardHeader> <CardHeader>
<CardTitle className="flex items-center gap-3"> <CardTitle className="flex items-center gap-3">
@@ -108,13 +108,15 @@ export function LatestScripts({
height={64} height={64}
width={64} width={64}
alt="" alt=""
onError={(e) => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)} onError={e => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)}
className="h-11 w-11 object-contain" className="h-11 w-11 object-contain"
/> />
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<p className="text-lg line-clamp-1"> <p className="text-lg line-clamp-1">
{script.name} {getDisplayValueFromType(script.type)} {script.name}
{" "}
{getDisplayValueFromType(script.type)}
</p> </p>
<p className="text-sm text-muted-foreground flex items-center gap-1"> <p className="text-sm text-muted-foreground flex items-center gap-1">
<CalendarPlus className="h-4 w-4" /> <CalendarPlus className="h-4 w-4" />
@@ -147,7 +149,7 @@ export function LatestScripts({
export function MostViewedScripts({ items }: { items: Category[] }) { export function MostViewedScripts({ items }: { items: Category[] }) {
const mostViewedScripts = items.reduce((acc: Script[], category) => { const mostViewedScripts = items.reduce((acc: Script[], category) => {
const foundScripts = category.scripts.filter((script) => mostPopularScripts.includes(script.slug)); const foundScripts = category.scripts.filter(script => mostPopularScripts.includes(script.slug));
return acc.concat(foundScripts); return acc.concat(foundScripts);
}, []); }, []);
@@ -159,7 +161,7 @@ export function MostViewedScripts({ items }: { items: Category[] }) {
</> </>
)} )}
<div className="min-w flex w-full flex-row flex-wrap gap-4"> <div className="min-w flex w-full flex-row flex-wrap gap-4">
{mostViewedScripts.map((script) => ( {mostViewedScripts.map(script => (
<Card key={script.slug} className="min-w-[250px] flex-1 flex-grow bg-accent/30"> <Card key={script.slug} className="min-w-[250px] flex-1 flex-grow bg-accent/30">
<CardHeader> <CardHeader>
<CardTitle className="flex items-center gap-3"> <CardTitle className="flex items-center gap-3">
@@ -170,13 +172,15 @@ export function MostViewedScripts({ items }: { items: Category[] }) {
height={64} height={64}
width={64} width={64}
alt="" alt=""
onError={(e) => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)} onError={e => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)}
className="h-11 w-11 object-contain" className="h-11 w-11 object-contain"
/> />
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<p className="line-clamp-1 text-lg"> <p className="line-clamp-1 text-lg">
{script.name} {getDisplayValueFromType(script.type)} {script.name}
{" "}
{getDisplayValueFromType(script.type)}
</p> </p>
<p className="flex items-center gap-1 text-sm text-muted-foreground"> <p className="flex items-center gap-1 text-sm text-muted-foreground">
<CalendarPlus className="h-4 w-4" /> <CalendarPlus className="h-4 w-4" />

View File

@@ -14,7 +14,6 @@ import { basePath } from "@/config/site-config";
import { extractDate } from "@/lib/time"; import { extractDate } from "@/lib/time";
import DisableDescription from "./script-items/disable-description"; import DisableDescription from "./script-items/disable-description";
import { formattedBadge } from "@/components/command-menu";
import { getDisplayValueFromType } from "./script-info-blocks"; import { getDisplayValueFromType } from "./script-info-blocks";
import DefaultPassword from "./script-items/default-password"; import DefaultPassword from "./script-items/default-password";
import InstallCommand from "./script-items/install-command"; import InstallCommand from "./script-items/install-command";
@@ -32,7 +31,7 @@ type ScriptItemProps = {
function ScriptHeader({ item }: { item: Script }) { function ScriptHeader({ item }: { item: Script }) {
const defaultInstallMethod = item.install_methods?.[0]; const defaultInstallMethod = item.install_methods?.[0];
const os = defaultInstallMethod?.resources?.os || (item.type === "addon" ? "Existing LXC or Proxmox Node" : "Proxmox Node"); const os = defaultInstallMethod?.resources?.os || "Proxmox Node";
const version = defaultInstallMethod?.resources?.version || ""; const version = defaultInstallMethod?.resources?.version || "";
return ( return (
@@ -56,7 +55,9 @@ function ScriptHeader({ item }: { item: Script }) {
<h1 className="text-2xl font-semibold tracking-tight flex items-center gap-2"> <h1 className="text-2xl font-semibold tracking-tight flex items-center gap-2">
{item.name} {item.name}
<VersionInfo item={item} /> <VersionInfo item={item} />
{formattedBadge(item.type)} <span className="inline-flex items-center rounded-md bg-accent/30 px-2 py-1 text-sm">
{getDisplayValueFromType(item.type)}
</span>
</h1> </h1>
<div className="mt-1 flex items-center gap-3 text-sm text-muted-foreground"> <div className="mt-1 flex items-center gap-3 text-sm text-muted-foreground">
<span> <span>

View File

@@ -36,24 +36,17 @@ const TooltipBadge: React.FC<TooltipProps> = ({ variant, label, content }) => (
export default function Tooltips({ item }: { item: Script }) { export default function Tooltips({ item }: { item: Script }) {
return ( return (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{item.privileged && item.type !== "addon" && ( {item.privileged && (
<TooltipBadge variant="warning" label="Privileged" content="This script will be run in a privileged LXC" /> <TooltipBadge variant="warning" label="Privileged" content="This script will be run in a privileged LXC" />
)} )}
{item.updateable && item.type !== "pve" && item.type !== "addon" && ( {item.updateable && item.type !== "pve" && (
<TooltipBadge <TooltipBadge
variant="success" variant="success"
label="Updateable" label="Updateable"
content={`To Update ${item.name}, run the command below (or type update) in the LXC Console.`} content={`To Update ${item.name}, run the command below (or type update) in the LXC Console.`}
/> />
)} )}
{item.updateable && item.type === "addon" && ( {!item.updateable && item.type !== "pve" && <TooltipBadge variant="failure" label="Not Updateable" />}
<TooltipBadge
variant="success"
label="Updateable"
content={`Run update_${item.slug} to update or use the bash command inside the LXC.`}
/>
)}
{!item.updateable && item.type !== "pve" && item.type !== "addon" && <TooltipBadge variant="failure" label="Not Updateable" />}
</div> </div>
); );
} }

View File

@@ -32,11 +32,6 @@ function ScriptContent() {
.flat() .flat()
.find(script => script.slug === selectedScript); .find(script => script.slug === selectedScript);
setItem(script); setItem(script);
if (script) {
document.title = `${script.name} | Proxmox VE Helper-Scripts`;
}
} else {
document.title = "Proxmox VE Helper-Scripts";
} }
}, [selectedScript, links]); }, [selectedScript, links]);

View File

@@ -0,0 +1,75 @@
#!/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://komo.do/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apk add --no-cache ca-certificates openssl
msg_ok "Installed Dependencies"
msg_info "Setup Docker Repository"
$STD apk add --no-cache docker docker-cli docker-compose openrc
msg_ok "Setup Docker Repository"
msg_info "Enabling Docker Service"
$STD rc-update add docker boot
$STD service docker start
msg_ok "Enabled Docker Service"
echo "${TAB3}Choose the database for Komodo installation:"
echo "${TAB3}1) MongoDB (recommended)"
echo "${TAB3}2) FerretDB"
read -rp "${TAB3}Enter your choice (default: 1): " DB_CHOICE
DB_CHOICE=${DB_CHOICE:-1}
case $DB_CHOICE in
1)
DB_COMPOSE_FILE="mongo.compose.yaml"
;;
2)
DB_COMPOSE_FILE="ferretdb.compose.yaml"
;;
*)
echo "Invalid choice. Defaulting to MongoDB."
DB_COMPOSE_FILE="mongo.compose.yaml"
;;
esac
mkdir -p /opt/komodo
cd /opt/komodo
curl -fsSL "https://raw.githubusercontent.com/moghtech/komodo/main/compose/$DB_COMPOSE_FILE" -o "$(basename "$DB_COMPOSE_FILE")"
msg_info "Setup Komodo Environment"
curl -fsSL "https://raw.githubusercontent.com/moghtech/komodo/main/compose/compose.env" -o "/opt/komodo/compose.env"
DB_PASSWORD=$(openssl rand -base64 16 | tr -d '/+=')
PASSKEY=$(openssl rand -base64 24 | tr -d '/+=')
WEBHOOK_SECRET=$(openssl rand -base64 24 | tr -d '/+=')
JWT_SECRET=$(openssl rand -base64 24 | tr -d '/+=')
sed -i "s/^KOMODO_DB_USERNAME=.*/KOMODO_DB_USERNAME=komodo_admin/" /opt/komodo/compose.env
sed -i "s/^KOMODO_DB_PASSWORD=.*/KOMODO_DB_PASSWORD=${DB_PASSWORD}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_PASSKEY=.*/KOMODO_PASSKEY=${PASSKEY}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_WEBHOOK_SECRET=.*/KOMODO_WEBHOOK_SECRET=${WEBHOOK_SECRET}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_JWT_SECRET=.*/KOMODO_JWT_SECRET=${JWT_SECRET}/" /opt/komodo/compose.env
msg_ok "Setup Komodo Environment"
msg_info "Initialize Komodo"
$STD docker compose -p komodo -f "/opt/komodo/$DB_COMPOSE_FILE" --env-file /opt/komodo/compose.env up -d
msg_ok "Initialized Komodo"
motd_ssh
customize
msg_info "Cleaning up"
$STD apk cache clean
msg_ok "Cleaned"

View File

@@ -13,10 +13,6 @@ setting_up_container
network_check network_check
update_os update_os
msg_info "Installing Dependencies"
$STD apt install -y ffmpeg
msg_ok "Installed Dependencies"
JAVA_VERSION="25" setup_java JAVA_VERSION="25" setup_java
NODE_VERSION="22" setup_nodejs NODE_VERSION="22" setup_nodejs
setup_mariadb setup_mariadb
@@ -74,7 +70,7 @@ After=network.target mariadb.service
Type=simple Type=simple
User=root User=root
WorkingDirectory=/opt/booklore/dist WorkingDirectory=/opt/booklore/dist
ExecStart=/usr/bin/java -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+UseCompactObjectHeaders -XX:MaxRAMPercentage=75.0 -XX:+ExitOnOutOfMemoryError -jar /opt/booklore/dist/app.jar ExecStart=/usr/bin/java -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+UseCompactObjectHeaders -jar /opt/booklore/dist/app.jar
EnvironmentFile=/opt/booklore_storage/.env EnvironmentFile=/opt/booklore_storage/.env
SuccessExitStatus=143 SuccessExitStatus=143
TimeoutStopSec=10 TimeoutStopSec=10

View File

@@ -39,7 +39,7 @@ $STD apt install -y \
texlive-xetex texlive-xetex
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
NODE_VERSION="22" NODE_MODULE="bun" setup_nodejs NODE_VERSION=22 NODE_MODULE="bun" setup_nodejs
fetch_and_deploy_gh_release "ConvertX" "C4illin/ConvertX" "tarball" "latest" "/opt/convertx" fetch_and_deploy_gh_release "ConvertX" "C4illin/ConvertX" "tarball" "latest" "/opt/convertx"
msg_info "Installing ConvertX" msg_info "Installing ConvertX"

View File

@@ -0,0 +1,39 @@
#!/bin/bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://coolify.io/
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 \
git \
openssl
msg_ok "Installed Dependencies"
msg_warn "WARNING: This script will run an external installer from a third-party source (https://coolify.io/)."
msg_warn "The following code is NOT maintained or audited by our repository."
msg_warn "If you have any doubts or concerns, please review the installer code before proceeding:"
msg_custom "${TAB3}${GATEWAY}${BGN}${CL}" "\e[1;34m" "→ https://cdn.coollabs.io/coolify/install.sh"
echo
read -r -p "${TAB3}Do you want to continue? [y/N]: " CONFIRM
if [[ ! "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then
msg_error "Aborted by user. No changes have been made."
exit 10
fi
msg_info "Installing Coolify (Patience - this installs Docker and pulls containers)"
$STD bash <(curl -fsSL https://cdn.coollabs.io/coolify/install.sh)
msg_ok "Installed Coolify"
motd_ssh
customize
cleanup_lxc

View File

@@ -15,40 +15,14 @@ update_os
msg_info "Installing Dependencies" msg_info "Installing Dependencies"
$STD apt install -y \ $STD apt install -y \
nginx \ nginx \
valkey \ valkey
mariadb-client \
rclone
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
PG_VERSION="17" setup_postgresql PG_VERSION="17" setup_postgresql
setup_go setup_go
NODE_VERSION="24" setup_nodejs NODE_VERSION="24" setup_nodejs
msg_info "Installing Database Clients"
# Create PostgreSQL version symlinks for compatibility
for v in 12 13 14 15 16 18; do
ln -sf /usr/lib/postgresql/17 /usr/lib/postgresql/$v
done
# Install MongoDB Database Tools via direct .deb (no APT repo for Debian 13)
[[ "$(get_os_info id)" == "ubuntu" ]] && MONGO_DIST="ubuntu2204" || MONGO_DIST="debian12"
MONGO_VERSION=$(get_latest_gh_tag "mongodb/mongo-tools" "100." || echo "100.14.1")
fetch_and_deploy_from_url "https://fastdl.mongodb.org/tools/db/mongodb-database-tools-${MONGO_DIST}-x86_64-${MONGO_VERSION}.deb"
mkdir -p /usr/local/mongodb-database-tools/bin
[[ -f /usr/bin/mongodump ]] && ln -sf /usr/bin/mongodump /usr/local/mongodb-database-tools/bin/mongodump
[[ -f /usr/bin/mongorestore ]] && ln -sf /usr/bin/mongorestore /usr/local/mongodb-database-tools/bin/mongorestore
# Create MariaDB and MySQL client symlinks for compatibility
mkdir -p /usr/local/mariadb-{10.6,12.1}/bin /usr/local/mysql-{5.7,8.0,8.4,9}/bin
for dir in /usr/local/mariadb-{10.6,12.1}/bin; do
ln -sf /usr/bin/mariadb-dump "$dir/mariadb-dump"
ln -sf /usr/bin/mariadb "$dir/mariadb"
done
for dir in /usr/local/mysql-{5.7,8.0,8.4,9}/bin; do
ln -sf /usr/bin/mariadb-dump "$dir/mysqldump"
ln -sf /usr/bin/mariadb "$dir/mysql"
done
msg_ok "Installed Database Clients"
fetch_and_deploy_gh_release "databasus" "databasus/databasus" "tarball" "latest" "/opt/databasus" fetch_and_deploy_gh_release "databasus" "databasus/databasus" "tarball" "latest" "/opt/databasus"
msg_info "Building Databasus (Patience)" msg_info "Building Databasus (Patience)"
@@ -73,6 +47,10 @@ msg_ok "Built Databasus"
msg_info "Configuring Databasus" msg_info "Configuring Databasus"
JWT_SECRET=$(openssl rand -hex 32) JWT_SECRET=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 32) ENCRYPTION_KEY=$(openssl rand -hex 32)
# Create PostgreSQL version symlinks for compatibility
for v in 12 13 14 15 16 18; do
ln -sf /usr/lib/postgresql/17 /usr/lib/postgresql/$v
done
# Install goose for migrations # Install goose for migrations
$STD go install github.com/pressly/goose/v3/cmd/goose@latest $STD go install github.com/pressly/goose/v3/cmd/goose@latest
ln -sf /root/go/bin/goose /usr/local/bin/goose ln -sf /root/go/bin/goose /usr/local/bin/goose

View File

@@ -16,23 +16,19 @@ update_os
msg_info "Installing Dependencies" msg_info "Installing Dependencies"
$STD apt install -y \ $STD apt install -y \
build-essential \ build-essential \
cmake \
git \ git \
imagemagick \
libffi-dev \
libgeos-dev \
libgeos++-dev \
libjemalloc2 \
libjemalloc-dev \
libmagickwand-dev \
libpq-dev \ libpq-dev \
libssl-dev \ libgeos-dev \
libvips-dev \
libxml2-dev \
libxslt-dev \
libyaml-dev \ libyaml-dev \
nginx \ libffi-dev \
redis-server libssl-dev \
libjemalloc2 \
imagemagick \
libmagickwand-dev \
libvips-dev \
cmake \
redis-server \
nginx
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
PG_VERSION="17" PG_MODULES="postgis-3" setup_postgresql PG_VERSION="17" PG_MODULES="postgis-3" setup_postgresql
@@ -86,8 +82,7 @@ elif [[ -f /opt/dawarich/app/package.json ]]; then
$STD npm install $STD npm install
fi fi
$STD bundle exec rake assets:precompile $STD bundle exec rake assets:precompile
$STD bundle exec rails db:schema:load $STD bundle exec rails db:prepare
$STD bundle exec rails db:seed || msg_warn "Database seed failed (upstream rgeo-geojson issue), app will still work"
$STD bundle exec rake data:migrate $STD bundle exec rake data:migrate
msg_ok "Installed Dawarich" msg_ok "Installed Dawarich"

64
install/dockge-install.sh Normal file
View File

@@ -0,0 +1,64 @@
#!/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://dockge.kuma.pet/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
DOCKER_LATEST_VERSION=$(get_latest_github_release "moby/moby")
msg_info "Installing Docker $DOCKER_LATEST_VERSION (with Compose, Buildx)"
DOCKER_CONFIG_PATH='/etc/docker/daemon.json'
mkdir -p $(dirname $DOCKER_CONFIG_PATH)
echo -e '{\n "log-driver": "journald"\n}' >/etc/docker/daemon.json
$STD sh <(curl -fsSL https://get.docker.com)
msg_ok "Installed Docker $DOCKER_LATEST_VERSION"
msg_info "Installing Dockge"
mkdir -p /opt/{dockge,stacks}
curl -fsSL "https://raw.githubusercontent.com/louislam/dockge/master/compose.yaml" -o "/opt/dockge/compose.yaml"
cd /opt/dockge
$STD docker compose up -d
msg_ok "Installed Dockge"
read -r -p "${TAB3}Would you like to add Immich? <y/N> " prompt
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
msg_info "Adding Immich compose.yaml"
mkdir -p /opt/stacks/immich
curl -fsSL "https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml" -o "/opt/stacks/immich/compose.yaml"
curl -fsSL "https://github.com/immich-app/immich/releases/latest/download/example.env" -o "/opt/stacks/immich/.env"
msg_ok "Added Immich compose.yaml"
fi
read -r -p "${TAB3}Would you like to add Home Assistant? <y/N> " prompt
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
msg_info "Adding Home Assistant compose.yaml"
mkdir -p /opt/stacks/homeassistant
cat <<EOF >/opt/stacks/homeassistant/compose.yaml
version: "3"
services:
homeassistant:
container_name: homeassistant
image: ghcr.io/home-assistant/home-assistant:stable
volumes:
- ./config:/config
- /etc/localtime:/etc/localtime:ro
- /run/dbus:/run/dbus:ro
restart: unless-stopped
privileged: true
network_mode: host
EOF
msg_ok "Added Home Assistant compose.yaml"
fi
motd_ssh
customize
cleanup_lxc

View File

@@ -0,0 +1,40 @@
#!/bin/bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://dokploy.com/
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 \
git \
openssl \
redis
msg_ok "Installed Dependencies"
msg_warn "WARNING: This script will run an external installer from a third-party source (https://dokploy.com/)."
msg_warn "The following code is NOT maintained or audited by our repository."
msg_warn "If you have any doubts or concerns, please review the installer code before proceeding:"
msg_custom "${TAB3}${GATEWAY}${BGN}${CL}" "\e[1;34m" "→ https://dokploy.com/install.sh"
echo
read -r -p "${TAB3}Do you want to continue? [y/N]: " CONFIRM
if [[ ! "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then
msg_error "Aborted by user. No changes have been made."
exit 10
fi
msg_info "Installing Dokploy (Patience - this installs Docker and pulls containers)"
$STD bash <(curl -sSL https://dokploy.com/install.sh)
msg_ok "Installed Dokploy"
motd_ssh
customize
cleanup_lxc

View File

@@ -72,7 +72,7 @@ cat <<EOF >/etc/apache2/sites-available/firefly.conf
</VirtualHost> </VirtualHost>
EOF EOF
chown www-data:www-data /opt/firefly/storage/oauth-*.key chown www-data:www-data /opt/firefly/storage/oauth-*.key
$STD a2enmod php8.5 $STD a2enmod php8.4
$STD a2enmod rewrite $STD a2enmod rewrite
$STD a2ensite firefly.conf $STD a2ensite firefly.conf
$STD a2dissite 000-default.conf $STD a2dissite 000-default.conf

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG # Copyright (c) 2021-2026 community-scripts ORG
# Authors: MickLesk (CanbiZ) | Co-Authors: remz1337 # Authors: MickLesk (CanbiZ)
# Co-Authors: remz1337
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://frigate.video/ | Github: https://github.com/blakeblackshear/frigate # Source: https://frigate.video/ | Github: https://github.com/blakeblackshear/frigate
@@ -84,7 +85,6 @@ $STD apt install -y \
tclsh \ tclsh \
libopenblas-dev \ libopenblas-dev \
liblapack-dev \ liblapack-dev \
libgomp1 \
make \ make \
moreutils moreutils
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
@@ -101,16 +101,9 @@ export NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
export TOKENIZERS_PARALLELISM=true export TOKENIZERS_PARALLELISM=true
export TRANSFORMERS_NO_ADVISORY_WARNINGS=1 export TRANSFORMERS_NO_ADVISORY_WARNINGS=1
export OPENCV_FFMPEG_LOGLEVEL=8 export OPENCV_FFMPEG_LOGLEVEL=8
export PYTHONWARNINGS="ignore:::numpy.core.getlimits"
export HAILORT_LOGGER_PATH=NONE export HAILORT_LOGGER_PATH=NONE
export TF_CPP_MIN_LOG_LEVEL=3
export TF_CPP_MIN_VLOG_LEVEL=3
export TF_ENABLE_ONEDNN_OPTS=0
export AUTOGRAPH_VERBOSITY=0
export GLOG_minloglevel=3
export GLOG_logtostderr=0
fetch_and_deploy_gh_release "frigate" "blakeblackshear/frigate" "tarball" "v0.17.0" "/opt/frigate" fetch_and_deploy_gh_release "frigate" "blakeblackshear/frigate" "tarball" "v0.16.4" "/opt/frigate"
msg_info "Building Nginx" msg_info "Building Nginx"
$STD bash /opt/frigate/docker/main/build_nginx.sh $STD bash /opt/frigate/docker/main/build_nginx.sh
@@ -145,19 +138,13 @@ install -c -m 644 libusb-1.0.pc /usr/local/lib/pkgconfig
ldconfig ldconfig
msg_ok "Built libUSB" msg_ok "Built libUSB"
msg_info "Bootstrapping pip"
wget -q https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py
sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' /tmp/get-pip.py
$STD python3 /tmp/get-pip.py "pip"
rm -f /tmp/get-pip.py
msg_ok "Bootstrapped pip"
msg_info "Installing Python Dependencies" msg_info "Installing Python Dependencies"
$STD pip3 install -r /opt/frigate/docker/main/requirements.txt $STD pip3 install -r /opt/frigate/docker/main/requirements.txt
msg_ok "Installed Python Dependencies" msg_ok "Installed Python Dependencies"
msg_info "Building Python Wheels (Patience)" msg_info "Building Python Wheels (Patience)"
mkdir -p /wheels mkdir -p /wheels
sed -i 's|^SQLITE3_VERSION=.*|SQLITE3_VERSION="version-3.46.0"|g' /opt/frigate/docker/main/build_pysqlite3.sh
$STD bash /opt/frigate/docker/main/build_pysqlite3.sh $STD bash /opt/frigate/docker/main/build_pysqlite3.sh
for i in {1..3}; do for i in {1..3}; do
$STD pip3 wheel --wheel-dir=/wheels -r /opt/frigate/docker/main/requirements-wheels.txt --default-timeout=300 --retries=3 && break $STD pip3 wheel --wheel-dir=/wheels -r /opt/frigate/docker/main/requirements-wheels.txt --default-timeout=300 --retries=3 && break
@@ -165,7 +152,7 @@ for i in {1..3}; do
done done
msg_ok "Built Python Wheels" msg_ok "Built Python Wheels"
NODE_VERSION="20" setup_nodejs NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs
msg_info "Downloading Inference Models" msg_info "Downloading Inference Models"
mkdir -p /models /openvino-model mkdir -p /models /openvino-model
@@ -196,10 +183,6 @@ $STD pip3 install -U /wheels/*.whl
ldconfig ldconfig
msg_ok "Installed HailoRT Runtime" msg_ok "Installed HailoRT Runtime"
msg_info "Installing MemryX Runtime"
$STD bash /opt/frigate/docker/main/install_memryx.sh
msg_ok "Installed MemryX Runtime"
msg_info "Installing OpenVino" msg_info "Installing OpenVino"
$STD pip3 install -r /opt/frigate/docker/main/requirements-ov.txt $STD pip3 install -r /opt/frigate/docker/main/requirements-ov.txt
msg_ok "Installed OpenVino" msg_ok "Installed OpenVino"
@@ -226,8 +209,6 @@ $STD make version
cd /opt/frigate/web cd /opt/frigate/web
$STD npm install $STD npm install
$STD npm run build $STD npm run build
mv /opt/frigate/web/dist/BASE_PATH/monacoeditorwork/* /opt/frigate/web/dist/assets/
rm -rf /opt/frigate/web/dist/BASE_PATH
cp -r /opt/frigate/web/dist/* /opt/frigate/web/ cp -r /opt/frigate/web/dist/* /opt/frigate/web/
sed -i '/^s6-svc -O \.$/s/^/#/' /opt/frigate/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/run sed -i '/^s6-svc -O \.$/s/^/#/' /opt/frigate/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/run
msg_ok "Built Frigate Application" msg_ok "Built Frigate Application"
@@ -243,19 +224,6 @@ echo "tmpfs /tmp/cache tmpfs defaults 0 0" >>/etc/fstab
cat <<EOF >/etc/frigate.env cat <<EOF >/etc/frigate.env
DEFAULT_FFMPEG_VERSION="7.0" DEFAULT_FFMPEG_VERSION="7.0"
INCLUDED_FFMPEG_VERSIONS="7.0:5.0" INCLUDED_FFMPEG_VERSIONS="7.0:5.0"
NVIDIA_VISIBLE_DEVICES=all
NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
TOKENIZERS_PARALLELISM=true
TRANSFORMERS_NO_ADVISORY_WARNINGS=1
OPENCV_FFMPEG_LOGLEVEL=8
PYTHONWARNINGS="ignore:::numpy.core.getlimits"
HAILORT_LOGGER_PATH=NONE
TF_CPP_MIN_LOG_LEVEL=3
TF_CPP_MIN_VLOG_LEVEL=3
TF_ENABLE_ONEDNN_OPTS=0
AUTOGRAPH_VERBOSITY=0
GLOG_minloglevel=3
GLOG_logtostderr=0
EOF EOF
cat <<EOF >/config/config.yml cat <<EOF >/config/config.yml
@@ -269,6 +237,7 @@ cameras:
input_args: -re -stream_loop -1 -fflags +genpts input_args: -re -stream_loop -1 -fflags +genpts
roles: roles:
- detect - detect
- rtmp
detect: detect:
height: 1080 height: 1080
width: 1920 width: 1920
@@ -286,7 +255,6 @@ ffmpeg:
detectors: detectors:
detector01: detector01:
type: openvino type: openvino
device: AUTO
model: model:
width: 300 width: 300
height: 300 height: 300

View File

@@ -76,20 +76,6 @@ source /opt/gramps-web/venv/bin/activate
$STD uv pip install --no-cache-dir --upgrade pip setuptools wheel $STD uv pip install --no-cache-dir --upgrade pip setuptools wheel
$STD uv pip install --no-cache-dir gunicorn $STD uv pip install --no-cache-dir gunicorn
$STD uv pip install --no-cache-dir /opt/gramps-web-api $STD uv pip install --no-cache-dir /opt/gramps-web-api
GRAMPS_VERSION=$(/opt/gramps-web/venv/bin/python3 -c "import gramps.version; print('%s%s' % (gramps.version.VERSION_TUPLE[0], gramps.version.VERSION_TUPLE[1]))" 2>/dev/null || echo "60")
GRAMPS_PLUGINS_DIR="/opt/gramps-web/data/gramps/gramps${GRAMPS_VERSION}/plugins"
mkdir -p "$GRAMPS_PLUGINS_DIR"
msg_info "Installing Gramps Addons (gramps${GRAMPS_VERSION})"
$STD wget -q https://github.com/gramps-project/addons/archive/refs/heads/master.zip -O /tmp/gramps-addons.zip
for addon in FilterRules JSON; do
unzip -p /tmp/gramps-addons.zip "addons-master/gramps${GRAMPS_VERSION}/download/${addon}.addon.tgz" | \
tar -xz -C "$GRAMPS_PLUGINS_DIR"
done
rm -f /tmp/gramps-addons.zip
msg_ok "Installed Gramps Addons"
cd /opt/gramps-web/frontend cd /opt/gramps-web/frontend
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
$STD corepack enable $STD corepack enable
@@ -98,7 +84,7 @@ $STD npm run build
cd /opt/gramps-web-api cd /opt/gramps-web-api
GRAMPS_API_CONFIG=/opt/gramps-web/config/config.cfg \ GRAMPS_API_CONFIG=/opt/gramps-web/config/config.cfg \
ALEMBIC_CONFIG=/opt/gramps-web-api/alembic.ini \ ALEMBIC_CONFIG=/opt/gramps-web-api/alembic.ini \
GRAMPSHOME=/opt/gramps-web/data \ GRAMPSHOME=/opt/gramps-web/data/gramps \
GRAMPS_DATABASE_PATH=/opt/gramps-web/data/gramps/grampsdb \ GRAMPS_DATABASE_PATH=/opt/gramps-web/data/gramps/grampsdb \
$STD /opt/gramps-web/venv/bin/python3 -m gramps_webapi user migrate $STD /opt/gramps-web/venv/bin/python3 -m gramps_webapi user migrate
msg_ok "Set up Gramps Web" msg_ok "Set up Gramps Web"
@@ -114,7 +100,7 @@ Type=simple
User=root User=root
WorkingDirectory=/opt/gramps-web-api WorkingDirectory=/opt/gramps-web-api
Environment=GRAMPS_API_CONFIG=/opt/gramps-web/config/config.cfg Environment=GRAMPS_API_CONFIG=/opt/gramps-web/config/config.cfg
Environment=GRAMPSHOME=/opt/gramps-web/data Environment=GRAMPSHOME=/opt/gramps-web/data/gramps
Environment=GRAMPS_DATABASE_PATH=/opt/gramps-web/data/gramps/grampsdb Environment=GRAMPS_DATABASE_PATH=/opt/gramps-web/data/gramps/grampsdb
Environment=PATH=/opt/gramps-web/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin Environment=PATH=/opt/gramps-web/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/opt/gramps-web/venv/bin/gunicorn -w 2 -b 0.0.0.0:5000 gramps_webapi.wsgi:app --timeout 120 --limit-request-line 8190 ExecStart=/opt/gramps-web/venv/bin/gunicorn -w 2 -b 0.0.0.0:5000 gramps_webapi.wsgi:app --timeout 120 --limit-request-line 8190

View File

@@ -32,9 +32,9 @@ if [ -d /dev/dri ]; then
$STD apt install -y --no-install-recommends patchelf $STD apt install -y --no-install-recommends patchelf
tmp_dir=$(mktemp -d) tmp_dir=$(mktemp -d)
$STD pushd "$tmp_dir" $STD pushd "$tmp_dir"
curl -fsSLO https://raw.githubusercontent.com/immich-app/immich/refs/heads/main/machine-learning/Dockerfile curl -fsSLO https://raw.githubusercontent.com/immich-app/base-images/refs/heads/main/server/Dockerfile
readarray -t INTEL_URLS < <( readarray -t INTEL_URLS < <(
sed -n "/intel-[igc|opencl]/p" ./Dockerfile | awk '{print $3}' sed -n "/intel-[igc|opencl]/p" ./Dockerfile | awk '{print $2}'
sed -n "/libigdgmm12/p" ./Dockerfile | awk '{print $3}' sed -n "/libigdgmm12/p" ./Dockerfile | awk '{print $3}'
) )
for url in "${INTEL_URLS[@]}"; do for url in "${INTEL_URLS[@]}"; do
@@ -150,11 +150,11 @@ PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql
VCHORD_RELEASE="0.5.3" VCHORD_RELEASE="0.5.3"
fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" "${VCHORD_RELEASE}" "/tmp" "postgresql-16-vchord_*_amd64.deb" fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" "${VCHORD_RELEASE}" "/tmp" "postgresql-16-vchord_*_amd64.deb"
sed -i "s/^#shared_preload.*/shared_preload_libraries = 'vchord.so'/" /etc/postgresql/16/main/postgresql.conf sed -i -e "/^#shared_preload/s/^#//;/^shared_preload/s/''/'vchord.so'/" /etc/postgresql/16/main/postgresql.conf
systemctl restart postgresql.service systemctl restart postgresql.service
PG_DB_NAME="immich" PG_DB_USER="immich" PG_DB_GRANT_SUPERUSER="true" PG_DB_SKIP_ALTER_ROLE="true" setup_postgresql_db PG_DB_NAME="immich" PG_DB_USER="immich" PG_DB_GRANT_SUPERUSER="true" PG_DB_SKIP_ALTER_ROLE="true" setup_postgresql_db
msg_warn "Compiling Custom Photo-processing Libraries (can take anywhere from 15min to 2h)" msg_info "Compiling Custom Photo-processing Library (extreme patience)"
LD_LIBRARY_PATH=/usr/local/lib LD_LIBRARY_PATH=/usr/local/lib
export LD_RUN_PATH=/usr/local/lib export LD_RUN_PATH=/usr/local/lib
STAGING_DIR=/opt/staging STAGING_DIR=/opt/staging
@@ -342,9 +342,9 @@ mkdir -p "$ML_DIR" && chown -R immich:immich "$INSTALL_DIR"
export VIRTUAL_ENV="${ML_DIR}/ml-venv" export VIRTUAL_ENV="${ML_DIR}/ml-venv"
if [[ -f ~/.openvino ]]; then if [[ -f ~/.openvino ]]; then
msg_info "Installing HW-accelerated machine-learning" msg_info "Installing HW-accelerated machine-learning"
$STD uv add --no-sync --optional openvino onnxruntime-openvino==1.24.1 --active -n -p python3.13 --managed-python $STD uv add --no-sync --optional openvino onnxruntime-openvino==1.20.0 --active -n -p python3.12 --managed-python
$STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p python3.13 --managed-python $STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p python3.12 --managed-python
patchelf --clear-execstack "${VIRTUAL_ENV}/lib/python3.13/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-313-x86_64-linux-gnu.so" patchelf --clear-execstack "${VIRTUAL_ENV}/lib/python3.12/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-312-x86_64-linux-gnu.so"
msg_ok "Installed HW-accelerated machine-learning" msg_ok "Installed HW-accelerated machine-learning"
else else
msg_info "Installing machine-learning" msg_info "Installing machine-learning"

View File

@@ -21,7 +21,7 @@ msg_ok "Installed Dependencies"
PG_VERSION="17" setup_postgresql PG_VERSION="17" setup_postgresql
PG_DB_NAME="joplin" PG_DB_USER="joplin" setup_postgresql_db PG_DB_NAME="joplin" PG_DB_USER="joplin" setup_postgresql_db
NODE_VERSION="24" NODE_MODULE="yarn,npm,pm2" setup_nodejs NODE_VERSION=24 NODE_MODULE="yarn,npm,pm2" setup_nodejs
mkdir -p /opt/pm2 mkdir -p /opt/pm2
export PM2_HOME=/opt/pm2 export PM2_HOME=/opt/pm2
$STD pm2 install pm2-logrotate $STD pm2 install pm2-logrotate

View File

@@ -1,212 +0,0 @@
#!/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/Chevron7Locked/kima-hub
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt-get install -y \
build-essential \
git \
openssl \
ffmpeg \
python3 \
python3-pip \
python3-dev \
python3-numpy \
redis-server
msg_ok "Installed Dependencies"
PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql
PG_DB_NAME="kima" PG_DB_USER="kima" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db
NODE_VERSION="20" setup_nodejs
msg_info "Configuring Redis"
systemctl enable -q --now redis-server
msg_ok "Configured Redis"
fetch_and_deploy_gh_release "kima-hub" "Chevron7Locked/kima-hub" "tarball"
msg_info "Installing Python Dependencies"
export PIP_BREAK_SYSTEM_PACKAGES=1
$STD pip3 install --no-cache-dir \
tensorflow \
essentia-tensorflow \
redis \
psycopg2-binary \
laion-clap \
torch \
torchaudio \
librosa \
transformers \
pgvector \
python-dotenv \
requests
msg_ok "Installed Python Dependencies"
msg_info "Downloading Essentia ML Models"
mkdir -p /opt/kima-hub/models
cd /opt/kima-hub/models
curl -fsSL -o msd-musicnn-1.pb "https://essentia.upf.edu/models/autotagging/msd/msd-musicnn-1.pb"
curl -fsSL -o mood_happy-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_happy/mood_happy-msd-musicnn-1.pb"
curl -fsSL -o mood_sad-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_sad/mood_sad-msd-musicnn-1.pb"
curl -fsSL -o mood_relaxed-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_relaxed/mood_relaxed-msd-musicnn-1.pb"
curl -fsSL -o mood_aggressive-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_aggressive/mood_aggressive-msd-musicnn-1.pb"
curl -fsSL -o mood_party-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_party/mood_party-msd-musicnn-1.pb"
curl -fsSL -o mood_acoustic-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_acoustic/mood_acoustic-msd-musicnn-1.pb"
curl -fsSL -o mood_electronic-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_electronic/mood_electronic-msd-musicnn-1.pb"
curl -fsSL -o danceability-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/danceability/danceability-msd-musicnn-1.pb"
curl -fsSL -o voice_instrumental-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/voice_instrumental/voice_instrumental-msd-musicnn-1.pb"
msg_ok "Downloaded Essentia ML Models"
msg_info "Downloading CLAP Model"
curl -fsSL -o /opt/kima-hub/models/music_audioset_epoch_15_esc_90.14.pt "https://huggingface.co/lukewys/laion_clap/resolve/main/music_audioset_epoch_15_esc_90.14.pt"
msg_ok "Downloaded CLAP Model"
msg_info "Building Backend"
cd /opt/kima-hub/backend
$STD npm ci
$STD npm run build
msg_ok "Built Backend"
msg_info "Configuring Backend"
SESSION_SECRET=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 32)
cat <<EOF >/opt/kima-hub/backend/.env
NODE_ENV=production
DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}
REDIS_URL=redis://localhost:6379
PORT=3006
MUSIC_PATH=/music
TRANSCODE_CACHE_PATH=/opt/kima-hub/cache/transcodes
SESSION_SECRET=${SESSION_SECRET}
SETTINGS_ENCRYPTION_KEY=${ENCRYPTION_KEY}
INTERNAL_API_SECRET=$(openssl rand -hex 16)
EOF
msg_ok "Configured Backend"
msg_info "Running Database Migrations"
cd /opt/kima-hub/backend
$STD npx prisma generate
$STD npx prisma migrate deploy
msg_ok "Ran Database Migrations"
msg_info "Building Frontend"
cd /opt/kima-hub/frontend
$STD npm ci
export NEXT_PUBLIC_BACKEND_URL=http://127.0.0.1:3006
$STD npm run build
msg_ok "Built Frontend"
msg_info "Configuring Frontend"
cat <<EOF >/opt/kima-hub/frontend/.env
NODE_ENV=production
BACKEND_URL=http://localhost:3006
PORT=3030
EOF
msg_ok "Configured Frontend"
msg_info "Creating Directories"
mkdir -p /opt/kima-hub/cache/transcodes
mkdir -p /music
msg_ok "Created Directories"
msg_info "Creating Services"
cat <<EOF >/etc/systemd/system/kima-backend.service
[Unit]
Description=Kima Hub Backend
After=network.target postgresql.service redis-server.service
Wants=postgresql.service redis-server.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/kima-hub/backend
EnvironmentFile=/opt/kima-hub/backend/.env
ExecStart=/usr/bin/node /opt/kima-hub/backend/dist/index.js
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/kima-frontend.service
[Unit]
Description=Kima Hub Frontend
After=network.target kima-backend.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/kima-hub/frontend
EnvironmentFile=/opt/kima-hub/frontend/.env
ExecStart=/usr/bin/npm start
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/kima-analyzer.service
[Unit]
Description=Kima Hub Audio Analyzer (Essentia)
After=network.target postgresql.service redis-server.service kima-backend.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/kima-hub/services/audio-analyzer
Environment=DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}
Environment=REDIS_URL=redis://localhost:6379
Environment=MUSIC_PATH=/music
Environment=BATCH_SIZE=10
Environment=SLEEP_INTERVAL=5
Environment=NUM_WORKERS=2
Environment=THREADS_PER_WORKER=1
ExecStart=/usr/bin/python3 /opt/kima-hub/services/audio-analyzer/analyzer.py
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/kima-analyzer-clap.service
[Unit]
Description=Kima Hub CLAP Audio Analyzer
After=network.target postgresql.service redis-server.service kima-backend.service kima-analyzer.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/kima-hub/services/audio-analyzer-clap
Environment=DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}
Environment=REDIS_URL=redis://localhost:6379
Environment=BACKEND_URL=http://localhost:3006
Environment=MUSIC_PATH=/music
Environment=SLEEP_INTERVAL=5
Environment=NUM_WORKERS=1
ExecStart=/usr/bin/python3 /opt/kima-hub/services/audio-analyzer-clap/analyzer.py
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now kima-backend kima-frontend kima-analyzer kima-analyzer-clap
msg_ok "Created Services"
motd_ssh
customize
cleanup_lxc

85
install/komodo-install.sh Normal file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://komo.do/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Setup Docker Repository"
setup_deb822_repo \
"docker" \
"https://download.docker.com/linux/$(get_os_info id)/gpg" \
"https://download.docker.com/linux/$(get_os_info id)" \
"$(get_os_info codename)" \
"stable" \
"$(dpkg --print-architecture)"
msg_ok "Setup Docker Repository"
msg_info "Installing Docker"
$STD apt install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
msg_ok "Installed Docker"
echo "${TAB3}Choose the database for Komodo installation:"
echo "${TAB3}1) MongoDB (recommended)"
echo "${TAB3}2) FerretDB"
read -rp "${TAB3}Enter your choice (default: 1): " DB_CHOICE
DB_CHOICE=${DB_CHOICE:-1}
case $DB_CHOICE in
1)
DB_COMPOSE_FILE="mongo.compose.yaml"
;;
2)
DB_COMPOSE_FILE="ferretdb.compose.yaml"
;;
*)
echo "Invalid choice. Defaulting to MongoDB."
DB_COMPOSE_FILE="mongo.compose.yaml"
;;
esac
mkdir -p /opt/komodo
cd /opt/komodo
curl -fsSL "https://raw.githubusercontent.com/moghtech/komodo/main/compose/$DB_COMPOSE_FILE" -o "/opt/komodo/$DB_COMPOSE_FILE"
msg_info "Setup Komodo Environment"
curl -fsSL "https://raw.githubusercontent.com/moghtech/komodo/main/compose/compose.env" -o "/opt/komodo/compose.env"
DB_PASSWORD=$(openssl rand -base64 16 | tr -d '/+=')
ADMIN_PASSWORD=$(openssl rand -base64 8 | tr -d '/+=')
PASSKEY=$(openssl rand -base64 24 | tr -d '/+=')
WEBHOOK_SECRET=$(openssl rand -base64 24 | tr -d '/+=')
JWT_SECRET=$(openssl rand -base64 24 | tr -d '/+=')
sed -i "s/^KOMODO_DB_USERNAME=.*/KOMODO_DB_USERNAME=komodo_admin/" /opt/komodo/compose.env
sed -i "s/^KOMODO_DB_PASSWORD=.*/KOMODO_DB_PASSWORD=${DB_PASSWORD}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_INIT_ADMIN_PASSWORD=changeme/KOMODO_INIT_ADMIN_PASSWORD=${ADMIN_PASSWORD}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_PASSKEY=.*/KOMODO_PASSKEY=${PASSKEY}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_WEBHOOK_SECRET=.*/KOMODO_WEBHOOK_SECRET=${WEBHOOK_SECRET}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_JWT_SECRET=.*/KOMODO_JWT_SECRET=${JWT_SECRET}/" /opt/komodo/compose.env
{
echo "Komodo Credentials"
echo ""
echo "Admin User : admin"
echo "Admin Password: $ADMIN_PASSWORD"
} >>~/komodo.creds
msg_ok "Setup Komodo Environment"
msg_info "Initialize Komodo"
$STD docker compose -p komodo -f /opt/komodo/$DB_COMPOSE_FILE --env-file /opt/komodo/compose.env up -d
msg_ok "Initialized Komodo"
motd_ssh
customize
cleanup_lxc

View File

@@ -28,7 +28,7 @@ $STD apt install -y \
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
PYTHON_VERSION="3.12" setup_uv PYTHON_VERSION="3.12" setup_uv
PG_VERSION="16" setup_postgresql POSTGRES_VERSION="16" setup_postgresql
NODE_MODULE="yarn" NODE_VERSION="24" setup_nodejs NODE_MODULE="yarn" NODE_VERSION="24" setup_nodejs
fetch_and_deploy_gh_release "mealie" "mealie-recipes/mealie" "tarball" "latest" "/opt/mealie" fetch_and_deploy_gh_release "mealie" "mealie-recipes/mealie" "tarball" "latest" "/opt/mealie"
PG_DB_NAME="mealie_db" PG_DB_USER="mealie_user" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db PG_DB_NAME="mealie_db" PG_DB_USER="mealie_user" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db

View File

@@ -38,7 +38,6 @@ sed -i "s|^DATABASE_URL=.*|DATABASE_URL=\"postgresql://$PG_DB_USER:$PG_DB_PASS@l
sed -i "s|^MEILI_HOST=.*|MEILI_HOST=http://localhost:7700|g" /opt/openarchiver/.env sed -i "s|^MEILI_HOST=.*|MEILI_HOST=http://localhost:7700|g" /opt/openarchiver/.env
sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$MEILISEARCH_MASTER_KEY|g" /opt/openarchiver/.env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$MEILISEARCH_MASTER_KEY|g" /opt/openarchiver/.env
sed -i "s|^REDIS_HOST=.*|REDIS_HOST=localhost|g" /opt/openarchiver/.env sed -i "s|^REDIS_HOST=.*|REDIS_HOST=localhost|g" /opt/openarchiver/.env
sed -i "s|^REDIS_USER=.*|REDIS_USER=|g" /opt/openarchiver/.env
sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=|g" /opt/openarchiver/.env sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=|g" /opt/openarchiver/.env
sed -i "s|^STORAGE_LOCAL_ROOT_PATH=.*|STORAGE_LOCAL_ROOT_PATH=/opt/openarchiver-data|g" /opt/openarchiver/.env sed -i "s|^STORAGE_LOCAL_ROOT_PATH=.*|STORAGE_LOCAL_ROOT_PATH=/opt/openarchiver-data|g" /opt/openarchiver/.env
sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$JWT_KEY|g" /opt/openarchiver/.env sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$JWT_KEY|g" /opt/openarchiver/.env

View File

@@ -14,30 +14,19 @@ network_check
update_os update_os
msg_info "Installing Dependencies" msg_info "Installing Dependencies"
$STD apt install -y \ $STD apt install -y apt-transport-https
apt-transport-https \
build-essential \
autoconf
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
PG_VERSION="17" setup_postgresql PG_VERSION="17" setup_postgresql
PG_DB_NAME="openproject" PG_DB_USER="openproject" setup_postgresql_db PG_DB_NAME="openproject" PG_DB_USER="openproject" setup_postgresql_db
API_KEY=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13) API_KEY=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)
echo "OpenProject API Key: $API_KEY" >>~/openproject.creds echo "OpenProject API Key: $API_KEY" >>~/openproject.creds
fetch_and_deploy_gh_release "jemalloc" "jemalloc/jemalloc" "tarball"
msg_info "Compiling jemalloc (Patience)" msg_info "Setting up OpenProject Repository"
cd /opt/jemalloc curl -fsSL "https://dl.packager.io/srv/opf/openproject/key" | gpg --dearmor >/etc/apt/trusted.gpg.d/packager-io.gpg
$STD ./autogen.sh curl -fsSL "https://dl.packager.io/srv/opf/openproject/stable/15/installer/debian/12.repo" -o "/etc/apt/sources.list.d/openproject.list"
$STD make $STD apt update
$STD make install msg_ok "Setup OpenProject Repository"
msg_ok "Compiled jemalloc"
setup_deb822_repo \
"openproject" \
"https://packages.openproject.com/srv/deb/opf/openproject/gpg-key.gpg" \
"https://packages.openproject.com/srv/deb/opf/openproject/stable/17/debian/" \
"12"
msg_info "Installing OpenProject" msg_info "Installing OpenProject"
$STD apt install -y openproject $STD apt install -y openproject
@@ -71,11 +60,6 @@ openproject/admin_email admin@example.net
openproject/default_language en openproject/default_language en
EOF EOF
$STD sudo openproject configure $STD sudo openproject configure
systemctl stop openproject-web-1
if ! grep -qF 'Environment=LD_PRELOAD=/usr/local/lib/libjemalloc.so.2' /etc/systemd/system/openproject-web-1.service; then
sed -i '/^\[Service\]/a Environment=LD_PRELOAD=/usr/local/lib/libjemalloc.so.2' /etc/systemd/system/openproject-web-1.service
fi
systemctl start openproject-web-1
msg_ok "Configured OpenProject" msg_ok "Configured OpenProject"
motd_ssh motd_ssh

91
install/palmr-install.sh Normal file
View File

@@ -0,0 +1,91 @@
#!/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/kyantech/Palmr
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
fetch_and_deploy_gh_release "Palmr" "kyantech/Palmr" "tarball" "latest" "/opt/palmr"
PNPM="$(jq -r '.packageManager' /opt/palmr/package.json)"
NODE_VERSION="24" NODE_MODULE="$PNPM" setup_nodejs
msg_info "Configuring palmr backend"
PALMR_DIR="/opt/palmr_data"
mkdir -p "$PALMR_DIR"
PALMR_DB="${PALMR_DIR}/palmr.db"
PALMR_KEY="$(openssl rand -hex 32)"
cd /opt/palmr/apps/server
sed -e 's/_ENCRYPTION=true/_ENCRYPTION=false/' \
-e '/^# ENC/s/# //' \
-e "s/ENCRYPTION_KEY=.*$/ENCRYPTION_KEY=$PALMR_KEY/" \
-e "s|file:.*$|file:$PALMR_DB\"|" \
-e "\|db\"$|a\\# Uncomment below when using a reverse proxy\\
# SECURE_SITE=true\\
# Uncomment and add your path if using symlinks for data storage\\
# CUSTOM_PATH=<path-to-your-bind-mount>" \
.env.example >./.env
$STD pnpm install
$STD npx prisma generate
$STD npx prisma migrate deploy
$STD npx prisma db push
$STD pnpm db:seed
$STD pnpm build
msg_ok "Configured palmr backend"
msg_info "Configuring palmr frontend"
cd /opt/palmr/apps/web
mv ./.env.example ./.env
export NODE_ENV=production
export NEXT_TELEMETRY_DISABLED=1
$STD pnpm install
$STD pnpm build
msg_ok "Configured palmr frontend"
msg_info "Creating service"
useradd -d "$PALMR_DIR" -M -s /usr/sbin/nologin -U palmr
chown -R palmr:palmr "$PALMR_DIR" /opt/palmr
cat <<EOF >/etc/systemd/system/palmr-backend.service
[Unit]
Description=palmr Backend Service
After=network.target
[Service]
Type=simple
User=palmr
Group=palmr
WorkingDirectory=/opt/palmr_data
ExecStart=/usr/bin/node /opt/palmr/apps/server/dist/server.js
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/palmr-frontend.service
[Unit]
Description=palmr Frontend Service
After=network.target palmr-backend.service
[Service]
Type=simple
User=palmr
Group=palmr
WorkingDirectory=/opt/palmr/apps/web
ExecStart=/usr/bin/pnpm start
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now palmr-backend palmr-frontend
msg_ok "Created service"
motd_ssh
customize
cleanup_lxc

View File

@@ -15,8 +15,6 @@ update_os
msg_info "Installing Dependencies" msg_info "Installing Dependencies"
$STD apt install -y \ $STD apt install -y \
build-essential \
python3 \
sqlite3 \ sqlite3 \
iptables iptables
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"

View File

@@ -44,8 +44,6 @@ echo passbolt-ce-server passbolt/nginx-domain string $LOCAL_IP | debconf-set-sel
echo passbolt-ce-server passbolt/nginx-certificate-file string /etc/ssl/passbolt/passbolt.crt | debconf-set-selections echo passbolt-ce-server passbolt/nginx-certificate-file string /etc/ssl/passbolt/passbolt.crt | debconf-set-selections
echo passbolt-ce-server passbolt/nginx-certificate-key-file string /etc/ssl/passbolt/passbolt.key | debconf-set-selections echo passbolt-ce-server passbolt/nginx-certificate-key-file string /etc/ssl/passbolt/passbolt.key | debconf-set-selections
$STD apt install -y --no-install-recommends passbolt-ce-server $STD apt install -y --no-install-recommends passbolt-ce-server
sed -i 's/client_max_body_size[[:space:]]\+[0-9]\+M;/client_max_body_size 15M;/' /etc/nginx/sites-enabled/nginx-passbolt.conf
systemctl reload nginx
msg_ok "Setup Passbolt" msg_ok "Setup Passbolt"
motd_ssh motd_ssh

View File

@@ -34,6 +34,7 @@ $STD npm install --no-audit --no-fund --no-save --ignore-scripts
cd /opt/patchmon/frontend cd /opt/patchmon/frontend
cat <<EOF >./.env cat <<EOF >./.env
VITE_API_URL=http://${LOCAL_IP}:3001/api/v1
VITE_APP_NAME=PatchMon VITE_APP_NAME=PatchMon
VITE_APP_VERSION=${VERSION} VITE_APP_VERSION=${VERSION}
EOF EOF

View File

@@ -1,74 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: michelroegl-brunner
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/Dictionarry-Hub/profilarr
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 \
python3-dev \
libffi-dev \
libssl-dev \
git
msg_ok "Installed Dependencies"
PYTHON_VERSION="3.12" setup_uv
NODE_VERSION="22" setup_nodejs
msg_info "Creating directories"
mkdir -p /opt/profilarr \
/config
msg_ok "Created directories"
fetch_and_deploy_gh_release "profilarr" "Dictionarry-Hub/profilarr" "tarball"
msg_info "Installing Python Dependencies"
cd /opt/profilarr/backend
$STD uv venv /opt/profilarr/backend/.venv
sed 's/==/>=/g' requirements.txt >requirements-relaxed.txt
$STD uv pip install --python /opt/profilarr/backend/.venv/bin/python -r requirements-relaxed.txt
rm -f requirements-relaxed.txt
msg_ok "Installed Python Dependencies"
msg_info "Building Frontend"
cd /opt/profilarr/frontend
$STD npm install
$STD npm run build
cp -r dist /opt/profilarr/backend/app/static
msg_ok "Built Frontend"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/profilarr.service
[Unit]
Description=Profilarr - Configuration Management Platform for Radarr/Sonarr
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/profilarr/backend
Environment="PATH=/opt/profilarr/backend/.venv/bin:/usr/local/bin:/usr/bin:/bin"
Environment="PYTHONPATH=/opt/profilarr/backend"
ExecStart=/opt/profilarr/backend/.venv/bin/gunicorn --bind 0.0.0.0:6868 --timeout 600 app.main:create_app()
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now profilarr
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -21,7 +21,7 @@ $STD apt install -y \
expect expect
msg_ok "Dependencies installed." msg_ok "Dependencies installed."
NODE_VERSION="24" setup_nodejs NODE_VERSION=24 setup_nodejs
fetch_and_deploy_gh_release "ProxmoxVE-Local" "community-scripts/ProxmoxVE-Local" "tarball" fetch_and_deploy_gh_release "ProxmoxVE-Local" "community-scripts/ProxmoxVE-Local" "tarball"
msg_info "Installing PVE Scripts local" msg_info "Installing PVE Scripts local"

View File

@@ -69,10 +69,6 @@ cat <<EOF >/opt/Reactive-Resume/.env
NODE_ENV=production NODE_ENV=production
PORT=3000 PORT=3000
# for use behind a reverse proxy, use your FQDN for PUBLIC_URL and STORAGE_URL # for use behind a reverse proxy, use your FQDN for PUBLIC_URL and STORAGE_URL
# To avoid issues when behind a reverse proxy with downloading PDFs, ensure that the
# storage path is accessible via a subdomain (i.e storage.yourapp.xyz) or you set your
# reverse proxy to properly rewrite the subpath (/rxresume) to point to the service
# running on port 9000 (minio).
PUBLIC_URL=http://${LOCAL_IP}:3000 PUBLIC_URL=http://${LOCAL_IP}:3000
STORAGE_URL=http://${LOCAL_IP}:9000/rxresume STORAGE_URL=http://${LOCAL_IP}:9000/rxresume
DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}?schema=public DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}?schema=public

View File

@@ -0,0 +1,41 @@
#!/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://runtipi.io/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_warn "WARNING: This script will run an external installer from a third-party source (https://runtipi.io/)."
msg_warn "The following code is NOT maintained or audited by our repository."
msg_warn "If you have any doubts or concerns, please review the installer code before proceeding:"
msg_custom "${TAB3}${GATEWAY}${BGN}${CL}" "\e[1;34m" "→ https://raw.githubusercontent.com/runtipi/runtipi/master/scripts/install.sh"
echo
read -r -p "${TAB3}Do you want to continue? [y/N]: " CONFIRM
if [[ ! "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then
msg_error "Aborted by user. No changes have been made."
exit 10
fi
msg_info "Installing Runtipi (Patience)"
DOCKER_CONFIG_PATH='/etc/docker/daemon.json'
mkdir -p "$(dirname "$DOCKER_CONFIG_PATH")"
echo -e '{\n "log-driver": "journald"\n}' >"$DOCKER_CONFIG_PATH"
cd /opt
curl -fsSL "https://raw.githubusercontent.com/runtipi/runtipi/master/scripts/install.sh" -o "install.sh"
chmod +x install.sh
$STD ./install.sh
chmod 666 /opt/runtipi/state/settings.json
rm -f /opt/install.sh
msg_ok "Installed Runtipi"
motd_ssh
customize
cleanup_lxc

View File

@@ -17,14 +17,12 @@ msg_info "Installing Dependencies"
$STD apt install -y nginx $STD apt install -y nginx
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
NODE_VERSION="25" setup_nodejs
PG_VERSION="18" setup_postgresql PG_VERSION="18" setup_postgresql
PG_DB_NAME="sparkyfitness" PG_DB_USER="sparky" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db PG_DB_NAME="sparkyfitness" PG_DB_USER="sparky" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db
fetch_and_deploy_gh_release sparkyfitness "CodeWithCJ/SparkyFitness" "tarball" "latest" fetch_and_deploy_gh_release sparkyfitness "CodeWithCJ/SparkyFitness" "tarball" "latest"
PNPM_VERSION="$(jq -r '.packageManager | split("@")[1]' /opt/sparkyfitness/package.json)"
NODE_VERSION="25" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs
msg_info "Configuring Sparky Fitness" msg_info "Configuring Sparky Fitness"
mkdir -p "/etc/sparkyfitness" "/var/lib/sparkyfitness/uploads" "/var/lib/sparkyfitness/backup" "/var/www/sparkyfitness" mkdir -p "/etc/sparkyfitness" "/var/lib/sparkyfitness/uploads" "/var/lib/sparkyfitness/backup" "/var/www/sparkyfitness"
cp "/opt/sparkyfitness/docker/.env.example" "/etc/sparkyfitness/.env" cp "/opt/sparkyfitness/docker/.env.example" "/etc/sparkyfitness/.env"
@@ -52,8 +50,8 @@ msg_ok "Built Backend"
msg_info "Building Frontend (Patience)" msg_info "Building Frontend (Patience)"
cd /opt/sparkyfitness/SparkyFitnessFrontend cd /opt/sparkyfitness/SparkyFitnessFrontend
$STD pnpm install $STD npm install
$STD pnpm run build $STD npm run build
cp -a /opt/sparkyfitness/SparkyFitnessFrontend/dist/. /var/www/sparkyfitness/ cp -a /opt/sparkyfitness/SparkyFitnessFrontend/dist/. /var/www/sparkyfitness/
msg_ok "Built Frontend" msg_ok "Built Frontend"

View File

@@ -1,69 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: pespinel
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://strapi.io/
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 \
python3 \
python3-setuptools \
libvips42
msg_ok "Installed Dependencies"
NODE_VERSION="24" setup_nodejs
msg_info "Installing Strapi (Patience)"
mkdir -p /opt/strapi
cd /opt/strapi
$STD npx --yes create-strapi-app@latest . --quickstart --no-run --skip-cloud
msg_ok "Installed Strapi"
msg_info "Building Strapi"
cd /opt/strapi
export NODE_OPTIONS="--max-old-space-size=3072"
$STD npm run build
msg_ok "Built Strapi"
msg_info "Creating Service"
cat <<EOF >/opt/strapi/.env
HOST=0.0.0.0
PORT=1337
APP_KEYS=$(openssl rand -base64 32)
API_TOKEN_SALT=$(openssl rand -base64 32)
ADMIN_JWT_SECRET=$(openssl rand -base64 32)
TRANSFER_TOKEN_SALT=$(openssl rand -base64 32)
JWT_SECRET=$(openssl rand -base64 32)
EOF
cat <<EOF >/etc/systemd/system/strapi.service
[Unit]
Description=Strapi CMS
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/strapi
EnvironmentFile=/opt/strapi/.env
ExecStart=/usr/bin/npm run start
Restart=on-failure
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now strapi
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -28,15 +28,15 @@ fetch_and_deploy_gh_release "wealthfolio" "afadil/wealthfolio" "tarball"
msg_info "Building Frontend (patience)" msg_info "Building Frontend (patience)"
cd /opt/wealthfolio cd /opt/wealthfolio
export BUILD_TARGET=web
$STD pnpm install --frozen-lockfile $STD pnpm install --frozen-lockfile
$STD pnpm --filter frontend... build $STD pnpm tsc
$STD pnpm vite build
msg_ok "Built Frontend" msg_ok "Built Frontend"
msg_info "Building Backend (patience)" msg_info "Building Backend (patience)"
source ~/.cargo/env cd /opt/wealthfolio/src-server
$STD cargo build --release --manifest-path apps/server/Cargo.toml $STD cargo build --release --manifest-path Cargo.toml
cp /opt/wealthfolio/target/release/wealthfolio-server /usr/local/bin/wealthfolio-server cp /opt/wealthfolio/src-server/target/release/wealthfolio-server /usr/local/bin/wealthfolio-server
chmod +x /usr/local/bin/wealthfolio-server chmod +x /usr/local/bin/wealthfolio-server
msg_ok "Built Backend" msg_ok "Built Backend"
@@ -58,7 +58,7 @@ echo "WF_PASSWORD=${WF_PASSWORD}" >~/wealthfolio.creds
msg_ok "Configured Wealthfolio" msg_ok "Configured Wealthfolio"
msg_info "Cleaning Up" msg_info "Cleaning Up"
rm -rf /opt/wealthfolio/target rm -rf /opt/wealthfolio/src-server/target
rm -rf /root/.cargo/registry rm -rf /root/.cargo/registry
rm -rf /opt/wealthfolio/node_modules rm -rf /opt/wealthfolio/node_modules
msg_ok "Cleaned Up" msg_ok "Cleaned Up"

View File

@@ -164,7 +164,7 @@ server {
location / { location / {
proxy_pass http://127.0.0.1:8000; proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $http_host; proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off; proxy_redirect off;

View File

@@ -28,23 +28,12 @@ setup_deb822_repo \
"stable" \ "stable" \
"main" "main"
$STD apt install -y elasticsearch $STD apt install -y elasticsearch
sed -i 's/^#\{0,2\} *-Xms[0-9]*g.*/-Xms2g/' /etc/elasticsearch/jvm.options sed -i 's/^-Xms.*/-Xms2g/' /etc/elasticsearch/jvm.options
sed -i 's/^#\{0,2\} *-Xmx[0-9]*g.*/-Xmx2g/' /etc/elasticsearch/jvm.options sed -i 's/^-Xmx.*/-Xmx2g/' /etc/elasticsearch/jvm.options
cat <<EOF >>/etc/elasticsearch/elasticsearch.yml
discovery.type: single-node
xpack.security.enabled: false
bootstrap.memory_lock: false
EOF
$STD /usr/share/elasticsearch/bin/elasticsearch-plugin install ingest-attachment -b $STD /usr/share/elasticsearch/bin/elasticsearch-plugin install ingest-attachment -b
systemctl daemon-reload systemctl daemon-reload
systemctl enable -q elasticsearch systemctl enable -q elasticsearch
systemctl restart -q elasticsearch systemctl restart -q elasticsearch
for i in $(seq 1 30); do
if curl -s http://localhost:9200 >/dev/null 2>&1; then
break
fi
sleep 2
done
msg_ok "Setup Elasticsearch" msg_ok "Setup Elasticsearch"
msg_info "Installing Zammad" msg_info "Installing Zammad"

View File

@@ -1,96 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: community-scripts
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/nicotsx/zerobyte
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
echo "davfs2 davfs2/suid_file boolean false" | debconf-set-selections
$STD apt-get install -y \
bzip2 \
fuse3 \
sshfs \
davfs2 \
openssh-client
msg_ok "Installed Dependencies"
fetch_and_deploy_gh_release "restic" "restic/restic" "singlefile" "latest" "/usr/local/bin" "restic_*_linux_amd64.bz2"
mv /usr/local/bin/restic /usr/local/bin/restic.bz2
bzip2 -d /usr/local/bin/restic.bz2
chmod +x /usr/local/bin/restic
fetch_and_deploy_gh_release "rclone" "rclone/rclone" "prebuild" "latest" "/opt/rclone" "rclone-*-linux-amd64.zip"
ln -sf /opt/rclone/rclone /usr/local/bin/rclone
fetch_and_deploy_gh_release "shoutrrr" "nicholas-fedor/shoutrrr" "prebuild" "latest" "/opt/shoutrrr" "shoutrrr_linux_amd64_*.tar.gz"
ln -sf /opt/shoutrrr/shoutrrr /usr/local/bin/shoutrrr
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"
NODE_VERSION="24" setup_nodejs
fetch_and_deploy_gh_release "zerobyte" "nicotsx/zerobyte" "tarball"
msg_info "Building Zerobyte (Patience)"
cd /opt/zerobyte
export VITE_RESTIC_VERSION=$(cat ~/.restic)
export VITE_RCLONE_VERSION=$(cat ~/.rclone)
export VITE_SHOUTRRR_VERSION=$(cat ~/.shoutrrr)
export NODE_OPTIONS="--max-old-space-size=3072"
$STD bun install
$STD node ./node_modules/vite/bin/vite.js build
msg_ok "Built Zerobyte"
msg_info "Configuring Zerobyte"
mkdir -p /var/lib/zerobyte/{data,restic/cache,repositories,volumes}
APP_SECRET=$(openssl rand -hex 32)
cat <<EOF >/opt/zerobyte/.env
BASE_URL=http://${LOCAL_IP}:4096
APP_SECRET=${APP_SECRET}
PORT=4096
ZEROBYTE_DATABASE_URL=/var/lib/zerobyte/data/zerobyte.db
RESTIC_CACHE_DIR=/var/lib/zerobyte/restic/cache
ZEROBYTE_REPOSITORIES_DIR=/var/lib/zerobyte/repositories
ZEROBYTE_VOLUMES_DIR=/var/lib/zerobyte/volumes
MIGRATIONS_PATH=/opt/zerobyte/app/drizzle
NODE_ENV=production
EOF
msg_ok "Configured Zerobyte"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/zerobyte.service
[Unit]
Description=Zerobyte Backup Automation
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/zerobyte
EnvironmentFile=/opt/zerobyte/.env
ExecStart=/usr/local/bin/bun .output/server/index.mjs
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now zerobyte
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -79,7 +79,7 @@ setting_up_container() {
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}" echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
echo -e "${NETWORK}Check Network Settings" echo -e "${NETWORK}Check Network Settings"
exit 121 exit 1
fi fi
msg_ok "Set up Container OS" msg_ok "Set up Container OS"
msg_ok "Network Connected: ${BL}$(ip addr show | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 | tail -n1)${CL}" msg_ok "Network Connected: ${BL}$(ip addr show | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 | tail -n1)${CL}"
@@ -99,7 +99,7 @@ network_check() {
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}" echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
else else
echo -e "${NETWORK}Check Network Settings" echo -e "${NETWORK}Check Network Settings"
exit 122 exit 1
fi fi
fi fi
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }') RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
@@ -119,12 +119,12 @@ update_os() {
local tools_content local tools_content
tools_content=$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) || { tools_content=$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) || {
msg_error "Failed to download tools.func" msg_error "Failed to download tools.func"
exit 115 exit 6
} }
source /dev/stdin <<<"$tools_content" source /dev/stdin <<<"$tools_content"
if ! declare -f fetch_and_deploy_gh_release >/dev/null 2>&1; then if ! declare -f fetch_and_deploy_gh_release >/dev/null 2>&1; then
msg_error "tools.func loaded but incomplete — missing expected functions" msg_error "tools.func loaded but incomplete — missing expected functions"
exit 115 exit 6
fi fi
msg_ok "Updated Container OS" msg_ok "Updated Container OS"
post_progress_to_api post_progress_to_api

View File

@@ -124,7 +124,6 @@ detect_repo_source
# * Generic/Shell errors (1-3, 10, 124-132, 134, 137, 139, 141, 143-146) # * 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) # * 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) # * Package manager errors (APT, DPKG: 100-102, 255)
# * Script Validation & Setup (103-123)
# * BSD sysexits (64-78) # * BSD sysexits (64-78)
# * Systemd/Service errors (150-154) # * Systemd/Service errors (150-154)
# * Python/pip/uv errors (160-162) # * Python/pip/uv errors (160-162)
@@ -132,7 +131,6 @@ detect_repo_source
# * MySQL/MariaDB errors (180-183) # * MySQL/MariaDB errors (180-183)
# * MongoDB errors (190-193) # * MongoDB errors (190-193)
# * Proxmox custom codes (200-231) # * Proxmox custom codes (200-231)
# * Tools & Addon Scripts (232-238)
# * Node.js/npm errors (239, 243, 245-249) # * Node.js/npm errors (239, 243, 245-249)
# - Returns description string for given exit code # - Returns description string for given exit code
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -191,29 +189,6 @@ explain_exit_code() {
101) echo "APT: Configuration error (bad sources.list, malformed config)" ;; 101) echo "APT: Configuration error (bad sources.list, malformed config)" ;;
102) echo "APT: Lock held by another process (dpkg/apt still running)" ;; 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" ;;
106) echo "Validation: Architecture not supported (ARM / PiMox)" ;;
107) echo "Validation: Kernel key parameters unreadable" ;;
108) echo "Validation: Kernel key limits exceeded" ;;
109) echo "Proxmox: No available container ID after max attempts" ;;
110) echo "Proxmox: Failed to apply default.vars" ;;
111) echo "Proxmox: App defaults file not available" ;;
112) echo "Proxmox: Invalid install menu option" ;;
113) echo "LXC: Under-provisioned — user aborted update" ;;
114) echo "LXC: Storage too low — user aborted update" ;;
115) echo "Download: install.func download failed or incomplete" ;;
116) echo "Proxmox: Default bridge vmbr0 not found" ;;
117) echo "LXC: Container did not reach running state" ;;
118) echo "LXC: No IP assigned to container after timeout" ;;
119) echo "Proxmox: No valid storage for rootdir content" ;;
120) echo "Proxmox: No valid storage for vztmpl content" ;;
121) echo "LXC: Container network not ready (no IP after retries)" ;;
122) echo "LXC: No internet connectivity — user declined to continue" ;;
123) echo "LXC: Local IP detection failed" ;;
# --- BSD sysexits.h (64-78) --- # --- BSD sysexits.h (64-78) ---
64) echo "Usage error (wrong arguments)" ;; 64) echo "Usage error (wrong arguments)" ;;
65) echo "Data format error (bad input data)" ;; 65) echo "Data format error (bad input data)" ;;
@@ -301,18 +276,8 @@ explain_exit_code() {
223) echo "Proxmox: Template not available after download" ;; 223) echo "Proxmox: Template not available after download" ;;
224) echo "Proxmox: PBS storage is for backups only" ;; 224) echo "Proxmox: PBS storage is for backups only" ;;
225) echo "Proxmox: No template available for OS/Version" ;; 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" ;; 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" ;;
235) echo "Tools: Backup or restore operation failed" ;;
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" ;;
# --- Node.js / npm / pnpm / yarn (239-249) --- # --- Node.js / npm / pnpm / yarn (239-249) ---
239) echo "npm/Node.js: Unexpected runtime error or dependency failure" ;; 239) echo "npm/Node.js: Unexpected runtime error or dependency failure" ;;
243) echo "Node.js: Out of memory (JavaScript heap out of memory)" ;; 243) echo "Node.js: Out of memory (JavaScript heap out of memory)" ;;
@@ -347,8 +312,7 @@ json_escape() {
s=${s//$'\r'/} s=${s//$'\r'/}
s=${s//$'\t'/\\t} s=${s//$'\t'/\\t}
# Remove any remaining control characters (0x00-0x1F except those already handled) # Remove any remaining control characters (0x00-0x1F except those already handled)
# Also remove DEL (0x7F) and invalid high bytes that break JSON parsers s=$(printf '%s' "$s" | tr -d '\000-\010\013\014\016-\037')
s=$(printf '%s' "$s" | tr -d '\000-\010\013\014\016-\037\177')
printf '%s' "$s" printf '%s' "$s"
} }
@@ -1018,7 +982,7 @@ EOF
fi fi
# All 3 attempts failed — do NOT set POST_UPDATE_DONE=true. # All 3 attempts failed — do NOT set POST_UPDATE_DONE=true.
# This allows the EXIT trap (on_exit in error_handler.func) to retry. # This allows the EXIT trap (api_exit_script) to retry with 3 fresh attempts.
# No infinite loop risk: EXIT trap fires exactly once. # No infinite loop risk: EXIT trap fires exactly once.
} }

View File

@@ -38,18 +38,17 @@
# - Captures app-declared resource defaults (CPU, RAM, Disk) # - Captures app-declared resource defaults (CPU, RAM, Disk)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
variables() { variables() {
NSAPP=$(echo "${APP,,}" | tr -d ' ') # This function sets the NSAPP variable by converting the value of the APP variable to lowercase and removing any spaces. NSAPP=$(echo "${APP,,}" | tr -d ' ') # This function sets the NSAPP variable by converting the value of the APP variable to lowercase and removing any spaces.
var_install="${NSAPP}-install" # sets the var_install variable by appending "-install" to the value of NSAPP. var_install="${NSAPP}-install" # sets the var_install variable by appending "-install" to the value of NSAPP.
INTEGER='^[0-9]+([.][0-9]+)?$' # it defines the INTEGER regular expression pattern. INTEGER='^[0-9]+([.][0-9]+)?$' # it defines the INTEGER regular expression pattern.
PVEHOST_NAME=$(hostname) # gets the Proxmox Hostname and sets it to Uppercase PVEHOST_NAME=$(hostname) # gets the Proxmox Hostname and sets it to Uppercase
DIAGNOSTICS="no" # Safe default: no telemetry until user consents via diagnostics_check() DIAGNOSTICS="no" # Safe default: no telemetry until user consents via diagnostics_check()
METHOD="default" # sets the METHOD variable to "default", used for the API call. METHOD="default" # sets the METHOD variable to "default", used for the API call.
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" # generates a random UUID and sets it to the RANDOM_UUID variable. RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" # generates a random UUID and sets it to the RANDOM_UUID variable.
EXECUTION_ID="${RANDOM_UUID}" # Unique execution ID for telemetry record identification (unique-indexed in PocketBase) EXECUTION_ID="${RANDOM_UUID}" # Unique execution ID for telemetry record identification (unique-indexed in PocketBase)
SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files
BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log" # Host-side container creation log BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log" # Host-side container creation log
# NOTE: combined_log is constructed locally in build_container() and ensure_log_on_host() combined_log="/tmp/install-${SESSION_ID}-combined.log" # Combined log (build + install) for failed installations
# as "/tmp/${NSAPP}-${CTID}-${SESSION_ID}.log" (requires CTID, not available here)
CTTYPE="${CTTYPE:-${CT_TYPE:-1}}" CTTYPE="${CTTYPE:-${CT_TYPE:-1}}"
# Parse dev_mode early # Parse dev_mode early
@@ -118,8 +117,8 @@ maxkeys_check() {
# Exit if kernel parameters are unavailable # Exit if kernel parameters are unavailable
if [[ "$per_user_maxkeys" -eq 0 || "$per_user_maxbytes" -eq 0 ]]; then if [[ "$per_user_maxkeys" -eq 0 || "$per_user_maxbytes" -eq 0 ]]; then
msg_error "Unable to read kernel key parameters. Ensure proper permissions." echo -e "${CROSS}${RD} Error: Unable to read kernel parameters. Ensure proper permissions.${CL}"
exit 107 exit 1
fi fi
# Fetch key usage for user ID 100000 (typical for containers) # Fetch key usage for user ID 100000 (typical for containers)
@@ -135,20 +134,20 @@ maxkeys_check() {
# Check if key or byte usage is near limits # Check if key or byte usage is near limits
failure=0 failure=0
if [[ "$used_lxc_keys" -gt "$threshold_keys" ]]; then if [[ "$used_lxc_keys" -gt "$threshold_keys" ]]; then
msg_warn "Key usage is near the limit (${used_lxc_keys}/${per_user_maxkeys})" echo -e "${CROSS}${RD} Warning: Key usage is near the limit (${used_lxc_keys}/${per_user_maxkeys}).${CL}"
echo -e "${INFO} Suggested action: Set ${GN}kernel.keys.maxkeys=${new_limit_keys}${CL} in ${BOLD}/etc/sysctl.d/98-community-scripts.conf${CL}." echo -e "${INFO} Suggested action: Set ${GN}kernel.keys.maxkeys=${new_limit_keys}${CL} in ${BOLD}/etc/sysctl.d/98-community-scripts.conf${CL}."
failure=1 failure=1
fi fi
if [[ "$used_lxc_bytes" -gt "$threshold_bytes" ]]; then if [[ "$used_lxc_bytes" -gt "$threshold_bytes" ]]; then
msg_warn "Key byte usage is near the limit (${used_lxc_bytes}/${per_user_maxbytes})" echo -e "${CROSS}${RD} Warning: Key byte usage is near the limit (${used_lxc_bytes}/${per_user_maxbytes}).${CL}"
echo -e "${INFO} Suggested action: Set ${GN}kernel.keys.maxbytes=${new_limit_bytes}${CL} in ${BOLD}/etc/sysctl.d/98-community-scripts.conf${CL}." echo -e "${INFO} Suggested action: Set ${GN}kernel.keys.maxbytes=${new_limit_bytes}${CL} in ${BOLD}/etc/sysctl.d/98-community-scripts.conf${CL}."
failure=1 failure=1
fi fi
# Provide next steps if issues are detected # Provide next steps if issues are detected
if [[ "$failure" -eq 1 ]]; then if [[ "$failure" -eq 1 ]]; then
msg_error "Kernel key limits exceeded - see suggestions above" echo -e "${INFO} To apply changes, run: ${BOLD}service procps force-reload${CL}"
exit 108 exit 1
fi fi
# Silent success - only show errors if they exist # Silent success - only show errors if they exist
@@ -355,7 +354,7 @@ get_valid_container_id() {
attempts=$((attempts + 1)) attempts=$((attempts + 1))
if [[ $attempts -ge $max_attempts ]]; then if [[ $attempts -ge $max_attempts ]]; then
msg_error "Could not find available container ID after $max_attempts attempts" msg_error "Could not find available container ID after $max_attempts attempts"
exit 109 exit 1
fi fi
done done
@@ -693,7 +692,7 @@ find_host_ssh_keys() {
/^[[:space:]]*#/ {next} /^[[:space:]]*#/ {next}
/^[[:space:]]*$/ {next} /^[[:space:]]*$/ {next}
{print} {print}
' | grep -E -c "$re" || true) ' | grep -E -c '"$re"' || true)
if ((c > 0)); then if ((c > 0)); then
files+=("$f") files+=("$f")
@@ -1851,7 +1850,7 @@ advanced_settings() {
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
# STEP 2: Root Password # STEP 2: Root Password
# ════════════════════════════════════════════════════════════════════════<EFBFBD><EFBFBD><EFBFBD>══ # ══════════════════════════════════════════════════════════════════════════
2) 2)
if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "ROOT PASSWORD" \ --title "ROOT PASSWORD" \
@@ -2034,8 +2033,7 @@ advanced_settings() {
((STEP++)) ((STEP++))
else else
whiptail --msgbox "Default bridge 'vmbr0' not found!\n\nPlease configure a network bridge in Proxmox first." 10 58 whiptail --msgbox "Default bridge 'vmbr0' not found!\n\nPlease configure a network bridge in Proxmox first." 10 58
msg_error "Default bridge 'vmbr0' not found" exit 1
exit 116
fi fi
else else
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
@@ -3023,7 +3021,7 @@ install_script() {
3 | mydefaults | MYDEFAULTS | userdefaults | USERDEFAULTS) 3 | mydefaults | MYDEFAULTS | userdefaults | USERDEFAULTS)
default_var_settings || { default_var_settings || {
msg_error "Failed to apply default.vars" msg_error "Failed to apply default.vars"
exit 110 exit 1
} }
defaults_target="/usr/local/community-scripts/default.vars" defaults_target="/usr/local/community-scripts/default.vars"
break break
@@ -3040,7 +3038,7 @@ install_script() {
break break
else else
msg_error "No App Defaults available for ${APP}" msg_error "No App Defaults available for ${APP}"
exit 111 exit 1
fi fi
;; ;;
"$SETTINGS_OPTION" | settings | SETTINGS) "$SETTINGS_OPTION" | settings | SETTINGS)
@@ -3050,8 +3048,8 @@ install_script() {
CHOICE="" CHOICE=""
;; ;;
*) *)
msg_error "Invalid option: $CHOICE" echo -e "${CROSS}${RD}Invalid option: $CHOICE${CL}"
exit 112 exit 1
;; ;;
esac esac
done done
@@ -3129,13 +3127,13 @@ check_container_resources() {
current_cpu=$(nproc) current_cpu=$(nproc)
if [[ "$current_ram" -lt "$var_ram" ]] || [[ "$current_cpu" -lt "$var_cpu" ]]; then if [[ "$current_ram" -lt "$var_ram" ]] || [[ "$current_cpu" -lt "$var_cpu" ]]; then
msg_warn "Under-provisioned: Required ${var_cpu} CPU/${var_ram}MB RAM, Current ${current_cpu} CPU/${current_ram}MB RAM" echo -e "\n${INFO}${HOLD} ${GN}Required: ${var_cpu} CPU, ${var_ram}MB RAM ${CL}| ${RD}Current: ${current_cpu} CPU, ${current_ram}MB RAM${CL}"
echo -e "${YWB}Please ensure that the ${APP} LXC is configured with at least ${var_cpu} vCPU and ${var_ram} MB RAM for the build process.${CL}\n" echo -e "${YWB}Please ensure that the ${APP} LXC is configured with at least ${var_cpu} vCPU and ${var_ram} MB RAM for the build process.${CL}\n"
echo -ne "${INFO}${HOLD} May cause data loss! ${INFO} Continue update with under-provisioned LXC? <yes/No> " echo -ne "${INFO}${HOLD} May cause data loss! ${INFO} Continue update with under-provisioned LXC? <yes/No> "
read -r prompt </dev/tty read -r prompt
if [[ ! ${prompt,,} =~ ^(yes)$ ]]; then if [[ ! ${prompt,,} =~ ^(yes)$ ]]; then
msg_error "Aborted: under-provisioned LXC (${current_cpu} CPU/${current_ram}MB RAM < ${var_cpu} CPU/${var_ram}MB RAM)" echo -e "${CROSS}${HOLD} ${YWB}Exiting based on user input.${CL}"
exit 113 exit 1
fi fi
else else
echo -e "" echo -e ""
@@ -3153,12 +3151,12 @@ check_container_storage() {
local used_size=$(df /boot --output=used | tail -n 1) local used_size=$(df /boot --output=used | tail -n 1)
usage=$((100 * used_size / total_size)) usage=$((100 * used_size / total_size))
if ((usage > 80)); then if ((usage > 80)); then
msg_warn "Storage is dangerously low (${usage}% used on /boot)" echo -e "${INFO}${HOLD} ${YWB}Warning: Storage is dangerously low (${usage}%).${CL}"
echo -ne "Continue anyway? <y/N> " echo -ne "Continue anyway? <y/N> "
read -r prompt </dev/tty read -r prompt
if [[ ! ${prompt,,} =~ ^(y|yes)$ ]]; then if [[ ! ${prompt,,} =~ ^(y|yes)$ ]]; then
msg_error "Aborted: storage too low (${usage}% used)" echo -e "${CROSS}${HOLD}${YWB}Exiting based on user input.${CL}"
exit 114 exit 1
fi fi
fi fi
} }
@@ -3446,7 +3444,7 @@ start() {
3) 3)
clear clear
exit_script exit_script
exit 0 exit
;; ;;
esac esac
ensure_profile_loaded ensure_profile_loaded
@@ -3547,16 +3545,10 @@ build_container() {
# Build PCT_OPTIONS as string for export # Build PCT_OPTIONS as string for export
TEMP_DIR=$(mktemp -d) TEMP_DIR=$(mktemp -d)
pushd "$TEMP_DIR" >/dev/null pushd "$TEMP_DIR" >/dev/null
local _func_url
if [ "$var_os" == "alpine" ]; then if [ "$var_os" == "alpine" ]; then
_func_url="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/alpine-install.func" export FUNCTIONS_FILE_PATH="$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/alpine-install.func)"
else else
_func_url="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/install.func" export FUNCTIONS_FILE_PATH="$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/install.func)"
fi
export FUNCTIONS_FILE_PATH="$(curl -fsSL "$_func_url")"
if [[ -z "$FUNCTIONS_FILE_PATH" || ${#FUNCTIONS_FILE_PATH} -lt 100 ]]; then
msg_error "Failed to download install functions from: $_func_url"
exit 115
fi fi
# Core exports for install.func # Core exports for install.func
@@ -3707,18 +3699,10 @@ $PCT_OPTIONS_STRING"
NVIDIA_DEVICES=() NVIDIA_DEVICES=()
# Store PCI info to avoid multiple calls # Store PCI info to avoid multiple calls
# grep returns exit 1 when no match — use || true to prevent ERR trap local pci_vga_info=$(lspci -nn 2>/dev/null | grep -E "VGA|Display|3D")
local pci_vga_info
pci_vga_info=$(lspci -nn 2>/dev/null | grep -E "VGA|Display|3D" || true)
# No GPU-related PCI devices at all? Skip silently.
if [[ -z "$pci_vga_info" ]]; then
msg_debug "No VGA/Display/3D PCI devices found"
return 0
fi
# Check for Intel GPU - look for Intel vendor ID [8086] # Check for Intel GPU - look for Intel vendor ID [8086]
if grep -q "\[8086:" <<<"$pci_vga_info"; then if echo "$pci_vga_info" | grep -q "\[8086:"; then
msg_custom "🎮" "${BL}" "Detected Intel GPU" msg_custom "🎮" "${BL}" "Detected Intel GPU"
if [[ -d /dev/dri ]]; then if [[ -d /dev/dri ]]; then
for d in /dev/dri/renderD* /dev/dri/card*; do for d in /dev/dri/renderD* /dev/dri/card*; do
@@ -3728,7 +3712,7 @@ $PCT_OPTIONS_STRING"
fi fi
# Check for AMD GPU - look for AMD vendor IDs [1002] (AMD/ATI) or [1022] (AMD) # Check for AMD GPU - look for AMD vendor IDs [1002] (AMD/ATI) or [1022] (AMD)
if grep -qE "\[1002:|\[1022:" <<<"$pci_vga_info"; then if echo "$pci_vga_info" | grep -qE "\[1002:|\[1022:"; then
msg_custom "🎮" "${RD}" "Detected AMD GPU" msg_custom "🎮" "${RD}" "Detected AMD GPU"
if [[ -d /dev/dri ]]; then if [[ -d /dev/dri ]]; then
# Only add if not already claimed by Intel # Only add if not already claimed by Intel
@@ -3741,7 +3725,7 @@ $PCT_OPTIONS_STRING"
fi fi
# Check for NVIDIA GPU - look for NVIDIA vendor ID [10de] # Check for NVIDIA GPU - look for NVIDIA vendor ID [10de]
if grep -q "\[10de:" <<<"$pci_vga_info"; then if echo "$pci_vga_info" | grep -q "\[10de:"; then
msg_custom "🎮" "${GN}" "Detected NVIDIA GPU" msg_custom "🎮" "${GN}" "Detected NVIDIA GPU"
# Simple passthrough - just bind /dev/nvidia* devices if they exist # Simple passthrough - just bind /dev/nvidia* devices if they exist
@@ -3842,7 +3826,7 @@ EOF
for gpu in "${available_gpus[@]}"; do for gpu in "${available_gpus[@]}"; do
echo " - $gpu" echo " - $gpu"
done done
read -rp "Which GPU type to passthrough? (${available_gpus[*]}): " selected_gpu </dev/tty read -rp "Which GPU type to passthrough? (${available_gpus[*]}): " selected_gpu
selected_gpu="${selected_gpu^^}" selected_gpu="${selected_gpu^^}"
# Validate selection # Validate selection
@@ -3935,10 +3919,8 @@ EOF
fi fi
sleep 1 sleep 1
if [ "$i" -eq 10 ]; then if [ "$i" -eq 10 ]; then
local ct_status msg_error "LXC Container did not reach running state"
ct_status=$(pct status "$CTID" 2>/dev/null || echo "unknown") exit 1
msg_error "LXC Container did not reach running state (status: ${ct_status})"
exit 117
fi fi
done done
@@ -3961,13 +3943,13 @@ EOF
if [ -z "$ip_in_lxc" ]; then if [ -z "$ip_in_lxc" ]; then
msg_error "No IP assigned to CT $CTID after 20s" msg_error "No IP assigned to CT $CTID after 20s"
msg_custom "🔧" "${YW}" "Troubleshooting:" echo -e "${YW}Troubleshooting:${CL}"
echo " • Verify bridge ${BRG} exists and has connectivity" echo " • Verify bridge ${BRG} exists and has connectivity"
echo " • Check if DHCP server is reachable (if using DHCP)" echo " • Check if DHCP server is reachable (if using DHCP)"
echo " • Verify static IP configuration (if using static IP)" echo " • Verify static IP configuration (if using static IP)"
echo " • Check Proxmox firewall rules" echo " • Check Proxmox firewall rules"
echo " • If using Tailscale: Disable MagicDNS temporarily" echo " • If using Tailscale: Disable MagicDNS temporarily"
exit 118 exit 1
fi fi
# Verify basic connectivity (ping test) # Verify basic connectivity (ping test)
@@ -3983,7 +3965,8 @@ EOF
done done
if [ "$ping_success" = false ]; then if [ "$ping_success" = false ]; then
msg_warn "Network configured (IP: $ip_in_lxc) but connectivity test failed - installation will continue" msg_warn "Network configured (IP: $ip_in_lxc) but connectivity test failed"
echo -e "${YW}Container may have limited internet access. Installation will continue...${CL}"
else else
msg_ok "Network in LXC is reachable (ping)" msg_ok "Network in LXC is reachable (ping)"
fi fi
@@ -4020,16 +4003,6 @@ EOF
# install_gpu_userland "NVIDIA" # install_gpu_userland "NVIDIA"
# fi # fi
# Disable error trap for entire customization & install phase.
# All errors are handled explicitly — recovery menu shown on failure.
# Without this, customization errors (e.g. container stopped during base package
# install) would trigger error_handler() with a simple "Remove broken container?"
# prompt instead of the full recovery menu with retry/repair options.
set +Eeuo pipefail
trap - ERR
local install_exit_code=0
# Continue with standard container setup # Continue with standard container setup
if [ "$var_os" == "alpine" ]; then if [ "$var_os" == "alpine" ]; then
sleep 3 sleep 3
@@ -4037,10 +4010,7 @@ EOF
http://dl-cdn.alpinelinux.org/alpine/latest-stable/main http://dl-cdn.alpinelinux.org/alpine/latest-stable/main
http://dl-cdn.alpinelinux.org/alpine/latest-stable/community http://dl-cdn.alpinelinux.org/alpine/latest-stable/community
EOF' EOF'
pct exec "$CTID" -- ash -c "apk add bash newt curl openssh nano mc ncurses jq" >>"$BUILD_LOG" 2>&1 || { pct exec "$CTID" -- ash -c "apk add bash newt curl openssh nano mc ncurses jq >/dev/null"
msg_error "Failed to install base packages in Alpine container"
install_exit_code=1
}
else else
sleep 3 sleep 3
LANG=${LANG:-en_US.UTF-8} LANG=${LANG:-en_US.UTF-8}
@@ -4063,69 +4033,70 @@ EOF'
msg_warn "Skipping timezone setup zone '$tz' not found in container" msg_warn "Skipping timezone setup zone '$tz' not found in container"
fi fi
pct exec "$CTID" -- bash -c "apt-get update 2>&1 && apt-get install -y sudo curl mc gnupg2 jq 2>&1" >>"$BUILD_LOG" 2>&1 || { pct exec "$CTID" -- bash -c "apt-get update >/dev/null && apt-get install -y sudo curl mc gnupg2 jq >/dev/null" || {
msg_error "apt-get base packages installation failed" msg_error "apt-get base packages installation failed"
install_exit_code=1 exit 1
} }
fi fi
# Only continue with installation if customization succeeded msg_ok "Customized LXC Container"
if [[ $install_exit_code -eq 0 ]]; then
msg_ok "Customized LXC Container"
# Optional DNS override for retry scenarios (inside LXC, never on host) # Optional DNS override for retry scenarios (inside LXC, never on host)
if [[ "${DNS_RETRY_OVERRIDE:-false}" == "true" ]]; then if [[ "${DNS_RETRY_OVERRIDE:-false}" == "true" ]]; then
msg_info "Applying DNS retry override in LXC (8.8.8.8, 1.1.1.1)" msg_info "Applying DNS retry override in LXC (8.8.8.8, 1.1.1.1)"
pct exec "$CTID" -- bash -c "printf 'nameserver 8.8.8.8\nnameserver 1.1.1.1\n' >/etc/resolv.conf" >/dev/null 2>&1 || true pct exec "$CTID" -- bash -c "printf 'nameserver 8.8.8.8\nnameserver 1.1.1.1\n' >/etc/resolv.conf" >/dev/null 2>&1 || true
msg_ok "DNS override applied in LXC" msg_ok "DNS override applied in LXC"
fi
# Install SSH keys
install_ssh_keys_into_ct
# Start timer for duration tracking
start_install_timer
# Run application installer
# Disable error trap - container errors are handled internally via flag file
set +Eeuo pipefail # Disable ALL error handling temporarily
trap - ERR # Remove ERR trap completely
# Signal handlers use this flag to stop the container on abort (SIGHUP/SIGINT/SIGTERM)
# Without this, SSH disconnects leave the container running as an orphan process
# that sends "configuring" status AFTER the host already reported "failed"
export CONTAINER_INSTALLING=true
# Capture lxc-attach terminal output to host-side log via tee.
# This is the ONLY reliable way to get install output when:
# - install.func fails to load (DNS error) → no container-side logging
# - install script crashes before logging starts
# - $STD/silent() not used for some commands
# PIPESTATUS[0] gets the real exit code from lxc-attach (not from tee).
local _LXC_CAPTURE_LOG="/tmp/.install-capture-${SESSION_ID}.log"
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh)" 2>&1 | tee "$_LXC_CAPTURE_LOG"
local lxc_exit=${PIPESTATUS[0]}
unset CONTAINER_INSTALLING
# Keep error handling DISABLED during failure detection and recovery
# Re-enabling it here would cause any pct exec/pull failure to trigger
# error_handler() on the host, bypassing the recovery menu entirely
# Check for error flag file in container (more reliable than lxc-attach exit code)
local install_exit_code=0
if [[ -n "${SESSION_ID:-}" ]]; then
local error_flag="/root/.install-${SESSION_ID}.failed"
if pct exec "$CTID" -- test -f "$error_flag" 2>/dev/null; then
install_exit_code=$(pct exec "$CTID" -- cat "$error_flag" 2>/dev/null || echo "1")
pct exec "$CTID" -- rm -f "$error_flag" 2>/dev/null || true
fi fi
fi
# Install SSH keys # Fallback to lxc-attach exit code if no flag file
install_ssh_keys_into_ct if [[ $install_exit_code -eq 0 && $lxc_exit -ne 0 ]]; then
install_exit_code=$lxc_exit
fi
# Start timer for duration tracking # Installation failed?
start_install_timer
# Run application installer
# Error handling already disabled above (before customization phase)
# Signal handlers use this flag to stop the container on abort (SIGHUP/SIGINT/SIGTERM)
# Without this, SSH disconnects leave the container running as an orphan process
# that sends "configuring" status AFTER the host already reported "failed"
export CONTAINER_INSTALLING=true
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh)"
local lxc_exit=$?
unset CONTAINER_INSTALLING
# Keep error handling DISABLED during failure detection and recovery
# Re-enabling it here would cause any pct exec/pull failure to trigger
# error_handler() on the host, bypassing the recovery menu entirely
# Check for error flag file in container (more reliable than lxc-attach exit code)
if [[ -n "${SESSION_ID:-}" ]]; then
local error_flag="/root/.install-${SESSION_ID}.failed"
if pct exec "$CTID" -- test -f "$error_flag" 2>/dev/null; then
install_exit_code=$(pct exec "$CTID" -- cat "$error_flag" 2>/dev/null || echo "1")
pct exec "$CTID" -- rm -f "$error_flag" 2>/dev/null || true
fi
fi
# Fallback to lxc-attach exit code if no flag file
if [[ $install_exit_code -eq 0 && ${lxc_exit:-0} -ne 0 ]]; then
install_exit_code=${lxc_exit:-0}
fi
fi # end: if [[ $install_exit_code -eq 0 ]] (customization succeeded)
# Installation or customization failed?
if [[ $install_exit_code -ne 0 ]]; then if [[ $install_exit_code -ne 0 ]]; then
# Prevent job-control signals from suspending the script during recovery.
# In non-interactive shells (bash -c), background processes (spinner) can
# trigger terminal-related signals that stop the entire process group.
# TSTP = Ctrl+Z, TTIN = bg read from tty, TTOU = bg write to tty (tostop)
trap '' TSTP TTIN TTOU
msg_error "Installation failed in container ${CTID} (exit code: ${install_exit_code})" msg_error "Installation failed in container ${CTID} (exit code: ${install_exit_code})"
# Copy install log from container BEFORE API call so get_error_text() can read it # Copy install log from container BEFORE API call so get_error_text() can read it
@@ -4157,9 +4128,19 @@ EOF'
build_log_copied=true build_log_copied=true
fi fi
# Copy and append INSTALL_LOG from container # Copy and append INSTALL_LOG from container (with timeout to prevent hangs)
local temp_install_log="/tmp/.install-temp-${SESSION_ID}.log" local temp_install_log="/tmp/.install-temp-${SESSION_ID}.log"
if pct pull "$CTID" "/root/.install-${SESSION_ID}.log" "$temp_install_log" 2>/dev/null; then local container_log_ok=false
if timeout 8 pct pull "$CTID" "/root/.install-${SESSION_ID}.log" "$temp_install_log" 2>/dev/null; then
# Only use container log if it has meaningful content (>100 bytes)
if [[ -s "$temp_install_log" ]] && [[ $(stat -c%s "$temp_install_log" 2>/dev/null || echo 0) -gt 100 ]]; then
container_log_ok=true
fi
fi
# PHASE 2: Use container-side log if available, otherwise use host-captured tee output
local _LXC_CAPTURE_LOG="/tmp/.install-capture-${SESSION_ID}.log"
if [[ "$container_log_ok" == true ]]; then
{ {
echo "================================================================================" echo "================================================================================"
echo "PHASE 2: APPLICATION INSTALLATION (Container)" echo "PHASE 2: APPLICATION INSTALLATION (Container)"
@@ -4167,27 +4148,31 @@ EOF'
cat "$temp_install_log" cat "$temp_install_log"
echo "" echo ""
} >>"$combined_log" } >>"$combined_log"
rm -f "$temp_install_log"
install_log_copied=true install_log_copied=true
elif [[ -s "$_LXC_CAPTURE_LOG" ]]; then
# Fallback: host-captured terminal output from lxc-attach
# This captures everything the user saw, including errors when install.func
# failed to load (DNS issues, etc.) and no container-side logging was set up.
{
echo "================================================================================"
echo "PHASE 2: APPLICATION INSTALLATION (Container - captured from terminal)"
echo "================================================================================"
# Strip ANSI escape codes from terminal capture
sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' "$_LXC_CAPTURE_LOG" | sed 's/\r$//'
echo ""
} >>"$combined_log"
install_log_copied=true
fi
rm -f "$temp_install_log"
if [[ "$install_log_copied" == true ]]; then
# Point INSTALL_LOG to combined log so get_full_log() finds it # Point INSTALL_LOG to combined log so get_full_log() finds it
INSTALL_LOG="$combined_log" INSTALL_LOG="$combined_log"
fi fi
fi fi
# Report failure to telemetry API (now with log available on host) # Report failure to telemetry API (now with log available on host)
# NOTE: Do NOT use msg_info/spinner here — the background spinner process
# causes SIGTSTP in non-interactive shells (bash -c "$(curl ...)"), which
# stops the entire process group and prevents the recovery dialog from appearing.
$STD echo -e "${TAB}⏳ Reporting failure to telemetry..."
post_update_to_api "failed" "$install_exit_code" post_update_to_api "failed" "$install_exit_code"
$STD echo -e "${TAB}${CM:-} Failure reported"
# Defense-in-depth: Ensure error handling stays disabled during recovery.
# Some functions (e.g. silent/$STD) unconditionally re-enable set -Eeuo pipefail
# and trap 'error_handler' ERR. If any code path above called such a function,
# the grep/sed pipelines below would trigger error_handler on non-match (exit 1).
set +Eeuo pipefail
trap - ERR
# Show combined log location # Show combined log location
if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then
@@ -4204,7 +4189,7 @@ EOF'
pct enter "$CTID" pct enter "$CTID"
echo "" echo ""
echo -en "${YW}Container ${CTID} still running. Remove now? (y/N): ${CL}" echo -en "${YW}Container ${CTID} still running. Remove now? (y/N): ${CL}"
if read -r response </dev/tty && [[ "$response" =~ ^[Yy]$ ]]; then if read -r response && [[ "$response" =~ ^[Yy]$ ]]; then
pct stop "$CTID" &>/dev/null || true pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true pct destroy "$CTID" &>/dev/null || true
msg_ok "Container ${CTID} removed" msg_ok "Container ${CTID} removed"
@@ -4302,7 +4287,7 @@ EOF'
if [[ "$is_cmd_not_found" == true ]]; then if [[ "$is_cmd_not_found" == true ]]; then
local missing_cmd="" local missing_cmd=""
if [[ -f "$combined_log" ]]; then if [[ -f "$combined_log" ]]; then
missing_cmd=$(grep -oiE '[a-zA-Z0-9_.-]+: command not found' "$combined_log" 2>/dev/null | tail -1 | sed 's/: command not found//') || true missing_cmd=$(grep -oiE '[a-zA-Z0-9_.-]+: command not found' "$combined_log" | tail -1 | sed 's/: command not found//')
fi fi
if [[ -n "$missing_cmd" ]]; then if [[ -n "$missing_cmd" ]]; then
echo -e "${TAB}${INFO} Missing command: ${GN}${missing_cmd}${CL}" echo -e "${TAB}${INFO} Missing command: ${GN}${missing_cmd}${CL}"
@@ -4354,7 +4339,6 @@ EOF'
echo "" echo ""
echo -en "${YW}Select option [1-${max_option}] (default: 1, auto-remove in 60s): ${CL}" echo -en "${YW}Select option [1-${max_option}] (default: 1, auto-remove in 60s): ${CL}"
local response=""
if read -t 60 -r response; then if read -t 60 -r response; then
case "${response:-1}" in case "${response:-1}" in
1) 1)
@@ -4442,8 +4426,9 @@ EOF'
# Re-run install script in existing container (don't destroy/recreate) # Re-run install script in existing container (don't destroy/recreate)
set +Eeuo pipefail set +Eeuo pipefail
trap - ERR trap - ERR
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh)" local _LXC_CAPTURE_LOG="/tmp/.install-capture-${SESSION_ID}.log"
local apt_retry_exit=$? lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh)" 2>&1 | tee "$_LXC_CAPTURE_LOG"
local apt_retry_exit=${PIPESTATUS[0]}
set -Eeuo pipefail set -Eeuo pipefail
trap 'error_handler' ERR trap 'error_handler' ERR
@@ -4544,15 +4529,14 @@ EOF'
# Force one final status update attempt after cleanup # Force one final status update attempt after cleanup
# This ensures status is updated even if the first attempt failed (e.g., HTTP 400) # This ensures status is updated even if the first attempt failed (e.g., HTTP 400)
$STD echo -e "${TAB}⏳ Finalizing telemetry report..."
post_update_to_api "failed" "$install_exit_code" "force" post_update_to_api "failed" "$install_exit_code" "force"
$STD echo -e "${TAB}${CM:-} Telemetry finalized"
# Restore default job-control signal handling before exit
trap - TSTP TTIN TTOU
exit $install_exit_code exit $install_exit_code
fi fi
# Clean up host-side capture log (not needed on success, already in combined_log on failure)
rm -f "/tmp/.install-capture-${SESSION_ID}.log" 2>/dev/null
# Re-enable error handling after successful install or recovery menu completion # Re-enable error handling after successful install or recovery menu completion
set -Eeuo pipefail set -Eeuo pipefail
trap 'error_handler' ERR trap 'error_handler' ERR
@@ -4568,7 +4552,7 @@ destroy_lxc() {
trap 'echo; msg_error "Aborted by user (SIGINT/SIGQUIT)"; return 130' INT QUIT trap 'echo; msg_error "Aborted by user (SIGINT/SIGQUIT)"; return 130' INT QUIT
local prompt local prompt
if ! read -rp "Remove this Container? <y/N> " prompt </dev/tty; then if ! read -rp "Remove this Container? <y/N> " prompt; then
# read returns non-zero on Ctrl-D/ESC # read returns non-zero on Ctrl-D/ESC
msg_error "Aborted input (Ctrl-D/ESC)" msg_error "Aborted input (Ctrl-D/ESC)"
return 130 return 130
@@ -4901,16 +4885,16 @@ create_lxc_container() {
return 0 return 0
fi fi
msg_info "An update for the Proxmox LXC stack is available" echo
echo "An update for the Proxmox LXC stack is available:"
echo " pve-container: installed=${_pvec_i:-n/a} candidate=${_pvec_c:-n/a}" echo " pve-container: installed=${_pvec_i:-n/a} candidate=${_pvec_c:-n/a}"
echo " lxc-pve : installed=${_lxcp_i:-n/a} candidate=${_lxcp_c:-n/a}" echo " lxc-pve : installed=${_lxcp_i:-n/a} candidate=${_lxcp_c:-n/a}"
echo echo
read -rp "Do you want to upgrade now? [y/N] " _ans </dev/tty read -rp "Do you want to upgrade now? [y/N] " _ans
case "${_ans,,}" in case "${_ans,,}" in
y | yes) y | yes)
msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)" msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)"
apt_update_safe if $STD apt-get update && $STD apt-get install -y --only-upgrade pve-container lxc-pve; then
if $STD apt-get install -y --only-upgrade pve-container lxc-pve; then
msg_ok "LXC stack upgraded." msg_ok "LXC stack upgraded."
if [[ "$do_retry" == "yes" ]]; then if [[ "$do_retry" == "yes" ]]; then
msg_info "Retrying container creation after upgrade" msg_info "Retrying container creation after upgrade"
@@ -4954,6 +4938,7 @@ create_lxc_container() {
exit 205 exit 205
} }
if qm status "$CTID" &>/dev/null || pct status "$CTID" &>/dev/null; then if qm status "$CTID" &>/dev/null || pct status "$CTID" &>/dev/null; then
echo -e "ID '$CTID' is already in use."
unset CTID unset CTID
msg_error "Cannot use ID that is already in use." msg_error "Cannot use ID that is already in use."
exit 206 exit 206
@@ -4968,11 +4953,11 @@ create_lxc_container() {
# Storage capability check # Storage capability check
check_storage_support "rootdir" || { check_storage_support "rootdir" || {
msg_error "No valid storage found for 'rootdir' [Container]" msg_error "No valid storage found for 'rootdir' [Container]"
exit 119 exit 1
} }
check_storage_support "vztmpl" || { check_storage_support "vztmpl" || {
msg_error "No valid storage found for 'vztmpl' [Template]" msg_error "No valid storage found for 'vztmpl' [Template]"
exit 120 exit 1
} }
# Template storage selection # Template storage selection
@@ -5011,40 +4996,17 @@ create_lxc_container() {
msg_info "Validating storage '$CONTAINER_STORAGE'" msg_info "Validating storage '$CONTAINER_STORAGE'"
STORAGE_TYPE=$(grep -E "^[^:]+: $CONTAINER_STORAGE$" /etc/pve/storage.cfg | cut -d: -f1 | head -1) STORAGE_TYPE=$(grep -E "^[^:]+: $CONTAINER_STORAGE$" /etc/pve/storage.cfg | cut -d: -f1 | head -1)
if [[ -z "$STORAGE_TYPE" ]]; then
msg_error "Storage '$CONTAINER_STORAGE' not found in /etc/pve/storage.cfg"
exit 213
fi
case "$STORAGE_TYPE" in case "$STORAGE_TYPE" in
iscsidirect) iscsidirect) exit 212 ;;
msg_error "Storage '$CONTAINER_STORAGE' uses iSCSI-direct which does not support container rootfs." iscsi | zfs) exit 213 ;;
exit 212 cephfs) exit 219 ;;
;; pbs) exit 224 ;;
iscsi | zfs)
msg_error "Storage '$CONTAINER_STORAGE' ($STORAGE_TYPE) does not support container rootdir content."
exit 213
;;
cephfs)
msg_error "Storage '$CONTAINER_STORAGE' uses CephFS which is not supported for LXC rootfs."
exit 219
;;
pbs)
msg_error "Storage '$CONTAINER_STORAGE' is a Proxmox Backup Server — cannot be used for containers."
exit 224
;;
linstor | rbd | nfs | cifs) linstor | rbd | nfs | cifs)
if ! pvesm status -storage "$CONTAINER_STORAGE" &>/dev/null; then pvesm status -storage "$CONTAINER_STORAGE" &>/dev/null || exit 217
msg_error "Storage '$CONTAINER_STORAGE' ($STORAGE_TYPE) is not accessible or inactive."
exit 217
fi
;; ;;
esac esac
if ! pvesm status -content rootdir 2>/dev/null | awk 'NR>1{print $1}' | grep -qx "$CONTAINER_STORAGE"; then pvesm status -content rootdir 2>/dev/null | awk 'NR>1{print $1}' | grep -qx "$CONTAINER_STORAGE" || exit 213
msg_error "Storage '$CONTAINER_STORAGE' ($STORAGE_TYPE) does not support 'rootdir' content."
exit 213
fi
msg_ok "Storage '$CONTAINER_STORAGE' ($STORAGE_TYPE) validated" msg_ok "Storage '$CONTAINER_STORAGE' ($STORAGE_TYPE) validated"
msg_info "Validating template storage '$TEMPLATE_STORAGE'" msg_info "Validating template storage '$TEMPLATE_STORAGE'"
@@ -5117,7 +5079,8 @@ create_lxc_container() {
# If still no template, try to find alternatives # If still no template, try to find alternatives
if [[ -z "$TEMPLATE" ]]; then if [[ -z "$TEMPLATE" ]]; then
msg_warn "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}, searching for alternatives..." echo ""
echo "[DEBUG] No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}, searching for alternatives..."
# Get all available versions for this OS type # Get all available versions for this OS type
AVAILABLE_VERSIONS=() AVAILABLE_VERSIONS=()
@@ -5137,7 +5100,7 @@ create_lxc_container() {
echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}" echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}"
done done
echo "" echo ""
read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or press Enter to cancel: " choice </dev/tty read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or press Enter to cancel: " choice
if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#AVAILABLE_VERSIONS[@]} ]]; then if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#AVAILABLE_VERSIONS[@]} ]]; then
PCT_OSVERSION="${AVAILABLE_VERSIONS[$((choice - 1))]}" PCT_OSVERSION="${AVAILABLE_VERSIONS[$((choice - 1))]}"
@@ -5200,7 +5163,7 @@ create_lxc_container() {
done done
echo "" echo ""
read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or Enter to exit: " choice </dev/tty read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or Enter to exit: " choice
if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#AVAILABLE_VERSIONS[@]} ]]; then if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#AVAILABLE_VERSIONS[@]} ]]; then
export var_version="${AVAILABLE_VERSIONS[$((choice - 1))]}" export var_version="${AVAILABLE_VERSIONS[$((choice - 1))]}"
@@ -5250,7 +5213,7 @@ create_lxc_container() {
} }
else else
msg_custom "🚫" "${YW}" "Installation cancelled" msg_custom "🚫" "${YW}" "Installation cancelled"
exit 0 exit 1
fi fi
else else
msg_error "No ${PCT_OSTYPE} templates available" msg_error "No ${PCT_OSTYPE} templates available"
@@ -5310,7 +5273,7 @@ create_lxc_container() {
[[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH" [[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
for attempt in {1..3}; do for attempt in {1..3}; do
msg_info "Attempt $attempt: Downloading template $TEMPLATE to $TEMPLATE_STORAGE" msg_info "Attempt $attempt: Downloading template $TEMPLATE to $TEMPLATE_STORAGE"
if pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1; then if pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1; then
msg_ok "Template download successful." msg_ok "Template download successful."
break break
fi fi
@@ -5387,35 +5350,17 @@ create_lxc_container() {
LOGFILE="/tmp/pct_create_${CTID}_$(date +%Y%m%d_%H%M%S)_${SESSION_ID}.log" LOGFILE="/tmp/pct_create_${CTID}_$(date +%Y%m%d_%H%M%S)_${SESSION_ID}.log"
# Helper: append pct_create log to BUILD_LOG before exit so combined log has full context
_flush_pct_log() {
if [[ -s "${LOGFILE:-}" && -n "${BUILD_LOG:-}" ]]; then
{
echo ""
echo "--- pct create output (${LOGFILE}) ---"
cat "$LOGFILE"
echo "--- end pct create output ---"
} >>"$BUILD_LOG" 2>/dev/null || true
fi
}
# Validate template before pct create (while holding lock) # Validate template before pct create (while holding lock)
if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH" 2>/dev/null || echo 0)" -lt 1000000 ]]; then if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH" 2>/dev/null || echo 0)" -lt 1000000 ]]; then
msg_info "Template file missing or too small downloading" msg_info "Template file missing or too small downloading"
rm -f "$TEMPLATE_PATH" rm -f "$TEMPLATE_PATH"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 || { pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1
msg_error "Failed to download template '$TEMPLATE' to storage '$TEMPLATE_STORAGE'"
exit 222
}
msg_ok "Template downloaded" msg_ok "Template downloaded"
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
if [[ -n "$ONLINE_TEMPLATE" ]]; then if [[ -n "$ONLINE_TEMPLATE" ]]; then
msg_info "Template appears corrupted re-downloading" msg_info "Template appears corrupted re-downloading"
rm -f "$TEMPLATE_PATH" rm -f "$TEMPLATE_PATH"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 || { pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1
msg_error "Failed to re-download template '$TEMPLATE'"
exit 222
}
msg_ok "Template re-downloaded" msg_ok "Template re-downloaded"
else else
msg_warn "Template appears corrupted, but no online version exists. Skipping re-download." msg_warn "Template appears corrupted, but no online version exists. Skipping re-download."
@@ -5436,7 +5381,7 @@ create_lxc_container() {
if grep -qiE 'unable to open|corrupt|invalid' "$LOGFILE"; then if grep -qiE 'unable to open|corrupt|invalid' "$LOGFILE"; then
msg_info "Template may be corrupted re-downloading" msg_info "Template may be corrupted re-downloading"
rm -f "$TEMPLATE_PATH" rm -f "$TEMPLATE_PATH"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1
msg_ok "Template re-downloaded" msg_ok "Template re-downloaded"
fi fi
@@ -5449,7 +5394,7 @@ create_lxc_container() {
if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then
msg_ok "Trying local storage fallback" msg_ok "Trying local storage fallback"
msg_info "Downloading template to local" msg_info "Downloading template to local"
pveam download local "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 pveam download local "$TEMPLATE" >/dev/null 2>&1
msg_ok "Template downloaded to local" msg_ok "Template downloaded to local"
else else
msg_ok "Trying local storage fallback" msg_ok "Trying local storage fallback"
@@ -5457,19 +5402,20 @@ create_lxc_container() {
if ! pct create "$CTID" "local:vztmpl/${TEMPLATE}" $PCT_OPTIONS >>"$LOGFILE" 2>&1; then if ! pct create "$CTID" "local:vztmpl/${TEMPLATE}" $PCT_OPTIONS >>"$LOGFILE" 2>&1; then
# Local fallback also failed - check for LXC stack version issue # Local fallback also failed - check for LXC stack version issue
if grep -qiE 'unsupported .* version' "$LOGFILE"; then if grep -qiE 'unsupported .* version' "$LOGFILE"; then
msg_warn "pct reported 'unsupported version' LXC stack might be too old for this template" echo
echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template."
echo "We can try to upgrade 'pve-container' and 'lxc-pve' now and retry automatically."
offer_lxc_stack_upgrade_and_maybe_retry "yes" offer_lxc_stack_upgrade_and_maybe_retry "yes"
rc=$? rc=$?
case $rc in case $rc in
0) : ;; # success - container created, continue 0) : ;; # success - container created, continue
2) 2)
msg_error "Upgrade declined. Please update and re-run: apt update && apt install --only-upgrade pve-container lxc-pve" echo "Upgrade was declined. Please update and re-run:
_flush_pct_log apt update && apt install --only-upgrade pve-container lxc-pve"
exit 231 exit 231
;; ;;
3) 3)
msg_error "Upgrade and/or retry failed. Please inspect: $LOGFILE" echo "Upgrade and/or retry failed. Please inspect: $LOGFILE"
_flush_pct_log
exit 231 exit 231
;; ;;
esac esac
@@ -5480,7 +5426,6 @@ create_lxc_container() {
pct create "$CTID" "local:vztmpl/${TEMPLATE}" $PCT_OPTIONS 2>&1 | tee -a "$LOGFILE" pct create "$CTID" "local:vztmpl/${TEMPLATE}" $PCT_OPTIONS 2>&1 | tee -a "$LOGFILE"
set +x set +x
fi fi
_flush_pct_log
exit 209 exit 209
fi fi
else else
@@ -5489,19 +5434,20 @@ create_lxc_container() {
else else
# Already on local storage and still failed - check LXC stack version # Already on local storage and still failed - check LXC stack version
if grep -qiE 'unsupported .* version' "$LOGFILE"; then if grep -qiE 'unsupported .* version' "$LOGFILE"; then
msg_warn "pct reported 'unsupported version' LXC stack might be too old for this template" echo
echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template."
echo "We can try to upgrade 'pve-container' and 'lxc-pve' now and retry automatically."
offer_lxc_stack_upgrade_and_maybe_retry "yes" offer_lxc_stack_upgrade_and_maybe_retry "yes"
rc=$? rc=$?
case $rc in case $rc in
0) : ;; # success - container created, continue 0) : ;; # success - container created, continue
2) 2)
msg_error "Upgrade declined. Please update and re-run: apt update && apt install --only-upgrade pve-container lxc-pve" echo "Upgrade was declined. Please update and re-run:
_flush_pct_log apt update && apt install --only-upgrade pve-container lxc-pve"
exit 231 exit 231
;; ;;
3) 3)
msg_error "Upgrade and/or retry failed. Please inspect: $LOGFILE" echo "Upgrade and/or retry failed. Please inspect: $LOGFILE"
_flush_pct_log
exit 231 exit 231
;; ;;
esac esac
@@ -5512,7 +5458,6 @@ create_lxc_container() {
pct create "$CTID" "local:vztmpl/${TEMPLATE}" $PCT_OPTIONS 2>&1 | tee -a "$LOGFILE" pct create "$CTID" "local:vztmpl/${TEMPLATE}" $PCT_OPTIONS 2>&1 | tee -a "$LOGFILE"
set +x set +x
fi fi
_flush_pct_log
exit 209 exit 209
fi fi
fi fi
@@ -5524,28 +5469,16 @@ create_lxc_container() {
# Verify container exists # Verify container exists
pct list | awk '{print $1}' | grep -qx "$CTID" || { pct list | awk '{print $1}' | grep -qx "$CTID" || {
msg_error "Container ID $CTID not listed in 'pct list'. See $LOGFILE" msg_error "Container ID $CTID not listed in 'pct list'. See $LOGFILE"
_flush_pct_log
exit 215 exit 215
} }
# Verify config rootfs # Verify config rootfs
grep -q '^rootfs:' "/etc/pve/lxc/$CTID.conf" || { grep -q '^rootfs:' "/etc/pve/lxc/$CTID.conf" || {
msg_error "RootFS entry missing in container config. See $LOGFILE" msg_error "RootFS entry missing in container config. See $LOGFILE"
_flush_pct_log
exit 216 exit 216
} }
msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created." msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created."
# Append pct create log to BUILD_LOG for combined log visibility
if [[ -s "$LOGFILE" && -n "${BUILD_LOG:-}" ]]; then
{
echo ""
echo "--- pct create output ---"
cat "$LOGFILE"
echo "--- end pct create output ---"
} >>"$BUILD_LOG" 2>/dev/null || true
fi
} }
# ============================================================================== # ==============================================================================
@@ -5667,21 +5600,44 @@ ensure_log_on_host() {
fi fi
} }
# ============================================================================== # ------------------------------------------------------------------------------
# TRAP MANAGEMENT # api_exit_script()
# ==============================================================================
# All traps (ERR, EXIT, INT, TERM, HUP) are set by catch_errors() in
# error_handler.func — called at the top of this file after sourcing.
# #
# Do NOT set duplicate traps here. The handlers in error_handler.func # - Exit trap handler for reporting to API telemetry
# (on_exit, on_interrupt, on_terminate, on_hangup, error_handler) already: # - Captures exit code and reports to PocketBase using centralized error descriptions
# - Send telemetry via post_update_to_api / _send_abort_telemetry # - Uses explain_exit_code() from api.func for consistent error messages
# - Stop orphaned containers via _stop_container_if_installing # - ALWAYS sends telemetry FIRST before log collection to prevent pct pull
# - Collect logs via ensure_log_on_host # hangs from blocking status updates (container may be dead/unresponsive)
# - Clean up lock files and spinner processes # - For non-zero exit codes: posts "failed" status
# # - For zero exit codes where post_update_to_api was never called:
# Previously, inline traps here overwrote catch_errors() traps, causing: # catches orphaned "installing" records (e.g., script exited cleanly
# - error_handler() never fired (no error output, no cleanup dialog) # but description() was never reached)
# - on_hangup() never fired (SSH disconnect → stuck records) # ------------------------------------------------------------------------------
# - Duplicated logic in two places (hard to debug) api_exit_script() {
# ============================================================================== local exit_code=$?
if [ $exit_code -ne 0 ]; then
# ALWAYS send telemetry FIRST - ensure status is reported even if
# ensure_log_on_host hangs (e.g. pct pull on dead container)
post_update_to_api "failed" "$exit_code" 2>/dev/null || true
# Best-effort log collection (non-critical after telemetry is sent)
if 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
if [[ "${CONTAINER_INSTALLING:-}" == "true" && -n "${CTID:-}" ]] && command -v pct &>/dev/null; then
pct stop "$CTID" 2>/dev/null || true
fi
elif [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
# Script exited with 0 but never sent a completion status
# exit_code=0 is never an error — report as success
post_update_to_api "done" "0"
fi
}
if command -v pveversion >/dev/null 2>&1; then
trap 'api_exit_script' EXIT
fi
trap 'local _ec=$?; if [[ $_ec -ne 0 ]]; then post_update_to_api "failed" "$_ec" 2>/dev/null || true; if declare -f ensure_log_on_host &>/dev/null; then ensure_log_on_host 2>/dev/null || true; fi; fi' ERR
trap 'post_update_to_api "failed" "129" 2>/dev/null || true; if [[ -n "${CTID:-}" ]] && command -v pct &>/dev/null; then pct stop "$CTID" 2>/dev/null || true; fi; exit 129' SIGHUP
trap 'post_update_to_api "failed" "130" 2>/dev/null || true; if [[ -n "${CTID:-}" ]] && command -v pct &>/dev/null; then pct stop "$CTID" 2>/dev/null || true; fi; exit 130' SIGINT
trap 'post_update_to_api "failed" "143" 2>/dev/null || true; if [[ -n "${CTID:-}" ]] && command -v pct &>/dev/null; then pct stop "$CTID" 2>/dev/null || true; fi; exit 143' SIGTERM

View File

@@ -276,7 +276,7 @@ shell_check() {
msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell." msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell."
echo -e "\nExiting..." echo -e "\nExiting..."
sleep 2 sleep 2
exit 103 exit
fi fi
} }
@@ -293,7 +293,7 @@ root_check() {
msg_error "Please run this script as root." msg_error "Please run this script as root."
echo -e "\nExiting..." echo -e "\nExiting..."
sleep 2 sleep 2
exit 104 exit
fi fi
} }
@@ -314,7 +314,7 @@ pve_check() {
if ((MINOR < 0 || MINOR > 9)); then if ((MINOR < 0 || MINOR > 9)); then
msg_error "This version of Proxmox VE is not supported." msg_error "This version of Proxmox VE is not supported."
msg_error "Supported: Proxmox VE version 8.0 8.9" msg_error "Supported: Proxmox VE version 8.0 8.9"
exit 105 exit 1
fi fi
return 0 return 0
fi fi
@@ -325,7 +325,7 @@ pve_check() {
if ((MINOR < 0 || MINOR > 1)); then if ((MINOR < 0 || MINOR > 1)); then
msg_error "This version of Proxmox VE is not yet supported." msg_error "This version of Proxmox VE is not yet supported."
msg_error "Supported: Proxmox VE version 9.0 9.1" msg_error "Supported: Proxmox VE version 9.0 9.1"
exit 105 exit 1
fi fi
return 0 return 0
fi fi
@@ -333,7 +333,7 @@ pve_check() {
# All other unsupported versions # All other unsupported versions
msg_error "This version of Proxmox VE is not supported." msg_error "This version of Proxmox VE is not supported."
msg_error "Supported versions: Proxmox VE 8.0 8.9 or 9.0 9.1" msg_error "Supported versions: Proxmox VE 8.0 8.9 or 9.0 9.1"
exit 105 exit 1
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -345,10 +345,11 @@ pve_check() {
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
arch_check() { arch_check() {
if [ "$(dpkg --print-architecture)" != "amd64" ]; then if [ "$(dpkg --print-architecture)" != "amd64" ]; then
msg_error "This script will not work with PiMox (ARM architecture detected)." echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n"
msg_warn "Visit https://github.com/asylumexp/Proxmox for ARM64 support." echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
echo -e "Exiting..."
sleep 2 sleep 2
exit 106 exit
fi fi
} }
@@ -489,8 +490,6 @@ log_section() {
# - Executes command with output redirected to active log file # - Executes command with output redirected to active log file
# - On error: displays last 20 lines of log and exits with original exit code # - On error: displays last 20 lines of log and exits with original exit code
# - Temporarily disables error trap to capture exit code correctly # - Temporarily disables error trap to capture exit code correctly
# - Saves and restores previous error handling state (so callers that
# intentionally disabled error handling aren't silently re-enabled)
# - Sources explain_exit_code() for detailed error messages # - Sources explain_exit_code() for detailed error messages
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
silent() { silent() {
@@ -508,30 +507,19 @@ silent() {
return 0 return 0
fi fi
# Save current error handling state before disabling
# This prevents re-enabling error handling when the caller intentionally
# disabled it (e.g. build_container recovery section)
local _restore_errexit=false
[[ "$-" == *e* ]] && _restore_errexit=true
set +Eeuo pipefail set +Eeuo pipefail
trap - ERR trap - ERR
"$@" >>"$logfile" 2>&1 "$@" >>"$logfile" 2>&1
local rc=$? local rc=$?
# Restore error handling ONLY if it was active before this call set -Eeuo pipefail
if $_restore_errexit; then trap 'error_handler' ERR
set -Eeuo pipefail
trap 'error_handler' ERR
fi
if [[ $rc -ne 0 ]]; then if [[ $rc -ne 0 ]]; then
# Source explain_exit_code if needed # Source explain_exit_code if needed
if ! declare -f explain_exit_code >/dev/null 2>&1; then if ! declare -f explain_exit_code >/dev/null 2>&1; then
if ! source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func); then source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func)
explain_exit_code() { echo "unknown (error_handler.func download failed)"; }
fi
fi fi
local explanation local explanation
@@ -552,53 +540,6 @@ silent() {
fi fi
} }
# ------------------------------------------------------------------------------
# apt_update_safe()
#
# - Runs apt-get update with graceful error handling
# - On failure: shows warning with common causes instead of aborting
# - Logs full output to active log file
# - Returns 0 even on failure so the caller can continue
# - Typical cause: enterprise repos returning 401 Unauthorized
#
# Usage:
# apt_update_safe # Warn on failure, continue without aborting
# ------------------------------------------------------------------------------
apt_update_safe() {
local logfile
logfile="$(get_active_logfile)"
local _restore_errexit=false
[[ "$-" == *e* ]] && _restore_errexit=true
set +Eeuo pipefail
trap - ERR
apt-get update >>"$logfile" 2>&1
local rc=$?
if $_restore_errexit; then
set -Eeuo pipefail
trap 'error_handler' ERR
fi
if [[ $rc -ne 0 ]]; then
msg_warn "apt-get update exited with code ${rc} — some repositories may have failed."
# Check log for common 401/403 enterprise repo issues
if grep -qiE '401\s*Unauthorized|403\s*Forbidden|enterprise\.proxmox\.com' "$logfile" 2>/dev/null; then
echo -e "${TAB}${INFO} ${YWB}Hint: Proxmox enterprise repository returned an auth error.${CL}"
echo -e "${TAB} If you don't have a subscription, you can disable the enterprise"
echo -e "${TAB} repo and use the no-subscription repo instead."
fi
echo -e "${TAB}${INFO} ${YWB}Continuing despite partial update failure — packages may still be installable.${CL}"
echo ""
fi
return 0
}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# spinner() # spinner()
# #
@@ -655,7 +596,6 @@ stop_spinner() {
unset SPINNER_PID SPINNER_MSG unset SPINNER_PID SPINNER_MSG
stty sane 2>/dev/null || true stty sane 2>/dev/null || true
stty -tostop 2>/dev/null || true
} }
# ============================================================================== # ==============================================================================
@@ -833,8 +773,8 @@ fatal() {
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
exit_script() { exit_script() {
clear clear
msg_error "User exited script" echo -e "\n${CROSS}${RD}User exited script${CL}\n"
exit 0 exit
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -848,16 +788,13 @@ exit_script() {
get_header() { get_header() {
local app_name=$(echo "${APP,,}" | tr -d ' ') local app_name=$(echo "${APP,,}" | tr -d ' ')
local app_type=${APP_TYPE:-ct} # Default to 'ct' if not set local app_type=${APP_TYPE:-ct} # Default to 'ct' if not set
local header_dir="${app_type}" local header_url="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/${app_type}/headers/${app_name}"
[[ "$app_type" == "addon" ]] && header_dir="tools"
local header_url="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/${header_dir}/headers/${app_name}"
local local_header_path="/usr/local/community-scripts/headers/${app_type}/${app_name}" local local_header_path="/usr/local/community-scripts/headers/${app_type}/${app_name}"
mkdir -p "$(dirname "$local_header_path")" mkdir -p "$(dirname "$local_header_path")"
if [ ! -s "$local_header_path" ]; then if [ ! -s "$local_header_path" ]; then
if ! curl -fsSL "$header_url" -o "$local_header_path"; then if ! curl -fsSL "$header_url" -o "$local_header_path"; then
msg_warn "Failed to download header: $header_url"
return 1 return 1
fi fi
fi fi
@@ -898,10 +835,10 @@ header_info() {
ensure_tput() { ensure_tput() {
if ! command -v tput >/dev/null 2>&1; then if ! command -v tput >/dev/null 2>&1; then
if grep -qi 'alpine' /etc/os-release; then if grep -qi 'alpine' /etc/os-release; then
apk add --no-cache ncurses >/dev/null 2>&1 || msg_warn "Failed to install ncurses (tput may be unavailable)" apk add --no-cache ncurses >/dev/null 2>&1
elif command -v apt-get >/dev/null 2>&1; then elif command -v apt-get >/dev/null 2>&1; then
apt-get update -qq >/dev/null apt-get update -qq >/dev/null
apt-get install -y -qq ncurses-bin >/dev/null 2>&1 || msg_warn "Failed to install ncurses-bin (tput may be unavailable)" apt-get install -y -qq ncurses-bin >/dev/null 2>&1
fi fi
fi fi
} }
@@ -932,13 +869,18 @@ is_alpine() {
# #
# - Determines if script should run in verbose mode # - Determines if script should run in verbose mode
# - Checks VERBOSE and var_verbose variables # - Checks VERBOSE and var_verbose variables
# - Also returns true if not running in TTY (pipe/redirect scenario)
# - Used by msg_info() to decide between spinner and static output # - Used by msg_info() to decide between spinner and static output
# - Note: Non-TTY (pipe) scenarios are handled separately in msg_info()
# to allow spinner output to pass through pipes (e.g. lxc-attach | tee)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
is_verbose_mode() { is_verbose_mode() {
local verbose="${VERBOSE:-${var_verbose:-no}}" local verbose="${VERBOSE:-${var_verbose:-no}}"
[[ "$verbose" != "no" ]] local tty_status
if [[ -t 2 ]]; then
tty_status="interactive"
else
tty_status="not-a-tty"
fi
[[ "$verbose" != "no" || ! -t 2 ]]
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -1356,7 +1298,6 @@ prompt_select() {
# Validate options # Validate options
if [[ $num_options -eq 0 ]]; then if [[ $num_options -eq 0 ]]; then
msg_warn "prompt_select called with no options"
echo "" >&2 echo "" >&2
return 1 return 1
fi fi
@@ -1599,30 +1540,22 @@ check_or_create_swap() {
local swap_size_mb local swap_size_mb
swap_size_mb=$(prompt_input "Enter swap size in MB (e.g., 2048 for 2GB):" "2048" 60) swap_size_mb=$(prompt_input "Enter swap size in MB (e.g., 2048 for 2GB):" "2048" 60)
if ! [[ "$swap_size_mb" =~ ^[0-9]+$ ]]; then if ! [[ "$swap_size_mb" =~ ^[0-9]+$ ]]; then
msg_error "Invalid swap size: '${swap_size_mb}' (must be a number in MB)" msg_error "Invalid size input. Aborting."
return 1 return 1
fi fi
local swap_file="/swapfile" local swap_file="/swapfile"
msg_info "Creating ${swap_size_mb}MB swap file at $swap_file" msg_info "Creating ${swap_size_mb}MB swap file at $swap_file"
if ! dd if=/dev/zero of="$swap_file" bs=1M count="$swap_size_mb" status=progress; then if dd if=/dev/zero of="$swap_file" bs=1M count="$swap_size_mb" status=progress &&
msg_error "Failed to allocate swap file (dd failed)" chmod 600 "$swap_file" &&
mkswap "$swap_file" &&
swapon "$swap_file"; then
msg_ok "Swap file created and activated successfully"
else
msg_error "Failed to create or activate swap"
return 1 return 1
fi fi
if ! chmod 600 "$swap_file"; then
msg_error "Failed to set permissions on $swap_file"
return 1
fi
if ! mkswap "$swap_file"; then
msg_error "Failed to format swap file (mkswap failed)"
return 1
fi
if ! swapon "$swap_file"; then
msg_error "Failed to activate swap (swapon failed)"
return 1
fi
msg_ok "Swap file created and activated successfully"
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -1704,7 +1637,7 @@ function get_lxc_ip() {
LOCAL_IP="$(get_current_ip || true)" LOCAL_IP="$(get_current_ip || true)"
if [[ -z "$LOCAL_IP" ]]; then if [[ -z "$LOCAL_IP" ]]; then
msg_error "Could not determine LOCAL_IP (checked: eth0, hostname -I, ip route, IPv6 targets)" msg_error "Could not determine LOCAL_IP"
return 1 return 1
fi fi
fi fi

View File

@@ -94,29 +94,6 @@ if ! declare -f explain_exit_code &>/dev/null; then
100) echo "APT: Package manager error (broken packages / dependency problems)" ;; 100) echo "APT: Package manager error (broken packages / dependency problems)" ;;
101) echo "APT: Configuration error (bad sources.list, malformed config)" ;; 101) echo "APT: Configuration error (bad sources.list, malformed config)" ;;
102) echo "APT: Lock held by another process (dpkg/apt still running)" ;; 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" ;;
106) echo "Validation: Architecture not supported (ARM / PiMox)" ;;
107) echo "Validation: Kernel key parameters unreadable" ;;
108) echo "Validation: Kernel key limits exceeded" ;;
109) echo "Proxmox: No available container ID after max attempts" ;;
110) echo "Proxmox: Failed to apply default.vars" ;;
111) echo "Proxmox: App defaults file not available" ;;
112) echo "Proxmox: Invalid install menu option" ;;
113) echo "LXC: Under-provisioned — user aborted update" ;;
114) echo "LXC: Storage too low — user aborted update" ;;
115) echo "Download: install.func download failed or incomplete" ;;
116) echo "Proxmox: Default bridge vmbr0 not found" ;;
117) echo "LXC: Container did not reach running state" ;;
118) echo "LXC: No IP assigned to container after timeout" ;;
119) echo "Proxmox: No valid storage for rootdir content" ;;
120) echo "Proxmox: No valid storage for vztmpl content" ;;
121) echo "LXC: Container network not ready (no IP after retries)" ;;
122) echo "LXC: No internet connectivity — user declined to continue" ;;
123) echo "LXC: Local IP detection failed" ;;
124) echo "Command timed out (timeout command)" ;; 124) echo "Command timed out (timeout command)" ;;
125) echo "Command failed to start (Docker daemon or execution error)" ;; 125) echo "Command failed to start (Docker daemon or execution error)" ;;
126) echo "Command invoked cannot execute (permission problem?)" ;; 126) echo "Command invoked cannot execute (permission problem?)" ;;
@@ -178,16 +155,6 @@ if ! declare -f explain_exit_code &>/dev/null; then
224) echo "Proxmox: PBS storage is for backups only" ;; 224) echo "Proxmox: PBS storage is for backups only" ;;
225) echo "Proxmox: No template available for OS/Version" ;; 225) echo "Proxmox: No template available for OS/Version" ;;
231) echo "Proxmox: LXC stack upgrade 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" ;;
235) echo "Tools: Backup or restore operation failed" ;;
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" ;; 239) echo "npm/Node.js: Unexpected runtime error or dependency failure" ;;
243) echo "Node.js: Out of memory (JavaScript heap out of memory)" ;; 243) echo "Node.js: Out of memory (JavaScript heap out of memory)" ;;
245) echo "Node.js: Invalid command-line option" ;; 245) echo "Node.js: Invalid command-line option" ;;
@@ -232,16 +199,11 @@ error_handler() {
return 0 return 0
fi fi
# Stop spinner and restore cursor FIRST — before any output
# This prevents spinner text overlapping with error messages
if declare -f stop_spinner >/dev/null 2>&1; then
stop_spinner 2>/dev/null || true
fi
printf "\e[?25h"
local explanation local explanation
explanation="$(explain_exit_code "$exit_code")" explanation="$(explain_exit_code "$exit_code")"
printf "\e[?25h"
# ALWAYS report failure to API immediately - don't wait for container checks # ALWAYS report failure to API immediately - don't wait for container checks
# This ensures we capture failures that occur before/after container exists # This ensures we capture failures that occur before/after container exists
if declare -f post_update_to_api &>/dev/null; then if declare -f post_update_to_api &>/dev/null; then
@@ -319,8 +281,6 @@ error_handler() {
echo -en "${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}" echo -en "${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}"
fi fi
# Read user response
local response=""
if read -t 60 -r response; then if read -t 60 -r response; then
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
echo "" echo ""
@@ -399,39 +359,9 @@ _send_abort_telemetry() {
command -v curl &>/dev/null || return 0 command -v curl &>/dev/null || return 0
[[ "${DIAGNOSTICS:-no}" == "no" ]] && return 0 [[ "${DIAGNOSTICS:-no}" == "no" ]] && return 0
[[ -z "${RANDOM_UUID:-}" ]] && return 0 [[ -z "${RANDOM_UUID:-}" ]] && return 0
curl -fsS -m 5 -X POST "${TELEMETRY_URL:-https://telemetry.community-scripts.org/telemetry}" \
# Collect last 20 log lines for error diagnosis (best-effort) -H "Content-Type: application/json" \
local error_text="" -d "{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"${TELEMETRY_TYPE:-lxc}\",\"nsapp\":\"${NSAPP:-${app:-unknown}}\",\"status\":\"failed\",\"exit_code\":${exit_code}}" &>/dev/null || true
if [[ -n "${INSTALL_LOG:-}" && -s "${INSTALL_LOG}" ]]; then
error_text=$(tail -n 20 "$INSTALL_LOG" 2>/dev/null | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\\/\\\\/g; s/"/\\"/g; s/\r//g' | tr '\n' '|' | sed 's/|$//' | tr -d '\000-\010\013\014\016-\037\177') || true
fi
# Calculate duration if start time is available
local duration=""
if [[ -n "${DIAGNOSTICS_START_TIME:-}" ]]; then
duration=$(($(date +%s) - DIAGNOSTICS_START_TIME))
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 "$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
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -507,12 +437,6 @@ on_exit() {
# - Exits with code 130 (128 + SIGINT=2) # - Exits with code 130 (128 + SIGINT=2)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
on_interrupt() { 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" _send_abort_telemetry "130"
_stop_container_if_installing _stop_container_if_installing
if declare -f msg_error >/dev/null 2>&1; then if declare -f msg_error >/dev/null 2>&1; then
@@ -532,12 +456,6 @@ on_interrupt() {
# - Exits with code 143 (128 + SIGTERM=15) # - Exits with code 143 (128 + SIGTERM=15)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
on_terminate() { 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" _send_abort_telemetry "143"
_stop_container_if_installing _stop_container_if_installing
if declare -f msg_error >/dev/null 2>&1; then if declare -f msg_error >/dev/null 2>&1; then
@@ -560,11 +478,6 @@ on_terminate() {
# - Exits with code 129 (128 + SIGHUP=1) # - Exits with code 129 (128 + SIGHUP=1)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
on_hangup() { 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" _send_abort_telemetry "129"
_stop_container_if_installing _stop_container_if_installing
exit 129 exit 129

View File

@@ -126,7 +126,7 @@ setting_up_container() {
if [ "$(hostname -I)" = "" ]; then if [ "$(hostname -I)" = "" ]; then
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}" echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
echo -e "${NETWORK}Check Network Settings" echo -e "${NETWORK}Check Network Settings"
exit 121 exit 1
fi fi
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
systemctl disable -q --now systemd-networkd-wait-online.service systemctl disable -q --now systemd-networkd-wait-online.service
@@ -177,7 +177,7 @@ network_check() {
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}" echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
else else
echo -e "${NETWORK}Check Network Settings" echo -e "${NETWORK}Check Network Settings"
exit 122 exit 1
fi fi
fi fi
@@ -233,7 +233,7 @@ fi
EOF EOF
chmod +x /usr/local/bin/apt-proxy-detect.sh chmod +x /usr/local/bin/apt-proxy-detect.sh
fi fi
apt_update_safe $STD apt-get update
$STD apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade $STD apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
msg_ok "Updated Container OS" msg_ok "Updated Container OS"
@@ -242,12 +242,12 @@ EOF
local tools_content local tools_content
tools_content=$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) || { tools_content=$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) || {
msg_error "Failed to download tools.func" msg_error "Failed to download tools.func"
exit 115 exit 6
} }
source /dev/stdin <<<"$tools_content" source /dev/stdin <<<"$tools_content"
if ! declare -f fetch_and_deploy_gh_release >/dev/null 2>&1; then if ! declare -f fetch_and_deploy_gh_release >/dev/null 2>&1; then
msg_error "tools.func loaded but incomplete — missing expected functions" msg_error "tools.func loaded but incomplete — missing expected functions"
exit 115 exit 6
fi fi
} }

File diff suppressed because it is too large Load Diff

View File

@@ -244,7 +244,7 @@ curl_handler() {
if [[ -z "$url" ]]; then if [[ -z "$url" ]]; then
msg_error "no valid url or option entered for curl_handler" msg_error "no valid url or option entered for curl_handler"
exit 64 exit 1
fi fi
$STD msg_info "Fetching: $url" $STD msg_info "Fetching: $url"
@@ -273,7 +273,7 @@ curl_handler() {
rm -f /tmp/curl_error.log rm -f /tmp/curl_error.log
fi fi
__curl_err_handler "$exit_code" "$url" "$curl_stderr" __curl_err_handler "$exit_code" "$url" "$curl_stderr"
exit "$exit_code" exit 1 # hard exit if exit_code is not 0
fi fi
$STD printf "\r\033[K${INFO}${YW}Retry $attempt/$max_retries in ${delay}s...${CL}" >&2 $STD printf "\r\033[K${INFO}${YW}Retry $attempt/$max_retries in ${delay}s...${CL}" >&2
@@ -316,7 +316,7 @@ __curl_err_handler() {
esac esac
[[ -n "$curl_msg" ]] && printf "%s\n" "$curl_msg" >&2 [[ -n "$curl_msg" ]] && printf "%s\n" "$curl_msg" >&2
exit "$exit_code" exit 1
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -331,7 +331,7 @@ shell_check() {
msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell." msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell."
echo -e "\nExiting..." echo -e "\nExiting..."
sleep 2 sleep 2
exit 103 exit
fi fi
} }
@@ -352,11 +352,11 @@ clear_line() {
# #
# - Determines if script should run in verbose mode # - Determines if script should run in verbose mode
# - Checks VERBOSE and var_verbose variables # - Checks VERBOSE and var_verbose variables
# - Note: Non-TTY (pipe) scenarios are handled separately in msg_info() # - Also returns true if not running in TTY (pipe/redirect scenario)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
is_verbose_mode() { is_verbose_mode() {
local verbose="${VERBOSE:-${var_verbose:-no}}" local verbose="${VERBOSE:-${var_verbose:-no}}"
[[ "$verbose" != "no" ]] [[ "$verbose" != "no" || ! -t 2 ]]
} }
### dev spinner ### ### dev spinner ###
@@ -552,7 +552,7 @@ check_root() {
msg_error "Please run this script as root." msg_error "Please run this script as root."
echo -e "\nExiting..." echo -e "\nExiting..."
sleep 2 sleep 2
exit 104 exit
fi fi
} }
@@ -562,7 +562,7 @@ pve_check() {
echo -e "Requires Proxmox Virtual Environment Version 8.1 - 8.4 or 9.0 - 9.1." echo -e "Requires Proxmox Virtual Environment Version 8.1 - 8.4 or 9.0 - 9.1."
echo -e "Exiting..." echo -e "Exiting..."
sleep 2 sleep 2
exit 105 exit
fi fi
} }
@@ -572,21 +572,21 @@ arch_check() {
echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n" echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
echo -e "Exiting..." echo -e "Exiting..."
sleep 2 sleep 2
exit 106 exit
fi fi
} }
exit_script() { exit_script() {
clear clear
echo -e "\n${CROSS}${RD}User exited script${CL}\n" echo -e "\n${CROSS}${RD}User exited script${CL}\n"
exit 0 exit
} }
check_hostname_conflict() { check_hostname_conflict() {
local hostname="$1" local hostname="$1"
if qm list | awk '{print $2}' | grep -qx "$hostname"; then if qm list | awk '{print $2}' | grep -qx "$hostname"; then
msg_error "Hostname $hostname already in use by another VM." msg_error "Hostname $hostname already in use by another VM."
exit 206 exit 1
fi fi
} }

View File

@@ -73,7 +73,7 @@ fi
DISTRO=$(pct exec "$CTID" -- cat /etc/os-release | grep -w "ID" | cut -d'=' -f2 | tr -d '"') DISTRO=$(pct exec "$CTID" -- cat /etc/os-release | grep -w "ID" | cut -d'=' -f2 | tr -d '"')
if [[ "$DISTRO" != "debian" && "$DISTRO" != "ubuntu" ]]; then if [[ "$DISTRO" != "debian" && "$DISTRO" != "ubuntu" ]]; then
msg "\e[1;31m Error: This script only supports Debian or Ubuntu LXC containers. Detected: $DISTRO. Aborting...\e[0m" msg "\e[1;31m Error: This script only supports Debian or Ubuntu LXC containers. Detected: $DISTRO. Aborting...\e[0m"
exit 238 exit 1
fi fi
CTID_CONFIG_PATH=/etc/pve/lxc/${CTID}.conf CTID_CONFIG_PATH=/etc/pve/lxc/${CTID}.conf

View File

@@ -32,7 +32,7 @@ header_info
if ! command -v pveversion &>/dev/null; then if ! command -v pveversion &>/dev/null; then
msg_error "This script must be run on the Proxmox VE host (not inside an LXC container)" msg_error "This script must be run on the Proxmox VE host (not inside an LXC container)"
exit 232 exit 1
fi fi
while true; do while true; do
@@ -64,7 +64,7 @@ while [[ -z "${CTID}" ]]; do
CTID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Containers on $NODE" --radiolist \ CTID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Containers on $NODE" --radiolist \
"\nSelect a container to add Tailscale to:\n" \ "\nSelect a container to add Tailscale to:\n" \
16 $((MSG_MAX_LENGTH + 23)) 6 \ 16 $((MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit 0 "${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit 1
done done
CTID_CONFIG_PATH="/etc/pve/lxc/${CTID}.conf" CTID_CONFIG_PATH="/etc/pve/lxc/${CTID}.conf"
@@ -76,90 +76,70 @@ grep -q "lxc.mount.entry: /dev/net/tun" "$CTID_CONFIG_PATH" || echo "lxc.mount.e
header_info header_info
msg_info "Installing Tailscale in CT $CTID" msg_info "Installing Tailscale in CT $CTID"
pct exec "$CTID" -- sh -c ' pct exec "$CTID" -- bash -c '
set -e set -e
export DEBIAN_FRONTEND=noninteractive
# Detect OS inside container # Source os-release properly (handles quoted values)
if [ -f /etc/alpine-release ]; then source /etc/os-release
# ── Alpine Linux ──
echo "[INFO] Alpine Linux detected, installing Tailscale via apk..."
# Enable community repo if not already enabled # Fallback if DNS is poisoned or blocked
if ! grep -q "^[^#].*community" /etc/apk/repositories 2>/dev/null; then ORIG_RESOLV="/etc/resolv.conf"
ALPINE_VERSION=$(cat /etc/alpine-release | cut -d. -f1,2) BACKUP_RESOLV="/tmp/resolv.conf.backup"
echo "https://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VERSION}/community" >> /etc/apk/repositories
fi
apk update # Check DNS resolution using multiple methods (dig may not be installed)
apk add --no-cache tailscale dns_check_failed=true
if command -v dig &>/dev/null; then
# Enable and start Tailscale service if dig +short pkgs.tailscale.com 2>/dev/null | grep -qvE "^127\.|^0\.0\.0\.0$|^$"; then
rc-update add tailscale default 2>/dev/null || true
rc-service tailscale start 2>/dev/null || true
else
# ── Debian / Ubuntu ──
export DEBIAN_FRONTEND=noninteractive
# Source os-release properly (handles quoted values)
. /etc/os-release
# Fallback if DNS is poisoned or blocked
ORIG_RESOLV="/etc/resolv.conf"
BACKUP_RESOLV="/tmp/resolv.conf.backup"
# Check DNS resolution using multiple methods (dig may not be installed)
dns_check_failed=true
if command -v dig >/dev/null 2>&1; then
if dig +short pkgs.tailscale.com 2>/dev/null | grep -qvE "^127\.|^0\.0\.0\.0$|^$"; then
dns_check_failed=false
fi
elif command -v host >/dev/null 2>&1; then
if host pkgs.tailscale.com 2>/dev/null | grep -q "has address"; then
dns_check_failed=false
fi
elif command -v nslookup >/dev/null 2>&1; then
if nslookup pkgs.tailscale.com 2>/dev/null | grep -q "Address:"; then
dns_check_failed=false
fi
elif command -v getent >/dev/null 2>&1; then
if getent hosts pkgs.tailscale.com >/dev/null 2>&1; then
dns_check_failed=false
fi
else
# No DNS tools available, try curl directly and assume DNS works
dns_check_failed=false dns_check_failed=false
fi fi
elif command -v host &>/dev/null; then
if $dns_check_failed; then if host pkgs.tailscale.com 2>/dev/null | grep -q "has address"; then
echo "[INFO] DNS resolution for pkgs.tailscale.com failed (blocked or redirected)." dns_check_failed=false
echo "[INFO] Temporarily overriding /etc/resolv.conf with Cloudflare DNS (1.1.1.1)"
cp "$ORIG_RESOLV" "$BACKUP_RESOLV"
echo "nameserver 1.1.1.1" >"$ORIG_RESOLV"
fi fi
elif command -v nslookup &>/dev/null; then
if ! command -v curl >/dev/null 2>&1; then if nslookup pkgs.tailscale.com 2>/dev/null | grep -q "Address:"; then
echo "[INFO] curl not found, installing..." dns_check_failed=false
apt-get update -qq
apt-get install -y curl >/dev/null
fi fi
elif command -v getent &>/dev/null; then
if getent hosts pkgs.tailscale.com &>/dev/null; then
dns_check_failed=false
fi
else
# No DNS tools available, try curl directly and assume DNS works
dns_check_failed=false
fi
# Ensure keyrings directory exists if $dns_check_failed; then
mkdir -p /usr/share/keyrings echo "[INFO] DNS resolution for pkgs.tailscale.com failed (blocked or redirected)."
echo "[INFO] Temporarily overriding /etc/resolv.conf with Cloudflare DNS (1.1.1.1)"
curl -fsSL "https://pkgs.tailscale.com/stable/${ID}/${VERSION_CODENAME}.noarmor.gpg" \ cp "$ORIG_RESOLV" "$BACKUP_RESOLV"
| tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null echo "nameserver 1.1.1.1" >"$ORIG_RESOLV"
fi
echo "deb [signed-by=/usr/share/keyrings/tailscale-archive-keyring.gpg] https://pkgs.tailscale.com/stable/${ID} ${VERSION_CODENAME} main" \
>/etc/apt/sources.list.d/tailscale.list
if ! command -v curl &>/dev/null; then
echo "[INFO] curl not found, installing..."
apt-get update -qq apt-get update -qq
apt-get install -y tailscale >/dev/null apt update -qq
apt install -y curl >/dev/null
fi
if [ -f /tmp/resolv.conf.backup ]; then # Ensure keyrings directory exists
echo "[INFO] Restoring original /etc/resolv.conf" mkdir -p /usr/share/keyrings
mv /tmp/resolv.conf.backup /etc/resolv.conf
fi curl -fsSL "https://pkgs.tailscale.com/stable/${ID}/${VERSION_CODENAME}.noarmor.gpg" \
| tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/tailscale-archive-keyring.gpg] https://pkgs.tailscale.com/stable/${ID} ${VERSION_CODENAME} main" \
>/etc/apt/sources.list.d/tailscale.list
apt-get update -qq
apt update -qq
apt install -y tailscale >/dev/null
if [[ -f /tmp/resolv.conf.backup ]]; then
echo "[INFO] Restoring original /etc/resolv.conf"
mv /tmp/resolv.conf.backup /etc/resolv.conf
fi fi
' '

View File

@@ -7,12 +7,8 @@
if ! command -v curl &>/dev/null; then if ! command -v curl &>/dev/null; then
printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2
if [[ -f "/etc/alpine-release" ]]; then apt-get update >/dev/null 2>&1
apk -U add curl >/dev/null 2>&1 apt-get install -y curl >/dev/null 2>&1
else
apt-get update >/dev/null 2>&1
apt-get install -y curl >/dev/null 2>&1
fi
fi fi
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/core.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
@@ -55,7 +51,7 @@ EOF
# HELPER FUNCTIONS # HELPER FUNCTIONS
# ============================================================================== # ==============================================================================
get_ip() { get_ip() {
ifconfig | grep -v '127.0.0.1' | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -m1 -Eo '([0-9]*\.){3}[0-9]*' || echo "127.0.0.1" hostname -I 2>/dev/null | awk '{print $1}' || echo "127.0.0.1"
} }
# ============================================================================== # ==============================================================================
@@ -69,17 +65,7 @@ elif [[ -f "/etc/debian_version" ]]; then
SERVICE_PATH="/etc/systemd/system/adguardhome-sync.service" SERVICE_PATH="/etc/systemd/system/adguardhome-sync.service"
else else
msg_error "Unsupported OS detected. Exiting." msg_error "Unsupported OS detected. Exiting."
exit 238 exit 1
fi
# ==============================================================================
# DEPENDENCY CHECK
# ==============================================================================
if ! command -v jq &>/dev/null; then
printf "\r\e[2K%b" '\033[93m Installing jq \033[m' >&2
if [[ "$OS" == "Alpine" ]]; then
apk -U add jq >/dev/null 2>&1
fi
fi fi
# ============================================================================== # ==============================================================================
@@ -312,7 +298,7 @@ if [[ "${type:-}" == "update" ]]; then
update update
else else
msg_error "${APP} is not installed. Nothing to update." msg_error "${APP} is not installed. Nothing to update."
exit 233 exit 1
fi fi
exit 0 exit 0
fi fi

View File

@@ -87,11 +87,11 @@ function update() {
function check_docker() { function check_docker() {
if ! command -v docker &>/dev/null; then if ! command -v docker &>/dev/null; then
msg_error "Docker is not installed. This script requires an existing Docker LXC. Exiting." msg_error "Docker is not installed. This script requires an existing Docker LXC. Exiting."
exit 10 exit 1
fi fi
if ! docker compose version &>/dev/null; then if ! docker compose version &>/dev/null; then
msg_error "Docker Compose plugin is not available. Please install it before running this script. Exiting." msg_error "Docker Compose plugin is not available. Please install it before running this script. Exiting."
exit 10 exit 1
fi fi
msg_ok "Docker $(docker --version | cut -d' ' -f3 | tr -d ',') and Docker Compose are available" msg_ok "Docker $(docker --version | cut -d' ' -f3 | tr -d ',') and Docker Compose are available"
} }
@@ -171,7 +171,7 @@ if [[ "${type:-}" == "update" ]]; then
update update
else else
msg_error "${APP} is not installed. Nothing to update." msg_error "${APP} is not installed. Nothing to update."
exit 233 exit 1
fi fi
exit 0 exit 0
fi fi

Some files were not shown because too many files have changed in this diff Show More