mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-04-28 13:20:40 +00:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 153df1325e | |||
| 4151b3abdb | |||
| a61c2bd809 | |||
| 43b0347446 | |||
| 55bad2aa40 | |||
| 4d2d6edefe | |||
| e2e7f0722f | |||
| b3c9f6e625 | |||
| ade3bde249 | |||
| 7cb40af4e6 | |||
| ce2b51a1a6 | |||
| 0986f485ee | |||
| cd1e584696 | |||
| cb156b6f85 | |||
| 06a676e6b0 | |||
| 3ac2ceda3d | |||
| 6082537f57 | |||
| bd3fbb3999 | |||
| 7e5e5be161 | |||
| 55c7549c3e | |||
| 4089fed9c9 | |||
| 325668d5c9 | |||
| 63296fc3e7 | |||
| e98fae3c54 | |||
| bf97029f57 | |||
| 5859c06715 | |||
| 9b4fc56de6 | |||
| 3a5244e285 | |||
| 1025715a74 | |||
| ec3b79bb61 | |||
| 37dfb58d29 | |||
| d95073f505 |
Generated
+6
-6
@@ -337,8 +337,8 @@ jobs:
|
|||||||
|
|
||||||
if (infoMatch) {
|
if (infoMatch) {
|
||||||
// ── INFO SUBCOMMAND ──────────────────────────────────────────────
|
// ── INFO SUBCOMMAND ──────────────────────────────────────────────
|
||||||
const notesArr = readJsonBlob(record.notes_json);
|
const notesArr = readJsonBlob(record.notes);
|
||||||
const methodsArr = readJsonBlob(record.install_methods_json);
|
const methodsArr = readJsonBlob(record.install_methods);
|
||||||
|
|
||||||
const out = [];
|
const out = [];
|
||||||
out.push('ℹ️ **PocketBase Bot**: Info for **`' + slug + '`**\n');
|
out.push('ℹ️ **PocketBase Bot**: Info for **`' + slug + '`**\n');
|
||||||
@@ -382,13 +382,13 @@ jobs:
|
|||||||
// ── NOTE SUBCOMMAND ──────────────────────────────────────────────
|
// ── NOTE SUBCOMMAND ──────────────────────────────────────────────
|
||||||
const noteAction = noteMatch[1].toLowerCase();
|
const noteAction = noteMatch[1].toLowerCase();
|
||||||
const noteArgsStr = rest.substring(noteMatch[0].length).trim();
|
const noteArgsStr = rest.substring(noteMatch[0].length).trim();
|
||||||
let notesArr = readJsonBlob(record.notes_json);
|
let notesArr = readJsonBlob(record.notes);
|
||||||
|
|
||||||
async function patchNotes(arr) {
|
async function patchNotes(arr) {
|
||||||
const res = await request(recordsUrl + '/' + record.id, {
|
const res = await request(recordsUrl + '/' + record.id, {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ notes_json: JSON.stringify(arr) })
|
body: JSON.stringify({ notes: arr })
|
||||||
});
|
});
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
await addReaction('-1');
|
await addReaction('-1');
|
||||||
@@ -504,7 +504,7 @@ jobs:
|
|||||||
// ── METHOD SUBCOMMAND ────────────────────────────────────────────
|
// ── METHOD SUBCOMMAND ────────────────────────────────────────────
|
||||||
const methodArgs = rest.replace(/^method\s*/i, '').trim();
|
const methodArgs = rest.replace(/^method\s*/i, '').trim();
|
||||||
const methodListMode = !methodArgs || methodArgs.toLowerCase() === 'list';
|
const methodListMode = !methodArgs || methodArgs.toLowerCase() === 'list';
|
||||||
let methodsArr = readJsonBlob(record.install_methods_json);
|
let methodsArr = readJsonBlob(record.install_methods);
|
||||||
|
|
||||||
// Method field classification
|
// Method field classification
|
||||||
const RESOURCE_KEYS = { cpu: 'number', ram: 'number', hdd: 'number', os: 'string', version: 'string' };
|
const RESOURCE_KEYS = { cpu: 'number', ram: 'number', hdd: 'number', os: 'string', version: 'string' };
|
||||||
@@ -526,7 +526,7 @@ jobs:
|
|||||||
const res = await request(recordsUrl + '/' + record.id, {
|
const res = await request(recordsUrl + '/' + record.id, {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ install_methods_json: arr })
|
body: JSON.stringify({ install_methods: arr })
|
||||||
});
|
});
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
await addReaction('-1');
|
await addReaction('-1');
|
||||||
|
|||||||
@@ -445,6 +445,48 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
## 2026-04-21
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- OpenCloud: Pin version to 6.1.0 [@vhsdream](https://github.com/vhsdream) ([#13890](https://github.com/community-scripts/ProxmoxVE/pull/13890))
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- homelable: fix install failure by correcting password-reset chmod target [@Copilot](https://github.com/Copilot) ([#13894](https://github.com/community-scripts/ProxmoxVE/pull/13894))
|
||||||
|
|
||||||
|
## 2026-04-20
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- WhoDB ([#13880](https://github.com/community-scripts/ProxmoxVE/pull/13880))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- pangolin: create migration tables before data transfer to prevent role loss [@MickLesk](https://github.com/MickLesk) ([#13874](https://github.com/community-scripts/ProxmoxVE/pull/13874))
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Pangolin: pre-apply schema migrations to prevent data loss [@MickLesk](https://github.com/MickLesk) ([#13861](https://github.com/community-scripts/ProxmoxVE/pull/13861))
|
||||||
|
- ActualBudget: change migration messages to warnings [@MickLesk](https://github.com/MickLesk) ([#13860](https://github.com/community-scripts/ProxmoxVE/pull/13860))
|
||||||
|
- slskd: migrate config keys for 0.25.0 breaking change [@MickLesk](https://github.com/MickLesk) ([#13862](https://github.com/community-scripts/ProxmoxVE/pull/13862))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Wanderer: add pocketbase CLI wrapper with env [@MickLesk](https://github.com/MickLesk) ([#13863](https://github.com/community-scripts/ProxmoxVE/pull/13863))
|
||||||
|
- feat(homelable): add password reset utility script [@davidsoncabista](https://github.com/davidsoncabista) ([#13798](https://github.com/community-scripts/ProxmoxVE/pull/13798))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Several Scripts: Bump NodeJS to align Node.js versions with upstream for 5 scripts [@MickLesk](https://github.com/MickLesk) ([#13875](https://github.com/community-scripts/ProxmoxVE/pull/13875))
|
||||||
|
- Refactor: PMG Post Install [@MickLesk](https://github.com/MickLesk) ([#13693](https://github.com/community-scripts/ProxmoxVE/pull/13693))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- core: detect Perl breakage after LXC stack upgrade and improve storage validation [@MickLesk](https://github.com/MickLesk) ([#13879](https://github.com/community-scripts/ProxmoxVE/pull/13879))
|
||||||
|
|
||||||
## 2026-04-19
|
## 2026-04-19
|
||||||
|
|
||||||
### 🆕 New Scripts
|
### 🆕 New Scripts
|
||||||
|
|||||||
+3
-3
@@ -48,9 +48,9 @@ function update_script() {
|
|||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
msg_info "Old Installation Found, you need to migrate your data and recreate to a new container"
|
msg_warn "Old Installation Found, you need to migrate your data and recreate to a new container"
|
||||||
msg_info "Please follow the instructions on the Actual Budget website to migrate your data"
|
msg_warn "Please follow the instructions on the Actual Budget website to migrate your data"
|
||||||
msg_info "https://actualbudget.org/docs/backup-restore/backup"
|
msg_warn "https://actualbudget.org/docs/backup-restore/backup"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
__ ____ __ __ __________ ___
|
||||||
|
/ |/ (_)___ / /_/ / / / ____/ |/ /
|
||||||
|
/ /|_/ / / __ \/ __/ /_/ / / / /|_/ /
|
||||||
|
/ / / / / / / / /_/ __ / /___/ / / /
|
||||||
|
/_/ /_/_/_/ /_/\__/_/ /_/\____/_/ /_/
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
_ ____ ____ ____
|
||||||
|
| | / / /_ ____ / __ \/ __ )
|
||||||
|
| | /| / / __ \/ __ \/ / / / __ |
|
||||||
|
| |/ |/ / / / / /_/ / /_/ / /_/ /
|
||||||
|
|__/|__/_/ /_/\____/_____/_____/
|
||||||
|
|
||||||
@@ -27,6 +27,9 @@ function update_script() {
|
|||||||
msg_error "No ${APP} Installation Found!"
|
msg_error "No ${APP} Installation Found!"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
NODE_VERSION="24" setup_nodejs
|
||||||
|
|
||||||
msg_info "Updating ${APP} LXC"
|
msg_info "Updating ${APP} LXC"
|
||||||
$STD apt update
|
$STD apt update
|
||||||
$STD apt -y upgrade
|
$STD apt -y upgrade
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
NODE_VERSION="22" setup_nodejs
|
||||||
|
|
||||||
if check_for_gh_release "kima-hub" "Chevron7Locked/kima-hub"; then
|
if check_for_gh_release "kima-hub" "Chevron7Locked/kima-hub"; then
|
||||||
msg_info "Stopping Services"
|
msg_info "Stopping Services"
|
||||||
systemctl stop kima-frontend kima-backend kima-analyzer kima-analyzer-clap
|
systemctl stop kima-frontend kima-backend kima-analyzer kima-analyzer-clap
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#!/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: MintHCM
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/minthcm/minthcm
|
||||||
|
|
||||||
|
APP="MintHCM"
|
||||||
|
var_tags="${var_tags:-hcm}"
|
||||||
|
var_disk="${var_disk:-20}"
|
||||||
|
var_cpu="${var_cpu:-4}"
|
||||||
|
var_ram="${var_ram:-4096}"
|
||||||
|
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 /var/www/MintHCM ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_custom "🚀" "${GN}" "The app offers a built-in updater. Please use it."
|
||||||
|
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}"
|
||||||
@@ -28,6 +28,8 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
NODE_VERSION="24" setup_nodejs
|
||||||
|
|
||||||
if check_for_gh_release "myip" "jason5ng32/MyIP"; then
|
if check_for_gh_release "myip" "jason5ng32/MyIP"; then
|
||||||
msg_info "Stopping Services"
|
msg_info "Stopping Services"
|
||||||
systemctl stop myip
|
systemctl stop myip
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
RELEASE="v6.0.0"
|
RELEASE="v6.1.0"
|
||||||
if check_for_gh_release "OpenCloud" "opencloud-eu/opencloud" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then
|
if check_for_gh_release "OpenCloud" "opencloud-eu/opencloud" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then
|
||||||
msg_info "Stopping services"
|
msg_info "Stopping services"
|
||||||
systemctl stop opencloud opencloud-wopi
|
systemctl stop opencloud opencloud-wopi
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
NODE_VERSION="22" setup_nodejs
|
NODE_VERSION="24" setup_nodejs
|
||||||
|
|
||||||
if check_for_gh_release "outline" "outline/outline"; then
|
if check_for_gh_release "outline" "outline/outline"; then
|
||||||
msg_info "Stopping Services"
|
msg_info "Stopping Services"
|
||||||
|
|||||||
+27
-1
@@ -69,7 +69,33 @@ function update_script() {
|
|||||||
|
|
||||||
msg_info "Running database migrations"
|
msg_info "Running database migrations"
|
||||||
cd /opt/pangolin
|
cd /opt/pangolin
|
||||||
ENVIRONMENT=prod $STD npx drizzle-kit push --config drizzle.sqlite.config.ts
|
|
||||||
|
# Pre-apply potentially destructive schema changes safely so drizzle-kit
|
||||||
|
# does not recreate tables (which would delete all rows).
|
||||||
|
local DB="/opt/pangolin/config/db/db.sqlite"
|
||||||
|
if [[ -f "$DB" ]]; then
|
||||||
|
sqlite3 "$DB" "ALTER TABLE 'orgs' ADD COLUMN 'settingsLogRetentionDaysConnection' integer DEFAULT 0 NOT NULL;" 2>/dev/null || true
|
||||||
|
sqlite3 "$DB" "ALTER TABLE 'clientSitesAssociationsCache' ADD COLUMN 'isJitMode' integer DEFAULT 0 NOT NULL;" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Create new role-mapping tables and migrate data before drizzle-kit
|
||||||
|
# drops the roleId columns from userOrgs and userInvites.
|
||||||
|
sqlite3 "$DB" "CREATE TABLE IF NOT EXISTS 'userOrgRoles' (
|
||||||
|
'userId' text NOT NULL REFERENCES 'user'('id') ON DELETE CASCADE,
|
||||||
|
'orgId' text NOT NULL REFERENCES 'orgs'('orgId') ON DELETE CASCADE,
|
||||||
|
'roleId' integer NOT NULL REFERENCES 'roles'('roleId') ON DELETE CASCADE,
|
||||||
|
UNIQUE('userId', 'orgId', 'roleId')
|
||||||
|
);" 2>/dev/null || true
|
||||||
|
sqlite3 "$DB" "INSERT OR IGNORE INTO 'userOrgRoles' (userId, orgId, roleId) SELECT userId, orgId, roleId FROM 'userOrgs' WHERE roleId IS NOT NULL;" 2>/dev/null || true
|
||||||
|
|
||||||
|
sqlite3 "$DB" "CREATE TABLE IF NOT EXISTS 'userInviteRoles' (
|
||||||
|
'inviteId' text NOT NULL REFERENCES 'userInvites'('inviteId') ON DELETE CASCADE,
|
||||||
|
'roleId' integer NOT NULL REFERENCES 'roles'('roleId') ON DELETE CASCADE,
|
||||||
|
PRIMARY KEY('inviteId', 'roleId')
|
||||||
|
);" 2>/dev/null || true
|
||||||
|
sqlite3 "$DB" "INSERT OR IGNORE INTO 'userInviteRoles' (inviteId, roleId) SELECT inviteId, roleId FROM 'userInvites' WHERE roleId IS NOT NULL;" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
ENVIRONMENT=prod $STD npx drizzle-kit push --force --config drizzle.sqlite.config.ts
|
||||||
msg_ok "Ran database migrations"
|
msg_ok "Ran database migrations"
|
||||||
|
|
||||||
msg_info "Updating Badger plugin version"
|
msg_info "Updating Badger plugin version"
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
NODE_VERSION="22" setup_nodejs
|
NODE_VERSION="24" setup_nodejs
|
||||||
PYTHON_VERSION="3.12" setup_uv
|
PYTHON_VERSION="3.12" setup_uv
|
||||||
|
|
||||||
if check_for_gh_release "shelfmark" "calibrain/shelfmark"; then
|
if check_for_gh_release "shelfmark" "calibrain/shelfmark"; then
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ function update_script() {
|
|||||||
|
|
||||||
msg_info "Restoring config"
|
msg_info "Restoring config"
|
||||||
mv /opt/slskd.yml.bak /opt/slskd/config/slskd.yml
|
mv /opt/slskd.yml.bak /opt/slskd/config/slskd.yml
|
||||||
|
|
||||||
|
# Migrate 0.25.0 breaking config key renames
|
||||||
|
sed -i 's/^global:/transfers:/' /opt/slskd/config/slskd.yml
|
||||||
|
sed -i 's/^integration:/integrations:/' /opt/slskd/config/slskd.yml
|
||||||
msg_ok "Restored config"
|
msg_ok "Restored config"
|
||||||
|
|
||||||
msg_info "Starting Service(s)"
|
msg_info "Starting Service(s)"
|
||||||
|
|||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
#!/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://whodb.com/
|
||||||
|
|
||||||
|
APP="WhoDB"
|
||||||
|
var_tags="${var_tags:-database;management;gui}"
|
||||||
|
var_cpu="${var_cpu:-1}"
|
||||||
|
var_ram="${var_ram:-512}"
|
||||||
|
var_disk="${var_disk:-2}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
|
||||||
|
if [[ ! -f /opt/whodb/whodb ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "whodb" "clidey/whodb"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop whodb
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "whodb" "clidey/whodb" "singlefile" "latest" "/opt/whodb" "whodb-*-linux-amd64"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start whodb
|
||||||
|
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}:8080${CL}"
|
||||||
@@ -45,6 +45,30 @@ STATUS_CHECKER_INTERVAL=60
|
|||||||
EOF
|
EOF
|
||||||
msg_ok "Configured Homelable"
|
msg_ok "Configured Homelable"
|
||||||
|
|
||||||
|
msg_info "Creating Password Reset Utility"
|
||||||
|
cat <<'EOF' >/root/change_password.sh
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
NEW_PASS=""
|
||||||
|
|
||||||
|
while [[ -z "$NEW_PASS" ]]; do
|
||||||
|
read -s -p "Enter new password: " NEW_PASS
|
||||||
|
echo ""
|
||||||
|
if [[ -z "$NEW_PASS" ]]; then
|
||||||
|
echo "Error: Password cannot be blank. Try again."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
HASH=$(/opt/homelable/backend/.venv/bin/python -c "from passlib.context import CryptContext; print(CryptContext(schemes=['bcrypt']).hash('${NEW_PASS}'))")
|
||||||
|
|
||||||
|
sed -i "s|^AUTH_PASSWORD_HASH=.*|AUTH_PASSWORD_HASH='${HASH}'|" /opt/homelable/backend/.env
|
||||||
|
|
||||||
|
systemctl restart homelable
|
||||||
|
echo "Password updated and service restarted successfully!"
|
||||||
|
EOF
|
||||||
|
chmod +x /root/change_password.sh
|
||||||
|
msg_ok "Created Password Reset Utility"
|
||||||
|
|
||||||
msg_info "Building Frontend"
|
msg_info "Building Frontend"
|
||||||
cd /opt/homelable/frontend
|
cd /opt/homelable/frontend
|
||||||
$STD npm ci
|
$STD npm ci
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ if [[ ! "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then
|
|||||||
exit 10
|
exit 10
|
||||||
fi
|
fi
|
||||||
|
|
||||||
NODE_VERSION="22" setup_nodejs
|
NODE_VERSION="24" setup_nodejs
|
||||||
|
|
||||||
msg_info "Installing ioBroker (Patience)"
|
msg_info "Installing ioBroker (Patience)"
|
||||||
$STD bash <(curl -fsSL https://iobroker.net/install.sh)
|
$STD bash <(curl -fsSL https://iobroker.net/install.sh)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ msg_ok "Installed Dependencies"
|
|||||||
|
|
||||||
PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql
|
PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql
|
||||||
PG_DB_NAME="kima" PG_DB_USER="kima" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db
|
PG_DB_NAME="kima" PG_DB_USER="kima" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db
|
||||||
NODE_VERSION="20" setup_nodejs
|
NODE_VERSION="22" setup_nodejs
|
||||||
|
|
||||||
msg_info "Configuring Redis"
|
msg_info "Configuring Redis"
|
||||||
systemctl enable -q --now redis-server
|
systemctl enable -q --now redis-server
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: MintHCM
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/minthcm/minthcm
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
PHP_VERSION="8.2"
|
||||||
|
PHP_APACHE="YES" PHP_MODULE="mysql,redis" PHP_FPM="YES" setup_php
|
||||||
|
setup_composer
|
||||||
|
setup_mariadb
|
||||||
|
$STD mariadb -u root -e "SET GLOBAL sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'"
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "MintHCM" "minthcm/minthcm" "tarball" "latest" "/var/www/MintHCM"
|
||||||
|
|
||||||
|
msg_info "Configuring MintHCM"
|
||||||
|
mkdir -p /etc/php/${PHP_VERSION}/mods-available
|
||||||
|
cp /var/www/MintHCM/docker/config/000-default.conf /etc/apache2/sites-available/000-default.conf
|
||||||
|
cp /var/www/MintHCM/docker/config/php-minthcm.ini /etc/php/${PHP_VERSION}/mods-available/php-minthcm.ini
|
||||||
|
mkdir -p "/etc/php/${PHP_VERSION}/cli/conf.d" "/etc/php/${PHP_VERSION}/apache2/conf.d"
|
||||||
|
ln -s "/etc/php/${PHP_VERSION}/mods-available/php-minthcm.ini" "/etc/php/${PHP_VERSION}/cli/conf.d/20-minthcm.ini"
|
||||||
|
ln -s "/etc/php/${PHP_VERSION}/mods-available/php-minthcm.ini" "/etc/php/${PHP_VERSION}/apache2/conf.d/20-minthcm.ini"
|
||||||
|
chown -R www-data:www-data /var/www/MintHCM
|
||||||
|
find /var/www/MintHCM -type d -exec chmod 755 {} \;
|
||||||
|
find /var/www/MintHCM -type f -exec chmod 644 {} \;
|
||||||
|
mkdir -p /var/www/script
|
||||||
|
cp /var/www/MintHCM/docker/script/generate_config.php /var/www/script/generate_config.php
|
||||||
|
cp /var/www/MintHCM/docker/.env /var/www/script/.env
|
||||||
|
chown -R www-data:www-data /var/www/script
|
||||||
|
$STD a2enmod rewrite
|
||||||
|
$STD a2enmod headers
|
||||||
|
$STD systemctl restart apache2
|
||||||
|
msg_ok "Configured MintHCM"
|
||||||
|
|
||||||
|
msg_info "Setting up Elasticsearch"
|
||||||
|
setup_deb822_repo \
|
||||||
|
"elasticsearch" \
|
||||||
|
"https://artifacts.elastic.co/GPG-KEY-elasticsearch" \
|
||||||
|
"https://artifacts.elastic.co/packages/7.x/apt" \
|
||||||
|
"stable"
|
||||||
|
$STD apt install -y elasticsearch
|
||||||
|
echo "-Xms2g" >>/etc/elasticsearch/jvm.options
|
||||||
|
echo "-Xmx2g" >>/etc/elasticsearch/jvm.options
|
||||||
|
$STD /usr/share/elasticsearch/bin/elasticsearch-plugin install ingest-attachment -b
|
||||||
|
systemctl enable -q --now elasticsearch
|
||||||
|
msg_ok "Set up Elasticsearch"
|
||||||
|
|
||||||
|
msg_info "Configuring Database"
|
||||||
|
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
|
||||||
|
$STD mariadb -u root -e "CREATE USER 'minthcm'@'localhost' IDENTIFIED BY '${DB_PASS}';"
|
||||||
|
$STD mariadb -u root -e "GRANT ALL ON *.* TO 'minthcm'@'localhost'; FLUSH PRIVILEGES;"
|
||||||
|
sed -i "s/^DB_HOST=.*/DB_HOST=localhost/" /var/www/script/.env
|
||||||
|
sed -i "s/^DB_USER=.*/DB_USER=minthcm/" /var/www/script/.env
|
||||||
|
sed -i "s/^DB_PASS=.*/DB_PASS=$DB_PASS/" /var/www/script/.env
|
||||||
|
sed -i "s/^ELASTICSEARCH_HOST=.*/ELASTICSEARCH_HOST=localhost/" /var/www/script/.env
|
||||||
|
msg_ok "Configured Database"
|
||||||
|
|
||||||
|
msg_info "Generating configuration file"
|
||||||
|
set -a
|
||||||
|
source /var/www/script/.env
|
||||||
|
set +a
|
||||||
|
$STD php /var/www/script/generate_config.php
|
||||||
|
msg_ok "Generated configuration file"
|
||||||
|
|
||||||
|
msg_info "Installing MintHCM"
|
||||||
|
cd /var/www/MintHCM
|
||||||
|
$STD sudo -u www-data php MintCLI install </var/www/MintHCM/configMint4
|
||||||
|
printf "* * * * * cd /var/www/MintHCM/legacy; php -f cron.php > /dev/null 2>&1\n" >/var/spool/cron/crontabs/www-data
|
||||||
|
service cron start
|
||||||
|
rm -f /var/www/MintHCM/configMint4
|
||||||
|
msg_ok "Installed MintHCM"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
@@ -13,7 +13,7 @@ setting_up_container
|
|||||||
network_check
|
network_check
|
||||||
update_os
|
update_os
|
||||||
|
|
||||||
NODE_VERSION="22" setup_nodejs
|
NODE_VERSION="24" setup_nodejs
|
||||||
fetch_and_deploy_gh_release "myip" "jason5ng32/MyIP" "tarball"
|
fetch_and_deploy_gh_release "myip" "jason5ng32/MyIP" "tarball"
|
||||||
|
|
||||||
msg_info "Configuring MyIP"
|
msg_info "Configuring MyIP"
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ $STD sudo -u cool coolconfig set-admin-password --user=admin --password="$COOLPA
|
|||||||
echo "$COOLPASS" >~/.coolpass
|
echo "$COOLPASS" >~/.coolpass
|
||||||
msg_ok "Installed Collabora Online"
|
msg_ok "Installed Collabora Online"
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v6.0.0" "/usr/bin" "opencloud-*-linux-amd64"
|
fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v6.1.0" "/usr/bin" "opencloud-*-linux-amd64"
|
||||||
mv /usr/bin/OpenCloud /usr/bin/opencloud
|
mv /usr/bin/OpenCloud /usr/bin/opencloud
|
||||||
|
|
||||||
msg_info "Configuring OpenCloud"
|
msg_info "Configuring OpenCloud"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ $STD apt install -y \
|
|||||||
redis
|
redis
|
||||||
msg_ok "Installed Dependencies"
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
NODE_VERSION="22" setup_nodejs
|
NODE_VERSION="24" setup_nodejs
|
||||||
PG_VERSION="16" setup_postgresql
|
PG_VERSION="16" setup_postgresql
|
||||||
PG_DB_NAME="outline" PG_DB_USER="outline" setup_postgresql_db
|
PG_DB_NAME="outline" PG_DB_USER="outline" setup_postgresql_db
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ else
|
|||||||
msg_ok "Installed internal bypasser dependencies"
|
msg_ok "Installed internal bypasser dependencies"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
NODE_VERSION="22" setup_nodejs
|
NODE_VERSION="24" setup_nodejs
|
||||||
PYTHON_VERSION="3.12" setup_uv
|
PYTHON_VERSION="3.12" setup_uv
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "shelfmark" "calibrain/shelfmark" "tarball" "latest" "/opt/shelfmark"
|
fetch_and_deploy_gh_release "shelfmark" "calibrain/shelfmark" "tarball" "latest" "/opt/shelfmark"
|
||||||
|
|||||||
@@ -60,6 +60,16 @@ wait -n
|
|||||||
EOF
|
EOF
|
||||||
chmod +x /opt/wanderer/start.sh
|
chmod +x /opt/wanderer/start.sh
|
||||||
|
|
||||||
|
cat <<'EOF' >/usr/local/bin/wanderer-pb
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -a
|
||||||
|
source /opt/wanderer/.env
|
||||||
|
set +a
|
||||||
|
cd /opt/wanderer/source/db
|
||||||
|
exec ./pocketbase "$@" --dir="$PB_DB_LOCATION"
|
||||||
|
EOF
|
||||||
|
chmod +x /usr/local/bin/wanderer-pb
|
||||||
|
|
||||||
cat <<EOF >/etc/systemd/system/wanderer-web.service
|
cat <<EOF >/etc/systemd/system/wanderer-web.service
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=wanderer
|
Description=wanderer
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#!/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://whodb.com/
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "whodb" "clidey/whodb" "singlefile" "latest" "/opt/whodb" "whodb-*-linux-amd64"
|
||||||
|
|
||||||
|
msg_info "Creating Service"
|
||||||
|
cat <<EOF >/etc/systemd/system/whodb.service
|
||||||
|
[Unit]
|
||||||
|
Description=WhoDB Database Management
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/opt/whodb
|
||||||
|
ExecStart=/opt/whodb/whodb
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now whodb
|
||||||
|
msg_ok "Created Service"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
+229
-22
@@ -5250,9 +5250,133 @@ create_lxc_container() {
|
|||||||
# Extract Debian OS minor from template name: debian-13-standard_13.1-1_amd64.tar.zst => "13.1"
|
# Extract Debian OS minor from template name: debian-13-standard_13.1-1_amd64.tar.zst => "13.1"
|
||||||
parse_template_osver() { sed -n 's/.*_\([0-9][0-9]*\(\.[0-9]\+\)\?\)-.*/\1/p' <<<"$1"; }
|
parse_template_osver() { sed -n 's/.*_\([0-9][0-9]*\(\.[0-9]\+\)\?\)-.*/\1/p' <<<"$1"; }
|
||||||
|
|
||||||
|
# Switch to the previous OS major version template and retry pct create
|
||||||
|
# Determines the fallback version automatically based on available templates.
|
||||||
|
# Returns: 0 = success, 1 = failed
|
||||||
|
fallback_to_previous_os_version() {
|
||||||
|
local old_template="$TEMPLATE"
|
||||||
|
local os_type="${PCT_OSTYPE:-}"
|
||||||
|
local current_ver="${PCT_OSVERSION:-}"
|
||||||
|
|
||||||
|
# Determine template search pattern based on OS type
|
||||||
|
local tpl_pattern=""
|
||||||
|
case "$os_type" in
|
||||||
|
debian | ubuntu) tpl_pattern="-standard_" ;;
|
||||||
|
alpine | fedora | rocky | centos) tpl_pattern="-default_" ;;
|
||||||
|
*) tpl_pattern="" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
msg_info "Searching for an older $os_type template (current: $os_type $current_ver)"
|
||||||
|
|
||||||
|
# Collect all available versions for this OS type (local + online)
|
||||||
|
local -a all_versions=()
|
||||||
|
|
||||||
|
# Local templates
|
||||||
|
mapfile -t _local_vers < <(
|
||||||
|
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
|
||||||
|
awk -v os="$os_type" -v pat="$tpl_pattern" '$1 ~ ("^"os"|/"os) && $1 ~ pat {print $1}' |
|
||||||
|
sed 's|.*/||' |
|
||||||
|
sed -E "s/^${os_type}-([0-9]+(\.[0-9]+)?).*/\1/" |
|
||||||
|
sort -u -V
|
||||||
|
)
|
||||||
|
all_versions+=("${_local_vers[@]}")
|
||||||
|
|
||||||
|
# Online templates (only if needed)
|
||||||
|
if command -v timeout &>/dev/null; then
|
||||||
|
timeout 30 pveam update >/dev/null 2>&1 || true
|
||||||
|
else
|
||||||
|
pveam update >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
mapfile -t _online_vers < <(
|
||||||
|
pveam available -section system 2>/dev/null |
|
||||||
|
awk '{print $2}' |
|
||||||
|
grep -E "^${os_type}-[0-9]" |
|
||||||
|
{ [[ -n "$tpl_pattern" ]] && grep "$tpl_pattern" || cat; } |
|
||||||
|
sed -E "s/^${os_type}-([0-9]+(\.[0-9]+)?).*/\1/" |
|
||||||
|
sort -u -V 2>/dev/null || true
|
||||||
|
)
|
||||||
|
all_versions+=("${_online_vers[@]}")
|
||||||
|
|
||||||
|
# Deduplicate and sort, find the highest version below current
|
||||||
|
local fallback_ver=""
|
||||||
|
fallback_ver=$(printf '%s\n' "${all_versions[@]}" | sort -u -V | awk -v cur="$current_ver" '{
|
||||||
|
# Compare major versions: extract major part
|
||||||
|
split($0, a, ".")
|
||||||
|
split(cur, b, ".")
|
||||||
|
if (a[1]+0 < b[1]+0) ver=$0
|
||||||
|
} END { if (ver) print ver }')
|
||||||
|
|
||||||
|
if [[ -z "$fallback_ver" ]]; then
|
||||||
|
msg_error "No older $os_type template version found."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_ok "Fallback version: $os_type $fallback_ver"
|
||||||
|
|
||||||
|
# Find the actual template file for this version
|
||||||
|
local fallback_search="${os_type}-${fallback_ver}"
|
||||||
|
local fallback_template=""
|
||||||
|
|
||||||
|
# Check local first
|
||||||
|
mapfile -t _fb_local < <(
|
||||||
|
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
|
||||||
|
awk -v search="$fallback_search" -v pat="$tpl_pattern" '$1 ~ search && $1 ~ pat {print $1}' |
|
||||||
|
sed 's|.*/||' | sort -t - -k 2 -V
|
||||||
|
)
|
||||||
|
if [[ ${#_fb_local[@]} -gt 0 ]]; then
|
||||||
|
fallback_template="${_fb_local[-1]}"
|
||||||
|
else
|
||||||
|
# Check online
|
||||||
|
mapfile -t _fb_online < <(
|
||||||
|
pveam available -section system 2>/dev/null |
|
||||||
|
awk '{print $2}' |
|
||||||
|
grep -E "^${fallback_search}.*${tpl_pattern}" |
|
||||||
|
sort -t - -k 2 -V 2>/dev/null || true
|
||||||
|
)
|
||||||
|
[[ ${#_fb_online[@]} -gt 0 ]] && fallback_template="${_fb_online[-1]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$fallback_template" ]]; then
|
||||||
|
msg_error "No template found for $os_type $fallback_ver."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_ok "Found template: $fallback_template"
|
||||||
|
|
||||||
|
# Download if needed
|
||||||
|
local fallback_path
|
||||||
|
fallback_path="$(pvesm path "$TEMPLATE_STORAGE:vztmpl/$fallback_template" 2>/dev/null || true)"
|
||||||
|
[[ -z "$fallback_path" ]] && fallback_path="/var/lib/vz/template/cache/$fallback_template"
|
||||||
|
|
||||||
|
if [[ ! -f "$fallback_path" ]]; then
|
||||||
|
msg_info "Downloading $os_type $fallback_ver template"
|
||||||
|
if ! pveam download "$TEMPLATE_STORAGE" "$fallback_template" >>"${BUILD_LOG:-/dev/null}" 2>&1; then
|
||||||
|
msg_error "Failed to download $os_type $fallback_ver template."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
msg_ok "Template downloaded"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update variables
|
||||||
|
TEMPLATE="$fallback_template"
|
||||||
|
TEMPLATE_PATH="$fallback_path"
|
||||||
|
PCT_OSVERSION="$fallback_ver"
|
||||||
|
export PCT_OSVERSION
|
||||||
|
|
||||||
|
# Retry pct create
|
||||||
|
msg_info "Retrying container creation with $os_type $fallback_ver"
|
||||||
|
if pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >>"$LOGFILE" 2>&1; then
|
||||||
|
msg_ok "Container created successfully with $os_type $fallback_ver (fallback from $old_template)."
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
msg_error "Container creation with $os_type $fallback_ver also failed. See $LOGFILE"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Offer upgrade for pve-container/lxc-pve if candidate > installed; optional auto-retry pct create
|
# Offer upgrade for pve-container/lxc-pve if candidate > installed; optional auto-retry pct create
|
||||||
# Returns:
|
# Returns:
|
||||||
# 0 = no upgrade needed
|
# 0 = no upgrade needed / container created after upgrade or fallback
|
||||||
# 1 = upgraded (and if do_retry=yes and retry succeeded, creation done)
|
# 1 = upgraded (and if do_retry=yes and retry succeeded, creation done)
|
||||||
# 2 = user declined
|
# 2 = user declined
|
||||||
# 3 = upgrade attempted but failed OR retry failed
|
# 3 = upgrade attempted but failed OR retry failed
|
||||||
@@ -5280,13 +5404,58 @@ create_lxc_container() {
|
|||||||
echo " pve-container: installed=${_pvec_i:-n/a} candidate=${_pvec_c:-n/a}"
|
echo " pve-container: installed=${_pvec_i:-n/a} candidate=${_pvec_c:-n/a}"
|
||||||
echo " lxc-pve : installed=${_lxcp_i:-n/a} candidate=${_lxcp_c:-n/a}"
|
echo " lxc-pve : installed=${_lxcp_i:-n/a} candidate=${_lxcp_c:-n/a}"
|
||||||
echo
|
echo
|
||||||
read -rp "Do you want to upgrade now? [y/N] " _ans </dev/tty
|
|
||||||
|
# Offer older OS version fallback when template version might be too new for LXC stack
|
||||||
|
local _has_fallback_option=false
|
||||||
|
if [[ -n "${PCT_OSTYPE:-}" && -n "${PCT_OSVERSION:-}" ]]; then
|
||||||
|
_has_fallback_option=true
|
||||||
|
echo " [1] Upgrade LXC stack now (recommended)"
|
||||||
|
echo " [2] Use an older ${PCT_OSTYPE} template instead (may not work with all scripts)"
|
||||||
|
echo " [3] Cancel"
|
||||||
|
echo
|
||||||
|
read -rp "Select option [1/2/3]: " _ans </dev/tty
|
||||||
|
else
|
||||||
|
read -rp "Do you want to upgrade now? [y/N] " _ans </dev/tty
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$_has_fallback_option" == true ]]; then
|
||||||
|
case "$_ans" in
|
||||||
|
1)
|
||||||
|
_ans="y"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
if [[ "$do_retry" == "yes" ]]; then
|
||||||
|
if fallback_to_previous_os_version; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 3
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
msg_custom "ℹ️" "${YW}" "OS version fallback is only available during container creation."
|
||||||
|
return 2
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
case "${_ans,,}" in
|
case "${_ans,,}" in
|
||||||
y | yes)
|
y | yes)
|
||||||
msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)"
|
msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)"
|
||||||
apt_update_safe
|
apt_update_safe
|
||||||
if $STD apt-get install -y --only-upgrade pve-container lxc-pve; then
|
if $STD apt-get install -y --only-upgrade pve-container lxc-pve; then
|
||||||
msg_ok "LXC stack upgraded."
|
msg_ok "LXC stack upgraded."
|
||||||
|
# Verify pct binary still works after upgrade (partial upgrades can break Perl modules)
|
||||||
|
if ! pct list &>/dev/null; then
|
||||||
|
msg_error "LXC stack upgrade caused PVE tool breakage (likely Perl module incompatibility)."
|
||||||
|
msg_custom "⚠️" "${YW}" "A partial package upgrade has left the PVE stack in an inconsistent state."
|
||||||
|
msg_custom "🔧" "${YW}" "Please run the following on the Proxmox host, then retry:"
|
||||||
|
echo -e "${TAB} apt update && apt dist-upgrade -y"
|
||||||
|
echo -e "${TAB} reboot"
|
||||||
|
return 3
|
||||||
|
fi
|
||||||
if [[ "$do_retry" == "yes" ]]; then
|
if [[ "$do_retry" == "yes" ]]; then
|
||||||
msg_info "Retrying container creation after upgrade"
|
msg_info "Retrying container creation after upgrade"
|
||||||
if pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >>"$LOGFILE" 2>&1; then
|
if pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >>"$LOGFILE" 2>&1; then
|
||||||
@@ -5385,10 +5554,35 @@ create_lxc_container() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
msg_info "Validating storage '$CONTAINER_STORAGE'"
|
msg_info "Validating storage '$CONTAINER_STORAGE'"
|
||||||
STORAGE_TYPE=$(grep -E "^[^:]+: $CONTAINER_STORAGE$" /etc/pve/storage.cfg | cut -d: -f1 | head -1 || true)
|
# Check if storage.cfg is accessible (pmxcfs must be mounted)
|
||||||
|
if [[ ! -f /etc/pve/storage.cfg ]]; then
|
||||||
|
if ! mountpoint -q /etc/pve 2>/dev/null; then
|
||||||
|
msg_error "Proxmox cluster filesystem (pmxcfs) is not mounted at /etc/pve."
|
||||||
|
msg_custom "🔧" "${YW}" "Try: systemctl restart pve-cluster"
|
||||||
|
else
|
||||||
|
msg_error "/etc/pve/storage.cfg does not exist."
|
||||||
|
msg_custom "🔧" "${YW}" "Check Proxmox cluster filesystem integrity: pvecm status"
|
||||||
|
fi
|
||||||
|
exit 213
|
||||||
|
fi
|
||||||
|
|
||||||
|
STORAGE_TYPE=$(grep -E "^[^:]+:[[:space:]]*$CONTAINER_STORAGE[[:space:]]*$" /etc/pve/storage.cfg | cut -d: -f1 | head -1 || true)
|
||||||
|
|
||||||
|
# Fallback: use pvesm status to determine storage type
|
||||||
|
if [[ -z "$STORAGE_TYPE" ]]; then
|
||||||
|
STORAGE_TYPE=$(pvesm status -storage "$CONTAINER_STORAGE" 2>/dev/null | awk 'NR>1{print $2}')
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -z "$STORAGE_TYPE" ]]; then
|
if [[ -z "$STORAGE_TYPE" ]]; then
|
||||||
msg_error "Storage '$CONTAINER_STORAGE' not found in /etc/pve/storage.cfg"
|
msg_error "Storage '$CONTAINER_STORAGE' not found in /etc/pve/storage.cfg"
|
||||||
|
msg_custom "📋" "${YW}" "Available storages: $(pvesm status 2>/dev/null | awk 'NR>1{printf "%s (%s) ", $1, $2}' || echo 'n/a')"
|
||||||
|
if [[ -r /etc/pve/storage.cfg ]]; then
|
||||||
|
msg_custom "📋" "${YW}" "Storage definitions found in config:"
|
||||||
|
grep -E '^[a-z]+:' /etc/pve/storage.cfg 2>/dev/null | while IFS= read -r _line; do
|
||||||
|
echo "${TAB} $_line"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
msg_custom "📖" "${YW}" "See https://pve.proxmox.com/wiki/Storage for storage configuration details."
|
||||||
exit 213
|
exit 213
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -5811,6 +6005,17 @@ create_lxc_container() {
|
|||||||
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >"$LOGFILE" 2>&1; then
|
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >"$LOGFILE" 2>&1; then
|
||||||
msg_debug "Container creation failed on ${TEMPLATE_STORAGE}. Checking error..."
|
msg_debug "Container creation failed on ${TEMPLATE_STORAGE}. Checking error..."
|
||||||
|
|
||||||
|
# Check for Perl module breakage (partial PVE upgrade)
|
||||||
|
if grep -qiE 'Compilation failed|Bareword.*not allowed' "$LOGFILE"; then
|
||||||
|
msg_error "Container creation failed due to broken Perl modules on the PVE host."
|
||||||
|
msg_custom "⚠️" "${YW}" "This usually happens after a partial PVE package upgrade."
|
||||||
|
msg_custom "🔧" "${YW}" "Please run the following on the Proxmox host, then retry:"
|
||||||
|
echo -e "${TAB} apt update && apt dist-upgrade -y"
|
||||||
|
echo -e "${TAB} reboot"
|
||||||
|
_flush_pct_log
|
||||||
|
exit 232
|
||||||
|
fi
|
||||||
|
|
||||||
# Check if CTID collision (race condition: ID claimed between validation and creation)
|
# Check if CTID collision (race condition: ID claimed between validation and creation)
|
||||||
if grep -qiE 'already exists|already in use' "$LOGFILE"; then
|
if grep -qiE 'already exists|already in use' "$LOGFILE"; then
|
||||||
local old_ctid="$CTID"
|
local old_ctid="$CTID"
|
||||||
@@ -5856,15 +6061,16 @@ create_lxc_container() {
|
|||||||
rc=$?
|
rc=$?
|
||||||
case $rc in
|
case $rc in
|
||||||
0) : ;; # success - container created, continue
|
0) : ;; # success - container created, continue
|
||||||
2)
|
2 | 3)
|
||||||
msg_error "Upgrade declined. Please update and re-run: apt update && apt install --only-upgrade pve-container lxc-pve"
|
# Upgrade declined or failed — try older OS version as last resort
|
||||||
_flush_pct_log
|
msg_warn "Attempting older ${PCT_OSTYPE:-} version as last resort"
|
||||||
exit 231
|
if fallback_to_previous_os_version; then
|
||||||
;;
|
: # success
|
||||||
3)
|
else
|
||||||
msg_error "Upgrade and/or retry failed. Please inspect: $LOGFILE"
|
msg_error "All recovery options exhausted. Please inspect: $LOGFILE"
|
||||||
_flush_pct_log
|
_flush_pct_log
|
||||||
exit 231
|
exit 231
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
else
|
else
|
||||||
@@ -5888,15 +6094,16 @@ create_lxc_container() {
|
|||||||
rc=$?
|
rc=$?
|
||||||
case $rc in
|
case $rc in
|
||||||
0) : ;; # success - container created, continue
|
0) : ;; # success - container created, continue
|
||||||
2)
|
2 | 3)
|
||||||
msg_error "Upgrade declined. Please update and re-run: apt update && apt install --only-upgrade pve-container lxc-pve"
|
# Upgrade declined or failed — try older OS version as last resort
|
||||||
_flush_pct_log
|
msg_warn "Attempting older ${PCT_OSTYPE:-} version as last resort"
|
||||||
exit 231
|
if fallback_to_previous_os_version; then
|
||||||
;;
|
: # success
|
||||||
3)
|
else
|
||||||
msg_error "Upgrade and/or retry failed. Please inspect: $LOGFILE"
|
msg_error "All recovery options exhausted. Please inspect: $LOGFILE"
|
||||||
_flush_pct_log
|
_flush_pct_log
|
||||||
exit 231
|
exit 231
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
else
|
else
|
||||||
@@ -5915,7 +6122,7 @@ create_lxc_container() {
|
|||||||
fi
|
fi
|
||||||
fi # close CTID collision else-branch
|
fi # close CTID collision else-branch
|
||||||
fi
|
fi
|
||||||
set +f # re-enable globbing after pct create block
|
set +f # re-enable globbing after pct create block
|
||||||
|
|
||||||
# Verify container exists (allow up to 10s for pmxcfs sync in clusters)
|
# Verify container exists (allow up to 10s for pmxcfs sync in clusters)
|
||||||
local _pct_visible=false
|
local _pct_visible=false
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ msg_error() {
|
|||||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
|
||||||
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "post-pmg-install" "pve"
|
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "post-pmg-install" "pve"
|
||||||
|
|
||||||
if ! grep -q "Proxmox Mail Gateway" /etc/issue 2>/dev/null; then
|
if ! dpkg -s proxmox-mailgateway-container >/dev/null 2>&1 &&
|
||||||
|
! dpkg -s proxmox-mailgateway >/dev/null 2>&1; then
|
||||||
msg_error "This script is only intended for Proxmox Mail Gateway"
|
msg_error "This script is only intended for Proxmox Mail Gateway"
|
||||||
exit 232
|
exit 232
|
||||||
fi
|
fi
|
||||||
@@ -57,14 +58,24 @@ repo_state() {
|
|||||||
local repo="$1"
|
local repo="$1"
|
||||||
local file=""
|
local file=""
|
||||||
local state="missing"
|
local state="missing"
|
||||||
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*.list; do
|
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources; do
|
||||||
[[ -f "$f" ]] || continue
|
[[ -f "$f" ]] || continue
|
||||||
if grep -q "$repo" "$f"; then
|
if grep -q "$repo" "$f"; then
|
||||||
file="$f"
|
file="$f"
|
||||||
if grep -qE "^[^#].*${repo}" "$f"; then
|
if [[ "$f" == *.sources ]]; then
|
||||||
state="active"
|
# deb822 format: check Enabled field
|
||||||
elif grep -qE "^#.*${repo}" "$f"; then
|
if grep -qiE '^Enabled:\s*no' "$f"; then
|
||||||
state="disabled"
|
state="disabled"
|
||||||
|
else
|
||||||
|
state="active"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# legacy format
|
||||||
|
if grep -qE "^[^#].*${repo}" "$f"; then
|
||||||
|
state="active"
|
||||||
|
elif grep -qE "^#.*${repo}" "$f"; then
|
||||||
|
state="disabled"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
@@ -72,6 +83,28 @@ repo_state() {
|
|||||||
echo "$state $file"
|
echo "$state $file"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggle_repo() {
|
||||||
|
# $1 = file, $2 = action (enable|disable)
|
||||||
|
local file="$1" action="$2"
|
||||||
|
if [[ "$file" == *.sources ]]; then
|
||||||
|
if [[ "$action" == "disable" ]]; then
|
||||||
|
if grep -qiE '^Enabled:' "$file"; then
|
||||||
|
sed -i 's/^Enabled:.*/Enabled: no/' "$file"
|
||||||
|
else
|
||||||
|
echo "Enabled: no" >>"$file"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
sed -i 's/^Enabled:.*/Enabled: yes/' "$file"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ "$action" == "disable" ]]; then
|
||||||
|
sed -i '/^[^#]/s/^/# /' "$file"
|
||||||
|
else
|
||||||
|
sed -i 's/^# *//' "$file"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
start_routines() {
|
start_routines() {
|
||||||
header_info
|
header_info
|
||||||
VERSION="$(awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release)"
|
VERSION="$(awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release)"
|
||||||
@@ -84,11 +117,20 @@ start_routines() {
|
|||||||
case $CHOICE in
|
case $CHOICE in
|
||||||
yes)
|
yes)
|
||||||
msg_info "Correcting Debian Sources"
|
msg_info "Correcting Debian Sources"
|
||||||
cat <<EOF >/etc/apt/sources.list
|
cat <<EOF >/etc/apt/sources.list.d/debian.sources
|
||||||
deb http://deb.debian.org/debian ${VERSION} main contrib
|
Types: deb
|
||||||
deb http://deb.debian.org/debian ${VERSION}-updates main contrib
|
URIs: http://deb.debian.org/debian
|
||||||
deb http://security.debian.org/debian-security ${VERSION}-security main contrib
|
Suites: ${VERSION} ${VERSION}-updates
|
||||||
|
Components: main contrib non-free non-free-firmware
|
||||||
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||||
|
|
||||||
|
Types: deb
|
||||||
|
URIs: http://security.debian.org/debian-security
|
||||||
|
Suites: ${VERSION}-security
|
||||||
|
Components: main contrib non-free non-free-firmware
|
||||||
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||||
EOF
|
EOF
|
||||||
|
rm -f /etc/apt/sources.list
|
||||||
msg_ok "Corrected Debian Sources"
|
msg_ok "Corrected Debian Sources"
|
||||||
;;
|
;;
|
||||||
no) msg_error "Selected no to Correcting Debian Sources" ;;
|
no) msg_error "Selected no to Correcting Debian Sources" ;;
|
||||||
@@ -108,7 +150,7 @@ EOF
|
|||||||
keep) msg_ok "Kept 'pmg-enterprise' repository" ;;
|
keep) msg_ok "Kept 'pmg-enterprise' repository" ;;
|
||||||
disable)
|
disable)
|
||||||
msg_info "Disabling 'pmg-enterprise' repository"
|
msg_info "Disabling 'pmg-enterprise' repository"
|
||||||
sed -i "s/^[^#].*pmg-enterprise/# &/" "$file"
|
toggle_repo "$file" disable
|
||||||
msg_ok "Disabled 'pmg-enterprise' repository"
|
msg_ok "Disabled 'pmg-enterprise' repository"
|
||||||
;;
|
;;
|
||||||
delete)
|
delete)
|
||||||
@@ -128,7 +170,7 @@ EOF
|
|||||||
case $CHOICE in
|
case $CHOICE in
|
||||||
enable)
|
enable)
|
||||||
msg_info "Enabling 'pmg-enterprise' repository"
|
msg_info "Enabling 'pmg-enterprise' repository"
|
||||||
sed -i "s/^#.*pmg-enterprise/deb/" "$file"
|
toggle_repo "$file" enable
|
||||||
msg_ok "Enabled 'pmg-enterprise' repository"
|
msg_ok "Enabled 'pmg-enterprise' repository"
|
||||||
;;
|
;;
|
||||||
keep) msg_ok "Kept 'pmg-enterprise' repository disabled" ;;
|
keep) msg_ok "Kept 'pmg-enterprise' repository disabled" ;;
|
||||||
@@ -149,8 +191,12 @@ EOF
|
|||||||
case $CHOICE in
|
case $CHOICE in
|
||||||
yes)
|
yes)
|
||||||
msg_info "Adding 'pmg-enterprise' repository"
|
msg_info "Adding 'pmg-enterprise' repository"
|
||||||
cat >/etc/apt/sources.list.d/pmg-enterprise.list <<EOF
|
cat >/etc/apt/sources.list.d/pmg-enterprise.sources <<EOF
|
||||||
deb https://enterprise.proxmox.com/debian/pmg ${VERSION} pmg-enterprise
|
Types: deb
|
||||||
|
URIs: https://enterprise.proxmox.com/debian/pmg
|
||||||
|
Suites: ${VERSION}
|
||||||
|
Components: pmg-enterprise
|
||||||
|
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
|
||||||
EOF
|
EOF
|
||||||
msg_ok "Added 'pmg-enterprise' repository"
|
msg_ok "Added 'pmg-enterprise' repository"
|
||||||
;;
|
;;
|
||||||
@@ -173,7 +219,7 @@ EOF
|
|||||||
keep) msg_ok "Kept 'pmg-no-subscription' repository" ;;
|
keep) msg_ok "Kept 'pmg-no-subscription' repository" ;;
|
||||||
disable)
|
disable)
|
||||||
msg_info "Disabling 'pmg-no-subscription' repository"
|
msg_info "Disabling 'pmg-no-subscription' repository"
|
||||||
sed -i "s/^[^#].*pmg-no-subscription/# &/" "$file"
|
toggle_repo "$file" disable
|
||||||
msg_ok "Disabled 'pmg-no-subscription' repository"
|
msg_ok "Disabled 'pmg-no-subscription' repository"
|
||||||
;;
|
;;
|
||||||
delete)
|
delete)
|
||||||
@@ -193,7 +239,7 @@ EOF
|
|||||||
case $CHOICE in
|
case $CHOICE in
|
||||||
enable)
|
enable)
|
||||||
msg_info "Enabling 'pmg-no-subscription' repository"
|
msg_info "Enabling 'pmg-no-subscription' repository"
|
||||||
sed -i "s/^#.*pmg-no-subscription/deb/" "$file"
|
toggle_repo "$file" enable
|
||||||
msg_ok "Enabled 'pmg-no-subscription' repository"
|
msg_ok "Enabled 'pmg-no-subscription' repository"
|
||||||
;;
|
;;
|
||||||
keep) msg_ok "Kept 'pmg-no-subscription' repository disabled" ;;
|
keep) msg_ok "Kept 'pmg-no-subscription' repository disabled" ;;
|
||||||
@@ -213,8 +259,12 @@ EOF
|
|||||||
case $CHOICE in
|
case $CHOICE in
|
||||||
yes)
|
yes)
|
||||||
msg_info "Adding 'pmg-no-subscription' repository"
|
msg_info "Adding 'pmg-no-subscription' repository"
|
||||||
cat >/etc/apt/sources.list.d/pmg-install-repo.list <<EOF
|
cat >/etc/apt/sources.list.d/pmg-no-subscription.sources <<EOF
|
||||||
deb http://download.proxmox.com/debian/pmg ${VERSION} pmg-no-subscription
|
Types: deb
|
||||||
|
URIs: http://download.proxmox.com/debian/pmg
|
||||||
|
Suites: ${VERSION}
|
||||||
|
Components: pmg-no-subscription
|
||||||
|
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
|
||||||
EOF
|
EOF
|
||||||
msg_ok "Added 'pmg-no-subscription' repository"
|
msg_ok "Added 'pmg-no-subscription' repository"
|
||||||
;;
|
;;
|
||||||
@@ -236,8 +286,13 @@ EOF
|
|||||||
case $CHOICE in
|
case $CHOICE in
|
||||||
yes)
|
yes)
|
||||||
msg_info "Adding 'pmgtest' repository (disabled)"
|
msg_info "Adding 'pmgtest' repository (disabled)"
|
||||||
cat >/etc/apt/sources.list.d/pmgtest-for-beta.list <<EOF
|
cat >/etc/apt/sources.list.d/pmgtest.sources <<EOF
|
||||||
# deb http://download.proxmox.com/debian/pmg ${VERSION} pmgtest
|
Types: deb
|
||||||
|
URIs: http://download.proxmox.com/debian/pmg
|
||||||
|
Suites: ${VERSION}
|
||||||
|
Components: pmgtest
|
||||||
|
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
|
||||||
|
Enabled: no
|
||||||
EOF
|
EOF
|
||||||
msg_ok "Added 'pmgtest' repository"
|
msg_ok "Added 'pmgtest' repository"
|
||||||
;;
|
;;
|
||||||
|
|||||||
Reference in New Issue
Block a user