Merge branch 'community-scripts:main' into pr-update-lxcs-services

This commit is contained in:
Rémi Bédard-Couture 2025-07-02 14:09:12 -04:00 committed by GitHub
commit 507057693a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 1464 additions and 1133 deletions

View File

@ -1,45 +0,0 @@
#!/usr/bin/env bash
source <(curl -s https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
# Copyright (c) 2021-2025 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
# Source: https://syncthing.net/
APP="Alpine-Syncthing"
var_tags="${var_tags:-alpine;networking}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}"
var_version="${var_version:-3.21}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
msg_info "Updating Alpine Packages"
$STD apk -U upgrade
msg_ok "Updated Alpine Packages"
msg_info "Updating Syncthing"
$STD apk upgrade syncthing
msg_ok "Updated Syncthing"
msg_info "Restarting Syncthing"
$STD rc-service syncthing restart
msg_ok "Restarted Syncthing"
exit 1
}
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}:8384${CL}"

View File

@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-512}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.21}" var_version="${var_version:-3.22}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
header_info "$APP" header_info "$APP"

View File

@ -40,5 +40,5 @@ start
build_container build_container
description description
msg_ok "Completed Successfully!\n" msg_ok "Completed Successfully!"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" msg_custom "🚀" "${GN}" "${APP} setup has been successfully initialized!"

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +0,0 @@
_ ______ __ ___ __
/ | / / __ \/ |/ /___ / /_ _______
/ |/ / /_/ / /|_/ / __ \/ / / / / ___/
/ /| / ____/ / / / /_/ / / /_/ (__ )
/_/ |_/_/ /_/ /_/ .___/_/\__,_/____/
/_/

6
ct/headers/scraparr Normal file
View File

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

6
ct/headers/zigbee2mqtt Normal file
View File

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

View File

@ -1,47 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
# Copyright (c) 2021-2025 community-scripts ORG
# Author: Florianb63
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://itsm-ng.com/
APP="itsmng"
var_tags="${var_tags:-asset-management;foss}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-10}"
var_os="${var_os:-debian}"
var_version="${var_version:-12}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /etc/itsm-ng/config_db.php ]]; then
msg_error "No ${APP} Installation Found!"
exit 1
fi
msg_info "Updating ${APP} LXC"
$STD apt-get update
$STD apt-get -y upgrade
msg_ok "Updated Successfully"
exit
}
start
build_container
description
msg_ok "Completed Successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"

View File

@ -1,45 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://jellyfin.org/
APP="Jellyfin"
var_tags="${var_tags:-media}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}"
var_os="${var_os:-ubuntu}"
var_version="${var_version:-24.04}"
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 /usr/lib/jellyfin ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Updating ${APP} LXC"
$STD apt-get update
$STD apt-get -y upgrade
$STD apt-get -y --with-new-pkgs upgrade jellyfin jellyfin-server
msg_ok "Updated ${APP} LXC"
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}:8096${CL}"

View File

@ -1,64 +0,0 @@
#!/usr/bin/env bash
source <(curl -s https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
# Copyright (c) 2021-2025 community-scripts ORG
# Author: Slaviša Arežina (tremor021)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/Casvt/Kapowarr
APP="Kapowarr"
var_tags="${var_tags:-Arr}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}"
var_disk="${var_disk:-2}"
var_os="${var_os:-debian}"
var_version="${var_version:-12}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /etc/systemd/system/kapowarr.service ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
RELEASE=$(curl -s https://api.github.com/repos/Casvt/Kapowarr/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
if [[ "${RELEASE}" != "$(cat $HOME/.kapowarr)" ]] || [[ ! -f $HOME/.kapowarr ]]; then
msg_info "Stopping $APP"
systemctl stop kapowarr
msg_ok "Stopped $APP"
msg_info "Creating Backup"
mv /opt/kapowarr/db /opt/
msg_ok "Backup Created"
msg_info "Updating $APP to ${RELEASE}"
fetch_and_deploy_gh_release "kapowarr" "Casvt/Kapowarr"
mv /opt/db /opt/kapowarr
msg_ok "Updated $APP to ${RELEASE}"
msg_info "Starting $APP"
systemctl start kapowarr
msg_ok "Started $APP"
msg_ok "Update Successful"
else
msg_ok "No update required. ${APP} is already at ${RELEASE}"
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}:5656${CL}"

View File

@ -1,58 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
# Copyright (c) 2021-2025 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/ZoeyVid/NPMplus
APP="NPMplus"
var_tags="${var_tags:-proxy;nginx}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}"
var_disk="${var_disk:-3}"
var_os="${var_os:-alpine}"
var_version="${var_version:-3.21}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
UPD=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "UPDATE MODE" --radiolist --cancel-button Exit-Script "Spacebar = Select" 14 60 2 \
"1" "Check for Alpine Updates" OFF \
"2" "Update NPMplus Docker Container" ON \
3>&1 1>&2 2>&3)
header_info "$APP"
case "$UPD" in
"1")
msg_info "Updating Alpine OS"
$STD apk -U upgrade
msg_ok "System updated"
exit
;;
"2")
msg_info "Updating NPMplus Container"
cd /opt
msg_info "Pulling latest container image"
$STD docker compose pull
msg_info "Recreating container"
$STD docker compose up -d
msg_ok "NPMplus container updated"
exit
;;
esac
exit 0
}
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}https://${IP}:81${CL}"

66
ct/scraparr.sh Normal file
View File

@ -0,0 +1,66 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
# Copyright (c) 2021-2025 community-scripts ORG
# Author: JasonGreenC
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/thecfu/scraparr
APP="Scraparr"
var_tags="${var_tags:-arr;monitoring}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-12}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/scraparr/ ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
RELEASE=$(curl -fsSL https://api.github.com/repos/thecfu/scraparr/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
if [[ ! -f "${HOME}/.scrappar" ]] || [[ "${RELEASE}" != "$(cat "${HOME}"/.scrappar)" ]]; then
msg_info "Stopping Services"
systemctl stop scraparr
msg_ok "Services Stopped"
PYTHON_VERSION="3.12" setup_uv
fetch_and_deploy_gh_release "scrappar" "thecfu/scraparr" "tarball" "latest" "/opt/scraparr"
msg_info "Updating ${APP} to ${RELEASE}"
cd /opt/scraparr || exit
$STD uv venv /opt/scraparr/.venv
$STD /opt/scraparr/.venv/bin/python -m ensurepip --upgrade
$STD /opt/scraparr/.venv/bin/python -m pip install --upgrade pip
$STD /opt/scraparr/.venv/bin/python -m pip install -r /opt/scraparr/src/scraparr/requirements.txt
chmod -R 755 /opt/scraparr
msg_ok "Updated ${APP} to v${RELEASE}"
msg_info "Starting Services"
systemctl start scraparr
msg_ok "Services Started"
else
msg_ok "No update required. ${APP} is already at v${RELEASE}"
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}:7100${CL}"

90
ct/zigbee2mqtt.sh Normal file
View File

@ -0,0 +1,90 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://www.zigbee2mqtt.io/
APP="Zigbee2MQTT"
var_tags="${var_tags:-smarthome;zigbee;mqtt}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-12}"
var_unprivileged="${var_unprivileged:-0}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/zigbee2mqtt ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if [[ -f ~/.zigbee2mqtt ]]; then
CURRENT="$(cat ~/.zigbee2mqtt)"
elif [[ -f /opt/${APP}_version.txt ]]; then
CURRENT="$(cat /opt/${APP}_version.txt)"
rm -f /opt/${APP}_version.txt
else
CURRENT=""
fi
RELEASE=$(curl -fsSL https://api.github.com/repos/Koenkk/zigbee2mqtt/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
if [[ "$RELEASE" != "$CURRENT" ]]; then
if ! command -v jq &>/dev/null; then
$STD apt-get update
$STD apt-get install -y jq
fi
NODE_VERSION=24 NODE_MODULE="pnpm@$(curl -fsSL https://raw.githubusercontent.com/Koenkk/zigbee2mqtt/master/package.json | jq -r '.packageManager | split("@")[1]')" setup_nodejs
msg_info "Stopping Service"
systemctl stop zigbee2mqtt
msg_ok "Stopped Service"
msg_info "Creating Backup"
rm -rf /opt/${APP}_backup*.tar.gz
mkdir -p /opt/z2m_backup
$STD tar -czf /opt/z2m_backup/${APP}_backup_$(date +%Y%m%d%H%M%S).tar.gz -C /opt zigbee2mqtt
mv /opt/zigbee2mqtt/data /opt/z2m_backup
msg_ok "Backup Created"
fetch_and_deploy_gh_release "Zigbee2MQTT" "Koenkk/zigbee2mqtt" "tarball" "latest" "/opt/zigbee2mqtt"
msg_info "Updating ${APP} to v${RELEASE}"
rm -rf /opt/zigbee2mqtt/data
mv /opt/z2m_backup/data /opt/zigbee2mqtt
cd /opt/zigbee2mqtt
$STD pnpm install --frozen-lockfile
$STD pnpm build
msg_ok "Updated Zigbee2MQTT"
msg_info "Starting Service"
systemctl start zigbee2mqtt
msg_ok "Started Service"
msg_info "Cleaning up"
rm -rf /opt/z2m_backup
msg_ok "Cleaned up"
echo "${RELEASE}" >/opt/${APP}_version.txt
else
msg_ok "No update required. ${APP} is already at v${RELEASE}."
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}:9442${CL}"

View File

@ -0,0 +1,35 @@
{
"name": "Docspell",
"slug": "docspell",
"categories": [
12
],
"date_created": "2025-07-02",
"type": "ct",
"updateable": true,
"privileged": false,
"config_path": "/opt/docspell/.env",
"interface_port": 3000,
"documentation": "https://docspell.io/",
"website": "https://docspell.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/docspell.svg",
"description": "Docspell is an open-source self-hosted application.",
"install_methods": [
{
"type": "default",
"script": "ct/docspell.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 2,
"os": "Debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@ -0,0 +1,35 @@
{
"name": "Frigate",
"slug": "frigate",
"categories": [
15
],
"date_created": "2025-07-02",
"type": "ct",
"updateable": true,
"privileged": false,
"config_path": "/opt/frigate/.env",
"interface_port": 3000,
"documentation": "https://frigate.io/",
"website": "https://frigate.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/frigate.svg",
"description": "Frigate is an open-source self-hosted application.",
"install_methods": [
{
"type": "default",
"script": "ct/frigate.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 2,
"os": "Debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@ -0,0 +1,35 @@
{
"name": "Hanko",
"slug": "hanko",
"categories": [
21
],
"date_created": "2025-07-02",
"type": "ct",
"updateable": true,
"privileged": false,
"config_path": "/opt/hanko/.env",
"interface_port": 3000,
"documentation": "https://docs.hanko.io/",
"website": "https://hanko.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/hanko.svg",
"description": "Hanko is an open-source authentication solution providing passkey-first login with support for WebAuthn/FIDO2, biometrics and modern identity flows. Easy to self-host and integrate via API or widget.",
"install_methods": [
{
"type": "default",
"script": "ct/hanko.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 2,
"os": "Debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@ -0,0 +1,35 @@
{
"name": "Healthchecks",
"slug": "healthchecks",
"categories": [
9
],
"date_created": "2025-07-02",
"type": "ct",
"updateable": true,
"privileged": false,
"config_path": "/opt/healthchecks/.env",
"interface_port": 3000,
"documentation": "https://healthchecks.io/",
"website": "https://healthchecks.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/healthchecks.svg",
"description": "Healthchecks is an open-source self-hosted application.",
"install_methods": [
{
"type": "default",
"script": "ct/healthchecks.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 2,
"os": "Debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@ -1,35 +0,0 @@
{
"name": "ITSMNG",
"slug": "itsmng",
"categories": [
25
],
"date_created": "2025-06-20",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://wiki.itsm-ng.org/en/home",
"website": "https://itsm-ng.com",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/itsm-ng.svg",
"config_path": "/etc/itsm-ng",
"description": "ITSM-NG is a Free Asset and IT Management Software package, Data center management, ITIL Service Desk, licenses tracking and software auditing.",
"install_methods": [
{
"type": "default",
"script": "ct/itsmng.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 10,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": "itsm",
"password": "itsm"
},
"notes": []
}

View File

@ -1,35 +0,0 @@
{
"name": "Kapowarr",
"slug": "kapowarr",
"categories": [
14
],
"date_created": "2025-06-09",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 5656,
"documentation": "https://casvt.github.io/Kapowarr/general_info/workings/",
"website": "https://casvt.github.io/Kapowarr/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/kapowarr.webp",
"config_path": "",
"description": "Kapowarr allows you to build a digital library of comics. You can add volumes, map them to a folder and start managing! Download, rename, move and convert issues of the volume (including TPB's, One Shots, Hard Covers, and more). The whole process is automated and can be customised in the settings.",
"install_methods": [
{
"type": "default",
"script": "ct/kapowarr.sh",
"resources": {
"cpu": 1,
"ram": 256,
"hdd": 2,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@ -0,0 +1,35 @@
{
"name": "Maxun",
"slug": "maxun",
"categories": [
0
],
"date_created": "2025-07-02",
"type": "ct",
"updateable": true,
"privileged": false,
"config_path": "/opt/maxun/.env",
"interface_port": 3000,
"documentation": "https://maxun.io/",
"website": "https://maxun.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/maxun.svg",
"description": "Maxun is an open-source self-hosted application.",
"install_methods": [
{
"type": "default",
"script": "ct/maxun.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 2,
"os": "Debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@ -0,0 +1,35 @@
{
"name": "Mealie",
"slug": "mealie",
"categories": [
13
],
"date_created": "2025-07-02",
"type": "ct",
"updateable": true,
"privileged": false,
"config_path": "/opt/mealie/.env",
"interface_port": 3000,
"documentation": "https://mealie.io/",
"website": "https://mealie.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/mealie.svg",
"description": "Mealie is an open-source self-hosted application.",
"install_methods": [
{
"type": "default",
"script": "ct/mealie.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 2,
"os": "Debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@ -0,0 +1,35 @@
{
"name": "Postiz",
"slug": "postiz",
"categories": [
20
],
"date_created": "2025-07-02",
"type": "ct",
"updateable": true,
"privileged": false,
"config_path": "/opt/postiz/.env",
"interface_port": 3000,
"documentation": "https://postiz.io/",
"website": "https://postiz.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/postiz.svg",
"description": "Postiz is an open-source self-hosted application.",
"install_methods": [
{
"type": "default",
"script": "ct/postiz.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 2,
"os": "Debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@ -0,0 +1,35 @@
{
"name": "Saltmaster",
"slug": "saltmaster",
"categories": [
1
],
"date_created": "2025-07-02",
"type": "ct",
"updateable": true,
"privileged": false,
"config_path": "/opt/saltmaster/.env",
"interface_port": 3000,
"documentation": "https://saltmaster.io/",
"website": "https://saltmaster.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/saltmaster.svg",
"description": "Saltmaster is an open-source self-hosted application.",
"install_methods": [
{
"type": "default",
"script": "ct/saltmaster.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 2,
"os": "Debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@ -0,0 +1,40 @@
{
"name": "Scraparr",
"slug": "scraparr",
"categories": [
14
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 7100,
"documentation": "https://github.com/thecfu/scraparr/blob/main/README.md",
"website": "https://github.com/thecfu/scraparr",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/scraparr-dark.svg",
"config_path": "/scraparr/config/config.yaml",
"description": "Scraparr is a Prometheus exporter for the *arr suite (Sonarr, Radarr, Lidarr, etc.). It provides metrics that can be scraped by Prometheus to monitor and visualize the health and performance of your *arr applications.",
"install_methods": [
{
"type": "default",
"script": "ct/scraparr.sh",
"resources": {
"cpu": 2,
"ram": 1024,
"hdd": 4,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Edit config file then restart the scraparr service: `systemctl restart scraparr`",
"type": "info"
}
]
}

View File

@ -1,19 +1,244 @@
[ [
{
"name": "wazuh/wazuh",
"version": "coverity-w27-4.13.0",
"date": "2025-07-01T03:17:32Z"
},
{
"name": "glpi-project/glpi",
"version": "10.0.18",
"date": "2025-02-12T11:07:02Z"
},
{
"name": "emqx/emqx",
"version": "e5.9.1",
"date": "2025-07-02T08:11:50Z"
},
{
"name": "apache/tomcat",
"version": "9.0.107",
"date": "2025-07-02T07:12:09Z"
},
{
"name": "nzbgetcom/nzbget",
"version": "v25.1",
"date": "2025-06-27T09:14:14Z"
},
{
"name": "qbittorrent/qBittorrent",
"version": "release-5.1.2",
"date": "2025-07-02T06:13:16Z"
},
{
"name": "home-assistant/core",
"version": "2025.6.3",
"date": "2025-06-24T13:00:12Z"
},
{ {
"name": "Jackett/Jackett", "name": "Jackett/Jackett",
"version": "v0.22.2075", "version": "v0.22.2107",
"date": "2025-06-28T10:16:17Z" "date": "2025-07-02T05:53:02Z"
},
{
"name": "firefly-iii/firefly-iii",
"version": "v6.2.20",
"date": "2025-07-02T04:03:37Z"
},
{
"name": "diced/zipline",
"version": "v4.2.0",
"date": "2025-07-02T00:45:31Z"
},
{
"name": "sysadminsmedia/homebox",
"version": "v0.20.2",
"date": "2025-07-02T00:37:07Z"
},
{
"name": "hyperion-project/hyperion.ng",
"version": "2.1.1",
"date": "2025-06-14T17:45:06Z"
},
{
"name": "mongodb/mongo",
"version": "r8.1.2",
"date": "2025-07-01T22:39:32Z"
},
{
"name": "Threadfin/Threadfin",
"version": "1.2.35",
"date": "2025-07-01T21:37:20Z"
},
{
"name": "actualbudget/actual",
"version": "v25.7.0",
"date": "2025-07-01T21:02:27Z"
},
{
"name": "TwiN/gatus",
"version": "v5.19.0",
"date": "2025-07-01T19:59:32Z"
},
{
"name": "Koenkk/zigbee2mqtt",
"version": "2.5.0",
"date": "2025-07-01T18:28:01Z"
},
{
"name": "keycloak/keycloak",
"version": "26.3.0",
"date": "2025-07-01T13:18:12Z"
},
{
"name": "hivemq/hivemq-community-edition",
"version": "2025.4",
"date": "2025-07-01T18:01:37Z"
},
{
"name": "HabitRPG/habitica",
"version": "v5.37.1",
"date": "2025-07-01T16:57:43Z"
},
{
"name": "navidrome/navidrome",
"version": "v0.57.0",
"date": "2025-07-01T16:47:46Z"
},
{
"name": "jenkinsci/jenkins",
"version": "jenkins-2.517",
"date": "2025-07-01T16:08:23Z"
},
{
"name": "element-hq/synapse",
"version": "v1.133.0",
"date": "2025-07-01T15:13:42Z"
},
{
"name": "syncthing/syncthing",
"version": "v1.30.0",
"date": "2025-07-01T11:29:11Z"
},
{
"name": "Checkmk/checkmk",
"version": "v2.2.0p44-rc1",
"date": "2025-07-01T11:10:25Z"
},
{
"name": "rcourtman/Pulse",
"version": "v99.99.99",
"date": "2025-07-01T08:26:41Z"
},
{
"name": "zabbix/zabbix",
"version": "7.4.0",
"date": "2025-07-01T04:36:51Z"
},
{
"name": "openobserve/openobserve",
"version": "v0.15.0-rc3",
"date": "2025-07-01T04:09:37Z"
},
{
"name": "NginxProxyManager/nginx-proxy-manager",
"version": "v2.12.4",
"date": "2025-07-01T01:45:42Z"
},
{
"name": "MagicMirrorOrg/MagicMirror",
"version": "v2.32.0",
"date": "2025-06-30T22:12:48Z"
},
{
"name": "docker/compose",
"version": "v2.38.1",
"date": "2025-06-30T20:07:35Z"
},
{
"name": "jhuckaby/Cronicle",
"version": "v0.9.81",
"date": "2025-06-30T16:40:33Z"
},
{
"name": "ollama/ollama",
"version": "v0.9.4-rc6",
"date": "2025-06-30T15:59:03Z"
},
{
"name": "prometheus/prometheus",
"version": "v2.53.5",
"date": "2025-06-30T11:01:12Z"
},
{
"name": "n8n-io/n8n",
"version": "n8n@1.100.0",
"date": "2025-06-23T12:48:35Z"
},
{
"name": "jupyter/notebook",
"version": "v7.4.4",
"date": "2025-06-30T13:04:22Z"
},
{
"name": "Graylog2/graylog2-server",
"version": "6.3.0",
"date": "2025-06-30T11:26:45Z"
},
{
"name": "grokability/snipe-it",
"version": "v8.1.17",
"date": "2025-06-30T11:26:27Z"
},
{
"name": "documenso/documenso",
"version": "v1.12.0-rc.8",
"date": "2025-06-30T09:47:37Z"
},
{
"name": "PrivateBin/PrivateBin",
"version": "1.7.8",
"date": "2025-06-30T09:00:54Z"
},
{
"name": "fuma-nama/fumadocs",
"version": "fumadocs-mdx@11.6.10",
"date": "2025-06-30T07:07:36Z"
},
{
"name": "mattermost/mattermost",
"version": "preview-v0.1",
"date": "2025-06-27T14:35:47Z"
},
{
"name": "typesense/typesense",
"version": "v29.0",
"date": "2025-06-30T03:52:33Z"
},
{
"name": "dgtlmoon/changedetection.io",
"version": "0.50.5",
"date": "2025-06-29T08:54:47Z"
},
{
"name": "theonedev/onedev",
"version": "v11.11.2",
"date": "2025-06-29T01:40:39Z"
},
{
"name": "linkwarden/linkwarden",
"version": "v2.11.2",
"date": "2025-06-28T17:33:38Z"
},
{
"name": "msgbyte/tianji",
"version": "v1.22.5",
"date": "2025-06-28T16:06:19Z"
}, },
{ {
"name": "Luligu/matterbridge", "name": "Luligu/matterbridge",
"version": "3.1.0", "version": "3.1.0",
"date": "2025-06-28T09:02:38Z" "date": "2025-06-28T09:02:38Z"
}, },
{
"name": "firefly-iii/firefly-iii",
"version": "v6.2.19",
"date": "2025-06-28T06:53:45Z"
},
{ {
"name": "esphome/esphome", "name": "esphome/esphome",
"version": "2025.6.2", "version": "2025.6.2",
@ -34,51 +259,21 @@
"version": "v1.5.0", "version": "v1.5.0",
"date": "2025-06-27T22:04:32Z" "date": "2025-06-27T22:04:32Z"
}, },
{
"name": "linkwarden/linkwarden",
"version": "v2.11.1",
"date": "2025-06-27T21:21:59Z"
},
{ {
"name": "homarr-labs/homarr", "name": "homarr-labs/homarr",
"version": "v1.26.0", "version": "v1.26.0",
"date": "2025-06-27T19:15:24Z" "date": "2025-06-27T19:15:24Z"
}, },
{
"name": "ollama/ollama",
"version": "v0.9.4-rc1",
"date": "2025-06-27T18:45:33Z"
},
{
"name": "home-assistant/core",
"version": "2025.6.3",
"date": "2025-06-24T13:00:12Z"
},
{
"name": "mattermost/mattermost",
"version": "preview-v0.1",
"date": "2025-06-27T14:35:47Z"
},
{ {
"name": "goauthentik/authentik", "name": "goauthentik/authentik",
"version": "version/2025.6.3", "version": "version/2025.6.3",
"date": "2025-06-27T14:01:06Z" "date": "2025-06-27T14:01:06Z"
}, },
{
"name": "keycloak/keycloak",
"version": "26.2.5",
"date": "2025-05-28T06:49:43Z"
},
{ {
"name": "rclone/rclone", "name": "rclone/rclone",
"version": "v1.70.2", "version": "v1.70.2",
"date": "2025-06-27T13:21:17Z" "date": "2025-06-27T13:21:17Z"
}, },
{
"name": "documenso/documenso",
"version": "v1.12.0-rc.7",
"date": "2025-06-27T12:17:45Z"
},
{ {
"name": "sabnzbd/sabnzbd", "name": "sabnzbd/sabnzbd",
"version": "4.5.1", "version": "4.5.1",
@ -89,31 +284,16 @@
"version": "flowise@3.0.3", "version": "flowise@3.0.3",
"date": "2025-06-27T09:53:57Z" "date": "2025-06-27T09:53:57Z"
}, },
{
"name": "nzbgetcom/nzbget",
"version": "v25.1",
"date": "2025-06-27T09:14:14Z"
},
{ {
"name": "cockpit-project/cockpit", "name": "cockpit-project/cockpit",
"version": "341.1", "version": "341.1",
"date": "2025-06-27T08:50:16Z" "date": "2025-06-27T08:50:16Z"
}, },
{
"name": "zabbix/zabbix",
"version": "7.2.10",
"date": "2025-06-27T06:40:00Z"
},
{ {
"name": "MediaBrowser/Emby.Releases", "name": "MediaBrowser/Emby.Releases",
"version": "4.9.1.2", "version": "4.9.1.2",
"date": "2025-06-26T22:08:00Z" "date": "2025-06-26T22:08:00Z"
}, },
{
"name": "prometheus/prometheus",
"version": "v3.4.2",
"date": "2025-06-26T21:45:21Z"
},
{ {
"name": "home-assistant/operating-system", "name": "home-assistant/operating-system",
"version": "15.2", "version": "15.2",
@ -134,11 +314,6 @@
"version": "v1.84.3", "version": "v1.84.3",
"date": "2025-06-26T16:31:57Z" "date": "2025-06-26T16:31:57Z"
}, },
{
"name": "fuma-nama/fumadocs",
"version": "fumadocs-ui@15.5.5",
"date": "2025-06-26T15:54:17Z"
},
{ {
"name": "traefik/traefik", "name": "traefik/traefik",
"version": "v3.5.0-rc1", "version": "v3.5.0-rc1",
@ -164,16 +339,6 @@
"version": "18.0.7", "version": "18.0.7",
"date": "2025-06-26T09:16:33Z" "date": "2025-06-26T09:16:33Z"
}, },
{
"name": "mongodb/mongo",
"version": "r8.1.2-rc1",
"date": "2025-06-25T22:42:04Z"
},
{
"name": "rcourtman/Pulse",
"version": "v3.32.0",
"date": "2025-06-25T22:27:01Z"
},
{ {
"name": "gristlabs/grist-core", "name": "gristlabs/grist-core",
"version": "v1.6.1", "version": "v1.6.1",
@ -184,11 +349,6 @@
"version": "v4.101.2", "version": "v4.101.2",
"date": "2025-06-25T21:18:52Z" "date": "2025-06-25T21:18:52Z"
}, },
{
"name": "msgbyte/tianji",
"version": "v1.22.4",
"date": "2025-06-25T20:46:20Z"
},
{ {
"name": "influxdata/influxdb", "name": "influxdata/influxdb",
"version": "v3.2.0", "version": "v3.2.0",
@ -199,21 +359,11 @@
"version": "2.0.5", "version": "2.0.5",
"date": "2025-06-25T14:53:31Z" "date": "2025-06-25T14:53:31Z"
}, },
{
"name": "jenkinsci/jenkins",
"version": "jenkins-2.504.3",
"date": "2025-06-25T14:43:01Z"
},
{ {
"name": "bunkerity/bunkerweb", "name": "bunkerity/bunkerweb",
"version": "testing", "version": "testing",
"date": "2025-06-16T18:10:42Z" "date": "2025-06-16T18:10:42Z"
}, },
{
"name": "n8n-io/n8n",
"version": "n8n@1.100.0",
"date": "2025-06-23T12:48:35Z"
},
{ {
"name": "moghtech/komodo", "name": "moghtech/komodo",
"version": "v1.18.4", "version": "v1.18.4",
@ -239,31 +389,11 @@
"version": "v2.18.0", "version": "v2.18.0",
"date": "2025-06-24T08:29:55Z" "date": "2025-06-24T08:29:55Z"
}, },
{
"name": "element-hq/synapse",
"version": "v1.132.0",
"date": "2025-06-17T13:49:30Z"
},
{
"name": "docker/compose",
"version": "v2.37.3",
"date": "2025-06-24T14:05:33Z"
},
{
"name": "Checkmk/checkmk",
"version": "v2.4.0p5",
"date": "2025-06-24T13:06:53Z"
},
{ {
"name": "fallenbagel/jellyseerr", "name": "fallenbagel/jellyseerr",
"version": "preview-fix-proxy-axios", "version": "preview-fix-proxy-axios",
"date": "2025-06-24T08:50:22Z" "date": "2025-06-24T08:50:22Z"
}, },
{
"name": "wazuh/wazuh",
"version": "coverity-w26-4.13.0",
"date": "2025-06-24T02:02:34Z"
},
{ {
"name": "minio/minio", "name": "minio/minio",
"version": "RELEASE.2025-06-13T11-33-47Z", "version": "RELEASE.2025-06-13T11-33-47Z",
@ -279,11 +409,6 @@
"version": "pmm-6401-v1.120.0", "version": "pmm-6401-v1.120.0",
"date": "2025-06-23T15:12:12Z" "date": "2025-06-23T15:12:12Z"
}, },
{
"name": "Graylog2/graylog2-server",
"version": "6.3.0-rc.2",
"date": "2025-06-23T11:31:38Z"
},
{ {
"name": "gotson/komga", "name": "gotson/komga",
"version": "1.22.0", "version": "1.22.0",
@ -294,11 +419,6 @@
"version": "2025.6.22", "version": "2025.6.22",
"date": "2025-06-22T22:41:11Z" "date": "2025-06-22T22:41:11Z"
}, },
{
"name": "qbittorrent/qBittorrent",
"version": "release-5.1.1",
"date": "2025-06-22T21:41:17Z"
},
{ {
"name": "clusterzx/paperless-ai", "name": "clusterzx/paperless-ai",
"version": "v3.0.7", "version": "v3.0.7",
@ -314,31 +434,16 @@
"version": "0.17.14", "version": "0.17.14",
"date": "2025-06-21T23:43:04Z" "date": "2025-06-21T23:43:04Z"
}, },
{
"name": "HabitRPG/habitica",
"version": "v5.37.0",
"date": "2025-06-21T14:05:12Z"
},
{ {
"name": "rogerfar/rdt-client", "name": "rogerfar/rdt-client",
"version": "v2.0.114", "version": "v2.0.114",
"date": "2025-06-21T11:20:21Z" "date": "2025-06-21T11:20:21Z"
}, },
{
"name": "theonedev/onedev",
"version": "v11.11.1",
"date": "2025-06-21T09:23:39Z"
},
{ {
"name": "pocketbase/pocketbase", "name": "pocketbase/pocketbase",
"version": "v0.28.4", "version": "v0.28.4",
"date": "2025-06-21T08:29:04Z" "date": "2025-06-21T08:29:04Z"
}, },
{
"name": "dgtlmoon/changedetection.io",
"version": "0.50.4",
"date": "2025-06-21T07:47:02Z"
},
{ {
"name": "go-gitea/gitea", "name": "go-gitea/gitea",
"version": "v1.24.2", "version": "v1.24.2",
@ -354,11 +459,6 @@
"version": "v4.0.15.2941", "version": "v4.0.15.2941",
"date": "2025-06-20T17:20:54Z" "date": "2025-06-20T17:20:54Z"
}, },
{
"name": "syncthing/syncthing",
"version": "2.0.0-rc.19",
"date": "2025-06-02T17:56:25Z"
},
{ {
"name": "benzino77/tasmocompiler", "name": "benzino77/tasmocompiler",
"version": "v12.7.0", "version": "v12.7.0",
@ -389,79 +489,9 @@
"version": "v3.5.5", "version": "v3.5.5",
"date": "2025-06-19T05:43:47Z" "date": "2025-06-19T05:43:47Z"
}, },
{
"name": "docmost/docmost",
"version": "v0.21.0",
"date": "2025-06-18T21:43:27Z"
},
{ {
"name": "ipfs/kubo", "name": "ipfs/kubo",
"version": "v0.35.0", "version": "v0.35.0",
"date": "2025-05-21T18:00:32Z" "date": "2025-05-21T18:00:32Z"
},
{
"name": "pterodactyl/panel",
"version": "v1.11.11",
"date": "2025-06-18T18:04:50Z"
},
{
"name": "NodeBB/NodeBB",
"version": "v3.12.7",
"date": "2025-06-18T14:22:53Z"
},
{
"name": "openhab/openhab-core",
"version": "5.0.0.M3",
"date": "2025-06-18T14:18:12Z"
},
{
"name": "Bubka/2FAuth",
"version": "v5.6.0",
"date": "2025-06-18T12:19:54Z"
},
{
"name": "zwave-js/zwave-js-ui",
"version": "v10.7.0",
"date": "2025-06-18T11:57:05Z"
},
{
"name": "forgejo/forgejo",
"version": "v11.0.2",
"date": "2025-06-18T09:38:19Z"
},
{
"name": "silverbulletmd/silverbullet",
"version": "2.0.0-pre3",
"date": "2025-06-18T08:01:24Z"
},
{
"name": "cross-seed/cross-seed",
"version": "v6.12.7",
"date": "2025-06-18T03:44:24Z"
},
{
"name": "grafana/grafana",
"version": "v11.5.6",
"date": "2025-06-17T22:00:40Z"
},
{
"name": "project-zot/zot",
"version": "v2.1.5",
"date": "2025-06-17T18:04:11Z"
},
{
"name": "BookStackApp/BookStack",
"version": "v25.05.1",
"date": "2025-06-17T14:38:04Z"
},
{
"name": "cloudflare/cloudflared",
"version": "2025.6.1",
"date": "2025-06-17T12:45:39Z"
},
{
"name": "crowdsecurity/crowdsec",
"version": "v1.6.9",
"date": "2025-06-17T11:54:50Z"
} }
] ]

View File

@ -0,0 +1,35 @@
{
"name": "Wallabag",
"slug": "wallabag",
"categories": [
12
],
"date_created": "2025-07-02",
"type": "ct",
"updateable": true,
"privileged": false,
"config_path": "/opt/wallabag/.env",
"interface_port": 3000,
"documentation": "https://wallabag.io/",
"website": "https://wallabag.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/wallabag.svg",
"description": "Wallabag is an open-source self-hosted application.",
"install_methods": [
{
"type": "default",
"script": "ct/wallabag.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 2,
"os": "Debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@ -1,29 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
# Source: https://syncthing.net/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Setup Syncthing"
$STD apk add --no-cache syncthing
msg_ok "Setup Syncthing"
msg_info "Enabling Syncthing Service"
$STD rc-update add syncthing default
msg_ok "Enabled Syncthing Service"
msg_info "Starting Syncthing"
$STD rc-service syncthing start
msg_ok "Started Syncthing"
motd_ssh
customize

View File

@ -17,6 +17,8 @@ msg_info "Installing Dependencies"
$STD apt-get install -y gpg $STD apt-get install -y gpg
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
#FFMPEG_VERSION="n7.1.1" FFMPEG_TYPE="full" setup_ffmpeg
#fetch_and_deploy_gh_release "argus" "release-argus/Argus" "singlefile" "latest" "/opt/argus" "Argus-.*linux-amd64" #fetch_and_deploy_gh_release "argus" "release-argus/Argus" "singlefile" "latest" "/opt/argus" "Argus-.*linux-amd64"
#fetch_and_deploy_gh_release "planka" "plankanban/planka" "prebuild" "latest" "/opt/planka" "planka-prebuild.zip" #fetch_and_deploy_gh_release "planka" "plankanban/planka" "prebuild" "latest" "/opt/planka" "planka-prebuild.zip"

View File

@ -1,9 +1,9 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck # Copyright (c) 2021-2025 community-scripts ORG
# Author: tteck (tteckster) # Author: MickLesk (CanbiZ)
# License: MIT # License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
# https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE # Source: https://hanko.io/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color color

View File

@ -1,77 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: Florianb63
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://itsm-ng.com/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
setup_mariadb
msg_info "Installing Repository"
curl -fsSL http://deb.itsm-ng.org/pubkey.gpg | gpg --dearmor -o /etc/apt/trusted.gpg.d/itsm-ng-keyring.gpg
echo "deb http://deb.itsm-ng.org/$(. /etc/os-release && echo "$ID")/ $(. /etc/os-release && echo "$VERSION_CODENAME") main" > /etc/apt/sources.list.d/itsm-ng.list
$STD apt update
msg_ok "Installed Repository"
msg_info "Installing ITSM-NG"
$STD apt install -y itsm-ng
msg_ok "Installed ITSM-NG"
msg_info "Setting up database"
DB_NAME=itsmng_db
DB_USER=itsmng
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
mariadb-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;"
{
echo "ITSM-NG Database Credentials"
echo "Database: $DB_NAME"
echo "Username: $DB_USER"
echo "Password: $DB_PASS"
} >>~/itsmng_db.creds
msg_ok "Set up database"
msg_info "Installing ITSM-NG"
cd /usr/share/itsm-ng
$STD php bin/console db:install --db-name=$DB_NAME --db-user=$DB_USER --db-password=$DB_PASS --no-interaction
msg_ok "Installed ITSM-NG"
msg_info "Configuring webserver"
$STD a2dissite 000-default.conf
msg_ok "Setup Service"
msg_info "Setup Cronjob"
echo "* * * * * php /usr/share/itsm-ng/front/cron.php" | crontab -
msg_ok "Setup Cronjob"
msg_info "Update PHP Params"
PHP_VERSION=$(ls /etc/php/ | grep -E '^[0-9]+\.[0-9]+$' | head -n 1)
PHP_INI="/etc/php/$PHP_VERSION/apache2/php.ini"
sed -i 's/^upload_max_filesize = .*/upload_max_filesize = 20M/' $PHP_INI
sed -i 's/^post_max_size = .*/post_max_size = 20M/' $PHP_INI
sed -i 's/^max_execution_time = .*/max_execution_time = 60/' $PHP_INI
sed -i 's/^max_input_vars = .*/max_input_vars = 5000/' $PHP_INI
sed -i 's/^memory_limit = .*/memory_limit = 256M/' $PHP_INI
sed -i 's/^;\?\s*session.cookie_httponly\s*=.*/session.cookie_httponly = On/' $PHP_INI
systemctl restart apache2
msg_ok "Update PHP Params"
motd_ssh
customize
msg_info "Cleaning up"
rm -rf /usr/share/itsm-ng/install
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@ -1,64 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://jellyfin.org/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Setting Up Hardware Acceleration"
$STD apt-get -y install {va-driver-all,ocl-icd-libopencl1,intel-opencl-icd,vainfo,intel-gpu-tools}
if [[ "$CTTYPE" == "0" ]]; then
chgrp video /dev/dri
chmod 755 /dev/dri
chmod 660 /dev/dri/*
$STD adduser $(id -u -n) video
$STD adduser $(id -u -n) render
fi
msg_ok "Set Up Hardware Acceleration"
msg_info "Installing Jellyfin"
VERSION="$(awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release)"
# If the keyring directory is absent, create it
if [[ ! -d /etc/apt/keyrings ]]; then
mkdir -p /etc/apt/keyrings
fi
# Download the repository signing key and install it to the keyring directory
curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | gpg --dearmor --yes --output /etc/apt/keyrings/jellyfin.gpg
# Install the Deb822 format jellyfin.sources entry
cat <<EOF >/etc/apt/sources.list.d/jellyfin.sources
Types: deb
URIs: https://repo.jellyfin.org/${PCT_OSTYPE}
Suites: ${VERSION}
Components: main
Architectures: amd64
Signed-By: /etc/apt/keyrings/jellyfin.gpg
EOF
# Install Jellyfin using the metapackage (which will fetch jellyfin-server, jellyfin-web, and jellyfin-ffmpeg5)
$STD apt-get update
$STD apt-get install -y jellyfin
sed -i 's/"MinimumLevel": "Information"/"MinimumLevel": "Error"/g' /etc/jellyfin/logging.json
chown -R jellyfin:adm /etc/jellyfin
sleep 10
systemctl restart jellyfin
if [[ "$CTTYPE" == "0" ]]; then
sed -i -e 's/^ssl-cert:x:104:$/render:x:104:root,jellyfin/' -e 's/^render:x:108:root,jellyfin$/ssl-cert:x:108:/' /etc/group
else
sed -i -e 's/^ssl-cert:x:104:$/render:x:104:jellyfin/' -e 's/^render:x:108:jellyfin$/ssl-cert:x:108:/' /etc/group
fi
msg_ok "Installed Jellyfin"
motd_ssh
customize
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@ -1,54 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: Slaviša Arežina (tremor021)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/Casvt/Kapowarr
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Setup Python3"
$STD apt-get install -y python3-pip
msg_ok "Setup Python3"
setup_uv
fetch_and_deploy_gh_release "kapowarr" "Casvt/Kapowarr"
msg_info "Setup Kapowarr"
cd /opt/kapowarr
$STD uv venv .venv
$STD source .venv/bin/activate
$STD uv pip install --upgrade pip
$STD uv pip install --no-cache-dir -r requirements.txt
msg_ok "Installed Kapowarr"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/kapowarr.service
[Unit]
Description=Kapowarr Service
After=network.target
[Service]
WorkingDirectory=/opt/kapowarr/
ExecStart=/opt/kapowarr/.venv/bin/python3 Kapowarr.py
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now kapowarr
msg_ok "Created Service"
motd_ssh
customize
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: JasonGreenC
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/thecfu/scraparr
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Scraparr"
PYTHON_VERSION="3.12" setup_uv
fetch_and_deploy_gh_release "scrappar" "thecfu/scraparr" "tarball" "latest" "/opt/scraparr"
cd /opt/scraparr || exit
$STD uv venv /opt/scraparr/.venv
$STD /opt/scraparr/.venv/bin/python -m ensurepip --upgrade
$STD /opt/scraparr/.venv/bin/python -m pip install --upgrade pip
$STD /opt/scraparr/.venv/bin/python -m pip install -r /opt/scraparr/src/scraparr/requirements.txt
chmod -R 755 /opt/scraparr
mkdir -p /scraparr/config
mv /opt/scraparr/config.yaml /scraparr/config/config.yaml
chmod -R 755 /scraparr
msg_ok "Installed Scraparr"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/scraparr.service
[Unit]
Description=Scraparr
Wants=network-online.target
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/scraparr/src
ExecStart=/opt/scraparr/.venv/bin/python -m scraparr.scraparr
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable -q --now scraparr
msg_ok "Configured Service"
motd_ssh
customize
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@ -14,28 +14,24 @@ update_os
msg_info "Installing Dependencies (Patience)" msg_info "Installing Dependencies (Patience)"
$STD apt-get install -y \ $STD apt-get install -y \
curl \
git \
unzip \
sudo \
make \ make \
php8.2 \
php8.2-{cli,common,bcmath,intl,fpm,tidy,xml,mysql,mbstring,zip,gd,curl} \
composer \
apache2 \ apache2 \
libapache2-mod-php \ libapache2-mod-php \
redis \ redis
mariadb-server
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
setup_mariadb
PHP_VERSION="8.3" PHP_APACHE="YES" PHP_FPM="YES" PHP_MODULE="bcmath,bz2,cli,exif,common,curl,tidy,fpm,gd,intl,mbstring,xml,mysql,zip" setup_php
setup_composer
msg_info "Setting up Database" msg_info "Setting up Database"
DB_NAME=wallabag_db DB_NAME=wallabag_db
DB_USER=wallabag DB_USER=wallabag
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13) DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
SECRET_KEY="$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | cut -c1-32)" SECRET_KEY="$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | cut -c1-32)"
$STD mysql -u root -e "CREATE DATABASE $DB_NAME;" $STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
$STD mysql -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';" $STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$STD mysql -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;" $STD mariadb -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
{ {
echo "Wallabag Credentials" echo "Wallabag Credentials"
echo "Database User: $DB_USER" echo "Database User: $DB_USER"
@ -44,11 +40,9 @@ $STD mysql -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localho
} >>~/wallabag.creds } >>~/wallabag.creds
msg_ok "Set up Database" msg_ok "Set up Database"
fetch_and_deploy_gh_release "wallabag" "wallabag/wallabag" "prebuild" "latest" "/opt/wallabag" "wallabag-*.tar.gz"
msg_info "Installing Wallabag (Patience)" msg_info "Installing Wallabag (Patience)"
RELEASE=$(curl -s https://api.github.com/repos/wallabag/wallabag/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
wget -q "https://github.com/wallabag/wallabag/archive/refs/tags/${RELEASE}.zip"
unzip -q ${RELEASE}.zip
mv wallabag-${RELEASE} /opt/wallabag
cd /opt/wallabag cd /opt/wallabag
useradd -d /opt/wallabag -s /bin/bash -M wallabag useradd -d /opt/wallabag -s /bin/bash -M wallabag
chown -R wallabag:wallabag /opt/wallabag chown -R wallabag:wallabag /opt/wallabag

View File

@ -186,92 +186,92 @@ ssh_check() {
fi fi
} }
select_storage() { # select_storage() {
local CLASS=$1 CONTENT CONTENT_LABEL # local CLASS=$1 CONTENT CONTENT_LABEL
case $CLASS in # case $CLASS in
container) # container)
CONTENT='rootdir' # CONTENT='rootdir'
CONTENT_LABEL='Container' # CONTENT_LABEL='Container'
;; # ;;
template) # template)
CONTENT='vztmpl' # CONTENT='vztmpl'
CONTENT_LABEL='Template' # CONTENT_LABEL='Template'
;; # ;;
iso) # iso)
CONTENT='iso' # CONTENT='iso'
CONTENT_LABEL='ISO image' # CONTENT_LABEL='ISO image'
;; # ;;
images) # images)
CONTENT='images' # CONTENT='images'
CONTENT_LABEL='VM Disk image' # CONTENT_LABEL='VM Disk image'
;; # ;;
backup) # backup)
CONTENT='backup' # CONTENT='backup'
CONTENT_LABEL='Backup' # CONTENT_LABEL='Backup'
;; # ;;
snippets) # snippets)
CONTENT='snippets' # CONTENT='snippets'
CONTENT_LABEL='Snippets' # CONTENT_LABEL='Snippets'
;; # ;;
*) # *)
msg_error "Invalid storage class '$CLASS'." # msg_error "Invalid storage class '$CLASS'."
exit 201 # exit 201
;; # ;;
esac # esac
command -v whiptail >/dev/null || { # command -v whiptail >/dev/null || {
msg_error "whiptail missing." # msg_error "whiptail missing."
exit 220 # exit 220
} # }
command -v numfmt >/dev/null || { # command -v numfmt >/dev/null || {
msg_error "numfmt missing." # msg_error "numfmt missing."
exit 221 # exit 221
} # }
local -a MENU # local -a MENU
while read -r line; do # while read -r line; do
local TAG=$(echo "$line" | awk '{print $1}') # local TAG=$(echo "$line" | awk '{print $1}')
local TYPE=$(echo "$line" | awk '{printf "%-10s", $2}') # local TYPE=$(echo "$line" | awk '{printf "%-10s", $2}')
local FREE=$(echo "$line" | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf "%9sB", $6}') # local FREE=$(echo "$line" | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf "%9sB", $6}')
MENU+=("$TAG" "Type: $TYPE Free: $FREE" "OFF") # MENU+=("$TAG" "Type: $TYPE Free: $FREE" "OFF")
done < <(pvesm status -content "$CONTENT" | awk 'NR>1') # done < <(pvesm status -content "$CONTENT" | awk 'NR>1')
if [ ${#MENU[@]} -eq 0 ]; then # if [ ${#MENU[@]} -eq 0 ]; then
msg_error "No storage found for content type '$CONTENT'." # msg_error "No storage found for content type '$CONTENT'."
exit 203 # exit 203
fi # fi
if [ $((${#MENU[@]} / 3)) -eq 1 ]; then # if [ $((${#MENU[@]} / 3)) -eq 1 ]; then
echo "${MENU[0]}" # echo "${MENU[0]}"
return # return
fi # fi
local STORAGE # local STORAGE
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \ # STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool for ${CONTENT_LABEL,,}?\n(Spacebar to select)" \ # "Which storage pool for ${CONTENT_LABEL,,}?\n(Spacebar to select)" \
16 70 6 "${MENU[@]}" 3>&1 1>&2 2>&3) || { # 16 70 6 "${MENU[@]}" 3>&1 1>&2 2>&3) || {
msg_error "Storage selection cancelled by user." # msg_error "Storage selection cancelled by user."
exit 202 # exit 202
} # }
echo "$STORAGE" # echo "$STORAGE"
} # }
manage_default_storage() { # manage_default_storage() {
local file="/usr/local/community-scripts/default_storage" # local file="/usr/local/community-scripts/default_storage"
mkdir -p /usr/local/community-scripts # mkdir -p /usr/local/community-scripts
local tmpl=$(select_storage template) # local tmpl=$(select_storage template)
local cont=$(select_storage container) # local cont=$(select_storage container)
cat <<EOF >"$file" # cat <<EOF >"$file"
TEMPLATE_STORAGE=$tmpl # TEMPLATE_STORAGE=$tmpl
CONTAINER_STORAGE=$cont # CONTAINER_STORAGE=$cont
EOF # EOF
msg_ok "Default Storage set: Template=${BL}$tmpl${CL} ${GN}|${CL} Container=${BL}$cont${CL}" # msg_ok "Default Storage set: Template=${BL}$tmpl${CL} ${GN}|${CL} Container=${BL}$cont${CL}"
whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \ # whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \
--msgbox "Default Storage set:\n\nTemplate: $tmpl\nContainer: $cont" 10 58 # --msgbox "Default Storage set:\n\nTemplate: $tmpl\nContainer: $cont" 10 58
} # }
base_settings() { base_settings() {
# Default Settings # Default Settings
@ -333,13 +333,13 @@ write_config() {
CT_TYPE="${CT_TYPE}" CT_TYPE="${CT_TYPE}"
DISK_SIZE="${DISK_SIZE}" DISK_SIZE="${DISK_SIZE}"
CORE_COUNT="${DISK_SIZE}" CORE_COUNT="${CORE_COUNT}"
RAM_SIZE="${RAM_SIZE}" RAM_SIZE="${RAM_SIZE}"
HN="${HN}" HN="${HN}"
BRG="${BRG}" BRG="${BRG}"
APT_CACHER_IP="${APT_CACHER_IP:-none}" APT_CACHER_IP="${APT_CACHER_IP:-none}"
DISABLEIP6="${DISABLEIP6}" DISABLEIP6="${DISABLEIP6}"
PW="${PW:-none}" PW='${PW:-none}'
SSH="${SSH}" SSH="${SSH}"
SSH_AUTHORIZED_KEY="${SSH_AUTHORIZED_KEY}" SSH_AUTHORIZED_KEY="${SSH_AUTHORIZED_KEY}"
VERBOSE="${VERBOSE}" VERBOSE="${VERBOSE}"
@ -351,6 +351,7 @@ SD="${SD:-none}"
MAC="${MAC:-none}" MAC="${MAC:-none}"
NS="${NS:-none}" NS="${NS:-none}"
NET="${NET}" NET="${NET}"
FUSE="${ENABLE_FUSE}"
EOF EOF
echo -e "${INFO}${BOLD}${GN}Writing configuration to ${FILEPATH}${CL}" echo -e "${INFO}${BOLD}${GN}Writing configuration to ${FILEPATH}${CL}"
@ -364,7 +365,7 @@ EOF
CT_TYPE="${CT_TYPE}" CT_TYPE="${CT_TYPE}"
DISK_SIZE="${DISK_SIZE}" DISK_SIZE="${DISK_SIZE}"
CORE_COUNT="${DISK_SIZE}" CORE_COUNT="${CORE_COUNT}"
RAM_SIZE="${RAM_SIZE}" RAM_SIZE="${RAM_SIZE}"
HN="${HN}" HN="${HN}"
BRG="${BRG}" BRG="${BRG}"
@ -382,6 +383,7 @@ SD="${SD:-none}"
MAC="${MAC:-none}" MAC="${MAC:-none}"
NS="${NS:-none}" NS="${NS:-none}"
NET="${NET}" NET="${NET}"
FUSE="${ENABLE_FUSE}"
EOF EOF
echo -e "${INFO}${BOLD}${GN}Writing configuration to ${FILEPATH}${CL}" echo -e "${INFO}${BOLD}${GN}Writing configuration to ${FILEPATH}${CL}"
@ -402,9 +404,11 @@ echo_default() {
# Output the selected values with icons # Output the selected values with icons
echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}${CT_ID}${CL}" echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}${CT_ID}${CL}"
echo -e "${OS}${BOLD}${DGN}Operating System: $var_os | Version: $var_version${CL}" echo -e "${OS}${BOLD}${DGN}Operating System: ${BGN}$var_os ($var_version)${CL}"
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}" echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB | ${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT} | ${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}" echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}"
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
if [ "$VERB" == "yes" ]; then if [ "$VERB" == "yes" ]; then
echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}Enabled${CL}" echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}Enabled${CL}"
fi fi
@ -861,12 +865,12 @@ advanced_settings() {
echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}"
fi 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" ENABLE_FUSE="yes"
# else else
# ENABLE_FUSE="no" ENABLE_FUSE="no"
# fi fi
# echo -e "${FUSE}${BOLD}${DGN}Enable FUSE Support: ${BGN}$ENABLE_FUSE${CL}" echo -e "${FUSE}${BOLD}${DGN}Enable FUSE Support: ${BGN}$ENABLE_FUSE${CL}"
if (whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "VERBOSE MODE" --yesno "Enable Verbose Mode?" 10 58); then if (whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "VERBOSE MODE" --yesno "Enable Verbose Mode?" 10 58); then
VERBOSE="yes" VERBOSE="yes"
@ -1195,12 +1199,10 @@ build_container() {
-unprivileged $CT_TYPE -unprivileged $CT_TYPE
$PW $PW
" "
# This executes create_lxc.sh and creates the container and .conf file bash -c "$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/create_lxc.sh)"
CREATE_CMD="bash -c \"\$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/create_lxc.sh)\""
eval "$CREATE_CMD"
RET=$? RET=$?
if [[ $RET -ne 0 ]]; then if [[ $RET -ne 0 ]]; then
msg_error "in line $LINENO: exit code $RET: while executing command $CREATE_CMD" msg_error "rny: in line $LINENO: exit code $RET: while executing create_lxc.sh"
exit $RET exit $RET
fi fi
@ -1273,21 +1275,24 @@ EOF'
pct exec "$CTID" -- ash -c "apk add bash newt curl openssh nano mc ncurses >/dev/null" pct exec "$CTID" -- ash -c "apk add bash newt curl openssh nano mc ncurses >/dev/null"
else else
sleep 3 sleep 3
# Set locale and timezone before update
pct exec "$CTID" -- bash -c "sed -i '/$LANG/ s/^# //' /etc/locale.gen" pct exec "$CTID" -- bash -c "sed -i '/$LANG/ s/^# //' /etc/locale.gen"
pct exec "$CTID" -- bash -c "locale_line=\$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print \$1}' | head -n 1) && \ pct exec "$CTID" -- bash -c "locale_line=\$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print \$1}' | head -n 1) && \
echo LANG=\$locale_line >/etc/default/locale && \ echo LANG=\$locale_line >/etc/default/locale && \
locale-gen >/dev/null && \ locale-gen >/dev/null && \
export LANG=\$locale_line" export LANG=\$locale_line"
if pct exec "$CTID" -- test -e "/usr/share/zoneinfo/$tz"; then
pct exec "$CTID" -- bash -c "echo $tz >/etc/timezone && ln -sf /usr/share/zoneinfo/$tz /etc/localtime" pct exec "$CTID" -- bash -c "echo $tz >/etc/timezone && ln -sf /usr/share/zoneinfo/$tz /etc/localtime"
else
msg_info "Skipping timezone setup zone '$tz' not found in container"
fi
# Install curl
pct exec "$CTID" -- bash -c "apt-get update >/dev/null && apt-get install -y sudo curl mc gnupg2 >/dev/null" pct exec "$CTID" -- bash -c "apt-get update >/dev/null && apt-get install -y sudo curl mc gnupg2 >/dev/null"
fi fi
msg_ok "Customized LXC Container" msg_ok "Customized LXC Container"
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/install/$var_install.sh)" $?
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/install/"$var_install".sh)" $?
} }
# This function sets the description of the container. # This function sets the description of the container.

View File

@ -9,21 +9,21 @@
# } # }
# fi # fi
trap 'on_error $? $LINENO' ERR # trap 'on_error $? $LINENO' ERR
trap 'on_exit' EXIT # trap 'on_exit' EXIT
trap 'on_interrupt' INT # trap 'on_interrupt' INT
trap 'on_terminate' TERM # trap 'on_terminate' TERM
if ! declare -f wait_for >/dev/null; then # if ! declare -f wait_for >/dev/null; then
wait_for() { # wait_for() {
true # true
} # }
fi # fi
declare -A MSG_INFO_SHOWN=() # declare -A MSG_INFO_SHOWN=()
SPINNER_PID="" # SPINNER_PID=""
SPINNER_ACTIVE=0 # SPINNER_ACTIVE=0
SPINNER_MSG="" # SPINNER_MSG=""
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Loads core utility groups once (colors, formatting, icons, defaults). # Loads core utility groups once (colors, formatting, icons, defaults).
@ -47,9 +47,9 @@ load_functions() {
# Error & Signal Handling robust, universal, subshell-safe # Error & Signal Handling robust, universal, subshell-safe
# ============================================================================ # ============================================================================
_stop_spinner_on_error() { # _stop_spinner_on_error() {
[[ -n "${SPINNER_PID:-}" ]] && kill "$SPINNER_PID" 2>/dev/null && wait "$SPINNER_PID" 2>/dev/null || true # [[ -n "${SPINNER_PID:-}" ]] && kill "$SPINNER_PID" 2>/dev/null && wait "$SPINNER_PID" 2>/dev/null || true
} # }
_tool_error_hint() { _tool_error_hint() {
local cmd="$1" local cmd="$1"
@ -89,44 +89,39 @@ _tool_error_hint() {
esac esac
} }
on_error() { # on_error() {
local code="$?" # local code="$?"
local line="${BASH_LINENO[0]:-unknown}" # local line="${BASH_LINENO[0]:-unknown}"
local cmd="${BASH_COMMAND:-unknown}" # local cmd="${BASH_COMMAND:-unknown}"
# Signalcode unterdrücken, falls INT/TERM kommt # # Signalcode unterdrücken, falls INT/TERM kommt
[[ "$code" == "130" || "$code" == "143" ]] && return # [[ "$code" == "130" || "$code" == "143" ]] && return
_stop_spinner_on_error # _stop_spinner_on_error
msg_error "Script failed at line $line with exit code $code: $cmd" # msg_error "Script failed at line $line with exit code $code: $cmd"
exit "$code" # exit "$code"
} # }
on_exit() { # on_exit() {
_stop_spinner_on_error # _stop_spinner_on_error
[[ "${VERBOSE:-no}" == "yes" ]] && msg_info "Script exited cleanly" # [[ "${VERBOSE:-no}" == "yes" ]] && msg_info "Script exited cleanly"
} # }
on_interrupt() { # on_interrupt() {
_stop_spinner_on_error # _stop_spinner_on_error
msg_error "Interrupted by user (CTRL+C)" # msg_error "Interrupted by user (CTRL+C)"
exit 130 # exit 130
} # }
on_terminate() { # on_terminate() {
_stop_spinner_on_error # _stop_spinner_on_error
msg_error "Terminated by signal (SIGTERM)" # msg_error "Terminated by signal (SIGTERM)"
exit 143 # exit 143
} # }
catch_errors() { catch_errors() {
trap 'on_error' ERR
trap 'on_exit' EXIT
trap 'on_interrupt' INT
trap 'on_terminate' TERM
set -Eeuo pipefail set -Eeuo pipefail
shopt -s inherit_errexit trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -143,6 +138,13 @@ color() {
CL=$(echo "\033[m") CL=$(echo "\033[m")
} }
# Special for spinner and colorized output via printf
color_spinner() {
CS_YW=$'\033[33m'
CS_YWB=$'\033[93m'
CS_CL=$'\033[m'
}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Defines formatting helpers like tab, bold, and line reset sequences. # Defines formatting helpers like tab, bold, and line reset sequences.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -363,149 +365,215 @@ fatal() {
kill -INT $$ kill -INT $$
} }
# Ensure POSIX compatibility across Alpine and Debian/Ubuntu # # Ensure POSIX compatibility across Alpine and Debian/Ubuntu
# === Spinner Start === # # === Spinner Start ===
# Trap cleanup on various signals # # Trap cleanup on various signals
trap 'cleanup_spinner' EXIT INT TERM HUP # trap 'cleanup_spinner' EXIT INT TERM HUP
spinner_frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏') # spinner_frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
# === Spinner Start === # # === Spinner Start ===
start_spinner() { # start_spinner() {
local msg="$1" # local msg="$1"
local spin_i=0 # local spin_i=0
local interval=0.1 # local interval=0.1
stop_spinner # stop_spinner
SPINNER_MSG="$msg" # SPINNER_MSG="$msg"
SPINNER_ACTIVE=1 # SPINNER_ACTIVE=1
{ # {
while [[ "$SPINNER_ACTIVE" -eq 1 ]]; do # while [[ "$SPINNER_ACTIVE" -eq 1 ]]; do
if [[ -t 2 ]]; then # if [[ -t 2 ]]; then
printf "\r\e[2K%s %b" "${TAB}${spinner_frames[spin_i]}${TAB}" "${YW}${SPINNER_MSG}${CL}" >&2 # printf "\r\e[2K%s %b" "${TAB}${spinner_frames[spin_i]}${TAB}" "${YW}${SPINNER_MSG}${CL}" >&2
else # else
printf "%s...\n" "$SPINNER_MSG" >&2 # printf "%s...\n" "$SPINNER_MSG" >&2
break # break
fi # fi
spin_i=$(((spin_i + 1) % ${#spinner_frames[@]})) # spin_i=$(((spin_i + 1) % ${#spinner_frames[@]}))
sleep "$interval" # 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
# echo -e "OS: ${var_os:-}"
# if [[ "${VERBOSE:-no}" != "no" || "${var_os:-}" == "alpine" || ! -t 2 ]]; then
# printf "\r\e[2K%s %b\n" "$HOURGLASS" "${YW}${msg}${CL}" >&2
# else
# start_spinner "$msg"
# fi
# }
spinner() {
local chars=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏)
local i=0
while true; do
local index=$((i++ % ${#chars[@]}))
printf "\r\033[2K%s %b" "${CS_YWB}${chars[$index]}${CS_CL}" "${CS_YWB}${SPINNER_MSG:-}${CS_CL}"
sleep 0.1
done 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() { stop_spinner() {
if [[ "$SPINNER_ACTIVE" -eq 1 && -n "$SPINNER_PID" ]]; then local pid="${SPINNER_PID:-}"
SPINNER_ACTIVE=0 [[ -z "$pid" && -f /tmp/.spinner.pid ]] && pid=$(</tmp/.spinner.pid)
if kill -0 "$SPINNER_PID" 2>/dev/null; then if [[ -n "$pid" && "$pid" =~ ^[0-9]+$ ]]; then
kill "$SPINNER_PID" 2>/dev/null || true if kill "$pid" 2>/dev/null; then
for _ in $(seq 1 10); do
sleep 0.05 sleep 0.05
kill -0 "$SPINNER_PID" 2>/dev/null || break kill -9 "$pid" 2>/dev/null || true
done wait "$pid" 2>/dev/null || true
fi
rm -f /tmp/.spinner.pid
unset SPINNER_PID
fi fi
if [[ "$SPINNER_PID" =~ ^[0-9]+$ ]]; then stty sane 2>/dev/null
ps -p "$SPINNER_PID" -o pid= >/dev/null 2>&1 && wait "$SPINNER_PID" 2>/dev/null || true #printf "\r\033[K\e[?25h\n"
fi
printf "\r\e[2K" >&2
SPINNER_PID=""
fi
}
cleanup_spinner() {
stop_spinner
} }
msg_info() { msg_info() {
local msg="$1" local msg="$1"
[[ -z "$msg" || -n "${MSG_INFO_SHOWN["$msg"]+x}" ]] && return SPINNER_MSG="$msg"
MSG_INFO_SHOWN["$msg"]=1 color_spinner
spinner &
stop_spinner SPINNER_PID=$!
echo "$SPINNER_PID" >/tmp/.spinner.pid
if [[ "${VERBOSE:-no}" != "no" || "${var_os:-}" == "alpine" || ! -t 2 ]]; then disown "$SPINNER_PID" 2>/dev/null || true
printf "\r\e[2K%s %b\n" "$HOURGLASS" "${YW}${msg}${CL}" >&2
else
start_spinner "$msg"
fi
} }
msg_ok() { msg_ok() {
local msg="$1"
[[ -z "$msg" ]] && return
stop_spinner stop_spinner
printf "\r\e[2K%s %b\n" "$CM" "${GN}${msg}${CL}" >&2 local msg="$1"
if declare -p MSG_INFO_SHOWN &>/dev/null && [[ "$(declare -p MSG_INFO_SHOWN 2>/dev/null)" =~ "declare -A" ]]; then echo -e "${BFR:-} ${CM:-✔️} ${GN}${msg}${CL}"
unset MSG_INFO_SHOWN["$msg"]
fi
} }
msg_error() { msg_error() {
local msg="$1"
[[ -z "$msg" ]] && return
stop_spinner stop_spinner
printf "\r\e[2K%s %b\n" "$CROSS" "${RD}${msg}${CL}" >&2 local msg="$1"
echo -e "${BFR:-} ${CROSS:-✖️} ${RD}${msg}${CL}"
} }
msg_warn() { msg_warn() {
local msg="$1"
[[ -z "$msg" ]] && return
stop_spinner stop_spinner
printf "\r\e[2K%s %b\n" "$INFO" "${YWB}${msg}${CL}" >&2 local msg="$1"
if declare -p MSG_INFO_SHOWN &>/dev/null && [[ "$(declare -p MSG_INFO_SHOWN 2>/dev/null)" =~ "declare -A" ]]; then echo -e "${BFR:-} ${INFO:-} ${YWB}${msg}${CL}"
unset MSG_INFO_SHOWN["$msg"]
fi
} }
msg_custom() { msg_custom() {
local symbol="${1:-"[*]"}" local symbol="${1:-"[*]"}"
local color="${2:-"\e[36m"}" # Default: Cyan local color="${2:-"\e[36m"}"
local msg="${3:-}" local msg="${3:-}"
[[ -z "$msg" ]] && return [[ -z "$msg" ]] && return
stop_spinner 2>/dev/null || true stop_spinner
printf "\r\e[2K%s %b\n" "$symbol" "${color}${msg}${CL:-\e[0m}" >&2 echo -e "${BFR:-} ${symbol} ${color}${msg}${CL:-\e[0m}"
printf "\r\033[K\e[?25h\n"
} }
msg_progress() { # msg_ok() {
local current="$1" # local msg="$1"
local total="$2" # [[ -z "$msg" ]] && return
local label="$3" # stop_spinner
local width=40 # printf "\r\e[2K%s %b\n" "$CM" "${GN}${msg}${CL}" >&2
local filled percent bar empty # if declare -p MSG_INFO_SHOWN &>/dev/null && [[ "$(declare -p MSG_INFO_SHOWN 2>/dev/null)" =~ "declare -A" ]]; then
local fill_char="#" # unset MSG_INFO_SHOWN["$msg"]
local empty_char="-" # fi
# }
if ! [[ "$current" =~ ^[0-9]+$ ]] || ! [[ "$total" =~ ^[0-9]+$ ]] || [[ "$total" -eq 0 ]]; then # msg_error() {
printf "\r\e[2K%s %b\n" "$CROSS" "${RD}Invalid progress input${CL}" >&2 # local msg="$1"
return # [[ -z "$msg" ]] && return
fi # stop_spinner
# printf "\r\e[2K%s %b\n" "$CROSS" "${RD}${msg}${CL}" >&2
# }
percent=$(((current * 100) / total)) # msg_warn() {
filled=$(((current * width) / total)) # local msg="$1"
empty=$((width - filled)) # [[ -z "$msg" ]] && return
# stop_spinner
# printf "\r\e[2K%s %b\n" "$INFO" "${YWB}${msg}${CL}" >&2
# if declare -p MSG_INFO_SHOWN &>/dev/null && [[ "$(declare -p MSG_INFO_SHOWN 2>/dev/null)" =~ "declare -A" ]]; then
# unset MSG_INFO_SHOWN["$msg"]
# fi
# }
bar=$(printf "%${filled}s" | tr ' ' "$fill_char") # msg_custom() {
bar+=$(printf "%${empty}s" | tr ' ' "$empty_char") # local symbol="${1:-"[*]"}"
# local color="${2:-"\e[36m"}" # Default: Cyan
# local msg="${3:-}"
printf "\r\e[2K%s [%s] %3d%% %s" "${TAB}" "$bar" "$percent" "$label" >&2 # [[ -z "$msg" ]] && return
# stop_spinner 2>/dev/null || true
# printf "\r\e[2K%s %b\n" "$symbol" "${color}${msg}${CL:-\e[0m}" >&2
# }
if [[ "$current" -eq "$total" ]]; then # msg_progress() {
printf "\n" >&2 # local current="$1"
fi # 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() { run_container_safe() {
local ct="$1" local ct="$1"
@ -555,3 +623,5 @@ check_or_create_swap() {
return 1 return 1
fi fi
} }
trap 'stop_spinner' EXIT INT TERM

View File

@ -27,7 +27,7 @@ trap on_terminate TERM
function on_exit() { function on_exit() {
local exit_code="$?" local exit_code="$?"
[[ -n "${lockfile:-}" ]] [[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile"
exit "$exit_code" exit "$exit_code"
} }
@ -50,18 +50,30 @@ function on_terminate() {
exit 143 exit 143
} }
function check_storage_support() {
local CONTENT="$1"
local -a VALID_STORAGES=()
while IFS= read -r line; do
local STORAGE=$(awk '{print $1}' <<<"$line")
[[ "$STORAGE" == "storage" || -z "$STORAGE" ]] && continue
VALID_STORAGES+=("$STORAGE")
done < <(pvesm status -content "$CONTENT" 2>/dev/null | awk 'NR>1')
[[ ${#VALID_STORAGES[@]} -gt 0 ]]
}
# This checks for the presence of valid Container Storage and Template Storage locations # This checks for the presence of valid Container Storage and Template Storage locations
msg_info "Validating Storage" msg_info "Validating Storage"
VALIDCT=$(pvesm status -content rootdir | awk 'NR>1') if ! check_storage_support "rootdir"; then
if [ -z "$VALIDCT" ]; then msg_error "No valid storage found for 'rootdir' (Container)."
msg_error "Unable to detect a valid Container Storage location."
exit 1 exit 1
fi fi
VALIDTMP=$(pvesm status -content vztmpl | awk 'NR>1') if ! check_storage_support "vztmpl"; then
if [ -z "$VALIDTMP" ]; then msg_error "No valid storage found for 'vztmpl' (Template)."
msg_error "Unable to detect a valid Template Storage location."
exit 1 exit 1
fi fi
msg_ok "Storage types rootdir and vztmpl are supported."
# This function is used to select the storage class and determine the corresponding storage content type and label. # This function is used to select the storage class and determine the corresponding storage content type and label.
function select_storage() { function select_storage() {
@ -107,12 +119,19 @@ function select_storage() {
} }
local -a MENU local -a MENU
while read -r line; do local -A STORAGE_MAP=()
local TAG=$(echo $line | awk '{print $1}') local COL_WIDTH=0
local TYPE=$(echo $line | awk '{printf "%-10s", $2}')
local FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}') while read -r TAG TYPE _ TOTAL USED FREE _; do
MENU+=("$TAG" "Type: $TYPE Free: $FREE " "OFF") [[ -n "$TAG" && -n "$TYPE" ]] || continue
done < <(pvesm status -content $CONTENT | awk 'NR>1') local DISPLAY="${TAG} (${TYPE})"
local USED_FMT=$(numfmt --to=iec --from-unit=K --format %.1f <<<"$USED")
local FREE_FMT=$(numfmt --to=iec --from-unit=K --format %.1f <<<"$FREE")
local INFO="Free: ${FREE_FMT}B Used: ${USED_FMT}B"
STORAGE_MAP["$DISPLAY"]="$TAG" # Map DISPLAY to actual TAG
MENU+=("$DISPLAY" "$INFO" "OFF")
((${#DISPLAY} > COL_WIDTH)) && COL_WIDTH=${#DISPLAY}
done < <(pvesm status -content "$CONTENT" | awk 'NR>1')
if [ ${#MENU[@]} -eq 0 ]; then if [ ${#MENU[@]} -eq 0 ]; then
msg_error "No storage found for content type '$CONTENT'." msg_error "No storage found for content type '$CONTENT'."
@ -120,18 +139,32 @@ function select_storage() {
fi fi
if [ $((${#MENU[@]} / 3)) -eq 1 ]; then if [ $((${#MENU[@]} / 3)) -eq 1 ]; then
printf "%s" "${MENU[0]}" echo "${STORAGE_MAP[${MENU[0]}]}"
return return
fi fi
local STORAGE local WIDTH=$((COL_WIDTH + 42))
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \ local DISPLAY_SELECTED=""
while true; do
DISPLAY_SELECTED=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool for ${CONTENT_LABEL,,}?\n(Spacebar to select)" \ "Which storage pool for ${CONTENT_LABEL,,}?\n(Spacebar to select)" \
16 70 6 "${MENU[@]}" 3>&1 1>&2 2>&3) || { 16 "$WIDTH" 6 "${MENU[@]}" 3>&1 1>&2 2>&3) || {
msg_error "Storage selection cancelled by user." msg_error "Storage selection cancelled by user."
exit 202 exit 202
} }
printf "%s" "$STORAGE"
# Validierung gegen STORAGE_MAP
if [[ -z "$DISPLAY_SELECTED" || -z "${STORAGE_MAP[$DISPLAY_SELECTED]+_}" ]]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Invalid Selection" \
--msgbox "No valid storage selected. Please choose a storage pool to continue." 9 60
continue
fi
break
done
echo "${STORAGE_MAP["$DISPLAY_SELECTED"]}"
} }
# Test if required variables are set # Test if required variables are set
@ -172,10 +205,29 @@ if [[ -f "$DEFAULT_FILE" ]]; then
msg_ok "Using ${BL}$CONTAINER_STORAGE${CL} ${GN}for Container Storage." msg_ok "Using ${BL}$CONTAINER_STORAGE${CL} ${GN}for Container Storage."
fi fi
else else
TEMPLATE_STORAGE=$(select_storage template) # TEMPLATE STORAGE SELECTION
# Template Storage
if ! TEMPLATE_STORAGE=$(select_storage template); then
[[ $? -eq 202 ]] && {
msg_error "Template Storage selection cancelled by user. Exiting."
kill -INT $$
}
msg_error "Unexpected error during template storage selection."
exit 1
fi
msg_ok "Using ${BL}$TEMPLATE_STORAGE${CL} ${GN}for Template Storage." msg_ok "Using ${BL}$TEMPLATE_STORAGE${CL} ${GN}for Template Storage."
CONTAINER_STORAGE=$(select_storage container)
# Container Storage
if ! CONTAINER_STORAGE=$(select_storage container); then
[[ $? -eq 202 ]] && {
msg_error "Container Storage selection cancelled by user. Exiting."
kill -INT $$
}
msg_error "Unexpected error during container storage selection."
exit 1
fi
msg_ok "Using ${BL}$CONTAINER_STORAGE${CL} ${GN}for Container Storage." msg_ok "Using ${BL}$CONTAINER_STORAGE${CL} ${GN}for Container Storage."
fi fi
# Check free space on selected container storage # Check free space on selected container storage

View File

@ -31,7 +31,7 @@ catch_errors() {
# This function handles errors # This function handles errors
error_handler() { error_handler() {
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/api.func)
printf "\e[?25h" printf "\e[?25h"
local exit_code="$?" local exit_code="$?"
local line_number="$1" local line_number="$1"
@ -65,7 +65,8 @@ setting_up_container() {
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
systemctl disable -q --now systemd-networkd-wait-online.service systemctl disable -q --now systemd-networkd-wait-online.service
msg_ok "Set up Container OS" msg_ok "Set up Container OS"
msg_custom "${CM}" "${GN}" "Network Connected: ${BL}$(hostname -I)" #msg_custom "${CM}" "${GN}" "Network Connected: ${BL}$(hostname -I)"
msg_ok "Network Connected: ${BL}$(hostname -I)"
} }
# This function checks the network connection by pinging a known IP address and prompts the user to continue if the internet is not connected # This function checks the network connection by pinging a known IP address and prompts the user to continue if the internet is not connected
@ -104,24 +105,24 @@ network_check() {
fi fi
# DNS resolution checks for GitHub-related domains (IPv4 and/or IPv6) # DNS resolution checks for GitHub-related domains (IPv4 and/or IPv6)
GITHUB_HOSTS=("github.com" "raw.githubusercontent.com" "api.github.com" "git.community-scripts.org") GIT_HOSTS=("github.com" "raw.githubusercontent.com" "api.github.com" "git.community-scripts.org")
GITHUB_STATUS="GitHub DNS:" GIT_STATUS="Git DNS:"
DNS_FAILED=false DNS_FAILED=false
for HOST in "${GITHUB_HOSTS[@]}"; do for HOST in "${GIT_HOSTS[@]}"; do
RESOLVEDIP=$(getent hosts "$HOST" | awk '{ print $1 }' | grep -E '(^([0-9]{1,3}\.){3}[0-9]{1,3}$)|(^[a-fA-F0-9:]+$)' | head -n1) RESOLVEDIP=$(getent hosts "$HOST" | awk '{ print $1 }' | grep -E '(^([0-9]{1,3}\.){3}[0-9]{1,3}$)|(^[a-fA-F0-9:]+$)' | head -n1)
if [[ -z "$RESOLVEDIP" ]]; then if [[ -z "$RESOLVEDIP" ]]; then
GITHUB_STATUS+="$HOST:($DNSFAIL)" GIT_STATUS+="$HOST:($DNSFAIL)"
DNS_FAILED=true DNS_FAILED=true
else else
GITHUB_STATUS+=" $HOST:($DNSOK)" GIT_STATUS+=" $HOST:($DNSOK)"
fi fi
done done
if [[ "$DNS_FAILED" == true ]]; then if [[ "$DNS_FAILED" == true ]]; then
fatal "$GITHUB_STATUS" fatal "$GIT_STATUS"
else else
msg_ok "$GITHUB_STATUS" msg_ok "$GIT_STATUS"
fi fi
set -e set -e

View File

@ -238,7 +238,6 @@ setup_mariadb() {
msg_info "Setting up MariaDB $MARIADB_VERSION" msg_info "Setting up MariaDB $MARIADB_VERSION"
# grab dynamic latest LTS version # grab dynamic latest LTS version
if [[ "$MARIADB_VERSION" == "latest" ]]; then if [[ "$MARIADB_VERSION" == "latest" ]]; then
$STD msg_info "Resolving latest GA MariaDB version"
MARIADB_VERSION=$(curl -fsSL http://mirror.mariadb.org/repo/ | MARIADB_VERSION=$(curl -fsSL http://mirror.mariadb.org/repo/ |
grep -Eo '[0-9]+\.[0-9]+\.[0-9]+/' | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+/' |
grep -vE 'rc/|rolling/' | grep -vE 'rc/|rolling/' |
@ -249,7 +248,6 @@ setup_mariadb() {
msg_error "Could not determine latest GA MariaDB version" msg_error "Could not determine latest GA MariaDB version"
return 1 return 1
fi fi
$STD msg_ok "Latest GA MariaDB version is $MARIADB_VERSION"
fi fi
local CURRENT_VERSION="" local CURRENT_VERSION=""
@ -274,7 +272,6 @@ setup_mariadb() {
$STD msg_info "Setup MariaDB $MARIADB_VERSION" $STD msg_info "Setup MariaDB $MARIADB_VERSION"
fi fi
$STD msg_info "Setting up MariaDB Repository"
curl -fsSL "https://mariadb.org/mariadb_release_signing_key.asc" | curl -fsSL "https://mariadb.org/mariadb_release_signing_key.asc" |
gpg --dearmor -o /etc/apt/trusted.gpg.d/mariadb.gpg gpg --dearmor -o /etc/apt/trusted.gpg.d/mariadb.gpg
@ -824,19 +821,30 @@ function fetch_and_deploy_gh_release() {
elif [[ "$mode" == "binary" ]]; then elif [[ "$mode" == "binary" ]]; then
local arch local arch
arch=$(dpkg --print-architecture 2>/dev/null || uname -m) arch=$(dpkg --print-architecture 2>/dev/null || uname -m)
[[ "$arch" == "x86_64" ]] && arch="x86_64" [[ "$arch" == "x86_64" ]] && arch="amd64"
[[ "$arch" == "aarch64" ]] && arch="arm64" [[ "$arch" == "aarch64" ]] && arch="arm64"
local assets url_match="" local assets url_match=""
assets=$(echo "$json" | jq -r '.assets[].browser_download_url') assets=$(echo "$json" | jq -r '.assets[].browser_download_url')
# If explicit filename pattern is provided (param $6), match that first
if [[ -n "$6" ]]; then
for u in $assets; do
[[ "$u" =~ $6 || "$u" == *"$6" ]] && url_match="$u" && break
done
fi
# If no match via explicit pattern, fall back to architecture heuristic
if [[ -z "$url_match" ]]; then
for u in $assets; do for u in $assets; do
if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then
url_match="$u" url_match="$u"
break break
fi fi
done done
fi
# Fallback: any .deb file
if [[ -z "$url_match" ]]; then if [[ -z "$url_match" ]]; then
for u in $assets; do for u in $assets; do
[[ "$u" =~ \.deb$ ]] && url_match="$u" && break [[ "$u" =~ \.deb$ ]] && url_match="$u" && break
@ -1611,3 +1619,142 @@ function setup_imagemagick() {
ensure_usr_local_bin_persist ensure_usr_local_bin_persist
msg_ok "Setup ImageMagick $VERSION" msg_ok "Setup ImageMagick $VERSION"
} }
# ------------------------------------------------------------------------------
# Installs FFmpeg from source or prebuilt binary (Debian/Ubuntu only).
#
# Description:
# - Downloads and builds FFmpeg from GitHub (https://github.com/FFmpeg/FFmpeg)
# - Supports specific version override via FFMPEG_VERSION (e.g. n7.1.1)
# - Supports build profile via FFMPEG_TYPE:
# - minimal : x264, vpx, mp3 only
# - medium : adds subtitles, fonts, opus, vorbis
# - full : adds dav1d, svt-av1, zlib, numa
# - binary : downloads static build (johnvansickle.com)
# - Defaults to latest stable version and full feature set
#
# Notes:
# - Requires: curl, jq, build-essential, and matching codec libraries
# - Result is installed to /usr/local/bin/ffmpeg
# ------------------------------------------------------------------------------
function setup_ffmpeg() {
local TMP_DIR
TMP_DIR=$(mktemp -d)
local GITHUB_REPO="FFmpeg/FFmpeg"
local VERSION="${FFMPEG_VERSION:-}"
local TYPE="${FFMPEG_TYPE:-full}"
local BIN_PATH="/usr/local/bin/ffmpeg"
# Binary fallback mode
if [[ "$TYPE" == "binary" ]]; then
msg_info "Installing FFmpeg (static binary)"
curl -fsSL https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz -o "$TMP_DIR/ffmpeg.tar.xz"
tar -xf "$TMP_DIR/ffmpeg.tar.xz" -C "$TMP_DIR"
local EXTRACTED_DIR
EXTRACTED_DIR=$(find "$TMP_DIR" -maxdepth 1 -type d -name "ffmpeg-*")
cp "$EXTRACTED_DIR/ffmpeg" "$BIN_PATH"
cp "$EXTRACTED_DIR/ffprobe" /usr/local/bin/ffprobe
chmod +x "$BIN_PATH" /usr/local/bin/ffprobe
rm -rf "$TMP_DIR"
msg_ok "Installed FFmpeg binary ($($BIN_PATH -version | head -n1))"
return
fi
# Auto-detect latest stable version if none specified
if [[ -z "$VERSION" ]]; then
msg_info "Fetching latest stable FFmpeg tag"
VERSION=$(curl -fsSL "https://api.github.com/repos/${GITHUB_REPO}/tags" |
jq -r '.[].name' |
grep -E '^n[0-9]+\.[0-9]+\.[0-9]+$' | # stable only
sort -V | tail -n1)
fi
if [[ -z "$VERSION" ]]; then
msg_error "Could not determine FFmpeg version"
rm -rf "$TMP_DIR"
return 1
fi
msg_info "Installing FFmpeg ${VERSION} ($TYPE)"
# Dependency selection
local DEPS=(build-essential yasm nasm pkg-config)
case "$TYPE" in
minimal)
DEPS+=(libx264-dev libvpx-dev libmp3lame-dev)
;;
medium)
DEPS+=(libx264-dev libvpx-dev libmp3lame-dev libfreetype6-dev libass-dev libopus-dev libvorbis-dev)
;;
full)
DEPS+=(
libx264-dev libx265-dev libvpx-dev libmp3lame-dev
libfreetype6-dev libass-dev libopus-dev libvorbis-dev
libdav1d-dev libsvtav1-dev zlib1g-dev libnuma-dev
)
;;
*)
msg_error "Invalid FFMPEG_TYPE: $TYPE"
rm -rf "$TMP_DIR"
return 1
;;
esac
$STD apt-get update
$STD apt-get install -y "${DEPS[@]}"
curl -fsSL "https://github.com/${GITHUB_REPO}/archive/refs/tags/${VERSION}.tar.gz" -o "$TMP_DIR/ffmpeg.tar.gz"
tar -xzf "$TMP_DIR/ffmpeg.tar.gz" -C "$TMP_DIR"
cd "$TMP_DIR/FFmpeg-"* || {
msg_error "Source extraction failed"
rm -rf "$TMP_DIR"
return 1
}
local args=(
--enable-gpl
--enable-shared
--enable-nonfree
--disable-static
--enable-libx264
--enable-libvpx
--enable-libmp3lame
)
if [[ "$TYPE" != "minimal" ]]; then
args+=(--enable-libfreetype --enable-libass --enable-libopus --enable-libvorbis)
fi
if [[ "$TYPE" == "full" ]]; then
args+=(--enable-libx265 --enable-libdav1d --enable-zlib)
fi
if [[ ${#args[@]} -eq 0 ]]; then
msg_error "FFmpeg configure args array is empty aborting."
rm -rf "$TMP_DIR"
return 1
fi
./configure "${args[@]}" >"$TMP_DIR/configure.log" 2>&1 || {
msg_error "FFmpeg ./configure failed (see $TMP_DIR/configure.log)"
cat "$TMP_DIR/configure.log" | tail -n 20
rm -rf "$TMP_DIR"
return 1
}
$STD make -j"$(nproc)"
$STD make install
if ! command -v ffmpeg &>/dev/null; then
msg_error "FFmpeg installation failed"
rm -rf "$TMP_DIR"
return 1
fi
local FINAL_VERSION
FINAL_VERSION=$(ffmpeg -version | head -n1 | awk '{print $3}')
rm -rf "$TMP_DIR"
ensure_usr_local_bin_persist
msg_ok "Setup FFmpeg $FINAL_VERSION"
}

View File

@ -40,53 +40,72 @@ CM="${TAB}✔️${TAB}${CL}"
header_info header_info
echo "Loading..." echo "Loading..."
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Deletion" --yesno "This will delete LXC containers. Proceed?" 10 58 if ! whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Deletion" --yesno "This will delete LXC containers. Proceed?" 10 58; then
echo -e "${RD}Aborted by user.${CL}"
exit 0
fi
NODE=$(hostname) mapfile -t containers < <(pct list | tail -n +2)
containers=$(pct list | tail -n +2 | awk '{print $0 " " $4}')
if [ -z "$containers" ]; then if [ ${#containers[@]} -eq 0 ]; then
whiptail --title "LXC Container Delete" --msgbox "No LXC containers available!" 10 60 whiptail --title "LXC Container Delete" --msgbox "No LXC containers available!" 10 60
exit 1 exit 1
fi fi
menu_items=("ALL" "Delete ALL containers" "OFF") # Add as first option menu_items=("ALL" "Delete ALL containers" "OFF")
FORMAT="%-10s %-15s %-10s" FORMAT="%-10s %-10s %-10s %-10s"
while read -r container; do for line in "${containers[@]}"; do
container_id=$(echo $container | awk '{print $1}') container_id=$(echo "$line" | awk '{print $1}')
container_name=$(echo $container | awk '{print $2}') container_name=$(echo "$line" | awk '{print $2}')
container_status=$(echo $container | awk '{print $3}') container_status=$(echo "$line" | awk '{print $3}')
formatted_line=$(printf "$FORMAT" "$container_name" "$container_status") container_os=$(echo "$line" | awk '{print $4}')
protected=$(pct config "$container_id" | awk '/^protection:/ {print $2}')
is_protected="No"
[[ "$protected" == "1" ]] && is_protected="Yes"
formatted_line=$(printf "$FORMAT" "$container_name" "$container_status" "$container_os" "$is_protected")
menu_items+=("$container_id" "$formatted_line" "OFF") menu_items+=("$container_id" "$formatted_line" "OFF")
done <<<"$containers" done
CHOICES=$(whiptail --title "LXC Container Delete" \ CHOICES=$(whiptail --title "LXC Container Delete" \
--checklist "Select LXC containers to delete:" 25 60 13 \ --checklist "Select LXC containers to delete:\n\nNAME STATUS OS PROTECTED" 25 70 15 \
"${menu_items[@]}" 3>&2 2>&1 1>&3) "${menu_items[@]}" 3>&2 2>&1 1>&3)
if [ -z "$CHOICES" ]; then if [ -z "$CHOICES" ]; then
whiptail --title "LXC Container Delete" \ whiptail --title "LXC Container Delete" --msgbox "No containers selected!" 10 60
--msgbox "No containers selected!" 10 60
exit 1 exit 1
fi fi
read -p "Delete containers manually or automatically? (Default: manual) m/a: " DELETE_MODE read -p "Delete containers manually or automatically? (Default: manual) m/a: " DELETE_MODE
DELETE_MODE=${DELETE_MODE:-m} DELETE_MODE=${DELETE_MODE:-m}
selected_ids=$(echo "$CHOICES" | tr -d '"' | tr -s ' ' '\n') selected_ids=$(echo "$CHOICES" | tr -d '"' | tr -s ' ' '\n')
# If "ALL" is selected, override with all container IDs # ALL ausgewählt
if echo "$selected_ids" | grep -q "^ALL$"; then if echo "$selected_ids" | grep -q "^ALL$"; then
selected_ids=$(echo "$containers" | awk '{print $1}') selected_ids=$(printf '%s\n' "${containers[@]}" | awk '{print $1}')
fi fi
for container_id in $selected_ids; do for container_id in $selected_ids; do
status=$(pct status $container_id) status=$(pct status "$container_id")
protected=$(pct config "$container_id" | awk '/^protection:/ {print $2}')
is_protected="No"
[[ "$protected" == "1" ]] && is_protected="Yes"
if [ "$status" == "status: running" ]; then if [[ "$is_protected" == "Yes" && "$DELETE_MODE" == "a" ]]; then
echo -e "${BL}[Info]${RD} Skipping protected container $container_id (auto mode).${CL}"
continue
fi
if [[ "$status" == "status: running" ]]; then
if [[ "$is_protected" == "Yes" && "$DELETE_MODE" == "m" ]]; then
read -p "⚠️ Container $container_id is PROTECTED. Delete anyway? (y/N): " CONFIRM_PROTECTED
[[ ! "$CONFIRM_PROTECTED" =~ ^[Yy]$ ]] && {
echo -e "${BL}[Info]${RD} Skipping protected container $container_id...${CL}"
continue
}
fi
echo -e "${BL}[Info]${GN} Stopping container $container_id...${CL}" echo -e "${BL}[Info]${GN} Stopping container $container_id...${CL}"
pct stop $container_id & pct stop "$container_id" &
sleep 5 sleep 5
echo -e "${BL}[Info]${GN} Container $container_id stopped.${CL}" echo -e "${BL}[Info]${GN} Container $container_id stopped.${CL}"
fi fi
@ -96,15 +115,30 @@ for container_id in $selected_ids; do
pct destroy "$container_id" -f & pct destroy "$container_id" -f &
pid=$! pid=$!
spinner $pid spinner $pid
[ $? -eq 0 ] && echo "Container $container_id deleted." || whiptail --title "Error" --msgbox "Failed to delete container $container_id." 10 60 if [ $? -eq 0 ]; then
echo "Container $container_id deleted."
else
whiptail --title "Error" --msgbox "Failed to delete container $container_id." 10 60
fi
else else
read -p "Delete container $container_id? (y/N): " CONFIRM read -p "Delete container $container_id? (y/N): " CONFIRM
if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
if [[ "$is_protected" == "Yes" ]]; then
read -p "⚠️ Container $container_id is PROTECTED. Delete anyway? (y/N): " CONFIRM_PROTECTED
[[ ! "$CONFIRM_PROTECTED" =~ ^[Yy]$ ]] && {
echo -e "${BL}[Info]${RD} Skipping protected container $container_id...${CL}"
continue
}
fi
echo -e "${BL}[Info]${GN} Deleting container $container_id...${CL}" echo -e "${BL}[Info]${GN} Deleting container $container_id...${CL}"
pct destroy "$container_id" -f & pct destroy "$container_id" -f &
pid=$! pid=$!
spinner $pid spinner $pid
[ $? -eq 0 ] && echo "Container $container_id deleted." || whiptail --title "Error" --msgbox "Failed to delete container $container_id." 10 60 if [ $? -eq 0 ]; then
echo "Container $container_id deleted."
else
whiptail --title "Error" --msgbox "Failed to delete container $container_id." 10 60
fi
else else
echo -e "${BL}[Info]${RD} Skipping container $container_id...${CL}" echo -e "${BL}[Info]${RD} Skipping container $container_id...${CL}"
fi fi