Compare commits

..

34 Commits

Author SHA1 Message Date
1cac2afc41 Update CHANGELOG.md (#4939)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-03 01:15:31 +01:00
644a365c69 Update versions.json (#4938)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-03 02:14:48 +02:00
9bd4f5bb1b Update CHANGELOG.md (#4935)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 20:01:56 +01:00
b2a80b6971 fix(wastebin): use tar asset (#4934)
* fix(wastebin): use tar asset

* and install script...

* testing

* Revert "testing"

This reverts commit 74d2fd163b.
2025-06-02 21:01:19 +02:00
1e3d0e501b lowercase immich 2025-06-02 18:14:47 +02:00
3aa1f05343 Update CHANGELOG.md (#4930)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 15:40:44 +01:00
05c008241e add hw for immich, openwebui / remove scrypted (#4927) 2025-06-02 16:40:08 +02:00
91d8efcde0 Update CHANGELOG.md (#4929)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 15:00:32 +01:00
16ac1adf75 Update CHANGELOG.md (#4928)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 14:54:14 +01:00
805bbc5ee3 Update CHANGELOG.md (#4925)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 13:16:50 +01:00
43697716ae Various fixes (#4924) 2025-06-02 14:16:11 +02:00
623c8d993d Update versions.json (#4923)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 14:07:38 +02:00
bf2545ce40 Pulse: fix missing .env on service startup 2025-06-02 13:44:28 +02:00
dd9e285962 Update kimai-install.sh 2025-06-02 13:23:18 +02:00
7f513afcf2 Update .app files (#4921)
Co-authored-by: GitHub Actions <github-actions[bot]@users.noreply.github.com>
2025-06-02 13:19:49 +02:00
912c92d6f3 update_install error for pulse 2025-06-02 13:17:20 +02:00
a4904fdd7e Update CHANGELOG.md (#4919)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 12:12:21 +01:00
b4a58b907f MySQL/MariaDB: fix create user with password (#4918)
* MySQL/MariaDB: Fix Authentification with password

* add apache guac

* harmonize $STD value
2025-06-02 13:11:41 +02:00
824fd22aae fix mysql_version 2025-06-02 12:07:11 +02:00
feacacc368 Update CHANGELOG.md (#4917)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 10:42:00 +01:00
a307f9086b tools.func: Bugfix old gpg key for mysql & little improvements (#4916) 2025-06-02 11:41:25 +02:00
d97ce713ac Update CHANGELOG.md (#4913)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 09:49:32 +01:00
807870e739 Update CHANGELOG.md (#4911)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 09:47:23 +01:00
53c40775ee Update date in json (#4912)
Co-authored-by: GitHub Actions <github-actions[bot]@users.noreply.github.com>
2025-06-02 09:47:02 +01:00
bf9f5d62e2 Update CHANGELOG.md (#4910)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 09:46:10 +01:00
6650e0bdd8 PVE-Privilege-Converter (#4906) 2025-06-02 10:46:00 +02:00
f2bf6c9a6f make Pulse installation non-interactive (#4848)
* fix: streamline Pulse installation for web-based configuration

- Remove all interactive prompts during installation
- Remove .env setup (handled by web UI)
- Remove configuration messages (handled by web UI)
- Change install directory from /opt/pulse-proxmox to /opt/pulse
- Update JSON note to reflect web-based setup wizard

Pulse now features a complete web-based configuration system with
automatic setup detection, making manual .env configuration obsolete.

The new workflow:
1. Script installs Pulse without any user interaction
2. Service starts automatically
3. User navigates to the provided URL
4. Pulse shows setup wizard for configuration
5. No SSH or manual file editing required

This provides the ideal community script experience - completely
hands-off installation with configuration through the web interface.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Update pulse.sh to align with non-interactive installation

- Change paths from /opt/pulse-proxmox to /opt/pulse
- Remove .env file backup/restore logic since Pulse now uses web-based configuration
- Simplify permissions setting to match new installation approach

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* little fixes

* Update pulse.sh

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: CanbiZ <47820557+MickLesk@users.noreply.github.com>
2025-06-02 10:45:00 +02:00
8d50a5d8a9 Update CHANGELOG.md (#4908)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 09:40:13 +01:00
4e3286f11b Introducing core.func (#4907) 2025-06-02 10:39:46 +02:00
e08a587439 kimai revert failed mariadb
quickfix due failed migration of mariadb for kimai #4880
2025-06-02 10:25:24 +02:00
6ee8349d28 Update CHANGELOG.md (#4905)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 08:56:48 +01:00
87f6c9ebde Display default password even if there isn't a default username (#4900)
This fixes the display of the Deluge script.
2025-06-02 09:56:23 +02:00
6239075c2d Update CHANGELOG.md (#4904)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-02 07:25:36 +01:00
04ee11aab7 Fix tinyauth configuration parsing (#4901)
Co-authored-by: Bidyut Mukherjee <bidyut@bidyut-macbook-pro.lan>
2025-06-02 08:25:09 +02:00
35 changed files with 1068 additions and 217 deletions

View File

@ -14,8 +14,40 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
All LXC instances created using this repository come pre-installed with Midnight Commander, which is a command-line tool (`mc`) that offers a user-friendly file and directory management interface for the terminal environment.
## 2025-06-03
## 2025-06-02
### 🆕 New Scripts
- PVE-Privilege-Converter [@MickLesk](https://github.com/MickLesk) ([#4906](https://github.com/community-scripts/ProxmoxVE/pull/4906))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix(wastebin): use tar asset [@dbeg](https://github.com/dbeg) ([#4934](https://github.com/community-scripts/ProxmoxVE/pull/4934))
- MySQL/MariaDB: fix create user with password [@MickLesk](https://github.com/MickLesk) ([#4918](https://github.com/community-scripts/ProxmoxVE/pull/4918))
- Fix alpine-tinyauth env configuration parsing logic [@gokussjx](https://github.com/gokussjx) ([#4901](https://github.com/community-scripts/ProxmoxVE/pull/4901))
- #### 💥 Breaking Changes
- make Pulse installation non-interactive [@rcourtman](https://github.com/rcourtman) ([#4848](https://github.com/community-scripts/ProxmoxVE/pull/4848))
### 🧰 Maintenance
- #### 💾 Core
- [core] add hw-accelerated for immich, openwebui / remove scrypted [@MickLesk](https://github.com/MickLesk) ([#4927](https://github.com/community-scripts/ProxmoxVE/pull/4927))
- [core] tools.func: Bugfix old gpg key for mysql & little improvements [@MickLesk](https://github.com/MickLesk) ([#4916](https://github.com/community-scripts/ProxmoxVE/pull/4916))
- [core] Varius fixes to Config file feature [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#4924](https://github.com/community-scripts/ProxmoxVE/pull/4924))
### 🌐 Website
- #### 🐞 Bug Fixes
- Display default password even if there isn't a default username [@0risc](https://github.com/0risc) ([#4900](https://github.com/community-scripts/ProxmoxVE/pull/4900))
## 2025-06-01
### 🆕 New Scripts

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2025 community-scripts ORG
# Author: rcourtman
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
@ -23,40 +23,37 @@ function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/pulse-proxmox ]]; then
if [[ -d /opt/pulse-monitor ]]; then
msg_error "An old installation was detected. Please recreate the LXC from scratch (https://github.com/community-scripts/ProxmoxVE/pull/4848)"
exit 1
fi
if [[ ! -d /opt/pulse ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
RELEASE=$(curl -fsSL https://api.github.com/repos/rcourtman/Pulse/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
msg_info "Stopping ${APP}"
systemctl stop pulse-monitor
systemctl stop pulse
msg_ok "Stopped ${APP}"
msg_info "Updating Pulse"
if [[ -f /opt/pulse-proxmox/.env ]]; then
cp /opt/pulse-proxmox/.env /tmp/.env.backup.pulse
fi
temp_file=$(mktemp)
mkdir -p /opt/pulse-proxmox
rm -rf /opt/pulse-proxmox/*
mkdir -p /opt/pulse
rm -rf /opt/pulse/*
curl -fsSL "https://github.com/rcourtman/Pulse/releases/download/v${RELEASE}/pulse-v${RELEASE}.tar.gz" -o "$temp_file"
tar zxf "$temp_file" --strip-components=1 -C /opt/pulse-proxmox
if [[ -f /tmp/.env.backup.pulse ]]; then
mv /tmp/.env.backup.pulse /opt/pulse-proxmox/.env
fi
tar zxf "$temp_file" --strip-components=1 -C /opt/pulse
echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated Pulse to ${RELEASE}"
msg_info "Setting permissions for /opt/pulse-proxmox..."
chown -R pulse:pulse "/opt/pulse-proxmox"
find "/opt/pulse-proxmox" -type d -exec chmod 755 {} \;
find "/opt/pulse-proxmox" -type f -exec chmod 644 {} \;
chmod 600 /opt/pulse-proxmox/.env
msg_info "Setting permissions for /opt/pulse..."
chown -R pulse:pulse "/opt/pulse"
find "/opt/pulse" -type d -exec chmod 755 {} \;
find "/opt/pulse" -type f -exec chmod 644 {} \;
msg_ok "Set permissions."
msg_info "Starting ${APP}"
systemctl start pulse-monitor
systemctl start pulse
msg_ok "Started ${APP}"
else
msg_ok "No update required. ${APP} is already at ${RELEASE}."

View File

@ -64,8 +64,8 @@ EOF
msg_info "Updating Wastebin"
temp_file=$(mktemp)
curl -fsSL "https://github.com/matze/wastebin/releases/download/${RELEASE}/wastebin_${RELEASE}_x86_64-unknown-linux-musl.zip" -o "$temp_file"
$STD unzip -o $temp_file
curl -fsSL "https://github.com/matze/wastebin/releases/download/${RELEASE}/wastebin_${RELEASE}_x86_64-unknown-linux-musl.tar.zst" -o "$temp_file"
tar -xf $temp_file
cp -f wastebin /opt/wastebin/
chmod +x /opt/wastebin/wastebin
echo "${RELEASE}" >/opt/${APP}_version.txt

View File

@ -12,7 +12,7 @@
"documentation": null,
"website": "https://github.com/rcourtman/Pulse",
"logo": "https://raw.githubusercontent.com/rcourtman/Pulse/main/src/public/logos/pulse-logo-256x256.png",
"config_path": "/opt/pulse-proxmox/.env",
"config_path": "/opt/pulse/.env",
"description": "A lightweight monitoring application for Proxmox VE that displays real-time status for VMs and containers via a simple web interface.",
"install_methods": [
{
@ -35,6 +35,10 @@
{
"text": "Create Proxmox-API-Token first: `https://github.com/rcourtman/Pulse?tab=readme-ov-file#creating-a-proxmox-api-token`",
"type": "Info"
},
{
"text": "After installation, access the web interface to configure your Proxmox connection details through the built-in setup wizard",
"type": "Info"
}
]
}

View File

@ -0,0 +1,48 @@
{
"name": "PVE Privilege Converter",
"slug": "pve-privilege-converter",
"categories": [
1
],
"date_created": "2025-06-02",
"type": "pve",
"updateable": false,
"privileged": false,
"interface_port": null,
"documentation": "https://github.com/onethree7/proxmox-lxc-privilege-converter",
"website": null,
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/proxmox.webp",
"config_path": "",
"description": "This script allows converting Proxmox LXC containers between privileged and unprivileged modes using vzdump backup and restore. It guides you through container selection, backup storage, ID assignment, and privilege flipping via automated restore. Useful for applying changes that require different LXC modes.",
"install_methods": [
{
"type": "default",
"script": "tools/pve/pve-privilege-converter.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Execute this script inside the Proxmox shell as root.",
"type": "info"
},
{
"text": "Ensure that the backup and target storage have enough space.",
"type": "warning"
},
{
"text": "The container will be recreated with a new ID and desired privilege setting.",
"type": "info"
}
]
}

View File

@ -1,4 +1,109 @@
[
{
"name": "FreshRSS/FreshRSS",
"version": "1.26.3",
"date": "2025-06-02T22:00:14Z"
},
{
"name": "TandoorRecipes/recipes",
"version": "2.0.0-alpha-4",
"date": "2025-05-14T05:01:45Z"
},
{
"name": "VictoriaMetrics/VictoriaMetrics",
"version": "v1.23.3-victorialogs",
"date": "2025-06-02T19:44:31Z"
},
{
"name": "syncthing/syncthing",
"version": "2.0.0-rc.19",
"date": "2025-06-02T17:56:25Z"
},
{
"name": "tailscale/tailscale",
"version": "v1.84.1",
"date": "2025-06-02T18:35:35Z"
},
{
"name": "grokability/snipe-it",
"version": "v8.1.15",
"date": "2025-06-02T17:38:24Z"
},
{
"name": "msgbyte/tianji",
"version": "v1.21.6",
"date": "2025-06-02T17:12:58Z"
},
{
"name": "mattermost/mattermost",
"version": "server/public/v0.1.14",
"date": "2025-05-29T15:35:16Z"
},
{
"name": "n8n-io/n8n",
"version": "n8n@1.94.1",
"date": "2025-05-27T10:36:43Z"
},
{
"name": "NodeBB/NodeBB",
"version": "v4.4.2",
"date": "2025-06-02T15:06:31Z"
},
{
"name": "wazuh/wazuh",
"version": "coverity-w22-4.13.0",
"date": "2025-05-26T15:04:48Z"
},
{
"name": "Checkmk/checkmk",
"version": "v2.2.0p43-rc3",
"date": "2025-06-02T13:53:47Z"
},
{
"name": "keycloak/keycloak",
"version": "26.2.5",
"date": "2025-05-28T06:49:43Z"
},
{
"name": "inventree/InvenTree",
"version": "0.17.13",
"date": "2025-06-02T12:44:20Z"
},
{
"name": "Graylog2/graylog2-server",
"version": "6.3.0-beta.4",
"date": "2025-06-02T11:21:42Z"
},
{
"name": "zitadel/zitadel",
"version": "v2.68.11",
"date": "2025-06-02T09:32:57Z"
},
{
"name": "openobserve/openobserve",
"version": "v0.0.0-dev",
"date": "2025-06-02T08:16:35Z"
},
{
"name": "Jackett/Jackett",
"version": "v0.22.1978",
"date": "2025-06-02T05:52:50Z"
},
{
"name": "firefly-iii/firefly-iii",
"version": "v6.2.16",
"date": "2025-05-27T16:27:42Z"
},
{
"name": "usememos/memos",
"version": "v0.24.4",
"date": "2025-06-02T02:49:05Z"
},
{
"name": "pi-hole/pi-hole",
"version": "v6.1.1",
"date": "2025-06-02T01:36:09Z"
},
{
"name": "advplyr/audiobookshelf",
"version": "v2.24.0",
@ -6,8 +111,8 @@
},
{
"name": "TriliumNext/Notes",
"version": "v0.93.0",
"date": "2025-04-17T20:05:25Z"
"version": "v0.94.0",
"date": "2025-06-01T21:23:25Z"
},
{
"name": "traccar/traccar",
@ -34,16 +139,6 @@
"version": "v4.2.0",
"date": "2025-06-01T12:31:14Z"
},
{
"name": "firefly-iii/firefly-iii",
"version": "v6.2.16",
"date": "2025-05-27T16:27:42Z"
},
{
"name": "msgbyte/tianji",
"version": "v1.21.3",
"date": "2025-06-01T10:27:50Z"
},
{
"name": "evcc-io/evcc",
"version": "0.204.1",
@ -54,11 +149,6 @@
"version": "v5.25.0.10024",
"date": "2025-05-26T21:58:37Z"
},
{
"name": "Jackett/Jackett",
"version": "v0.22.1975",
"date": "2025-06-01T05:58:55Z"
},
{
"name": "home-assistant/core",
"version": "2025.5.3",
@ -89,21 +179,11 @@
"version": "v0.14.1",
"date": "2024-08-29T22:32:51Z"
},
{
"name": "keycloak/keycloak",
"version": "26.2.5",
"date": "2025-05-28T06:49:43Z"
},
{
"name": "goauthentik/authentik",
"version": "version/2025.4.1",
"date": "2025-05-15T17:48:29Z"
},
{
"name": "pi-hole/pi-hole",
"version": "v6.1",
"date": "2025-05-30T22:07:45Z"
},
{
"name": "moghtech/komodo",
"version": "v1.18.0",
@ -129,11 +209,6 @@
"version": "v0.20.0",
"date": "2025-05-30T14:39:51Z"
},
{
"name": "wazuh/wazuh",
"version": "coverity-w22-4.13.0",
"date": "2025-05-26T15:04:48Z"
},
{
"name": "nzbgetcom/nzbget",
"version": "v25.0",
@ -144,11 +219,6 @@
"version": "v2.12.0",
"date": "2025-05-30T00:26:27Z"
},
{
"name": "VictoriaMetrics/VictoriaMetrics",
"version": "v1.23.2-victorialogs",
"date": "2025-05-29T22:26:27Z"
},
{
"name": "open-webui/open-webui",
"version": "v0.6.13",
@ -164,11 +234,6 @@
"version": "v0.56.1",
"date": "2025-05-29T19:09:16Z"
},
{
"name": "tailscale/tailscale",
"version": "v1.84.1",
"date": "2025-05-29T17:41:04Z"
},
{
"name": "influxdata/influxdb",
"version": "v2.7.12",
@ -184,21 +249,6 @@
"version": "flowise@3.0.1",
"date": "2025-05-29T17:00:06Z"
},
{
"name": "n8n-io/n8n",
"version": "n8n@1.94.1",
"date": "2025-05-27T10:36:43Z"
},
{
"name": "syncthing/syncthing",
"version": "v1.29.6",
"date": "2025-05-06T07:57:02Z"
},
{
"name": "mattermost/mattermost",
"version": "server/public/v0.1.14",
"date": "2025-05-29T15:35:16Z"
},
{
"name": "readeck/readeck",
"version": "0.19.2",
@ -244,16 +294,6 @@
"version": "v1.1.0",
"date": "2025-05-28T09:39:00Z"
},
{
"name": "zitadel/zitadel",
"version": "v2.71.11",
"date": "2025-05-28T09:16:41Z"
},
{
"name": "Checkmk/checkmk",
"version": "v2.2.0p43-rc1",
"date": "2025-05-28T06:23:13Z"
},
{
"name": "Athou/commafeed",
"version": "5.10.0",
@ -329,11 +369,6 @@
"version": "v7.4.3",
"date": "2025-05-26T14:27:27Z"
},
{
"name": "Graylog2/graylog2-server",
"version": "6.3.0-beta.3",
"date": "2025-05-26T12:40:56Z"
},
{
"name": "Luligu/matterbridge",
"version": "3.0.4",
@ -394,11 +429,6 @@
"version": "v2.36.2",
"date": "2025-05-23T14:21:20Z"
},
{
"name": "grokability/snipe-it",
"version": "v8.1.4",
"date": "2025-05-23T12:29:19Z"
},
{
"name": "rogerfar/rdt-client",
"version": "v2.0.113",
@ -459,11 +489,6 @@
"version": "10.0.18",
"date": "2025-02-12T11:07:02Z"
},
{
"name": "inventree/InvenTree",
"version": "0.17.12",
"date": "2025-05-21T05:44:55Z"
},
{
"name": "diced/zipline",
"version": "v4.1.0",
@ -534,11 +559,6 @@
"version": "v1.1.1",
"date": "2025-05-17T10:10:36Z"
},
{
"name": "NodeBB/NodeBB",
"version": "v4.4.1",
"date": "2025-05-16T16:37:51Z"
},
{
"name": "wavelog/wavelog",
"version": "2.0.4",
@ -579,11 +599,6 @@
"version": "0.42.1",
"date": "2020-06-07T07:27:04Z"
},
{
"name": "TandoorRecipes/recipes",
"version": "2.0.0-alpha-4",
"date": "2025-05-14T05:01:45Z"
},
{
"name": "netbox-community/netbox",
"version": "v4.3.1",
@ -604,11 +619,6 @@
"version": "v2025-05-11",
"date": "2025-05-12T19:14:57Z"
},
{
"name": "usememos/memos",
"version": "v0.24.3",
"date": "2025-05-12T15:23:21Z"
},
{
"name": "stackblitz-labs/bolt.diy",
"version": "1.0.0",
@ -659,11 +669,6 @@
"version": "2025-05-07-r1",
"date": "2025-05-07T12:18:42Z"
},
{
"name": "openobserve/openobserve",
"version": "v0.14.7",
"date": "2025-05-07T11:32:23Z"
},
{
"name": "sysadminsmedia/homebox",
"version": "v0.19.0",
@ -699,11 +704,6 @@
"version": "v2.0.0.4645",
"date": "2017-03-07T18:56:06Z"
},
{
"name": "FreshRSS/FreshRSS",
"version": "1.26.2",
"date": "2025-05-03T20:23:27Z"
},
{
"name": "actualbudget/actual",
"version": "v25.5.0",

View File

@ -5,7 +5,7 @@ import { Script } from "@/lib/types";
export default function DefaultPassword({ item }: { item: Script }) {
const { username, password } = item.default_credentials;
const hasDefaultLogin = username && password;
const hasDefaultLogin = username || password;
if (!hasDefaultLogin) return null;
@ -23,14 +23,17 @@ export default function DefaultPassword({ item }: { item: Script }) {
<p className="mb-2 text-sm">
You can use the following credentials to login to the {item.name} {item.type}.
</p>
{["username", "password"].map((type) => (
<div key={type} className="text-sm">
{type.charAt(0).toUpperCase() + type.slice(1)}:{" "}
<Button variant="secondary" size="null" onClick={() => copyCredential(type as "username" | "password")}>
{item.default_credentials[type as "username" | "password"]}
</Button>
</div>
))}
{["username", "password"].map((type) => {
const value = item.default_credentials[type as "username" | "password"];
return value && value.trim() !== "" ? (
<div key={type} className="text-sm">
{type.charAt(0).toUpperCase() + type.slice(1)}:{" "}
<Button variant="secondary" size="null" onClick={() => copyCredential(type as "username" | "password")}>
{value}
</Button>
</div>
) : null;
})}
</div>
</div>
);

View File

@ -33,7 +33,7 @@ DB_NAME=2fauth_db
DB_USER=2fauth
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "2FAuth Credentials"

View File

@ -48,7 +48,7 @@ $STD apk add nextcloud-mysql mariadb mariadb-client
$STD mariadb-install-db --user=mysql --datadir=/var/lib/mysql
$STD service mariadb start
$STD rc-update add mariadb
mariadb -uroot -p"$ADMIN_PASS" -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '$ADMIN_PASS' WITH GRANT OPTION; DELETE FROM mysql.user WHERE User=''; DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1'); DROP DATABASE test; DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%'; CREATE DATABASE $DB_NAME; GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS'; GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost.localdomain' IDENTIFIED BY '$DB_PASS'; FLUSH PRIVILEGES;"
$STD mariadb -uroot -p"$ADMIN_PASS" -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '$ADMIN_PASS' WITH GRANT OPTION; DELETE FROM mysql.user WHERE User=''; DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1'); DROP DATABASE test; DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%'; CREATE DATABASE $DB_NAME; GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS'; GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost.localdomain' IDENTIFIED BY '$DB_PASS'; FLUSH PRIVILEGES;"
$STD apk del mariadb-client
msg_ok "Installed MySQL Database"

View File

@ -61,7 +61,15 @@ pidfile="/var/run/tinyauth.pid"
start_pre() {
if [ -f "/opt/tinyauth/.env" ]; then
export \$(grep -v '^#' /opt/tinyauth/.env | xargs)
while IFS= read -r line || [ -n "$line" ]; do
[ -z "$line" ] && continue
case "$line" in
'#'*)
continue
;;
esac
export "$line"
done < "/opt/tinyauth/.env"
fi
}

View File

@ -76,9 +76,9 @@ msg_info "Setup Database"
DB_NAME=guacamole_db
DB_USER=guacamole_user
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
mariadb -u root -e "CREATE DATABASE $DB_NAME;"
mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "Guacamole-Credentials"
echo "Database User: $DB_USER"

View File

@ -28,9 +28,9 @@ msg_info "Setting up Database"
DB_NAME=bookstack
DB_USER=bookstack
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
$STD sudo mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD sudo mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
$STD sudo mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "Bookstack-Credentials"
echo "Bookstack Database User: $DB_USER"

View File

@ -23,7 +23,7 @@ install_mariadb
msg_info "Setting up Database"
ROOT_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
$STD sudo mariadb -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$ROOT_PASS'); flush privileges;"
$STD mariadb -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '$ROOT_PASS'); flush privileges;"
{
echo "Dolibarr DB Credentials"
echo "MariaDB Root Password: $ROOT_PASS"

View File

@ -31,9 +31,9 @@ DB_NAME=firefly
DB_USER=firefly
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
MYSQL_VERSION=$(mariadb --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
mysql -u root -e "CREATE DATABASE $DB_NAME;"
mysql -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
mysql -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "Firefly-Credentials"
echo "Firefly Database User: $DB_USER"

View File

@ -25,9 +25,9 @@ msg_info "Configuring Database"
DB_NAME=ghost
DB_USER=ghostuser
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
mariadb -u root -e "CREATE DATABASE $DB_NAME;"
mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "Ghost-Credentials"

View File

@ -29,10 +29,10 @@ DB_NAME=glpi_db
DB_USER=glpi
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql
mariadb -u root -e "CREATE DATABASE $DB_NAME;"
mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
mariadb -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';"
mariadb -u root -e "GRANT SELECT ON \`mysql\`.\`time_zone_name\` TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';"
$STD mariadb -u root -e "GRANT SELECT ON \`mysql\`.\`time_zone_name\` TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "GLPI Database Credentials"
echo "Database: $DB_NAME"

View File

@ -23,7 +23,7 @@ $STD apt-get install -y \
lsb-release
msg_ok "Installed Dependencies"
install_mariadb
install_mysql
msg_info "Adding PHP8.4 Repository"
$STD curl -sSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
@ -44,10 +44,10 @@ msg_info "Setting up database"
DB_NAME=kimai_db
DB_USER=kimai
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
MYSQL_VERSION=$(mysql --version | grep -oP 'Distrib \K[0-9]+\.[0-9]+\.[0-9]+')
mariadb -u root -e "CREATE DATABASE $DB_NAME;"
mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
MYSQL_VERSION=$(mysql --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
$STD mysql -u root -e "CREATE DATABASE $DB_NAME;"
$STD mysql -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mysql -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "Kimai-Credentials"
echo "Kimai Database User: $DB_USER"

View File

@ -29,7 +29,7 @@ DB_NAME=monica
DB_USER=monica
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "monica-Credentials"

View File

@ -58,9 +58,9 @@ DB_NAME=paymenter
DB_USER=paymenter
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql
mariadb -u root -e "CREATE DATABASE $DB_NAME;"
mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
mariadb -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost' WITH GRANT OPTION;"
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost' WITH GRANT OPTION;"
{
echo "Paymenter Database Credentials"
echo "Database: $DB_NAME"

View File

@ -42,7 +42,7 @@ DB_NAME=panel
DB_USER=pelican
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "Pelican Panel-Credentials"

View File

@ -28,7 +28,7 @@ DB_NAME=phpipam
DB_USER=phpipam
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "phpIPAM-Credentials"
@ -43,7 +43,7 @@ RELEASE=$(curl -fsSL https://api.github.com/repos/phpipam/phpipam/releases/lates
cd /opt
curl -fsSL "https://github.com/phpipam/phpipam/releases/download/v${RELEASE}/phpipam-v${RELEASE}.zip" -o "phpipam-v${RELEASE}.zip"
$STD unzip "phpipam-v${RELEASE}.zip"
mariadb -u root "${DB_NAME}" </opt/phpipam/db/SCHEMA.sql
$STD mariadb -u root "${DB_NAME}" </opt/phpipam/db/SCHEMA.sql
cp /opt/phpipam/config.dist.php /opt/phpipam/config.php
sed -i -e "s/\(\$disable_installer = \).*/\1true;/" \
-e "s/\(\$db\['user'\] = \).*/\1'$DB_USER';/" \

View File

@ -38,7 +38,7 @@ DB_NAME=plantit
DB_USER=plantit_usr
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "Plant-it Credentials"

View File

@ -27,7 +27,7 @@ DB_NAME=projectsend
DB_USER=projectsend
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "projectsend-Credentials"

View File

@ -43,7 +43,7 @@ DB_NAME=panel
DB_USER=pterodactyl
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "pterodactyl Panel-Credentials"

View File

@ -17,7 +17,7 @@ update_os
msg_info "Installing Dependencies"
$STD apt-get install -y \
diffutils
msg_ok "Installed Core Dependencies"
msg_ok "Installed Dependencies"
msg_info "Creating dedicated user pulse..."
if useradd -r -m -d /opt/pulse-home -s /bin/bash pulse; then
@ -32,36 +32,23 @@ NODE_VERSION="20" install_node_and_modules
msg_info "Setup Pulse"
RELEASE=$(curl -fsSL https://api.github.com/repos/rcourtman/Pulse/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
temp_file=$(mktemp)
mkdir -p /opt/pulse-proxmox
mkdir -p /opt/pulse
curl -fsSL "https://github.com/rcourtman/Pulse/releases/download/v${RELEASE}/pulse-v${RELEASE}.tar.gz" -o "$temp_file"
tar zxf "$temp_file" --strip-components=1 -C /opt/pulse-proxmox
tar zxf "$temp_file" --strip-components=1 -C /opt/pulse
touch /opt/pulse/.env
chown pulse:pulse /opt/pulse/.env
echo "${RELEASE}" >/opt/${APPLICATION}_version.txt
msg_ok "Installed Pulse"
read -rp "${TAB3}Proxmox Host (z.B. https://proxmox.example.com:8006): " PROXMOX_HOST
read -rp "${TAB3}Proxmox Token ID (z.B. user@pam!mytoken): " PROXMOX_TOKEN_ID
read -rp "${TAB3}Proxmox Token Secret: " PROXMOX_TOKEN_SECRET
read -rp "${TAB3}Port (default: 7655): " PORT
PORT="${PORT:-7655}"
msg_info "Creating .env file"
cat <<EOF >/opt/pulse-proxmox/.env
PROXMOX_HOST=${PROXMOX_HOST}
PROXMOX_TOKEN_ID=${PROXMOX_TOKEN_ID}
PROXMOX_TOKEN_SECRET=${PROXMOX_TOKEN_SECRET}
PORT=${PORT}
EOF
msg_ok "Created .env file"
msg_info "Setting permissions for /opt/pulse-proxmox..."
chown -R pulse:pulse "/opt/pulse-proxmox"
find "/opt/pulse-proxmox" -type d -exec chmod 755 {} \;
find "/opt/pulse-proxmox" -type f -exec chmod 644 {} \;
chmod 600 /opt/pulse-proxmox/.env
msg_info "Setting permissions for /opt/pulse..."
chown -R pulse:pulse "/opt/pulse"
find "/opt/pulse" -type d -exec chmod 755 {} \;
find "/opt/pulse" -type f -exec chmod 644 {} \;
msg_ok "Set permissions."
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/pulse-monitor.service
cat <<EOF >/etc/systemd/system/pulse.service
[Unit]
Description=Pulse Monitoring Application
After=network.target
@ -70,8 +57,8 @@ After=network.target
Type=simple
User=pulse
Group=pulse
WorkingDirectory=/opt/pulse-proxmox
EnvironmentFile=/opt/pulse-proxmox/.env
WorkingDirectory=/opt/pulse
EnvironmentFile=/opt/pulse/.env
ExecStart=/usr/bin/npm run start
Restart=on-failure
RestartSec=5
@ -81,7 +68,7 @@ StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now pulse-monitor
systemctl enable -q --now pulse
msg_ok "Created Service"
motd_ssh

View File

@ -43,7 +43,7 @@ sqlpass="root"
echo "mariadb-server mariadb-server/root_password password $sqlpass" | debconf-set-selections
echo "mariadb-server mariadb-server/root_password_again password $sqlpass" | debconf-set-selections
service mysql start
mariadb -u "$sqluser" -p"$sqlpass" -e "source sql/user.sql" || true
$STD mariadb -u "$sqluser" -p"$sqlpass" -e "source sql/user.sql" || true
msg_ok "Installed Database"
msg_info "Installing Shinobi"

View File

@ -27,9 +27,9 @@ msg_info "Setting up database"
DB_NAME=snipeit_db
DB_USER=snipeit
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
mariadb -u root -e "CREATE DATABASE $DB_NAME;"
mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "SnipeIT-Credentials"
echo "SnipeIT Database User: $DB_USER"

View File

@ -16,8 +16,8 @@ update_os
msg_info "Installing Wastebin"
temp_file=$(mktemp)
RELEASE=$(curl -fsSL https://api.github.com/repos/matze/wastebin/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
curl -fsSL "https://github.com/matze/wastebin/releases/download/${RELEASE}/wastebin_${RELEASE}_x86_64-unknown-linux-musl.zip" -o "$temp_file"
$STD unzip $temp_file
curl -fsSL "https://github.com/matze/wastebin/releases/download/${RELEASE}/wastebin_${RELEASE}_x86_64-unknown-linux-musl.tar.zst" -o "$temp_file"
tar -xf $temp_file
mkdir -p /opt/wastebin
mv wastebin /opt/wastebin/
chmod +x /opt/wastebin/wastebin

View File

@ -26,7 +26,7 @@ DB_NAME=wavelog
DB_USER=waveloguser
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{
echo "Wavelog-Credentials"

View File

@ -385,7 +385,7 @@ HN="${HN}"
BRG="${BRG}"
APT_CACHER_IP="${APT_CACHER_IP:-none}"
DISABLEIP6="${DISABLEIP6}"
PW="${PW:-none}"
PW='${PW:-none}'
SSH="${SSH}"
SSH_AUTHORIZED_KEY="${SSH_AUTHORIZED_KEY}"
VERBOSE="${VERBOSE}"
@ -397,6 +397,7 @@ SD="${SD:-none}"
MAC="${MAC:-none}"
NS="${NS:-none}"
NET="${NET}"
FUSE="${ENABLE_FUSE}"
EOF
echo -e "${INFO}${BOLD}${GN}Writing configuration to ${FILEPATH}${CL}"
@ -416,7 +417,7 @@ HN="${HN}"
BRG="${BRG}"
APT_CACHER_IP="${APT_CACHER_IP:-none}"
DISABLEIP6="${DISABLEIP6}"
PW="${PW:-none}"
PW='${PW:-none}'
SSH="${SSH}"
SSH_AUTHORIZED_KEY="${SSH_AUTHORIZED_KEY}"
VERBOSE="${VERBOSE}"
@ -428,6 +429,7 @@ SD="${SD:-none}"
MAC="${MAC:-none}"
NS="${NS:-none}"
NET="${NET}"
FUSE="${ENABLE_FUSE}"
EOF
echo -e "${INFO}${BOLD}${GN}Writing configuration to ${FILEPATH}${CL}"
@ -795,7 +797,7 @@ advanced_settings() {
echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}"
fi
if (whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "FUSE Support" --yesno "Enable FUSE support?\nRequired for tools like rclone, mergerfs, AppImage, etc." 10 58); then
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "FUSE Support" --yesno "Enable FUSE support?\nRequired for tools like rclone, mergerfs, AppImage, etc." 10 58); then
ENABLE_FUSE="yes"
else
ENABLE_FUSE="no"
@ -1139,7 +1141,7 @@ EOF
fi
if [ "$CT_TYPE" == "0" ]; then
if [[ "$APP" == "Channels" || "$APP" == "Emby" || "$APP" == "ErsatzTV" || "$APP" == "Frigate" || "$APP" == "Jellyfin" || "$APP" == "Plex" || "$APP" == "Scrypted" || "$APP" == "Tdarr" || "$APP" == "Unmanic" || "$APP" == "Ollama" || "$APP" == "FileFlows" ]]; then
if [[ "$APP" == "Channels" || "$APP" == "Emby" || "$APP" == "ErsatzTV" || "$APP" == "Frigate" || "$APP" == "Jellyfin" || "$APP" == "Plex" || "$APP" == "immich" || "$APP" == "Tdarr" || "$APP" == "Open WebUI" || "$APP" == "Unmanic" || "$APP" == "Ollama" || "$APP" == "FileFlows" ]]; then
cat <<EOF >>"$LXC_CONFIG"
# VAAPI hardware transcoding
lxc.cgroup2.devices.allow: c 226:0 rwm
@ -1151,7 +1153,7 @@ lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,creat
EOF
fi
else
if [[ "$APP" == "Channels" || "$APP" == "Emby" || "$APP" == "ErsatzTV" || "$APP" == "Frigate" || "$APP" == "Jellyfin" || "$APP" == "Plex" || "$APP" == "Scrypted" || "$APP" == "Tdarr" || "$APP" == "Unmanic" || "$APP" == "Ollama" || "$APP" == "FileFlows" ]]; then
if [[ "$APP" == "Channels" || "$APP" == "Emby" || "$APP" == "ErsatzTV" || "$APP" == "Frigate" || "$APP" == "Jellyfin" || "$APP" == "Plex" || "$APP" == "immich" || "$APP" == "Tdarr" || "$APP" == "Open WebUI" || "$APP" == "Unmanic" || "$APP" == "Ollama" || "$APP" == "FileFlows" ]]; then
if [[ -e "/dev/dri/renderD128" ]]; then
if [[ -e "/dev/dri/card0" ]]; then
cat <<EOF >>"$LXC_CONFIG"

View File

@ -618,6 +618,24 @@ config_file() {
fi
fi
if [[ -n "$ENABLE_FUSE" ]]; then
if [[ "$ENABLE_FUSE" == "yes" ]]; then
echo -e "${FUSE}${BOLD}${DGN}Enable FUSE: ${BGN}Yes${CL}"
elif [[ "$ENABLE_FUSE" == "no" ]]; then
echo -e "${FUSE}${BOLD}${DGN}Enable FUSE: ${BGN}No${CL}"
else
msg_error "Enable FUSE needs to be 'yes' or 'no', was ${ENABLE_FUSE}"
exit
fi
else
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "FUSE" --yesno "Enable FUSE?" 10 58); then
ENABLE_FUSE="yes"
else
ENABLE_FUSE="no"
fi
echo -e "${FUSE}${BOLD}${DGN}Enable FUSE: ${BGN}$ENABLE_FUSE${CL}"
fi
if [[ -n "${VERBOSE-}" ]]; then
if [[ "$VERBOSE" == "yes" ]]; then
echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}$VERBOSE${CL}"

544
misc/core.func Normal file
View File

@ -0,0 +1,544 @@
# Copyright (c) 2021-2025 community-scripts ORG
# License: MIT | https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/LICENSE
# if ! declare -f wait_for >/dev/null; then
# echo "[DEBUG] Undefined function 'wait_for' used from: ${BASH_SOURCE[*]}" >&2
# wait_for() {
# echo "[DEBUG] Fallback: wait_for called with: $*" >&2
# true
# }
# fi
trap 'on_error $? $LINENO' ERR
trap 'on_exit' EXIT
trap 'on_interrupt' INT
trap 'on_terminate' TERM
if ! declare -f wait_for >/dev/null; then
wait_for() {
true
}
fi
declare -A MSG_INFO_SHOWN=()
SPINNER_PID=""
SPINNER_ACTIVE=0
SPINNER_MSG=""
# ------------------------------------------------------------------------------
# Loads core utility groups once (colors, formatting, icons, defaults).
# ------------------------------------------------------------------------------
[[ -n "${_CORE_FUNC_LOADED:-}" ]] && return
_CORE_FUNC_LOADED=1
load_functions() {
[[ -n "${__FUNCTIONS_LOADED:-}" ]] && return
__FUNCTIONS_LOADED=1
color
formatting
icons
default_vars
set_std_mode
# add more
}
on_error() {
local exit_code="$1"
local lineno="$2"
msg_error "Script failed at line $lineno with exit code $exit_code"
# Optionally log to your API or file here
exit "$exit_code"
}
on_exit() {
# Always called on script exit, success or failure
cleanup_temp_files || true
msg_info "Script exited"
}
on_interrupt() {
msg_error "Interrupted by user (CTRL+C)"
exit 130
}
on_terminate() {
msg_error "Terminated by signal (TERM)"
exit 143
}
setup_trap_abort_handling() {
trap '__handle_signal_abort SIGINT' SIGINT
trap '__handle_signal_abort SIGTERM' SIGTERM
trap '__handle_unexpected_error $?' ERR
}
__handle_signal_abort() {
local signal="$1"
echo
[ -n "${SPINNER_PID:-}" ] && kill "$SPINNER_PID" 2>/dev/null && wait "$SPINNER_PID" 2>/dev/null
case "$signal" in
SIGINT)
msg_error "Script aborted by user (CTRL+C)"
exit 130
;;
SIGTERM)
msg_error "Script terminated (SIGTERM)"
exit 143
;;
*)
msg_error "Script interrupted (unknown signal: $signal)"
exit 1
;;
esac
}
__handle_unexpected_error() {
local exit_code="$1"
echo
[ -n "${SPINNER_PID:-}" ] && kill "$SPINNER_PID" 2>/dev/null && wait "$SPINNER_PID" 2>/dev/null
case "$exit_code" in
1)
msg_error "Generic error occurred (exit code 1)"
;;
2)
msg_error "Misuse of shell builtins (exit code 2)"
;;
126)
msg_error "Command invoked cannot execute (exit code 126)"
;;
127)
msg_error "Command not found (exit code 127)"
;;
128)
msg_error "Invalid exit argument (exit code 128)"
;;
130)
msg_error "Script aborted by user (CTRL+C)"
;;
143)
msg_error "Script terminated by SIGTERM"
;;
*)
msg_error "Unexpected error occurred (exit code $exit_code)"
;;
esac
exit "$exit_code"
}
# ------------------------------------------------------------------------------
# Sets ANSI color codes used for styled terminal output.
# ------------------------------------------------------------------------------
color() {
YW=$(echo "\033[33m")
YWB=$'\e[93m'
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
BGN=$(echo "\033[4;92m")
GN=$(echo "\033[1;92m")
DGN=$(echo "\033[32m")
CL=$(echo "\033[m")
}
# ------------------------------------------------------------------------------
# Defines formatting helpers like tab, bold, and line reset sequences.
# ------------------------------------------------------------------------------
formatting() {
BFR="\\r\\033[K"
BOLD=$(echo "\033[1m")
HOLD=" "
TAB=" "
TAB3=" "
}
# ------------------------------------------------------------------------------
# Sets symbolic icons used throughout user feedback and prompts.
# ------------------------------------------------------------------------------
icons() {
CM="${TAB}✔️${TAB}"
CROSS="${TAB}✖️${TAB}"
DNSOK="✔️ "
DNSFAIL="${TAB}✖️${TAB}"
INFO="${TAB}💡${TAB}${CL}"
OS="${TAB}🖥️${TAB}${CL}"
OSVERSION="${TAB}🌟${TAB}${CL}"
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
DISKSIZE="${TAB}💾${TAB}${CL}"
CPUCORE="${TAB}🧠${TAB}${CL}"
RAMSIZE="${TAB}🛠️${TAB}${CL}"
SEARCH="${TAB}🔍${TAB}${CL}"
VERBOSE_CROPPED="🔍${TAB}"
VERIFYPW="${TAB}🔐${TAB}${CL}"
CONTAINERID="${TAB}🆔${TAB}${CL}"
HOSTNAME="${TAB}🏠${TAB}${CL}"
BRIDGE="${TAB}🌉${TAB}${CL}"
NETWORK="${TAB}📡${TAB}${CL}"
GATEWAY="${TAB}🌐${TAB}${CL}"
DISABLEIPV6="${TAB}🚫${TAB}${CL}"
DEFAULT="${TAB}⚙️${TAB}${CL}"
MACADDRESS="${TAB}🔗${TAB}${CL}"
VLANTAG="${TAB}🏷️${TAB}${CL}"
ROOTSSH="${TAB}🔑${TAB}${CL}"
CREATING="${TAB}🚀${TAB}${CL}"
ADVANCED="${TAB}🧩${TAB}${CL}"
FUSE="${TAB}🗂️${TAB}${CL}"
}
# ------------------------------------------------------------------------------
# Sets default retry and wait variables used for system actions.
# ------------------------------------------------------------------------------
default_vars() {
RETRY_NUM=10
RETRY_EVERY=3
i=$RETRY_NUM
#[[ "${VAR_OS:-}" == "unknown" ]]
}
# ------------------------------------------------------------------------------
# Sets default verbose mode for script and os execution.
# ------------------------------------------------------------------------------
set_std_mode() {
if [ "${VERBOSE:-no}" = "yes" ]; then
STD=""
else
STD="silent"
fi
}
# Silent execution function
silent() {
"$@" >/dev/null 2>&1
}
# Function to download & save header files
get_header() {
local app_name=$(echo "${APP,,}" | tr -d ' ')
local app_type=${APP_TYPE:-ct} # Default 'ct'
local header_url="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/${app_type}/headers/${app_name}"
local local_header_path="/usr/local/community-scripts/headers/${app_type}/${app_name}"
mkdir -p "$(dirname "$local_header_path")"
if [ ! -s "$local_header_path" ]; then
if ! curl -fsSL "$header_url" -o "$local_header_path"; then
return 1
fi
fi
cat "$local_header_path" 2>/dev/null || true
}
header_info() {
local app_name=$(echo "${APP,,}" | tr -d ' ')
local header_content
header_content=$(get_header "$app_name") || header_content=""
clear
local term_width
term_width=$(tput cols 2>/dev/null || echo 120)
if [ -n "$header_content" ]; then
echo "$header_content"
fi
}
# ------------------------------------------------------------------------------
# Performs a curl request with retry logic and inline feedback.
# ------------------------------------------------------------------------------
run_curl() {
if [ "$VERBOSE" = "no" ]; then
$STD curl "$@"
else
curl "$@"
fi
}
curl_handler() {
set +e
trap 'set -e' RETURN
local args=()
local url=""
local max_retries=3
local delay=2
local attempt=1
local exit_code
local has_output_file=false
local result=""
# Parse arguments
for arg in "$@"; do
if [[ "$arg" != -* && -z "$url" ]]; then
url="$arg"
fi
[[ "$arg" == "-o" || "$arg" == --output ]] && has_output_file=true
args+=("$arg")
done
if [[ -z "$url" ]]; then
msg_error "No valid URL or option entered for curl_handler"
return 1
fi
$STD msg_info "Fetching: $url"
while [[ $attempt -le $max_retries ]]; do
if $has_output_file; then
$STD run_curl "${args[@]}"
exit_code=$?
else
result=$(run_curl "${args[@]}")
exit_code=$?
fi
if [[ $exit_code -eq 0 ]]; then
$STD msg_ok "Fetched: $url"
$has_output_file || printf '%s' "$result"
return 0
fi
if ((attempt >= max_retries)); then
# Read error log if it exists
if [ -s /tmp/curl_error.log ]; then
local curl_stderr
curl_stderr=$(</tmp/curl_error.log)
rm -f /tmp/curl_error.log
fi
__curl_err_handler "$exit_code" "$url" "${curl_stderr:-}"
exit
fi
$STD printf "\r\033[K${INFO}${YW}Retry $attempt/$max_retries in ${delay}s...${CL}" >&2
sleep "$delay"
((attempt++))
done
set -e
}
# ------------------------------------------------------------------------------
# Handles specific curl error codes and displays descriptive messages.
# ------------------------------------------------------------------------------
__curl_err_handler() {
local exit_code="$1"
local target="$2"
local curl_msg="$3"
case $exit_code in
1) msg_error "Unsupported protocol: $target" ;;
2) msg_error "Curl init failed: $target" ;;
3) msg_error "Malformed URL: $target" ;;
5) msg_error "Proxy resolution failed: $target" ;;
6) msg_error "Host resolution failed: $target" ;;
7) msg_error "Connection failed: $target" ;;
9) msg_error "Access denied: $target" ;;
18) msg_error "Partial file transfer: $target" ;;
22) msg_error "HTTP error (e.g. 400/404): $target" ;;
23) msg_error "Write error on local system: $target" ;;
26) msg_error "Read error from local file: $target" ;;
28) msg_error "Timeout: $target" ;;
35) msg_error "SSL connect error: $target" ;;
47) msg_error "Too many redirects: $target" ;;
51) msg_error "SSL cert verify failed: $target" ;;
52) msg_error "Empty server response: $target" ;;
55) msg_error "Send error: $target" ;;
56) msg_error "Receive error: $target" ;;
60) msg_error "SSL CA not trusted: $target" ;;
67) msg_error "Login denied by server: $target" ;;
78) msg_error "Remote file not found (404): $target" ;;
*) msg_error "Curl failed with code $exit_code: $target" ;;
esac
[[ -n "$curl_msg" ]] && printf "%s\n" "$curl_msg" >&2
exit 1
}
fatal() {
msg_error "$1"
kill -INT $$
}
# Ensure POSIX compatibility across Alpine and Debian/Ubuntu
# === Spinner Start ===
# Trap cleanup on various signals
trap 'cleanup_spinner' EXIT INT TERM HUP
spinner_frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
# === Spinner Start ===
start_spinner() {
local msg="$1"
local spin_i=0
local interval=0.1
stop_spinner
SPINNER_MSG="$msg"
SPINNER_ACTIVE=1
{
while [[ "$SPINNER_ACTIVE" -eq 1 ]]; do
if [[ -t 2 ]]; then
printf "\r\e[2K%s %b" "${TAB}${spinner_frames[spin_i]}${TAB}" "${YW}${SPINNER_MSG}${CL}" >&2
else
printf "%s...\n" "$SPINNER_MSG" >&2
break
fi
spin_i=$(((spin_i + 1) % ${#spinner_frames[@]}))
sleep "$interval"
done
} &
local pid=$!
if ps -p "$pid" >/dev/null 2>&1; then
SPINNER_PID="$pid"
else
SPINNER_ACTIVE=0
SPINNER_PID=""
fi
}
# === Spinner Stop ===
stop_spinner() {
if [[ "$SPINNER_ACTIVE" -eq 1 && -n "$SPINNER_PID" ]]; then
SPINNER_ACTIVE=0
if kill -0 "$SPINNER_PID" 2>/dev/null; then
kill "$SPINNER_PID" 2>/dev/null || true
for _ in $(seq 1 10); do
sleep 0.05
kill -0 "$SPINNER_PID" 2>/dev/null || break
done
fi
if [[ "$SPINNER_PID" =~ ^[0-9]+$ ]]; then
ps -p "$SPINNER_PID" -o pid= >/dev/null 2>&1 && wait "$SPINNER_PID" 2>/dev/null || true
fi
printf "\r\e[2K" >&2
SPINNER_PID=""
fi
}
cleanup_spinner() {
stop_spinner
}
msg_info() {
local msg="$1"
[[ -z "$msg" || -n "${MSG_INFO_SHOWN["$msg"]+x}" ]] && return
MSG_INFO_SHOWN["$msg"]=1
stop_spinner
start_spinner "$msg"
}
msg_ok() {
local msg="$1"
[[ -z "$msg" ]] && return
stop_spinner
printf "\r\e[2K%s %b\n" "$CM" "${GN}${msg}${CL}" >&2
unset MSG_INFO_SHOWN["$msg"]
}
msg_error() {
local msg="$1"
[[ -z "$msg" ]] && return
stop_spinner
printf "\r\e[2K%s %b\n" "$CROSS" "${RD}${msg}${CL}" >&2
}
msg_warn() {
local msg="$1"
[[ -z "$msg" ]] && return
stop_spinner
printf "\r\e[2K%s %b\n" "$INFO" "${YWB}${msg}${CL}" >&2
unset MSG_INFO_SHOWN["$msg"]
}
msg_custom() {
local symbol="${1:-"[*]"}"
local color="${2:-"\e[36m"}" # Default: Cyan
local msg="${3:-}"
[[ -z "$msg" ]] && return
stop_spinner 2>/dev/null || true
printf "\r\e[2K%s %b\n" "$symbol" "${color}${msg}${CL:-\e[0m}" >&2
}
msg_progress() {
local current="$1"
local total="$2"
local label="$3"
local width=40
local filled percent bar empty
local fill_char="#"
local empty_char="-"
if ! [[ "$current" =~ ^[0-9]+$ ]] || ! [[ "$total" =~ ^[0-9]+$ ]] || [[ "$total" -eq 0 ]]; then
printf "\r\e[2K%s %b\n" "$CROSS" "${RD}Invalid progress input${CL}" >&2
return
fi
percent=$(((current * 100) / total))
filled=$(((current * width) / total))
empty=$((width - filled))
bar=$(printf "%${filled}s" | tr ' ' "$fill_char")
bar+=$(printf "%${empty}s" | tr ' ' "$empty_char")
printf "\r\e[2K%s [%s] %3d%% %s" "${TAB}" "$bar" "$percent" "$label" >&2
if [[ "$current" -eq "$total" ]]; then
printf "\n" >&2
fi
}
run_container_safe() {
local ct="$1"
shift
local cmd="$*"
lxc-attach -n "$ct" -- bash -euo pipefail -c "
trap 'echo Aborted in container; exit 130' SIGINT SIGTERM
$cmd
" || __handle_general_error "lxc-attach to CT $ct"
}
check_or_create_swap() {
msg_info "Checking for active swap"
if swapon --noheadings --show | grep -q 'swap'; then
msg_ok "Swap is active"
return 0
fi
msg_error "No active swap detected"
read -p "Do you want to create a swap file? [y/N]: " create_swap
create_swap="${create_swap,,}" # to lowercase
if [[ "$create_swap" != "y" && "$create_swap" != "yes" ]]; then
msg_info "Skipping swap file creation"
return 1
fi
read -p "Enter swap size in MB (e.g., 2048 for 2GB): " swap_size_mb
if ! [[ "$swap_size_mb" =~ ^[0-9]+$ ]]; then
msg_error "Invalid size input. Aborting."
return 1
fi
local swap_file="/swapfile"
msg_info "Creating ${swap_size_mb}MB swap file at $swap_file"
if dd if=/dev/zero of="$swap_file" bs=1M count="$swap_size_mb" status=progress &&
chmod 600 "$swap_file" &&
mkswap "$swap_file" &&
swapon "$swap_file"; then
msg_ok "Swap file created and activated successfully"
else
msg_error "Failed to create or activate swap"
return 1
fi
}

View File

@ -302,28 +302,34 @@ install_mysql() {
msg_info "MySQL $CURRENT_VERSION found, replacing with $MYSQL_VERSION"
NEED_INSTALL=true
else
msg_ok "MySQL $MYSQL_VERSION already installed"
# Check for patch-level updates
if apt list --upgradable 2>/dev/null | grep -q '^mysql-server/'; then
msg_info "MySQL $CURRENT_VERSION available for upgrade"
$STD apt-get update
$STD apt-get install --only-upgrade -y mysql-server
msg_ok "MySQL upgraded"
fi
return
fi
else
msg_info "MySQL not found, installing version $MYSQL_VERSION"
msg_info "Installing MySQL $MYSQL_VERSION"
NEED_INSTALL=true
fi
if [[ "$NEED_INSTALL" == true ]]; then
msg_info "Removing conflicting MySQL packages"
$STD systemctl stop mysql >/dev/null 2>&1 || true
$STD apt-get purge -y 'mysql*'
$STD apt-get purge -y "^mysql-server.*" "^mysql-client.*" "^mysql-common.*" || true
rm -f /etc/apt/sources.list.d/mysql.list /etc/apt/trusted.gpg.d/mysql.gpg
msg_info "Setting up MySQL APT Repository"
local DISTRO_CODENAME
DISTRO_CODENAME="$(awk -F= '/VERSION_CODENAME/ { print $2 }' /etc/os-release)"
curl -fsSL https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 | gpg --dearmor -o /etc/apt/trusted.gpg.d/mysql.gpg
curl -fsSL https://repo.mysql.com/RPM-GPG-KEY-mysql-2023 | gpg --dearmor -o /etc/apt/trusted.gpg.d/mysql.gpg
echo "deb [signed-by=/etc/apt/trusted.gpg.d/mysql.gpg] https://repo.mysql.com/apt/debian/ ${DISTRO_CODENAME} mysql-${MYSQL_VERSION}" \
>/etc/apt/sources.list.d/mysql.list
export DEBIAN_FRONTEND=noninteractive
$STD apt-get update
$STD apt-get install -y mysql-server
msg_ok "Installed MySQL $MYSQL_VERSION"
fi
}

View File

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

View File

@ -0,0 +1,196 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: MickLesk
# Adapted from onethree7 (https://github.com/onethree7/proxmox-lxc-privilege-converter)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
if ! command -v curl >/dev/null 2>&1; then
printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2
apt-get update >/dev/null 2>&1
apt-get install -y curl >/dev/null 2>&1
fi
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/core.func)
load_functions
set -euo pipefail
shopt -s inherit_errexit nullglob
APP="PVE-Privilege-Converter"
APP_TYPE="tools"
header_info "$APP"
check_root() {
if [[ $EUID -ne 0 ]]; then
msg_error "Script must be run as root"
exit 1
fi
}
select_target_storage_and_container_id() {
echo -e "\nSelect target storage for restored container:\n"
mapfile -t target_storages < <(pvesm status --content images | awk 'NR > 1 {print $1}')
for i in "${!target_storages[@]}"; do
printf "%s) %s\n" "$((i + 1))" "${target_storages[$i]}"
done
while true; do
read -rp "Enter number of target storage: " choice
if [[ "$choice" =~ ^[0-9]+$ ]] && ((choice >= 1 && choice <= ${#target_storages[@]})); then
TARGET_STORAGE="${target_storages[$((choice - 1))]}"
break
else
echo "Invalid selection. Try again."
fi
done
next_free_id=$(pvesh get /cluster/nextid 2>/dev/null || echo 999)
[[ "$next_free_id" =~ ^[0-9]+$ ]] || next_free_id=999
echo ""
read -rp "Suggested next free container ID: $next_free_id. Enter new container ID [default: $next_free_id]: " NEW_CONTAINER_ID
NEW_CONTAINER_ID="${NEW_CONTAINER_ID:-$next_free_id}"
}
select_container() {
mapfile -t lxc_list_raw < <(pct list | awk 'NR > 1 {print $1, $3}')
lxc_list=()
for entry in "${lxc_list_raw[@]}"; do
[[ -n "$entry" ]] && lxc_list+=("$entry")
done
if [[ ${#lxc_list[@]} -eq 0 ]]; then
msg_error "No containers found"
exit 1
fi
PS3="Enter number of container to convert: "
select opt in "${lxc_list[@]}"; do
if [[ -n "$opt" ]]; then
read -r CONTAINER_ID CONTAINER_NAME <<<"$opt"
CONTAINER_NAME="${CONTAINER_NAME:-}"
break
else
echo "Invalid selection. Try again."
fi
done
}
select_backup_storage() {
echo -e "Select backup storage (temporary vzdump location):"
mapfile -t backup_storages < <(pvesm status --content backup | awk 'NR > 1 {print $1}')
local PS3="Enter number of backup storage: "
select opt in "${backup_storages[@]}"; do
if [[ -n "$opt" ]]; then
BACKUP_STORAGE="$opt"
break
else
echo "Invalid selection. Try again."
fi
done
}
backup_container() {
msg_custom "📦" "\e[36m" "Backing up container $CONTAINER_ID"
vzdump_output=$(mktemp)
vzdump "$CONTAINER_ID" --compress zstd --storage "$BACKUP_STORAGE" --mode snapshot | tee "$vzdump_output"
BACKUP_PATH=$(awk '/tar.zst/ {print $NF}' "$vzdump_output" | tr -d "'")
if [ -z "$BACKUP_PATH" ] || ! grep -q "Backup job finished successfully" "$vzdump_output"; then
rm "$vzdump_output"
msg_error "Backup failed"
exit 1
fi
rm "$vzdump_output"
msg_ok "Backup complete: $BACKUP_PATH"
}
perform_conversion() {
if pct config "$CONTAINER_ID" | grep -q 'unprivileged: 1'; then
UNPRIVILEGED=true
else
UNPRIVILEGED=false
fi
msg_custom "🛠️" "\e[36m" "Restoring as $(if $UNPRIVILEGED; then echo privileged; else echo unprivileged; fi) container"
restore_opts=("$NEW_CONTAINER_ID" "$BACKUP_PATH" --storage "$TARGET_STORAGE")
if $UNPRIVILEGED; then
restore_opts+=(--unprivileged false)
else
restore_opts+=(--unprivileged)
fi
if pct restore "${restore_opts[@]}" -ignore-unpack-errors 1; then
msg_ok "Conversion successful"
else
msg_error "Conversion failed"
exit 1
fi
}
manage_states() {
read -rp "Shutdown source and start new container? [Y/n]: " answer
answer=${answer:-Y}
if [[ $answer =~ ^[Yy] ]]; then
pct shutdown "$CONTAINER_ID"
for i in {1..36}; do
sleep 5
! pct status "$CONTAINER_ID" | grep -q running && break
done
if pct status "$CONTAINER_ID" | grep -q running; then
read -rp "Timeout reached. Force shutdown? [Y/n]: " force
if [[ ${force:-Y} =~ ^[Yy] ]]; then
pkill -9 -f "lxc-start -F -n $CONTAINER_ID"
fi
fi
pct start "$NEW_CONTAINER_ID"
msg_ok "New container started"
else
msg_custom "" "\e[36m" "Skipped container state change"
fi
}
cleanup_files() {
read -rp "Delete backup archive? [$BACKUP_PATH] [Y/n]: " cleanup
if [[ ${cleanup:-Y} =~ ^[Yy] ]]; then
rm -f "$BACKUP_PATH" && msg_ok "Removed backup archive"
else
msg_custom "💾" "\e[36m" "Retained backup archive"
fi
}
summary() {
local conversion="Unknown"
if [[ -n "${UNPRIVILEGED:-}" ]]; then
if $UNPRIVILEGED; then
conversion="Unprivileged → Privileged"
else
conversion="Privileged → Unprivileged"
fi
fi
echo
msg_custom "📄" "\e[36m" "Summary:"
msg_custom " " "\e[36m" "$(printf "%-22s %s" "Original Container:" "$CONTAINER_ID ($CONTAINER_NAME)")"
msg_custom " " "\e[36m" "$(printf "%-22s %s" "Backup Storage:" "$BACKUP_STORAGE")"
msg_custom " " "\e[36m" "$(printf "%-22s %s" "Target Storage:" "$TARGET_STORAGE")"
msg_custom " " "\e[36m" "$(printf "%-22s %s" "Backup Path:" "$BACKUP_PATH")"
msg_custom " " "\e[36m" "$(printf "%-22s %s" "New Container ID:" "$NEW_CONTAINER_ID")"
msg_custom " " "\e[36m" "$(printf "%-22s %s" "Privilege Conversion:" "$conversion")"
echo
}
main() {
header_info
check_root
select_container
select_backup_storage
backup_container
select_target_storage_and_container_id
perform_conversion
manage_states
cleanup_files
summary
}
main