Compare commits

...

46 Commits

Author SHA1 Message Date
community-scripts-pr-app[bot]
4e21f411f5 Update CHANGELOG.md (#11045)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-22 00:15:40 +00:00
community-scripts-pr-app[bot]
fe21d3577f Update versions.json (#11044)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-22 01:14:47 +01:00
community-scripts-pr-app[bot]
3725023ee3 Update .app files (#11041)
Co-authored-by: GitHub Actions <github-actions[bot]@users.noreply.github.com>
2026-01-21 21:30:02 +01:00
community-scripts-pr-app[bot]
c19817af8d Update CHANGELOG.md (#11040)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-21 20:26:43 +00:00
push-app-to-main[bot]
5378d41acf Byparr (#11039)
* Add byparr (ct)

* refactor

* Update date_created to new value

* refactor

---------

Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>
2026-01-21 21:25:50 +01:00
community-scripts-pr-app[bot]
5bb48fc843 Update CHANGELOG.md (#11037)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-21 14:54:58 +00:00
Ruan Bahia
e935289128 fix: Snipe-IT update missing all user uploads (#11032) (#11033) 2026-01-21 15:54:24 +01:00
community-scripts-pr-app[bot]
0db119d2c3 Update CHANGELOG.md (#11036)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-21 14:39:41 +00:00
CanbiZ (MickLesk)
5c9087a91a tools: add ubuntu PHP repository setup (#11034)
Switches to using the ondrej/php PPA for Ubuntu and retains the Sury repository for Debian when setting up PHP. This ensures compatibility with the respective distributions' recommended PHP sources.
2026-01-21 15:39:15 +01:00
community-scripts-pr-app[bot]
1d7d8c27fa Update CHANGELOG.md (#11035)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-21 14:14:52 +00:00
Tobias
fae2d032ab yubal: fix for v0.2 (#11006) 2026-01-21 15:14:29 +01:00
CanbiZ (MickLesk)
2fab70294f fix joplin 2026-01-21 14:58:55 +01:00
CanbiZ (MickLesk)
477199a4c2 yarn rebuild 2026-01-21 13:17:29 +01:00
CanbiZ (MickLesk)
733425f970 Merge branch 'main' of https://github.com/community-scripts/ProxmoxVE 2026-01-21 13:07:28 +01:00
CanbiZ (MickLesk)
7395a44277 Run TypeScript compilation in Joplin Server scripts
Added 'yarn run tsc' to both update and install scripts for Joplin Server to ensure TypeScript sources are compiled. Also removed an unused variable from build.func for code cleanup.
2026-01-21 13:07:20 +01:00
community-scripts-pr-app[bot]
f555f9ae0c Update versions.json (#11030)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-21 13:07:18 +01:00
CanbiZ (MickLesk)
fe2384a2fa Initialize variables in create_lxc_container
Added initialization for ONLINE_TEMPLATE and ONLINE_TEMPLATES arrays at the start of the create_lxc_container function to ensure variables are defined before use.
2026-01-21 12:42:19 +01:00
CanbiZ (MickLesk)
5384adf0c3 Remove unnecessary set +u/set -u in create_lxc_container
only as test exist
2026-01-21 12:40:55 +01:00
CanbiZ (MickLesk)
ed18776710 fix unbound var: ONLINE_TEMPLATES 2026-01-21 12:39:57 +01:00
community-scripts-pr-app[bot]
13824931b0 Update CHANGELOG.md (#11029)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-21 11:02:01 +00:00
CanbiZ (MickLesk)
88557d53f4 core: allow empty tags & improve template search (#11020) 2026-01-21 12:01:34 +01:00
community-scripts-pr-app[bot]
0c9653c7cb Update CHANGELOG.md (#11028)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-21 11:01:13 +00:00
CanbiZ (MickLesk)
914c316f42 Joplin-Server: use yarn workspaces focus for faster builds (#11027) 2026-01-21 12:00:46 +01:00
community-scripts-pr-app[bot]
49d92afb98 Update CHANGELOG.md (#11018)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-21 05:47:47 +00:00
Slaviša Arežina
dba473b2b3 Set disable flag to true in joplin-server.json (#11008) 2026-01-21 06:47:22 +01:00
community-scripts-pr-app[bot]
5dd50aacd7 Update CHANGELOG.md (#11016)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-21 00:15:04 +00:00
community-scripts-pr-app[bot]
0dcb8b5ef7 Update versions.json (#11015)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-21 01:14:40 +01:00
community-scripts-pr-app[bot]
a48435e064 Update CHANGELOG.md (#11014)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-20 22:42:19 +00:00
CanbiZ (MickLesk)
cb2141ebe2 Revert "Revert "core: add retry logic for template lock in LXC container crea…" (#11013)
This reverts commit 7699f4f6ad.
2026-01-20 23:41:53 +01:00
community-scripts-pr-app[bot]
b1f21b4024 Update CHANGELOG.md (#11012)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-20 22:36:24 +00:00
CanbiZ (MickLesk)
7699f4f6ad Revert "core: add retry logic for template lock in LXC container creation (#1…" (#11011)
This reverts commit d71f24bddb.
2026-01-20 23:35:39 +01:00
community-scripts-pr-app[bot]
657a9629be Update CHANGELOG.md (#11009)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-20 21:36:58 +00:00
CanbiZ (MickLesk)
d71f24bddb core: add retry logic for template lock in LXC container creation (#11002) 2026-01-20 22:36:32 +01:00
community-scripts-pr-app[bot]
5a1c1e06f9 Update CHANGELOG.md (#11007)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-20 21:21:31 +00:00
CanbiZ (MickLesk)
7146e8d5b9 dolibarr: switch mirror (#11004) 2026-01-20 22:21:02 +01:00
community-scripts-pr-app[bot]
a5dfa33af3 Update CHANGELOG.md (#11001)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-20 14:03:39 +00:00
CanbiZ (MickLesk)
6dd5fbd7da core: add input validations for several functions (#10995) 2026-01-20 15:03:14 +01:00
community-scripts-pr-app[bot]
718cda8eb1 Update CHANGELOG.md (#11000)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-20 14:00:13 +00:00
CanbiZ (MickLesk)
ff5263981b core: implement ensure_profile_loaded function (#10999) 2026-01-20 14:59:41 +01:00
community-scripts-pr-app[bot]
785177fe29 Update CHANGELOG.md (#10997)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-20 13:42:13 +01:00
CanbiZ (MickLesk)
5e7e7c884d checkmk: reordner base function (#10990) 2026-01-20 13:36:13 +01:00
community-scripts-pr-app[bot]
97275d06ea Update CHANGELOG.md (#10996)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-20 12:35:56 +00:00
CanbiZ (MickLesk)
0f15d81cd3 fix(homepage): preserve config directory during updates (#10993)
Fixes #10985 - The update script was deleting user config files due to
CLEAN_INSTALL=1 flag. Now backs up and restores both .env and config/
directory to preserve user configurations.
2026-01-20 13:35:28 +01:00
community-scripts-pr-app[bot]
6712f6a9ca Update CHANGELOG.md (#10994)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-20 12:24:59 +00:00
miausalvaje
1816b0169e DiscoPanel: add go for update build process (#10991)
* Refactor Go installation and DiscoPanel build process

Updated the Go installation process and modified the build command for DiscoPanel. Also updated the systemd service configuration to include Go in the PATH.

* Using setup_go

Using setup_go instead of a manual installation.
2026-01-20 13:24:32 +01:00
community-scripts-pr-app[bot]
3f05972eb9 Update versions.json (#10992)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-20 13:06:36 +01:00
17 changed files with 1107 additions and 383 deletions

View File

@@ -10,8 +10,57 @@
> [!CAUTION]
Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit the project's popularity for potentially malicious purposes.
## 2026-01-22
## 2026-01-21
### 🆕 New Scripts
- Byparr ([#11039](https://github.com/community-scripts/ProxmoxVE/pull/11039))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix: Snipe-IT update missing all user uploads (#11032) [@ruanmed](https://github.com/ruanmed) ([#11033](https://github.com/community-scripts/ProxmoxVE/pull/11033))
- yubal: fix for v0.2 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11006](https://github.com/community-scripts/ProxmoxVE/pull/11006))
- Joplin-Server: use yarn workspaces focus for faster builds [@MickLesk](https://github.com/MickLesk) ([#11027](https://github.com/community-scripts/ProxmoxVE/pull/11027))
### 💾 Core
- #### ✨ New Features
- tools: add ubuntu PHP repository setup [@MickLesk](https://github.com/MickLesk) ([#11034](https://github.com/community-scripts/ProxmoxVE/pull/11034))
- #### 🔧 Refactor
- core: allow empty tags & improve template search [@MickLesk](https://github.com/MickLesk) ([#11020](https://github.com/community-scripts/ProxmoxVE/pull/11020))
### 🌐 Website
- #### 📝 Script Information
- Joplin Server: Set disable flag to true in joplin-server.json [@tremor021](https://github.com/tremor021) ([#11008](https://github.com/community-scripts/ProxmoxVE/pull/11008))
## 2026-01-20
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- dolibarr: switch mirror [@MickLesk](https://github.com/MickLesk) ([#11004](https://github.com/community-scripts/ProxmoxVE/pull/11004))
- checkmk: reordner base function [@MickLesk](https://github.com/MickLesk) ([#10990](https://github.com/community-scripts/ProxmoxVE/pull/10990))
- Homepage: preserve config directory during updates [@MickLesk](https://github.com/MickLesk) ([#10993](https://github.com/community-scripts/ProxmoxVE/pull/10993))
- DiscoPanel: add go for update build process [@miausalvaje](https://github.com/miausalvaje) ([#10991](https://github.com/community-scripts/ProxmoxVE/pull/10991))
### 💾 Core
- #### ✨ New Features
- core: add retry logic for template lock in LXC container creation [@MickLesk](https://github.com/MickLesk) ([#11002](https://github.com/community-scripts/ProxmoxVE/pull/11002))
- core: implement ensure_profile_loaded function [@MickLesk](https://github.com/MickLesk) ([#10999](https://github.com/community-scripts/ProxmoxVE/pull/10999))
- core: add input validations for several functions [@MickLesk](https://github.com/MickLesk) ([#10995](https://github.com/community-scripts/ProxmoxVE/pull/10995))
## 2026-01-19
### 🆕 New Scripts

53
ct/byparr.sh Normal file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: luismco
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/ThePhaseless/Byparr
APP="Byparr"
var_tags="${var_tags:-proxy}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-4}"
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/Byparr ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "Byparr" "ThePhaseless/Byparr"; then
msg_info "Stopping Service"
systemctl stop byparr
msg_ok "Stopped Service"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Byparr" "ThePhaseless/Byparr" "tarball" "latest"
msg_info "Starting Service"
systemctl start byparr
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}:8191${CL}"

View File

@@ -54,9 +54,14 @@ function update_script() {
cd /opt/discopanel/web/discopanel
$STD npm install
$STD npm run build
msg_ok "Built Web Interface"
setup_go
msg_info "Building DiscoPanel"
cd /opt/discopanel
$STD go build -o discopanel cmd/discopanel/main.go
msg_ok "Setup DiscoPanel"
msg_ok "Built DiscoPanel"
msg_info "Restoring Data"
mkdir -p /opt/discopanel/data

6
ct/headers/byparr Normal file
View File

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

View File

@@ -45,8 +45,11 @@ function update_script() {
msg_ok "Stopped service"
cp /opt/homepage/.env /opt/homepage.env
cp -r /opt/homepage/config /opt/homepage_config_backup
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "homepage" "gethomepage/homepage" "tarball"
mv /opt/homepage.env /opt/homepage
rm -rf /opt/homepage/config
mv /opt/homepage_config_backup /opt/homepage/config
msg_info "Updating Homepage (Patience)"
RELEASE=$(get_latest_github_release "gethomepage/homepage")

View File

@@ -44,7 +44,9 @@ function update_script() {
sed -i "/onenote-converter/d" packages/lib/package.json
$STD yarn config set --home enableTelemetry 0
export BUILD_SEQUENCIAL=1
$STD yarn install --inline-builds
$STD yarn workspaces focus @joplin/server
$STD yarn workspaces foreach -R --topological-dev --from @joplin/server run build
$STD yarn workspaces foreach -R --topological-dev --from @joplin/server run tsc
msg_ok "Updated Joplin-Server"
msg_info "Starting Services"

View File

@@ -50,8 +50,8 @@ function update_script() {
$STD apt update
$STD apt -y upgrade
cp /opt/snipe-it-backup/.env /opt/snipe-it/.env
cp -r /opt/snipe-it-backup/public/uploads/ /opt/snipe-it/public/uploads/
cp -r /opt/snipe-it-backup/storage/private_uploads /opt/snipe-it/storage/private_uploads
cp -r /opt/snipe-it-backup/public/uploads/. /opt/snipe-it/public/uploads/
cp -r /opt/snipe-it-backup/storage/private_uploads/. /opt/snipe-it/storage/private_uploads/
cd /opt/snipe-it/
export COMPOSER_ALLOW_SUPERUSER=1
$STD composer install --no-dev --optimize-autoloader --no-interaction

View File

@@ -0,0 +1,35 @@
{
"name": "Byparr",
"slug": "byparr",
"categories": [
14
],
"date_created": "2026-01-21",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8191,
"documentation": "https://github.com/ThePhaseless/Byparr/blob/master/README.md",
"website": "https://github.com/ThePhaseless/Byparr",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/byparr.webp",
"config_path": "",
"description": "Byparr is a proxy server to bypass Cloudflare and DDoS-GUARD protection.",
"install_methods": [
{
"type": "default",
"script": "ct/byparr.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,4 +1,284 @@
[
{
"name": "Stirling-Tools/Stirling-PDF",
"version": "v2.3.0",
"date": "2026-01-15T19:29:02Z"
},
{
"name": "ollama/ollama",
"version": "v0.14.3-rc3",
"date": "2026-01-20T20:20:53Z"
},
{
"name": "BerriAI/litellm",
"version": "v1.81.0.rc.4",
"date": "2026-01-21T21:43:55Z"
},
{
"name": "Infisical/infisical",
"version": "v0.156.2",
"date": "2026-01-21T21:02:11Z"
},
{
"name": "runtipi/runtipi",
"version": "nightly",
"date": "2026-01-20T21:10:15Z"
},
{
"name": "Comfy-Org/ComfyUI",
"version": "v0.10.0",
"date": "2026-01-21T19:22:04Z"
},
{
"name": "fccview/jotty",
"version": "1.18.1",
"date": "2026-01-21T19:16:44Z"
},
{
"name": "firefly-iii/firefly-iii",
"version": "v6.4.16",
"date": "2026-01-17T07:54:15Z"
},
{
"name": "metabase/metabase",
"version": "v0.57.x",
"date": "2026-01-21T17:54:29Z"
},
{
"name": "openobserve/openobserve",
"version": "v0.50.2",
"date": "2026-01-21T17:02:52Z"
},
{
"name": "LimeSurvey/LimeSurvey",
"version": "7.0.0-beta1+260113",
"date": "2026-01-21T15:14:45Z"
},
{
"name": "jenkinsci/jenkins",
"version": "jenkins-2.541.1",
"date": "2026-01-21T15:09:10Z"
},
{
"name": "dedicatedcode/reitti",
"version": "v3.4.0",
"date": "2026-01-21T14:29:46Z"
},
{
"name": "node-red/node-red",
"version": "4.1.3",
"date": "2026-01-07T16:24:23Z"
},
{
"name": "prometheus/prometheus",
"version": "v3.5.1",
"date": "2026-01-21T13:28:57Z"
},
{
"name": "apache/tomcat",
"version": "10.1.51",
"date": "2026-01-21T13:19:21Z"
},
{
"name": "semaphoreui/semaphore",
"version": "v2.17.0-rc7",
"date": "2026-01-21T12:12:33Z"
},
{
"name": "evcc-io/evcc",
"version": "0.300.5",
"date": "2026-01-21T11:35:44Z"
},
{
"name": "javedh-dev/tracktor",
"version": "1.2.1",
"date": "2026-01-21T11:12:28Z"
},
{
"name": "endurain-project/endurain",
"version": "v0.17.0",
"date": "2026-01-21T10:55:33Z"
},
{
"name": "emqx/emqx",
"version": "e5.10.3-rc.2",
"date": "2026-01-21T08:57:16Z"
},
{
"name": "docker/compose",
"version": "v5.0.2",
"date": "2026-01-21T07:42:38Z"
},
{
"name": "SigNoz/signoz",
"version": "v0.108.0",
"date": "2026-01-21T06:45:16Z"
},
{
"name": "rabbitmq/rabbitmq-server",
"version": "v4.2.2",
"date": "2025-12-15T18:25:36Z"
},
{
"name": "Jackett/Jackett",
"version": "v0.24.898",
"date": "2026-01-21T05:50:19Z"
},
{
"name": "9001/copyparty",
"version": "v1.20.3",
"date": "2026-01-21T05:39:57Z"
},
{
"name": "donetick/donetick",
"version": "v0.1.70-beta.1",
"date": "2026-01-21T05:35:05Z"
},
{
"name": "esphome/esphome",
"version": "2026.1.0",
"date": "2026-01-21T03:43:09Z"
},
{
"name": "jeedom/core",
"version": "4.5.2",
"date": "2026-01-21T00:27:05Z"
},
{
"name": "steveiliop56/tinyauth",
"version": "v4.1.0",
"date": "2025-11-23T12:13:34Z"
},
{
"name": "paperless-ngx/paperless-ngx",
"version": "v2.20.5",
"date": "2026-01-21T00:12:33Z"
},
{
"name": "keycloak/keycloak",
"version": "26.4.8",
"date": "2026-01-15T13:52:29Z"
},
{
"name": "ZoeyVid/NPMplus",
"version": "2026-01-20-r2",
"date": "2026-01-20T22:28:54Z"
},
{
"name": "seerr-team/seerr",
"version": "preview-availability-sync-fix",
"date": "2026-01-20T22:11:24Z"
},
{
"name": "chrisbenincasa/tunarr",
"version": "v1.2.0-dev.1",
"date": "2026-01-20T21:46:14Z"
},
{
"name": "rcourtman/Pulse",
"version": "v5.0.17",
"date": "2026-01-20T19:07:30Z"
},
{
"name": "netbox-community/netbox",
"version": "v4.5.1",
"date": "2026-01-20T19:45:05Z"
},
{
"name": "nickheyer/discopanel",
"version": "v1.0.24",
"date": "2026-01-20T18:31:20Z"
},
{
"name": "mysql/mysql-server",
"version": "mysql-cluster-8.0.45",
"date": "2026-01-20T18:27:03Z"
},
{
"name": "element-hq/synapse",
"version": "v1.145.0",
"date": "2026-01-13T16:49:51Z"
},
{
"name": "chrisvel/tududi",
"version": "v0.88.4",
"date": "2026-01-20T16:02:12Z"
},
{
"name": "gtsteffaniak/filebrowser",
"version": "v1.1.1-stable",
"date": "2026-01-12T23:25:10Z"
},
{
"name": "mattermost/mattermost",
"version": "@mattermost/client@11.3.0",
"date": "2026-01-20T15:26:31Z"
},
{
"name": "theonedev/onedev",
"version": "v14.0.8",
"date": "2026-01-20T15:10:44Z"
},
{
"name": "meilisearch/meilisearch",
"version": "latest",
"date": "2026-01-20T14:25:19Z"
},
{
"name": "sysadminsmedia/homebox",
"version": "v0.23.0-rc.1",
"date": "2026-01-20T14:19:56Z"
},
{
"name": "n8n-io/n8n",
"version": "n8n@2.3.6",
"date": "2026-01-16T15:00:42Z"
},
{
"name": "dgtlmoon/changedetection.io",
"version": "0.52.8",
"date": "2026-01-20T12:36:05Z"
},
{
"name": "lazy-media/reactive-resume",
"version": "v1.2.7",
"date": "2026-01-20T11:59:40Z"
},
{
"name": "cloudflare/cloudflared",
"version": "2026.1.1",
"date": "2026-01-20T11:22:06Z"
},
{
"name": "passbolt/passbolt_api",
"version": "v5.9.0-test.1",
"date": "2026-01-20T10:34:53Z"
},
{
"name": "Luligu/matterbridge",
"version": "3.5.0",
"date": "2026-01-20T08:53:52Z"
},
{
"name": "nzbgetcom/nzbget",
"version": "v25.4",
"date": "2025-10-09T10:27:01Z"
},
{
"name": "HydroshieldMKII/Guardian",
"version": "v1.3.4",
"date": "2026-01-20T06:20:36Z"
},
{
"name": "morpheus65535/bazarr",
"version": "v1.5.4",
"date": "2026-01-04T22:41:00Z"
},
{
"name": "diced/zipline",
"version": "v4.4.1",
"date": "2026-01-20T01:29:01Z"
},
{
"name": "binwiederhier/ntfy",
"version": "v2.16.0",
@@ -10,29 +290,9 @@
"date": "2026-01-19T20:51:19Z"
},
{
"name": "ollama/ollama",
"version": "v0.14.3-rc2",
"date": "2026-01-19T20:48:34Z"
},
{
"name": "firefly-iii/firefly-iii",
"version": "v6.4.16",
"date": "2026-01-17T07:54:15Z"
},
{
"name": "metabase/metabase",
"version": "v0.58.x",
"date": "2026-01-19T18:21:04Z"
},
{
"name": "apache/tomcat",
"version": "11.0.16",
"date": "2026-01-19T18:15:05Z"
},
{
"name": "paperless-ngx/paperless-ngx",
"version": "v2.20.5",
"date": "2026-01-19T17:55:57Z"
"name": "livebook-dev/livebook",
"version": "nightly",
"date": "2026-01-19T18:03:38Z"
},
{
"name": "ghostfolio/ghostfolio",
@@ -44,16 +304,6 @@
"version": "server-v3.5.2",
"date": "2025-12-19T21:28:55Z"
},
{
"name": "meilisearch/meilisearch",
"version": "prototype-v1.33.0-hannoy-better-linear-scanning.4",
"date": "2026-01-19T16:37:18Z"
},
{
"name": "Infisical/infisical",
"version": "v0.155.6",
"date": "2026-01-19T16:35:03Z"
},
{
"name": "bunkerity/bunkerweb",
"version": "v1.6.7",
@@ -69,11 +319,6 @@
"version": "pmm-6401-v1.134.0",
"date": "2026-01-19T13:31:08Z"
},
{
"name": "keycloak/keycloak",
"version": "26.4.8",
"date": "2026-01-15T13:52:29Z"
},
{
"name": "crowdsecurity/crowdsec",
"version": "v1.7.4",
@@ -94,36 +339,11 @@
"version": "v1.9.14",
"date": "2026-01-19T09:16:56Z"
},
{
"name": "dgtlmoon/changedetection.io",
"version": "0.52.7",
"date": "2026-01-19T08:38:05Z"
},
{
"name": "morpheus65535/bazarr",
"version": "v1.5.4",
"date": "2026-01-04T22:41:00Z"
},
{
"name": "Jackett/Jackett",
"version": "v0.24.887",
"date": "2026-01-19T05:55:24Z"
},
{
"name": "gethomepage/homepage",
"version": "v1.9.0",
"date": "2026-01-19T05:46:09Z"
},
{
"name": "nickheyer/discopanel",
"version": "v1.0.23",
"date": "2026-01-19T05:14:43Z"
},
{
"name": "9001/copyparty",
"version": "v1.20.2",
"date": "2026-01-19T02:20:10Z"
},
{
"name": "jellyfin/jellyfin",
"version": "v10.11.6",
@@ -134,16 +354,6 @@
"version": "2.1.0rc1",
"date": "2026-01-19T00:48:21Z"
},
{
"name": "steveiliop56/tinyauth",
"version": "v4.1.0",
"date": "2025-11-23T12:13:34Z"
},
{
"name": "jeedom/core",
"version": "4.5.2",
"date": "2026-01-19T00:27:05Z"
},
{
"name": "Kareadita/Kavita",
"version": "v0.8.9.1",
@@ -164,16 +374,6 @@
"version": "v2.5.0",
"date": "2026-01-18T22:16:38Z"
},
{
"name": "seerr-team/seerr",
"version": "preview-remonitor-sonarr-episodes",
"date": "2026-01-18T20:33:38Z"
},
{
"name": "fccview/jotty",
"version": "1.18.0",
"date": "2026-01-18T19:00:48Z"
},
{
"name": "Brandawg93/PeaNUT",
"version": "v5.21.2",
@@ -194,11 +394,6 @@
"version": "2.4",
"date": "2026-01-18T12:12:02Z"
},
{
"name": "BerriAI/litellm",
"version": "v1.81.0-nightly",
"date": "2026-01-18T04:06:15Z"
},
{
"name": "hyperion-project/hyperion.ng",
"version": "2.1.1",
@@ -209,26 +404,11 @@
"version": "v7.14.2",
"date": "2026-01-18T00:26:09Z"
},
{
"name": "chrisbenincasa/tunarr",
"version": "v1.1.1",
"date": "2026-01-17T22:35:09Z"
},
{
"name": "ZoeyVid/NPMplus",
"version": "2026-01-17-r3",
"date": "2026-01-17T21:45:17Z"
},
{
"name": "outline/outline",
"version": "v1.3.0",
"date": "2026-01-17T16:28:04Z"
},
{
"name": "evcc-io/evcc",
"version": "0.300.4",
"date": "2026-01-17T14:11:01Z"
},
{
"name": "LogicLabs-OU/OpenArchiver",
"version": "v0.4.1",
@@ -244,11 +424,6 @@
"version": "v6.13.6",
"date": "2025-11-04T13:35:35Z"
},
{
"name": "esphome/esphome",
"version": "2025.12.7",
"date": "2026-01-17T03:49:29Z"
},
{
"name": "coder/code-server",
"version": "v4.108.1",
@@ -269,26 +444,6 @@
"version": "v1.50.1",
"date": "2026-01-16T19:27:38Z"
},
{
"name": "livebook-dev/livebook",
"version": "v0.18.3",
"date": "2026-01-14T21:50:55Z"
},
{
"name": "cloudflare/cloudflared",
"version": "2026.1.0",
"date": "2026-01-16T17:48:15Z"
},
{
"name": "n8n-io/n8n",
"version": "n8n@2.3.6",
"date": "2026-01-16T15:00:42Z"
},
{
"name": "emqx/emqx",
"version": "6.0.2",
"date": "2026-01-16T13:52:11Z"
},
{
"name": "silverbulletmd/silverbullet",
"version": "2.4.1",
@@ -319,31 +474,11 @@
"version": "v0.13.6",
"date": "2026-01-15T23:34:51Z"
},
{
"name": "semaphoreui/semaphore",
"version": "v2.17.0-rc3",
"date": "2026-01-15T21:30:26Z"
},
{
"name": "azukaar/Cosmos-Server",
"version": "v0.20.0",
"date": "2026-01-15T20:59:44Z"
},
{
"name": "runtipi/runtipi",
"version": "nightly",
"date": "2026-01-15T20:03:50Z"
},
{
"name": "Stirling-Tools/Stirling-PDF",
"version": "v2.3.0",
"date": "2026-01-15T19:29:02Z"
},
{
"name": "Comfy-Org/ComfyUI",
"version": "v0.9.2",
"date": "2026-01-15T17:55:40Z"
},
{
"name": "zwave-js/zwave-js-ui",
"version": "v11.10.1",
@@ -359,26 +494,11 @@
"version": "0.24.3",
"date": "2026-01-15T14:40:15Z"
},
{
"name": "openobserve/openobserve",
"version": "v0.50.0-rc3",
"date": "2026-01-15T13:57:37Z"
},
{
"name": "readeck/readeck",
"version": "0.21.6",
"date": "2026-01-15T11:18:58Z"
},
{
"name": "mattermost/mattermost",
"version": "v10.11.10",
"date": "2026-01-15T10:36:07Z"
},
{
"name": "SigNoz/signoz",
"version": "v0.107.0",
"date": "2026-01-15T06:50:08Z"
},
{
"name": "zitadel/zitadel",
"version": "v4.9.1",
@@ -429,11 +549,6 @@
"version": "v3.3.1-rc2",
"date": "2026-01-14T12:29:28Z"
},
{
"name": "dedicatedcode/reitti",
"version": "v3.3.0",
"date": "2026-01-14T11:06:59Z"
},
{
"name": "cloudreve/cloudreve",
"version": "4.11.1",
@@ -474,31 +589,6 @@
"version": "v0.5.5",
"date": "2026-01-13T17:03:32Z"
},
{
"name": "element-hq/synapse",
"version": "v1.145.0",
"date": "2026-01-13T16:49:51Z"
},
{
"name": "LimeSurvey/LimeSurvey",
"version": "6.16.3+251215",
"date": "2026-01-13T10:36:10Z"
},
{
"name": "endurain-project/endurain",
"version": "v0.16.6",
"date": "2026-01-13T10:28:14Z"
},
{
"name": "jenkinsci/jenkins",
"version": "jenkins-2.546",
"date": "2026-01-13T10:08:09Z"
},
{
"name": "Luligu/matterbridge",
"version": "3.4.7",
"date": "2026-01-13T07:28:02Z"
},
{
"name": "henrygd/beszel",
"version": "v0.18.2",
@@ -514,11 +604,6 @@
"version": "26.1.1",
"date": "2026-01-12T23:26:02Z"
},
{
"name": "gtsteffaniak/filebrowser",
"version": "v1.1.1-stable",
"date": "2026-01-12T23:25:10Z"
},
{
"name": "influxdata/influxdb",
"version": "v2.8.0",
@@ -534,11 +619,6 @@
"version": "v1.7.10",
"date": "2026-01-12T20:50:50Z"
},
{
"name": "rcourtman/Pulse",
"version": "v5.0.16",
"date": "2026-01-12T20:18:34Z"
},
{
"name": "release-argus/Argus",
"version": "0.29.2",
@@ -624,11 +704,6 @@
"version": "v0.14.1",
"date": "2024-08-29T22:32:51Z"
},
{
"name": "theonedev/onedev",
"version": "v14.0.7",
"date": "2026-01-10T10:31:47Z"
},
{
"name": "Kozea/Radicale",
"version": "v3.6.0",
@@ -709,21 +784,11 @@
"version": "5.2.7",
"date": "2026-01-07T23:48:00Z"
},
{
"name": "prometheus/prometheus",
"version": "v0.309.1",
"date": "2026-01-07T19:20:52Z"
},
{
"name": "leiweibau/Pi.Alert",
"version": "v2026-01-07",
"date": "2026-01-07T18:50:28Z"
},
{
"name": "node-red/node-red",
"version": "4.1.3",
"date": "2026-01-07T16:24:23Z"
},
{
"name": "MDeLuise/plant-it",
"version": "1.0.1",
@@ -759,11 +824,6 @@
"version": "2.46.0",
"date": "2026-01-07T00:19:31Z"
},
{
"name": "netbox-community/netbox",
"version": "v4.5.0",
"date": "2026-01-06T21:14:27Z"
},
{
"name": "caddyserver/caddy",
"version": "v2.10.2",
@@ -822,7 +882,7 @@
{
"name": "mealie-recipes/mealie",
"version": "v3.9.2",
"date": "2026-01-02T19:40:09Z"
"date": "2026-01-02T19:40:19Z"
},
{
"name": "gotify/server",
@@ -849,11 +909,6 @@
"version": "v25.12.1",
"date": "2025-12-30T17:25:57Z"
},
{
"name": "javedh-dev/tracktor",
"version": "1.1.0",
"date": "2025-12-30T04:42:18Z"
},
{
"name": "ArchiveBox/ArchiveBox",
"version": "v0.8.6rc1",
@@ -874,16 +929,6 @@
"version": "v4.7.0",
"date": "2025-12-27T20:37:54Z"
},
{
"name": "sysadminsmedia/homebox",
"version": "v0.22.3",
"date": "2025-12-26T22:31:20Z"
},
{
"name": "HydroshieldMKII/Guardian",
"version": "v1.3.3",
"date": "2025-12-25T20:19:52Z"
},
{
"name": "matze/wastebin",
"version": "3.4.0",
@@ -919,11 +964,6 @@
"version": "v5.7",
"date": "2025-12-23T14:53:51Z"
},
{
"name": "nzbgetcom/nzbget",
"version": "v25.4",
"date": "2025-10-09T10:27:01Z"
},
{
"name": "itsmng/itsm-ng",
"version": "v1.6.11",
@@ -944,16 +984,6 @@
"version": "v4.0.16.2944",
"date": "2025-11-05T01:56:48Z"
},
{
"name": "chrisvel/tududi",
"version": "v0.88.2",
"date": "2025-12-22T14:36:59Z"
},
{
"name": "passbolt/passbolt_api",
"version": "v5.8.0",
"date": "2025-12-22T10:12:48Z"
},
{
"name": "benjaminjonard/koillection",
"version": "1.7.1",
@@ -1009,11 +1039,6 @@
"version": "v1.25.3",
"date": "2025-12-18T18:11:48Z"
},
{
"name": "docker/compose",
"version": "v5.0.1",
"date": "2025-12-18T14:22:38Z"
},
{
"name": "juanfont/headscale",
"version": "v0.27.1",
@@ -1034,11 +1059,6 @@
"version": "v4.1.0",
"date": "2025-12-15T18:53:25Z"
},
{
"name": "rabbitmq/rabbitmq-server",
"version": "v4.2.2",
"date": "2025-12-15T18:25:36Z"
},
{
"name": "docmost/docmost",
"version": "v0.24.1",
@@ -1059,11 +1079,6 @@
"version": "v1.13.2",
"date": "2025-12-13T22:59:03Z"
},
{
"name": "diced/zipline",
"version": "v4.4.0",
"date": "2025-12-13T22:49:07Z"
},
{
"name": "WGDashboard/WGDashboard",
"version": "v4.3.1",
@@ -1424,31 +1439,16 @@
"version": "v2.2.2",
"date": "2025-10-06T21:31:07Z"
},
{
"name": "mysql/mysql-server",
"version": "mysql-cluster-7.6.36",
"date": "2025-10-06T15:19:49Z"
},
{
"name": "jordan-dalby/ByteStash",
"version": "v1.5.9",
"date": "2025-10-06T08:34:01Z"
},
{
"name": "donetick/donetick",
"version": "v0.1.64",
"date": "2025-10-03T05:18:24Z"
},
{
"name": "thomiceli/opengist",
"version": "v1.11.1",
"date": "2025-09-30T00:24:16Z"
},
{
"name": "lazy-media/Reactive-Resume",
"version": "v1.2.6",
"date": "2025-09-28T18:09:21Z"
},
{
"name": "Pf2eToolsOrg/Pf2eTools",
"version": "v0.10.1",

50
install/byparr-install.sh Normal file
View File

@@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: luismco
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/ThePhaseless/Byparr
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt -y install \
xauth \
xvfb \
scrot \
chromium \
chromium-driver \
ca-certificates
msg_ok "Installed Dependencies"
fetch_and_deploy_gh_release "Byparr" "ThePhaseless/Byparr" "tarball" "latest"
setup_uv
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/byparr.service
[Unit]
Description=Byparr
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/Byparr
ExecStart=/usr/local/bin/uv run python3 main.py
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now byparr
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -21,9 +21,6 @@ rm -rf /opt/checkmk.deb
echo "${RELEASE}" >"/opt/checkmk_version.txt"
msg_ok "Installed Checkmk"
motd_ssh
customize
msg_info "Creating Service"
SITE_NAME="monitoring"
$STD omd create "$SITE_NAME"
@@ -42,3 +39,5 @@ $STD omd start "$SITE_NAME"
msg_ok "Created Service"
cleanup_lxc
motd_ssh
customize

View File

@@ -34,7 +34,7 @@ msg_info "Setup Dolibarr"
BASE="https://sourceforge.net/projects/dolibarr/files/Dolibarr%20installer%20for%20Debian-Ubuntu%20(DoliDeb)/"
RELEASE=$(curl -fsSL "$BASE" | grep -oP '(?<=/Dolibarr%20installer%20for%20Debian-Ubuntu%20%28DoliDeb%29/)\d+(\.\d+)+(?=/)' | sort -V | tail -n1)
FILE=$(curl -fsSL "${BASE}${RELEASE}/" | grep -oP 'dolibarr_[^"]+_all.deb' | head -n1)
curl -fsSL "https://netcologne.dl.sourceforge.net/project/dolibarr/Dolibarr%20installer%20for%20Debian-Ubuntu%20(DoliDeb)/${RELEASE}/${FILE}?viasf=1" -o ""$FILE""
curl -fsSL "https://altushost-swe.dl.sourceforge.net/project/dolibarr/Dolibarr%20installer%20for%20Debian-Ubuntu%20(DoliDeb)/${RELEASE}/${FILE}?viasf=1" -o ""$FILE""
echo "dolibarr dolibarr/reconfigure-webserver multiselect apache2" | debconf-set-selections
$STD apt-get install ./$FILE -y
$STD apt install -f

View File

@@ -36,8 +36,9 @@ cd /opt/joplin-server
sed -i "/onenote-converter/d" packages/lib/package.json
$STD yarn config set --home enableTelemetry 0
export BUILD_SEQUENCIAL=1
$STD yarn install --inline-builds
$STD yarn workspaces focus @joplin/server
$STD yarn workspaces foreach -R --topological-dev --from @joplin/server run build
$STD yarn workspaces foreach -R --topological-dev --from @joplin/server run tsc
cat <<EOF >/opt/joplin-server/.env
PM2_HOME=/opt/pm2
NODE_ENV=production

View File

@@ -59,7 +59,7 @@ msg_ok "Installed Python Dependencies"
msg_info "Creating Service"
cat <<EOF >/opt/yubal.env
YUBAL_HOST=0.0.0.0
YUBAL_PORT=8001
YUBAL_PORT=8000
YUBAL_DATA=/opt/yubal_data
YUBAL_CONFIG=/opt/yubal_config
YUBAL_ROOT=/opt/yubal
@@ -76,7 +76,7 @@ User=root
WorkingDirectory=/opt/yubal
EnvironmentFile=/opt/yubal.env
Environment="PATH=/opt/yubal/.venv/bin:/usr/local/bin:/usr/bin:/bin"
ExecStart=/opt/yubal/.venv/bin/python -m yubal
ExecStart=/opt/yubal/.venv/bin/python -m yubal_api
Restart=always
RestartSec=5

View File

@@ -357,6 +357,268 @@ validate_hostname() {
return 0
}
# ------------------------------------------------------------------------------
# validate_mac_address()
#
# - Validates MAC address format (XX:XX:XX:XX:XX:XX)
# - Empty value is allowed (auto-generated)
# - Returns 0 if valid, 1 if invalid
# ------------------------------------------------------------------------------
validate_mac_address() {
local mac="$1"
[[ -z "$mac" ]] && return 0
if [[ ! "$mac" =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]]; then
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# validate_vlan_tag()
#
# - Validates VLAN tag (1-4094)
# - Empty value is allowed (no VLAN)
# - Returns 0 if valid, 1 if invalid
# ------------------------------------------------------------------------------
validate_vlan_tag() {
local vlan="$1"
[[ -z "$vlan" ]] && return 0
if ! [[ "$vlan" =~ ^[0-9]+$ ]] || ((vlan < 1 || vlan > 4094)); then
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# validate_mtu()
#
# - Validates MTU size (576-65535, common values: 1500, 9000)
# - Empty value is allowed (default 1500)
# - Returns 0 if valid, 1 if invalid
# ------------------------------------------------------------------------------
validate_mtu() {
local mtu="$1"
[[ -z "$mtu" ]] && return 0
if ! [[ "$mtu" =~ ^[0-9]+$ ]] || ((mtu < 576 || mtu > 65535)); then
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# validate_ipv6_address()
#
# - Validates IPv6 address with optional CIDR notation
# - Supports compressed (::) and full notation
# - Empty value is allowed
# - Returns 0 if valid, 1 if invalid
# ------------------------------------------------------------------------------
validate_ipv6_address() {
local ipv6="$1"
[[ -z "$ipv6" ]] && return 0
# Extract address and CIDR
local addr="${ipv6%%/*}"
local cidr="${ipv6##*/}"
# Validate CIDR if present (1-128)
if [[ "$ipv6" == */* ]]; then
if ! [[ "$cidr" =~ ^[0-9]+$ ]] || ((cidr < 1 || cidr > 128)); then
return 1
fi
fi
# Basic IPv6 validation - check for valid characters and structure
# Must contain only hex digits and colons
if [[ ! "$addr" =~ ^[0-9a-fA-F:]+$ ]]; then
return 1
fi
# Must contain at least one colon
if [[ ! "$addr" == *:* ]]; then
return 1
fi
# Check for valid double-colon usage (only one :: allowed)
if [[ "$addr" == *::*::* ]]; then
return 1
fi
# Check that no segment exceeds 4 hex chars
local IFS=':'
local -a segments
read -ra segments <<< "$addr"
for seg in "${segments[@]}"; do
if [[ ${#seg} -gt 4 ]]; then
return 1
fi
done
return 0
}
# ------------------------------------------------------------------------------
# validate_bridge()
#
# - Validates that network bridge exists and is active
# - Returns 0 if valid, 1 if invalid
# ------------------------------------------------------------------------------
validate_bridge() {
local bridge="$1"
[[ -z "$bridge" ]] && return 1
# Check if bridge interface exists
if ! ip link show "$bridge" &>/dev/null; then
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# validate_gateway_in_subnet()
#
# - Validates that gateway IP is in the same subnet as static IP
# - Arguments: static_ip (with CIDR), gateway_ip
# - Returns 0 if valid, 1 if invalid
# ------------------------------------------------------------------------------
validate_gateway_in_subnet() {
local static_ip="$1"
local gateway="$2"
[[ -z "$static_ip" || -z "$gateway" ]] && return 0
# Extract IP and CIDR
local ip="${static_ip%%/*}"
local cidr="${static_ip##*/}"
# Convert CIDR to netmask bits
local mask=$((0xFFFFFFFF << (32 - cidr) & 0xFFFFFFFF))
# Convert IPs to integers
local IFS='.'
read -r i1 i2 i3 i4 <<< "$ip"
read -r g1 g2 g3 g4 <<< "$gateway"
local ip_int=$(( (i1 << 24) + (i2 << 16) + (i3 << 8) + i4 ))
local gw_int=$(( (g1 << 24) + (g2 << 16) + (g3 << 8) + g4 ))
# Check if both are in same network
if (( (ip_int & mask) != (gw_int & mask) )); then
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# validate_ip_address()
#
# - Validates IPv4 address with CIDR notation
# - Checks each octet is 0-255
# - Checks CIDR is 1-32
# - Returns 0 if valid, 1 if invalid
# ------------------------------------------------------------------------------
validate_ip_address() {
local ip="$1"
[[ -z "$ip" ]] && return 1
# Check format with CIDR
if [[ ! "$ip" =~ ^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/([0-9]{1,2})$ ]]; then
return 1
fi
local o1="${BASH_REMATCH[1]}"
local o2="${BASH_REMATCH[2]}"
local o3="${BASH_REMATCH[3]}"
local o4="${BASH_REMATCH[4]}"
local cidr="${BASH_REMATCH[5]}"
# Validate octets (0-255)
for octet in "$o1" "$o2" "$o3" "$o4"; do
if ((octet > 255)); then
return 1
fi
done
# Validate CIDR (1-32)
if ((cidr < 1 || cidr > 32)); then
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# validate_gateway_ip()
#
# - Validates gateway IPv4 address (without CIDR)
# - Checks each octet is 0-255
# - Returns 0 if valid, 1 if invalid
# ------------------------------------------------------------------------------
validate_gateway_ip() {
local ip="$1"
[[ -z "$ip" ]] && return 0
# Check format without CIDR
if [[ ! "$ip" =~ ^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$ ]]; then
return 1
fi
local o1="${BASH_REMATCH[1]}"
local o2="${BASH_REMATCH[2]}"
local o3="${BASH_REMATCH[3]}"
local o4="${BASH_REMATCH[4]}"
# Validate octets (0-255)
for octet in "$o1" "$o2" "$o3" "$o4"; do
if ((octet > 255)); then
return 1
fi
done
return 0
}
# ------------------------------------------------------------------------------
# validate_timezone()
#
# - Validates timezone string against system zoneinfo
# - Empty value or "host" is allowed
# - Returns 0 if valid, 1 if invalid
# ------------------------------------------------------------------------------
validate_timezone() {
local tz="$1"
[[ -z "$tz" || "$tz" == "host" ]] && return 0
# Check if timezone file exists
if [[ ! -f "/usr/share/zoneinfo/$tz" ]]; then
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# validate_tags()
#
# - Validates Proxmox tags format
# - Only alphanumeric, hyphens, underscores, and semicolons allowed
# - Empty value is allowed
# - Returns 0 if valid, 1 if invalid
# ------------------------------------------------------------------------------
validate_tags() {
local tags="$1"
[[ -z "$tags" ]] && return 0
# Tags can only contain alphanumeric, -, _, and ; (separator)
if [[ ! "$tags" =~ ^[a-zA-Z0-9_\;-]+$ ]]; then
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# find_host_ssh_keys()
#
@@ -772,6 +1034,119 @@ load_vars_file() {
# Trim trailing whitespace
var_val="${var_val%"${var_val##*[![:space:]]}"}"
# Validate values before setting (skip empty values - they use defaults)
if [[ -n "$var_val" ]]; then
case "$var_key" in
var_mac)
if ! validate_mac_address "$var_val"; then
msg_warn "Invalid MAC address '$var_val' in $file, ignoring"
continue
fi
;;
var_vlan)
if ! validate_vlan_tag "$var_val"; then
msg_warn "Invalid VLAN tag '$var_val' in $file (must be 1-4094), ignoring"
continue
fi
;;
var_mtu)
if ! validate_mtu "$var_val"; then
msg_warn "Invalid MTU '$var_val' in $file (must be 576-65535), ignoring"
continue
fi
;;
var_tags)
if ! validate_tags "$var_val"; then
msg_warn "Invalid tags '$var_val' in $file (alphanumeric, -, _, ; only), ignoring"
continue
fi
;;
var_timezone)
if ! validate_timezone "$var_val"; then
msg_warn "Invalid timezone '$var_val' in $file, ignoring"
continue
fi
;;
var_brg)
if ! validate_bridge "$var_val"; then
msg_warn "Bridge '$var_val' not found in $file, ignoring"
continue
fi
;;
var_gateway)
if ! validate_gateway_ip "$var_val"; then
msg_warn "Invalid gateway IP '$var_val' in $file, ignoring"
continue
fi
;;
var_hostname)
if ! validate_hostname "$var_val"; then
msg_warn "Invalid hostname '$var_val' in $file, ignoring"
continue
fi
;;
var_cpu)
if ! [[ "$var_val" =~ ^[0-9]+$ ]] || ((var_val < 1 || var_val > 128)); then
msg_warn "Invalid CPU count '$var_val' in $file (must be 1-128), ignoring"
continue
fi
;;
var_ram)
if ! [[ "$var_val" =~ ^[0-9]+$ ]] || ((var_val < 256)); then
msg_warn "Invalid RAM '$var_val' in $file (must be >= 256 MiB), ignoring"
continue
fi
;;
var_disk)
if ! [[ "$var_val" =~ ^[0-9]+$ ]] || ((var_val < 1)); then
msg_warn "Invalid disk size '$var_val' in $file (must be >= 1 GB), ignoring"
continue
fi
;;
var_unprivileged)
if [[ "$var_val" != "0" && "$var_val" != "1" ]]; then
msg_warn "Invalid unprivileged value '$var_val' in $file (must be 0 or 1), ignoring"
continue
fi
;;
var_nesting)
if [[ "$var_val" != "0" && "$var_val" != "1" ]]; then
msg_warn "Invalid nesting value '$var_val' in $file (must be 0 or 1), ignoring"
continue
fi
;;
var_keyctl)
if [[ "$var_val" != "0" && "$var_val" != "1" ]]; then
msg_warn "Invalid keyctl value '$var_val' in $file (must be 0 or 1), ignoring"
continue
fi
;;
var_net)
# var_net can be: dhcp, static IP/CIDR, or IP range
if [[ "$var_val" != "dhcp" ]]; then
if is_ip_range "$var_val"; then
: # IP range is valid, will be resolved at runtime
elif ! validate_ip_address "$var_val"; then
msg_warn "Invalid network '$var_val' in $file (must be dhcp or IP/CIDR), ignoring"
continue
fi
fi
;;
var_fuse|var_tun|var_gpu|var_ssh|var_verbose|var_protection)
if [[ "$var_val" != "yes" && "$var_val" != "no" ]]; then
msg_warn "Invalid boolean '$var_val' for $var_key in $file (must be yes/no), ignoring"
continue
fi
;;
var_ipv6_method)
if [[ "$var_val" != "auto" && "$var_val" != "dhcp" && "$var_val" != "static" && "$var_val" != "none" ]]; then
msg_warn "Invalid IPv6 method '$var_val' in $file (must be auto/dhcp/static/none), ignoring"
continue
fi
;;
esac
fi
# Set variable: force mode overrides existing, otherwise only set if empty
if [[ "$force" == "yes" ]]; then
export "${var_key}=${var_val}"
@@ -1612,8 +1987,14 @@ advanced_settings() {
# ═══════════════════════════════════════════════════════════════════════════
8)
if [[ ${#BRIDGE_MENU_OPTIONS[@]} -eq 0 ]]; then
_bridge="vmbr0"
((STEP++))
# Validate default bridge exists
if validate_bridge "vmbr0"; then
_bridge="vmbr0"
((STEP++))
else
whiptail --msgbox "Default bridge 'vmbr0' not found!\n\nPlease configure a network bridge in Proxmox first." 10 58
exit 1
fi
else
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "NETWORK BRIDGE" \
@@ -1621,8 +2002,13 @@ advanced_settings() {
--menu "\nSelect network bridge:" 16 58 6 \
"${BRIDGE_MENU_OPTIONS[@]}" \
3>&1 1>&2 2>&3); then
_bridge="${result:-vmbr0}"
((STEP++))
local bridge_test="${result:-vmbr0}"
if validate_bridge "$bridge_test"; then
_bridge="$bridge_test"
((STEP++))
else
whiptail --msgbox "Bridge '$bridge_test' is not available or not active." 8 58
fi
else
((STEP--))
fi
@@ -1650,7 +2036,7 @@ advanced_settings() {
--ok-button "Next" --cancel-button "Back" \
--inputbox "\nEnter Static IPv4 CIDR Address\n(e.g. 192.168.1.100/24)" 12 58 "" \
3>&1 1>&2 2>&3); then
if [[ "$static_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/([0-9]|[1-2][0-9]|3[0-2])$ ]]; then
if validate_ip_address "$static_ip"; then
# Get gateway
local gateway_ip
if gateway_ip=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
@@ -1658,16 +2044,21 @@ advanced_settings() {
--ok-button "Next" --cancel-button "Back" \
--inputbox "\nEnter Gateway IP address" 10 58 "" \
3>&1 1>&2 2>&3); then
if [[ "$gateway_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
_net="$static_ip"
_gate=",gw=$gateway_ip"
((STEP++))
if validate_gateway_ip "$gateway_ip"; then
# Validate gateway is in same subnet
if validate_gateway_in_subnet "$static_ip" "$gateway_ip"; then
_net="$static_ip"
_gate=",gw=$gateway_ip"
((STEP++))
else
whiptail --msgbox "Gateway is not in the same subnet as the static IP.\n\nStatic IP: $static_ip\nGateway: $gateway_ip" 10 58
fi
else
whiptail --msgbox "Invalid Gateway IP format." 8 58
whiptail --msgbox "Invalid Gateway IP format.\n\nEach octet must be 0-255.\nExample: 192.168.1.1" 10 58
fi
fi
else
whiptail --msgbox "Invalid IPv4 CIDR format.\nExample: 192.168.1.100/24" 8 58
whiptail --msgbox "Invalid IPv4 CIDR format.\n\nEach octet must be 0-255.\nCIDR must be 1-32.\nExample: 192.168.1.100/24" 12 58
fi
fi
elif [[ "$result" == "range" ]]; then
@@ -1691,12 +2082,17 @@ advanced_settings() {
--ok-button "Next" --cancel-button "Back" \
--inputbox "\nFound free IP: $NET_RESOLVED\n\nEnter Gateway IP address" 12 58 "" \
3>&1 1>&2 2>&3); then
if [[ "$gateway_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
_net="$NET_RESOLVED"
_gate=",gw=$gateway_ip"
((STEP++))
if validate_gateway_ip "$gateway_ip"; then
# Validate gateway is in same subnet
if validate_gateway_in_subnet "$NET_RESOLVED" "$gateway_ip"; then
_net="$NET_RESOLVED"
_gate=",gw=$gateway_ip"
((STEP++))
else
whiptail --msgbox "Gateway is not in the same subnet as the IP.\n\nIP: $NET_RESOLVED\nGateway: $gateway_ip" 10 58
fi
else
whiptail --msgbox "Invalid Gateway IP format." 8 58
whiptail --msgbox "Invalid Gateway IP format.\n\nEach octet must be 0-255.\nExample: 192.168.1.1" 10 58
fi
fi
else
@@ -1739,16 +2135,33 @@ advanced_settings() {
--title "STATIC IPv6 ADDRESS" \
--inputbox "\nEnter IPv6 CIDR address\n(e.g. 2001:db8::1/64)" 12 58 "" \
3>&1 1>&2 2>&3); then
if [[ "$ipv6_addr" =~ ^([0-9a-fA-F:]+:+)+[0-9a-fA-F]+(/[0-9]{1,3})$ ]]; then
if validate_ipv6_address "$ipv6_addr"; then
_ipv6_addr="$ipv6_addr"
# Optional gateway
_ipv6_gate=$(whiptail --backtitle "Proxmox VE Helper Scripts" \
--title "IPv6 GATEWAY" \
--inputbox "\nEnter IPv6 gateway (optional, leave blank for none)" 10 58 "" \
3>&1 1>&2 2>&3) || true
((STEP++))
# Optional gateway - loop until valid or empty
local ipv6_gw_valid=false
while [[ "$ipv6_gw_valid" == "false" ]]; do
local ipv6_gw
ipv6_gw=$(whiptail --backtitle "Proxmox VE Helper Scripts" \
--title "IPv6 GATEWAY" \
--inputbox "\nEnter IPv6 gateway (optional, leave blank for none)" 10 58 "" \
3>&1 1>&2 2>&3) || true
# Validate gateway if provided
if [[ -n "$ipv6_gw" ]]; then
if validate_ipv6_address "$ipv6_gw"; then
_ipv6_gate="$ipv6_gw"
ipv6_gw_valid=true
((STEP++))
else
whiptail --msgbox "Invalid IPv6 gateway format.\n\nExample: 2001:db8::1" 8 58
fi
else
_ipv6_gate=""
ipv6_gw_valid=true
((STEP++))
fi
done
else
whiptail --msgbox "Invalid IPv6 CIDR format." 8 58
whiptail --msgbox "Invalid IPv6 CIDR format.\n\nExample: 2001:db8::1/64\nCIDR must be 1-128." 10 58
fi
fi
;;
@@ -1781,10 +2194,14 @@ advanced_settings() {
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "MTU SIZE" \
--ok-button "Next" --cancel-button "Back" \
--inputbox "\nSet Interface MTU Size\n(leave blank for default 1500)" 12 58 "" \
--inputbox "\nSet Interface MTU Size\n(leave blank for default 1500, common values: 1500, 9000)" 12 62 "" \
3>&1 1>&2 2>&3); then
_mtu="$result"
((STEP++))
if validate_mtu "$result"; then
_mtu="$result"
((STEP++))
else
whiptail --msgbox "Invalid MTU size.\n\nMTU must be between 576 and 65535.\nCommon values: 1500 (default), 9000 (jumbo frames)" 10 58
fi
else
((STEP--))
fi
@@ -1829,10 +2246,14 @@ advanced_settings() {
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "MAC ADDRESS" \
--ok-button "Next" --cancel-button "Back" \
--inputbox "\nSet MAC Address\n(leave blank for auto-generated)" 12 58 "" \
--inputbox "\nSet MAC Address\n(leave blank for auto-generated, format: XX:XX:XX:XX:XX:XX)" 12 62 "" \
3>&1 1>&2 2>&3); then
_mac="$result"
((STEP++))
if validate_mac_address "$result"; then
_mac="$result"
((STEP++))
else
whiptail --msgbox "Invalid MAC address format.\n\nRequired format: XX:XX:XX:XX:XX:XX\nExample: 02:00:00:00:00:01" 10 58
fi
else
((STEP--))
fi
@@ -1845,10 +2266,14 @@ advanced_settings() {
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "VLAN TAG" \
--ok-button "Next" --cancel-button "Back" \
--inputbox "\nSet VLAN Tag\n(leave blank for no VLAN)" 12 58 "" \
--inputbox "\nSet VLAN Tag (1-4094)\n(leave blank for no VLAN)" 12 58 "" \
3>&1 1>&2 2>&3); then
_vlan="$result"
((STEP++))
if validate_vlan_tag "$result"; then
_vlan="$result"
((STEP++))
else
whiptail --msgbox "Invalid VLAN tag.\n\nVLAN must be a number between 1 and 4094." 8 58
fi
else
((STEP--))
fi
@@ -1861,11 +2286,16 @@ advanced_settings() {
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "CONTAINER TAGS" \
--ok-button "Next" --cancel-button "Back" \
--inputbox "\nSet Custom Tags (semicolon-separated)\n(remove all for no tags)" 12 58 "$_tags" \
--inputbox "\nSet Custom Tags (semicolon-separated)\n(alphanumeric, hyphens, underscores only)" 12 58 "$_tags" \
3>&1 1>&2 2>&3); then
_tags="${result:-;}"
_tags=$(echo "$_tags" | tr -d '[:space:]')
((STEP++))
local tags_test="${result:-}"
tags_test=$(echo "$tags_test" | tr -d '[:space:]')
if validate_tags "$tags_test"; then
_tags="$tags_test"
((STEP++))
else
whiptail --msgbox "Invalid tag format.\n\nTags can only contain:\n- Letters (a-z, A-Z)\n- Numbers (0-9)\n- Hyphens (-)\n- Underscores (_)\n- Semicolons (;) as separator" 14 58
fi
else
((STEP--))
fi
@@ -2044,9 +2474,14 @@ advanced_settings() {
--ok-button "Next" --cancel-button "Back" \
--inputbox "\nSet container timezone.\n\nExamples: Europe/Berlin, America/New_York, Asia/Tokyo\n\nHost timezone: ${_host_timezone:-unknown}\n\nLeave empty to inherit from host." 16 62 "$_ct_timezone" \
3>&1 1>&2 2>&3); then
_ct_timezone="$result"
[[ "${_ct_timezone:-}" == Etc/* ]] && _ct_timezone="host" # pct doesn't accept Etc/* zones
((STEP++))
local tz_test="$result"
[[ "${tz_test:-}" == Etc/* ]] && tz_test="host" # pct doesn't accept Etc/* zones
if validate_timezone "$tz_test"; then
_ct_timezone="$tz_test"
((STEP++))
else
whiptail --msgbox "Invalid timezone: '$result'\n\nTimezone must exist in /usr/share/zoneinfo/\n\nExamples:\n- Europe/Berlin\n- America/New_York\n- Asia/Tokyo\n- UTC" 14 58
fi
else
((STEP--))
fi
@@ -2843,6 +3278,7 @@ start() {
elif [ ! -z ${PHS_SILENT+x} ] && [[ "${PHS_SILENT}" == "1" ]]; then
VERBOSE="no"
set_std_mode
ensure_profile_loaded
update_script
cleanup_lxc
else
@@ -2868,6 +3304,7 @@ start() {
exit
;;
esac
ensure_profile_loaded
update_script
cleanup_lxc
fi
@@ -3005,8 +3442,13 @@ build_container() {
export DEV_MODE_DRYRUN="${DEV_MODE_DRYRUN:-false}"
# Build PCT_OPTIONS as multi-line string
PCT_OPTIONS_STRING=" -hostname $HN
PCT_OPTIONS_STRING=" -hostname $HN"
# Only add -tags if TAGS is not empty
if [ -n "$TAGS" ]; then
PCT_OPTIONS_STRING="$PCT_OPTIONS_STRING
-tags $TAGS"
fi
# Only add -features if FEATURES is not empty
if [ -n "$FEATURES" ]; then
@@ -4036,37 +4478,42 @@ create_lxc_container() {
msg_info "Searching for template '$TEMPLATE_SEARCH'"
# Initialize variables
ONLINE_TEMPLATE=""
ONLINE_TEMPLATES=()
# 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
)
pveam update >/dev/null 2>&1 || msg_warn "Could not update template catalog (pveam update failed)."
msg_ok "Template search completed"
set +u
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)
set -u
ONLINE_TEMPLATE=""
[[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
if [[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]]; then
count=0
for idx in "${!ONLINE_TEMPLATES[@]}"; do
((count++))
[[ $count -ge 3 ]] && break
done
fi
# 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)"
fi
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
@@ -4075,6 +4522,7 @@ create_lxc_container() {
echo "[DEBUG] 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)$' |
@@ -4097,6 +4545,7 @@ create_lxc_container() {
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)$' |
@@ -4306,50 +4755,88 @@ create_lxc_container() {
-rootfs $CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}"
fi
# Lock by template file (avoid concurrent downloads/creates)
# Lock by template file (avoid concurrent template downloads/validation)
lockfile="/tmp/template.${TEMPLATE}.lock"
# Cleanup stale lock files (older than 1 hour - likely from crashed processes)
if [[ -f "$lockfile" ]]; then
local lock_age=$(($(date +%s) - $(stat -c %Y "$lockfile" 2>/dev/null || echo 0)))
if [[ $lock_age -gt 3600 ]]; then
msg_warn "Removing stale template lock file (age: ${lock_age}s)"
rm -f "$lockfile"
fi
fi
exec 9>"$lockfile" || {
msg_error "Failed to create lock file '$lockfile'."
exit 200
}
flock -w 60 9 || {
msg_error "Timeout while waiting for template lock."
exit 211
}
# Retry logic for template lock (another container creation may be running)
local lock_attempts=0
local max_lock_attempts=10
local lock_wait_time=30
while ! flock -w "$lock_wait_time" 9; do
lock_attempts=$((lock_attempts + 1))
if [[ $lock_attempts -ge $max_lock_attempts ]]; then
msg_error "Timeout while waiting for template lock after ${max_lock_attempts} attempts."
msg_custom "💡" "${YW}" "Another container creation may be stuck. Check running processes or remove: $lockfile"
exit 211
fi
msg_custom "⏳" "${YW}" "Another container is being created with this template. Waiting... (attempt ${lock_attempts}/${max_lock_attempts})"
done
LOGFILE="/tmp/pct_create_${CTID}_$(date +%Y%m%d_%H%M%S)_${SESSION_ID}.log"
# 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"
rm -f "$TEMPLATE_PATH"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1
msg_ok "Template downloaded"
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
if [[ -n "$ONLINE_TEMPLATE" ]]; then
msg_info "Template appears corrupted re-downloading"
rm -f "$TEMPLATE_PATH"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1
msg_ok "Template re-downloaded"
else
msg_warn "Template appears corrupted, but no online version exists. Skipping re-download."
fi
fi
# Release lock after template validation - pct create has its own internal locking
exec 9>&-
msg_debug "pct create command: pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} $PCT_OPTIONS"
msg_debug "Logfile: $LOGFILE"
# First attempt (PCT_OPTIONS is a multi-line string, use it directly)
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >"$LOGFILE" 2>&1; then
msg_debug "Container creation failed on ${TEMPLATE_STORAGE}. Validating template..."
msg_debug "Container creation failed on ${TEMPLATE_STORAGE}. Checking error..."
# Validate template file
if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
msg_warn "Template file too small or missing re-downloading."
# Check if template issue - retry with fresh download
if grep -qiE 'unable to open|corrupt|invalid' "$LOGFILE"; then
msg_info "Template may be corrupted re-downloading"
rm -f "$TEMPLATE_PATH"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE"
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
if [[ -n "$ONLINE_TEMPLATE" ]]; then
msg_warn "Template appears corrupted re-downloading."
rm -f "$TEMPLATE_PATH"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE"
else
msg_warn "Template appears corrupted, but no online version exists. Skipping re-download."
fi
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1
msg_ok "Template re-downloaded"
fi
# Retry after repair
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >>"$LOGFILE" 2>&1; then
# Fallback to local storage if not already on local
if [[ "$TEMPLATE_STORAGE" != "local" ]]; then
msg_info "Retrying container creation with fallback to local storage..."
msg_info "Retrying container creation with fallback to local storage"
LOCAL_TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then
msg_info "Downloading template to local..."
msg_ok "Trying local storage fallback"
msg_info "Downloading template to local"
pveam download local "$TEMPLATE" >/dev/null 2>&1
msg_ok "Template downloaded to local"
else
msg_ok "Trying local storage fallback"
fi
if ! pct create "$CTID" "local:vztmpl/${TEMPLATE}" $PCT_OPTIONS >>"$LOGFILE" 2>&1; then
# Local fallback also failed - check for LXC stack version issue

View File

@@ -38,8 +38,6 @@ load_functions() {
icons
default_vars
set_std_mode
# Note: get_lxc_ip() is NOT called here automatically
# Call it explicitly when you need LOCAL_IP variable
}
# ------------------------------------------------------------------------------
@@ -129,6 +127,34 @@ icons() {
HOURGLASS="${TAB}${TAB}"
}
# ------------------------------------------------------------------------------
# ensure_profile_loaded()
#
# - Sources /etc/profile.d/*.sh scripts if not already loaded
# - Fixes PATH issues when running via pct enter/exec (non-login shells)
# - Safe to call multiple times (uses guard variable)
# - Should be called in update_script() or any script running inside LXC
# ------------------------------------------------------------------------------
ensure_profile_loaded() {
# Skip if already loaded or running on Proxmox host
[[ -n "${_PROFILE_LOADED:-}" ]] && return
command -v pveversion &>/dev/null && return
# Source all profile.d scripts to ensure PATH is complete
if [[ -d /etc/profile.d ]]; then
for script in /etc/profile.d/*.sh; do
[[ -r "$script" ]] && source "$script"
done
fi
# Also ensure /usr/local/bin is in PATH (common install location)
if [[ ":$PATH:" != *":/usr/local/bin:"* ]]; then
export PATH="/usr/local/bin:$PATH"
fi
export _PROFILE_LOADED=1
}
# ------------------------------------------------------------------------------
# default_vars()
#

View File

@@ -4387,11 +4387,19 @@ EOF
return 1
}
manage_tool_repository "php" "$PHP_VERSION" "" "https://packages.sury.org/debsuryorg-archive-keyring.deb" || {
msg_error "Failed to setup PHP repository"
return 1
}
# Use different repository based on OS
if [[ "$DISTRO_ID" == "ubuntu" ]]; then
# Ubuntu: Use ondrej/php PPA
msg_info "Adding ondrej/php PPA for Ubuntu"
$STD apt install -y software-properties-common
$STD add-apt-repository -y ppa:ondrej/php
else
# Debian: Use Sury repository
manage_tool_repository "php" "$PHP_VERSION" "" "https://packages.sury.org/debsuryorg-archive-keyring.deb" || {
msg_error "Failed to setup PHP repository"
return 1
}
fi
ensure_apt_working || return 1
$STD apt update