Compare commits

...

30 Commits

Author SHA1 Message Date
push-app-to-main[bot] 390a2aabd7 Add postiz (ct) 2026-06-11 06:18:42 +00:00
community-scripts-pr-app[bot] 173f49a6f6 Update CHANGELOG.md (#15043)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-11 06:15:01 +00:00
Sam Heinz 6851a02bdc misc scripts: add support for arm64 (#12639)
* misc scripts: add support for arm64

* Replace tools.func call that checks arch

* Update misc/build.func

Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>

* Update misc/build.func

Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>

* Update misc/build.func

Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>

* Update misc/build.func

Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>

* build.func: change back to VE

* build.func: remove arm64 support for focal, bullseye

Legacy support removed since no cts use them anymore.

* Improve arm64 support and arch-specific downloads

Add clearer architecture error messages and gate arm64 usage, plus implement architecture-aware behavior across the toolkit. Changes include: update exit-code messages to reference amd64/arm64, refuse arm64 unless explicitly enabled, show architecture in summaries, and use arch-specific package lists when installing in containers. Make downloads for FFmpeg and yq choose the correct amd64/arm64 binaries, tighten template download error handling and formatting, and clean up minor whitespace/comment issues. These changes aim to make arm64 handling explicit and downloads/installations more robust for non-amd64 systems.

* remove arm64 overlay

* update ifupdown2 source

* Revert "remove arm64 overlay"

This reverts commit 231945dfa7.

* Revert changes from "Improve arm64 support and arch-specific downloads"

* Reapply "Improve arm64 support and arch-specific downloads"

This reapplies commit 7c051fb648.

* Reapply "remove arm64 overlay"

This reverts commit 866b6950c0.

* Redo template name handling

* fix template name handling change

* add ensure_whiptail function

This is required as some arm64 systems will not have whiptail installed, as it is not installed by default.

* add arm64_notice function

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix for copilot detected bugs

---------

Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>
Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-11 08:14:32 +02:00
community-scripts-pr-app[bot] cd65eaedc0 Update CHANGELOG.md (#15041)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-11 05:35:15 +00:00
Torin 8012553578 Fix for cross-seed node version (#15025) 2026-06-11 07:34:54 +02:00
community-scripts-pr-app[bot] da33106e59 Update CHANGELOG.md (#15036)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-10 21:10:09 +00:00
Slaviša Arežina e4c320f4d1 Fix update procedure (#15033) 2026-06-10 23:09:31 +02:00
community-scripts-pr-app[bot] 2ce26925ea Update CHANGELOG.md (#15035)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-10 20:05:15 +00:00
push-app-to-main[bot] 2cfd82f2d6 Baserow (#14968)
* Add baserow (ct)

* ram

---------

Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com>
2026-06-10 22:04:45 +02:00
community-scripts-pr-app[bot] c65f19bfc1 Update CHANGELOG.md (#15022)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-09 15:17:18 +00:00
community-scripts-pr-app[bot] a289140712 Update CHANGELOG.md (#15021)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-09 15:16:46 +00:00
push-app-to-main[bot] a171dea170 Add paperclip (ct) (#14990) 2026-06-09 17:16:38 +02:00
CanbiZ (MickLesk) 8917549436 endurain: Install pytz package during backend setup (#15014) 2026-06-09 17:16:12 +02:00
community-scripts-pr-app[bot] 40f08f3f70 Update CHANGELOG.md (#15019)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-09 15:13:27 +00:00
CanbiZ (MickLesk) 5fd6f67a58 Refactor: Proxmox Backup Server - use deb822 (#15013) 2026-06-09 17:12:56 +02:00
community-scripts-pr-app[bot] 8792b8037b Update CHANGELOG.md (#15011)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-08 20:46:25 +00:00
community-scripts-pr-app[bot] b9c115acca Update CHANGELOG.md (#15010)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-08 20:29:01 +00:00
CanbiZ (MickLesk) 3f619e4286 security: Fix HTTP to HTTPS for all package and repository downloads (#15009)
Co-authored-by: Security Fix <security@community-scripts.org>
2026-06-08 22:28:40 +02:00
CanbiZ (MickLesk) 0f37e30f28 security: Fix MITM RCE vulnerability in microcode scripts (CVE) (#15007)
Co-authored-by: Security Fix <security@community-scripts.org>
2026-06-08 22:28:17 +02:00
Security Fix 34243ff62f security: Fix HTTP to HTTPS for package downloads (container-level)
- install/deconz-install.sh: Switch GPG key and repository URLs to HTTPS
- install/deconz-install.sh: Switch libssl1.1 .deb download to HTTPS with --proto flag
- install/odoo-install.sh: Switch python3-lxml-html-clean .deb download to HTTPS
- ct/odoo.sh: Switch python3-lxml-html-clean .deb download to HTTPS in update_script

Changes:
  - All http:// → https:// for package/key downloads
  - Added --proto '=https' to prevent protocol downgrade
  - Improved quoting for file variables

Impact: Prevents MITM attacks on container installations
Affected containers: deconz, odoo
Related to: security/fix-microcode-https PR (host-level fix)
2026-06-08 21:20:24 +02:00
community-scripts-pr-app[bot] 131545081c Update CHANGELOG.md (#15004)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-08 13:36:24 +00:00
Michel Roegl-Brunner f98a64b632 Move flowiseai to node 24 to alligne with upstream (#14999) 2026-06-08 15:35:50 +02:00
community-scripts-pr-app[bot] 56129f7833 Update CHANGELOG.md (#15001)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-08 11:34:16 +00:00
Stéphane FERREIRA 68af0f5b41 homelable: preserve MCP server config across updates (#14996)
* homelable: preserve MCP server config across updates

The update path runs CLEAN_INSTALL=1 fetch_and_deploy_gh_release, which
wipes /opt/homelable before redeploying. The backup/restore only covers
backend/.env and data/, so an optionally-installed MCP server (set up via
Pouzor/homelable's own scripts/lxc-mcp-install.sh, which targets exactly
this LXC and lives in /opt/homelable/mcp) loses its .env and .venv on
every update. The homelable-mcp service then keeps running on deleted
inodes and dies at the next restart.

Back up mcp/.env when present, and after the deploy restore it, rebuild
the venv (same uv pattern as the backend), restore ownership and restart
the service. Fully conditional: installs without the MCP are unaffected.

* homelable: remove comments per maintainer review
2026-06-08 13:33:50 +02:00
community-scripts-pr-app[bot] 0a21262cf1 Update CHANGELOG.md (#14997)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-08 06:33:47 +00:00
Stéphane FERREIRA b3a2fbbf98 changedetection: migrate Python install to uv venv (#14995)
The update path installed into the global interpreter with a global
--ignore-installed flag, which leaves the previous *.dist-info behind
on every dependency bump. Duplicate metadata makes pip resolve against
stale requirements (e.g. downgrading pydantic-core) and the service
crashes at the next restart. Fixes the typing_extensions workaround
(#13548) at the root: in a venv there are no Debian-owned packages to
conflict with, so neither --ignore-installed nor --break-system-packages
is needed.

Follows the existing setup_uv + venv-or-migrate pattern from
prometheus-pve-exporter and esphome. Existing installs are migrated
automatically on the next update; the systemd unit is repointed to the
venv binary.

Fixes #14987
2026-06-08 08:33:20 +02:00
community-scripts-pr-app[bot] 373b138fe0 Update CHANGELOG.md (#14994)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-07 20:56:35 +00:00
community-scripts-pr-app[bot] ed8b35f50b Update CHANGELOG.md (#14993)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-07 20:56:14 +00:00
CanbiZ (MickLesk) eab30076ca Navidrome: remove genereic filebrowser addon setup (#14991) 2026-06-07 22:56:12 +02:00
CanbiZ (MickLesk) dc2193f4bb Immich: use actual installed PostgreSQL version for vchord package (#14989) 2026-06-07 22:55:53 +02:00
40 changed files with 1489 additions and 309 deletions
+72
View File
@@ -480,8 +480,80 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details>
## 2026-06-11
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Fix for cross-seed after node upgrade [@TorinFrancis](https://github.com/TorinFrancis) ([#15025](https://github.com/community-scripts/ProxmoxVE/pull/15025))
### 💾 Core
- #### ✨ New Features
- misc scripts: add support for arm64 [@asylumexp](https://github.com/asylumexp) ([#12639](https://github.com/community-scripts/ProxmoxVE/pull/12639))
## 2026-06-10
### 🆕 New Scripts
- Baserow ([#14968](https://github.com/community-scripts/ProxmoxVE/pull/14968))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Koillection: Fix update procedure [@tremor021](https://github.com/tremor021) ([#15033](https://github.com/community-scripts/ProxmoxVE/pull/15033))
## 2026-06-09
### 🆕 New Scripts
- paperclip ([#14990](https://github.com/community-scripts/ProxmoxVE/pull/14990))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- endurain: Install pytz package during backend setup [@MickLesk](https://github.com/MickLesk) ([#15014](https://github.com/community-scripts/ProxmoxVE/pull/15014))
- #### 🔧 Refactor
- Refactor: Proxmox Backup Server - use deb822 [@MickLesk](https://github.com/MickLesk) ([#15013](https://github.com/community-scripts/ProxmoxVE/pull/15013))
## 2026-06-08
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- security: Fix HTTP to HTTPS for all package and repository downloads [@MickLesk](https://github.com/MickLesk) ([#15009](https://github.com/community-scripts/ProxmoxVE/pull/15009))
- homelable: preserve MCP server config across updates [@ferr079](https://github.com/ferr079) ([#14996](https://github.com/community-scripts/ProxmoxVE/pull/14996))
- changedetection: migrate Python install to uv venv [@ferr079](https://github.com/ferr079) ([#14995](https://github.com/community-scripts/ProxmoxVE/pull/14995))
- #### 🔧 Refactor
- Update Flowwiseai to node 24 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14999](https://github.com/community-scripts/ProxmoxVE/pull/14999))
### 🧰 Tools
- #### 🐞 Bug Fixes
- security: Fix MITM RCE vulnerability in microcode scripts (CVE) [@MickLesk](https://github.com/MickLesk) ([#15007](https://github.com/community-scripts/ProxmoxVE/pull/15007))
## 2026-06-07
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Immich: use actual installed PostgreSQL version for vchord package [@MickLesk](https://github.com/MickLesk) ([#14989](https://github.com/community-scripts/ProxmoxVE/pull/14989))
- #### 🔧 Refactor
- Navidrome: remove genereic filebrowser addon setup [@MickLesk](https://github.com/MickLesk) ([#14991](https://github.com/community-scripts/ProxmoxVE/pull/14991))
## 2026-06-06
### 🆕 New Scripts
+82
View File
@@ -0,0 +1,82 @@
#!/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/baserow/baserow
APP="Baserow"
var_tags="${var_tags:-database;nocode;spreadsheet}"
var_cpu="${var_cpu:-4}"
var_ram="${var_ram:-10240}"
var_disk="${var_disk:-15}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/baserow ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "baserow" "baserow/baserow"; then
msg_info "Stopping Services"
systemctl stop baserow-backend baserow-celery baserow-celery-beat baserow-celery-export baserow-frontend
msg_ok "Stopped Services"
msg_info "Backing up Data"
cp /opt/baserow/.env /opt/baserow.env.bak
msg_ok "Backed up Data"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "baserow" "baserow/baserow" "tarball"
msg_info "Restoring Configuration"
cp /opt/baserow.env.bak /opt/baserow/.env
rm -f /opt/baserow.env.bak
msg_ok "Restored Configuration"
msg_info "Updating Backend Dependencies"
cd /opt/baserow/backend
$STD uv sync --frozen --no-dev
msg_ok "Updated Backend Dependencies"
msg_info "Updating Frontend"
cd /opt/baserow/web-frontend
$STD npm install
$STD npm run build
msg_ok "Updated Frontend"
msg_info "Running Migrations"
cd /opt/baserow/backend
set -a && source /opt/baserow/.env && set +a
export PYTHONPATH="/opt/baserow/backend/src:/opt/baserow/premium/backend/src:/opt/baserow/enterprise/backend/src"
$STD /opt/baserow/backend/.venv/bin/python src/baserow/manage.py migrate
msg_ok "Ran Migrations"
msg_info "Starting Services"
systemctl start baserow-backend baserow-celery baserow-celery-beat baserow-celery-export baserow-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}"
+25 -6
View File
@@ -34,13 +34,32 @@ function update_script() {
NODE_VERSION="24" setup_nodejs
msg_info "Updating ${APP}"
$STD pip3 install changedetection.io --upgrade --break-system-packages --ignore-installed typing_extensions
msg_ok "Updated ${APP}"
VENV_PATH="/opt/changedetection/.venv"
CHANGEDETECTION_BIN="${VENV_PATH}/bin/changedetection.io"
msg_info "Updating Playwright"
$STD pip3 install playwright --upgrade --break-system-packages
msg_ok "Updated Playwright"
PYTHON_VERSION="3.13" setup_uv
if [[ ! -d "$VENV_PATH" || ! -x "$CHANGEDETECTION_BIN" ]]; then
msg_info "Migrating to uv/venv"
rm -rf "$VENV_PATH"
$STD uv venv --clear "$VENV_PATH"
$STD "$VENV_PATH/bin/python" -m ensurepip --upgrade
$STD "$VENV_PATH/bin/python" -m pip install --upgrade pip
$STD "$VENV_PATH/bin/python" -m pip install changedetection.io playwright
msg_ok "Migrated to uv/venv"
else
msg_info "Updating ${APP}"
$STD "$VENV_PATH/bin/python" -m pip install --upgrade changedetection.io playwright
msg_ok "Updated ${APP}"
fi
SERVICE_FILE="/etc/systemd/system/changedetection.service"
if ! grep -q "${VENV_PATH}/bin/changedetection.io" "$SERVICE_FILE"; then
msg_info "Updating systemd service"
sed -i "s|^ExecStart=.*|ExecStart=${VENV_PATH}/bin/changedetection.io -d /opt/changedetection -p 5000|" "$SERVICE_FILE"
$STD systemctl daemon-reload
msg_ok "Updated systemd service"
fi
if [[ -f /etc/systemd/system/browserless.service ]]; then
msg_info "Updating Browserless (Patience)"
+1 -1
View File
@@ -25,7 +25,7 @@ function update_script() {
check_container_storage
check_container_resources
NODE_VERSION="26" setup_nodejs
NODE_VERSION="24" setup_nodejs
ensure_dependencies build-essential
if command -v cross-seed &>/dev/null; then
+1
View File
@@ -64,6 +64,7 @@ function update_script() {
$STD poetry export -f requirements.txt --output requirements.txt --without-hashes
$STD uv venv --clear
$STD uv pip install -r requirements.txt
$STD uv pip install pytz
msg_ok "Backend Updated"
msg_info "Starting Service"
+1 -1
View File
@@ -29,7 +29,7 @@ function update_script() {
exit
fi
NODE_VERSION="20" NODE_MODULE="pnpm" setup_nodejs
NODE_VERSION="24" NODE_MODULE="pnpm" setup_nodejs
msg_info "Updating FlowiseAI (this may take some time)"
systemctl stop flowise
+6
View File
@@ -0,0 +1,6 @@
____
/ __ )____ _________ _________ _ __
/ __ / __ `/ ___/ _ \/ ___/ __ \ | /| / /
/ /_/ / /_/ (__ ) __/ / / /_/ / |/ |/ /
/_____/\__,_/____/\___/_/ \____/|__/|__/
+6
View File
@@ -0,0 +1,6 @@
____ ___
/ __ \____ _____ ___ __________/ (_)___
/ /_/ / __ `/ __ \/ _ \/ ___/ ___/ / / __ \
/ ____/ /_/ / /_/ / __/ / / /__/ / / /_/ /
/_/ \__,_/ .___/\___/_/ \___/_/_/ .___/
/_/ /_/
+6
View File
@@ -0,0 +1,6 @@
____ __ _
/ __ \____ _____/ /_(_)___
/ /_/ / __ \/ ___/ __/ /_ /
/ ____/ /_/ (__ ) /_/ / / /_
/_/ \____/____/\__/_/ /___/
+16
View File
@@ -38,6 +38,9 @@ function update_script() {
msg_info "Backing up Configuration and Data"
cp /opt/homelable/backend/.env /opt/homelable.env.bak
cp -r /opt/homelable/data /opt/homelable_data_bak
if [[ -f /opt/homelable/mcp/.env ]]; then
cp -a /opt/homelable/mcp/.env /opt/homelable-mcp.env.bak
fi
msg_ok "Backed up Configuration and Data"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "homelable" "Pouzor/homelable" "tarball" "latest" "/opt/homelable"
@@ -61,6 +64,19 @@ function update_script() {
rm -rf /opt/homelable_data_bak
msg_ok "Restored Configuration and Data"
if [[ -f /opt/homelable-mcp.env.bak ]]; then
msg_info "Restoring MCP Server"
cp -a /opt/homelable-mcp.env.bak /opt/homelable/mcp/.env
rm -f /opt/homelable-mcp.env.bak
MCP_OWNER=$(stat -c '%U' /opt/homelable/mcp/.env)
cd /opt/homelable/mcp
$STD uv venv --clear /opt/homelable/mcp/.venv
$STD uv pip install --python /opt/homelable/mcp/.venv/bin/python -r requirements.txt
chown -R "$MCP_OWNER":"$MCP_OWNER" /opt/homelable/mcp
systemctl restart homelable-mcp
msg_ok "Restored MCP Server"
fi
msg_info "Starting Service"
systemctl start homelable
msg_ok "Started Service"
+4 -4
View File
@@ -43,10 +43,9 @@ function update_script() {
fetch_and_deploy_gh_release "koillection" "benjaminjonard/koillection" "tarball"
msg_info "Updating Koillection"
cd /opt/koillection
cp -r /opt/koillection-backup/.env.local /opt/koillection
cp -r /opt/koillection-backup/public/uploads/. /opt/koillection/public/uploads/
# Ensure APP_RUNTIME is in .env.local for CLI commands (upgrades from older versions)
if ! grep -q "APP_RUNTIME" /opt/koillection/.env.local 2>/dev/null; then
# Ensure file ends with newline before appending to avoid concatenation
@@ -54,12 +53,13 @@ function update_script() {
echo 'APP_RUNTIME="Symfony\Component\Runtime\SymfonyRuntime"' >>/opt/koillection/.env.local
fi
NODE_VERSION="26" NODE_MODULE="yarn" setup_nodejs
cd /opt/koillection
export COMPOSER_ALLOW_SUPERUSER=1
export APP_RUNTIME='Symfony\Component\Runtime\SymfonyRuntime'
$STD composer install --no-dev -o --no-interaction --classmap-authoritative
$STD php bin/console doctrine:migrations:migrate --no-interaction
$STD php bin/console app:translations:dump
cd assets/
cd assets/
$STD yarn install
$STD yarn build
mkdir -p /opt/koillection/public/uploads
@@ -67,7 +67,7 @@ function update_script() {
chown -R www-data:www-data /opt/koillection/var/log
chown -R www-data:www-data /opt/koillection/public/uploads
rm -r /opt/koillection-backup
# Ensure APP_RUNTIME is set in Apache config (for upgrades from older versions)
if ! grep -q "APP_RUNTIME" /etc/apache2/sites-available/koillection.conf 2>/dev/null; then
sed -i '/<VirtualHost/a\ SetEnv APP_RUNTIME "Symfony\\Component\\Runtime\\SymfonyRuntime"' /etc/apache2/sites-available/koillection.conf
+1 -1
View File
@@ -31,7 +31,7 @@ function update_script() {
fi
ensure_dependencies python3-lxml
if ! [[ $(dpkg -s python3-lxml-html-clean 2>/dev/null) ]]; then
curl -fsSL "http://archive.ubuntu.com/ubuntu/pool/universe/l/lxml-html-clean/python3-lxml-html-clean_0.1.1-1_all.deb" -o /opt/python3-lxml-html-clean.deb
curl -fsSL --proto '=https' "https://archive.ubuntu.com/ubuntu/pool/universe/l/lxml-html-clean/python3-lxml-html-clean_0.1.1-1_all.deb" -o /opt/python3-lxml-html-clean.deb
$STD dpkg -i /opt/python3-lxml-html-clean.deb
rm -f /opt/python3-lxml-html-clean.deb
fi
+83
View File
@@ -0,0 +1,83 @@
#!/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: Fabian Pulch (fpulch)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/paperclipai/paperclip
APP="Paperclip"
var_tags="${var_tags:-ai;automation;dev-tools}"
var_cpu="${var_cpu:-4}"
var_ram="${var_ram:-8192}"
var_disk="${var_disk:-20}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/paperclip-ai ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "paperclip-ai" "paperclipai/paperclip"; then
msg_info "Stopping Service"
systemctl stop paperclip
msg_ok "Stopped Service"
msg_info "Backing up Configuration"
cp /opt/paperclip-ai/.env /opt/paperclip.env.bak
msg_ok "Backed up Configuration"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "paperclip-ai" "paperclipai/paperclip" "tarball"
msg_info "Restoring Configuration"
mv /opt/paperclip.env.bak /opt/paperclip-ai/.env
msg_ok "Restored Configuration"
msg_info "Rebuilding Paperclip"
cd /opt/paperclip-ai
export HUSKY=0
export NODE_OPTIONS="--max-old-space-size=8192"
$STD pnpm install --frozen-lockfile
$STD pnpm build
unset NODE_OPTIONS
msg_ok "Rebuilt Paperclip"
msg_info "Updating Agent CLIs"
$STD npm install -g \
@anthropic-ai/claude-code@latest \
@openai/codex@latest
msg_ok "Updated Agent CLIs"
msg_info "Running Database Migrations"
set -a && source /opt/paperclip-ai/.env && set +a
$STD pnpm db:migrate
msg_ok "Ran Database Migrations"
msg_info "Starting Service"
systemctl start paperclip
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}:3100${CL}"
+83
View File
@@ -0,0 +1,83 @@
#!/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/gitroomhq/postiz-app
APP="Postiz"
var_tags="${var_tags:-social-media;scheduling;automation}"
var_cpu="${var_cpu:-4}"
var_ram="${var_ram:-8192}"
var_disk="${var_disk:-20}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/postiz ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "postiz" "gitroomhq/postiz-app"; then
msg_info "Stopping Services"
systemctl stop postiz-orchestrator postiz-frontend postiz-backend
msg_ok "Stopped Services"
msg_info "Backing up Data"
cp /opt/postiz/.env /opt/postiz_env.bak
cp -r /opt/postiz/uploads /opt/postiz_uploads.bak 2>/dev/null || true
msg_ok "Backed up Data"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "postiz" "gitroomhq/postiz-app" "tarball"
msg_info "Building Application"
cd /opt/postiz
cp /opt/postiz_env.bak /opt/postiz/.env
set -a && source /opt/postiz/.env && set +a
export NODE_OPTIONS="--max-old-space-size=4096"
$STD pnpm install
$STD pnpm run build
unset NODE_OPTIONS
msg_ok "Built Application"
msg_info "Running Database Migrations"
cd /opt/postiz
$STD pnpm run prisma-db-push
msg_ok "Ran Database Migrations"
msg_info "Restoring Data"
mkdir -p /opt/postiz/uploads
cp -r /opt/postiz_uploads.bak/. /opt/postiz/uploads 2>/dev/null || true
rm -f /opt/postiz_env.bak
rm -rf /opt/postiz_uploads.bak
msg_ok "Restored Data"
msg_info "Starting Services"
systemctl start postiz-backend postiz-frontend postiz-orchestrator
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}${CL}"
+194
View File
@@ -0,0 +1,194 @@
#!/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/baserow/baserow
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 \
libpq-dev \
redis-server \
gettext \
xmlsec1 \
git \
libffi-dev \
libssl-dev \
zlib1g-dev \
libjpeg-dev \
libxml2-dev \
libxslt-dev \
python3-dev
msg_ok "Installed Dependencies"
PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql
PG_DB_NAME="baserow" PG_DB_USER="baserow" setup_postgresql_db
NODE_VERSION="24" setup_nodejs
setup_uv
fetch_and_deploy_gh_release "baserow" "baserow/baserow" "tarball"
msg_info "Installing Backend Dependencies"
cd /opt/baserow/backend
UV_LINK_MODE="copy"
$STD uv sync --frozen --no-dev
msg_ok "Installed Backend Dependencies"
msg_info "Building Frontend"
cd /opt/baserow/web-frontend
NODE_OPTIONS="--max-old-space-size=4096" $STD npm install --legacy-peer-deps
NODE_OPTIONS="--max-old-space-size=4096" $STD npm run build
msg_ok "Built Frontend"
msg_info "Configuring Baserow"
SECRET_KEY=$(openssl rand -base64 64 | tr -dc 'a-zA-Z0-9' | head -c50)
cat <<EOF >/opt/baserow/.env
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=${PG_DB_NAME}
DATABASE_USER=${PG_DB_USER}
DATABASE_PASSWORD=${PG_DB_PASS}
SECRET_KEY=${SECRET_KEY}
BASEROW_JWT_SIGNING_KEY=${SECRET_KEY}
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_PROTOCOL=redis
BASEROW_PUBLIC_URL=http://${LOCAL_IP}
PUBLIC_BACKEND_URL=http://${LOCAL_IP}:8000
PUBLIC_WEB_FRONTEND_URL=http://${LOCAL_IP}:3000
PRIVATE_BACKEND_URL=http://localhost:8000
PRIVATE_WEB_FRONTEND_URL=http://localhost:3000
BASEROW_DISABLE_PUBLIC_URL_CHECK=true
DJANGO_SETTINGS_MODULE=baserow.config.settings.base
BASEROW_AMOUNT_OF_WORKERS=2
MEDIA_ROOT=/opt/baserow/media
EOF
mkdir -p /opt/baserow/media
msg_ok "Configured Baserow"
msg_info "Running Migrations"
cd /opt/baserow/backend
set -a && source /opt/baserow/.env && set +a
export PYTHONPATH="/opt/baserow/backend/src:/opt/baserow/premium/backend/src:/opt/baserow/enterprise/backend/src"
$STD /opt/baserow/backend/.venv/bin/python src/baserow/manage.py migrate
$STD /opt/baserow/backend/.venv/bin/python src/baserow/manage.py sync_templates
msg_ok "Ran Migrations"
msg_info "Creating Services"
cat <<EOF >/etc/systemd/system/baserow-backend.service
[Unit]
Description=Baserow Backend
After=network.target postgresql.service redis-server.service
Requires=postgresql.service redis-server.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/baserow/backend
EnvironmentFile=/opt/baserow/.env
Environment=PYTHONPATH=/opt/baserow/backend/src:/opt/baserow/premium/backend/src:/opt/baserow/enterprise/backend/src
ExecStart=/opt/baserow/backend/.venv/bin/gunicorn baserow.config.asgi:application -w 2 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/baserow-celery.service
[Unit]
Description=Baserow Celery Worker
After=network.target postgresql.service redis-server.service
Requires=postgresql.service redis-server.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/baserow/backend
EnvironmentFile=/opt/baserow/.env
Environment=PYTHONPATH=/opt/baserow/backend/src:/opt/baserow/premium/backend/src:/opt/baserow/enterprise/backend/src
ExecStart=/opt/baserow/backend/.venv/bin/celery -A baserow worker -l INFO
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/baserow-celery-export.service
[Unit]
Description=Baserow Celery Export Worker
After=network.target postgresql.service redis-server.service
Requires=postgresql.service redis-server.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/baserow/backend
EnvironmentFile=/opt/baserow/.env
Environment=PYTHONPATH=/opt/baserow/backend/src:/opt/baserow/premium/backend/src:/opt/baserow/enterprise/backend/src
ExecStart=/opt/baserow/backend/.venv/bin/celery -A baserow worker -l INFO -Q export
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/baserow-celery-beat.service
[Unit]
Description=Baserow Celery Beat Scheduler
After=network.target postgresql.service redis-server.service
Requires=postgresql.service redis-server.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/baserow/backend
EnvironmentFile=/opt/baserow/.env
Environment=PYTHONPATH=/opt/baserow/backend/src:/opt/baserow/premium/backend/src:/opt/baserow/enterprise/backend/src
ExecStart=/opt/baserow/backend/.venv/bin/celery -A baserow beat -l INFO -S redbeat.RedBeatScheduler
Restart=on-failure
RestartSec=5
KillSignal=SIGQUIT
[Install]
WantedBy=multi-target.target
EOF
cat <<EOF >/etc/systemd/system/baserow-frontend.service
[Unit]
Description=Baserow Web Frontend
After=network.target baserow-backend.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/baserow/web-frontend
EnvironmentFile=/opt/baserow/.env
Environment=HOST=0.0.0.0
Environment=PORT=3000
ExecStart=/usr/bin/node --import ./env-remap.mjs .output/server/index.mjs
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now redis-server baserow-backend baserow-celery baserow-celery-export baserow-celery-beat baserow-frontend
msg_ok "Created Services"
motd_ssh
customize
cleanup_lxc
+8 -11
View File
@@ -43,19 +43,16 @@ $STD apt-get install -y \
ca-certificates
msg_ok "Installed Dependencies"
msg_info "Setup Python3"
$STD apt-get install -y \
python3 \
python3-dev \
python3-pip
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
msg_ok "Setup Python3"
PYTHON_VERSION="3.13" setup_uv
NODE_VERSION="24" setup_nodejs
msg_info "Installing Change Detection"
mkdir /opt/changedetection
$STD pip3 install changedetection.io
mkdir -p /opt/changedetection
$STD uv venv --clear /opt/changedetection/.venv
$STD /opt/changedetection/.venv/bin/python -m ensurepip --upgrade
$STD /opt/changedetection/.venv/bin/python -m pip install --upgrade pip
$STD /opt/changedetection/.venv/bin/python -m pip install changedetection.io
cat <<EOF >/opt/changedetection/.env
WEBDRIVER_URL=http://127.0.0.1:4444/wd/hub
PLAYWRIGHT_DRIVER_URL=ws://localhost:3000/chrome?launch=eyJkZWZhdWx0Vmlld3BvcnQiOnsiaGVpZ2h0Ijo3MjAsIndpZHRoIjoxMjgwfSwiaGVhZGxlc3MiOmZhbHNlLCJzdGVhbHRoIjp0cnVlfQ==&blockAds=true
@@ -64,7 +61,7 @@ msg_ok "Installed Change Detection"
msg_info "Installing Browserless & Playwright"
mkdir /opt/browserless
$STD python3 -m pip install playwright
$STD /opt/changedetection/.venv/bin/python -m pip install playwright
$STD git clone https://github.com/browserless/chrome /opt/browserless
$STD npm ci --include=optional --include=dev --prefix /opt/browserless
$STD /opt/browserless/node_modules/playwright-core/cli.js install --with-deps &>/dev/null
@@ -121,7 +118,7 @@ Wants=browserless.service
Type=simple
EnvironmentFile=/opt/changedetection/.env
WorkingDirectory=/opt/changedetection
ExecStart=changedetection.io -d /opt/changedetection -p 5000
ExecStart=/opt/changedetection/.venv/bin/changedetection.io -d /opt/changedetection -p 5000
[Install]
WantedBy=multi-user.target
+1 -1
View File
@@ -17,7 +17,7 @@ msg_info "Installing Dependencies"
$STD apt install -y build-essential
msg_ok "Installed Dependencies"
NODE_VERSION="26" setup_nodejs
NODE_VERSION="24" setup_nodejs
msg_info "Setup Cross-Seed"
$STD npm install cross-seed@latest -g
+4 -4
View File
@@ -16,14 +16,14 @@ update_os
msg_info "Setting Phoscon Repository"
setup_deb822_repo \
"deconz" \
"http://phoscon.de/apt/deconz.pub.key" \
"http://phoscon.de/apt/deconz" \
"https://phoscon.de/apt/deconz.pub.key" \
"https://phoscon.de/apt/deconz" \
"generic"
msg_ok "Setup Phoscon Repository"
msg_info "Installing deConz"
libssl=$(curl -fsSL "http://security.ubuntu.com/ubuntu/pool/main/o/openssl/" | grep -o 'libssl1\.1_1\.1\.1f-1ubuntu2\.2[^"]*amd64\.deb' | head -n1)
curl -fsSL "http://security.ubuntu.com/ubuntu/pool/main/o/openssl/$libssl" -o "$libssl"
libssl=$(curl -fsSL --proto '=https' "https://security.ubuntu.com/ubuntu/pool/main/o/openssl/" | grep -o 'libssl1\.1_1\.1\.1f-1ubuntu2\.2[^"]*amd64\.deb' | head -n1)
curl -fsSL --proto '=https' "https://security.ubuntu.com/ubuntu/pool/main/o/openssl/$libssl" -o "$libssl"
$STD dpkg -i "$libssl"
$STD apt install -y deconz
rm -rf "$libssl"
+1
View File
@@ -88,6 +88,7 @@ $STD poetry self add poetry-plugin-export
$STD poetry export -f requirements.txt --output requirements.txt --without-hashes
$STD uv venv --clear
$STD uv pip install -r requirements.txt
$STD uv pip install pytz
msg_ok "Setup Backend"
msg_info "Creating Service"
+1 -1
View File
@@ -17,7 +17,7 @@ msg_info "Installing Dependencies"
$STD apt install -y build-essential python3-dev
msg_ok "Installed Dependencies"
NODE_VERSION="20" setup_nodejs
NODE_VERSION="24" setup_nodejs
msg_info "Installing FlowiseAI (Patience)"
$STD npm install -g flowise \
+1 -1
View File
@@ -15,7 +15,7 @@ update_os
msg_info "Setup GlobaLeaks"
DISTRO_CODENAME="$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)"
curl -fsSL https://deb.globaleaks.org/globaleaks.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/globaleaks.gpg
echo "deb [signed-by=/etc/apt/trusted.gpg.d/globaleaks.gpg] http://deb.globaleaks.org $DISTRO_CODENAME/" >/etc/apt/sources.list.d/globaleaks.list
echo "deb [signed-by=/etc/apt/trusted.gpg.d/globaleaks.gpg] https://deb.globaleaks.org $DISTRO_CODENAME/" >/etc/apt/sources.list.d/globaleaks.list
echo 'APPARMOR_SANDBOXING=0' >/etc/default/globaleaks
$STD apt update
$STD apt -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold install globaleaks
+6 -3
View File
@@ -149,10 +149,13 @@ msg_ok "Installed packages from Debian Testing repo"
setup_uv
PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql
VCHORD_RELEASE="0.5.3"
fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" "${VCHORD_RELEASE}" "/tmp" "postgresql-16-vchord_*_amd64.deb"
ACTUAL_PG_VERSION=$(ls /etc/postgresql/ 2>/dev/null | sort -V | tail -1)
ACTUAL_PG_VERSION=${ACTUAL_PG_VERSION:-16}
sed -i "s/^#shared_preload.*/shared_preload_libraries = 'vchord.so'/" /etc/postgresql/16/main/postgresql.conf
VCHORD_RELEASE="0.5.3"
fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" "${VCHORD_RELEASE}" "/tmp" "postgresql-${ACTUAL_PG_VERSION}-vchord_*_amd64.deb"
sed -i "s/^#shared_preload.*/shared_preload_libraries = 'vchord.so'/" /etc/postgresql/${ACTUAL_PG_VERSION}/main/postgresql.conf
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
+1 -1
View File
@@ -20,7 +20,7 @@ $STD apt install -y \
mediainfo
cat <<EOF >/etc/apt/sources.list.d/non-free.list
deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb https://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
EOF
$STD apt update
$STD apt install -y unrar
-5
View File
@@ -23,11 +23,6 @@ msg_info "Starting Navidrome"
systemctl enable -q --now navidrome
msg_ok "Started Navidrome"
read -p "${TAB3}Do you want to install filebrowser addon? (y/n) " -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]; then
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/filebrowser.sh)"
fi
motd_ssh
customize
cleanup_lxc
+1 -1
View File
@@ -15,7 +15,7 @@ update_os
msg_info "Installing Dependencies"
$STD apt install -y python3-lxml wkhtmltopdf
curl -fsSL "http://archive.ubuntu.com/ubuntu/pool/universe/l/lxml-html-clean/python3-lxml-html-clean_0.1.1-1_all.deb" -o /opt/python3-lxml-html-clean.deb
curl -fsSL --proto '=https' "https://archive.ubuntu.com/ubuntu/pool/universe/l/lxml-html-clean/python3-lxml-html-clean_0.1.1-1_all.deb" -o /opt/python3-lxml-html-clean.deb
$STD dpkg -i /opt/python3-lxml-html-clean.deb
msg_ok "Installed Dependencies"
+162
View File
@@ -0,0 +1,162 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Fabian Pulch (fpulch)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/paperclipai/paperclip
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt install -y \
build-essential \
git \
ripgrep
msg_ok "Installed Dependencies"
NODE_VERSION="24" NODE_MODULE="pnpm" setup_nodejs
PG_VERSION="17" setup_postgresql
PG_DB_NAME="paperclip" PG_DB_USER="paperclip" setup_postgresql_db
fetch_and_deploy_gh_release "paperclip-ai" "paperclipai/paperclip" "tarball"
msg_info "Building Paperclip"
cd /opt/paperclip-ai
export HUSKY=0
export NODE_OPTIONS="--max-old-space-size=8192"
$STD pnpm install --frozen-lockfile
$STD pnpm build
unset NODE_OPTIONS
msg_ok "Built Paperclip"
msg_info "Installing Agent CLIs"
$STD npm install -g \
@anthropic-ai/claude-code@latest \
@openai/codex@latest
msg_ok "Installed Agent CLIs"
msg_info "Configuring Paperclip"
PAPERCLIP_HOME="/opt/paperclip-data"
PAPERCLIP_CONFIG="${PAPERCLIP_HOME}/instances/default/config.json"
mkdir -p /opt/paperclip-data
mkdir -p /root/.claude /root/.codex
BETTER_AUTH_SECRET=$(openssl rand -hex 32)
cat <<EOF >/opt/paperclip-ai/.env
DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@127.0.0.1:5432/${PG_DB_NAME}
HOST=0.0.0.0
PORT=3100
SERVE_UI=true
PAPERCLIP_HOME=${PAPERCLIP_HOME}
PAPERCLIP_CONFIG=${PAPERCLIP_CONFIG}
PAPERCLIP_INSTANCE_ID=default
PAPERCLIP_DEPLOYMENT_MODE=authenticated
PAPERCLIP_DEPLOYMENT_EXPOSURE=private
PAPERCLIP_PUBLIC_URL=http://${LOCAL_IP}:3100
BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
EOF
msg_ok "Configured Paperclip"
msg_info "Running Database Migrations"
set -a && source /opt/paperclip-ai/.env && set +a
$STD pnpm db:migrate
msg_ok "Ran Database Migrations"
msg_info "Bootstrapping Paperclip"
PAPERCLIP_ONBOARD_LOG=/opt/paperclip-ai/paperclip-onboard.log
PAPERCLIP_BOOTSTRAP_LOG=/opt/paperclip-ai/paperclip-bootstrap.log
for PAPERCLIP_ONBOARD_CMD in \
"pnpm paperclipai onboard --yes --bind lan" \
"pnpm paperclipai onboard --yes"; do
rm -f "$PAPERCLIP_ONBOARD_LOG"
setsid env \
PAPERCLIP_HOME="$PAPERCLIP_HOME" \
PAPERCLIP_CONFIG="$PAPERCLIP_CONFIG" \
bash -c 'cd /opt/paperclip-ai && exec "$@"' _ $PAPERCLIP_ONBOARD_CMD \
>"$PAPERCLIP_ONBOARD_LOG" 2>&1 &
PAPERCLIP_ONBOARD_PID=$!
for _ in {1..60}; do
if [[ -f "$PAPERCLIP_CONFIG" ]]; then
break
fi
if ! kill -0 "$PAPERCLIP_ONBOARD_PID" 2>/dev/null; then
break
fi
sleep 2
done
if kill -0 "$PAPERCLIP_ONBOARD_PID" 2>/dev/null; then
kill -- -"${PAPERCLIP_ONBOARD_PID}" >/dev/null 2>&1 || true
wait "$PAPERCLIP_ONBOARD_PID" 2>/dev/null || true
fi
[[ -f "$PAPERCLIP_CONFIG" ]] && break
if ! grep -q "unknown option '--bind'" "$PAPERCLIP_ONBOARD_LOG"; then
break
fi
msg_info "Retrying Paperclip Onboarding"
done
if [[ ! -f "$PAPERCLIP_CONFIG" ]]; then
msg_error "Failed to bootstrap Paperclip"
exit 1
fi
if grep -q 'authenticated' $PAPERCLIP_CONFIG; then
pnpm paperclipai auth bootstrap-ceo >"$PAPERCLIP_BOOTSTRAP_LOG" 2>&1 || true
PAPERCLIP_INVITE_URL=$(awk -F'Invite URL: ' '/Invite URL:/ {print $2; exit}' "$PAPERCLIP_BOOTSTRAP_LOG")
PAPERCLIP_INVITE_EXPIRY=$(awk -F'Expires: ' '/Expires:/ {print $2; exit}' "$PAPERCLIP_BOOTSTRAP_LOG")
if [[ -n "$PAPERCLIP_INVITE_URL" ]]; then
cat <<EOF >>~/paperclip.creds
Paperclip Admin Invite
Invite URL: ${PAPERCLIP_INVITE_URL}
Expires: ${PAPERCLIP_INVITE_EXPIRY}
EOF
msg_ok "Generated Paperclip CEO Invite"
echo -e "${INFO}${YW} Open this invite URL to finish Paperclip admin setup:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}${PAPERCLIP_INVITE_URL}${CL}"
[[ -n "$PAPERCLIP_INVITE_EXPIRY" ]] && echo -e "${TAB}${INFO}${YW}Invite expires: ${PAPERCLIP_INVITE_EXPIRY}${CL}"
else
msg_warn "Paperclip authenticated mode is enabled, but no CEO invite was generated automatically"
fi
else
msg_info "Paperclip Bootstrapped in Local Trusted Mode"
fi
rm -f "$PAPERCLIP_ONBOARD_LOG" "$PAPERCLIP_BOOTSTRAP_LOG"
msg_ok "Bootstrapped Paperclip"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/paperclip.service
[Unit]
Description=Paperclip
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/paperclip-ai
EnvironmentFile=/opt/paperclip-ai/.env
Environment=HOME=/root
Environment=CODEX_HOME=/root/.codex
Environment=PATH=/root/.local/bin:/usr/local/bin:/usr/bin:/bin
Environment=DISABLE_AUTOUPDATER=1
ExecStart=/usr/bin/env pnpm paperclipai run
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now paperclip
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
+251
View File
@@ -0,0 +1,251 @@
#!/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/gitroomhq/postiz-app
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 \
redis-server \
nginx
msg_ok "Installed Dependencies"
PG_VERSION="17" setup_postgresql
PG_DB_NAME="postiz" PG_DB_USER="postiz" setup_postgresql_db
NODE_VERSION="24" setup_nodejs
fetch_and_deploy_gh_release "temporal" "temporalio/cli" "prebuild" "latest" "/opt/temporal" "temporal_cli_*_linux_amd64.tar.gz"
chmod +x /opt/temporal/temporal
fetch_and_deploy_gh_release "postiz" "gitroomhq/postiz-app" "tarball"
msg_info "Installing pnpm"
PNPM_VERSION=$(sed -n 's/.*"packageManager":\s*"pnpm@\([^"]*\)".*/\1/p' /opt/postiz/package.json)
$STD npm install -g "pnpm@${PNPM_VERSION}"
msg_ok "Installed pnpm"
msg_info "Configuring Application"
JWT_SECRET=$(openssl rand -base64 32)
mkdir -p /opt/postiz/uploads
cat <<EOF >/opt/postiz/.env
DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}
REDIS_URL=redis://localhost:6379
JWT_SECRET=${JWT_SECRET}
MAIN_URL=http://${LOCAL_IP}
FRONTEND_URL=http://${LOCAL_IP}
NEXT_PUBLIC_BACKEND_URL=http://${LOCAL_IP}/api
BACKEND_INTERNAL_URL=http://localhost:3000
NOT_SECURED=true
TEMPORAL_ADDRESS=localhost:7233
IS_GENERAL=true
STORAGE_PROVIDER=local
UPLOAD_DIRECTORY=/opt/postiz/uploads
NEXT_PUBLIC_UPLOAD_DIRECTORY=/uploads
NX_ADD_PLUGINS=false
EOF
msg_ok "Configured Application"
msg_info "Building Application"
cd /opt/postiz
set -a && source /opt/postiz/.env && set +a
export NODE_OPTIONS="--max-old-space-size=4096"
$STD pnpm install
$STD pnpm run build
unset NODE_OPTIONS
msg_ok "Built Application"
msg_info "Running Database Migrations"
cd /opt/postiz
set -a && source /opt/postiz/.env && set +a
$STD pnpm run prisma-db-push
msg_ok "Ran Database Migrations"
msg_info "Creating Services"
PNPM_BIN="$(command -v pnpm)"
cat <<EOF >/etc/systemd/system/postiz-temporal.service
[Unit]
Description=Temporal Dev Server (Postiz)
After=network.target
[Service]
Type=simple
User=root
ExecStart=/opt/temporal/temporal server start-dev --db-filename /opt/temporal/temporal.db --log-format json --log-level warn
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/postiz-backend.service
[Unit]
Description=Postiz Backend
After=network.target postgresql.service redis-server.service postiz-temporal.service
Requires=postgresql.service redis-server.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/postiz
EnvironmentFile=/opt/postiz/.env
ExecStart=${PNPM_BIN} run start:prod:backend
Environment=NODE_OPTIONS=--max-old-space-size=512
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/postiz-frontend.service
[Unit]
Description=Postiz Frontend
After=network.target postiz-backend.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/postiz
EnvironmentFile=/opt/postiz/.env
Environment=PORT=4200
ExecStart=${PNPM_BIN} run start:prod:frontend
Environment=NODE_OPTIONS=--max-old-space-size=512
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/postiz-orchestrator.service
[Unit]
Description=Postiz Orchestrator
After=network.target postiz-temporal.service postiz-backend.service
Requires=postiz-temporal.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/postiz
EnvironmentFile=/opt/postiz/.env
ExecStart=${PNPM_BIN} run start:prod:orchestrator
Environment=NODE_OPTIONS=--max-old-space-size=384
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now redis-server postiz-temporal postiz-backend postiz-frontend postiz-orchestrator
msg_ok "Created Services"
msg_info "Creating Helper Scripts"
cat <<'EOF' >/usr/local/bin/postiz-rebuild
#!/usr/bin/env bash
echo "=== Postiz Rebuild ==="
echo "Stopping services..."
systemctl stop postiz-orchestrator postiz-frontend postiz-backend
cd /opt/postiz
set -a && source /opt/postiz/.env && set +a
export NODE_OPTIONS="--max-old-space-size=4096"
echo "Building application (this may take a while)..."
pnpm run build
BUILD_RC=$?
unset NODE_OPTIONS
if [[ $BUILD_RC -ne 0 ]]; then
echo "ERROR: Build failed! Check the output above."
echo "Starting services with previous build..."
systemctl start postiz-backend postiz-frontend postiz-orchestrator
exit 1
fi
echo "Running database migrations..."
pnpm run prisma-db-push
echo "Starting services..."
systemctl start postiz-backend postiz-frontend postiz-orchestrator
echo "=== Rebuild complete ==="
EOF
chmod +x /usr/local/bin/postiz-rebuild
msg_ok "Created Helper Scripts"
msg_info "Configuring Nginx"
cat <<EOF >/etc/nginx/sites-available/postiz
server {
listen 80 default_server;
server_name _;
client_max_body_size 100M;
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
location /api/ {
proxy_pass http://127.0.0.1:3000/;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header Reload \$http_reload;
proxy_set_header Onboarding \$http_onboarding;
proxy_set_header Activate \$http_activate;
proxy_set_header Auth \$http_auth;
proxy_set_header Showorg \$http_showorg;
proxy_set_header Impersonate \$http_impersonate;
proxy_set_header Accept-Language \$http_accept_language;
}
location /uploads/ {
alias /opt/postiz/uploads/;
}
location / {
proxy_pass http://127.0.0.1:4200/;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header Reload \$http_reload;
proxy_set_header Onboarding \$http_onboarding;
proxy_set_header Activate \$http_activate;
proxy_set_header Auth \$http_auth;
proxy_set_header Showorg \$http_showorg;
proxy_set_header Impersonate \$http_impersonate;
proxy_set_header Accept-Language \$http_accept_language;
proxy_set_header i18next \$http_i18next;
}
}
EOF
ln -sf /etc/nginx/sites-available/postiz /etc/nginx/sites-enabled/postiz
rm -f /etc/nginx/sites-enabled/default
$STD nginx -t
systemctl enable -q nginx
systemctl reload -q nginx
msg_ok "Configured Nginx"
motd_ssh
customize
cleanup_lxc
+6 -5
View File
@@ -14,11 +14,12 @@ network_check
update_os
msg_info "Installing Proxmox Backup Server"
curl -fsSL "https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg" -o "/etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg"
cat <<EOF >>/etc/apt/sources.list
deb http://download.proxmox.com/debian/pbs trixie pbs-no-subscription
EOF
$STD apt update
setup_deb822_repo \
"proxmox-backup-server" \
"https://enterprise.proxmox.com/debian/proxmox-archive-keyring-trixie.gpg" \
"http://download.proxmox.com/debian/pbs" \
"trixie" \
"pbs-no-subscription"
export DEBIAN_FRONTEND=noninteractive
export IFUPDOWN2_NO_IFRELOAD=1
$STD apt install -y proxmox-backup-server
+1 -1
View File
@@ -196,7 +196,7 @@ explain_exit_code() {
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)" ;;
106) echo "Validation: Unsupported architecture (requires amd64 or arm64)" ;;
107) echo "Validation: Kernel key parameters unreadable" ;;
108) echo "Validation: Kernel key limits exceeded" ;;
109) echo "Proxmox: No available container ID after max attempts" ;;
+343 -222
View File
@@ -52,6 +52,11 @@ variables() {
# as "/tmp/${NSAPP}-${CTID}-${SESSION_ID}.log" (requires CTID, not available here)
CTTYPE="${CTTYPE:-${CT_TYPE:-1}}"
# ARM64 Template default variables
DEBIAN_DEFAULT_CODENAME="trixie"
UBUNTU_DEFAULT_CODENAME="noble"
ALPINE_DEFAULT_VERSION="3.23"
# Parse dev_mode early
parse_dev_mode
@@ -1936,7 +1941,7 @@ advanced_settings() {
# ═══════════════════════════════════════════════════════════════════════════
# STEP 2: Root Password
# ═════════════════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════════════════
2)
if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "ROOT PASSWORD" \
@@ -3046,6 +3051,9 @@ echo_default() {
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}"
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
if [[ "$(dpkg --print-architecture)" == "arm64" ]]; then
echo -e "${INFO}${BOLD}${DGN}Architecture: ${BGN}arm64${CL}"
fi
if [[ -n "${var_gpu:-}" && "${var_gpu}" == "yes" ]]; then
echo -e "${GPU}${BOLD}${DGN}GPU Passthrough: ${BGN}Enabled${CL}"
fi
@@ -3082,7 +3090,9 @@ install_script() {
pve_check
shell_check
root_check
ensure_whiptail
arch_check
arm64_notice
ssh_check
maxkeys_check
diagnostics_check
@@ -4355,19 +4365,23 @@ EOF
msg_warn "Skipping timezone setup zone '$tz' not found in container"
fi
local _base_pkgs="sudo curl mc gnupg2 jq"
if [[ "${ARCH:-amd64}" == "arm64" ]]; then
_base_pkgs+=" openssh-server wget gcc"
fi
# Detect broken DNS resolver (e.g. Tailscale MagicDNS) and inject public DNS
if ! pct exec "$CTID" -- bash -c "getent hosts deb.debian.org >/dev/null 2>&1 && getent hosts archive.ubuntu.com >/dev/null 2>&1"; then
msg_warn "APT repository DNS resolution failed in container, injecting public DNS servers"
pct exec "$CTID" -- bash -c "echo -e 'nameserver 8.8.8.8\nnameserver 1.1.1.1' >/etc/resolv.conf"
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 2>&1 && apt-get install -y ${_base_pkgs} 2>&1" >>"$BUILD_LOG" 2>&1 || {
local failed_mirror
failed_mirror=$(pct exec "$CTID" -- bash -c "grep -m1 -oP '(?<=URIs: https?://)[^/]+' /etc/apt/sources.list.d/debian.sources 2>/dev/null || grep -m1 -oP '(?<=deb https?://)[^/]+' /etc/apt/sources.list 2>/dev/null" 2>/dev/null || echo "unknown")
msg_warn "apt-get update failed (${failed_mirror}), trying alternate mirrors..."
local mirror_exit=0
pct exec "$CTID" -- bash -c '
APT_BASE="sudo curl mc gnupg2 jq"
pct exec "$CTID" -- env APT_BASE="$_base_pkgs" bash -c '
DISTRO=$(. /etc/os-release 2>/dev/null && echo "$ID" || echo "debian")
if [ "$DISTRO" = "ubuntu" ]; then
@@ -4477,7 +4491,7 @@ EOF
[ -f \"\$src\" ] && sed -i \"s|URIs: http[s]*://[^/]*/|URIs: http://${custom_mirror}/|g; s|deb http[s]*://[^/]*/|deb http://${custom_mirror}/|g\" \"\$src\"
done
rm -rf /var/lib/apt/lists/*
apt-get update >/dev/null 2>&1 && apt-get install -y sudo curl mc gnupg2 jq >/dev/null 2>&1
apt-get update >/dev/null 2>&1 && apt-get install -y ${_base_pkgs} >/dev/null 2>&1
" && break
msg_warn "Mirror '${custom_mirror}' also failed. Try another or type 'skip'."
done
@@ -4517,7 +4531,9 @@ EOF
# 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 _install_script
_install_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh")"
lxc-attach -n "$CTID" -- bash -c "$_install_script"
local lxc_exit=$?
unset CONTAINER_INSTALLING
@@ -4912,7 +4928,9 @@ EOF
# Re-run install script in existing container (don't destroy/recreate)
set +Eeuo pipefail
trap - ERR
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh)"
local _install_script
_install_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh")"
lxc-attach -n "$CTID" -- bash -c "$_install_script"
local apt_retry_exit=$?
set -Eeuo pipefail
trap 'error_handler' ERR
@@ -5670,6 +5688,72 @@ create_lxc_container() {
esac
}
ARCH="$(dpkg --print-architecture)"
# Maps OS type + version to the release variant name used by ARM64 template sources.
arm64_template_variant() {
case "$1:$2" in
debian:12) echo "bookworm" ;;
debian:13) echo "trixie" ;;
debian:) echo "$DEBIAN_DEFAULT_CODENAME" ;;
ubuntu:24.04) echo "noble" ;;
ubuntu:26.04) echo "questing" ;;
ubuntu:) echo "$UBUNTU_DEFAULT_CODENAME" ;;
alpine:*) echo "${2:-$ALPINE_DEFAULT_VERSION}" ;;
*) return 1 ;;
esac
}
# Downloads an ARM64 LXC rootfs template to $1.
# Debian: fetches latest release from community-scripts/debian-arm64-lxc on GitHub.
# Others: fetches from jenkins.linuxcontainers.org.
download_arm64_template() {
local dest="$1" url
mkdir -p "$(dirname "$dest")" || {
msg_error "Cannot create template dir."
exit 207
}
if [[ "$PCT_OSTYPE" == "debian" ]]; then
url=$(
curl -fsSL "https://api.github.com/repos/community-scripts/debian-arm64-lxc/releases/latest" |
jq -r --arg v "$CUSTOM_TEMPLATE_VARIANT" \
'.assets[].browser_download_url | select(test("debian-" + $v + "-arm64-rootfs\\.tar\\.xz$"))' |
head -n1
)
[[ -n "$url" ]] || {
msg_error "Could not find Debian ${CUSTOM_TEMPLATE_VARIANT} ARM64 template URL."
exit 207
}
else
url="https://jenkins.linuxcontainers.org/job/image-${PCT_OSTYPE}/architecture=arm64,release=${CUSTOM_TEMPLATE_VARIANT},variant=default/lastStableBuild/artifact/rootfs.tar.xz"
fi
msg_info "Downloading ${PCT_OSTYPE^} ${CUSTOM_TEMPLATE_VARIANT} ARM64 template"
if ! curl -fsSL -o "$dest" "$url"; then
msg_error "Failed to download ARM64 template from: $url"
exit 208
fi
msg_ok "Downloaded ARM64 LXC template"
}
download_template() {
local dest="${1:-$TEMPLATE_PATH}"
if [[ "$ARCH" == "arm64" ]]; then
download_arm64_template "$dest"
else
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 || {
msg_error "Failed to download template '$TEMPLATE' to storage '$TEMPLATE_STORAGE'"
exit 222
}
fi
}
# ------------------------------------------------------------------------------
# Required input variables
# ------------------------------------------------------------------------------
@@ -5836,153 +5920,120 @@ create_lxc_container() {
# ------------------------------------------------------------------------------
# Template discovery & validation
# ------------------------------------------------------------------------------
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
case "$PCT_OSTYPE" in
debian | ubuntu) TEMPLATE_PATTERN="-standard_" ;;
alpine | fedora | rocky | centos) TEMPLATE_PATTERN="-default_" ;;
*) TEMPLATE_PATTERN="" ;;
esac
CUSTOM_TEMPLATE_VARIANT=""
msg_info "Searching for template '$TEMPLATE_SEARCH'"
if [[ "$ARCH" == "arm64" ]]; then
# ARM64: use custom template download from linuxcontainers.org / GitHub
msg_info "Preparing ARM64 template"
# Initialize variables
ONLINE_TEMPLATE=""
ONLINE_TEMPLATES=()
CUSTOM_TEMPLATE_VARIANT=$(arm64_template_variant "$PCT_OSTYPE" "${PCT_OSVERSION:-}") || {
msg_error "No ARM64 template mapping for ${PCT_OSTYPE} ${PCT_OSVERSION:-latest}"
exit 207
}
# Step 1: Check local templates first (instant)
mapfile -t LOCAL_TEMPLATES < <(
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
awk -v search="${TEMPLATE_SEARCH}" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
sed 's|.*/||' | sort -t - -k 2 -V
)
TEMPLATE="${PCT_OSTYPE}-${CUSTOM_TEMPLATE_VARIANT}-rootfs.tar.xz"
TEMPLATE_SOURCE="custom-arm64"
# Step 2: If local template found, use it immediately (skip pveam update)
if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
TEMPLATE="${LOCAL_TEMPLATES[-1]}"
TEMPLATE_SOURCE="local"
msg_ok "Template search completed"
else
# Step 3: No local template - need to check online (this may be slow)
msg_info "No local template found, checking online catalog..."
# Update catalog with timeout to prevent long hangs
if command -v timeout &>/dev/null; then
if ! timeout 30 pveam update >/dev/null 2>&1; then
msg_warn "Template catalog update timed out (possible network/DNS issue). Run 'pveam update' manually to diagnose."
fi
else
pveam update >/dev/null 2>&1 || msg_warn "Could not update template catalog (pveam update failed)"
# Resolve template path
TEMPLATE_PATH="$(pvesm path "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" 2>/dev/null || true)"
if [[ -z "$TEMPLATE_PATH" ]]; then
local _tpl_base
_tpl_base=$(awk -v s="$TEMPLATE_STORAGE" '
$0 ~ "^[^:]+:[[:space:]]*" s "$" {f=1; next}
f && /^[^[:space:]]/ {f=0}
f && $1 == "path" {print $2; exit}
' /etc/pve/storage.cfg)
TEMPLATE_PATH="${_tpl_base:-/var/lib/vz}/template/cache/$TEMPLATE"
fi
# Download if missing, too small, or corrupt
if [[ ! -f "$TEMPLATE_PATH" ]]; then
download_arm64_template "$TEMPLATE_PATH"
elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]] || ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
msg_warn "Local template invalid - re-downloading."
rm -f "$TEMPLATE_PATH"
download_arm64_template "$TEMPLATE_PATH"
else
msg_ok "Template ${BL}$TEMPLATE${CL} found locally."
fi
else
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
case "$PCT_OSTYPE" in
debian | ubuntu) TEMPLATE_PATTERN="-standard_" ;;
alpine | fedora | rocky | centos) TEMPLATE_PATTERN="-default_" ;;
*) TEMPLATE_PATTERN="" ;;
esac
msg_info "Searching for template '$TEMPLATE_SEARCH'"
# Initialize variables
ONLINE_TEMPLATE=""
ONLINE_TEMPLATES=()
mapfile -t ONLINE_TEMPLATES < <(pveam available -section system 2>/dev/null | grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' | awk '{print $2}' | grep -E "^${TEMPLATE_SEARCH}.*${TEMPLATE_PATTERN}" | sort -t - -k 2 -V 2>/dev/null || true)
[[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
TEMPLATE="$ONLINE_TEMPLATE"
TEMPLATE_SOURCE="online"
msg_ok "Template search completed"
fi
# If still no template, try to find alternatives
if [[ -z "$TEMPLATE" ]]; then
msg_warn "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}, searching for alternatives..."
# Get all available versions for this OS type
AVAILABLE_VERSIONS=()
mapfile -t AVAILABLE_VERSIONS < <(
pveam available -section system 2>/dev/null |
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
awk -F'\t' '{print $1}' |
grep "^${PCT_OSTYPE}-" |
sed -E "s/.*${PCT_OSTYPE}-([0-9]+(\.[0-9]+)?).*/\1/" |
sort -u -V 2>/dev/null
# Step 1: Check local templates first (instant)
mapfile -t LOCAL_TEMPLATES < <(
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
awk -v search="${TEMPLATE_SEARCH}" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
sed 's|.*/||' | sort -t - -k 2 -V
)
if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
echo ""
echo "${BL}Available ${PCT_OSTYPE} versions:${CL}"
for i in "${!AVAILABLE_VERSIONS[@]}"; do
echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}"
done
echo ""
read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or press Enter to cancel: " choice </dev/tty
# Step 2: If local template found, use it immediately (skip pveam update)
if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
TEMPLATE="${LOCAL_TEMPLATES[-1]}"
TEMPLATE_SOURCE="local"
msg_ok "Template search completed"
else
# Step 3: No local template - need to check online (this may be slow)
msg_info "No local template found, checking online catalog..."
if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#AVAILABLE_VERSIONS[@]} ]]; then
PCT_OSVERSION="${AVAILABLE_VERSIONS[$((choice - 1))]}"
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION}"
ONLINE_TEMPLATES=()
mapfile -t ONLINE_TEMPLATES < <(
pveam available -section system 2>/dev/null |
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
awk '{print $2}' |
grep -E "^${TEMPLATE_SEARCH}-.*${TEMPLATE_PATTERN}" |
sort -t - -k 2 -V 2>/dev/null || true
)
if [[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]]; then
TEMPLATE="${ONLINE_TEMPLATES[-1]}"
TEMPLATE_SOURCE="online"
else
msg_error "No templates available for ${PCT_OSTYPE} ${PCT_OSVERSION}"
exit 225
# Update catalog with timeout to prevent long hangs
if command -v timeout &>/dev/null; then
if ! timeout 30 pveam update >/dev/null 2>&1; then
msg_warn "Template catalog update timed out (possible network/DNS issue). Run 'pveam update' manually to diagnose."
fi
else
msg_custom "🚫" "${YW}" "Installation cancelled"
exit 0
pveam update >/dev/null 2>&1 || msg_warn "Could not update template catalog (pveam update failed)"
fi
else
msg_error "No ${PCT_OSTYPE} templates available at all"
exit 225
ONLINE_TEMPLATES=()
mapfile -t ONLINE_TEMPLATES < <(pveam available -section system 2>/dev/null | grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' | awk '{print $2}' | grep -E "^${TEMPLATE_SEARCH}.*${TEMPLATE_PATTERN}" | sort -t - -k 2 -V 2>/dev/null || true)
[[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
TEMPLATE="$ONLINE_TEMPLATE"
TEMPLATE_SOURCE="online"
msg_ok "Template search completed"
fi
fi
TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
if [[ -z "$TEMPLATE_PATH" ]]; then
TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
[[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
fi
# If we still don't have a path but have a valid template name, construct it
if [[ -z "$TEMPLATE_PATH" && -n "$TEMPLATE" ]]; then
TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
fi
[[ -n "$TEMPLATE_PATH" ]] || {
# If still no template, try to find alternatives
if [[ -z "$TEMPLATE" ]]; then
msg_error "Template ${PCT_OSTYPE} ${PCT_OSVERSION} not available"
msg_warn "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}, searching for alternatives..."
# Get available versions
# Get all available versions for this OS type
AVAILABLE_VERSIONS=()
mapfile -t AVAILABLE_VERSIONS < <(
pveam available -section system 2>/dev/null |
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
awk -F'\t' '{print $1}' |
grep "^${PCT_OSTYPE}-" |
sed -E 's/.*'"${PCT_OSTYPE}"'-([0-9]+\.[0-9]+).*/\1/' |
grep -E '^[0-9]+\.[0-9]+$' |
sort -u -V 2>/dev/null || sort -u
sed -E "s/.*${PCT_OSTYPE}-([0-9]+(\.[0-9]+)?).*/\1/" |
sort -u -V 2>/dev/null
)
if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
echo -e "\n${BL}Available versions:${CL}"
echo ""
echo "${BL}Available ${PCT_OSTYPE} versions:${CL}"
for i in "${!AVAILABLE_VERSIONS[@]}"; do
echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}"
done
echo ""
read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or Enter to exit: " choice </dev/tty
read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or press Enter to cancel: " choice </dev/tty
if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#AVAILABLE_VERSIONS[@]} ]]; then
export var_version="${AVAILABLE_VERSIONS[$((choice - 1))]}"
export PCT_OSVERSION="$var_version"
msg_ok "Switched to ${PCT_OSTYPE} ${var_version}"
PCT_OSVERSION="${AVAILABLE_VERSIONS[$((choice - 1))]}"
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION}"
# Retry template search with new version
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
mapfile -t LOCAL_TEMPLATES < <(
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
awk -v search="${TEMPLATE_SEARCH}-" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
sed 's|.*/||' | sort -t - -k 2 -V
)
ONLINE_TEMPLATES=()
mapfile -t ONLINE_TEMPLATES < <(
pveam available -section system 2>/dev/null |
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
@@ -5990,109 +6041,181 @@ create_lxc_container() {
grep -E "^${TEMPLATE_SEARCH}-.*${TEMPLATE_PATTERN}" |
sort -t - -k 2 -V 2>/dev/null || true
)
ONLINE_TEMPLATE=""
[[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
TEMPLATE="${LOCAL_TEMPLATES[-1]}"
TEMPLATE_SOURCE="local"
else
TEMPLATE="$ONLINE_TEMPLATE"
if [[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]]; then
TEMPLATE="${ONLINE_TEMPLATES[-1]}"
TEMPLATE_SOURCE="online"
else
msg_error "No templates available for ${PCT_OSTYPE} ${PCT_OSVERSION}"
exit 225
fi
TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
if [[ -z "$TEMPLATE_PATH" ]]; then
TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
[[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
fi
# If we still don't have a path but have a valid template name, construct it
if [[ -z "$TEMPLATE_PATH" && -n "$TEMPLATE" ]]; then
TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
fi
[[ -n "$TEMPLATE_PATH" ]] || {
msg_error "Template still not found after version change"
exit 220
}
else
msg_custom "🚫" "${YW}" "Installation cancelled"
exit 0
fi
else
msg_error "No ${PCT_OSTYPE} templates available"
exit 220
exit 225
fi
fi
}
# Validate that we found a template
if [[ -z "$TEMPLATE" ]]; then
msg_error "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}"
msg_custom "️" "${YW}" "Please check:"
msg_custom " •" "${YW}" "Is pveam catalog available? (run: pveam available -section system)"
msg_custom " •" "${YW}" "Does the template exist for your OS version?"
exit 225
fi
msg_ok "Template ${BL}$TEMPLATE${CL} [$TEMPLATE_SOURCE]"
msg_debug "Resolved TEMPLATE_PATH=$TEMPLATE_PATH"
NEED_DOWNLOAD=0
if [[ ! -f "$TEMPLATE_PATH" ]]; then
msg_info "Template not present locally will download."
NEED_DOWNLOAD=1
elif [[ ! -r "$TEMPLATE_PATH" ]]; then
msg_error "Template file exists but is not readable check permissions."
exit 221
elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
if [[ -n "$ONLINE_TEMPLATE" ]]; then
msg_warn "Template file too small (<1MB) re-downloading."
NEED_DOWNLOAD=1
else
msg_warn "Template looks too small, but no online version exists. Keeping local file."
TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
if [[ -z "$TEMPLATE_PATH" ]]; then
TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
[[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
fi
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
if [[ -n "$ONLINE_TEMPLATE" ]]; then
msg_warn "Template appears corrupted re-downloading."
NEED_DOWNLOAD=1
else
msg_warn "Template appears corrupted, but no online version exists. Keeping local file."
fi
else
$STD msg_ok "Template $TEMPLATE is present and valid."
fi
if [[ "$TEMPLATE_SOURCE" == "local" && -n "$ONLINE_TEMPLATE" && "$TEMPLATE" != "$ONLINE_TEMPLATE" ]]; then
msg_warn "Local template is outdated: $TEMPLATE (latest available: $ONLINE_TEMPLATE)"
if whiptail --yesno "A newer template is available:\n$ONLINE_TEMPLATE\n\nDo you want to download and use it instead?" 12 70; then
TEMPLATE="$ONLINE_TEMPLATE"
NEED_DOWNLOAD=1
else
msg_custom "️" "${BL}" "Continuing with local template $TEMPLATE"
# If we still don't have a path but have a valid template name, construct it
if [[ -z "$TEMPLATE_PATH" && -n "$TEMPLATE" ]]; then
TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
fi
fi
if [[ "$NEED_DOWNLOAD" -eq 1 ]]; then
[[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
for attempt in {1..3}; do
msg_info "Attempt $attempt: Downloading template $TEMPLATE to $TEMPLATE_STORAGE"
if pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1; then
msg_ok "Template download successful."
break
[[ -n "$TEMPLATE_PATH" ]] || {
if [[ -z "$TEMPLATE" ]]; then
msg_error "Template ${PCT_OSTYPE} ${PCT_OSVERSION} not available"
# Get available versions
mapfile -t AVAILABLE_VERSIONS < <(
pveam available -section system 2>/dev/null |
grep "^${PCT_OSTYPE}-" |
sed -E 's/.*'"${PCT_OSTYPE}"'-([0-9]+\.[0-9]+).*/\1/' |
grep -E '^[0-9]+\.[0-9]+$' |
sort -u -V 2>/dev/null || sort -u
)
if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
echo -e "\n${BL}Available versions:${CL}"
for i in "${!AVAILABLE_VERSIONS[@]}"; do
echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}"
done
echo ""
read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or press Enter to exit: " choice </dev/tty
if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#AVAILABLE_VERSIONS[@]} ]]; then
export var_version="${AVAILABLE_VERSIONS[$((choice - 1))]}"
export PCT_OSVERSION="$var_version"
msg_ok "Switched to ${PCT_OSTYPE} ${var_version}"
# Retry template search with new version
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
mapfile -t LOCAL_TEMPLATES < <(
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
awk -v search="${TEMPLATE_SEARCH}-" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
sed 's|.*/||' | sort -t - -k 2 -V
)
mapfile -t ONLINE_TEMPLATES < <(
pveam available -section system 2>/dev/null |
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
awk '{print $2}' |
grep -E "^${TEMPLATE_SEARCH}-.*${TEMPLATE_PATTERN}" |
sort -t - -k 2 -V 2>/dev/null || true
)
ONLINE_TEMPLATE=""
[[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
TEMPLATE="${LOCAL_TEMPLATES[-1]}"
TEMPLATE_SOURCE="local"
else
TEMPLATE="$ONLINE_TEMPLATE"
TEMPLATE_SOURCE="online"
fi
TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
if [[ -z "$TEMPLATE_PATH" ]]; then
TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
[[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
fi
# If we still don't have a path but have a valid template name, construct it
if [[ -z "$TEMPLATE_PATH" && -n "$TEMPLATE" ]]; then
TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
fi
[[ -n "$TEMPLATE_PATH" ]] || {
msg_error "Template still not found after version change"
exit 220
}
else
msg_custom "🚫" "${YW}" "Installation cancelled"
exit 0
fi
else
msg_error "No ${PCT_OSTYPE} templates available"
exit 220
fi
fi
if [[ $attempt -eq 3 ]]; then
msg_error "Failed after 3 attempts. Please check network access, permissions, or manually run:\n pveam download $TEMPLATE_STORAGE $TEMPLATE"
exit 222
fi
sleep $((attempt * 5))
done
fi
}
if ! pveam list "$TEMPLATE_STORAGE" 2>/dev/null | grep -q "$TEMPLATE"; then
msg_error "Template $TEMPLATE not available in storage $TEMPLATE_STORAGE after download."
exit 223
# Validate that we found a template
if [[ -z "$TEMPLATE" ]]; then
msg_error "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}"
msg_custom "️" "${YW}" "Please check:"
msg_custom " •" "${YW}" "Is pveam catalog available? (run: pveam available -section system)"
msg_custom " •" "${YW}" "Does the template exist for your OS version?"
exit 225
fi
msg_ok "Template ${BL}$TEMPLATE${CL} [$TEMPLATE_SOURCE]"
msg_debug "Resolved TEMPLATE_PATH=$TEMPLATE_PATH"
NEED_DOWNLOAD=0
if [[ ! -f "$TEMPLATE_PATH" ]]; then
msg_info "Template not present locally, will download it."
NEED_DOWNLOAD=1
elif [[ ! -r "$TEMPLATE_PATH" ]]; then
msg_error "Template file exists but is not readable, check permissions."
exit 221
elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
if [[ -n "$ONLINE_TEMPLATE" ]]; then
msg_warn "Template file too small (<1MB), re-downloading."
NEED_DOWNLOAD=1
else
msg_warn "Template looks too small, but no online version exists. Keeping local file."
fi
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
if [[ -n "$ONLINE_TEMPLATE" ]]; then
msg_warn "Template appears corrupted, re-downloading."
NEED_DOWNLOAD=1
else
msg_warn "Template appears corrupted, but no online version exists. Keeping local file."
fi
else
$STD msg_ok "Template $TEMPLATE is present and valid."
fi
if [[ "$TEMPLATE_SOURCE" == "local" && -n "$ONLINE_TEMPLATE" && "$TEMPLATE" != "$ONLINE_TEMPLATE" ]]; then
msg_warn "Local template is outdated: $TEMPLATE (latest available: $ONLINE_TEMPLATE)"
if whiptail --yesno "A newer template is available:\n$ONLINE_TEMPLATE\n\nDo you want to download and use it instead?" 12 70; then
TEMPLATE="$ONLINE_TEMPLATE"
NEED_DOWNLOAD=1
else
msg_custom "️" "${BL}" "Continuing with local template $TEMPLATE"
fi
fi
if [[ "$NEED_DOWNLOAD" -eq 1 ]]; then
[[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
for attempt in {1..3}; do
msg_info "Attempt $attempt: Downloading template $TEMPLATE to $TEMPLATE_STORAGE"
if pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1; then
msg_ok "Template download successful."
break
fi
if [[ $attempt -eq 3 ]]; then
msg_error "Failed after 3 attempts. Please check network access, permissions, or manually run:\n pveam download $TEMPLATE_STORAGE $TEMPLATE"
exit 222
fi
sleep $((attempt * 5))
done
fi
if ! pveam list "$TEMPLATE_STORAGE" 2>/dev/null | grep -q "$TEMPLATE"; then
msg_error "Template $TEMPLATE not available in storage $TEMPLATE_STORAGE after download."
exit 223
fi
fi
# ------------------------------------------------------------------------------
@@ -6169,21 +6292,15 @@ create_lxc_container() {
# 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
msg_info "Template file missing or too small downloading"
msg_info "Template file missing or too small - downloading"
rm -f "$TEMPLATE_PATH"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 || {
msg_error "Failed to download template '$TEMPLATE' to storage '$TEMPLATE_STORAGE'"
exit 222
}
download_template
msg_ok "Template downloaded"
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
if [[ -n "$ONLINE_TEMPLATE" ]]; then
msg_info "Template appears corrupted re-downloading"
if [[ "$ARCH" == "arm64" || -n "$ONLINE_TEMPLATE" ]]; then
msg_info "Template appears corrupted - re-downloading"
rm -f "$TEMPLATE_PATH"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 || {
msg_error "Failed to re-download template '$TEMPLATE'"
exit 222
}
download_template
msg_ok "Template re-downloaded"
else
msg_warn "Template appears corrupted, but no online version exists. Skipping re-download."
@@ -6231,9 +6348,9 @@ create_lxc_container() {
else
# Not a CTID collision - check if template issue and retry with fresh download
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"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1
download_template
msg_ok "Template re-downloaded"
fi
@@ -6246,7 +6363,11 @@ create_lxc_container() {
if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then
msg_ok "Trying local storage fallback"
msg_info "Downloading template to local"
pveam download local "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1
if [[ "$ARCH" == "arm64" ]]; then
download_arm64_template "$LOCAL_TEMPLATE_PATH"
else
pveam download local "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1
fi
msg_ok "Template downloaded to local"
else
msg_ok "Trying local storage fallback"
+41 -3
View File
@@ -346,9 +346,15 @@ pve_check() {
# - Provides link to ARM64-compatible scripts
# ------------------------------------------------------------------------------
arch_check() {
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
msg_error "This script will not work with PiMox (ARM architecture detected)."
msg_warn "Visit https://github.com/asylumexp/Proxmox for ARM64 support."
local arch
arch="$(dpkg --print-architecture)"
if [[ "$arch" != "amd64" && "$arch" != "arm64" ]]; then
msg_error "This script requires amd64 or arm64 (detected: $arch)."
sleep 2
exit 106
fi
if [[ "$arch" == "arm64" && "${var_arm64:-}" != "yes" ]]; then
msg_error "This script does not yet support arm64."
sleep 2
exit 106
fi
@@ -1714,6 +1720,38 @@ function get_lxc_ip() {
export LOCAL_IP
}
# ------------------------------------------------------------------------------
# ensure_whiptail()
#
# - Ensures whiptail is installed
# - Some ARM64 systems will not have whiptail installed
# - Exits with error message if installation fails
# ------------------------------------------------------------------------------
ensure_whiptail() {
command -v whiptail >/dev/null 2>&1 && return 0
msg_info "Installing whiptail"
apt_update_safe
$STD apt-get install -y whiptail || {
msg_error "Failed to install whiptail"
exit 100
}
msg_ok "Installed whiptail"
}
# ------------------------------------------------------------------------------
# arm64_notice()
#
# - Shows a short warning when running scripts on ARM64 systems
# ------------------------------------------------------------------------------
arm64_notice() {
[[ "$(dpkg --print-architecture)" == "arm64" ]] || return 0
whiptail --backtitle "Proxmox VE Helper Scripts" \
--title "ARM64 SUPPORT" \
--ok-button "Continue" \
--msgbox "ARM64 support is in active development.\n\nSome scripts, packages, or application releases may not be fully tested or working yet." 10 68
}
# ==============================================================================
# SIGNAL TRAPS
# ==============================================================================
+1 -1
View File
@@ -99,7 +99,7 @@ if ! declare -f explain_exit_code &>/dev/null; then
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)" ;;
106) echo "Validation: Unsupported architecture (requires amd64 or arm64)" ;;
107) echo "Validation: Kernel key parameters unreadable" ;;
108) echo "Validation: Kernel key limits exceeded" ;;
109) echo "Proxmox: No available container ID after max attempts" ;;
+56 -13
View File
@@ -3157,10 +3157,14 @@ fetch_and_deploy_codeberg_release() {
# Fall back to architecture heuristic
if [[ -z "$url_match" ]]; then
for u in $assets; do
if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then
url_match="$u"
break
[[ "$u" =~ \.deb$ ]] || continue
if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
[[ "$u" =~ (amd64|x86_64).*\.deb$ ]] || continue
elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
[[ "$u" =~ (arm64|aarch64).*\.deb$ ]] || continue
fi
url_match="$u"
break
done
fi
@@ -3457,7 +3461,11 @@ _gh_scan_older_releases() {
done)
fi
if [[ "$has_match" != "true" ]]; then
has_match=$(echo "$releases_list" | jq -r ".[$i].assets[].browser_download_url" | grep -qE "($arch|amd64|x86_64|aarch64|arm64).*\.deb$" && echo true)
if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
has_match=$(echo "$releases_list" | jq -r ".[$i].assets[].browser_download_url" | grep -qE '(amd64|x86_64).*\.deb$' && echo true)
elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
has_match=$(echo "$releases_list" | jq -r ".[$i].assets[].browser_download_url" | grep -qE '(arm64|aarch64).*\.deb$' && echo true)
fi
fi
if [[ "$has_match" != "true" ]]; then
has_match=$(echo "$releases_list" | jq -r ".[$i].assets[].browser_download_url" | grep -qE '\.deb$' && echo true)
@@ -3663,10 +3671,14 @@ fetch_and_deploy_gh_release() {
# If no match via explicit pattern, fall back to architecture heuristic
if [[ -z "$url_match" ]]; then
for u in $assets; do
if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then
url_match="$u"
break
[[ "$u" =~ \.deb$ ]] || continue
if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
[[ "$u" =~ (amd64|x86_64).*\.deb$ ]] || continue
elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
[[ "$u" =~ (arm64|aarch64).*\.deb$ ]] || continue
fi
url_match="$u"
break
done
fi
@@ -3697,10 +3709,14 @@ fetch_and_deploy_gh_release() {
fi
if [[ -z "$url_match" ]]; then
for u in $assets; do
if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then
url_match="$u"
break
[[ "$u" =~ \.deb$ ]] || continue
if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
[[ "$u" =~ (amd64|x86_64).*\.deb$ ]] || continue
elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
[[ "$u" =~ (arm64|aarch64).*\.deb$ ]] || continue
fi
url_match="$u"
break
done
fi
if [[ -z "$url_match" ]]; then
@@ -4458,7 +4474,12 @@ setup_ffmpeg() {
# Binary fallback mode
if [[ "$TYPE" == "binary" ]]; then
if ! CURL_TIMEOUT=300 curl_with_retry "https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz" "$TMP_DIR/ffmpeg.tar.xz"; then
local ffmpeg_arch
case "$(dpkg --print-architecture 2>/dev/null || echo amd64)" in
arm64) ffmpeg_arch="arm64" ;;
*) ffmpeg_arch="amd64" ;;
esac
if ! CURL_TIMEOUT=300 curl_with_retry "https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-${ffmpeg_arch}-static.tar.xz" "$TMP_DIR/ffmpeg.tar.xz"; then
msg_error "Failed to download FFmpeg binary"
msg_error "Hint: Check connectivity to johnvansickle.com/ffmpeg (static builds, may be slow — large file)"
rm -rf "$TMP_DIR"
@@ -4546,7 +4567,17 @@ setup_ffmpeg() {
# If no source download (either VERSION empty or download failed), use binary
if [[ -z "$VERSION" ]]; then
msg_info "Setup FFmpeg from pre-built binary"
if ! CURL_TIMEOUT=300 curl_with_retry "https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz" "$TMP_DIR/ffmpeg.tar.xz"; then
local ffmpeg_arch detected_arch
detected_arch="$(dpkg --print-architecture 2>/dev/null || true)"
if [[ -z "$detected_arch" ]]; then
detected_arch="$(uname -m 2>/dev/null || true)"
fi
case "$detected_arch" in
arm64 | aarch64) ffmpeg_arch="arm64" ;;
amd64 | x86_64) ffmpeg_arch="amd64" ;;
*) ffmpeg_arch="amd64" ;;
esac
if ! CURL_TIMEOUT=300 curl_with_retry "https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-${ffmpeg_arch}-static.tar.xz" "$TMP_DIR/ffmpeg.tar.xz"; then
msg_error "Failed to download FFmpeg pre-built binary"
msg_error "Hint: Check connectivity to johnvansickle.com/ffmpeg (large file, may timeout on slow connections)"
rm -rf "$TMP_DIR"
@@ -8576,7 +8607,19 @@ setup_yq() {
msg_info "Setup yq $LATEST_VERSION"
fi
if ! curl_with_retry "https://github.com/${GITHUB_REPO}/releases/download/v${LATEST_VERSION}/yq_linux_amd64" "$TMP_DIR/yq"; then
local yq_arch detected_arch
if command -v dpkg &>/dev/null; then
detected_arch="$(dpkg --print-architecture 2>/dev/null)"
else
detected_arch="$(uname -m 2>/dev/null)"
fi
case "$detected_arch" in
arm64 | aarch64) yq_arch="arm64" ;;
amd64 | x86_64) yq_arch="amd64" ;;
*) yq_arch="amd64" ;;
esac
if ! curl_with_retry "https://github.com/${GITHUB_REPO}/releases/download/v${LATEST_VERSION}/yq_linux_${yq_arch}" "$TMP_DIR/yq"; then
msg_error "Failed to download yq"
msg_error "Hint: Check connectivity to github.com/${GITHUB_REPO} — set GITHUB_TOKEN to avoid rate-limiting"
rm -rf "$TMP_DIR"
+6 -6
View File
@@ -96,14 +96,14 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
msg_info "Installing Hardware Acceleration (non-free)"
pct exec "${privileged_container}" -- bash -c "cat <<EOF >/etc/apt/sources.list.d/non-free.list
deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb https://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb-src https://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb http://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb https://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb-src https://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
deb https://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
deb-src https://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
EOF"
pct exec "${privileged_container}" -- bash -c "silent() { \"\$@\" >/dev/null 2>&1; } && $STD apt-get update && $STD apt-get install -y intel-media-va-driver-non-free ocl-icd-libopencl1 intel-opencl-icd vainfo intel-gpu-tools && $STD adduser \$(id -u -n) video && $STD adduser \$(id -u -n) render"
+1 -1
View File
@@ -76,7 +76,7 @@ intel() {
}
msg_info "Downloading the Intel Processor Microcode Package $microcode"
curl -fsSL "http://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode/$microcode" -o $(basename "http://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode/$microcode")
curl -fsSL --proto '=https' "https://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode/$microcode" -o "$microcode"
msg_ok "Downloaded the Intel Processor Microcode Package $microcode"
msg_info "Installing $microcode (Patience)"
+1 -1
View File
@@ -90,7 +90,7 @@ intel() {
}
msg_info "Downloading Intel processor microcode package $microcode"
curl -fsSL "http://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode/$microcode" -o $(basename "http://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode/$microcode")
curl -fsSL --proto '=https' "https://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode/$microcode" -o "$microcode"
msg_ok "Downloaded Intel processor microcode package $microcode"
msg_info "Installing $microcode (this might take a while)"
+4 -4
View File
@@ -71,9 +71,9 @@ start_routines() {
yes)
msg_info "Changing to Proxmox Backup Server 3 Sources"
cat <<EOF >/etc/apt/sources.list
deb http://deb.debian.org/debian bookworm main contrib
deb http://deb.debian.org/debian bookworm-updates main contrib
deb http://security.debian.org/debian-security bookworm-security main contrib
deb https://deb.debian.org/debian bookworm main contrib
deb https://deb.debian.org/debian bookworm-updates main contrib
deb https://security.debian.org/debian-security bookworm-security main contrib
EOF
msg_ok "Changed to Proxmox Backup Server 3 Sources"
;;
@@ -105,7 +105,7 @@ EOF
yes)
msg_info "Enabling 'pbs-no-subscription' repository"
cat <<EOF >/etc/apt/sources.list.d/pbs-install-repo.list
deb http://download.proxmox.com/debian/pbs bookworm pbs-no-subscription
deb https://download.proxmox.com/debian/pbs bookworm pbs-no-subscription
EOF
msg_ok "Enabled 'pbs-no-subscription' repository"
;;
+3 -3
View File
@@ -126,9 +126,9 @@ start_routines_3() {
yes)
msg_info "Correcting Debian Sources"
cat <<EOF >/etc/apt/sources.list
deb http://deb.debian.org/debian ${VERSION} main contrib
deb http://deb.debian.org/debian ${VERSION}-updates main contrib
deb http://security.debian.org/debian-security ${VERSION}-security main contrib
deb https://deb.debian.org/debian ${VERSION} main contrib
deb https://deb.debian.org/debian ${VERSION}-updates main contrib
deb https://security.debian.org/debian-security ${VERSION}-security main contrib
EOF
msg_ok "Corrected Debian Sources"
;;
+4 -4
View File
@@ -115,9 +115,9 @@ start_routines_8() {
yes)
msg_info "Correcting Proxmox VE Sources"
cat <<EOF >/etc/apt/sources.list
deb http://deb.debian.org/debian bookworm main contrib
deb http://deb.debian.org/debian bookworm-updates main contrib
deb http://security.debian.org/debian-security bookworm-security main contrib
deb https://deb.debian.org/debian bookworm main contrib
deb https://deb.debian.org/debian bookworm-updates main contrib
deb https://security.debian.org/debian-security bookworm-security main contrib
EOF
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' >/etc/apt/apt.conf.d/no-bookworm-firmware.conf
msg_ok "Corrected Proxmox VE Sources"
@@ -146,7 +146,7 @@ EOF
yes)
msg_info "Enabling 'pve-no-subscription' repository"
cat <<EOF >/etc/apt/sources.list.d/pve-install-repo.list
deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription
deb https://download.proxmox.com/debian/pve bookworm pve-no-subscription
EOF
msg_ok "Enabled 'pve-no-subscription' repository"
;;
+4 -4
View File
@@ -54,9 +54,9 @@ start_routines() {
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "PVE8 SOURCES" "This will set the correct sources to update and install Proxmox VE 8." 10 58
msg_info "Changing to Proxmox VE 8 Sources"
cat <<EOF >/etc/apt/sources.list
deb http://ftp.debian.org/debian bookworm main contrib
deb http://ftp.debian.org/debian bookworm-updates main contrib
deb http://security.debian.org/debian-security bookworm-security main contrib
deb https://ftp.debian.org/debian bookworm main contrib
deb https://ftp.debian.org/debian bookworm-updates main contrib
deb https://security.debian.org/debian-security bookworm-security main contrib
EOF
msg_ok "Changed to Proxmox VE 8 Sources"
@@ -70,7 +70,7 @@ EOF
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "PVE8-NO-SUBSCRIPTION" "The 'pve-no-subscription' repository provides access to all of the open-source components of Proxmox VE." 10 58
msg_info "Enabling 'pve-no-subscription' repository"
cat <<EOF >/etc/apt/sources.list.d/pve-install-repo.list
deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription
deb https://download.proxmox.com/debian/pve bookworm pve-no-subscription
EOF
msg_ok "Enabled 'pve-no-subscription' repository"