Merge branch 'main' into dramikei/ente-enhancement
This commit is contained in:
commit
06c6536699
@ -1,6 +1,6 @@
|
|||||||
module proxmox-api
|
module proxmox-api
|
||||||
|
|
||||||
go 1.23.2
|
go 1.24.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gorilla/mux v1.8.1
|
github.com/gorilla/mux v1.8.1
|
||||||
@ -17,7 +17,7 @@ require (
|
|||||||
github.com/xdg-go/scram v1.1.2 // indirect
|
github.com/xdg-go/scram v1.1.2 // indirect
|
||||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
golang.org/x/crypto v0.35.0 // indirect
|
golang.org/x/crypto v0.45.0 // indirect
|
||||||
golang.org/x/sync v0.11.0 // indirect
|
golang.org/x/sync v0.18.0 // indirect
|
||||||
golang.org/x/text v0.22.0 // indirect
|
golang.org/x/text v0.31.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
12
api/go.sum
12
api/go.sum
@ -27,16 +27,16 @@ go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793Sqyh
|
|||||||
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -48,8 +48,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
|||||||
@ -7,9 +7,9 @@ source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxV
|
|||||||
|
|
||||||
APP="Alpine"
|
APP="Alpine"
|
||||||
var_tags="${var_tags:-os;alpine}"
|
var_tags="${var_tags:-os;alpine}"
|
||||||
var_cpu="${var_cpu:-1}"
|
var_cpu="${var_cpu:-4}"
|
||||||
var_ram="${var_ram:-512}"
|
var_ram="${var_ram:-4096}"
|
||||||
var_disk="${var_disk:-1}"
|
var_disk="${var_disk:-5}"
|
||||||
var_os="${var_os:-alpine}"
|
var_os="${var_os:-alpine}"
|
||||||
var_version="${var_version:-3.22}"
|
var_version="${var_version:-3.22}"
|
||||||
var_unprivileged="${var_unprivileged:-1}"
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|||||||
@ -1,81 +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/BookStackApp/BookStack
|
|
||||||
|
|
||||||
APP="Bookstack"
|
|
||||||
var_tags="${var_tags:-organizer}"
|
|
||||||
var_cpu="${var_cpu:-1}"
|
|
||||||
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/bookstack ]]; then
|
|
||||||
msg_error "No ${APP} Installation Found!"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
if check_for_gh_release "bookstack" "BookStackApp/BookStack"; then
|
|
||||||
msg_info "Stopping Apache2"
|
|
||||||
systemctl stop apache2
|
|
||||||
msg_ok "Services Stopped"
|
|
||||||
|
|
||||||
msg_info "Backing up data"
|
|
||||||
mv /opt/bookstack /opt/bookstack-backup
|
|
||||||
msg_ok "Backup finished"
|
|
||||||
|
|
||||||
setup_mariadb
|
|
||||||
fetch_and_deploy_gh_release "bookstack" "BookStackApp/BookStack"
|
|
||||||
PHP_MODULE="ldap,tidy,bz2,mysqli" PHP_FPM="YES" PHP_APACHE="YES" PHP_VERSION="8.3" setup_php
|
|
||||||
setup_composer
|
|
||||||
|
|
||||||
msg_info "Restoring backup"
|
|
||||||
cp /opt/bookstack-backup/.env /opt/bookstack/.env
|
|
||||||
[[ -d /opt/bookstack-backup/public/uploads ]] && cp -a /opt/bookstack-backup/public/uploads/. /opt/bookstack/public/uploads/
|
|
||||||
[[ -d /opt/bookstack-backup/storage/uploads ]] && cp -a /opt/bookstack-backup/storage/uploads/. /opt/bookstack/storage/uploads/
|
|
||||||
[[ -d /opt/bookstack-backup/themes ]] && cp -a /opt/bookstack-backup/themes/. /opt/bookstack/themes/
|
|
||||||
msg_ok "Backup restored"
|
|
||||||
|
|
||||||
msg_info "Configuring BookStack"
|
|
||||||
cd /opt/bookstack
|
|
||||||
export COMPOSER_ALLOW_SUPERUSER=1
|
|
||||||
$STD composer install --no-dev
|
|
||||||
$STD php artisan migrate --force
|
|
||||||
chown www-data:www-data -R /opt/bookstack /opt/bookstack/bootstrap/cache /opt/bookstack/public/uploads /opt/bookstack/storage
|
|
||||||
chmod -R 755 /opt/bookstack /opt/bookstack/bootstrap/cache /opt/bookstack/public/uploads /opt/bookstack/storage
|
|
||||||
chmod -R 775 /opt/bookstack/storage /opt/bookstack/bootstrap/cache /opt/bookstack/public/uploads
|
|
||||||
chmod -R 640 /opt/bookstack/.env
|
|
||||||
msg_ok "Configured BookStack"
|
|
||||||
|
|
||||||
msg_info "Starting Apache2"
|
|
||||||
systemctl start apache2
|
|
||||||
msg_ok "Started Apache2"
|
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /opt/bookstack-backup
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated Successfully"
|
|
||||||
fi
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
start
|
|
||||||
build_container
|
|
||||||
description
|
|
||||||
|
|
||||||
msg_ok "Completed Successfully!\n"
|
|
||||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
|
||||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
|
||||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
|
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
|
||||||
# Author: jdacode
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://github.com/comfyanonymous/ComfyUI
|
|
||||||
|
|
||||||
APP="ComfyUI"
|
|
||||||
var_tags="${var_tags:-ai}"
|
|
||||||
var_cpu="${var_cpu:-4}"
|
|
||||||
var_ram="${var_ram:-8192}"
|
|
||||||
var_disk="${var_disk:-25}"
|
|
||||||
var_os="${var_os:-debian}"
|
|
||||||
var_version="${var_version:-13}"
|
|
||||||
var_unprivileged="${var_unprivileged:-1}"
|
|
||||||
|
|
||||||
header_info "$APP"
|
|
||||||
variables
|
|
||||||
color
|
|
||||||
catch_errors
|
|
||||||
|
|
||||||
function update_script() {
|
|
||||||
header_info
|
|
||||||
check_container_storage
|
|
||||||
check_container_resources
|
|
||||||
|
|
||||||
if [[ ! -f /opt/${APP} ]]; then
|
|
||||||
msg_error "No ${APP} Installation Found!"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
msg_error "To update use the ${APP} Manager."
|
|
||||||
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}:8188${CL}"
|
|
||||||
11
ct/debian.sh
11
ct/debian.sh
@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
|
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
|
||||||
# Copyright (c) 2021-2025 tteck
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
# Author: tteck (tteckster)
|
# Author: MickLesk (CanbiZ)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||||
# Source: https://www.debian.org/
|
# Source:
|
||||||
|
|
||||||
APP="Debian"
|
APP="Debian"
|
||||||
var_tags="${var_tags:-}"
|
var_tags="${var_tags:-}"
|
||||||
@ -30,9 +30,10 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
msg_info "Updating $APP LXC"
|
msg_info "Updating $APP LXC"
|
||||||
$STD apt-get update
|
$STD apt update
|
||||||
$STD apt-get -y upgrade
|
$STD apt upgrade -y
|
||||||
msg_ok "Updated $APP LXC"
|
msg_ok "Updated $APP LXC"
|
||||||
|
cleanup_lxc
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,118 +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: ekke85
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://github.com/Dispatcharr/Dispatcharr
|
|
||||||
|
|
||||||
APP="Dispatcharr"
|
|
||||||
APP_NAME=${APP,,}
|
|
||||||
var_tags="${var_tags:-media;arr}"
|
|
||||||
var_cpu="${var_cpu:-1}"
|
|
||||||
var_ram="${var_ram:-2048}"
|
|
||||||
var_disk="${var_disk:-8}"
|
|
||||||
var_os="${var_os:-debian}"
|
|
||||||
var_version="${var_version:-13}"
|
|
||||||
var_unprivileged="${var_unprivileged:-1}"
|
|
||||||
|
|
||||||
header_info "$APP"
|
|
||||||
variables
|
|
||||||
color
|
|
||||||
catch_errors
|
|
||||||
|
|
||||||
function update_script() {
|
|
||||||
header_info
|
|
||||||
check_container_storage
|
|
||||||
check_container_resources
|
|
||||||
|
|
||||||
if [[ ! -d "/opt/dispatcharr" ]]; then
|
|
||||||
msg_error "No ${APP} Installation Found!"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
RELEASE=$(curl -fsSL https://api.github.com/repos/Dispatcharr/Dispatcharr/releases/latest | jq -r '.tag_name' | sed 's/^v//')
|
|
||||||
if [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]] || [[ ! -f /opt/${APP}_version.txt ]]; then
|
|
||||||
msg_ok "Starting update"
|
|
||||||
APP_DIR="/opt/dispatcharr"
|
|
||||||
APP_USER="dispatcharr"
|
|
||||||
APP_GROUP="dispatcharr"
|
|
||||||
|
|
||||||
msg_info "Stopping $APP"
|
|
||||||
systemctl stop dispatcharr-celery
|
|
||||||
systemctl stop dispatcharr-celerybeat
|
|
||||||
systemctl stop dispatcharr-daphne
|
|
||||||
systemctl stop dispatcharr
|
|
||||||
msg_ok "Stopped $APP"
|
|
||||||
|
|
||||||
msg_info "Creating Backup"
|
|
||||||
BACKUP_FILE="/opt/dispatcharr_$(date +%F).tar.gz"
|
|
||||||
msg_info "Source and Database backup"
|
|
||||||
set -o allexport
|
|
||||||
source /etc/$APP_NAME/$APP_NAME.env
|
|
||||||
set +o allexport
|
|
||||||
PGPASSWORD=$POSTGRES_PASSWORD pg_dump -U $POSTGRES_USER -h $POSTGRES_HOST $POSTGRES_DB >/opt/$POSTGRES_DB-$(date +%F).sql
|
|
||||||
$STD tar -czf "$BACKUP_FILE" /opt/dispatcharr /opt/Dispatcharr_version.txt /opt/$POSTGRES_DB-$(date +%F).sql &>/dev/null
|
|
||||||
msg_ok "Backup Created"
|
|
||||||
|
|
||||||
msg_info "Updating $APP to v${RELEASE}"
|
|
||||||
rm -rf /opt/dispatcharr
|
|
||||||
fetch_and_deploy_gh_release "dispatcharr" "Dispatcharr/Dispatcharr"
|
|
||||||
chown -R "$APP_USER:$APP_GROUP" "$APP_DIR"
|
|
||||||
sed -i 's/program\[\x27channel_id\x27\]/program["channel_id"]/g' "${APP_DIR}/apps/output/views.py"
|
|
||||||
|
|
||||||
msg_ok "Dispatcharr Updated to $RELEASE"
|
|
||||||
|
|
||||||
msg_info "Creating Python Virtual Environment"
|
|
||||||
cd $APP_DIR
|
|
||||||
python3 -m venv env
|
|
||||||
source env/bin/activate
|
|
||||||
$STD pip install --upgrade pip
|
|
||||||
$STD pip install -r requirements.txt
|
|
||||||
$STD pip install gunicorn
|
|
||||||
ln -sf /usr/bin/ffmpeg $APP_DIR/env/bin/ffmpeg
|
|
||||||
msg_ok "Python Environment Setup"
|
|
||||||
|
|
||||||
msg_info "Building Frontend"
|
|
||||||
cd $APP_DIR/frontend
|
|
||||||
$STD npm install --legacy-peer-deps
|
|
||||||
$STD npm run build
|
|
||||||
msg_ok "Built Frontend"
|
|
||||||
|
|
||||||
msg_info "Running Django Migrations"
|
|
||||||
cd $APP_DIR
|
|
||||||
source env/bin/activate
|
|
||||||
set -o allexport
|
|
||||||
source /etc/$APP_NAME/$APP_NAME.env
|
|
||||||
set +o allexport
|
|
||||||
$STD python manage.py migrate --noinput
|
|
||||||
$STD python manage.py collectstatic --noinput
|
|
||||||
msg_ok "Migrations Complete"
|
|
||||||
|
|
||||||
msg_info "Starting $APP"
|
|
||||||
systemctl start dispatcharr-celery
|
|
||||||
systemctl start dispatcharr-celerybeat
|
|
||||||
systemctl start dispatcharr-daphne
|
|
||||||
systemctl start dispatcharr
|
|
||||||
msg_ok "Started $APP"
|
|
||||||
echo "${RELEASE}" >"/opt/${APP}_version.txt"
|
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /opt/$POSTGRES_DB-$(date +%F).sql
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
|
|
||||||
msg_ok "Update Successful, Backup saved to $BACKUP_FILE"
|
|
||||||
|
|
||||||
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}${CL}"
|
|
||||||
95
ct/docker.sh
Normal file
95
ct/docker.sh
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#!/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.docker.com/
|
||||||
|
|
||||||
|
APP="Docker"
|
||||||
|
var_tags="${var_tags:-docker}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-2048}"
|
||||||
|
var_disk="${var_disk:-4}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
|
||||||
|
get_latest_release() {
|
||||||
|
curl -fsSL https://api.github.com/repos/"$1"/releases/latest | grep '"tag_name":' | cut -d'"' -f4
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_info "Updating base system"
|
||||||
|
$STD apt update
|
||||||
|
$STD apt -y upgrade
|
||||||
|
msg_ok "Base system updated"
|
||||||
|
|
||||||
|
msg_info "Updating Docker Engine"
|
||||||
|
$STD apt install --only-upgrade -y docker-ce docker-ce-cli containerd.io
|
||||||
|
msg_ok "Docker Engine updated"
|
||||||
|
|
||||||
|
if [[ -f /usr/local/lib/docker/cli-plugins/docker-compose ]]; then
|
||||||
|
COMPOSE_BIN="/usr/local/lib/docker/cli-plugins/docker-compose"
|
||||||
|
COMPOSE_NEW_VERSION=$(get_latest_release "docker/compose")
|
||||||
|
msg_info "Updating Docker Compose to $COMPOSE_NEW_VERSION"
|
||||||
|
curl -fsSL "https://github.com/docker/compose/releases/download/${COMPOSE_NEW_VERSION}/docker-compose-$(uname -s)-$(uname -m)" \
|
||||||
|
-o "$COMPOSE_BIN"
|
||||||
|
chmod +x "$COMPOSE_BIN"
|
||||||
|
msg_ok "Docker Compose updated"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if docker ps -a --format '{{.Names}}' | grep -q '^portainer$'; then
|
||||||
|
msg_info "Updating Portainer"
|
||||||
|
$STD docker pull portainer/portainer-ce:latest
|
||||||
|
$STD docker stop portainer && docker rm portainer
|
||||||
|
$STD docker volume create portainer_data >/dev/null 2>&1
|
||||||
|
$STD docker run -d \
|
||||||
|
-p 8000:8000 \
|
||||||
|
-p 9443:9443 \
|
||||||
|
--name=portainer \
|
||||||
|
--restart=always \
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
-v portainer_data:/data \
|
||||||
|
portainer/portainer-ce:latest
|
||||||
|
msg_ok "Updated Portainer"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if docker ps -a --format '{{.Names}}' | grep -q '^portainer_agent$'; then
|
||||||
|
msg_info "Updating Portainer Agent"
|
||||||
|
$STD docker pull portainer/agent:latest
|
||||||
|
$STD docker stop portainer_agent && docker rm portainer_agent
|
||||||
|
$STD docker run -d \
|
||||||
|
-p 9001:9001 \
|
||||||
|
--name=portainer_agent \
|
||||||
|
--restart=always \
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
-v /var/lib/docker/volumes:/var/lib/docker/volumes \
|
||||||
|
portainer/agent
|
||||||
|
msg_ok "Updated Portainer Agent"
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Cleaning up"
|
||||||
|
$STD apt-get -y autoremove
|
||||||
|
$STD apt-get -y autoclean
|
||||||
|
msg_ok "Cleanup complete"
|
||||||
|
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} If you installed Portainer, access it at the following URL:${CL}"
|
||||||
|
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:9443${CL}"
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
source <(curl -s https://raw.githubusercontent.com/vsc55/community-scripts-ProxmoxVED/refs/heads/freepbx/misc/build.func)
|
source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVED/refs/heads/freepbx/misc/build.func)
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
# Author: Arian Nasr (arian-nasr)
|
# Author: Arian Nasr (arian-nasr)
|
||||||
# Updated by: Javier Pastor (vsc55)
|
# Updated by: Javier Pastor (vsc55)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
# Author: CrazyWolf13
|
# Author: CrazyWolf13
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
@ -13,7 +13,6 @@ var_disk="${var_disk:-6}"
|
|||||||
var_os="${var_os:-debian}"
|
var_os="${var_os:-debian}"
|
||||||
var_version="${var_version:-12}"
|
var_version="${var_version:-12}"
|
||||||
var_unprivileged="${var_unprivileged:-1}"
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
var_app_version="${var_app_version:-latest}"
|
|
||||||
|
|
||||||
header_info "$APP"
|
header_info "$APP"
|
||||||
|
|
||||||
@ -78,7 +77,7 @@ WantedBy=multi-user.target
|
|||||||
EOF
|
EOF
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
msg_ok "Old Enviroment fixed"
|
msg_ok "Old Enviroment fixed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if check_for_gh_release "gitea-mirror" "RayLabsHQ/gitea-mirror"; then
|
if check_for_gh_release "gitea-mirror" "RayLabsHQ/gitea-mirror"; then
|
||||||
msg_info "Stopping Services"
|
msg_info "Stopping Services"
|
||||||
@ -90,15 +89,10 @@ fi
|
|||||||
cp /opt/gitea-mirror/data/* /opt/gitea-mirror-backup/data/
|
cp /opt/gitea-mirror/data/* /opt/gitea-mirror-backup/data/
|
||||||
msg_ok "Backup Data"
|
msg_ok "Backup Data"
|
||||||
|
|
||||||
msg_info "Installing Bun"
|
NODE_VERSION="22" NODE_MODULES="bun" setup_nodejs
|
||||||
export BUN_INSTALL=/opt/bun
|
|
||||||
curl -fsSL https://bun.sh/install | $STD bash
|
|
||||||
ln -sf /opt/bun/bin/bun /usr/local/bin/bun
|
|
||||||
ln -sf /opt/bun/bin/bun /usr/local/bin/bunx
|
|
||||||
msg_ok "Installed Bun"
|
|
||||||
|
|
||||||
rm -rf /opt/gitea-mirror
|
rm -rf /opt/gitea-mirror
|
||||||
fetch_and_deploy_gh_release "gitea-mirror" "RayLabsHQ/gitea-mirror" "tarball" $var_app_version
|
fetch_and_deploy_gh_release "gitea-mirror" "RayLabsHQ/gitea-mirror"
|
||||||
|
|
||||||
msg_info "Updating and rebuilding ${APP}"
|
msg_info "Updating and rebuilding ${APP}"
|
||||||
cd /opt/gitea-mirror
|
cd /opt/gitea-mirror
|
||||||
@ -116,7 +110,7 @@ fi
|
|||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start gitea-mirror
|
systemctl start gitea-mirror
|
||||||
msg_ok "Service Started"
|
msg_ok "Service Started"
|
||||||
msg_ok "Update Successfully"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|||||||
44
ct/hanko.sh
44
ct/hanko.sh
@ -1,44 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
|
|
||||||
# Copyright (c) 2021-2025 tteck
|
|
||||||
# Author: tteck (tteckster)
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
|
||||||
# Source: https://www.debian.org/
|
|
||||||
|
|
||||||
APP="Hanko"
|
|
||||||
var_tags="${var_tags:-os}"
|
|
||||||
var_cpu="${var_cpu:-1}"
|
|
||||||
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 /var ]]; then
|
|
||||||
msg_error "No ${APP} Installation Found!"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
msg_info "Updating $APP LXC"
|
|
||||||
$STD apt-get update
|
|
||||||
$STD apt-get -y upgrade
|
|
||||||
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}:8000${CL}"
|
|
||||||
6
ct/headers/asterisk
Normal file
6
ct/headers/asterisk
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
___ __ _ __
|
||||||
|
/ | _____/ /____ _____(_)____/ /__
|
||||||
|
/ /| | / ___/ __/ _ \/ ___/ / ___/ //_/
|
||||||
|
/ ___ |(__ ) /_/ __/ / / (__ ) ,<
|
||||||
|
/_/ |_/____/\__/\___/_/ /_/____/_/|_|
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
____ __ __ __
|
|
||||||
/ __ )____ ____ / /_______/ /_____ ______/ /__
|
|
||||||
/ __ / __ \/ __ \/ //_/ ___/ __/ __ `/ ___/ //_/
|
|
||||||
/ /_/ / /_/ / /_/ / ,< (__ ) /_/ /_/ / /__/ ,<
|
|
||||||
/_____/\____/\____/_/|_/____/\__/\__,_/\___/_/|_|
|
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
______ ____ __ ______
|
|
||||||
/ ____/___ ____ ___ / __/_ __/ / / / _/
|
|
||||||
/ / / __ \/ __ `__ \/ /_/ / / / / / // /
|
|
||||||
/ /___/ /_/ / / / / / / __/ /_/ / /_/ // /
|
|
||||||
\____/\____/_/ /_/ /_/_/ \__, /\____/___/
|
|
||||||
/____/
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
____ _ __ __
|
|
||||||
/ __ \(_)________ ____ _/ /______/ /_ ____ ___________
|
|
||||||
/ / / / / ___/ __ \/ __ `/ __/ ___/ __ \/ __ `/ ___/ ___/
|
|
||||||
/ /_/ / (__ ) /_/ / /_/ / /_/ /__/ / / / /_/ / / / /
|
|
||||||
/_____/_/____/ .___/\__,_/\__/\___/_/ /_/\__,_/_/ /_/
|
|
||||||
/_/
|
|
||||||
6
ct/headers/docker
Normal file
6
ct/headers/docker
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
____ __
|
||||||
|
/ __ \____ _____/ /_____ _____
|
||||||
|
/ / / / __ \/ ___/ //_/ _ \/ ___/
|
||||||
|
/ /_/ / /_/ / /__/ ,< / __/ /
|
||||||
|
/_____/\____/\___/_/|_|\___/_/
|
||||||
|
|
||||||
6
ct/headers/domain-locker
Normal file
6
ct/headers/domain-locker
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
____ _ __ __
|
||||||
|
/ __ \____ ____ ___ ____ _(_)___ / / ____ _____/ /_____ _____
|
||||||
|
/ / / / __ \/ __ `__ \/ __ `/ / __ \______/ / / __ \/ ___/ //_/ _ \/ ___/
|
||||||
|
/ /_/ / /_/ / / / / / / /_/ / / / / /_____/ /___/ /_/ / /__/ ,< / __/ /
|
||||||
|
/_____/\____/_/ /_/ /_/\__,_/_/_/ /_/ /_____/\____/\___/_/|_|\___/_/
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
__ __ __
|
|
||||||
/ / / /___ _____ / /______
|
|
||||||
/ /_/ / __ `/ __ \/ //_/ __ \
|
|
||||||
/ __ / /_/ / / / / ,< / /_/ /
|
|
||||||
/_/ /_/\__,_/_/ /_/_/|_|\____/
|
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
__ ____ _____
|
|
||||||
/ /__ / / /_ __/ __(_)___
|
|
||||||
__ / / _ \/ / / / / / /_/ / __ \
|
|
||||||
/ /_/ / __/ / / /_/ / __/ / / / /
|
|
||||||
\____/\___/_/_/\__, /_/ /_/_/ /_/
|
|
||||||
/____/
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
__ _ __ __
|
|
||||||
/ / (_) _____ / /_ ____ ____ / /__
|
|
||||||
/ / / / | / / _ \/ __ \/ __ \/ __ \/ //_/
|
|
||||||
/ /___/ /| |/ / __/ /_/ / /_/ / /_/ / ,<
|
|
||||||
/_____/_/ |___/\___/_.___/\____/\____/_/|_|
|
|
||||||
|
|
||||||
6
ct/headers/metabase
Normal file
6
ct/headers/metabase
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
__ ___ __ __
|
||||||
|
/ |/ /__ / /_____ _/ /_ ____ _________
|
||||||
|
/ /|_/ / _ \/ __/ __ `/ __ \/ __ `/ ___/ _ \
|
||||||
|
/ / / / __/ /_/ /_/ / /_/ / /_/ (__ ) __/
|
||||||
|
/_/ /_/\___/\__/\__,_/_.___/\__,_/____/\___/
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
__ __
|
|
||||||
____ ____ / /____ _________ ____ ____ / /__
|
|
||||||
/ __ \/ __ \/ __/ _ \/ ___/ __ \/ __ \/ __ \/ //_/
|
|
||||||
/ / / / /_/ / /_/ __(__ ) / / / /_/ / /_/ / ,<
|
|
||||||
/_/ /_/\____/\__/\___/____/_/ /_/\____/\____/_/|_|
|
|
||||||
|
|
||||||
6
ct/headers/omada
Normal file
6
ct/headers/omada
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
____ __
|
||||||
|
/ __ \____ ___ ____ _____/ /___ _
|
||||||
|
/ / / / __ `__ \/ __ `/ __ / __ `/
|
||||||
|
/ /_/ / / / / / / /_/ / /_/ / /_/ /
|
||||||
|
\____/_/ /_/ /_/\__,_/\__,_/\__,_/
|
||||||
|
|
||||||
6
ct/headers/passbolt
Normal file
6
ct/headers/passbolt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
____ __ ____
|
||||||
|
/ __ \____ ___________/ /_ ____ / / /_
|
||||||
|
/ /_/ / __ `/ ___/ ___/ __ \/ __ \/ / __/
|
||||||
|
/ ____/ /_/ (__ |__ ) /_/ / /_/ / / /_
|
||||||
|
/_/ \__,_/____/____/_.___/\____/_/\__/
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
____ __ __ __ ___
|
|
||||||
/ __ \____ _/ /______/ /_ / |/ /___ ____
|
|
||||||
/ /_/ / __ `/ __/ ___/ __ \/ /|_/ / __ \/ __ \
|
|
||||||
/ ____/ /_/ / /_/ /__/ / / / / / / /_/ / / / /
|
|
||||||
/_/ \__,_/\__/\___/_/ /_/_/ /_/\____/_/ /_/
|
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
____ __ _
|
|
||||||
/ __ \____ _____/ /_(_)___
|
|
||||||
/ /_/ / __ \/ ___/ __/ /_ /
|
|
||||||
/ ____/ /_/ (__ ) /_/ / / /_
|
|
||||||
/_/ \____/____/\__/_/ /___/
|
|
||||||
|
|
||||||
6
ct/headers/snowshare
Normal file
6
ct/headers/snowshare
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
_____ _____ __
|
||||||
|
/ ___/____ ____ _ __/ ___// /_ ____ _________
|
||||||
|
\__ \/ __ \/ __ \ | /| / /\__ \/ __ \/ __ `/ ___/ _ \
|
||||||
|
___/ / / / / /_/ / |/ |/ /___/ / / / / /_/ / / / __/
|
||||||
|
/____/_/ /_/\____/|__/|__//____/_/ /_/\__,_/_/ \___/
|
||||||
|
|
||||||
6
ct/headers/upgopher
Normal file
6
ct/headers/upgopher
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
__ __ __
|
||||||
|
/ / / /___ ____ _____ ____ / /_ ___ _____
|
||||||
|
/ / / / __ \/ __ `/ __ \/ __ \/ __ \/ _ \/ ___/
|
||||||
|
/ /_/ / /_/ / /_/ / /_/ / /_/ / / / / __/ /
|
||||||
|
\____/ .___/\__, /\____/ .___/_/ /_/\___/_/
|
||||||
|
/_/ /____/ /_/
|
||||||
6
ct/headers/web-check
Normal file
6
ct/headers/web-check
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
__ __ __
|
||||||
|
_ _____ / /_ _____/ /_ ___ _____/ /__
|
||||||
|
| | /| / / _ \/ __ \______/ ___/ __ \/ _ \/ ___/ //_/
|
||||||
|
| |/ |/ / __/ /_/ /_____/ /__/ / / / __/ /__/ ,<
|
||||||
|
|__/|__/\___/_.___/ \___/_/ /_/\___/\___/_/|_|
|
||||||
|
|
||||||
@ -1,53 +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.10}"
|
|
||||||
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 Intel Dependencies"
|
|
||||||
fetch_and_deploy_gh_release "intel-igc-core-2" "intel/intel-graphics-compiler" "binary" "latest" "" "intel-igc-core-2_*_amd64.deb"
|
|
||||||
fetch_and_deploy_gh_release "intel-igc-opencl-2" "intel/intel-graphics-compiler" "binary" "latest" "" "intel-igc-opencl-2_*_amd64.deb"
|
|
||||||
fetch_and_deploy_gh_release "intel-libgdgmm12" "intel/compute-runtime" "binary" "latest" "" "libigdgmm12_*_amd64.deb"
|
|
||||||
fetch_and_deploy_gh_release "intel-opencl-icd" "intel/compute-runtime" "binary" "latest" "" "intel-opencl-icd_*_amd64.deb"
|
|
||||||
msg_ok "Updated Intel Dependencies"
|
|
||||||
|
|
||||||
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}"
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
|
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
|
||||||
# Author: michelroegl-brunner
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
|
||||||
# Source: https://librenms.org
|
|
||||||
|
|
||||||
APP="Librenms"
|
|
||||||
var_tags="${var_tags:-monitoring}"
|
|
||||||
var_cpu="${var_cpu:-2}"
|
|
||||||
var_ram="${var_ram:-2048}"
|
|
||||||
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/librenms ]; then
|
|
||||||
msg_error "No ${APP} Installation Found!"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
msg_info "Updating ${APP} Installation"
|
|
||||||
su librenms
|
|
||||||
cd /opt/librenms
|
|
||||||
./daily.sh
|
|
||||||
msg_ok "Updated ${APP} Installation"
|
|
||||||
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
|
|
||||||
start
|
|
||||||
build_container
|
|
||||||
desiption
|
|
||||||
|
|
||||||
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}/openproject${CL}"
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/refs/heads/main/misc/build.func)
|
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
|
||||||
# Author: dkuku
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://github.com/livebook-dev/livebook
|
|
||||||
|
|
||||||
APP="Livebook"
|
|
||||||
var_tags="${var_tags:-development}"
|
|
||||||
var_disk="${var_disk:-4}"
|
|
||||||
var_cpu="${var_cpu:-2}"
|
|
||||||
var_ram="${var_ram:-1024}"
|
|
||||||
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 [[ ! -f /opt/livebook/.mix/escripts/livebook ]]; then
|
|
||||||
msg_error "No ${APP} Installation Found!"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
if check_for_gh_release "livebook" "livebook-dev/livebook"; then
|
|
||||||
msg_info "Stopping ${APP}"
|
|
||||||
systemctl stop livebook
|
|
||||||
msg_info "Service stopped"
|
|
||||||
|
|
||||||
msg_info "Updating container"
|
|
||||||
$STD apt-get update
|
|
||||||
$STD apt-get -y upgrade
|
|
||||||
msg_ok "Updated container"
|
|
||||||
|
|
||||||
msg_info "Updating ${APP}"
|
|
||||||
source /opt/livebook/.env
|
|
||||||
cd /opt/livebook
|
|
||||||
$STD mix escript.install hex livebook --force
|
|
||||||
|
|
||||||
chown -R livebook:livebook /opt/livebook /data
|
|
||||||
systemctl start livebook
|
|
||||||
msg_ok "Updated ${APP}"
|
|
||||||
fi
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
|
|
||||||
start
|
|
||||||
build_container
|
|
||||||
description
|
|
||||||
|
|
||||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
|
||||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
|
||||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
|
||||||
87
ct/mealie.sh
Normal file
87
ct/mealie.sh
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#!/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://mealie.io
|
||||||
|
|
||||||
|
APP="Mealie"
|
||||||
|
var_tags="${var_tags:-recipes}"
|
||||||
|
var_cpu="${var_cpu:-5}"
|
||||||
|
var_ram="${var_ram:-4096}"
|
||||||
|
var_disk="${var_disk:-10}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
|
||||||
|
if [[ ! -d /opt/mealie ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
if check_for_gh_release "mealie" "mealie-recipes/mealie"; then
|
||||||
|
PYTHON_VERSION="3.12" setup_uv
|
||||||
|
NODE_MODULE="yarn" NODE_VERSION="24" setup_nodejs
|
||||||
|
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop mealie
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
msg_info "Backing up configuration"
|
||||||
|
mkdir -p /opt/mealie_bak
|
||||||
|
cp -f /opt/mealie/mealie.env /opt/mealie_bak/mealie.env.bak
|
||||||
|
cp -f /opt/mealie/start.sh /opt/mealie_bak/start.sh.bak
|
||||||
|
msg_ok "Backup completed"
|
||||||
|
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "mealie" "mealie-recipes/mealie" "tarball" "latest" "/opt/mealie"
|
||||||
|
|
||||||
|
msg_info "Rebuilding Frontend"
|
||||||
|
export NUXT_TELEMETRY_DISABLED=1
|
||||||
|
cd /opt/mealie/frontend
|
||||||
|
$STD yarn install --prefer-offline --frozen-lockfile --non-interactive --production=false --network-timeout 1000000
|
||||||
|
$STD yarn generate
|
||||||
|
cp -r /opt/mealie/frontend/dist/* /opt/mealie/mealie/frontend/
|
||||||
|
msg_ok "Frontend rebuilt"
|
||||||
|
|
||||||
|
msg_info "Updating Python Dependencies"
|
||||||
|
cd /opt/mealie
|
||||||
|
$STD uv sync --frozen --extra pgsql
|
||||||
|
msg_ok "Dependencies updated"
|
||||||
|
|
||||||
|
msg_info "Restoring configuration"
|
||||||
|
grep -q "^SECRET=" /opt/mealie_bak/mealie.env.bak || echo "SECRET=$(openssl rand -hex 32)" >>/opt/mealie_bak/mealie.env.bak
|
||||||
|
grep -q "^MEALIE_HOME=" /opt/mealie_bak/mealie.env.bak || echo "MEALIE_HOME=/opt/mealie" >>/opt/mealie_bak/mealie.env.bak
|
||||||
|
grep -q "^NLTK_DATA=" /opt/mealie_bak/mealie.env.bak || echo "NLTK_DATA=/nltk_data" >>/opt/mealie_bak/mealie.env.bak
|
||||||
|
|
||||||
|
mv -f /opt/mealie_bak/mealie.env.bak /opt/mealie/mealie.env
|
||||||
|
mv -f /opt/mealie_bak/start.sh.bak /opt/mealie/start.sh
|
||||||
|
chmod +x /opt/mealie/start.sh
|
||||||
|
sed -i 's|exec .*|source /opt/mealie/.venv/bin/activate\nexec uv run mealie|' /opt/mealie/start.sh
|
||||||
|
msg_ok "Configuration restored"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start mealie
|
||||||
|
msg_ok "Started Service"
|
||||||
|
msg_ok "Updated successfully"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
start
|
||||||
|
build_container
|
||||||
|
description
|
||||||
|
|
||||||
|
msg_ok "Completed Successfully!\n"
|
||||||
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||||
|
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||||
|
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9000${CL}"
|
||||||
65
ct/metabase.sh
Normal file
65
ct/metabase.sh
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#!/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: Slaviša Arežina (tremor021)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://www.metabase.com/
|
||||||
|
|
||||||
|
APP="Metabase"
|
||||||
|
var_tags="${var_tags:-analytics}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-2048}"
|
||||||
|
var_disk="${var_disk:-6}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
if [[ ! -d /opt/metabase ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "metabase" "metabase/metabase"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop metabase
|
||||||
|
msg_info "Service stopped"
|
||||||
|
|
||||||
|
msg_info "Creating backup"
|
||||||
|
mv /opt/metabase/.env /opt
|
||||||
|
msg_ok "Created backup"
|
||||||
|
|
||||||
|
msg_info "Updating Metabase"
|
||||||
|
RELEASE=$(get_latest_github_release "metabase/metabase")
|
||||||
|
curl -fsSL "https://downloads.metabase.com/v${RELEASE}.x/metabase.jar" -o /opt/metabase/metabase.jar
|
||||||
|
echo $RELEASE >~/.metabase
|
||||||
|
msg_ok "Updated Metabase"
|
||||||
|
|
||||||
|
msg_info "Restoring backup"
|
||||||
|
mv /opt/.env /opt/metabase
|
||||||
|
msg_ok "Restored backup"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start metabase
|
||||||
|
msg_ok "Started Service"
|
||||||
|
msg_ok "Updated successfully!"
|
||||||
|
fi
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
start
|
||||||
|
build_container
|
||||||
|
description
|
||||||
|
|
||||||
|
msg_ok "Completed Successfully!\n"
|
||||||
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||||
|
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||||
|
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||||
@ -1,59 +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: Slaviša Arežina (tremor021)
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://github.com/streetwriters/notesnook
|
|
||||||
|
|
||||||
APP="notesnook"
|
|
||||||
var_tags="${var_tags:-os}"
|
|
||||||
var_cpu="${var_cpu:-2}"
|
|
||||||
var_ram="${var_ram:-3072}"
|
|
||||||
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 [[ ! -d /opt/notesnook ]]; then
|
|
||||||
msg_error "No ${APP} Installation Found!"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_info "Stopping Service"
|
|
||||||
systemctl stop notesnook
|
|
||||||
msg_ok "Stopped Service"
|
|
||||||
|
|
||||||
msg_info "Updating ${APP} (Patience)"
|
|
||||||
rm -rf /opt/notesnook
|
|
||||||
fetch_and_deploy_gh_release "notesnook" "streetwriters/notesnook" "tarball"
|
|
||||||
cd /opt/notesnook
|
|
||||||
export NODE_OPTIONS="--max-old-space-size=2560"
|
|
||||||
$STD npm install
|
|
||||||
$STD npm run build:web
|
|
||||||
msg_ok "Updated $APP"
|
|
||||||
|
|
||||||
msg_info "Starting Service"
|
|
||||||
systemctl start notesnook
|
|
||||||
msg_ok "Started Service"
|
|
||||||
|
|
||||||
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}https://${IP}${CL}"
|
|
||||||
@ -1,79 +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: vhsdream
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://github.com/PatchMon/PatchMon
|
|
||||||
|
|
||||||
APP="PatchMon"
|
|
||||||
APP_NAME=${APP,,}
|
|
||||||
var_tags="${var_tags:-monitoring}"
|
|
||||||
var_cpu="${var_cpu:-2}"
|
|
||||||
var_ram="${var_ram:-2048}"
|
|
||||||
var_disk="${var_disk:-4}"
|
|
||||||
var_os="${var_os:-debian}"
|
|
||||||
var_version="${var_version:-13}"
|
|
||||||
var_unprivileged="${var_unprivileged:-1}"
|
|
||||||
|
|
||||||
header_info "$APP"
|
|
||||||
variables
|
|
||||||
color
|
|
||||||
catch_errors
|
|
||||||
|
|
||||||
function update_script() {
|
|
||||||
header_info
|
|
||||||
check_container_storage
|
|
||||||
check_container_resources
|
|
||||||
|
|
||||||
if [[ ! -d "/opt/patchmon" ]]; then
|
|
||||||
msg_error "No ${APP} Installation Found!"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
NODE_VERSION="24" setup_nodejs
|
|
||||||
|
|
||||||
if check_for_gh_release "PatchMon" "PatchMon/PatchMon"; then
|
|
||||||
|
|
||||||
msg_info "Stopping $APP"
|
|
||||||
systemctl stop patchmon-server
|
|
||||||
msg_ok "Stopped $APP"
|
|
||||||
|
|
||||||
msg_info "Creating Backup"
|
|
||||||
cp /opt/patchmon/backend/.env /opt/backend.env
|
|
||||||
cp /opt/patchmon/frontend/.env /opt/frontend.env
|
|
||||||
msg_ok "Backup Created"
|
|
||||||
|
|
||||||
rm -rf /opt/patchmon
|
|
||||||
fetch_and_deploy_gh_release "PatchMon" "PatchMon/PatchMon" "tarball" "latest" "/opt/patchmon"
|
|
||||||
|
|
||||||
msg_info "Updating ${APP}"
|
|
||||||
cd /opt/patchmon
|
|
||||||
export NODE_ENV=production
|
|
||||||
$STD npm install --no-audit --no-fund --no-save --ignore-scripts
|
|
||||||
cd /opt/patchmon/backend
|
|
||||||
$STD npm install --no-audit --no-fund --no-save --ignore-scripts
|
|
||||||
cd /opt/patchmon/frontend
|
|
||||||
$STD npm install --include=dev --no-audit --no-fund --no-save --ignore-scripts
|
|
||||||
$STD npm run build
|
|
||||||
cd /opt/patchmon/backend
|
|
||||||
mv /opt/backend.env /opt/patchmon/backend/.env
|
|
||||||
mv /opt/frontend.env /opt/patchmon/frontend/.env
|
|
||||||
$STD npx prisma migrate deploy
|
|
||||||
$STD npx prisma generate
|
|
||||||
msg_ok "Updated ${APP}"
|
|
||||||
|
|
||||||
msg_info "Starting $APP"
|
|
||||||
systemctl start patchmon-server
|
|
||||||
msg_ok "Started $APP"
|
|
||||||
fi
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
|
|
||||||
start
|
|
||||||
build_container
|
|
||||||
description
|
|
||||||
|
|
||||||
msg_ok "Completed Successfully!\n"
|
|
||||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
|
||||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
|
||||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
|
||||||
64
ct/postiz.sh
64
ct/postiz.sh
@ -1,64 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
source <(curl -fsSL 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="Postiz"
|
|
||||||
var_tags="${var_tags:-Arr}"
|
|
||||||
var_cpu="${var_cpu:-2}"
|
|
||||||
var_ram="${var_ram:-3072}"
|
|
||||||
var_disk="${var_disk:-8}"
|
|
||||||
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/postiz.service ]]; then
|
|
||||||
msg_error "No ${APP} Installation Found!"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
RELEASE=$(curl -fsSL 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}"
|
|
||||||
@ -11,7 +11,7 @@ var_cpu="${var_cpu:-2}"
|
|||||||
var_ram="${var_ram:-2048}"
|
var_ram="${var_ram:-2048}"
|
||||||
var_disk="${var_disk:-5}"
|
var_disk="${var_disk:-5}"
|
||||||
var_os="${var_os:-debian}"
|
var_os="${var_os:-debian}"
|
||||||
var_version="${var_version:-12}"
|
var_version="${var_version:-13}"
|
||||||
var_unprivileged="${var_unprivileged:-1}"
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
header_info "$APP"
|
header_info "$APP"
|
||||||
|
|||||||
60
ct/snowshare.sh
Normal file
60
ct/snowshare.sh
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#!/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: TuroYT
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/TuroYT/snowshare
|
||||||
|
|
||||||
|
APP="SnowShare"
|
||||||
|
var_tags="${var_tags:-file-sharing}"
|
||||||
|
var_cpu="${var_cpu:-1}"
|
||||||
|
var_ram="${var_ram:-1024}"
|
||||||
|
var_disk="${var_disk:-5}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
if [[ ! -d /opt/snowshare ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "snowshare" "TuroYT/snowshare"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop snowshare
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "snowshare" "TuroYT/snowshare"
|
||||||
|
|
||||||
|
msg_info "Updating Snowshare"
|
||||||
|
cd /opt/snowshare
|
||||||
|
$STD npm ci
|
||||||
|
$STD npx prisma generate
|
||||||
|
$STD npm run build
|
||||||
|
msg_ok "Updated Snowshare"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start snowshare
|
||||||
|
msg_ok "Started Service"
|
||||||
|
msg_ok "Updated successfully!"
|
||||||
|
fi
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
start
|
||||||
|
build_container
|
||||||
|
description
|
||||||
|
|
||||||
|
msg_ok "Completed Successfully!\n"
|
||||||
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||||
|
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||||
|
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||||
69
ct/web-check.sh
Normal file
69
ct/web-check.sh
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#!/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: CrazyWolf13
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/Lissy93/web-check
|
||||||
|
|
||||||
|
APP="web-check"
|
||||||
|
var_tags="${var_tags:-network;analysis}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-2048}"
|
||||||
|
var_disk="${var_disk:-12}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
if [[ ! -d /opt/web-check ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "web-check" "CrazyWolf13/web-check"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop web-check
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
msg_info "Creating backup"
|
||||||
|
mv /opt/web-check/.env /opt
|
||||||
|
msg_ok "Created backup"
|
||||||
|
|
||||||
|
NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "web-check" "CrazyWolf13/web-check"
|
||||||
|
|
||||||
|
msg_info "Building Web-Check"
|
||||||
|
cd /opt/web-check
|
||||||
|
$STD yarn install --frozen-lockfile --network-timeout 100000
|
||||||
|
$STD yarn build --production
|
||||||
|
rm -rf /var/lib/apt/lists/* /app/node_modules/.cache
|
||||||
|
msg_ok "Built Web-Check"
|
||||||
|
|
||||||
|
msg_info "Restoring backup"
|
||||||
|
mv /opt/.env /opt/web-check
|
||||||
|
msg_ok "Restored backup"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start web-check
|
||||||
|
msg_ok "Started Service"
|
||||||
|
msg_ok "Updated Successfully!"
|
||||||
|
fi
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
start
|
||||||
|
build_container
|
||||||
|
description
|
||||||
|
|
||||||
|
msg_ok "Completed Successfully!\n"
|
||||||
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||||
|
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||||
|
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||||
532
docs/DEV_MODE.md
Normal file
532
docs/DEV_MODE.md
Normal file
@ -0,0 +1,532 @@
|
|||||||
|
# Dev Mode - Debugging & Development Guide
|
||||||
|
|
||||||
|
Development modes provide powerful debugging and testing capabilities for container creation and installation processes.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Single mode
|
||||||
|
export dev_mode="motd"
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/wallabag.sh)"
|
||||||
|
|
||||||
|
# Multiple modes (comma-separated)
|
||||||
|
export dev_mode="motd,keep,trace"
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/wallabag.sh)"
|
||||||
|
|
||||||
|
# Combine with verbose output
|
||||||
|
export var_verbose="yes"
|
||||||
|
export dev_mode="pause,logs"
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/wallabag.sh)"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Available Modes
|
||||||
|
|
||||||
|
### 1. **motd** - Early SSH/MOTD Setup
|
||||||
|
|
||||||
|
Sets up SSH access and MOTD **before** the main application installation.
|
||||||
|
|
||||||
|
**Use Case**:
|
||||||
|
|
||||||
|
- Quick access to container for manual debugging
|
||||||
|
- Continue installation manually if something goes wrong
|
||||||
|
- Verify container networking before main install
|
||||||
|
|
||||||
|
**Behavior**:
|
||||||
|
|
||||||
|
```
|
||||||
|
✔ Container created
|
||||||
|
✔ Network configured
|
||||||
|
[DEV] Setting up MOTD and SSH before installation
|
||||||
|
✔ [DEV] MOTD/SSH ready - container accessible
|
||||||
|
# Container is now accessible via SSH while installation proceeds
|
||||||
|
```
|
||||||
|
|
||||||
|
**Combined with**: `keep`, `breakpoint`, `logs`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. **keep** - Preserve Container on Failure
|
||||||
|
|
||||||
|
Never delete the container when installation fails. Skips cleanup prompt.
|
||||||
|
|
||||||
|
**Use Case**:
|
||||||
|
|
||||||
|
- Repeated tests of the same installation
|
||||||
|
- Debugging failed installations
|
||||||
|
- Manual fix attempts
|
||||||
|
|
||||||
|
**Behavior**:
|
||||||
|
|
||||||
|
```
|
||||||
|
✖ Installation failed in container 107 (exit code: 1)
|
||||||
|
✔ Container creation log: /tmp/create-lxc-107-abc12345.log
|
||||||
|
✔ Installation log: /tmp/install-lxc-107-abc12345.log
|
||||||
|
|
||||||
|
🔧 [DEV] Keep mode active - container 107 preserved
|
||||||
|
root@proxmox:~#
|
||||||
|
```
|
||||||
|
|
||||||
|
**Container remains**: `pct enter 107` to access and debug
|
||||||
|
|
||||||
|
**Combined with**: `motd`, `trace`, `logs`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. **trace** - Bash Command Tracing
|
||||||
|
|
||||||
|
Enables `set -x` for complete command-line tracing. Shows every command before execution.
|
||||||
|
|
||||||
|
**Use Case**:
|
||||||
|
|
||||||
|
- Deep debugging of installation logic
|
||||||
|
- Understanding script flow
|
||||||
|
- Identifying where errors occur exactly
|
||||||
|
|
||||||
|
**Behavior**:
|
||||||
|
|
||||||
|
```
|
||||||
|
+(/opt/wallabag/bin/console): /opt/wallabag/bin/console cache:warmup
|
||||||
|
+(/opt/wallabag/bin/console): env APP_ENV=prod /opt/wallabag/bin/console cache:warmup
|
||||||
|
+(/opt/wallabag/bin/console): [[ -d /opt/wallabag/app/cache ]]
|
||||||
|
+(/opt/wallabag/bin/console): rm -rf /opt/wallabag/app/cache/*
|
||||||
|
```
|
||||||
|
|
||||||
|
**⚠️ Warning**: Exposes passwords and secrets in log output! Only use in isolated environments.
|
||||||
|
|
||||||
|
**Log Output**: All trace output saved to logs (see `logs` mode)
|
||||||
|
|
||||||
|
**Combined with**: `keep`, `pause`, `logs`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. **pause** - Step-by-Step Execution
|
||||||
|
|
||||||
|
Pauses after each major step (`msg_info`). Requires manual Enter press to continue.
|
||||||
|
|
||||||
|
**Use Case**:
|
||||||
|
|
||||||
|
- Inspect container state between steps
|
||||||
|
- Understand what each step does
|
||||||
|
- Identify which step causes problems
|
||||||
|
|
||||||
|
**Behavior**:
|
||||||
|
|
||||||
|
```
|
||||||
|
⏳ Setting up Container OS
|
||||||
|
[PAUSE] Press Enter to continue...
|
||||||
|
⏳ Updating Container OS
|
||||||
|
[PAUSE] Press Enter to continue...
|
||||||
|
⏳ Installing Dependencies
|
||||||
|
[PAUSE] Press Enter to continue...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Between pauses**: You can open another terminal and inspect the container
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In another terminal while paused
|
||||||
|
pct enter 107
|
||||||
|
root@container:~# df -h # Check disk usage
|
||||||
|
root@container:~# ps aux # Check running processes
|
||||||
|
```
|
||||||
|
|
||||||
|
**Combined with**: `motd`, `keep`, `logs`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. **breakpoint** - Interactive Shell on Error
|
||||||
|
|
||||||
|
Opens interactive shell inside the container when an error occurs instead of cleanup prompt.
|
||||||
|
|
||||||
|
**Use Case**:
|
||||||
|
|
||||||
|
- Live debugging in the actual container
|
||||||
|
- Manual command testing
|
||||||
|
- Inspect container state at point of failure
|
||||||
|
|
||||||
|
**Behavior**:
|
||||||
|
|
||||||
|
```
|
||||||
|
✖ Installation failed in container 107 (exit code: 1)
|
||||||
|
✔ Container creation log: /tmp/create-lxc-107-abc12345.log
|
||||||
|
✔ Installation log: /tmp/install-lxc-107-abc12345.log
|
||||||
|
|
||||||
|
🐛 [DEV] Breakpoint mode - opening shell in container 107
|
||||||
|
Type 'exit' to return to host
|
||||||
|
root@wallabag:~#
|
||||||
|
|
||||||
|
# Now you can debug:
|
||||||
|
root@wallabag:~# tail -f /root/.install-abc12345.log
|
||||||
|
root@wallabag:~# mysql -u root -p$PASSWORD wallabag
|
||||||
|
root@wallabag:~# apt-get install -y strace
|
||||||
|
root@wallabag:~# exit
|
||||||
|
|
||||||
|
Container 107 still running. Remove now? (y/N): n
|
||||||
|
🔧 Container 107 kept for debugging
|
||||||
|
```
|
||||||
|
|
||||||
|
**Combined with**: `keep`, `logs`, `trace`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. **logs** - Persistent Logging
|
||||||
|
|
||||||
|
Saves all logs to `/var/log/community-scripts/` with timestamps. Logs persist even on successful installation.
|
||||||
|
|
||||||
|
**Use Case**:
|
||||||
|
|
||||||
|
- Post-mortem analysis
|
||||||
|
- Performance analysis
|
||||||
|
- Automated testing with log collection
|
||||||
|
- CI/CD integration
|
||||||
|
|
||||||
|
**Behavior**:
|
||||||
|
|
||||||
|
```
|
||||||
|
Logs location: /var/log/community-scripts/
|
||||||
|
|
||||||
|
create-lxc-abc12345-20251117_143022.log (host-side creation)
|
||||||
|
install-abc12345-20251117_143022.log (container-side installation)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Access logs**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View creation log
|
||||||
|
tail -f /var/log/community-scripts/create-lxc-*.log
|
||||||
|
|
||||||
|
# Search for errors
|
||||||
|
grep ERROR /var/log/community-scripts/*.log
|
||||||
|
|
||||||
|
# Analyze performance
|
||||||
|
grep "msg_info\|msg_ok" /var/log/community-scripts/create-*.log
|
||||||
|
```
|
||||||
|
|
||||||
|
**With trace mode**: Creates detailed trace of all commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep "^+" /var/log/community-scripts/install-*.log
|
||||||
|
```
|
||||||
|
|
||||||
|
**Combined with**: All other modes (recommended for CI/CD)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. **dryrun** - Simulation Mode
|
||||||
|
|
||||||
|
Shows all commands that would be executed without actually running them.
|
||||||
|
|
||||||
|
**Use Case**:
|
||||||
|
|
||||||
|
- Test script logic without making changes
|
||||||
|
- Verify command syntax
|
||||||
|
- Understand what will happen
|
||||||
|
- Pre-flight checks
|
||||||
|
|
||||||
|
**Behavior**:
|
||||||
|
|
||||||
|
```
|
||||||
|
[DRYRUN] apt-get update
|
||||||
|
[DRYRUN] apt-get install -y curl
|
||||||
|
[DRYRUN] mkdir -p /opt/wallabag
|
||||||
|
[DRYRUN] cd /opt/wallabag
|
||||||
|
[DRYRUN] git clone https://github.com/wallabag/wallabag.git .
|
||||||
|
```
|
||||||
|
|
||||||
|
**No actual changes made**: Container/system remains unchanged
|
||||||
|
|
||||||
|
**Combined with**: `trace` (shows dryrun trace), `logs` (shows what would run)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mode Combinations
|
||||||
|
|
||||||
|
### Development Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# First test: See what would happen
|
||||||
|
export dev_mode="dryrun,logs"
|
||||||
|
bash -c "$(curl ...)"
|
||||||
|
|
||||||
|
# Then test with tracing and pauses
|
||||||
|
export dev_mode="pause,trace,logs"
|
||||||
|
bash -c "$(curl ...)"
|
||||||
|
|
||||||
|
# Finally full debug with early SSH access
|
||||||
|
export dev_mode="motd,keep,breakpoint,logs"
|
||||||
|
bash -c "$(curl ...)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### CI/CD Integration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Automated testing with full logging
|
||||||
|
export dev_mode="logs"
|
||||||
|
export var_verbose="yes"
|
||||||
|
bash -c "$(curl ...)"
|
||||||
|
|
||||||
|
# Capture logs for analysis
|
||||||
|
tar czf installation-logs-$(date +%s).tar.gz /var/log/community-scripts/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production-like Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Keep containers for manual verification
|
||||||
|
export dev_mode="keep,logs"
|
||||||
|
for i in {1..5}; do
|
||||||
|
bash -c "$(curl ...)"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Inspect all created containers
|
||||||
|
pct list
|
||||||
|
pct enter 100
|
||||||
|
```
|
||||||
|
|
||||||
|
### Live Debugging
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH in early, step through installation, debug on error
|
||||||
|
export dev_mode="motd,pause,breakpoint,keep"
|
||||||
|
bash -c "$(curl ...)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Environment Variables Reference
|
||||||
|
|
||||||
|
### Dev Mode Variables
|
||||||
|
|
||||||
|
- `dev_mode` (string): Comma-separated list of modes
|
||||||
|
- Format: `"motd,keep,trace"`
|
||||||
|
- Default: Empty (no dev modes)
|
||||||
|
|
||||||
|
### Output Control
|
||||||
|
|
||||||
|
- `var_verbose="yes"`: Show all command output (disables silent mode)
|
||||||
|
- Pairs well with: `trace`, `pause`, `logs`
|
||||||
|
|
||||||
|
### Examples with vars
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Maximum verbosity and debugging
|
||||||
|
export var_verbose="yes"
|
||||||
|
export dev_mode="motd,trace,pause,logs"
|
||||||
|
bash -c "$(curl ...)"
|
||||||
|
|
||||||
|
# Silent debug (logs only)
|
||||||
|
export dev_mode="keep,logs"
|
||||||
|
bash -c "$(curl ...)"
|
||||||
|
|
||||||
|
# Interactive debugging
|
||||||
|
export var_verbose="yes"
|
||||||
|
export dev_mode="motd,breakpoint"
|
||||||
|
bash -c "$(curl ...)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting with Dev Mode
|
||||||
|
|
||||||
|
### "Installation failed at step X"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export dev_mode="pause,logs"
|
||||||
|
# Step through until the failure point
|
||||||
|
# Check container state between pauses
|
||||||
|
pct enter 107
|
||||||
|
```
|
||||||
|
|
||||||
|
### "Password/credentials not working"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export dev_mode="motd,keep,trace"
|
||||||
|
# With trace mode, see exact password handling (be careful with logs!)
|
||||||
|
# Use motd to SSH in and test manually
|
||||||
|
ssh root@container-ip
|
||||||
|
```
|
||||||
|
|
||||||
|
### "Permission denied errors"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export dev_mode="breakpoint,keep"
|
||||||
|
# Get shell at failure point
|
||||||
|
# Check file permissions, user context, SELinux status
|
||||||
|
ls -la /path/to/file
|
||||||
|
whoami
|
||||||
|
```
|
||||||
|
|
||||||
|
### "Networking issues"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export dev_mode="motd"
|
||||||
|
# SSH in with motd mode before main install
|
||||||
|
ssh root@container-ip
|
||||||
|
ping 8.8.8.8
|
||||||
|
nslookup example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### "Need to manually complete installation"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export dev_mode="motd,keep"
|
||||||
|
# Container accessible via SSH while installation runs
|
||||||
|
# After failure, SSH in and manually continue
|
||||||
|
ssh root@container-ip
|
||||||
|
# ... manual commands ...
|
||||||
|
exit
|
||||||
|
# Then use 'keep' mode to preserve container for inspection
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Log Files Locations
|
||||||
|
|
||||||
|
### Default (without `logs` mode)
|
||||||
|
|
||||||
|
- Host creation: `/tmp/create-lxc-<SESSION_ID>.log`
|
||||||
|
- Container install: Copied to `/tmp/install-lxc-<CTID>-<SESSION_ID>.log` on failure
|
||||||
|
|
||||||
|
### With `logs` mode
|
||||||
|
|
||||||
|
- Host creation: `/var/log/community-scripts/create-lxc-<SESSION_ID>-<TIMESTAMP>.log`
|
||||||
|
- Container install: `/var/log/community-scripts/install-<SESSION_ID>-<TIMESTAMP>.log`
|
||||||
|
|
||||||
|
### View logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Tail in real-time
|
||||||
|
tail -f /var/log/community-scripts/*.log
|
||||||
|
|
||||||
|
# Search for errors
|
||||||
|
grep -r "exit code [1-9]" /var/log/community-scripts/
|
||||||
|
|
||||||
|
# Filter by session
|
||||||
|
grep "ed563b19" /var/log/community-scripts/*.log
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### ✅ DO
|
||||||
|
|
||||||
|
- Use `logs` mode for CI/CD and automated testing
|
||||||
|
- Use `motd` for early SSH access during long installations
|
||||||
|
- Use `pause` when learning the installation flow
|
||||||
|
- Use `trace` when debugging logic issues (watch for secrets!)
|
||||||
|
- Combine modes for comprehensive debugging
|
||||||
|
- Archive logs after successful tests
|
||||||
|
|
||||||
|
### ❌ DON'T
|
||||||
|
|
||||||
|
- Use `trace` in production or with untrusted networks (exposes secrets)
|
||||||
|
- Leave `keep` mode enabled for unattended scripts (containers accumulate)
|
||||||
|
- Use `dryrun` and expect actual changes
|
||||||
|
- Commit `dev_mode` exports to production deployment scripts
|
||||||
|
- Use `breakpoint` in non-interactive environments (will hang)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Example 1: Debug a Failed Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Initial test to see the failure
|
||||||
|
export dev_mode="keep,logs"
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/wallabag.sh)"
|
||||||
|
|
||||||
|
# Container 107 kept, check logs
|
||||||
|
tail /var/log/community-scripts/install-*.log
|
||||||
|
|
||||||
|
# SSH in to debug
|
||||||
|
pct enter 107
|
||||||
|
root@wallabag:~# cat /root/.install-*.log | tail -100
|
||||||
|
root@wallabag:~# apt-get update # Retry the failing command
|
||||||
|
root@wallabag:~# exit
|
||||||
|
|
||||||
|
# Re-run with manual step-through
|
||||||
|
export dev_mode="motd,pause,keep"
|
||||||
|
bash -c "$(curl ...)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2: Verify Installation Steps
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export dev_mode="pause,logs"
|
||||||
|
export var_verbose="yes"
|
||||||
|
bash -c "$(curl ...)"
|
||||||
|
|
||||||
|
# Press Enter through each step
|
||||||
|
# Monitor container in another terminal
|
||||||
|
# pct enter 107
|
||||||
|
# Review logs in real-time
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 3: CI/CD Pipeline Integration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
export dev_mode="logs"
|
||||||
|
export var_verbose="no"
|
||||||
|
|
||||||
|
for app in wallabag nextcloud wordpress; do
|
||||||
|
echo "Testing $app installation..."
|
||||||
|
APP="$app" bash -c "$(curl ...)" || {
|
||||||
|
echo "FAILED: $app"
|
||||||
|
tar czf logs-$app.tar.gz /var/log/community-scripts/
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "SUCCESS: $app"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "All installations successful"
|
||||||
|
tar czf all-logs.tar.gz /var/log/community-scripts/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Advanced Usage
|
||||||
|
|
||||||
|
### Custom Log Analysis
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Extract all errors
|
||||||
|
grep "ERROR\|exit code [1-9]" /var/log/community-scripts/*.log
|
||||||
|
|
||||||
|
# Performance timeline
|
||||||
|
grep "^$(date +%Y-%m-%d)" /var/log/community-scripts/*.log | grep "msg_"
|
||||||
|
|
||||||
|
# Memory usage during install
|
||||||
|
grep "free\|available" /var/log/community-scripts/*.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration with External Tools
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Send logs to Elasticsearch
|
||||||
|
curl -X POST "localhost:9200/installation-logs/_doc" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d @/var/log/community-scripts/install-*.log
|
||||||
|
|
||||||
|
# Archive for compliance
|
||||||
|
tar czf installation-records-$(date +%Y%m).tar.gz \
|
||||||
|
/var/log/community-scripts/
|
||||||
|
gpg --encrypt installation-records-*.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Support & Issues
|
||||||
|
|
||||||
|
When reporting installation issues, always include:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Collect all relevant information
|
||||||
|
export dev_mode="logs"
|
||||||
|
# Run the failing installation
|
||||||
|
# Then provide:
|
||||||
|
tar czf debug-logs.tar.gz /var/log/community-scripts/
|
||||||
|
```
|
||||||
|
|
||||||
|
Include the `debug-logs.tar.gz` when reporting issues for better diagnostics.
|
||||||
298
docs/EXIT_CODES.md
Normal file
298
docs/EXIT_CODES.md
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
# Exit Code Reference
|
||||||
|
|
||||||
|
Comprehensive documentation of all exit codes used in ProxmoxVED scripts.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Generic/Shell Errors (1-255)](#genericshell-errors)
|
||||||
|
- [Package Manager Errors (100-101, 255)](#package-manager-errors)
|
||||||
|
- [Node.js/npm Errors (243-254)](#nodejsnpm-errors)
|
||||||
|
- [Python/pip Errors (210-212)](#pythonpip-errors)
|
||||||
|
- [Database Errors (231-254)](#database-errors)
|
||||||
|
- [Proxmox Custom Codes (200-231)](#proxmox-custom-codes)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Generic/Shell Errors
|
||||||
|
|
||||||
|
Standard Unix/Linux exit codes used across all scripts.
|
||||||
|
|
||||||
|
| Code | Description | Common Causes | Solutions |
|
||||||
|
| ------- | --------------------------------------- | ----------------------------------------- | ---------------------------------------------- |
|
||||||
|
| **1** | General error / Operation not permitted | Permission denied, general failure | Check user permissions, run as root if needed |
|
||||||
|
| **2** | Misuse of shell builtins | Syntax error in script | Review script syntax, check bash version |
|
||||||
|
| **126** | Command cannot execute | Permission problem, not executable | `chmod +x script.sh` or check file permissions |
|
||||||
|
| **127** | Command not found | Missing binary, wrong PATH | Install required package, check PATH variable |
|
||||||
|
| **128** | Invalid argument to exit | Invalid exit code passed | Use exit codes 0-255 only |
|
||||||
|
| **130** | Terminated by Ctrl+C (SIGINT) | User interrupted script | Expected behavior, no action needed |
|
||||||
|
| **137** | Killed (SIGKILL) | Out of memory, forced termination | Check memory usage, increase RAM allocation |
|
||||||
|
| **139** | Segmentation fault | Memory access violation, corrupted binary | Reinstall package, check system stability |
|
||||||
|
| **143** | Terminated (SIGTERM) | Graceful shutdown signal | Expected during container stops |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Package Manager Errors
|
||||||
|
|
||||||
|
APT, DPKG, and package installation errors.
|
||||||
|
|
||||||
|
| Code | Description | Common Causes | Solutions |
|
||||||
|
| ------- | -------------------------- | --------------------------------------- | ------------------------------------------------- |
|
||||||
|
| **100** | APT: Package manager error | Broken packages, dependency conflicts | `apt --fix-broken install`, `dpkg --configure -a` |
|
||||||
|
| **101** | APT: Configuration error | Malformed sources.list, bad repo config | Check `/etc/apt/sources.list`, run `apt update` |
|
||||||
|
| **255** | DPKG: Fatal internal error | Corrupted package database | `dpkg --configure -a`, restore from backup |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Node.js/npm Errors
|
||||||
|
|
||||||
|
Node.js runtime and package manager errors.
|
||||||
|
|
||||||
|
| Code | Description | Common Causes | Solutions |
|
||||||
|
| ------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------- |
|
||||||
|
| **243** | Node.js: Out of memory | JavaScript heap exhausted | Increase `--max-old-space-size`, optimize code |
|
||||||
|
| **245** | Node.js: Invalid command-line option | Wrong Node.js flags | Check Node.js version, verify CLI options |
|
||||||
|
| **246** | Node.js: Internal JavaScript Parse Error | Syntax error in JS code | Review JavaScript syntax, check dependencies |
|
||||||
|
| **247** | Node.js: Fatal internal error | Node.js runtime crash | Update Node.js, check for known bugs |
|
||||||
|
| **248** | Node.js: Invalid C++ addon / N-API failure | Native module incompatibility | Rebuild native modules, update packages |
|
||||||
|
| **249** | Node.js: Inspector error | Debug/inspect protocol failure | Disable inspector, check port conflicts |
|
||||||
|
| **254** | npm/pnpm/yarn: Unknown fatal error | Package manager crash | Clear cache, reinstall package manager |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Python/pip Errors
|
||||||
|
|
||||||
|
Python runtime and package installation errors.
|
||||||
|
|
||||||
|
| Code | Description | Common Causes | Solutions |
|
||||||
|
| ------- | ------------------------------------ | --------------------------------------- | -------------------------------------------------------- |
|
||||||
|
| **210** | Python: Virtualenv missing or broken | venv not created, corrupted environment | `python3 -m venv venv`, recreate virtualenv |
|
||||||
|
| **211** | Python: Dependency resolution failed | Conflicting package versions | Use `pip install --upgrade`, check requirements.txt |
|
||||||
|
| **212** | Python: Installation aborted | EXTERNALLY-MANAGED, permission denied | Use `--break-system-packages` or venv, check permissions |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Database Errors
|
||||||
|
|
||||||
|
### PostgreSQL (231-234)
|
||||||
|
|
||||||
|
| Code | Description | Common Causes | Solutions |
|
||||||
|
| ------- | ----------------------- | ---------------------------------- | ----------------------------------------------------- |
|
||||||
|
| **231** | Connection failed | Server not running, wrong socket | `systemctl start postgresql`, check connection string |
|
||||||
|
| **232** | Authentication failed | Wrong credentials | Verify username/password, check `pg_hba.conf` |
|
||||||
|
| **233** | Database does not exist | Database not created | `CREATE DATABASE`, restore from backup |
|
||||||
|
| **234** | Fatal error in query | Syntax error, constraint violation | Review SQL syntax, check constraints |
|
||||||
|
|
||||||
|
### MySQL/MariaDB (241-244)
|
||||||
|
|
||||||
|
| Code | Description | Common Causes | Solutions |
|
||||||
|
| ------- | ----------------------- | ---------------------------------- | ---------------------------------------------------- |
|
||||||
|
| **241** | Connection failed | Server not running, wrong socket | `systemctl start mysql`, check connection parameters |
|
||||||
|
| **242** | Authentication failed | Wrong credentials | Verify username/password, grant privileges |
|
||||||
|
| **243** | Database does not exist | Database not created | `CREATE DATABASE`, restore from backup |
|
||||||
|
| **244** | Fatal error in query | Syntax error, constraint violation | Review SQL syntax, check constraints |
|
||||||
|
|
||||||
|
### MongoDB (251-254)
|
||||||
|
|
||||||
|
| Code | Description | Common Causes | Solutions |
|
||||||
|
| ------- | --------------------- | -------------------- | ------------------------------------------ |
|
||||||
|
| **251** | Connection failed | Server not running | `systemctl start mongod`, check port 27017 |
|
||||||
|
| **252** | Authentication failed | Wrong credentials | Verify username/password, create user |
|
||||||
|
| **253** | Database not found | Database not created | Database auto-created on first write |
|
||||||
|
| **254** | Fatal query error | Invalid query syntax | Review MongoDB query syntax |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Proxmox Custom Codes
|
||||||
|
|
||||||
|
Custom exit codes specific to ProxmoxVED scripts.
|
||||||
|
|
||||||
|
### Container Creation Errors (200-209)
|
||||||
|
|
||||||
|
| Code | Description | Common Causes | Solutions |
|
||||||
|
| ------- | ---------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------- |
|
||||||
|
| **200** | Failed to create lock file | Permission denied, disk full | Check `/tmp` permissions, free disk space |
|
||||||
|
| **203** | Missing CTID variable | Script configuration error | Set CTID in script or via prompt |
|
||||||
|
| **204** | Missing PCT_OSTYPE variable | Template selection failed | Verify template availability |
|
||||||
|
| **205** | Invalid CTID (<100) | CTID below minimum value | Use CTID ≥ 100 (1-99 reserved for Proxmox) |
|
||||||
|
| **206** | CTID already in use | Container/VM with same ID exists | Check `pct list` and `/etc/pve/lxc/`, use different ID |
|
||||||
|
| **207** | Password contains unescaped special characters | Special chars like `-`, `/`, `\`, `*` at start/end | Avoid leading special chars, use alphanumeric passwords |
|
||||||
|
| **208** | Invalid configuration | DNS format (`.home` vs `home`), MAC format (`-` vs `:`) | Remove leading dots from DNS, use `:` in MAC addresses |
|
||||||
|
| **209** | Container creation failed | Multiple possible causes | Check logs in `/tmp/pct_create_*.log`, verify template |
|
||||||
|
|
||||||
|
### Cluster & Storage Errors (210, 214, 217)
|
||||||
|
|
||||||
|
| Code | Description | Common Causes | Solutions |
|
||||||
|
| ------- | --------------------------------- | ---------------------------------- | ----------------------------------------------------------- |
|
||||||
|
| **210** | Cluster not quorate | Cluster nodes down, network issues | Check cluster status: `pvecm status`, fix node connectivity |
|
||||||
|
| **211** | Timeout waiting for template lock | Concurrent download in progress | Wait for other download to complete (60s timeout) |
|
||||||
|
| **214** | Not enough storage space | Disk full, quota exceeded | Free disk space, increase storage allocation |
|
||||||
|
| **217** | Storage does not support rootdir | Wrong storage type selected | Use storage supporting containers (dir, zfspool, lvm-thin) |
|
||||||
|
|
||||||
|
### Container Verification Errors (215-216)
|
||||||
|
|
||||||
|
| Code | Description | Common Causes | Solutions |
|
||||||
|
| ------- | -------------------------------- | -------------------------------- | --------------------------------------------------------- |
|
||||||
|
| **215** | Container created but not listed | Ghost state, incomplete creation | Check `/etc/pve/lxc/CTID.conf`, remove manually if needed |
|
||||||
|
| **216** | RootFS entry missing in config | Incomplete container creation | Delete container, retry creation |
|
||||||
|
|
||||||
|
### Template Errors (218, 220-223, 225)
|
||||||
|
|
||||||
|
| Code | Description | Common Causes | Solutions |
|
||||||
|
| ------- | ----------------------------------------- | ------------------------------------------------ | ----------------------------------------------------------- |
|
||||||
|
| **218** | Template file corrupted or incomplete | Download interrupted, file <1MB, invalid archive | Delete template, run `pveam update && pveam download` |
|
||||||
|
| **220** | Unable to resolve template path | Template storage not accessible | Check storage availability, verify permissions |
|
||||||
|
| **221** | Template file exists but not readable | Permission denied | `chmod 644 template.tar.zst`, check storage permissions |
|
||||||
|
| **222** | Template download failed after 3 attempts | Network issues, storage problems | Check internet connectivity, verify storage space |
|
||||||
|
| **223** | Template not available after download | Storage sync issue, I/O delay | Wait a few seconds, verify storage is mounted |
|
||||||
|
| **225** | No template available for OS/Version | Unsupported OS version, catalog outdated | Run `pveam update`, check `pveam available -section system` |
|
||||||
|
|
||||||
|
### LXC Stack Errors (231)
|
||||||
|
|
||||||
|
| Code | Description | Common Causes | Solutions |
|
||||||
|
| ------- | ------------------------------ | ------------------------------------------- | -------------------------------------------- |
|
||||||
|
| **231** | LXC stack upgrade/retry failed | Outdated `pve-container`, Debian 13.1 issue | See [Debian 13.1 Fix Guide](#debian-131-fix) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Special Case: Debian 13.1 "unsupported version" Error
|
||||||
|
|
||||||
|
### Problem
|
||||||
|
|
||||||
|
```
|
||||||
|
TASK ERROR: unable to create CT 129 - unsupported debian version '13.1'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Root Cause
|
||||||
|
|
||||||
|
Outdated `pve-container` package doesn't recognize Debian 13 (Trixie).
|
||||||
|
|
||||||
|
### Solutions
|
||||||
|
|
||||||
|
#### Option 1: Full System Upgrade (Recommended)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt update
|
||||||
|
apt full-upgrade -y
|
||||||
|
reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify fix:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dpkg -l pve-container
|
||||||
|
# PVE 8: Should show 5.3.3+
|
||||||
|
# PVE 9: Should show 6.0.13+
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option 2: Update Only pve-container
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt update
|
||||||
|
apt install --only-upgrade pve-container -y
|
||||||
|
```
|
||||||
|
|
||||||
|
**Warning:** If Proxmox fails to boot after this, your system was inconsistent. Perform Option 1 instead.
|
||||||
|
|
||||||
|
#### Option 3: Verify Repository Configuration
|
||||||
|
|
||||||
|
Many users disable Enterprise repos but forget to add no-subscription repos.
|
||||||
|
|
||||||
|
**For PVE 9 (Trixie):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat /etc/apt/sources.list.d/pve-no-subscription.list
|
||||||
|
```
|
||||||
|
|
||||||
|
Should contain:
|
||||||
|
|
||||||
|
```
|
||||||
|
deb http://download.proxmox.com/debian/pve trixie pve-no-subscription
|
||||||
|
deb http://download.proxmox.com/debian/ceph-squid trixie no-subscription
|
||||||
|
```
|
||||||
|
|
||||||
|
**For PVE 8 (Bookworm):**
|
||||||
|
|
||||||
|
```
|
||||||
|
deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription
|
||||||
|
deb http://download.proxmox.com/debian/ceph-quincy bookworm no-subscription
|
||||||
|
```
|
||||||
|
|
||||||
|
Then:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt update
|
||||||
|
apt full-upgrade -y
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reference
|
||||||
|
|
||||||
|
Official discussion: [GitHub #8126](https://github.com/community-scripts/ProxmoxVE/discussions/8126)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting Tips
|
||||||
|
|
||||||
|
### Finding Error Details
|
||||||
|
|
||||||
|
1. **Check logs:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tail -n 50 /tmp/pct_create_*.log
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Enable verbose mode:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash -x script.sh # Shows every command executed
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Check container status:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pct list
|
||||||
|
pct status CTID
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Verify storage:**
|
||||||
|
```bash
|
||||||
|
pvesm status
|
||||||
|
df -h
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Patterns
|
||||||
|
|
||||||
|
- **Exit 0 with error message:** Configuration validation failed (check DNS, MAC, password format)
|
||||||
|
- **Exit 206 but container not visible:** Ghost container state - check `/etc/pve/lxc/` manually
|
||||||
|
- **Exit 209 generic error:** Check `/tmp/pct_create_*.log` for specific `pct create` failure reason
|
||||||
|
- **Exit 218 or 222:** Template issues - delete and re-download template
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference Chart
|
||||||
|
|
||||||
|
| Exit Code Range | Category | Typical Issue |
|
||||||
|
| --------------- | ------------------ | ------------------------------------------- |
|
||||||
|
| 1-2, 126-143 | Shell/System | Permissions, signals, missing commands |
|
||||||
|
| 100-101, 255 | Package Manager | APT/DPKG errors, broken packages |
|
||||||
|
| 200-209 | Container Creation | CTID, password, configuration |
|
||||||
|
| 210-217 | Storage/Cluster | Disk space, quorum, storage type |
|
||||||
|
| 218-225 | Templates | Download, corruption, availability |
|
||||||
|
| 231-254 | Databases/Runtime | PostgreSQL, MySQL, MongoDB, Node.js, Python |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Found an undocumented exit code or have a solution to share? Please:
|
||||||
|
|
||||||
|
1. Open an issue on [GitHub](https://github.com/community-scripts/ProxmoxVED/issues)
|
||||||
|
2. Include:
|
||||||
|
- Exit code number
|
||||||
|
- Error message
|
||||||
|
- Steps to reproduce
|
||||||
|
- Solution that worked for you
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Last updated: November 2025_
|
||||||
|
_ProxmoxVED Version: 2.x_
|
||||||
6
frontend/package-lock.json
generated
6
frontend/package-lock.json
generated
@ -10202,9 +10202,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "6.3.6",
|
"version": "6.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
|
||||||
"integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
|
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ComfyUI",
|
|
||||||
"slug": "comfyui",
|
|
||||||
"categories": [
|
|
||||||
20
|
|
||||||
],
|
|
||||||
"date_created": "2025-08-01",
|
|
||||||
"type": "ct",
|
|
||||||
"updateable": true,
|
|
||||||
"privileged": false,
|
|
||||||
"config_path": "/opt",
|
|
||||||
"interface_port": 8188,
|
|
||||||
"documentation": "https://github.com/comfyanonymous/ComfyUI",
|
|
||||||
"website": "https://www.comfy.org/",
|
|
||||||
"logo": "https://framerusercontent.com/images/3cNQMWKzIhIrQ5KErBm7dSmbd2w.png",
|
|
||||||
"description": "ComfyUI is a node-based interface and inference engine for generative AI. Users can combine various AI models and operations through nodes to achieve highly customizable and controllable content generation.",
|
|
||||||
"install_methods": [
|
|
||||||
{
|
|
||||||
"type": "default",
|
|
||||||
"script": "ct/comfyui.sh",
|
|
||||||
"resources": {
|
|
||||||
"cpu": 4,
|
|
||||||
"ram": 8192,
|
|
||||||
"hdd": 25,
|
|
||||||
"os": "debian",
|
|
||||||
"version": "13"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default_credentials": {
|
|
||||||
"username": null,
|
|
||||||
"password": null
|
|
||||||
},
|
|
||||||
"notes": [
|
|
||||||
{
|
|
||||||
"text": "Application takes long time to install. Please be patient!",
|
|
||||||
"type": "warning"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text": "Please check that you have installed the drivers for your GPU.",
|
|
||||||
"type": "info"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Dispatcharr",
|
|
||||||
"slug": "dispatcharr",
|
|
||||||
"categories": [
|
|
||||||
14
|
|
||||||
],
|
|
||||||
"date_created": "2025-07-01",
|
|
||||||
"type": "ct",
|
|
||||||
"updateable": true,
|
|
||||||
"privileged": false,
|
|
||||||
"interface_port": 9191,
|
|
||||||
"documentation": "https://dispatcharr.github.io/Dispatcharr-Docs/",
|
|
||||||
"website": "https://dispatcharr.github.io/Dispatcharr-Docs/",
|
|
||||||
"logo": "https://raw.githubusercontent.com/Dispatcharr/Dispatcharr/refs/heads/main/frontend/src/images/logo.png",
|
|
||||||
"config_path": "",
|
|
||||||
"description": "Dispatcharr is an open-source powerhouse for managing IPTV streams and EPG data with elegance and control. Born from necessity and built with passion, it started as a personal project by OkinawaBoss and evolved with contributions from legends like dekzter, SergeantPanda and Bucatini.",
|
|
||||||
"install_methods": [
|
|
||||||
{
|
|
||||||
"type": "default",
|
|
||||||
"script": "ct/dispatcharr.sh",
|
|
||||||
"resources": {
|
|
||||||
"cpu": 1,
|
|
||||||
"ram": 1024,
|
|
||||||
"hdd": 8,
|
|
||||||
"os": "debian",
|
|
||||||
"version": "12"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default_credentials": {
|
|
||||||
"username": null,
|
|
||||||
"password": null
|
|
||||||
},
|
|
||||||
"notes": []
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"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": []
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "LibreNMS",
|
|
||||||
"slug": "librenms",
|
|
||||||
"categories": [
|
|
||||||
9
|
|
||||||
],
|
|
||||||
"date_created": "2025-03-24",
|
|
||||||
"type": "ct",
|
|
||||||
"updateable": false,
|
|
||||||
"privileged": false,
|
|
||||||
"interface_port": 80,
|
|
||||||
"documentation": "https://docs.librenms.org/",
|
|
||||||
"website": "https://librenms.org/",
|
|
||||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/librenms.webp",
|
|
||||||
"config_path": "/opt/librenms/config.php and /opt/librenms/.env",
|
|
||||||
"description": "LibreNMS is an open-source, community-driven network monitoring system that provides automatic discovery, alerting, and performance tracking for network devices. It supports a wide range of hardware and integrates with various notification and logging platforms.",
|
|
||||||
"install_methods": [
|
|
||||||
{
|
|
||||||
"type": "default",
|
|
||||||
"script": "ct/librenms.sh",
|
|
||||||
"resources": {
|
|
||||||
"cpu": 2,
|
|
||||||
"ram": 2048,
|
|
||||||
"hdd": 4,
|
|
||||||
"os": "Debian",
|
|
||||||
"version": "12"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default_credentials": {
|
|
||||||
"username": "admin",
|
|
||||||
"password": "admin"
|
|
||||||
},
|
|
||||||
"notes": []
|
|
||||||
}
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Livebook",
|
|
||||||
"slug": "livebook",
|
|
||||||
"categories": [
|
|
||||||
20
|
|
||||||
],
|
|
||||||
"date_created": "2025-08-12",
|
|
||||||
"type": "ct",
|
|
||||||
"updateable": true,
|
|
||||||
"privileged": false,
|
|
||||||
"interface_port": 8080,
|
|
||||||
"documentation": null,
|
|
||||||
"config_path": "/opt/.env",
|
|
||||||
"website": "https://livebook.dev",
|
|
||||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/livebook.svg",
|
|
||||||
"description": "Elixir Livebook is an interactive, web-based notebook platform for Elixir that combines code, documentation, and visualizations in a single document. Similar to Jupyter notebooks, it allows developers to write and execute Elixir code in real-time, making it ideal for data exploration, prototyping, learning, and collaborative development. Livebook features rich markdown support, built-in charting capabilities, and seamless integration with the Elixir ecosystem.",
|
|
||||||
"install_methods": [
|
|
||||||
{
|
|
||||||
"type": "default",
|
|
||||||
"script": "ct/livebook.sh",
|
|
||||||
"resources": {
|
|
||||||
"cpu": 1,
|
|
||||||
"ram": 1024,
|
|
||||||
"hdd": 4,
|
|
||||||
"os": "Ubuntu",
|
|
||||||
"version": "24.04"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default_credentials": {
|
|
||||||
"username": null,
|
|
||||||
"password": null
|
|
||||||
},
|
|
||||||
"notes": [
|
|
||||||
{
|
|
||||||
"text": "Show Livebook password: `cat /opt/livebook.creds`",
|
|
||||||
"type": "info"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
35
frontend/public/json/metabase.json
Normal file
35
frontend/public/json/metabase.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "Metabase",
|
||||||
|
"slug": "metabase",
|
||||||
|
"categories": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
"date_created": "2025-09-04",
|
||||||
|
"type": "ct",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": false,
|
||||||
|
"interface_port": 3000,
|
||||||
|
"documentation": "https://www.metabase.com/docs/latest/",
|
||||||
|
"config_path": "/opt/metabase/.env",
|
||||||
|
"website": "https://www.metabase.com/",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/metabase.webp",
|
||||||
|
"description": "Metabase is an open-source business intelligence platform. You can use Metabase to ask questions about your data, or embed Metabase in your app to let your customers explore their data on their own.",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "ct/metabase.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": 2,
|
||||||
|
"ram": 2048,
|
||||||
|
"hdd": 6,
|
||||||
|
"os": "Debian",
|
||||||
|
"version": "13"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": null,
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"notes": []
|
||||||
|
}
|
||||||
@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Notesnook",
|
|
||||||
"slug": "notesnook",
|
|
||||||
"categories": [
|
|
||||||
12
|
|
||||||
],
|
|
||||||
"date_created": "2025-05-27",
|
|
||||||
"type": "ct",
|
|
||||||
"updateable": true,
|
|
||||||
"privileged": false,
|
|
||||||
"interface_port": 443,
|
|
||||||
"documentation": null,
|
|
||||||
"config_path": "/",
|
|
||||||
"website": "https://notesnook.com/",
|
|
||||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/notesnook.webp",
|
|
||||||
"description": "Notesnook is a free (as in speech) & open-source note-taking app focused on user privacy & ease of use. To ensure zero knowledge principles, Notesnook encrypts everything on your device using XChaCha20-Poly1305 & Argon2.",
|
|
||||||
"install_methods": [
|
|
||||||
{
|
|
||||||
"type": "default",
|
|
||||||
"script": "ct/notesnook.sh",
|
|
||||||
"resources": {
|
|
||||||
"cpu": 2,
|
|
||||||
"ram": 3072,
|
|
||||||
"hdd": 10,
|
|
||||||
"os": "Debian",
|
|
||||||
"version": "12"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default_credentials": {
|
|
||||||
"username": null,
|
|
||||||
"password": null
|
|
||||||
},
|
|
||||||
"notes": [
|
|
||||||
{
|
|
||||||
"text": "Before doing update of the app, please make a backup in the application Web UI. You will need to restore this backup after update finishes!",
|
|
||||||
"type": "warning"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "PatchMon",
|
|
||||||
"slug": "patchmon",
|
|
||||||
"categories": [
|
|
||||||
9
|
|
||||||
],
|
|
||||||
"date_created": "2025-10-23",
|
|
||||||
"type": "ct",
|
|
||||||
"updateable": true,
|
|
||||||
"privileged": false,
|
|
||||||
"interface_port": 3399,
|
|
||||||
"documentation": "https://docs.patchmon.net",
|
|
||||||
"website": "https://patchmon.net",
|
|
||||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/patchmon.webp",
|
|
||||||
"config_path": "/opt/patchmon/backend/.env, /opt/patchmon/frontend/.env",
|
|
||||||
"description": "Monitor Linux patches across all your hosts with real-time visibility, security update tracking, and comprehensive package management.",
|
|
||||||
"install_methods": [
|
|
||||||
{
|
|
||||||
"type": "default",
|
|
||||||
"script": "ct/patchmon.sh",
|
|
||||||
"resources": {
|
|
||||||
"cpu": 2,
|
|
||||||
"ram": 2048,
|
|
||||||
"hdd": 4,
|
|
||||||
"os": "debian",
|
|
||||||
"version": "13"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default_credentials": {
|
|
||||||
"username": null,
|
|
||||||
"password": null
|
|
||||||
},
|
|
||||||
"notes": []
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"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": []
|
|
||||||
}
|
|
||||||
46
frontend/public/json/qbittorrent-exporter.json
Normal file
46
frontend/public/json/qbittorrent-exporter.json
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"name": "qbittorrent Exporter",
|
||||||
|
"slug": "qbittorrent-exporter",
|
||||||
|
"categories": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
"date_created": "2025-11-21",
|
||||||
|
"type": "addon",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": false,
|
||||||
|
"interface_port": 8090,
|
||||||
|
"documentation": "https://github.com/martabal/qbittorrent-exporter",
|
||||||
|
"website": "https://github.com/martabal/qbittorrent-exporter",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/qbittorrent.webp",
|
||||||
|
"config_path": "/opt/qbittorrent-exporter.env",
|
||||||
|
"description": "A fast and lightweight prometheus exporter for qBittorrent ",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "tools/addon/qbittorrent-exporter.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": null,
|
||||||
|
"ram": null,
|
||||||
|
"hdd": null,
|
||||||
|
"os": null,
|
||||||
|
"version": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "alpine",
|
||||||
|
"script": "tools/addon/qbittorrent-exporter.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": null,
|
||||||
|
"ram": null,
|
||||||
|
"hdd": null,
|
||||||
|
"os": null,
|
||||||
|
"version": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": null,
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"notes": []
|
||||||
|
}
|
||||||
35
frontend/public/json/snowshare.json
Normal file
35
frontend/public/json/snowshare.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "SnowShare",
|
||||||
|
"slug": "snowshare",
|
||||||
|
"categories": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"date_created": "2025-09-24",
|
||||||
|
"type": "ct",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": false,
|
||||||
|
"interface_port": 3000,
|
||||||
|
"documentation": "https://github.com/TuroYT/snowshare",
|
||||||
|
"config_path": "/opt/snowshare/.env",
|
||||||
|
"website": "https://github.com/TuroYT/snowshare",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/png/snowshare.png",
|
||||||
|
"description": "A modern, secure file and link sharing platform built with Next.js, Prisma, and NextAuth. Share URLs, code snippets, and files with customizable expiration, privacy, and QR codes.",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "ct/snowshare.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": 1,
|
||||||
|
"ram": 1024,
|
||||||
|
"hdd": 5,
|
||||||
|
"os": "Debian",
|
||||||
|
"version": "13"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": null,
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"notes": []
|
||||||
|
}
|
||||||
@ -58,8 +58,8 @@ export const OperatingSystems: OperatingSystem[] = [
|
|||||||
{
|
{
|
||||||
name: "Debian",
|
name: "Debian",
|
||||||
versions: [
|
versions: [
|
||||||
{ name: "11", slug: "bullseye" },
|
|
||||||
{ name: "12", slug: "bookworm" },
|
{ name: "12", slug: "bookworm" },
|
||||||
|
{ name: "13", slug: "trixie" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,98 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
|
||||||
# Author: MickLesk (CanbiZ)
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://garagehq.deuxfleurs.fr/
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
msg_info "Preparing directories"
|
|
||||||
mkdir -p /var/lib/garage/meta /var/lib/garage/data /var/lib/garage/snapshots
|
|
||||||
msg_ok "Prepared directories"
|
|
||||||
|
|
||||||
msg_info "Setup Garage packages"
|
|
||||||
$STD apk add --no-cache garage garage-openrc openssl
|
|
||||||
msg_ok "Setup Garage packages"
|
|
||||||
|
|
||||||
# msg_info "Generating RPC secret"
|
|
||||||
# if [[ ! -s /etc/garage.rpc_secret ]]; then
|
|
||||||
# openssl rand -hex 32 | tr -d '\n' >/etc/garage.rpc_secret
|
|
||||||
# chmod 600 /etc/garage.rpc_secret
|
|
||||||
# fi
|
|
||||||
# msg_ok "Generated RPC secret"
|
|
||||||
|
|
||||||
# msg_info "Generating tokens"
|
|
||||||
# if [[ ! -s /etc/garage.tokens.env ]]; then
|
|
||||||
# ADMIN_TOKEN="$(openssl rand -base64 32)"
|
|
||||||
# METRICS_TOKEN="$(openssl rand -base64 32)"
|
|
||||||
# cat >/etc/garage.tokens.env <<EOF
|
|
||||||
# GARAGE_ADMIN_TOKEN="${ADMIN_TOKEN}"
|
|
||||||
# GARAGE_METRICS_TOKEN="${METRICS_TOKEN}"
|
|
||||||
# EOF
|
|
||||||
# chmod 600 /etc/garage.tokens.env
|
|
||||||
# else
|
|
||||||
# source /etc/garage.tokens.env
|
|
||||||
# ADMIN_TOKEN="${GARAGE_ADMIN_TOKEN}"
|
|
||||||
# METRICS_TOKEN="${GARAGE_METRICS_TOKEN}"
|
|
||||||
# fi
|
|
||||||
# msg_ok "Generated tokens"
|
|
||||||
|
|
||||||
msg_info "Writing config"
|
|
||||||
if [[ ! -f /etc/garage.toml ]]; then
|
|
||||||
cat >/etc/garage.toml <<EOF
|
|
||||||
replication_factor = 1
|
|
||||||
consistency_mode = "consistent"
|
|
||||||
|
|
||||||
metadata_dir = "/var/lib/garage/meta"
|
|
||||||
data_dir = "/var/lib/garage/data"
|
|
||||||
metadata_snapshots_dir = "/var/lib/garage/snapshots"
|
|
||||||
|
|
||||||
db_engine = "lmdb"
|
|
||||||
metadata_fsync = true
|
|
||||||
data_fsync = false
|
|
||||||
metadata_auto_snapshot_interval = "6h"
|
|
||||||
|
|
||||||
rpc_bind_addr = "0.0.0.0:3901"
|
|
||||||
rpc_public_addr = "127.0.0.1:3901"
|
|
||||||
allow_world_readable_secrets = false
|
|
||||||
|
|
||||||
[s3_api]
|
|
||||||
api_bind_addr = "0.0.0.0:3900"
|
|
||||||
s3_region = "garage"
|
|
||||||
root_domain = ".s3.garage"
|
|
||||||
|
|
||||||
[s3_web]
|
|
||||||
bind_addr = "0.0.0.0:3902"
|
|
||||||
root_domain = ".web.garage"
|
|
||||||
add_host_to_metrics = true
|
|
||||||
|
|
||||||
[admin]
|
|
||||||
api_bind_addr = "0.0.0.0:3903"
|
|
||||||
metrics_require_token = false
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
msg_ok "Wrote config"
|
|
||||||
|
|
||||||
msg_info "Enable + start service"
|
|
||||||
$STD rc-update add garage default
|
|
||||||
$STD rc-service garage restart || $STD rc-service garage start
|
|
||||||
$STD rc-service garage status || true
|
|
||||||
msg_ok "Service active"
|
|
||||||
|
|
||||||
msg_info "Setup Node"
|
|
||||||
garage node id
|
|
||||||
NODE_ID=$(garage node id | cut -d@ -f1)
|
|
||||||
garage layout assign $NODE_ID --capacity 1T
|
|
||||||
garage layout apply
|
|
||||||
garage status
|
|
||||||
msg_ok "Node setup"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
@ -21,7 +21,6 @@ $STD apk add nano
|
|||||||
$STD apk add mc
|
$STD apk add mc
|
||||||
msg_ok "Installed Dependencies"
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "redlib" "redlib-org/redlib" "prebuild" "latest" "/opt/redlib" "redlib-x86_64-unknown-linux-musl.tar.gz"
|
|
||||||
|
|
||||||
motd_ssh
|
motd_ssh
|
||||||
customize
|
customize
|
||||||
|
|||||||
@ -1,87 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
|
||||||
# Author: jdacode
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://github.com/comfyanonymous/ComfyUI
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "${TAB3}Choose the GPU type for ComfyUI:"
|
|
||||||
echo "${TAB3}[1]-None [2]-NVIDIA [3]-AMD [4]-Intel"
|
|
||||||
read -rp "${TAB3}Enter your choice [1-4] (default: 1): " gpu_choice
|
|
||||||
gpu_choice=${gpu_choice:-1}
|
|
||||||
case "$gpu_choice" in
|
|
||||||
1) comfyui_gpu_type="none";;
|
|
||||||
2) comfyui_gpu_type="nvidia";;
|
|
||||||
3) comfyui_gpu_type="amd";;
|
|
||||||
4) comfyui_gpu_type="intel";;
|
|
||||||
*) comfyui_gpu_type="none"; echo "${TAB3}Invalid choice. Defaulting to ${comfyui_gpu_type}." ;;
|
|
||||||
esac
|
|
||||||
echo
|
|
||||||
|
|
||||||
PYTHON_VERSION="3.12" setup_uv
|
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "ComfyUI" "comfyanonymous/ComfyUI" "tarball" "latest" "/opt/ComfyUI"
|
|
||||||
|
|
||||||
msg_info "Python dependencies"
|
|
||||||
$STD uv venv "/opt/ComfyUI/venv"
|
|
||||||
if [[ "${comfyui_gpu_type,,}" == "nvidia" ]]; then
|
|
||||||
$STD uv pip install \
|
|
||||||
torch \
|
|
||||||
torchvision \
|
|
||||||
torchaudio \
|
|
||||||
--extra-index-url "https://download.pytorch.org/whl/cu128" \
|
|
||||||
--python="/opt/ComfyUI/venv/bin/python"
|
|
||||||
elif [[ "${comfyui_gpu_type,,}" == "amd" ]]; then
|
|
||||||
$STD uv pip install \
|
|
||||||
torch \
|
|
||||||
torchvision \
|
|
||||||
torchaudio \
|
|
||||||
--index-url "https://download.pytorch.org/whl/rocm6.3" \
|
|
||||||
--python="/opt/ComfyUI/venv/bin/python"
|
|
||||||
elif [[ "${comfyui_gpu_type,,}" == "intel" ]]; then
|
|
||||||
$STD uv pip install \
|
|
||||||
torch \
|
|
||||||
torchvision \
|
|
||||||
torchaudio \
|
|
||||||
--index-url "https://download.pytorch.org/whl/xpu" \
|
|
||||||
--python="/opt/ComfyUI/venv/bin/python"
|
|
||||||
fi
|
|
||||||
$STD uv pip install -r "/opt/ComfyUI/requirements.txt" --python="/opt/ComfyUI/venv/bin/python"
|
|
||||||
msg_ok "Python dependencies"
|
|
||||||
|
|
||||||
msg_info "Creating Service"
|
|
||||||
cat <<EOF >/etc/systemd/system/comfyui.service
|
|
||||||
[Unit]
|
|
||||||
Description=ComfyUI Service
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=root
|
|
||||||
WorkingDirectory=/opt/ComfyUI
|
|
||||||
ExecStart=/opt/ComfyUI/venv/bin/python /opt/ComfyUI/main.py --listen --port 8188 --cpu
|
|
||||||
Restart=on-failure
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
systemctl enable -q --now comfyui
|
|
||||||
msg_ok "Created Service"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt -y autoremove
|
|
||||||
$STD apt -y autoclean
|
|
||||||
$STD apt -y clean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
74
install/cronmaster-install.sh
Normal file
74
install/cronmaster-install.sh
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
|
# Author: Slaviša Arežina (tremor021)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/fccview/cronmaster
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
msg_info "Installing dependencies"
|
||||||
|
$STD apt install -y pciutils
|
||||||
|
msg_ok "Installed dependencies"
|
||||||
|
|
||||||
|
NODE_VERSION="24" NODE_MODULE="yarn" setup_nodejs
|
||||||
|
|
||||||
|
setup_deb822_repo \
|
||||||
|
"docker" \
|
||||||
|
"https://download.docker.com/linux/debian/gpg" \
|
||||||
|
"https://download.docker.com/linux/debian" \
|
||||||
|
"trixie" \
|
||||||
|
"stable"
|
||||||
|
$STD apt install -y docker-ce-cli
|
||||||
|
fetch_and_deploy_gh_release "cronmaster" "fccview/cronmaster" "tarball"
|
||||||
|
|
||||||
|
msg_info "Setting up CronMaster"
|
||||||
|
AUTH_PASS="$(openssl rand -base64 18 | cut -c1-13)"
|
||||||
|
cd /opt/cronmaster
|
||||||
|
$STD yarn --frozen-lockfile
|
||||||
|
export NEXT_TELEMETRY_DISABLED=1
|
||||||
|
$STD yarn build
|
||||||
|
cat <<EOF >/opt/cronmaster/.env
|
||||||
|
NODE_ENV=production
|
||||||
|
APP_URL=
|
||||||
|
LOCALE=
|
||||||
|
HOME=
|
||||||
|
AUTH_PASSWORD=${AUTH_PASS}
|
||||||
|
PORT=3000
|
||||||
|
HOSTNAME="0.0.0.0"
|
||||||
|
NEXT_TELEMETRY_DISABLED=1
|
||||||
|
EOF
|
||||||
|
{
|
||||||
|
echo "CronMaster Credentials:"
|
||||||
|
echo ""
|
||||||
|
echo "Password: $AUTH_PASS"
|
||||||
|
}>>~/cronmaster.creds
|
||||||
|
msg_ok "Setup CronMaster"
|
||||||
|
|
||||||
|
msg_info "Creating Service"
|
||||||
|
cat <<EOF >/etc/systemd/system/cronmaster.service
|
||||||
|
[Unit]
|
||||||
|
Description=CronMaster Service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
EnvironmentFile=/opt/cronmaster/.env
|
||||||
|
WorkingDirectory=/opt/cronmaster
|
||||||
|
ExecStart=/usr/bin/yarn start
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl start --now -q cronmaster
|
||||||
|
msg_info "Created Service"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
@ -1,10 +1,9 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
# Author: Test Suite for tools.func
|
# 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:
|
||||||
# Purpose: Run comprehensive test suite for all setup_* functions from tools.func
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
color
|
color
|
||||||
@ -18,14 +17,10 @@ msg_info "Installing Base Dependencies"
|
|||||||
$STD apt-get install -y curl wget ca-certificates
|
$STD apt-get install -y curl wget ca-certificates
|
||||||
msg_ok "Installed Base Dependencies"
|
msg_ok "Installed Base Dependencies"
|
||||||
|
|
||||||
msg_info "Downloading and executing tools.func test suite"
|
# msg_info "Downloading and executing tools.func test suite"
|
||||||
bash <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/test-tools-func.sh)
|
# bash <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/test-tools-func.sh)
|
||||||
msg_ok "Test suite completed"
|
# msg_ok "Test suite completed"
|
||||||
|
|
||||||
motd_ssh
|
motd_ssh
|
||||||
customize
|
customize
|
||||||
|
cleanup_lxc
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt-get -y autoremove
|
|
||||||
$STD apt-get -y autoclean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
|
|||||||
@ -1,79 +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://hanko.io/
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
setup_yq
|
|
||||||
PG_VERSION="16" setup_postgresql
|
|
||||||
NODE_VERSION=22 NODE_MODULE="yarn@latest,npm@latest" setup_nodejs
|
|
||||||
|
|
||||||
msg_info "Setting up PostgreSQL Database"
|
|
||||||
DB_NAME=hanko
|
|
||||||
DB_USER=hanko
|
|
||||||
DB_PASS="$(openssl rand -base64 18 | cut -c1-13)"
|
|
||||||
APP_SECRET=$(openssl rand -base64 32)
|
|
||||||
$STD sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';"
|
|
||||||
$STD sudo -u postgres psql -c "CREATE DATABASE $DB_NAME WITH OWNER $DB_USER ENCODING 'UTF8' TEMPLATE template0;"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET client_encoding TO 'utf8';"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET default_transaction_isolation TO 'read committed';"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC'"
|
|
||||||
{
|
|
||||||
echo "Hanko-Credentials"
|
|
||||||
echo "Hanko Database User: $DB_USER"
|
|
||||||
echo "Hanko Database Password: $DB_PASS"
|
|
||||||
echo "Hanko Database Name: $DB_NAME"
|
|
||||||
} >>~/hanko.creds
|
|
||||||
msg_ok "Set up PostgreSQL Database"
|
|
||||||
|
|
||||||
msg_info "Setup Hanko"
|
|
||||||
fetch_and_deploy_gh_release "hanko" "teamhanko/hanko" "prebuild" "latest" "/opt/hanko" "hanko_Linux_x86_64.tar.gz"
|
|
||||||
curl -fsSL https://raw.githubusercontent.com/teamhanko/hanko/refs/heads/main/backend/config/config.yaml -o /opt/hanko/config.yaml
|
|
||||||
env DB_USER="$DB_USER" DB_PASS="$DB_PASS" APP_SECRET="$APP_SECRET" \
|
|
||||||
yq eval '
|
|
||||||
.database.user = strenv(DB_USER) |
|
|
||||||
.database.password = strenv(DB_PASS) |
|
|
||||||
.database.host = "localhost" |
|
|
||||||
.database.port = "5432" |
|
|
||||||
.database.dialect = "postgres" |
|
|
||||||
.app.secret = strenv(APP_SECRET)
|
|
||||||
' -i /opt/hanko/config.yaml
|
|
||||||
$STD /opt/hanko/hanko --config /opt/hanko/config.yaml migrate up
|
|
||||||
yarn add @teamhanko/hanko-elements
|
|
||||||
msg_ok "Setup Hanko"
|
|
||||||
|
|
||||||
msg_info "Setup Service"
|
|
||||||
cat <<EOF >/etc/systemd/system/hanko.service
|
|
||||||
[Unit]
|
|
||||||
Description=Hanko Service
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
ExecStart=/opt/hanko/hanko serve all --config /opt/hanko/config.yaml
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=5
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
|
|
||||||
systemctl enable -q --now hanko
|
|
||||||
msg_ok "Service Setup"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt-get -y autoremove
|
|
||||||
$STD apt-get -y autoclean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
@ -1,266 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
|
||||||
# Author: ekke85
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://github.com/Dispatcharr/Dispatcharr
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
msg_info "Installing Dependencies"
|
|
||||||
$STD apt install -y \
|
|
||||||
build-essential \
|
|
||||||
gcc \
|
|
||||||
python3-dev \
|
|
||||||
libpq-dev \
|
|
||||||
nginx \
|
|
||||||
redis-server \
|
|
||||||
ffmpeg \
|
|
||||||
procps \
|
|
||||||
streamlink
|
|
||||||
msg_ok "Installed Dependencies"
|
|
||||||
|
|
||||||
setup_uv
|
|
||||||
NODE_VERSION="24" setup_nodejs
|
|
||||||
PG_VERSION="16" setup_postgresql
|
|
||||||
|
|
||||||
msg_info "Creating PostgreSQL Database"
|
|
||||||
DB_NAME=dispatcharr_db
|
|
||||||
DB_USER=dispatcharr_usr
|
|
||||||
DB_PASS="$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)"
|
|
||||||
$STD sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';"
|
|
||||||
$STD sudo -u postgres psql -c "CREATE DATABASE $DB_NAME WITH OWNER $DB_USER ENCODING 'UTF8' TEMPLATE template0;"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET client_encoding TO 'utf8';"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET default_transaction_isolation TO 'read committed';"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC';"
|
|
||||||
|
|
||||||
cat <<EOF >~/dispatcharr.creds
|
|
||||||
Dispatcharr-Credentials
|
|
||||||
Dispatcharr Database Name: $DB_NAME
|
|
||||||
Dispatcharr Database User: $DB_USER
|
|
||||||
Dispatcharr Database Password: $DB_PASS
|
|
||||||
EOF
|
|
||||||
msg_ok "Created PostgreSQL Database"
|
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "dispatcharr" "Dispatcharr/Dispatcharr"
|
|
||||||
|
|
||||||
msg_info "Installing Python Dependencies with uv"
|
|
||||||
cd /opt/dispatcharr || exit
|
|
||||||
|
|
||||||
$STD uv venv
|
|
||||||
$STD uv pip install -r requirements.txt --index-strategy unsafe-best-match
|
|
||||||
$STD uv pip install gunicorn gevent celery redis daphne
|
|
||||||
msg_ok "Installed Python Dependencies"
|
|
||||||
|
|
||||||
msg_info "Configuring Dispatcharr"
|
|
||||||
export DATABASE_URL="postgresql://${DB_USER}:${DB_PASS}@localhost:5432/${DB_NAME}"
|
|
||||||
export POSTGRES_DB=$DB_NAME
|
|
||||||
export POSTGRES_USER=$DB_USER
|
|
||||||
export POSTGRES_PASSWORD=$DB_PASS
|
|
||||||
export POSTGRES_HOST=localhost
|
|
||||||
$STD uv run python manage.py migrate --noinput
|
|
||||||
$STD uv run python manage.py collectstatic --noinput
|
|
||||||
cat <<EOF >/opt/dispatcharr/.env
|
|
||||||
DATABASE_URL=postgresql://${DB_USER}:${DB_PASS}@localhost:5432/${DB_NAME}
|
|
||||||
POSTGRES_DB=$DB_NAME
|
|
||||||
POSTGRES_USER=$DB_USER
|
|
||||||
POSTGRES_PASSWORD=$DB_PASS
|
|
||||||
POSTGRES_HOST=localhost
|
|
||||||
CELERY_BROKER_URL=redis://localhost:6379/0
|
|
||||||
EOF
|
|
||||||
cd /opt/dispatcharr/frontend || exit
|
|
||||||
$STD npm install --legacy-peer-deps
|
|
||||||
$STD npm run build
|
|
||||||
msg_ok "Configured Dispatcharr"
|
|
||||||
|
|
||||||
msg_info "Configuring Nginx"
|
|
||||||
cat <<EOF >/etc/nginx/sites-available/dispatcharr.conf
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name _;
|
|
||||||
|
|
||||||
# Serve static assets with correct MIME types
|
|
||||||
location /assets/ {
|
|
||||||
alias /opt/dispatcharr/frontend/dist/assets/;
|
|
||||||
expires 30d;
|
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
|
|
||||||
# Explicitly set MIME types for webpack-built assets
|
|
||||||
types {
|
|
||||||
text/javascript js;
|
|
||||||
text/css css;
|
|
||||||
image/png png;
|
|
||||||
image/svg+xml svg svgz;
|
|
||||||
font/woff2 woff2;
|
|
||||||
font/woff woff;
|
|
||||||
font/ttf ttf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
location /static/ {
|
|
||||||
alias /opt/dispatcharr/static/;
|
|
||||||
expires 30d;
|
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
}
|
|
||||||
|
|
||||||
location /media/ {
|
|
||||||
alias /opt/dispatcharr/media/;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /ws/ {
|
|
||||||
proxy_pass http://127.0.0.1:8001;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade \$http_upgrade;
|
|
||||||
proxy_set_header Connection "Upgrade";
|
|
||||||
proxy_set_header Host \$host;
|
|
||||||
proxy_set_header X-Real-IP \$remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
# All other requests proxy to Gunicorn
|
|
||||||
location / {
|
|
||||||
include proxy_params;
|
|
||||||
proxy_pass http://127.0.0.1:5656;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
ln -sf /etc/nginx/sites-available/dispatcharr.conf /etc/nginx/sites-enabled/dispatcharr.conf
|
|
||||||
rm -f /etc/nginx/sites-enabled/default
|
|
||||||
systemctl restart nginx
|
|
||||||
msg_ok "Configured Nginx"
|
|
||||||
|
|
||||||
msg_info "Creating Services"
|
|
||||||
cat <<EOF >/opt/dispatcharr/start-gunicorn.sh
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
cd /opt/dispatcharr
|
|
||||||
set -a
|
|
||||||
source .env
|
|
||||||
set +a
|
|
||||||
exec uv run gunicorn \\
|
|
||||||
--workers=4 \\
|
|
||||||
--worker-class=gevent \\
|
|
||||||
--timeout=300 \\
|
|
||||||
--bind 0.0.0.0:5656 \\
|
|
||||||
dispatcharr.wsgi:application
|
|
||||||
EOF
|
|
||||||
chmod +x /opt/dispatcharr/start-gunicorn.sh
|
|
||||||
|
|
||||||
cat <<EOF >/opt/dispatcharr/start-celery.sh
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
cd /opt/dispatcharr
|
|
||||||
set -a
|
|
||||||
source .env
|
|
||||||
set +a
|
|
||||||
exec uv run celery -A dispatcharr worker -l info -c 4
|
|
||||||
EOF
|
|
||||||
chmod +x /opt/dispatcharr/start-celery.sh
|
|
||||||
|
|
||||||
cat <<EOF >/opt/dispatcharr/start-celerybeat.sh
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
cd /opt/dispatcharr
|
|
||||||
set -a
|
|
||||||
source .env
|
|
||||||
set +a
|
|
||||||
exec uv run celery -A dispatcharr beat -l info
|
|
||||||
EOF
|
|
||||||
chmod +x /opt/dispatcharr/start-celerybeat.sh
|
|
||||||
|
|
||||||
cat <<EOF >/opt/dispatcharr/start-daphne.sh
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
cd /opt/dispatcharr
|
|
||||||
set -a
|
|
||||||
source .env
|
|
||||||
set +a
|
|
||||||
exec uv run daphne -b 0.0.0.0 -p 8001 dispatcharr.asgi:application
|
|
||||||
EOF
|
|
||||||
chmod +x /opt/dispatcharr/start-daphne.sh
|
|
||||||
|
|
||||||
cat <<EOF >/etc/systemd/system/dispatcharr.service
|
|
||||||
[Unit]
|
|
||||||
Description=Dispatcharr Web Server
|
|
||||||
After=network.target postgresql.service redis-server.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
WorkingDirectory=/opt/dispatcharr
|
|
||||||
ExecStart=/opt/dispatcharr/start-gunicorn.sh
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=10
|
|
||||||
User=root
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat <<EOF >/etc/systemd/system/dispatcharr-celery.service
|
|
||||||
[Unit]
|
|
||||||
Description=Dispatcharr Celery Worker
|
|
||||||
After=network.target redis-server.service
|
|
||||||
Requires=dispatcharr.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
WorkingDirectory=/opt/dispatcharr
|
|
||||||
ExecStart=/opt/dispatcharr/start-celery.sh
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=10
|
|
||||||
User=root
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat <<EOF >/etc/systemd/system/dispatcharr-celerybeat.service
|
|
||||||
[Unit]
|
|
||||||
Description=Dispatcharr Celery Beat Scheduler
|
|
||||||
After=network.target redis-server.service
|
|
||||||
Requires=dispatcharr.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
WorkingDirectory=/opt/dispatcharr
|
|
||||||
ExecStart=/opt/dispatcharr/start-celerybeat.sh
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=10
|
|
||||||
User=root
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat <<EOF >/etc/systemd/system/dispatcharr-daphne.service
|
|
||||||
[Unit]
|
|
||||||
Description=Dispatcharr WebSocket Server (Daphne)
|
|
||||||
After=network.target
|
|
||||||
Requires=dispatcharr.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
WorkingDirectory=/opt/dispatcharr
|
|
||||||
ExecStart=/opt/dispatcharr/start-daphne.sh
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=10
|
|
||||||
User=root
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
systemctl enable -q --now dispatcharr dispatcharr-celery dispatcharr-celerybeat dispatcharr-daphne
|
|
||||||
msg_ok "Created Services"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt -y autoremove
|
|
||||||
$STD apt -y autoclean
|
|
||||||
$STD apt -y clean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
121
install/docker-install.sh
Normal file
121
install/docker-install.sh
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#!/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://www.docker.com/
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
# Apply AppArmor workaround BEFORE installing Docker
|
||||||
|
# See: https://github.com/opencontainers/runc/issues/4968
|
||||||
|
apply_docker_apparmor_workaround
|
||||||
|
|
||||||
|
get_latest_release() {
|
||||||
|
curl -fsSL https://api.github.com/repos/"$1"/releases/latest | grep '"tag_name":' | cut -d'"' -f4
|
||||||
|
}
|
||||||
|
|
||||||
|
DOCKER_LATEST_VERSION=$(get_latest_release "moby/moby")
|
||||||
|
PORTAINER_LATEST_VERSION=$(get_latest_release "portainer/portainer")
|
||||||
|
PORTAINER_AGENT_LATEST_VERSION=$(get_latest_release "portainer/agent")
|
||||||
|
DOCKER_COMPOSE_LATEST_VERSION=$(get_latest_release "docker/compose")
|
||||||
|
|
||||||
|
msg_info "Installing Docker $DOCKER_LATEST_VERSION"
|
||||||
|
DOCKER_CONFIG_PATH='/etc/docker/daemon.json'
|
||||||
|
mkdir -p $(dirname $DOCKER_CONFIG_PATH)
|
||||||
|
echo -e '{\n "log-driver": "journald"\n}' >/etc/docker/daemon.json
|
||||||
|
$STD sh <(curl -fsSL https://get.docker.com)
|
||||||
|
msg_ok "Installed Docker $DOCKER_LATEST_VERSION"
|
||||||
|
|
||||||
|
# Restart Docker to apply AppArmor workaround (if running in LXC)
|
||||||
|
$STD systemctl restart docker
|
||||||
|
|
||||||
|
read -r -p "${TAB3}Install Docker Compose v2 plugin? <y/N> " prompt_compose
|
||||||
|
if [[ ${prompt_compose,,} =~ ^(y|yes)$ ]]; then
|
||||||
|
msg_info "Installing Docker Compose $DOCKER_COMPOSE_LATEST_VERSION"
|
||||||
|
mkdir -p /usr/local/lib/docker/cli-plugins
|
||||||
|
curl -fsSL "https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_LATEST_VERSION}/docker-compose-$(uname -s)-$(uname -m)" \
|
||||||
|
-o /usr/local/lib/docker/cli-plugins/docker-compose
|
||||||
|
chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
|
||||||
|
msg_ok "Installed Docker Compose $DOCKER_COMPOSE_LATEST_VERSION"
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -r -p "${TAB3}Would you like to add Portainer (UI)? <y/N> " prompt
|
||||||
|
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
|
||||||
|
msg_info "Installing Portainer $PORTAINER_LATEST_VERSION"
|
||||||
|
docker volume create portainer_data >/dev/null
|
||||||
|
$STD docker run -d \
|
||||||
|
-p 8000:8000 \
|
||||||
|
-p 9443:9443 \
|
||||||
|
--name=portainer \
|
||||||
|
--restart=always \
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
-v portainer_data:/data \
|
||||||
|
portainer/portainer-ce:latest
|
||||||
|
msg_ok "Installed Portainer $PORTAINER_LATEST_VERSION"
|
||||||
|
else
|
||||||
|
read -r -p "${TAB3}Would you like to install the Portainer Agent (for remote management)? <y/N> " prompt_agent
|
||||||
|
if [[ ${prompt_agent,,} =~ ^(y|yes)$ ]]; then
|
||||||
|
msg_info "Installing Portainer Agent $PORTAINER_AGENT_LATEST_VERSION"
|
||||||
|
$STD docker run -d \
|
||||||
|
-p 9001:9001 \
|
||||||
|
--name portainer_agent \
|
||||||
|
--restart=always \
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
-v /var/lib/docker/volumes:/var/lib/docker/volumes \
|
||||||
|
portainer/agent
|
||||||
|
msg_ok "Installed Portainer Agent $PORTAINER_AGENT_LATEST_VERSION"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -r -p "${TAB3}Expose Docker TCP socket (insecure) ? [n = No, l = Local only (127.0.0.1), a = All interfaces (0.0.0.0)] <n/l/a>: " socket_choice
|
||||||
|
case "${socket_choice,,}" in
|
||||||
|
l)
|
||||||
|
socket="tcp://127.0.0.1:2375"
|
||||||
|
;;
|
||||||
|
a)
|
||||||
|
socket="tcp://0.0.0.0:2375"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
socket=""
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ -n "$socket" ]]; then
|
||||||
|
msg_info "Enabling Docker TCP socket on $socket"
|
||||||
|
$STD apt-get install -y jq
|
||||||
|
|
||||||
|
tmpfile=$(mktemp)
|
||||||
|
jq --arg sock "$socket" '. + { "hosts": ["unix:///var/run/docker.sock", $sock] }' /etc/docker/daemon.json >"$tmpfile" && mv "$tmpfile" /etc/docker/daemon.json
|
||||||
|
|
||||||
|
mkdir -p /etc/systemd/system/docker.service.d
|
||||||
|
cat <<EOF >/etc/systemd/system/docker.service.d/override.conf
|
||||||
|
[Service]
|
||||||
|
ExecStart=
|
||||||
|
ExecStart=/usr/bin/dockerd
|
||||||
|
EOF
|
||||||
|
|
||||||
|
$STD systemctl daemon-reexec
|
||||||
|
$STD systemctl daemon-reload
|
||||||
|
|
||||||
|
if systemctl restart docker; then
|
||||||
|
msg_ok "Docker TCP socket available on $socket"
|
||||||
|
else
|
||||||
|
msg_error "Docker failed to restart. Check journalctl -xeu docker.service"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
|
||||||
|
msg_info "Cleaning up"
|
||||||
|
$STD apt-get -y autoremove
|
||||||
|
$STD apt-get -y autoclean
|
||||||
|
msg_ok "Cleaned"
|
||||||
@ -19,13 +19,17 @@ $STD apt-get install -y \
|
|||||||
libsodium-dev \
|
libsodium-dev \
|
||||||
pkg-config \
|
pkg-config \
|
||||||
caddy \
|
caddy \
|
||||||
gcc
|
gcc \
|
||||||
|
curl \
|
||||||
|
jq
|
||||||
msg_ok "Installed Dependencies"
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
PG_VERSION="17" setup_postgresql
|
PG_VERSION="17" setup_postgresql
|
||||||
setup_go
|
setup_go
|
||||||
NODE_VERSION="24" NODE_MODULE="yarn" setup_nodejs
|
NODE_VERSION="24" NODE_MODULE="yarn" setup_nodejs
|
||||||
|
ENTE_CLI_VERSION=$(curl -s https://api.github.com/repos/ente-io/ente/releases | jq -r '[.[] | select(.tag_name | startswith("cli-v"))][0].tag_name')
|
||||||
fetch_and_deploy_gh_release "ente" "ente-io/ente" "tarball" "latest" "/opt/ente"
|
fetch_and_deploy_gh_release "ente" "ente-io/ente" "tarball" "latest" "/opt/ente"
|
||||||
|
fetch_and_deploy_gh_release "ente" "ente-io/ente" "tarball" "$ENTE_CLI_VERSION" "/usr/local/bin/ente" "ente-cli-$ENTE_CLI_VERSION-linux-amd64.tar.gz"
|
||||||
|
|
||||||
msg_info "Setting up PostgreSQL"
|
msg_info "Setting up PostgreSQL"
|
||||||
DB_NAME="ente_db"
|
DB_NAME="ente_db"
|
||||||
@ -41,6 +45,24 @@ $STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC';"
|
|||||||
echo "Database Name: $DB_NAME"
|
echo "Database Name: $DB_NAME"
|
||||||
echo "Database User: $DB_USER"
|
echo "Database User: $DB_USER"
|
||||||
echo "Database Password: $DB_PASS"
|
echo "Database Password: $DB_PASS"
|
||||||
|
echo ""
|
||||||
|
echo "Important Configuration Notes:"
|
||||||
|
echo "- Frontend is built with IP: $(hostname -I | awk '{print $1}')"
|
||||||
|
echo "- If IP changes, run: /opt/ente/rebuild-frontend.sh"
|
||||||
|
echo "- Museum API: http://$(hostname -I | awk '{print $1}'):8080"
|
||||||
|
echo "- Photos UI: http://$(hostname -I | awk '{print $1}'):3000"
|
||||||
|
echo "- Accounts UI: http://$(hostname -I | awk '{print $1}'):3001"
|
||||||
|
echo "- Auth UI: http://$(hostname -I | awk '{print $1}'):3003"
|
||||||
|
echo ""
|
||||||
|
echo "Post-Installation Steps Required:"
|
||||||
|
echo "1. Create your first user account via the web UI"
|
||||||
|
echo "2. Check museum logs for email verification code:"
|
||||||
|
echo " journalctl -u ente-museum -n 100 | grep -i 'verification'"
|
||||||
|
echo "3. Use verification code to complete account setup"
|
||||||
|
echo "4. Remove subscription limit (replace <email> with your account):"
|
||||||
|
echo " ente admin update-subscription -a <email> -u <email> --no-limit"
|
||||||
|
echo ""
|
||||||
|
echo "Note: Email verification requires manual intervention since SMTP is not configured"
|
||||||
} >>~/ente.creds
|
} >>~/ente.creds
|
||||||
msg_ok "Set up PostgreSQL"
|
msg_ok "Set up PostgreSQL"
|
||||||
|
|
||||||
@ -89,12 +111,13 @@ $STD go build cmd/museum/main.go
|
|||||||
msg_ok "Built Museum"
|
msg_ok "Built Museum"
|
||||||
|
|
||||||
msg_info "Generating Secrets"
|
msg_info "Generating Secrets"
|
||||||
SECRET_ENC=$($STD go run tools/gen-random-keys/main.go | grep "encryption" | awk '{print $2}')
|
SECRET_ENC=$(go run tools/gen-random-keys/main.go 2>/dev/null | grep "encryption" | awk '{print $2}')
|
||||||
SECRET_HASH=$($STD go run tools/gen-random-keys/main.go | grep "hash" | awk '{print $2}')
|
SECRET_HASH=$(go run tools/gen-random-keys/main.go 2>/dev/null | grep "hash" | awk '{print $2}')
|
||||||
SECRET_JWT=$($STD go run tools/gen-random-keys/main.go | grep "jwt" | awk '{print $2}')
|
SECRET_JWT=$(go run tools/gen-random-keys/main.go 2>/dev/null | grep "jwt" | awk '{print $2}')
|
||||||
msg_ok "Generated Secrets"
|
msg_ok "Generated Secrets"
|
||||||
|
|
||||||
msg_info "Creating museum.yaml"
|
msg_info "Creating museum.yaml"
|
||||||
|
CONTAINER_IP=$(hostname -I | awk '{print $1}')
|
||||||
cat <<EOF >/opt/ente/server/museum.yaml
|
cat <<EOF >/opt/ente/server/museum.yaml
|
||||||
db:
|
db:
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
@ -114,9 +137,9 @@ s3:
|
|||||||
bucket: ente-dev
|
bucket: ente-dev
|
||||||
|
|
||||||
apps:
|
apps:
|
||||||
public-albums: http://localhost:3002
|
public-albums: http://${CONTAINER_IP}:3002
|
||||||
cast: http://localhost:3004
|
cast: http://${CONTAINER_IP}:3004
|
||||||
accounts: http://localhost:3001
|
accounts: http://${CONTAINER_IP}:3001
|
||||||
|
|
||||||
key:
|
key:
|
||||||
encryption: $SECRET_ENC
|
encryption: $SECRET_ENC
|
||||||
@ -124,6 +147,15 @@ key:
|
|||||||
|
|
||||||
jwt:
|
jwt:
|
||||||
secret: $SECRET_JWT
|
secret: $SECRET_JWT
|
||||||
|
|
||||||
|
# SMTP not configured - verification codes will appear in logs
|
||||||
|
# To configure SMTP, add:
|
||||||
|
# smtp:
|
||||||
|
# host: your-smtp-server
|
||||||
|
# port: 587
|
||||||
|
# username: your-username
|
||||||
|
# password: your-password
|
||||||
|
# email: noreply@yourdomain.com
|
||||||
EOF
|
EOF
|
||||||
msg_ok "Created museum.yaml"
|
msg_ok "Created museum.yaml"
|
||||||
|
|
||||||
@ -172,6 +204,30 @@ cp -r apps/photos/out /var/www/ente/apps/photos
|
|||||||
cp -r apps/accounts/out /var/www/ente/apps/accounts
|
cp -r apps/accounts/out /var/www/ente/apps/accounts
|
||||||
cp -r apps/auth/out /var/www/ente/apps/auth
|
cp -r apps/auth/out /var/www/ente/apps/auth
|
||||||
cp -r apps/cast/out /var/www/ente/apps/cast
|
cp -r apps/cast/out /var/www/ente/apps/cast
|
||||||
|
|
||||||
|
# Save build configuration for future rebuilds
|
||||||
|
cat <<REBUILD_EOF >/opt/ente/rebuild-frontend.sh
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Rebuild Ente frontend with current IP
|
||||||
|
CONTAINER_IP=\$(hostname -I | awk '{print \$1}')
|
||||||
|
echo "Building frontend with IP: \$CONTAINER_IP"
|
||||||
|
cd /opt/ente/web
|
||||||
|
export
|
||||||
|
=http://\${CONTAINER_IP}:8080
|
||||||
|
export NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT=http://\${CONTAINER_IP}:3002
|
||||||
|
yarn build
|
||||||
|
yarn build:accounts
|
||||||
|
yarn build:auth
|
||||||
|
yarn build:cast
|
||||||
|
rm -rf /var/www/ente/apps/*
|
||||||
|
cp -r apps/photos/out /var/www/ente/apps/photos
|
||||||
|
cp -r apps/accounts/out /var/www/ente/apps/accounts
|
||||||
|
cp -r apps/auth/out /var/www/ente/apps/auth
|
||||||
|
cp -r apps/cast/out /var/www/ente/apps/cast
|
||||||
|
systemctl reload caddy
|
||||||
|
echo "Frontend rebuilt successfully!"
|
||||||
|
REBUILD_EOF
|
||||||
|
chmod +x /opt/ente/rebuild-frontend.sh
|
||||||
msg_ok "Built Web Applications"
|
msg_ok "Built Web Applications"
|
||||||
|
|
||||||
msg_info "Creating Museum Service"
|
msg_info "Creating Museum Service"
|
||||||
@ -192,31 +248,82 @@ systemctl enable -q --now ente-museum
|
|||||||
msg_ok "Created Museum Service"
|
msg_ok "Created Museum Service"
|
||||||
|
|
||||||
msg_info "Configuring Caddy"
|
msg_info "Configuring Caddy"
|
||||||
|
CONTAINER_IP=$(hostname -I | awk '{print $1}')
|
||||||
cat <<EOF >/etc/caddy/Caddyfile
|
cat <<EOF >/etc/caddy/Caddyfile
|
||||||
|
# Ente Photos - Main Application
|
||||||
:3000 {
|
:3000 {
|
||||||
root * /var/www/ente/apps/photos
|
root * /var/www/ente/apps/photos
|
||||||
file_server
|
file_server
|
||||||
try_files {path} {path}.html /index.html
|
try_files {path} {path}.html /index.html
|
||||||
|
|
||||||
|
header {
|
||||||
|
Access-Control-Allow-Origin *
|
||||||
|
Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||||
|
Access-Control-Allow-Headers *
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Ente Accounts
|
||||||
:3001 {
|
:3001 {
|
||||||
root * /var/www/ente/apps/accounts
|
root * /var/www/ente/apps/accounts
|
||||||
file_server
|
file_server
|
||||||
try_files {path} {path}.html /index.html
|
try_files {path} {path}.html /index.html
|
||||||
|
|
||||||
|
header {
|
||||||
|
Access-Control-Allow-Origin *
|
||||||
|
Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||||
|
Access-Control-Allow-Headers *
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Public Albums
|
||||||
:3002 {
|
:3002 {
|
||||||
root * /var/www/ente/apps/photos
|
root * /var/www/ente/apps/photos
|
||||||
file_server
|
file_server
|
||||||
try_files {path} {path}.html /index.html
|
try_files {path} {path}.html /index.html
|
||||||
|
|
||||||
|
header {
|
||||||
|
Access-Control-Allow-Origin *
|
||||||
|
Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||||
|
Access-Control-Allow-Headers *
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Auth
|
||||||
:3003 {
|
:3003 {
|
||||||
root * /var/www/ente/apps/auth
|
root * /var/www/ente/apps/auth
|
||||||
file_server
|
file_server
|
||||||
try_files {path} {path}.html /index.html
|
try_files {path} {path}.html /index.html
|
||||||
|
|
||||||
|
header {
|
||||||
|
Access-Control-Allow-Origin *
|
||||||
|
Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||||
|
Access-Control-Allow-Headers *
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Cast
|
||||||
:3004 {
|
:3004 {
|
||||||
root * /var/www/ente/apps/cast
|
root * /var/www/ente/apps/cast
|
||||||
file_server
|
file_server
|
||||||
try_files {path} {path}.html /index.html
|
try_files {path} {path}.html /index.html
|
||||||
|
|
||||||
|
header {
|
||||||
|
Access-Control-Allow-Origin *
|
||||||
|
Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||||
|
Access-Control-Allow-Headers *
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Museum API Proxy
|
||||||
|
:8080 {
|
||||||
|
reverse_proxy localhost:8080
|
||||||
|
|
||||||
|
header {
|
||||||
|
Access-Control-Allow-Origin *
|
||||||
|
Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||||
|
Access-Control-Allow-Headers *
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
systemctl reload caddy
|
systemctl reload caddy
|
||||||
@ -225,7 +332,63 @@ msg_ok "Configured Caddy"
|
|||||||
motd_ssh
|
motd_ssh
|
||||||
customize
|
customize
|
||||||
|
|
||||||
|
msg_info "Creating helper scripts"
|
||||||
|
cat <<'HELPER_EOF' >/usr/local/bin/ente-get-verification
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
echo "Searching for verification codes in museum logs..."
|
||||||
|
journalctl -u ente-museum --no-pager | grep -i "verification\|verify\|code" | tail -20
|
||||||
|
HELPER_EOF
|
||||||
|
chmod +x /usr/local/bin/ente-get-verification
|
||||||
|
|
||||||
|
cat <<'HELPER_EOF' >/usr/local/bin/ente-upgrade-subscription
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Usage: ente-upgrade-subscription <email>"
|
||||||
|
echo "Example: ente-upgrade-subscription user@example.com"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
EMAIL="$1"
|
||||||
|
echo "Upgrading subscription for: $EMAIL"
|
||||||
|
ente admin update-subscription -a "$EMAIL" -u "$EMAIL" --no-limit
|
||||||
|
HELPER_EOF
|
||||||
|
chmod +x /usr/local/bin/ente-upgrade-subscription
|
||||||
|
|
||||||
|
msg_ok "Created helper scripts"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
msg_info "Cleaning up"
|
||||||
$STD apt-get -y autoremove
|
$STD apt -y autoremove
|
||||||
$STD apt-get -y autoclean
|
$STD apt -y autoclean
|
||||||
msg_ok "Cleaned"
|
msg_ok "Cleaned"
|
||||||
|
|
||||||
|
# Final setup summary
|
||||||
|
CONTAINER_IP=$(hostname -I | awk '{print $1}')
|
||||||
|
echo -e "\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo -e " ${GN}Ente Installation Complete!${CL}"
|
||||||
|
echo -e "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo -e "\n${BL}Access URLs:${CL}"
|
||||||
|
echo -e " Photos: http://${CONTAINER_IP}:3000"
|
||||||
|
echo -e " Accounts: http://${CONTAINER_IP}:3001"
|
||||||
|
echo -e " Auth: http://${CONTAINER_IP}:3003"
|
||||||
|
echo -e " API: http://${CONTAINER_IP}:8080"
|
||||||
|
echo -e "\n${YW}⚠️ Important Post-Installation Steps:${CL}"
|
||||||
|
echo -e "\n${BL}1. Create your first account:${CL}"
|
||||||
|
echo -e " • Open http://${CONTAINER_IP}:3000 in your browser"
|
||||||
|
echo -e " • Click 'Sign Up' and create an account"
|
||||||
|
echo -e "\n${BL}2. Verify your email (required):${CL}"
|
||||||
|
echo -e " • Run: ${GN}ente-get-verification${CL}"
|
||||||
|
echo -e " • Look for the verification code in the output"
|
||||||
|
echo -e " • Enter the code in the web UI to complete registration"
|
||||||
|
echo -e "\n${BL}3. Remove storage limit:${CL}"
|
||||||
|
echo -e " • After email verification is complete"
|
||||||
|
echo -e " • Run: ${GN}ente-upgrade-subscription your@email.com${CL}"
|
||||||
|
echo -e " • This removes the 10GB limit"
|
||||||
|
echo -e "\n${BL}4. If IP changes:${CL}"
|
||||||
|
echo -e " • Run: ${GN}/opt/ente/rebuild-frontend.sh${CL}"
|
||||||
|
echo -e " • This rebuilds the frontend with the new IP"
|
||||||
|
echo -e "\n${YW}Known Limitations:${CL}"
|
||||||
|
echo -e " • Email verification requires checking logs (no SMTP configured)"
|
||||||
|
echo -e " • Account creation must be done manually via web UI"
|
||||||
|
echo -e " • Subscription upgrade requires CLI after account creation"
|
||||||
|
echo -e " • Frontend must be rebuilt if container IP changes"
|
||||||
|
echo -e "\n${BL}Credentials saved to:${CL} ~/ente.creds"
|
||||||
|
echo -e "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
|||||||
@ -13,21 +13,7 @@ setting_up_container
|
|||||||
network_check
|
network_check
|
||||||
update_os
|
update_os
|
||||||
|
|
||||||
msg_info "Installing dependencies"
|
NODE_VERSION="22" NODE_MODULES="bun" setup_nodejs
|
||||||
$STD apt-get install -y \
|
|
||||||
build-essential \
|
|
||||||
openssl \
|
|
||||||
sqlite3 \
|
|
||||||
unzip
|
|
||||||
msg_ok "Installed Dependencies"
|
|
||||||
|
|
||||||
msg_info "Installing Bun"
|
|
||||||
export BUN_INSTALL=/opt/bun
|
|
||||||
curl -fsSL https://bun.sh/install | $STD bash
|
|
||||||
ln -sf /opt/bun/bin/bun /usr/local/bin/bun
|
|
||||||
ln -sf /opt/bun/bin/bun /usr/local/bin/bunx
|
|
||||||
msg_ok "Installed Bun"
|
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "gitea-mirror" "RayLabsHQ/gitea-mirror"
|
fetch_and_deploy_gh_release "gitea-mirror" "RayLabsHQ/gitea-mirror"
|
||||||
|
|
||||||
msg_info "Installing gitea-mirror"
|
msg_info "Installing gitea-mirror"
|
||||||
@ -70,8 +56,4 @@ msg_ok "Created Service"
|
|||||||
|
|
||||||
motd_ssh
|
motd_ssh
|
||||||
customize
|
customize
|
||||||
|
cleanup_lxc
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt-get -y autoremove
|
|
||||||
$STD apt-get -y autoclean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
|
|||||||
@ -1,153 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
|
||||||
# Author: michelroegl-brunner
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
|
||||||
# Source: https://github.com/opf/openproject
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
msg_info "Installing Dependencies"
|
|
||||||
$STD apt-get install -y \
|
|
||||||
lsb-release \
|
|
||||||
ca-certificates \
|
|
||||||
acl \
|
|
||||||
fping \
|
|
||||||
graphviz \
|
|
||||||
imagemagick \
|
|
||||||
mtr-tiny \
|
|
||||||
nginx \
|
|
||||||
nmap \
|
|
||||||
rrdtool \
|
|
||||||
snmp \
|
|
||||||
snmpd
|
|
||||||
msg_ok "Installed Dependencies"
|
|
||||||
|
|
||||||
PHP_VERSION="8.3" PHP_FPM="YES" PHP_MODULE="gmp,mysql,snmp" setup_php
|
|
||||||
setup_mariadb
|
|
||||||
setup_composer
|
|
||||||
PYTHON_VERSION="3.13" setup_uv
|
|
||||||
|
|
||||||
msg_info "Installing Python"
|
|
||||||
$STD apt-get install -y \
|
|
||||||
python3-{dotenv,pymysql,redis,setuptools,systemd,pip}
|
|
||||||
msg_ok "Installed Python"
|
|
||||||
|
|
||||||
msg_info "Configuring Database"
|
|
||||||
DB_NAME=librenms
|
|
||||||
DB_USER=librenms
|
|
||||||
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
|
|
||||||
$STD mariadb -u root -e "CREATE DATABASE $DB_NAME CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
|
||||||
$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 "LibreNMS-Credentials"
|
|
||||||
echo "LibreNMS Database User: $DB_USER"
|
|
||||||
echo "LibreNMS Database Password: $DB_PASS"
|
|
||||||
echo "LibreNMS Database Name: $DB_NAME"
|
|
||||||
} >>~/librenms.creds
|
|
||||||
msg_ok "Configured Database"
|
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "LibreNMS" "librenms/librenms"
|
|
||||||
|
|
||||||
msg_info "Configuring LibreNMS"
|
|
||||||
$STD useradd librenms -d /opt/librenms -M -r -s "$(which bash)"
|
|
||||||
setfacl -d -m g::rwx /opt/librenms/rrd /opt/librenms/logs /opt/librenms/bootstrap/cache/ /opt/librenms/storage/
|
|
||||||
setfacl -R -m g::rwx /opt/librenms/rrd /opt/librenms/logs /opt/librenms/bootstrap/cache/ /opt/librenms/storage/
|
|
||||||
cd /opt/librenms
|
|
||||||
$STD uv venv .venv
|
|
||||||
$STD source .venv/bin/activate
|
|
||||||
$STD uv pip install -r requirements.txt
|
|
||||||
cat <<EOF >/opt/librenms/.env
|
|
||||||
DB_DATABASE=${DB_NAME}
|
|
||||||
DB_USERNAME=${DB_USER}
|
|
||||||
DB_PASSWORD=${DB_PASS}
|
|
||||||
EOF
|
|
||||||
chown -R librenms:librenms /opt/librenms
|
|
||||||
chmod 771 /opt/librenms
|
|
||||||
setfacl -d -m g::rwx /opt/librenms/bootstrap/cache /opt/librenms/storage /opt/librenms/logs /opt/librenms/rrd
|
|
||||||
chmod -R ug=rwX /opt/librenms/bootstrap/cache /opt/librenms/storage /opt/librenms/logs /opt/librenms/rrd
|
|
||||||
msg_ok "Configured LibreNMS"
|
|
||||||
|
|
||||||
msg_info "Configure MariaDB"
|
|
||||||
sed -i "/\[mysqld\]/a innodb_file_per_table=1\nlower_case_table_names=0" /etc/mysql/mariadb.conf.d/50-server.cnf
|
|
||||||
systemctl enable -q --now mariadb
|
|
||||||
msg_ok "Configured MariaDB"
|
|
||||||
|
|
||||||
msg_info "Configure PHP-FPM"
|
|
||||||
cp /etc/php/8.2/fpm/pool.d/www.conf /etc/php/8.2/fpm/pool.d/librenms.conf
|
|
||||||
sed -i "s/\[www\]/\[librenms\]/g" /etc/php/8.2/fpm/pool.d/librenms.conf
|
|
||||||
sed -i "s/user = www-data/user = librenms/g" /etc/php/8.2/fpm/pool.d/librenms.conf
|
|
||||||
sed -i "s/group = www-data/group = librenms/g" /etc/php/8.2/fpm/pool.d/librenms.conf
|
|
||||||
sed -i "s/listen = \/run\/php\/php8.2-fpm.sock/listen = \/run\/php-fpm-librenms.sock/g" /etc/php/8.2/fpm/pool.d/librenms.conf
|
|
||||||
msg_ok "Configured PHP-FPM"
|
|
||||||
|
|
||||||
msg_info "Configure Nginx"
|
|
||||||
IP_ADDR=$(hostname -I | awk '{print $1}')
|
|
||||||
cat >/etc/nginx/sites-enabled/librenms <<'EOF'
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name ${IP_ADDR};
|
|
||||||
root /opt/librenms/html;
|
|
||||||
index index.php;
|
|
||||||
|
|
||||||
charset utf-8;
|
|
||||||
gzip on;
|
|
||||||
gzip_types text/css application/javascript text/javascript application/x-javascript image/svg+xml text/plain text/xsd text/xsl text/xml image/x-icon;
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ /index.php?$query_string;
|
|
||||||
}
|
|
||||||
location ~ [^/]\.php(/|$) {
|
|
||||||
fastcgi_pass unix:/run/php-fpm-librenms.sock;
|
|
||||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
|
||||||
include fastcgi.conf;
|
|
||||||
}
|
|
||||||
location ~ /\.(?!well-known).* {
|
|
||||||
deny all;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
rm /etc/nginx/sites-enabled/default
|
|
||||||
$STD systemctl reload nginx
|
|
||||||
systemctl restart php8.2-fpm
|
|
||||||
msg_ok "Configured Nginx"
|
|
||||||
|
|
||||||
msg_info "Configure Services"
|
|
||||||
COMPOSER_ALLOW_SUPERUSER=1
|
|
||||||
$STD composer install --no-dev
|
|
||||||
$STD php8.2 artisan migrate --force
|
|
||||||
$STD php8.2 artisan key:generate --force
|
|
||||||
$STD su librenms -s /bin/bash -c "lnms db:seed --force"
|
|
||||||
$STD su librenms -s /bin/bash -c "lnms user:add -p admin -r admin admin"
|
|
||||||
ln -s /opt/librenms/lnms /usr/bin/lnms
|
|
||||||
mkdir -p /etc/bash_completion.d/
|
|
||||||
cp /opt/librenms/misc/lnms-completion.bash /etc/bash_completion.d/
|
|
||||||
cp /opt/librenms/snmpd.conf.example /etc/snmp/snmpd.conf
|
|
||||||
|
|
||||||
RANDOM_STRING=$(openssl rand -base64 16 | tr -dc 'a-zA-Z0-9')
|
|
||||||
sed -i "s/RANDOMSTRINGHERE/$RANDOM_STRING/g" /etc/snmp/snmpd.conf
|
|
||||||
echo "SNMP Community String: $RANDOM_STRING" >>~/librenms.creds
|
|
||||||
curl -qo /usr/bin/distro https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/distro
|
|
||||||
chmod +x /usr/bin/distro
|
|
||||||
systemctl enable -q --now snmpd
|
|
||||||
|
|
||||||
cp /opt/librenms/dist/librenms.cron /etc/cron.d/librenms
|
|
||||||
cp /opt/librenms/dist/librenms-scheduler.service /opt/librenms/dist/librenms-scheduler.timer /etc/systemd/system/
|
|
||||||
|
|
||||||
systemctl enable -q --now librenms-scheduler.timer
|
|
||||||
cp /opt/librenms/misc/librenms.logrotate /etc/logrotate.d/librenms
|
|
||||||
msg_ok "Configured Services"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt-get -y autoremove
|
|
||||||
$STD apt-get -y autoclean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
@ -1,105 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
|
||||||
# Author: dkuku
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://github.com/livebook-dev/livebook
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
msg_info "Installing Dependencies"
|
|
||||||
$STD apt-get install -y \
|
|
||||||
build-essential \
|
|
||||||
ca-certificates \
|
|
||||||
cmake \
|
|
||||||
git \
|
|
||||||
libncurses5-dev
|
|
||||||
msg_ok "Installed Dependencies"
|
|
||||||
|
|
||||||
msg_info "Creating livebook user"
|
|
||||||
mkdir -p /opt/livebook /data
|
|
||||||
export HOME=/opt/livebook
|
|
||||||
$STD adduser --system --group --home /opt/livebook --shell /bin/bash livebook
|
|
||||||
msg_ok "Created livebook user"
|
|
||||||
|
|
||||||
|
|
||||||
msg_warn "WARNING: This script will run an external installer from a third-party source (https://elixir-lang.org)."
|
|
||||||
msg_warn "The following code is NOT maintained or audited by our repository."
|
|
||||||
msg_warn "If you have any doubts or concerns, please review the installer code before proceeding:"
|
|
||||||
msg_custom "${TAB3}${GATEWAY}${BGN}${CL}" "\e[1;34m" "→ https://elixir-lang.org/install.sh"
|
|
||||||
echo
|
|
||||||
read -r -p "${TAB3}Do you want to continue? [y/N]: " CONFIRM
|
|
||||||
if [[ ! "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then
|
|
||||||
msg_error "Aborted by user. No changes have been made."
|
|
||||||
exit 10
|
|
||||||
fi
|
|
||||||
bash <(curl -sL https://elixir-lang.org/install.sh)
|
|
||||||
|
|
||||||
msg_info "Setup Erlang and Elixir"
|
|
||||||
ERLANG_VERSION=$(ls /opt/livebook/.elixir-install/installs/otp/ | head -n1)
|
|
||||||
ELIXIR_VERSION=$(ls /opt/livebook/.elixir-install/installs/elixir/ | head -n1)
|
|
||||||
LIVEBOOK_PASSWORD=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c16)
|
|
||||||
|
|
||||||
export ERLANG_BIN="/opt/livebook/.elixir-install/installs/otp/$ERLANG_VERSION/bin"
|
|
||||||
export ELIXIR_BIN="/opt/livebook/.elixir-install/installs/elixir/$ELIXIR_VERSION/bin"
|
|
||||||
export PATH="$ERLANG_BIN:$ELIXIR_BIN:$PATH"
|
|
||||||
|
|
||||||
$STD mix local.hex --force
|
|
||||||
$STD mix local.rebar --force
|
|
||||||
$STD mix escript.install hex livebook --force
|
|
||||||
|
|
||||||
cat <<EOF >/opt/livebook/.env
|
|
||||||
export HOME=/opt/livebook
|
|
||||||
export ERLANG_VERSION=$ERLANG_VERSION
|
|
||||||
export ELIXIR_VERSION=$ELIXIR_VERSION
|
|
||||||
export LIVEBOOK_PORT=8080
|
|
||||||
export LIVEBOOK_IP="::"
|
|
||||||
export LIVEBOOK_HOME=/data
|
|
||||||
export LIVEBOOK_PASSWORD="$LIVEBOOK_PASSWORD"
|
|
||||||
export ESCRIPTS_BIN=/opt/livebook/.mix/escripts
|
|
||||||
export ERLANG_BIN="/opt/livebook/.elixir-install/installs/otp/\${ERLANG_VERSION}/bin"
|
|
||||||
export ELIXIR_BIN="/opt/livebook/.elixir-install/installs/elixir/\${ELIXIR_VERSION}/bin"
|
|
||||||
export PATH="\$ESCRIPTS_BIN:\$ERLANG_BIN:\$ELIXIR_BIN:\$PATH"
|
|
||||||
EOF
|
|
||||||
cat <<EOF >/opt/livebook/livebook.creds
|
|
||||||
Livebook-Credentials
|
|
||||||
Livebook Password: $LIVEBOOK_PASSWORD
|
|
||||||
EOF
|
|
||||||
msg_ok "Installed Erlang $ERLANG_VERSION and Elixir $ELIXIR_VERSION"
|
|
||||||
|
|
||||||
msg_info "Installing Livebook"
|
|
||||||
cat <<EOF >/etc/systemd/system/livebook.service
|
|
||||||
[Unit]
|
|
||||||
Description=Livebook
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=exec
|
|
||||||
User=livebook
|
|
||||||
Group=livebook
|
|
||||||
WorkingDirectory=/data
|
|
||||||
EnvironmentFile=-/opt/livebook/.env
|
|
||||||
ExecStart=/bin/bash -c 'source /opt/livebook/.env && cd /opt/livebook && livebook server'
|
|
||||||
Restart=always
|
|
||||||
RestartSec=5
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
chown -R livebook:livebook /opt/livebook /data
|
|
||||||
systemctl enable -q --now livebook
|
|
||||||
msg_ok "Installed Livebook"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
$STD apt-get autoremove -y
|
|
||||||
$STD apt-get autoclean
|
|
||||||
msg_ok "Cleaned Up"
|
|
||||||
110
install/mealie-install.sh
Normal file
110
install/mealie-install.sh
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
|
# Author: MickLesk (CanbiZ)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://mealie.io
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
msg_info "Installing Dependencies"
|
||||||
|
$STD apt install -y \
|
||||||
|
build-essential \
|
||||||
|
libpq-dev \
|
||||||
|
libwebp-dev \
|
||||||
|
libsasl2-dev \
|
||||||
|
libldap2-dev \
|
||||||
|
libssl-dev
|
||||||
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
|
PYTHON_VERSION="3.12" setup_uv
|
||||||
|
POSTGRES_VERSION="16" setup_postgresql
|
||||||
|
NODE_MODULE="yarn" NODE_VERSION="24" setup_nodejs
|
||||||
|
fetch_and_deploy_gh_release "mealie" "mealie-recipes/mealie" "tarball" "latest" "/opt/mealie"
|
||||||
|
PG_DB_NAME="mealie_db" PG_DB_USER="mealie_user" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db
|
||||||
|
|
||||||
|
msg_info "Installing Python Dependencies with uv"
|
||||||
|
cd /opt/mealie
|
||||||
|
$STD uv sync --frozen --extra pgsql
|
||||||
|
msg_ok "Installed Python Dependencies"
|
||||||
|
|
||||||
|
msg_info "Building Frontend"
|
||||||
|
export NUXT_TELEMETRY_DISABLED=1
|
||||||
|
cd /opt/mealie/frontend
|
||||||
|
$STD yarn install --prefer-offline --frozen-lockfile --non-interactive --production=false --network-timeout 1000000
|
||||||
|
$STD yarn generate
|
||||||
|
msg_ok "Built Frontend"
|
||||||
|
|
||||||
|
msg_info "Copying Built Frontend"
|
||||||
|
mkdir -p /opt/mealie/mealie/frontend
|
||||||
|
cp -r /opt/mealie/frontend/dist/* /opt/mealie/mealie/frontend/
|
||||||
|
msg_ok "Copied Frontend"
|
||||||
|
|
||||||
|
msg_info "Downloading NLTK Data"
|
||||||
|
mkdir -p /nltk_data/
|
||||||
|
cd /opt/mealie
|
||||||
|
$STD uv run python -m nltk.downloader -d /nltk_data averaged_perceptron_tagger_eng
|
||||||
|
msg_ok "Downloaded NLTK Data"
|
||||||
|
|
||||||
|
msg_info "Writing Environment File"
|
||||||
|
SECRET=$(openssl rand -hex 32)
|
||||||
|
mkdir -p /run/secrets
|
||||||
|
cat <<EOF >/opt/mealie/mealie.env
|
||||||
|
MEALIE_HOME=/opt/mealie
|
||||||
|
NLTK_DATA=/nltk_data
|
||||||
|
SECRET=${SECRET}
|
||||||
|
|
||||||
|
DB_ENGINE=postgres
|
||||||
|
POSTGRES_SERVER=localhost
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
POSTGRES_USER=${PG_DB_USER}
|
||||||
|
POSTGRES_PASSWORD=${PG_DB_PASS}
|
||||||
|
POSTGRES_DB=${PG_DB_NAME}
|
||||||
|
|
||||||
|
PRODUCTION=true
|
||||||
|
HOST=0.0.0.0
|
||||||
|
PORT=9000
|
||||||
|
EOF
|
||||||
|
msg_ok "Wrote Environment File"
|
||||||
|
|
||||||
|
msg_info "Creating Start Script"
|
||||||
|
cat <<'EOF' >/opt/mealie/start.sh
|
||||||
|
#!/bin/bash
|
||||||
|
set -a
|
||||||
|
source /opt/mealie/mealie.env
|
||||||
|
set +a
|
||||||
|
exec uv run mealie
|
||||||
|
EOF
|
||||||
|
chmod +x /opt/mealie/start.sh
|
||||||
|
msg_ok "Created Start Script"
|
||||||
|
|
||||||
|
msg_info "Creating Systemd Service"
|
||||||
|
cat <<'EOF' >/etc/systemd/system/mealie.service
|
||||||
|
[Unit]
|
||||||
|
Description=Mealie Recipe Manager
|
||||||
|
After=network.target postgresql.service
|
||||||
|
Wants=postgresql.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/opt/mealie
|
||||||
|
ExecStart=/opt/mealie/start.sh
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now mealie
|
||||||
|
msg_ok "Created and Started Service"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
59
install/metabase-install.sh
Normal file
59
install/metabase-install.sh
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
|
# Author: Slaviša Arežina (tremor021)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||||
|
# Source: https://www.metabase.com/
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
JAVA_VERSION="21" setup_java
|
||||||
|
PG_VERSION="17" setup_postgresql
|
||||||
|
PG_DB_NAME="metabase_db" PG_DB_USER="metabase" setup_postgresql_db
|
||||||
|
|
||||||
|
msg_info "Setting up Metabase"
|
||||||
|
mkdir -p /opt/metabase
|
||||||
|
RELEASE=$(get_latest_github_release "metabase/metabase")
|
||||||
|
curl -fsSL "https://downloads.metabase.com/v${RELEASE}.x/metabase.jar" -o /opt/metabase/metabase.jar
|
||||||
|
cd /opt/metabase
|
||||||
|
|
||||||
|
cat <<EOF >/opt/metabase/.env
|
||||||
|
MB_DB_TYPE=postgres
|
||||||
|
MB_DB_DBNAME=$PG_DB_NAME
|
||||||
|
MB_DB_PORT=5432
|
||||||
|
MB_DB_USER=$PG_DB_USER
|
||||||
|
MB_DB_PASS=$PG_DB_PASS
|
||||||
|
MB_DB_HOST=localhost
|
||||||
|
EOF
|
||||||
|
echo $RELEASE >~/.metabase
|
||||||
|
msg_ok "Setup Metabase"
|
||||||
|
|
||||||
|
msg_info "Creating Service"
|
||||||
|
cat <<EOF >/etc/systemd/system/metabase.service
|
||||||
|
[Unit]
|
||||||
|
Description=Metabase Service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
EnvironmentFile=/opt/metabase/.env
|
||||||
|
WorkingDirectory=/opt/metabase
|
||||||
|
ExecStart=/usr/bin/java --add-opens java.base/java.nio=ALL-UNNAMED -jar metabase.jar
|
||||||
|
Restart=always
|
||||||
|
SuccessExitStatus=143
|
||||||
|
TimeoutStopSec=120
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now metabase
|
||||||
|
msg_ok "Created Service"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
@ -1,72 +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/streetwriters/notesnook
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
msg_info "Installing Dependencies"
|
|
||||||
$STD apt-get install -y \
|
|
||||||
make \
|
|
||||||
git \
|
|
||||||
caddy
|
|
||||||
msg_ok "Installed Dependencies"
|
|
||||||
|
|
||||||
NODE_VERSION="22" setup_nodejs
|
|
||||||
fetch_and_deploy_gh_release "notesnook" "streetwriters/notesnook" "tarball"
|
|
||||||
|
|
||||||
msg_info "Configuring Notesnook (Patience)"
|
|
||||||
cd /opt/notesnook
|
|
||||||
export NODE_OPTIONS="--max-old-space-size=2560"
|
|
||||||
$STD npm install
|
|
||||||
$STD npm run build:web
|
|
||||||
msg_ok "Configured Notesnook"
|
|
||||||
|
|
||||||
msg_info "Configuring Caddy"
|
|
||||||
LOCAL_IP=$(hostname -I | awk '{print $1}')
|
|
||||||
cat <<EOF >/etc/caddy/Caddyfile
|
|
||||||
{
|
|
||||||
email admin@example.com
|
|
||||||
}
|
|
||||||
|
|
||||||
${LOCAL_IP} {
|
|
||||||
reverse_proxy 127.0.0.1:3000
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
msg_ok "Configured Caddy"
|
|
||||||
|
|
||||||
msg_info "Creating Service"
|
|
||||||
cat <<EOF >/etc/systemd/system/notesnook.service
|
|
||||||
[Unit]
|
|
||||||
Description=Notesnook Service
|
|
||||||
After=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=root
|
|
||||||
WorkingDirectory=/opt/notesnook
|
|
||||||
ExecStart=/usr/bin/npx serve apps/web/build
|
|
||||||
Restart=on-failure
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
systemctl reload caddy
|
|
||||||
systemctl enable -q --now notesnook
|
|
||||||
msg_ok "Created Service"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt-get -y autoremove
|
|
||||||
$STD apt-get -y autoclean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
@ -1,289 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
|
||||||
# Author: vhsdream
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://github.com/PatcMmon/PatchMon
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
msg_info "Installing Dependencies"
|
|
||||||
$STD apt install -y \
|
|
||||||
build-essential \
|
|
||||||
gcc \
|
|
||||||
nginx \
|
|
||||||
redis-server
|
|
||||||
msg_ok "Installed Dependencies"
|
|
||||||
|
|
||||||
NODE_VERSION="24" setup_nodejs
|
|
||||||
PG_VERSION="17" setup_postgresql
|
|
||||||
|
|
||||||
msg_info "Creating PostgreSQL Database"
|
|
||||||
DB_NAME=patchmon_db
|
|
||||||
DB_USER=patchmon_usr
|
|
||||||
DB_PASS="$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)"
|
|
||||||
$STD sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';"
|
|
||||||
$STD sudo -u postgres psql -c "CREATE DATABASE $DB_NAME WITH OWNER $DB_USER ENCODING 'UTF8' TEMPLATE template0;"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET client_encoding TO 'utf8';"
|
|
||||||
$STD sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER;"
|
|
||||||
|
|
||||||
cat <<EOF >~/patchmon.creds
|
|
||||||
PatchMon Credentials
|
|
||||||
PatchMon Database Name: $DB_NAME
|
|
||||||
PatchMon Database User: $DB_USER
|
|
||||||
PatchMon Database Password: $DB_PASS
|
|
||||||
EOF
|
|
||||||
msg_ok "Created PostgreSQL Database"
|
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "PatchMon" "PatchMon/PatchMon" "tarball" "latest" "/opt/patchmon"
|
|
||||||
|
|
||||||
msg_info "Configuring PatchMon"
|
|
||||||
cd /opt/patchmon
|
|
||||||
export NODE_ENV=production
|
|
||||||
$STD npm install --no-audit --no-fund --no-save --ignore-scripts
|
|
||||||
cd /opt/patchmon/backend
|
|
||||||
$STD npm install --no-audit --no-fund --no-save --ignore-scripts
|
|
||||||
cd /opt/patchmon/frontend
|
|
||||||
$STD npm install --include=dev --no-audit --no-fund --no-save --ignore-scripts
|
|
||||||
$STD npm run build
|
|
||||||
|
|
||||||
JWT_SECRET="$(openssl rand -base64 64 | tr -d "=+/" | cut -c1-50)"
|
|
||||||
LOCAL_IP="$(hostname -I | awk '{print $1}')"
|
|
||||||
cat <<EOF >/opt/patchmon/backend/.env
|
|
||||||
# Database Configuration
|
|
||||||
DATABASE_URL="postgresql://$DB_USER:$DB_PASS@localhost:5432/$DB_NAME"
|
|
||||||
PY_THRESHOLD=3M_DB_CONN_MAX_ATTEMPTS=30
|
|
||||||
PM_DB_CONN_WAIT_INTERVAL=2
|
|
||||||
|
|
||||||
# JWT Configuration
|
|
||||||
JWT_SECRET="$JWT_SECRET"
|
|
||||||
JWT_EXPIRES_IN=1h
|
|
||||||
JWT_REFRESH_EXPIRES_IN=7d
|
|
||||||
|
|
||||||
# Server Configuration
|
|
||||||
PORT=3399
|
|
||||||
NODE_ENV=production
|
|
||||||
|
|
||||||
# API Configuration
|
|
||||||
API_VERSION=v1
|
|
||||||
|
|
||||||
# CORS Configuration
|
|
||||||
CORS_ORIGIN="http://$LOCAL_IP"
|
|
||||||
|
|
||||||
# Session Configuration
|
|
||||||
SESSION_INACTIVITY_TIMEOUT_MINUTES=30
|
|
||||||
|
|
||||||
# User Configuration
|
|
||||||
DEFAULT_USER_ROLE=user
|
|
||||||
|
|
||||||
# Rate Limiting (times in milliseconds)
|
|
||||||
RATE_LIMIT_WINDOW_MS=900000
|
|
||||||
RATE_LIMIT_MAX=5000
|
|
||||||
AUTH_RATE_LIMIT_WINDOW_MS=600000
|
|
||||||
AUTH_RATE_LIMIT_MAX=500
|
|
||||||
AGENT_RATE_LIMIT_WINDOW_MS=60000
|
|
||||||
AGENT_RATE_LIMIT_MAX=1000
|
|
||||||
|
|
||||||
# Redis Configuration
|
|
||||||
REDIS_HOST=localhost
|
|
||||||
REDIS_PORT=6379
|
|
||||||
|
|
||||||
# Logging
|
|
||||||
LOG_LEVEL=info
|
|
||||||
ENABLE_LOGGING=true
|
|
||||||
|
|
||||||
# TFA Configuration
|
|
||||||
TFA_REMEMBER_ME_EXPIRES_IN=30d
|
|
||||||
TFA_MAX_REMEMBER_SESSIONS=5
|
|
||||||
TFA_SUSPICIOUS_ACTIVITY_THRESHOLD=3
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat <<EOF >/opt/patchmon/frontend/.env
|
|
||||||
VITE_API_URL=http://$LOCAL_IP/api/v1
|
|
||||||
VITE_APP_NAME=PatchMon
|
|
||||||
VITE_APP_VERSION=1.3.0
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cd /opt/patchmon/backend
|
|
||||||
$STD npx prisma migrate deploy
|
|
||||||
$STD npx prisma generate
|
|
||||||
msg_ok "Configured PatchMon"
|
|
||||||
|
|
||||||
msg_info "Configuring Nginx"
|
|
||||||
cat <<EOF >/etc/nginx/sites-available/patchmon.conf
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name $LOCAL_IP;
|
|
||||||
|
|
||||||
# Security headers
|
|
||||||
add_header X-Frame-Options DENY always;
|
|
||||||
add_header X-Content-Type-Options nosniff always;
|
|
||||||
add_header X-XSS-Protection "1; mode=block" always;
|
|
||||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
||||||
|
|
||||||
# Frontend
|
|
||||||
location / {
|
|
||||||
root /opt/patchmon/frontend/dist;
|
|
||||||
try_files \$uri \$uri/ /index.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Bull Board proxy
|
|
||||||
location /bullboard {
|
|
||||||
proxy_pass http://127.0.0.1:3399;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade \$http_upgrade;
|
|
||||||
proxy_set_header Connection 'upgrade';
|
|
||||||
proxy_set_header Host \$host;
|
|
||||||
proxy_set_header X-Real-IP \$remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
|
||||||
proxy_set_header X-Forwarded-Host \$host;
|
|
||||||
proxy_set_header Cookie \$http_cookie;
|
|
||||||
proxy_cache_bypass \$http_upgrade;
|
|
||||||
proxy_read_timeout 300s;
|
|
||||||
proxy_connect_timeout 75s;
|
|
||||||
|
|
||||||
# Enable cookie passthrough
|
|
||||||
proxy_pass_header Set-Cookie;
|
|
||||||
proxy_cookie_path / /;
|
|
||||||
|
|
||||||
# Preserve original client IP
|
|
||||||
proxy_set_header X-Original-Forwarded-For \$http_x_forwarded_for;
|
|
||||||
if (\$request_method = 'OPTIONS') {
|
|
||||||
return 204;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# API proxy
|
|
||||||
location /api/ {
|
|
||||||
proxy_pass http://127.0.0.1:3399;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade \$http_upgrade;
|
|
||||||
proxy_set_header Connection 'upgrade';
|
|
||||||
proxy_set_header Host \$host;
|
|
||||||
proxy_set_header X-Real-IP \$remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
|
||||||
proxy_cache_bypass \$http_upgrade;
|
|
||||||
proxy_read_timeout 300s;
|
|
||||||
proxy_connect_timeout 75s;
|
|
||||||
|
|
||||||
# Preserve original client IP
|
|
||||||
proxy_set_header X-Original-Forwarded-For \$http_x_forwarded_for;
|
|
||||||
if (\$request_method = 'OPTIONS') {
|
|
||||||
return 204;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Static assets caching (exclude Bull Board assets)
|
|
||||||
location ~* ^/(?!bullboard).*\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
||||||
root /opt/patchmon/frontend/dist;
|
|
||||||
expires 1y;
|
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
}
|
|
||||||
|
|
||||||
# Health check endpoint
|
|
||||||
location /health {
|
|
||||||
proxy_pass http://127.0.0.1:3399/health;
|
|
||||||
access_log off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
ln -sf /etc/nginx/sites-available/patchmon.conf /etc/nginx/sites-enabled/
|
|
||||||
rm -f /etc/nginx/sites-enabled/default
|
|
||||||
$STD nginx -t
|
|
||||||
systemctl restart nginx
|
|
||||||
msg_ok "Configured Nginx"
|
|
||||||
|
|
||||||
msg_info "Creating service"
|
|
||||||
cat <<EOF >/etc/systemd/system/patchmon-server.service
|
|
||||||
[Unit]
|
|
||||||
Description=PatchMon Service
|
|
||||||
After=network.target postgresql.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
WorkingDirectory=/opt/patchmon/backend
|
|
||||||
ExecStart=/usr/bin/node src/server.js
|
|
||||||
Restart=always
|
|
||||||
RestartSec=10
|
|
||||||
Environment=NODE_ENV=production
|
|
||||||
Environment=PATH=/usr/bin:/usr/local/bin
|
|
||||||
NoNewPrivileges=true
|
|
||||||
PrivateTmp=true
|
|
||||||
ProtectSystem=strict
|
|
||||||
ProtectHome=true
|
|
||||||
ReadWritePaths=/opt/patchmon
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
systemctl enable -q --now patchmon-server
|
|
||||||
msg_ok "Created and started service"
|
|
||||||
|
|
||||||
msg_info "Updating settings"
|
|
||||||
cat <<EOF >/opt/patchmon/backend/update-settings.js
|
|
||||||
const { PrismaClient } = require('@prisma/client');
|
|
||||||
const { v4: uuidv4 } = require('uuid');
|
|
||||||
const prisma = new PrismaClient();
|
|
||||||
|
|
||||||
async function updateSettings() {
|
|
||||||
try {
|
|
||||||
const existingSettings = await prisma.settings.findFirst();
|
|
||||||
|
|
||||||
const settingsData = {
|
|
||||||
id: uuidv4(),
|
|
||||||
server_url: 'http://$LOCAL_IP',
|
|
||||||
server_protocol: 'http',
|
|
||||||
server_host: '$LOCAL_IP',
|
|
||||||
server_port: 3399,
|
|
||||||
update_interval: 60,
|
|
||||||
auto_update: true,
|
|
||||||
signup_enabled: false,
|
|
||||||
ignore_ssl_self_signed: false,
|
|
||||||
updated_at: new Date()
|
|
||||||
};
|
|
||||||
|
|
||||||
if (existingSettings) {
|
|
||||||
// Update existing settings
|
|
||||||
await prisma.settings.update({
|
|
||||||
where: { id: existingSettings.id },
|
|
||||||
data: settingsData
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Create new settings record
|
|
||||||
await prisma.settings.create({
|
|
||||||
data: settingsData
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('✅ Database settings updated successfully');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('❌ Error updating settings:', error.message);
|
|
||||||
process.exit(1);
|
|
||||||
} finally {
|
|
||||||
await prisma.\$disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateSettings();
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cd /opt/patchmon/backend
|
|
||||||
$STD node update-settings.js
|
|
||||||
msg_ok "Settings updated successfully"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt -y autoremove
|
|
||||||
$STD apt -y autoclean
|
|
||||||
$STD apt -y clean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
@ -1,112 +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/gitroomhq/postiz-app
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
msg_info "Installing dependencies"
|
|
||||||
$STD apt-get install -y \
|
|
||||||
build-essential \
|
|
||||||
python3-pip \
|
|
||||||
supervisor \
|
|
||||||
debian-keyring \
|
|
||||||
debian-archive-keyring \
|
|
||||||
apt-transport-https \
|
|
||||||
redis
|
|
||||||
msg_ok "Installed dependencies"
|
|
||||||
|
|
||||||
NODE_VERSION="20" setup_nodejs
|
|
||||||
PG_VERSION="17" setup_postgresql
|
|
||||||
|
|
||||||
msg_info "Setting up PostgreSQL Database"
|
|
||||||
DB_NAME=postiz
|
|
||||||
DB_USER=postiz
|
|
||||||
DB_PASS="$(openssl rand -base64 18 | cut -c1-13)"
|
|
||||||
$STD sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';"
|
|
||||||
$STD sudo -u postgres psql -c "CREATE DATABASE $DB_NAME WITH OWNER $DB_USER ENCODING 'UTF8' TEMPLATE template0;"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET client_encoding TO 'utf8';"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET default_transaction_isolation TO 'read committed';"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC'"
|
|
||||||
{
|
|
||||||
echo "Postiz DB Credentials"
|
|
||||||
echo "Postiz Database User: $DB_USER"
|
|
||||||
echo "Postiz Database Password: $DB_PASS"
|
|
||||||
echo "Postiz Database Name: $DB_NAME"
|
|
||||||
} >>~/postiz.creds
|
|
||||||
msg_ok "Set up PostgreSQL Database"
|
|
||||||
|
|
||||||
msg_info "Setting up Caddy"
|
|
||||||
curl -1sLf "https://dl.cloudsmith.io/public/caddy/stable/gpg.key" | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
|
|
||||||
curl -1sLf "https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt" >/etc/apt/sources.list.d/caddy-stable.list
|
|
||||||
$STD apt-get update
|
|
||||||
$STD apt-get install caddy
|
|
||||||
msg_ok "Set up Caddy"
|
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "postiz" "gitroomhq/postiz-app"
|
|
||||||
|
|
||||||
msg_info "Configuring Postiz"
|
|
||||||
LOCAL_IP=$(hostname -I | awk '{print $1}')
|
|
||||||
JWT_SECRET=$(openssl rand -base64 64 | tr '+/' '-_' | tr -d '=')
|
|
||||||
cd /opt/postiz
|
|
||||||
mkdir -p /etc/supervisor.d
|
|
||||||
$STD npm --no-update-notifier --no-fund --global install pnpm@10.6.1 pm2
|
|
||||||
cp var/docker/supervisord.conf /etc/supervisord.conf
|
|
||||||
cp var/docker/Caddyfile ./Caddyfile
|
|
||||||
cp var/docker/entrypoint.sh ./entrypoint.sh
|
|
||||||
cp var/docker/supervisord/caddy.conf /etc/supervisor.d/caddy.conf
|
|
||||||
sed -i "s#/app/Caddyfile#/opt/postiz/Caddyfile#g" /etc/supervisor.d/caddy.conf
|
|
||||||
sed -i "s#/app/Caddyfile#/opt/postiz/Caddyfile#g" /opt/postiz/entrypoint.sh
|
|
||||||
sed -i "s#directory=/app#directory=/opt/postiz#g" /etc/supervisor.d/caddy.conf
|
|
||||||
export NODE_OPTIONS="--max-old-space-size=2560"
|
|
||||||
$STD pnpm install
|
|
||||||
$STD pnpm run build
|
|
||||||
chmod +x entrypoint.sh
|
|
||||||
|
|
||||||
cat <<EOF >.env
|
|
||||||
NOT_SECURED="true"
|
|
||||||
IS_GENERAL="true"
|
|
||||||
DATABASE_URL="postgresql://$DB_USER:$DB_PASS@localhost:5432/$DB_NAME"
|
|
||||||
REDIS_URL="redis://localhost:6379"
|
|
||||||
JWT_SECRET="$JWT_SECRET"
|
|
||||||
FRONTEND_URL="http://$LOCAL_IP:4200"
|
|
||||||
NEXT_PUBLIC_BACKEND_URL="http://$LOCAL_IP:3000"
|
|
||||||
BACKEND_INTERNAL_URL="http://$LOCAL_IP:3000"
|
|
||||||
EOF
|
|
||||||
msg_ok "Configured Postiz"
|
|
||||||
|
|
||||||
msg_info "Creating Service"
|
|
||||||
cat <<EOF >/etc/systemd/system/postiz.service
|
|
||||||
[Unit]
|
|
||||||
Description=Postiz Service
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=root
|
|
||||||
WorkingDirectory=/opt/postiz
|
|
||||||
EnvironmentFile=/opt/postiz/.env
|
|
||||||
ExecStart=/usr/bin/pnpm run pm2-run
|
|
||||||
Restart=always
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
systemctl enable -q --now postiz
|
|
||||||
msg_ok "Created Service"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt-get -y autoremove
|
|
||||||
$STD apt-get -y autoclean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
|
||||||
# Author: CrazyWolf13
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: Proxmox Server Solution GmbH
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
msg_info "Installing Proxmox Datacenter Manager"
|
|
||||||
curl -fsSL https://enterprise.proxmox.com/debian/proxmox-archive-keyring-trixie.gpg -o /usr/share/keyrings/proxmox-archive-keyring.gpg
|
|
||||||
echo "deb [signed-by=/usr/share/keyrings/proxmox-archive-keyring.gpg] http://download.proxmox.com/debian/pdm bookworm pdm-test " >/etc/apt/sources.list.d/pdm-test.list
|
|
||||||
$STD apt-get update
|
|
||||||
DEBIAN_FRONTEND=noninteractive
|
|
||||||
$STD apt-get -o Dpkg::Options::="--force-confdef" \
|
|
||||||
-o Dpkg::Options::="--force-confold" \
|
|
||||||
install -y proxmox-datacenter-manager \
|
|
||||||
proxmox-datacenter-manager-ui
|
|
||||||
msg_ok "Installed Proxmox Datacenter Manager"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt-get -y autoremove
|
|
||||||
$STD apt-get -y autoclean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
@ -13,69 +13,105 @@ setting_up_container
|
|||||||
network_check
|
network_check
|
||||||
update_os
|
update_os
|
||||||
|
|
||||||
msg_info "Installing Dependencies"
|
|
||||||
$STD apt-get install -y \
|
|
||||||
caddy \
|
|
||||||
apt-transport-https \
|
|
||||||
ca-certificates
|
|
||||||
msg_ok "Installed Dependencies"
|
|
||||||
|
|
||||||
setup_clickhouse
|
setup_clickhouse
|
||||||
PG_VERSION=17 setup_postgresql
|
PG_VERSION=17 setup_postgresql
|
||||||
NODE_VERSION="20" NODE_MODULE="next" setup_nodejs
|
NODE_VERSION="24" NODE_MODULE="next" setup_nodejs
|
||||||
|
PG_DB_NAME="rybbit_db" PG_DB_USER="rybbit" setup_postgresql_db
|
||||||
#sed -i 's|<default_profile>default</default_profile>|<default_profile>read_only</default_profile>|' /etc/clickhouse-server/users.xml
|
|
||||||
#sed -i 's|<default_password></default_password>|<default_password>DISABLED</default_password>|' /etc/clickhouse-server/users.xml
|
|
||||||
|
|
||||||
msg_info "Setting up PostgreSQL Database"
|
|
||||||
DB_NAME=rybbit_db
|
|
||||||
DB_USER=rybbit
|
|
||||||
DB_PASS="$(openssl rand -base64 18 | cut -c1-13)"
|
|
||||||
$STD sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';"
|
|
||||||
$STD sudo -u postgres psql -c "CREATE DATABASE $DB_NAME WITH OWNER $DB_USER ENCODING 'UTF8' TEMPLATE template0;"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET client_encoding TO 'utf8';"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET default_transaction_isolation TO 'read committed';"
|
|
||||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC'"
|
|
||||||
{
|
|
||||||
echo "Rybbit-Credentials"
|
|
||||||
echo "Rybbit Database User: $DB_USER"
|
|
||||||
echo "Rybbit Database Password: $DB_PASS"
|
|
||||||
echo "Rybbit Database Name: $DB_NAME"
|
|
||||||
} >>~/rybbit.creds
|
|
||||||
msg_ok "Set up PostgreSQL Database"
|
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "rybbit" "rybbit-io/rybbit" "tarball" "latest" "/opt/rybbit"
|
fetch_and_deploy_gh_release "rybbit" "rybbit-io/rybbit" "tarball" "latest" "/opt/rybbit"
|
||||||
|
|
||||||
|
msg_info "Building Rybbit Shared Module"
|
||||||
cd /opt/rybbit/shared
|
cd /opt/rybbit/shared
|
||||||
npm install
|
$STD npm install
|
||||||
npm run build
|
$STD npm run build
|
||||||
|
msg_ok "Built Shared Module"
|
||||||
|
|
||||||
|
msg_info "Building Rybbit Server"
|
||||||
cd /opt/rybbit/server
|
cd /opt/rybbit/server
|
||||||
npm ci
|
$STD npm ci
|
||||||
npm run build
|
$STD npm run build
|
||||||
|
msg_ok "Built Server"
|
||||||
|
|
||||||
|
msg_info "Building Rybbit Client"
|
||||||
cd /opt/rybbit/client
|
cd /opt/rybbit/client
|
||||||
npm ci --legacy-peer-deps
|
NEXT_PUBLIC_BACKEND_URL="http://localhost:3001" \
|
||||||
npm run build
|
NEXT_PUBLIC_DISABLE_SIGNUP="false" \
|
||||||
|
$STD npm ci --legacy-peer-deps
|
||||||
|
$STD npm run build
|
||||||
|
msg_ok "Built Client"
|
||||||
|
|
||||||
mv /opt/rybbit/.env.example /opt/rybbit/.env
|
msg_info "Configuring Rybbit"
|
||||||
sed -i "s|^POSTGRES_DB=.*|POSTGRES_DB=$DB_NAME|g" /opt/rybbit/.env
|
CONTAINER_IP=$(hostname -I | awk '{print $1}')
|
||||||
sed -i "s|^POSTGRES_USER=.*|POSTGRES_USER=$DB_USER|g" /opt/rybbit/.env
|
BETTER_AUTH_SECRET=$(openssl rand -hex 32)
|
||||||
sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$DB_PASS|g" /opt/rybbit/.env
|
|
||||||
sed -i "s|^DOMAIN_NAME=.*|DOMAIN_NAME=localhost|g" /opt/rybbit/.env
|
|
||||||
sed -i "s|^BASE_URL=.*|BASE_URL=\"http://localhost\"|g" /opt/rybbit/.env
|
|
||||||
msg_ok "Rybbit Installed"
|
|
||||||
|
|
||||||
msg_info "Setting up Caddy"
|
cat >/opt/rybbit/.env <<EOF
|
||||||
mkdir -p /etc/caddy
|
# Database Configuration
|
||||||
cp /opt/rybbit/Caddyfile /etc/caddy/Caddyfile
|
POSTGRES_HOST=localhost
|
||||||
systemctl enable -q --now caddy
|
POSTGRES_PORT=5432
|
||||||
msg_ok "Caddy Setup"
|
POSTGRES_DB=$PG_DB_NAME
|
||||||
|
POSTGRES_USER=$PG_DB_USER
|
||||||
|
POSTGRES_PASSWORD=$PG_DB_PASS
|
||||||
|
|
||||||
|
CLICKHOUSE_HOST=http://localhost:8123
|
||||||
|
CLICKHOUSE_DB=analytics
|
||||||
|
CLICKHOUSE_PASSWORD=
|
||||||
|
|
||||||
|
# Application Configuration
|
||||||
|
NODE_ENV=production
|
||||||
|
BASE_URL=http://${CONTAINER_IP}:3002
|
||||||
|
BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
|
||||||
|
DISABLE_SIGNUP=false
|
||||||
|
DISABLE_TELEMETRY=true
|
||||||
|
MAPBOX_TOKEN=
|
||||||
|
EOF
|
||||||
|
msg_ok "Configured Rybbit"
|
||||||
|
|
||||||
|
msg_info "Creating Rybbit Services"
|
||||||
|
cat >/etc/systemd/system/rybbit-server.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Rybbit Server
|
||||||
|
After=network.target postgresql.service clickhouse-server.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/opt/rybbit/server
|
||||||
|
EnvironmentFile=/opt/rybbit/.env
|
||||||
|
ExecStart=/usr/bin/node /opt/rybbit/server/dist/index.js
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >/etc/systemd/system/rybbit-client.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Rybbit Client
|
||||||
|
After=network.target rybbit-server.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/opt/rybbit/client
|
||||||
|
Environment="NODE_ENV=production"
|
||||||
|
Environment="NEXT_PUBLIC_BACKEND_URL=http://${CONTAINER_IP}:3001"
|
||||||
|
Environment="NEXT_PUBLIC_DISABLE_SIGNUP=false"
|
||||||
|
Environment="PORT=3002"
|
||||||
|
Environment="HOSTNAME=0.0.0.0"
|
||||||
|
ExecStart=/usr/bin/node /opt/rybbit/client/.next/standalone/server.js
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable -q --now rybbit-server.service
|
||||||
|
systemctl enable -q --now rybbit-client.service
|
||||||
|
msg_ok "Created and Started Rybbit Services"
|
||||||
|
|
||||||
motd_ssh
|
motd_ssh
|
||||||
customize
|
customize
|
||||||
|
cleanup_lxc
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt-get -y autoremove
|
|
||||||
$STD apt-get -y autoclean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
|
|||||||
85
install/snowshare-install.sh
Normal file
85
install/snowshare-install.sh
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
|
# Author: TuroYT
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
setup_nodejs
|
||||||
|
setup_postgresql
|
||||||
|
fetch_and_deploy_gh_release "snowshare" "TuroYT/snowshare"
|
||||||
|
|
||||||
|
msg_info "Setting up PostgreSQL Database"
|
||||||
|
DB_NAME=snowshare
|
||||||
|
DB_USER=snowshare
|
||||||
|
DB_PASS="$(openssl rand -base64 18 | cut -c1-13)"
|
||||||
|
$STD sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';"
|
||||||
|
$STD sudo -u postgres psql -c "CREATE DATABASE $DB_NAME WITH OWNER $DB_USER ENCODING 'UTF8' TEMPLATE template0;"
|
||||||
|
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET client_encoding TO 'utf8';"
|
||||||
|
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET default_transaction_isolation TO 'read committed';"
|
||||||
|
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC';"
|
||||||
|
{
|
||||||
|
echo "SnowShare-Database-Credentials"
|
||||||
|
echo "Database Username: $DB_USER"
|
||||||
|
echo "Database Password: $DB_PASS"
|
||||||
|
echo "Database Name: $DB_NAME"
|
||||||
|
} >>~/snowshare.creds
|
||||||
|
msg_ok "Set up PostgreSQL Database"
|
||||||
|
|
||||||
|
msg_info "Installing SnowShare"
|
||||||
|
cd /opt/snowshare
|
||||||
|
$STD npm ci
|
||||||
|
cat <<EOF >/opt/snowshare.env
|
||||||
|
DATABASE_URL="postgresql://$DB_USER:$DB_PASS@localhost:5432/$DB_NAME"
|
||||||
|
NEXTAUTH_URL="http://localhost:3000"
|
||||||
|
NEXTAUTH_SECRET="$(openssl rand -base64 32)"
|
||||||
|
ALLOW_SIGNUP=true
|
||||||
|
NODE_ENV=production
|
||||||
|
EOF
|
||||||
|
set -a
|
||||||
|
source /opt/snowshare.env
|
||||||
|
set +a
|
||||||
|
$STD npx prisma generate
|
||||||
|
$STD npx prisma migrate deploy
|
||||||
|
$STD npm run build
|
||||||
|
cat <<EOF >/etc/systemd/system/snowshare.service
|
||||||
|
[Unit]
|
||||||
|
Description=SnowShare - Modern File Sharing Platform
|
||||||
|
After=network.target postgresql.service
|
||||||
|
Requires=postgresql.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
WorkingDirectory=/opt/snowshare
|
||||||
|
EnvironmentFile=/opt/snowshare.env
|
||||||
|
ExecStart=/usr/bin/npm start
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now snowshare
|
||||||
|
msg_ok "Installed SnowShare"
|
||||||
|
|
||||||
|
msg_info "Setting up Cleanup Cron Job"
|
||||||
|
cat <<EOF >/etc/cron.d/snowshare-cleanup
|
||||||
|
0 2 * * * root cd /opt/snowshare && /usr/bin/npm run cleanup:expired >> /var/log/snowshare-cleanup.log 2>&1
|
||||||
|
EOF
|
||||||
|
msg_ok "Set up Cleanup Cron Job"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
|
||||||
|
msg_info "Cleaning up"
|
||||||
|
$STD apt -y autoremove
|
||||||
|
$STD apt -y autoclean
|
||||||
|
$STD apt -y clean
|
||||||
|
msg_ok "Cleaned"
|
||||||
@ -21,7 +21,7 @@ $STD apt install -y \
|
|||||||
ufw \
|
ufw \
|
||||||
iproute2
|
iproute2
|
||||||
mkdir -p /etc/systemd/system-preset
|
mkdir -p /etc/systemd/system-preset
|
||||||
echo "disable *" > /etc/systemd/system-preset/99-no-autostart.preset
|
echo "disable *" >/etc/systemd/system-preset/99-no-autostart.preset
|
||||||
$STD apt install -y \
|
$STD apt install -y \
|
||||||
transmission-daemon \
|
transmission-daemon \
|
||||||
privoxy
|
privoxy
|
||||||
@ -49,12 +49,13 @@ chmod +x /opt/privoxy/*.sh
|
|||||||
$STD ln -s /usr/bin/transmission-daemon /usr/local/bin/transmission-daemon
|
$STD ln -s /usr/bin/transmission-daemon /usr/local/bin/transmission-daemon
|
||||||
$STD update-alternatives --set iptables /usr/sbin/iptables-legacy
|
$STD update-alternatives --set iptables /usr/sbin/iptables-legacy
|
||||||
$STD update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
|
$STD update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
|
||||||
|
rm -rf /opt/docker-transmission-openvpn
|
||||||
msg_ok "Configured transmission-openvpn"
|
msg_ok "Configured transmission-openvpn"
|
||||||
|
|
||||||
msg_info "Creating Service"
|
msg_info "Creating Service"
|
||||||
LOCAL_SUBNETS=$(
|
LOCAL_SUBNETS=$(
|
||||||
ip -o -4 addr show \
|
ip -o -4 addr show |
|
||||||
| awk '!/127.0.0.1/ {
|
awk '!/127.0.0.1/ {
|
||||||
split($4, a, "/"); ip=a[1]; mask=a[2];
|
split($4, a, "/"); ip=a[1]; mask=a[2];
|
||||||
split(ip, o, ".");
|
split(ip, o, ".");
|
||||||
if (mask < 8) {
|
if (mask < 8) {
|
||||||
@ -66,12 +67,12 @@ LOCAL_SUBNETS=$(
|
|||||||
} else {
|
} else {
|
||||||
print o[1]"."o[2]"."o[3]".*";
|
print o[1]"."o[2]"."o[3]".*";
|
||||||
}
|
}
|
||||||
}' \
|
}' |
|
||||||
| sort -u | paste -sd, -
|
sort -u | paste -sd, -
|
||||||
)
|
)
|
||||||
TRANSMISSION_RPC_WHITELIST="127.0.0.*,${LOCAL_SUBNETS}"
|
TRANSMISSION_RPC_WHITELIST="127.0.0.*,${LOCAL_SUBNETS}"
|
||||||
mkdir -p /opt/transmission-openvpn
|
mkdir -p /opt/transmission-openvpn
|
||||||
cat <<EOF > "/opt/transmission-openvpn/.env"
|
cat <<EOF >"/opt/transmission-openvpn/.env"
|
||||||
OPENVPN_USERNAME="username"
|
OPENVPN_USERNAME="username"
|
||||||
OPENVPN_PASSWORD="password"
|
OPENVPN_PASSWORD="password"
|
||||||
OPENVPN_PROVIDER="PIA"
|
OPENVPN_PROVIDER="PIA"
|
||||||
@ -111,7 +112,7 @@ LOG_TO_STDOUT="false"
|
|||||||
HEALTH_CHECK_HOST="google.com"
|
HEALTH_CHECK_HOST="google.com"
|
||||||
SELFHEAL="false"
|
SELFHEAL="false"
|
||||||
EOF
|
EOF
|
||||||
cat <<EOF > /etc/systemd/system/openvpn-custom.service
|
cat <<EOF >/etc/systemd/system/openvpn-custom.service
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Custom OpenVPN start service
|
Description=Custom OpenVPN start service
|
||||||
After=network.target
|
After=network.target
|
||||||
@ -126,15 +127,9 @@ EnvironmentFile=/opt/transmission-openvpn/.env
|
|||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
EOF
|
EOF
|
||||||
systemctl enable --now -q openvpn-custom.service
|
systemctl enable -q --now openvpn-custom
|
||||||
msg_ok "Created Service"
|
msg_ok "Created Service"
|
||||||
|
|
||||||
motd_ssh
|
motd_ssh
|
||||||
customize
|
customize
|
||||||
|
cleanup_lxc
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt -y autoremove
|
|
||||||
$STD apt -y autoclean
|
|
||||||
$STD apt -y clean
|
|
||||||
rm -rf /opt/docker-transmission-openvpn
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
# Author: MickLesk (Canbiz)
|
# Author: MickLesk (Canbiz)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
|
||||||
source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
color
|
color
|
||||||
verb_ip6
|
verb_ip6
|
||||||
catch_errors
|
catch_errors
|
||||||
|
|||||||
141
install/web-check-install.sh
Normal file
141
install/web-check-install.sh
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
|
# Author: CrazyWolf13
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/lissy93/web-check
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
msg_info "Installing Dependencies"
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
$STD apt -y install --no-install-recommends \
|
||||||
|
git \
|
||||||
|
traceroute \
|
||||||
|
make \
|
||||||
|
g++ \
|
||||||
|
traceroute \
|
||||||
|
xvfb \
|
||||||
|
dbus \
|
||||||
|
xorg \
|
||||||
|
xvfb \
|
||||||
|
gtk2-engines-pixbuf \
|
||||||
|
dbus-x11 \
|
||||||
|
xfonts-base \
|
||||||
|
xfonts-100dpi \
|
||||||
|
xfonts-75dpi \
|
||||||
|
xfonts-scalable \
|
||||||
|
imagemagick \
|
||||||
|
x11-apps
|
||||||
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
|
NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs
|
||||||
|
|
||||||
|
msg_info "Setup Python3"
|
||||||
|
$STD apt install -y python3
|
||||||
|
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
|
||||||
|
msg_ok "Setup Python3"
|
||||||
|
|
||||||
|
msg_info "Installing Chromium"
|
||||||
|
curl -fsSL https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/google-chrome-keyring.gpg
|
||||||
|
cat <<EOF | sudo tee /etc/apt/sources.list.d/google-chrome.sources >/dev/null
|
||||||
|
Types: deb
|
||||||
|
URIs: http://dl.google.com/linux/chrome/deb/
|
||||||
|
Suites: stable
|
||||||
|
Components: main
|
||||||
|
Architectures: amd64
|
||||||
|
Signed-By: /usr/share/keyrings/google-chrome-keyring.gpg
|
||||||
|
EOF
|
||||||
|
$STD apt update
|
||||||
|
$STD apt -y install \
|
||||||
|
chromium \
|
||||||
|
libxss1 \
|
||||||
|
lsb-release
|
||||||
|
msg_ok "Installed Chromium"
|
||||||
|
|
||||||
|
msg_info "Setting up Chromium"
|
||||||
|
/usr/bin/chromium --no-sandbox --version >/etc/chromium-version
|
||||||
|
chmod 755 /usr/bin/chromium
|
||||||
|
msg_ok "Setup Chromium"
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "web-check" "MickLesk/web-check"
|
||||||
|
|
||||||
|
msg_info "Installing Web-Check (Patience)"
|
||||||
|
cd /opt/web-check
|
||||||
|
cat <<'EOF' >/opt/web-check/.env
|
||||||
|
CHROME_PATH=/usr/bin/chromium
|
||||||
|
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
||||||
|
HEADLESS=true
|
||||||
|
GOOGLE_CLOUD_API_KEY=''
|
||||||
|
REACT_APP_SHODAN_API_KEY=''
|
||||||
|
REACT_APP_WHO_API_KEY=''
|
||||||
|
SECURITY_TRAILS_API_KEY=''
|
||||||
|
CLOUDMERSIVE_API_KEY=''
|
||||||
|
TRANCO_USERNAME=''
|
||||||
|
TRANCO_API_KEY=''
|
||||||
|
URL_SCAN_API_KEY=''
|
||||||
|
BUILT_WITH_API_KEY=''
|
||||||
|
TORRENT_IP_API_KEY=''
|
||||||
|
PORT='3000'
|
||||||
|
DISABLE_GUI='false'
|
||||||
|
API_TIMEOUT_LIMIT='10000'
|
||||||
|
API_CORS_ORIGIN='*'
|
||||||
|
API_ENABLE_RATE_LIMIT='false'
|
||||||
|
REACT_APP_API_ENDPOINT='/api'
|
||||||
|
ENABLE_ANALYTICS='false'
|
||||||
|
EOF
|
||||||
|
$STD yarn install --frozen-lockfile --network-timeout 100000
|
||||||
|
msg_ok "Installed Web-Check"
|
||||||
|
|
||||||
|
msg_info "Building Web-Check"
|
||||||
|
$STD yarn build --production
|
||||||
|
rm -rf /var/lib/apt/lists/* /app/node_modules/.cache
|
||||||
|
msg_ok "Built Web-Check"
|
||||||
|
|
||||||
|
msg_info "Creating Service"
|
||||||
|
cat <<'EOF' >/opt/run_web-check.sh
|
||||||
|
#!/bin/bash
|
||||||
|
SCREEN_RESOLUTION="1280x1024x24"
|
||||||
|
if ! systemctl is-active --quiet dbus; then
|
||||||
|
echo "Warning: dbus service is not running. Some features may not work properly."
|
||||||
|
fi
|
||||||
|
[[ -z "${DISPLAY}" ]] && export DISPLAY=":99"
|
||||||
|
Xvfb "${DISPLAY}" -screen 0 "${SCREEN_RESOLUTION}" &
|
||||||
|
XVFB_PID=$!
|
||||||
|
sleep 2
|
||||||
|
cd /opt/web-check
|
||||||
|
exec yarn start
|
||||||
|
EOF
|
||||||
|
chmod +x /opt/run_web-check.sh
|
||||||
|
cat <<'EOF' >/etc/systemd/system/web-check.service
|
||||||
|
[Unit]
|
||||||
|
Description=Web Check Service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
WorkingDirectory=/opt/web-check
|
||||||
|
EnvironmentFile=/opt/web-check/.env
|
||||||
|
ExecStartPre=/bin/bash -c "service dbus start || true"
|
||||||
|
ExecStartPre=/bin/bash -c "if ! pgrep -f 'Xvfb.*:99' > /dev/null; then Xvfb :99 -screen 0 1280x1024x24 & fi"
|
||||||
|
ExecStart=/opt/run_web-check.sh
|
||||||
|
Restart=on-failure
|
||||||
|
Environment=DISPLAY=:99
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now web-check
|
||||||
|
msg_ok "Created Service"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
234
misc/REFACTORING_SUMMARY.md
Normal file
234
misc/REFACTORING_SUMMARY.md
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
# Build.func Refactoring Summary - CORRECTED
|
||||||
|
|
||||||
|
**Datum:** 29.10.2025
|
||||||
|
**Backup:** build.func.backup-refactoring-\*
|
||||||
|
|
||||||
|
## Durchgeführte Änderungen (KORRIGIERT)
|
||||||
|
|
||||||
|
### 1. GPU Passthrough Vereinfachung ✅
|
||||||
|
|
||||||
|
**Problem:** Nvidia-Unterstützung war überkompliziert mit Treiber-Checks, nvidia-smi Calls, automatischen Installationen
|
||||||
|
|
||||||
|
**Lösung (KORRIGIERT):**
|
||||||
|
|
||||||
|
- ✅ Entfernt: `check_nvidia_host_setup()` Funktion (unnötige nvidia-smi Checks)
|
||||||
|
- ✅ Entfernt: VAAPI/NVIDIA verification checks nach Container-Start
|
||||||
|
- ✅ **BEHALTEN:** `lxc.mount.entry` für alle GPU-Typen (Intel/AMD/NVIDIA) ✅✅✅
|
||||||
|
- ✅ **BEHALTEN:** `lxc.cgroup2.devices.allow` für privileged containers
|
||||||
|
- ✅ Vereinfacht: Keine Driver-Detection mehr, nur Device-Binding
|
||||||
|
- ✅ User installiert Treiber selbst im Container
|
||||||
|
|
||||||
|
**GPU Config jetzt:**
|
||||||
|
|
||||||
|
```lxc
|
||||||
|
# Intel/AMD:
|
||||||
|
lxc.mount.entry: /dev/dri/renderD128 /dev/dri/renderD128 none bind,optional,create=file
|
||||||
|
lxc.mount.entry: /dev/dri/card0 /dev/dri/card0 none bind,optional,create=file
|
||||||
|
lxc.cgroup2.devices.allow: c 226:128 rwm # if privileged
|
||||||
|
|
||||||
|
# NVIDIA:
|
||||||
|
lxc.mount.entry: /dev/nvidia0 /dev/nvidia0 none bind,optional,create=file
|
||||||
|
lxc.mount.entry: /dev/nvidiactl /dev/nvidiactl none bind,optional,create=file
|
||||||
|
lxc.mount.entry: /dev/nvidia-uvm /dev/nvidia-uvm none bind,optional,create=file
|
||||||
|
lxc.cgroup2.devices.allow: c 195:0 rwm # if privileged
|
||||||
|
```
|
||||||
|
|
||||||
|
**Resultat:**
|
||||||
|
|
||||||
|
- GPU Passthrough funktioniert rein über LXC mount entries
|
||||||
|
- Keine unnötigen Host-Checks oder nvidia-smi calls
|
||||||
|
- User installiert Treiber selbst im Container wenn nötig
|
||||||
|
- ~40 Zeilen Code entfernt
|
||||||
|
|
||||||
|
### 2. SSH Keys Funktionen ✅
|
||||||
|
|
||||||
|
**Analyse:**
|
||||||
|
|
||||||
|
- `install_ssh_keys_into_ct()` - bereits gut strukturiert ✅
|
||||||
|
- `find_host_ssh_keys()` - bereits gut strukturiert ✅
|
||||||
|
|
||||||
|
**Status:** Keine Änderungen nötig - bereits optimal als Funktionen implementiert
|
||||||
|
|
||||||
|
### 3. Default Vars Logik überarbeitet ✅
|
||||||
|
|
||||||
|
**Problem:** Einige var\_\* defaults machen keinen Sinn als globale Defaults:
|
||||||
|
|
||||||
|
- `var_ctid` - Container-IDs können nur 1x vergeben werden ❌
|
||||||
|
- `var_ipv6_static` - Statische IPs können nur 1x vergeben werden ❌
|
||||||
|
|
||||||
|
**Kein Problem (KORRIGIERT):**
|
||||||
|
|
||||||
|
- `var_gateway` - Kann als Default gesetzt werden (User's Verantwortung) ✅
|
||||||
|
- `var_apt_cacher` - Kann als Default gesetzt werden + Runtime-Check ✅
|
||||||
|
- `var_apt_cacher_ip` - Kann als Default gesetzt werden + Runtime-Check ✅
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
|
||||||
|
- ✅ **ENTFERNT** aus VAR_WHITELIST: var_ctid, var_ipv6_static
|
||||||
|
- ✅ **BEHALTEN** in VAR_WHITELIST: var_gateway, var_apt_cacher, var_apt_cacher_ip
|
||||||
|
- ✅ **NEU:** Runtime-Check für APT Cacher Erreichbarkeit (curl timeout 2s)
|
||||||
|
- ✅ Kommentare hinzugefügt zur Erklärung
|
||||||
|
|
||||||
|
**APT Cacher Runtime Check:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Runtime check: Verify APT cacher is reachable if configured
|
||||||
|
if [[ -n "$APT_CACHER_IP" && "$APT_CACHER" == "yes" ]]; then
|
||||||
|
if ! curl -s --connect-timeout 2 "http://${APT_CACHER_IP}:3142" >/dev/null 2>&1; then
|
||||||
|
msg_warn "APT Cacher configured but not reachable at ${APT_CACHER_IP}:3142"
|
||||||
|
msg_info "Disabling APT Cacher for this installation"
|
||||||
|
APT_CACHER=""
|
||||||
|
APT_CACHER_IP=""
|
||||||
|
else
|
||||||
|
msg_ok "APT Cacher verified at ${APT_CACHER_IP}:3142"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
**Resultat:**
|
||||||
|
|
||||||
|
- Nur sinnvolle Defaults: keine var_ctid, keine static IPs
|
||||||
|
- APT Cacher funktioniert mit automatischem Fallback wenn nicht erreichbar
|
||||||
|
- Gateway bleibt als Default (User's Verantwortung bei Konflikten)
|
||||||
|
|
||||||
|
## Code-Statistik
|
||||||
|
|
||||||
|
### Vorher:
|
||||||
|
|
||||||
|
- Zeilen: 3,518
|
||||||
|
- check_nvidia_host_setup(): 22 Zeilen
|
||||||
|
- NVIDIA verification: 8 Zeilen
|
||||||
|
- Var whitelist entries: 28 Einträge
|
||||||
|
|
||||||
|
### Nachher:
|
||||||
|
|
||||||
|
- Zeilen: 3,458
|
||||||
|
- check_nvidia_host_setup(): **ENTFERNT**
|
||||||
|
- NVIDIA verification: **ENTFERNT**
|
||||||
|
- APT Cacher check: **NEU** (13 Zeilen)
|
||||||
|
- lxc.mount.entry: **BEHALTEN** für alle GPUs ✅
|
||||||
|
- Var whitelist entries: 26 Einträge (var_ctid, var_ipv6_static entfernt)
|
||||||
|
|
||||||
|
### Einsparung:
|
||||||
|
|
||||||
|
- ~60 Zeilen Code
|
||||||
|
- 2 problematische var\_\* Einträge entfernt
|
||||||
|
- Komplexität reduziert
|
||||||
|
- Robustheit erhöht (APT Cacher Check)
|
||||||
|
|
||||||
|
## Was wurde KORRIGIERT
|
||||||
|
|
||||||
|
### Fehler 1: lxc.mount.entry entfernt ❌
|
||||||
|
|
||||||
|
**Problem:** Ich hatte die `lxc.mount.entry` Zeilen entfernt und nur `dev0:` Einträge behalten.
|
||||||
|
**Lösung:** `lxc.mount.entry` für alle GPU-Typen wieder hinzugefügt! ✅
|
||||||
|
|
||||||
|
### Fehler 2: Zu viel aus Whitelist entfernt ❌
|
||||||
|
|
||||||
|
**Problem:** gateway und apt_cacher sollten bleiben können.
|
||||||
|
**Lösung:** Nur var_ctid und var_ipv6_static entfernt! ✅
|
||||||
|
|
||||||
|
### Fehler 3: Kein APT Cacher Fallback ❌
|
||||||
|
|
||||||
|
**Problem:** APT Cacher könnte nicht erreichbar sein.
|
||||||
|
**Lösung:** Runtime-Check mit curl --connect-timeout 2 hinzugefügt! ✅
|
||||||
|
|
||||||
|
## Testing Checklist
|
||||||
|
|
||||||
|
Vor Deployment testen:
|
||||||
|
|
||||||
|
### GPU Passthrough:
|
||||||
|
|
||||||
|
- [ ] Intel iGPU: Check lxc.mount.entry für /dev/dri/\*
|
||||||
|
- [ ] AMD GPU: Check lxc.mount.entry für /dev/dri/\*
|
||||||
|
- [ ] NVIDIA GPU: Check lxc.mount.entry für /dev/nvidia\*
|
||||||
|
- [ ] Privileged: Check lxc.cgroup2.devices.allow
|
||||||
|
- [ ] Unprivileged: Check nur lxc.mount.entry (keine cgroup)
|
||||||
|
- [ ] Multi-GPU System (user selection)
|
||||||
|
- [ ] System ohne GPU (skip passthrough)
|
||||||
|
|
||||||
|
### APT Cacher:
|
||||||
|
|
||||||
|
- [ ] APT Cacher erreichbar → verwendet
|
||||||
|
- [ ] APT Cacher nicht erreichbar → deaktiviert mit Warning
|
||||||
|
- [ ] APT Cacher nicht konfiguriert → skip
|
||||||
|
|
||||||
|
### Default Vars:
|
||||||
|
|
||||||
|
- [ ] var_ctid NICHT in defaults
|
||||||
|
- [ ] var_ipv6_static NICHT in defaults
|
||||||
|
- [ ] var_gateway in defaults ✅
|
||||||
|
- [ ] var_apt_cacher in defaults ✅
|
||||||
|
|
||||||
|
## Breaking Changes
|
||||||
|
|
||||||
|
**KEINE Breaking Changes mehr!**
|
||||||
|
|
||||||
|
### GPU Passthrough:
|
||||||
|
|
||||||
|
- ✅ lxc.mount.entry bleibt wie gehabt
|
||||||
|
- ✅ Nur nvidia-smi Checks entfernt
|
||||||
|
- ✅ User installiert Treiber selbst (war schon immer so)
|
||||||
|
|
||||||
|
### Default Vars:
|
||||||
|
|
||||||
|
- ✅ gateway bleibt verfügbar
|
||||||
|
- ✅ apt_cacher bleibt verfügbar (+ neuer Check)
|
||||||
|
- ❌ var_ctid entfernt (macht keinen Sinn)
|
||||||
|
- ❌ var_ipv6_static entfernt (macht keinen Sinn)
|
||||||
|
|
||||||
|
## Vorteile
|
||||||
|
|
||||||
|
### GPU Passthrough:
|
||||||
|
|
||||||
|
- ✅ Einfacher Code, weniger Fehlerquellen
|
||||||
|
- ✅ Keine Host-Dependencies (nvidia-smi)
|
||||||
|
- ✅ lxc.mount.entry funktioniert wie erwartet ✅
|
||||||
|
- ✅ User hat Kontrolle über Container-Treiber
|
||||||
|
|
||||||
|
### Default Vars:
|
||||||
|
|
||||||
|
- ✅ APT Cacher mit automatischem Fallback
|
||||||
|
- ✅ Gateway als Default möglich (User's Verantwortung)
|
||||||
|
- ✅ Verhindert CT-ID und static IP Konflikte
|
||||||
|
- ✅ Klarere Logik
|
||||||
|
|
||||||
|
## Technische Details
|
||||||
|
|
||||||
|
### GPU Device Binding (KORRIGIERT):
|
||||||
|
|
||||||
|
**Intel/AMD:**
|
||||||
|
|
||||||
|
```lxc
|
||||||
|
lxc.mount.entry: /dev/dri/renderD128 /dev/dri/renderD128 none bind,optional,create=file
|
||||||
|
lxc.mount.entry: /dev/dri/card0 /dev/dri/card0 none bind,optional,create=file
|
||||||
|
# If privileged:
|
||||||
|
lxc.cgroup2.devices.allow: c 226:128 rwm
|
||||||
|
lxc.cgroup2.devices.allow: c 226:0 rwm
|
||||||
|
```
|
||||||
|
|
||||||
|
**NVIDIA:**
|
||||||
|
|
||||||
|
```lxc
|
||||||
|
lxc.mount.entry: /dev/nvidia0 /dev/nvidia0 none bind,optional,create=file
|
||||||
|
lxc.mount.entry: /dev/nvidiactl /dev/nvidiactl none bind,optional,create=file
|
||||||
|
lxc.mount.entry: /dev/nvidia-uvm /dev/nvidia-uvm none bind,optional,create=file
|
||||||
|
lxc.mount.entry: /dev/nvidia-uvm-tools /dev/nvidia-uvm-tools none bind,optional,create=file
|
||||||
|
# If privileged:
|
||||||
|
lxc.cgroup2.devices.allow: c 195:0 rwm
|
||||||
|
lxc.cgroup2.devices.allow: c 195:255 rwm
|
||||||
|
```
|
||||||
|
|
||||||
|
### Whitelist Diff (KORRIGIERT):
|
||||||
|
|
||||||
|
**Entfernt:**
|
||||||
|
|
||||||
|
- var_ctid (macht keinen Sinn - CT IDs sind unique)
|
||||||
|
- var_ipv6_static (macht keinen Sinn - static IPs sind unique)
|
||||||
|
|
||||||
|
**Behalten:**
|
||||||
|
|
||||||
|
- var_gateway (User's Verantwortung)
|
||||||
|
- var_apt_cacher (mit Runtime-Check)
|
||||||
|
- var_apt_cacher_ip (mit Runtime-Check)
|
||||||
|
- Alle anderen 24 Einträge
|
||||||
@ -86,10 +86,10 @@ network_check() {
|
|||||||
set +e
|
set +e
|
||||||
trap - ERR
|
trap - ERR
|
||||||
if ping -c 1 -W 1 1.1.1.1 &>/dev/null || ping -c 1 -W 1 8.8.8.8 &>/dev/null || ping -c 1 -W 1 9.9.9.9 &>/dev/null; then
|
if ping -c 1 -W 1 1.1.1.1 &>/dev/null || ping -c 1 -W 1 8.8.8.8 &>/dev/null || ping -c 1 -W 1 9.9.9.9 &>/dev/null; then
|
||||||
msg_ok "Internet Connected"
|
ipv4_status="${GN}✔${CL} IPv4"
|
||||||
else
|
else
|
||||||
msg_error "Internet NOT Connected"
|
ipv4_status="${RD}✖${CL} IPv4"
|
||||||
read -r -p "Would you like to continue anyway? <y/N> " prompt
|
read -r -p "Internet NOT connected. Continue anyway? <y/N> " prompt
|
||||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
|
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||||
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
|
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
|
||||||
else
|
else
|
||||||
@ -98,7 +98,11 @@ network_check() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
|
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
|
||||||
if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to ${BL}$RESOLVEDIP${CL}"; fi
|
if [[ -z "$RESOLVEDIP" ]]; then
|
||||||
|
msg_error "Internet: ${ipv4_status} DNS Failed"
|
||||||
|
else
|
||||||
|
msg_ok "Internet: ${ipv4_status} DNS: ${BL}${RESOLVEDIP}${CL}"
|
||||||
|
fi
|
||||||
set -e
|
set -e
|
||||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
||||||
}
|
}
|
||||||
|
|||||||
230
misc/api.func
230
misc/api.func
@ -2,57 +2,153 @@
|
|||||||
# Author: michelroegl-brunner
|
# Author: michelroegl-brunner
|
||||||
# License: MIT | https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/LICENSE
|
# License: MIT | https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/LICENSE
|
||||||
|
|
||||||
get_error_description() {
|
# ==============================================================================
|
||||||
local exit_code="$1"
|
# API.FUNC - TELEMETRY & DIAGNOSTICS API
|
||||||
case "$exit_code" in
|
# ==============================================================================
|
||||||
0) echo " " ;;
|
#
|
||||||
1) echo "General error: An unspecified error occurred." ;;
|
# Provides functions for sending anonymous telemetry data to Community-Scripts
|
||||||
2) echo "Incorrect shell usage or invalid command arguments." ;;
|
# API for analytics and diagnostics purposes.
|
||||||
3) echo "Unexecuted function or invalid shell condition." ;;
|
#
|
||||||
4) echo "Error opening a file or invalid path." ;;
|
# Features:
|
||||||
5) echo "I/O error: An input/output failure occurred." ;;
|
# - Container/VM creation statistics
|
||||||
6) echo "No such device or address." ;;
|
# - Installation success/failure tracking
|
||||||
7) echo "Insufficient memory or resource exhaustion." ;;
|
# - Error code mapping and reporting
|
||||||
8) echo "Non-executable file or invalid file format." ;;
|
# - Privacy-respecting anonymous telemetry
|
||||||
9) echo "Failed child process execution." ;;
|
#
|
||||||
18) echo "Connection to a remote server failed." ;;
|
# Usage:
|
||||||
22) echo "Invalid argument or faulty network connection." ;;
|
# source <(curl -fsSL .../api.func)
|
||||||
28) echo "No space left on device." ;;
|
# post_to_api # Report container creation
|
||||||
35) echo "Timeout while establishing a connection." ;;
|
# post_update_to_api # Report installation status
|
||||||
56) echo "Faulty TLS connection." ;;
|
#
|
||||||
60) echo "SSL certificate error." ;;
|
# Privacy:
|
||||||
100) echo "LXC install error: Unexpected error in create_lxc.sh." ;;
|
# - Only anonymous statistics (no personal data)
|
||||||
101) echo "LXC install error: No network connection detected." ;;
|
# - User can opt-out via diagnostics settings
|
||||||
200) echo "LXC creation failed." ;;
|
# - Random UUID for session tracking only
|
||||||
201) echo "LXC error: Invalid Storage class." ;;
|
#
|
||||||
202) echo "User aborted menu in create_lxc.sh." ;;
|
# ==============================================================================
|
||||||
203) echo "CTID not set in create_lxc.sh." ;;
|
|
||||||
204) echo "PCT_OSTYPE not set in create_lxc.sh." ;;
|
# ==============================================================================
|
||||||
205) echo "CTID cannot be less than 100 in create_lxc.sh." ;;
|
# SECTION 1: ERROR CODE DESCRIPTIONS
|
||||||
206) echo "CTID already in use in create_lxc.sh." ;;
|
# ==============================================================================
|
||||||
207) echo "Template not found in create_lxc.sh." ;;
|
|
||||||
208) echo "Error downloading template in create_lxc.sh." ;;
|
# ------------------------------------------------------------------------------
|
||||||
209) echo "Container creation failed, but template is intact in create_lxc.sh." ;;
|
# explain_exit_code()
|
||||||
125) echo "Docker error: Container could not start." ;;
|
#
|
||||||
126) echo "Command not executable: Incorrect permissions or missing dependencies." ;;
|
# - Maps numeric exit codes to human-readable error descriptions
|
||||||
127) echo "Command not found: Incorrect path or missing dependency." ;;
|
# - Supports:
|
||||||
128) echo "Invalid exit signal, e.g., incorrect Git command." ;;
|
# * Generic/Shell errors (1, 2, 126, 127, 128, 130, 137, 139, 143)
|
||||||
129) echo "Signal 1 (SIGHUP): Process terminated due to hangup." ;;
|
# * Package manager errors (APT, DPKG: 100, 101, 255)
|
||||||
130) echo "Signal 2 (SIGINT): Manual termination via Ctrl+C." ;;
|
# * Node.js/npm errors (243-249, 254)
|
||||||
132) echo "Signal 4 (SIGILL): Illegal machine instruction." ;;
|
# * Python/pip/uv errors (210-212)
|
||||||
133) echo "Signal 5 (SIGTRAP): Debugging error or invalid breakpoint signal." ;;
|
# * PostgreSQL errors (231-234)
|
||||||
134) echo "Signal 6 (SIGABRT): Program aborted itself." ;;
|
# * MySQL/MariaDB errors (241-244)
|
||||||
135) echo "Signal 7 (SIGBUS): Memory error, invalid memory address." ;;
|
# * MongoDB errors (251-254)
|
||||||
137) echo "Signal 9 (SIGKILL): Process forcibly terminated (OOM-killer or 'kill -9')." ;;
|
# * Proxmox custom codes (200-231)
|
||||||
139) echo "Signal 11 (SIGSEGV): Segmentation fault, possibly due to invalid pointer access." ;;
|
# - Returns description string for given exit code
|
||||||
141) echo "Signal 13 (SIGPIPE): Pipe closed unexpectedly." ;;
|
# - Shared function with error_handler.func for consistency
|
||||||
143) echo "Signal 15 (SIGTERM): Process terminated normally." ;;
|
# ------------------------------------------------------------------------------
|
||||||
152) echo "Signal 24 (SIGXCPU): CPU time limit exceeded." ;;
|
explain_exit_code() {
|
||||||
255) echo "Unknown critical error, often due to missing permissions or broken scripts." ;;
|
local code="$1"
|
||||||
*) echo "Unknown error code ($exit_code)." ;;
|
case "$code" in
|
||||||
|
# --- Generic / Shell ---
|
||||||
|
1) echo "General error / Operation not permitted" ;;
|
||||||
|
2) echo "Misuse of shell builtins (e.g. syntax error)" ;;
|
||||||
|
126) echo "Command invoked cannot execute (permission problem?)" ;;
|
||||||
|
127) echo "Command not found" ;;
|
||||||
|
128) echo "Invalid argument to exit" ;;
|
||||||
|
130) echo "Terminated by Ctrl+C (SIGINT)" ;;
|
||||||
|
137) echo "Killed (SIGKILL / Out of memory?)" ;;
|
||||||
|
139) echo "Segmentation fault (core dumped)" ;;
|
||||||
|
143) echo "Terminated (SIGTERM)" ;;
|
||||||
|
|
||||||
|
# --- Package manager / APT / DPKG ---
|
||||||
|
100) echo "APT: Package manager error (broken packages / dependency problems)" ;;
|
||||||
|
101) echo "APT: Configuration error (bad sources.list, malformed config)" ;;
|
||||||
|
255) echo "DPKG: Fatal internal error" ;;
|
||||||
|
|
||||||
|
# --- Node.js / npm / pnpm / yarn ---
|
||||||
|
243) echo "Node.js: Out of memory (JavaScript heap out of memory)" ;;
|
||||||
|
245) echo "Node.js: Invalid command-line option" ;;
|
||||||
|
246) echo "Node.js: Internal JavaScript Parse Error" ;;
|
||||||
|
247) echo "Node.js: Fatal internal error" ;;
|
||||||
|
248) echo "Node.js: Invalid C++ addon / N-API failure" ;;
|
||||||
|
249) echo "Node.js: Inspector error" ;;
|
||||||
|
254) echo "npm/pnpm/yarn: Unknown fatal error" ;;
|
||||||
|
|
||||||
|
# --- Python / pip / uv ---
|
||||||
|
210) echo "Python: Virtualenv / uv environment missing or broken" ;;
|
||||||
|
211) echo "Python: Dependency resolution failed" ;;
|
||||||
|
212) echo "Python: Installation aborted (permissions or EXTERNALLY-MANAGED)" ;;
|
||||||
|
|
||||||
|
# --- PostgreSQL ---
|
||||||
|
231) echo "PostgreSQL: Connection failed (server not running / wrong socket)" ;;
|
||||||
|
232) echo "PostgreSQL: Authentication failed (bad user/password)" ;;
|
||||||
|
233) echo "PostgreSQL: Database does not exist" ;;
|
||||||
|
234) echo "PostgreSQL: Fatal error in query / syntax" ;;
|
||||||
|
|
||||||
|
# --- MySQL / MariaDB ---
|
||||||
|
241) echo "MySQL/MariaDB: Connection failed (server not running / wrong socket)" ;;
|
||||||
|
242) echo "MySQL/MariaDB: Authentication failed (bad user/password)" ;;
|
||||||
|
243) echo "MySQL/MariaDB: Database does not exist" ;;
|
||||||
|
244) echo "MySQL/MariaDB: Fatal error in query / syntax" ;;
|
||||||
|
|
||||||
|
# --- MongoDB ---
|
||||||
|
251) echo "MongoDB: Connection failed (server not running)" ;;
|
||||||
|
252) echo "MongoDB: Authentication failed (bad user/password)" ;;
|
||||||
|
253) echo "MongoDB: Database not found" ;;
|
||||||
|
254) echo "MongoDB: Fatal query error" ;;
|
||||||
|
|
||||||
|
# --- Proxmox Custom Codes ---
|
||||||
|
200) echo "Custom: Failed to create lock file" ;;
|
||||||
|
203) echo "Custom: Missing CTID variable" ;;
|
||||||
|
204) echo "Custom: Missing PCT_OSTYPE variable" ;;
|
||||||
|
205) echo "Custom: Invalid CTID (<100)" ;;
|
||||||
|
206) echo "Custom: CTID already in use (check 'pct list' and /etc/pve/lxc/)" ;;
|
||||||
|
207) echo "Custom: Password contains unescaped special characters (-, /, \\, *, etc.)" ;;
|
||||||
|
208) echo "Custom: Invalid configuration (DNS/MAC/Network format error)" ;;
|
||||||
|
209) echo "Custom: Container creation failed (check logs for pct create output)" ;;
|
||||||
|
210) echo "Custom: Cluster not quorate" ;;
|
||||||
|
211) echo "Custom: Timeout waiting for template lock (concurrent download in progress)" ;;
|
||||||
|
214) echo "Custom: Not enough storage space" ;;
|
||||||
|
215) echo "Custom: Container created but not listed (ghost state - check /etc/pve/lxc/)" ;;
|
||||||
|
216) echo "Custom: RootFS entry missing in config (incomplete creation)" ;;
|
||||||
|
217) echo "Custom: Storage does not support rootdir (check storage capabilities)" ;;
|
||||||
|
218) echo "Custom: Template file corrupted or incomplete download (size <1MB or invalid archive)" ;;
|
||||||
|
220) echo "Custom: Unable to resolve template path" ;;
|
||||||
|
221) echo "Custom: Template file exists but not readable (check file permissions)" ;;
|
||||||
|
222) echo "Custom: Template download failed after 3 attempts (network/storage issue)" ;;
|
||||||
|
223) echo "Custom: Template not available after download (storage sync issue)" ;;
|
||||||
|
225) echo "Custom: No template available for OS/Version (check 'pveam available')" ;;
|
||||||
|
231) echo "Custom: LXC stack upgrade/retry failed (outdated pve-container - check https://github.com/community-scripts/ProxmoxVE/discussions/8126)" ;;
|
||||||
|
|
||||||
|
# --- Default ---
|
||||||
|
*) echo "Unknown error" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SECTION 2: TELEMETRY FUNCTIONS
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# post_to_api()
|
||||||
|
#
|
||||||
|
# - Sends LXC container creation statistics to Community-Scripts API
|
||||||
|
# - Only executes if:
|
||||||
|
# * curl is available
|
||||||
|
# * DIAGNOSTICS=yes
|
||||||
|
# * RANDOM_UUID is set
|
||||||
|
# - Payload includes:
|
||||||
|
# * Container type, disk size, CPU cores, RAM
|
||||||
|
# * OS type and version
|
||||||
|
# * IPv6 disable status
|
||||||
|
# * Application name (NSAPP)
|
||||||
|
# * Installation method
|
||||||
|
# * PVE version
|
||||||
|
# * Status: "installing"
|
||||||
|
# * Random UUID for session tracking
|
||||||
|
# - Anonymous telemetry (no personal data)
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
post_to_api() {
|
post_to_api() {
|
||||||
|
|
||||||
if ! command -v curl &>/dev/null; then
|
if ! command -v curl &>/dev/null; then
|
||||||
@ -81,7 +177,6 @@ post_to_api() {
|
|||||||
"ram_size": $RAM_SIZE,
|
"ram_size": $RAM_SIZE,
|
||||||
"os_type": "$var_os",
|
"os_type": "$var_os",
|
||||||
"os_version": "$var_version",
|
"os_version": "$var_version",
|
||||||
"disableip6": "$DISABLEIP6",
|
|
||||||
"nsapp": "$NSAPP",
|
"nsapp": "$NSAPP",
|
||||||
"method": "$METHOD",
|
"method": "$METHOD",
|
||||||
"pve_version": "$pve_version",
|
"pve_version": "$pve_version",
|
||||||
@ -98,6 +193,18 @@ EOF
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# post_to_api_vm()
|
||||||
|
#
|
||||||
|
# - Sends VM creation statistics to Community-Scripts API
|
||||||
|
# - Similar to post_to_api() but for virtual machines (not containers)
|
||||||
|
# - Reads DIAGNOSTICS from /usr/local/community-scripts/diagnostics file
|
||||||
|
# - Payload differences:
|
||||||
|
# * ct_type=2 (VM instead of LXC)
|
||||||
|
# * type="vm"
|
||||||
|
# * Disk size without 'G' suffix (parsed from DISK_SIZE variable)
|
||||||
|
# - Only executes if DIAGNOSTICS=yes and RANDOM_UUID is set
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
post_to_api_vm() {
|
post_to_api_vm() {
|
||||||
|
|
||||||
if [[ ! -f /usr/local/community-scripts/diagnostics ]]; then
|
if [[ ! -f /usr/local/community-scripts/diagnostics ]]; then
|
||||||
@ -132,7 +239,6 @@ post_to_api_vm() {
|
|||||||
"ram_size": $RAM_SIZE,
|
"ram_size": $RAM_SIZE,
|
||||||
"os_type": "$var_os",
|
"os_type": "$var_os",
|
||||||
"os_version": "$var_version",
|
"os_version": "$var_version",
|
||||||
"disableip6": "",
|
|
||||||
"nsapp": "$NSAPP",
|
"nsapp": "$NSAPP",
|
||||||
"method": "$METHOD",
|
"method": "$METHOD",
|
||||||
"pve_version": "$pve_version",
|
"pve_version": "$pve_version",
|
||||||
@ -148,13 +254,33 @@ EOF
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
POST_UPDATE_DONE=false
|
# ------------------------------------------------------------------------------
|
||||||
|
# post_update_to_api()
|
||||||
|
#
|
||||||
|
# - Reports installation completion status to API
|
||||||
|
# - Prevents duplicate submissions via POST_UPDATE_DONE flag
|
||||||
|
# - Arguments:
|
||||||
|
# * $1: status ("success" or "failed")
|
||||||
|
# * $2: exit_code (default: 1 for failed, 0 for success)
|
||||||
|
# - Payload includes:
|
||||||
|
# * Final status (success/failed)
|
||||||
|
# * Error description via get_error_description()
|
||||||
|
# * Random UUID for session correlation
|
||||||
|
# - Only executes once per session
|
||||||
|
# - Silently returns if:
|
||||||
|
# * curl not available
|
||||||
|
# * Already reported (POST_UPDATE_DONE=true)
|
||||||
|
# * DIAGNOSTICS=no
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
post_update_to_api() {
|
post_update_to_api() {
|
||||||
|
|
||||||
if ! command -v curl &>/dev/null; then
|
if ! command -v curl &>/dev/null; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Initialize flag if not set (prevents 'unbound variable' error with set -u)
|
||||||
|
POST_UPDATE_DONE=${POST_UPDATE_DONE:-false}
|
||||||
|
|
||||||
if [ "$POST_UPDATE_DONE" = true ]; then
|
if [ "$POST_UPDATE_DONE" = true ]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@ -171,7 +297,7 @@ post_update_to_api() {
|
|||||||
exit_code=1
|
exit_code=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
error=$(get_error_description "$exit_code")
|
error=$(explain_exit_code "$exit_code")
|
||||||
|
|
||||||
if [ -z "$error" ]; then
|
if [ -z "$error" ]; then
|
||||||
error="Unknown error"
|
error="Unknown error"
|
||||||
|
|||||||
2210
misc/build.func
2210
misc/build.func
File diff suppressed because it is too large
Load Diff
364
misc/cloud-init.sh
Normal file
364
misc/cloud-init.sh
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Cloud-Init Library - Universal Helper for all Proxmox VM Scripts
|
||||||
|
# ==============================================================================
|
||||||
|
# Author: community-scripts ORG
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# 1. Source this library in your VM script:
|
||||||
|
# source /dev/stdin <<<$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/vm/cloud-init-lib.sh)
|
||||||
|
#
|
||||||
|
# 2. Call setup_cloud_init with parameters:
|
||||||
|
# setup_cloud_init "$VMID" "$STORAGE" "$HN" "$USE_CLOUD_INIT"
|
||||||
|
#
|
||||||
|
# Compatible with: Debian, Ubuntu, and all Cloud-Init enabled distributions
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# Configuration defaults (can be overridden before sourcing)
|
||||||
|
CLOUDINIT_DEFAULT_USER="${CLOUDINIT_DEFAULT_USER:-root}"
|
||||||
|
CLOUDINIT_DNS_SERVERS="${CLOUDINIT_DNS_SERVERS:-1.1.1.1 8.8.8.8}"
|
||||||
|
CLOUDINIT_SEARCH_DOMAIN="${CLOUDINIT_SEARCH_DOMAIN:-local}"
|
||||||
|
CLOUDINIT_SSH_KEYS="${CLOUDINIT_SSH_KEYS:-/root/.ssh/authorized_keys}"
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Main Setup Function - Configures Proxmox Native Cloud-Init
|
||||||
|
# ==============================================================================
|
||||||
|
# Parameters:
|
||||||
|
# $1 - VMID (required)
|
||||||
|
# $2 - Storage name (required)
|
||||||
|
# $3 - Hostname (optional, default: vm-<vmid>)
|
||||||
|
# $4 - Enable Cloud-Init (yes/no, default: no)
|
||||||
|
# $5 - User (optional, default: root)
|
||||||
|
# $6 - Network mode (dhcp/static, default: dhcp)
|
||||||
|
# $7 - Static IP (optional, format: 192.168.1.100/24)
|
||||||
|
# $8 - Gateway (optional)
|
||||||
|
# $9 - Nameservers (optional, default: 1.1.1.1 8.8.8.8)
|
||||||
|
#
|
||||||
|
# Returns: 0 on success, 1 on failure
|
||||||
|
# Exports: CLOUDINIT_USER, CLOUDINIT_PASSWORD, CLOUDINIT_CRED_FILE
|
||||||
|
# ==============================================================================
|
||||||
|
function setup_cloud_init() {
|
||||||
|
local vmid="$1"
|
||||||
|
local storage="$2"
|
||||||
|
local hostname="${3:-vm-${vmid}}"
|
||||||
|
local enable="${4:-no}"
|
||||||
|
local ciuser="${5:-$CLOUDINIT_DEFAULT_USER}"
|
||||||
|
local network_mode="${6:-dhcp}"
|
||||||
|
local static_ip="${7:-}"
|
||||||
|
local gateway="${8:-}"
|
||||||
|
local nameservers="${9:-$CLOUDINIT_DNS_SERVERS}"
|
||||||
|
|
||||||
|
# Skip if not enabled
|
||||||
|
if [ "$enable" != "yes" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Configuring Cloud-Init" 2>/dev/null || echo "[INFO] Configuring Cloud-Init"
|
||||||
|
|
||||||
|
# Create Cloud-Init drive (try ide2 first, then scsi1 as fallback)
|
||||||
|
if ! qm set "$vmid" --ide2 "${storage}:cloudinit" >/dev/null 2>&1; then
|
||||||
|
qm set "$vmid" --scsi1 "${storage}:cloudinit" >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set user
|
||||||
|
qm set "$vmid" --ciuser "$ciuser" >/dev/null
|
||||||
|
|
||||||
|
# Generate and set secure random password
|
||||||
|
local cipassword=$(openssl rand -base64 16)
|
||||||
|
qm set "$vmid" --cipassword "$cipassword" >/dev/null
|
||||||
|
|
||||||
|
# Add SSH keys if available
|
||||||
|
if [ -f "$CLOUDINIT_SSH_KEYS" ]; then
|
||||||
|
qm set "$vmid" --sshkeys "$CLOUDINIT_SSH_KEYS" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configure network
|
||||||
|
if [ "$network_mode" = "static" ] && [ -n "$static_ip" ] && [ -n "$gateway" ]; then
|
||||||
|
qm set "$vmid" --ipconfig0 "ip=${static_ip},gw=${gateway}" >/dev/null
|
||||||
|
else
|
||||||
|
qm set "$vmid" --ipconfig0 "ip=dhcp" >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set DNS servers
|
||||||
|
qm set "$vmid" --nameserver "$nameservers" >/dev/null
|
||||||
|
|
||||||
|
# Set search domain
|
||||||
|
qm set "$vmid" --searchdomain "$CLOUDINIT_SEARCH_DOMAIN" >/dev/null
|
||||||
|
|
||||||
|
# Enable package upgrades on first boot (if supported by Proxmox version)
|
||||||
|
qm set "$vmid" --ciupgrade 1 >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# Save credentials to file
|
||||||
|
local cred_file="/tmp/${hostname}-${vmid}-cloud-init-credentials.txt"
|
||||||
|
cat >"$cred_file" <<EOF
|
||||||
|
========================================
|
||||||
|
Cloud-Init Credentials
|
||||||
|
========================================
|
||||||
|
VM ID: ${vmid}
|
||||||
|
Hostname: ${hostname}
|
||||||
|
Created: $(date)
|
||||||
|
|
||||||
|
Username: ${ciuser}
|
||||||
|
Password: ${cipassword}
|
||||||
|
|
||||||
|
Network: ${network_mode}$([ "$network_mode" = "static" ] && echo " (IP: ${static_ip}, GW: ${gateway})" || echo " (DHCP)")
|
||||||
|
DNS: ${nameservers}
|
||||||
|
|
||||||
|
========================================
|
||||||
|
SSH Access (if keys configured):
|
||||||
|
ssh ${ciuser}@<vm-ip>
|
||||||
|
|
||||||
|
Proxmox UI Configuration:
|
||||||
|
VM ${vmid} > Cloud-Init > Edit
|
||||||
|
- User, Password, SSH Keys
|
||||||
|
- Network (IP Config)
|
||||||
|
- DNS, Search Domain
|
||||||
|
========================================
|
||||||
|
EOF
|
||||||
|
|
||||||
|
msg_ok "Cloud-Init configured (User: ${ciuser})" 2>/dev/null || echo "[OK] Cloud-Init configured (User: ${ciuser})"
|
||||||
|
|
||||||
|
# Export for use in calling script (DO NOT display password here - will be shown in summary)
|
||||||
|
export CLOUDINIT_USER="$ciuser"
|
||||||
|
export CLOUDINIT_PASSWORD="$cipassword"
|
||||||
|
export CLOUDINIT_CRED_FILE="$cred_file"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Interactive Cloud-Init Configuration (Whiptail/Dialog)
|
||||||
|
# ==============================================================================
|
||||||
|
# Prompts user for Cloud-Init configuration choices
|
||||||
|
# Returns configuration via exported variables:
|
||||||
|
# - CLOUDINIT_ENABLE (yes/no)
|
||||||
|
# - CLOUDINIT_USER
|
||||||
|
# - CLOUDINIT_NETWORK_MODE (dhcp/static)
|
||||||
|
# - CLOUDINIT_IP (if static)
|
||||||
|
# - CLOUDINIT_GW (if static)
|
||||||
|
# - CLOUDINIT_DNS
|
||||||
|
# ==============================================================================
|
||||||
|
function configure_cloud_init_interactive() {
|
||||||
|
local default_user="${1:-root}"
|
||||||
|
|
||||||
|
# Check if whiptail is available
|
||||||
|
if ! command -v whiptail >/dev/null 2>&1; then
|
||||||
|
echo "Warning: whiptail not available, skipping interactive configuration"
|
||||||
|
export CLOUDINIT_ENABLE="no"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ask if user wants to enable Cloud-Init
|
||||||
|
if ! (whiptail --backtitle "Proxmox VE Helper Scripts" --title "CLOUD-INIT" \
|
||||||
|
--yesno "Enable Cloud-Init for VM configuration?\n\nCloud-Init allows automatic configuration of:\n• User accounts and passwords\n• SSH keys\n• Network settings (DHCP/Static)\n• DNS configuration\n\nYou can also configure these settings later in Proxmox UI." 16 68); then
|
||||||
|
export CLOUDINIT_ENABLE="no"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
export CLOUDINIT_ENABLE="yes"
|
||||||
|
|
||||||
|
# Username
|
||||||
|
if CLOUDINIT_USER=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox \
|
||||||
|
"Cloud-Init Username" 8 58 "$default_user" --title "USERNAME" 3>&1 1>&2 2>&3); then
|
||||||
|
export CLOUDINIT_USER="${CLOUDINIT_USER:-$default_user}"
|
||||||
|
else
|
||||||
|
export CLOUDINIT_USER="$default_user"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Network configuration
|
||||||
|
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "NETWORK MODE" \
|
||||||
|
--yesno "Use DHCP for network configuration?\n\nSelect 'No' for static IP configuration." 10 58); then
|
||||||
|
export CLOUDINIT_NETWORK_MODE="dhcp"
|
||||||
|
else
|
||||||
|
export CLOUDINIT_NETWORK_MODE="static"
|
||||||
|
|
||||||
|
# Static IP
|
||||||
|
if CLOUDINIT_IP=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox \
|
||||||
|
"Static IP Address (CIDR format)\nExample: 192.168.1.100/24" 9 58 "" --title "IP ADDRESS" 3>&1 1>&2 2>&3); then
|
||||||
|
export CLOUDINIT_IP
|
||||||
|
else
|
||||||
|
echo "Error: Static IP required for static network mode"
|
||||||
|
export CLOUDINIT_NETWORK_MODE="dhcp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Gateway
|
||||||
|
if [ "$CLOUDINIT_NETWORK_MODE" = "static" ]; then
|
||||||
|
if CLOUDINIT_GW=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox \
|
||||||
|
"Gateway IP Address\nExample: 192.168.1.1" 8 58 "" --title "GATEWAY" 3>&1 1>&2 2>&3); then
|
||||||
|
export CLOUDINIT_GW
|
||||||
|
else
|
||||||
|
echo "Error: Gateway required for static network mode"
|
||||||
|
export CLOUDINIT_NETWORK_MODE="dhcp"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# DNS Servers
|
||||||
|
if CLOUDINIT_DNS=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox \
|
||||||
|
"DNS Servers (space-separated)" 8 58 "1.1.1.1 8.8.8.8" --title "DNS SERVERS" 3>&1 1>&2 2>&3); then
|
||||||
|
export CLOUDINIT_DNS="${CLOUDINIT_DNS:-1.1.1.1 8.8.8.8}"
|
||||||
|
else
|
||||||
|
export CLOUDINIT_DNS="1.1.1.1 8.8.8.8"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Display Cloud-Init Summary Information
|
||||||
|
# ==============================================================================
|
||||||
|
function display_cloud_init_info() {
|
||||||
|
local vmid="$1"
|
||||||
|
local hostname="${2:-}"
|
||||||
|
|
||||||
|
if [ -n "$CLOUDINIT_CRED_FILE" ] && [ -f "$CLOUDINIT_CRED_FILE" ]; then
|
||||||
|
if [ -n "${INFO:-}" ]; then
|
||||||
|
echo -e "\n${INFO}${BOLD:-}${GN:-} Cloud-Init Configuration:${CL:-}"
|
||||||
|
echo -e "${TAB:- }${DGN:-}User: ${BGN:-}${CLOUDINIT_USER:-root}${CL:-}"
|
||||||
|
echo -e "${TAB:- }${DGN:-}Password: ${BGN:-}${CLOUDINIT_PASSWORD}${CL:-}"
|
||||||
|
echo -e "${TAB:- }${DGN:-}Credentials: ${BL:-}${CLOUDINIT_CRED_FILE}${CL:-}"
|
||||||
|
echo -e "${TAB:- }${YW:-}💡 You can configure Cloud-Init settings in Proxmox UI:${CL:-}"
|
||||||
|
echo -e "${TAB:- }${YW:-} VM ${vmid} > Cloud-Init > Edit (User, Password, SSH Keys, Network)${CL:-}"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo "[INFO] Cloud-Init Configuration:"
|
||||||
|
echo " User: ${CLOUDINIT_USER:-root}"
|
||||||
|
echo " Password: ${CLOUDINIT_PASSWORD}"
|
||||||
|
echo " Credentials: ${CLOUDINIT_CRED_FILE}"
|
||||||
|
echo " You can configure Cloud-Init settings in Proxmox UI:"
|
||||||
|
echo " VM ${vmid} > Cloud-Init > Edit"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Check if VM has Cloud-Init configured
|
||||||
|
# ==============================================================================
|
||||||
|
function has_cloud_init() {
|
||||||
|
local vmid="$1"
|
||||||
|
qm config "$vmid" 2>/dev/null | grep -qE "(ide2|scsi1):.*cloudinit"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Regenerate Cloud-Init configuration
|
||||||
|
# ==============================================================================
|
||||||
|
function regenerate_cloud_init() {
|
||||||
|
local vmid="$1"
|
||||||
|
|
||||||
|
if has_cloud_init "$vmid"; then
|
||||||
|
msg_info "Regenerating Cloud-Init configuration" 2>/dev/null || echo "[INFO] Regenerating Cloud-Init"
|
||||||
|
qm cloudinit update "$vmid" >/dev/null 2>&1 || true
|
||||||
|
msg_ok "Cloud-Init configuration regenerated" 2>/dev/null || echo "[OK] Cloud-Init regenerated"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "Warning: VM $vmid does not have Cloud-Init configured"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Get VM IP address via qemu-guest-agent
|
||||||
|
# ==============================================================================
|
||||||
|
function get_vm_ip() {
|
||||||
|
local vmid="$1"
|
||||||
|
local timeout="${2:-30}"
|
||||||
|
|
||||||
|
local elapsed=0
|
||||||
|
while [ $elapsed -lt $timeout ]; do
|
||||||
|
local vm_ip=$(qm guest cmd "$vmid" network-get-interfaces 2>/dev/null |
|
||||||
|
jq -r '.[] | select(.name != "lo") | ."ip-addresses"[]? | select(."ip-address-type" == "ipv4") | ."ip-address"' 2>/dev/null | head -1)
|
||||||
|
|
||||||
|
if [ -n "$vm_ip" ]; then
|
||||||
|
echo "$vm_ip"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
elapsed=$((elapsed + 2))
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Wait for Cloud-Init to complete (requires SSH access)
|
||||||
|
# ==============================================================================
|
||||||
|
function wait_for_cloud_init() {
|
||||||
|
local vmid="$1"
|
||||||
|
local timeout="${2:-300}"
|
||||||
|
local vm_ip="${3:-}"
|
||||||
|
|
||||||
|
# Get IP if not provided
|
||||||
|
if [ -z "$vm_ip" ]; then
|
||||||
|
vm_ip=$(get_vm_ip "$vmid" 60)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$vm_ip" ]; then
|
||||||
|
echo "Warning: Unable to determine VM IP address"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Waiting for Cloud-Init to complete on ${vm_ip}" 2>/dev/null || echo "[INFO] Waiting for Cloud-Init on ${vm_ip}"
|
||||||
|
|
||||||
|
local elapsed=0
|
||||||
|
while [ $elapsed -lt $timeout ]; do
|
||||||
|
if timeout 10 ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
||||||
|
"${CLOUDINIT_USER:-root}@${vm_ip}" "cloud-init status --wait" 2>/dev/null; then
|
||||||
|
msg_ok "Cloud-Init completed successfully" 2>/dev/null || echo "[OK] Cloud-Init completed"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 10
|
||||||
|
elapsed=$((elapsed + 10))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Warning: Cloud-Init did not complete within ${timeout}s"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Export all functions for use in other scripts
|
||||||
|
# ==============================================================================
|
||||||
|
export -f setup_cloud_init 2>/dev/null || true
|
||||||
|
export -f configure_cloud_init_interactive 2>/dev/null || true
|
||||||
|
export -f display_cloud_init_info 2>/dev/null || true
|
||||||
|
export -f has_cloud_init 2>/dev/null || true
|
||||||
|
export -f regenerate_cloud_init 2>/dev/null || true
|
||||||
|
export -f get_vm_ip 2>/dev/null || true
|
||||||
|
export -f wait_for_cloud_init 2>/dev/null || true
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Quick Start Examples
|
||||||
|
# ==============================================================================
|
||||||
|
: <<'EXAMPLES'
|
||||||
|
|
||||||
|
# Example 1: Simple DHCP setup (most common)
|
||||||
|
setup_cloud_init "$VMID" "$STORAGE" "$HN" "yes"
|
||||||
|
|
||||||
|
# Example 2: Static IP setup
|
||||||
|
setup_cloud_init "$VMID" "$STORAGE" "myserver" "yes" "root" "static" "192.168.1.100/24" "192.168.1.1"
|
||||||
|
|
||||||
|
# Example 3: Interactive configuration in advanced_settings()
|
||||||
|
configure_cloud_init_interactive "admin"
|
||||||
|
if [ "$CLOUDINIT_ENABLE" = "yes" ]; then
|
||||||
|
setup_cloud_init "$VMID" "$STORAGE" "$HN" "yes" "$CLOUDINIT_USER" \
|
||||||
|
"$CLOUDINIT_NETWORK_MODE" "$CLOUDINIT_IP" "$CLOUDINIT_GW" "$CLOUDINIT_DNS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Example 4: Display info after VM creation
|
||||||
|
display_cloud_init_info "$VMID" "$HN"
|
||||||
|
|
||||||
|
# Example 5: Check if VM has Cloud-Init
|
||||||
|
if has_cloud_init "$VMID"; then
|
||||||
|
echo "Cloud-Init is configured"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Example 6: Wait for Cloud-Init to complete after VM start
|
||||||
|
if [ "$START_VM" = "yes" ]; then
|
||||||
|
qm start "$VMID"
|
||||||
|
sleep 30
|
||||||
|
wait_for_cloud_init "$VMID" 300
|
||||||
|
fi
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
724
misc/core.func
724
misc/core.func
@ -2,13 +2,34 @@
|
|||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
# License: MIT | https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/LICENSE
|
# License: MIT | https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/LICENSE
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ==============================================================================
|
||||||
# Loads core utility groups once (colors, formatting, icons, defaults).
|
# CORE FUNCTIONS - LXC CONTAINER UTILITIES
|
||||||
# ------------------------------------------------------------------------------
|
# ==============================================================================
|
||||||
|
#
|
||||||
|
# This file provides core utility functions for LXC container management
|
||||||
|
# including colors, formatting, validation checks, message output, and
|
||||||
|
# execution helpers used throughout the Community-Scripts ecosystem.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# source <(curl -fsSL https://git.community-scripts.org/.../core.func)
|
||||||
|
# load_functions
|
||||||
|
#
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
[[ -n "${_CORE_FUNC_LOADED:-}" ]] && return
|
[[ -n "${_CORE_FUNC_LOADED:-}" ]] && return
|
||||||
_CORE_FUNC_LOADED=1
|
_CORE_FUNC_LOADED=1
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SECTION 1: INITIALIZATION & SETUP
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# load_functions()
|
||||||
|
#
|
||||||
|
# - Initializes all core utility groups (colors, formatting, icons, defaults)
|
||||||
|
# - Ensures functions are loaded only once via __FUNCTIONS_LOADED flag
|
||||||
|
# - Must be called at start of any script using these utilities
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
load_functions() {
|
load_functions() {
|
||||||
[[ -n "${__FUNCTIONS_LOADED:-}" ]] && return
|
[[ -n "${__FUNCTIONS_LOADED:-}" ]] && return
|
||||||
__FUNCTIONS_LOADED=1
|
__FUNCTIONS_LOADED=1
|
||||||
@ -17,11 +38,14 @@ load_functions() {
|
|||||||
icons
|
icons
|
||||||
default_vars
|
default_vars
|
||||||
set_std_mode
|
set_std_mode
|
||||||
# add more
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Sets ANSI color codes used for styled terminal output.
|
# color()
|
||||||
|
#
|
||||||
|
# - Sets ANSI color codes for styled terminal output
|
||||||
|
# - Variables: YW (yellow), YWB (yellow bright), BL (blue), RD (red)
|
||||||
|
# GN (green), DGN (dark green), BGN (background green), CL (clear)
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
color() {
|
color() {
|
||||||
YW=$(echo "\033[33m")
|
YW=$(echo "\033[33m")
|
||||||
@ -34,7 +58,14 @@ color() {
|
|||||||
CL=$(echo "\033[m")
|
CL=$(echo "\033[m")
|
||||||
}
|
}
|
||||||
|
|
||||||
# Special for spinner and colorized output via printf
|
# ------------------------------------------------------------------------------
|
||||||
|
# color_spinner()
|
||||||
|
#
|
||||||
|
# - Sets ANSI color codes specifically for spinner animation
|
||||||
|
# - Variables: CS_YW (spinner yellow), CS_YWB (spinner yellow bright),
|
||||||
|
# CS_CL (spinner clear)
|
||||||
|
# - Used by spinner() function to avoid color conflicts
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
color_spinner() {
|
color_spinner() {
|
||||||
CS_YW=$'\033[33m'
|
CS_YW=$'\033[33m'
|
||||||
CS_YWB=$'\033[93m'
|
CS_YWB=$'\033[93m'
|
||||||
@ -42,7 +73,12 @@ color_spinner() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Defines formatting helpers like tab, bold, and line reset sequences.
|
# formatting()
|
||||||
|
#
|
||||||
|
# - Defines formatting helpers for terminal output
|
||||||
|
# - BFR: Backspace and clear line sequence
|
||||||
|
# - BOLD: Bold text escape code
|
||||||
|
# - TAB/TAB3: Indentation spacing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
formatting() {
|
formatting() {
|
||||||
BFR="\\r\\033[K"
|
BFR="\\r\\033[K"
|
||||||
@ -53,7 +89,11 @@ formatting() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Sets symbolic icons used throughout user feedback and prompts.
|
# icons()
|
||||||
|
#
|
||||||
|
# - Sets symbolic emoji icons used throughout user feedback
|
||||||
|
# - Provides consistent visual indicators for success, error, info, etc.
|
||||||
|
# - Icons: CM (checkmark), CROSS (error), INFO (info), HOURGLASS (wait), etc.
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
icons() {
|
icons() {
|
||||||
CM="${TAB}✔️${TAB}"
|
CM="${TAB}✔️${TAB}"
|
||||||
@ -84,21 +124,29 @@ icons() {
|
|||||||
ADVANCED="${TAB}🧩${TAB}${CL}"
|
ADVANCED="${TAB}🧩${TAB}${CL}"
|
||||||
FUSE="${TAB}🗂️${TAB}${CL}"
|
FUSE="${TAB}🗂️${TAB}${CL}"
|
||||||
HOURGLASS="${TAB}⏳${TAB}"
|
HOURGLASS="${TAB}⏳${TAB}"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Sets default retry and wait variables used for system actions.
|
# default_vars()
|
||||||
|
#
|
||||||
|
# - Sets default retry and wait variables used for system actions
|
||||||
|
# - RETRY_NUM: Maximum number of retry attempts (default: 10)
|
||||||
|
# - RETRY_EVERY: Seconds to wait between retries (default: 3)
|
||||||
|
# - i: Counter variable initialized to RETRY_NUM
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
default_vars() {
|
default_vars() {
|
||||||
RETRY_NUM=10
|
RETRY_NUM=10
|
||||||
RETRY_EVERY=3
|
RETRY_EVERY=3
|
||||||
i=$RETRY_NUM
|
i=$RETRY_NUM
|
||||||
#[[ "${VAR_OS:-}" == "unknown" ]]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Sets default verbose mode for script and os execution.
|
# set_std_mode()
|
||||||
|
#
|
||||||
|
# - Sets default verbose mode for script and OS execution
|
||||||
|
# - If VERBOSE=yes: STD="" (show all output)
|
||||||
|
# - If VERBOSE=no: STD="silent" (suppress output via silent() wrapper)
|
||||||
|
# - If DEV_MODE_TRACE=true: Enables bash tracing (set -x)
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
set_std_mode() {
|
set_std_mode() {
|
||||||
if [ "${VERBOSE:-no}" = "yes" ]; then
|
if [ "${VERBOSE:-no}" = "yes" ]; then
|
||||||
@ -106,53 +154,93 @@ set_std_mode() {
|
|||||||
else
|
else
|
||||||
STD="silent"
|
STD="silent"
|
||||||
fi
|
fi
|
||||||
}
|
|
||||||
|
|
||||||
SILENT_LOGFILE="/tmp/silent.$$.log"
|
# Enable bash tracing if trace mode active
|
||||||
|
if [[ "${DEV_MODE_TRACE:-false}" == "true" ]]; then
|
||||||
silent() {
|
set -x
|
||||||
local cmd="$*"
|
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
||||||
local caller_line="${BASH_LINENO[0]:-unknown}"
|
|
||||||
|
|
||||||
set +Eeuo pipefail
|
|
||||||
trap - ERR
|
|
||||||
|
|
||||||
"$@" >>"$SILENT_LOGFILE" 2>&1
|
|
||||||
local rc=$?
|
|
||||||
|
|
||||||
set -Eeuo pipefail
|
|
||||||
trap 'error_handler' ERR
|
|
||||||
|
|
||||||
if [[ $rc -ne 0 ]]; then
|
|
||||||
# Source explain_exit_code if needed
|
|
||||||
if ! declare -f explain_exit_code >/dev/null 2>&1; then
|
|
||||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/error_handler.func)
|
|
||||||
fi
|
|
||||||
|
|
||||||
local explanation
|
|
||||||
explanation="$(explain_exit_code "$rc")"
|
|
||||||
|
|
||||||
printf "\e[?25h"
|
|
||||||
echo -e "\n${RD}[ERROR]${CL} in line ${RD}${caller_line}${CL}: exit code ${RD}${rc}${CL} (${explanation})"
|
|
||||||
echo -e "${RD}Command:${CL} ${YWB}${cmd}${CL}\n"
|
|
||||||
|
|
||||||
if [[ -s "$SILENT_LOGFILE" ]]; then
|
|
||||||
local log_lines=$(wc -l <"$SILENT_LOGFILE")
|
|
||||||
echo "--- Last 10 lines of silent log ---"
|
|
||||||
tail -n 10 "$SILENT_LOGFILE"
|
|
||||||
echo "-----------------------------------"
|
|
||||||
|
|
||||||
# Show how to view full log if there are more lines
|
|
||||||
if [[ $log_lines -gt 10 ]]; then
|
|
||||||
echo -e "${YW}View full log (${log_lines} lines):${CL} cat $SILENT_LOGFILE"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit "$rc"
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check if the shell is using bash
|
# ------------------------------------------------------------------------------
|
||||||
|
# parse_dev_mode()
|
||||||
|
#
|
||||||
|
# - Parses comma-separated dev_mode variable (e.g., "motd,keep,trace")
|
||||||
|
# - Sets global flags for each mode:
|
||||||
|
# * DEV_MODE_MOTD: Setup SSH/MOTD before installation
|
||||||
|
# * DEV_MODE_KEEP: Never delete container on failure
|
||||||
|
# * DEV_MODE_TRACE: Enable bash set -x tracing
|
||||||
|
# * DEV_MODE_PAUSE: Pause after each msg_info step
|
||||||
|
# * DEV_MODE_BREAKPOINT: Open shell on error instead of cleanup
|
||||||
|
# * DEV_MODE_LOGS: Persist all logs to /var/log/community-scripts/
|
||||||
|
# * DEV_MODE_DRYRUN: Show commands without executing
|
||||||
|
# - Call this early in script execution
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
parse_dev_mode() {
|
||||||
|
local mode
|
||||||
|
# Initialize all flags to false
|
||||||
|
export DEV_MODE_MOTD=false
|
||||||
|
export DEV_MODE_KEEP=false
|
||||||
|
export DEV_MODE_TRACE=false
|
||||||
|
export DEV_MODE_PAUSE=false
|
||||||
|
export DEV_MODE_BREAKPOINT=false
|
||||||
|
export DEV_MODE_LOGS=false
|
||||||
|
export DEV_MODE_DRYRUN=false
|
||||||
|
|
||||||
|
# Parse comma-separated modes
|
||||||
|
if [[ -n "${dev_mode:-}" ]]; then
|
||||||
|
IFS=',' read -ra MODES <<<"$dev_mode"
|
||||||
|
for mode in "${MODES[@]}"; do
|
||||||
|
mode="$(echo "$mode" | xargs)" # Trim whitespace
|
||||||
|
case "$mode" in
|
||||||
|
motd) export DEV_MODE_MOTD=true ;;
|
||||||
|
keep) export DEV_MODE_KEEP=true ;;
|
||||||
|
trace) export DEV_MODE_TRACE=true ;;
|
||||||
|
pause) export DEV_MODE_PAUSE=true ;;
|
||||||
|
breakpoint) export DEV_MODE_BREAKPOINT=true ;;
|
||||||
|
logs) export DEV_MODE_LOGS=true ;;
|
||||||
|
dryrun) export DEV_MODE_DRYRUN=true ;;
|
||||||
|
*)
|
||||||
|
if declare -f msg_warn >/dev/null 2>&1; then
|
||||||
|
msg_warn "Unknown dev_mode: '$mode' (ignored)"
|
||||||
|
else
|
||||||
|
echo "[WARN] Unknown dev_mode: '$mode' (ignored)" >&2
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Show active dev modes
|
||||||
|
local active_modes=()
|
||||||
|
[[ $DEV_MODE_MOTD == true ]] && active_modes+=("motd")
|
||||||
|
[[ $DEV_MODE_KEEP == true ]] && active_modes+=("keep")
|
||||||
|
[[ $DEV_MODE_TRACE == true ]] && active_modes+=("trace")
|
||||||
|
[[ $DEV_MODE_PAUSE == true ]] && active_modes+=("pause")
|
||||||
|
[[ $DEV_MODE_BREAKPOINT == true ]] && active_modes+=("breakpoint")
|
||||||
|
[[ $DEV_MODE_LOGS == true ]] && active_modes+=("logs")
|
||||||
|
[[ $DEV_MODE_DRYRUN == true ]] && active_modes+=("dryrun")
|
||||||
|
|
||||||
|
if [[ ${#active_modes[@]} -gt 0 ]]; then
|
||||||
|
if declare -f msg_custom >/dev/null 2>&1; then
|
||||||
|
msg_custom "🔧" "${YWB}" "Dev modes active: ${active_modes[*]}"
|
||||||
|
else
|
||||||
|
echo "[DEV] Active modes: ${active_modes[*]}" >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SECTION 2: VALIDATION CHECKS
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# shell_check()
|
||||||
|
#
|
||||||
|
# - Verifies that the script is running under Bash shell
|
||||||
|
# - Exits with error message if different shell is detected
|
||||||
|
# - Required because scripts use Bash-specific features
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
shell_check() {
|
shell_check() {
|
||||||
if [[ "$(ps -p $$ -o comm=)" != "bash" ]]; then
|
if [[ "$(ps -p $$ -o comm=)" != "bash" ]]; then
|
||||||
clear
|
clear
|
||||||
@ -163,7 +251,13 @@ shell_check() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run as root only
|
# ------------------------------------------------------------------------------
|
||||||
|
# root_check()
|
||||||
|
#
|
||||||
|
# - Verifies script is running with root privileges
|
||||||
|
# - Detects if executed via sudo (which can cause issues)
|
||||||
|
# - Exits with error if not running as root directly
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
root_check() {
|
root_check() {
|
||||||
if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
|
if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
|
||||||
clear
|
clear
|
||||||
@ -174,8 +268,13 @@ root_check() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function checks the version of Proxmox Virtual Environment (PVE) and exits if the version is not supported.
|
# ------------------------------------------------------------------------------
|
||||||
# Supported: Proxmox VE 8.0.x – 8.9.x and 9.0 (NOT 9.1+)
|
# pve_check()
|
||||||
|
#
|
||||||
|
# - Validates Proxmox VE version compatibility
|
||||||
|
# - Supported: PVE 8.0-8.9 and PVE 9.0-9.1
|
||||||
|
# - Exits with error message if unsupported version detected
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
pve_check() {
|
pve_check() {
|
||||||
local PVE_VER
|
local PVE_VER
|
||||||
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
|
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
|
||||||
@ -191,12 +290,12 @@ pve_check() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check for Proxmox VE 9.x: allow ONLY 9.0
|
# Check for Proxmox VE 9.x: allow 9.0–9.1
|
||||||
if [[ "$PVE_VER" =~ ^9\.([0-9]+) ]]; then
|
if [[ "$PVE_VER" =~ ^9\.([0-9]+) ]]; then
|
||||||
local MINOR="${BASH_REMATCH[1]}"
|
local MINOR="${BASH_REMATCH[1]}"
|
||||||
if ((MINOR != 0)); then
|
if ((MINOR < 0 || MINOR > 1)); then
|
||||||
msg_error "This version of Proxmox VE is not yet supported."
|
msg_error "This version of Proxmox VE is not yet supported."
|
||||||
msg_error "Supported: Proxmox VE version 9.0"
|
msg_error "Supported: Proxmox VE version 9.0 – 9.1"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
@ -204,11 +303,17 @@ pve_check() {
|
|||||||
|
|
||||||
# All other unsupported versions
|
# All other unsupported versions
|
||||||
msg_error "This version of Proxmox VE is not supported."
|
msg_error "This version of Proxmox VE is not supported."
|
||||||
msg_error "Supported versions: Proxmox VE 8.0 – 8.x or 9.0"
|
msg_error "Supported versions: Proxmox VE 8.0 – 8.9 or 9.0 – 9.1"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function checks the system architecture and exits if it's not "amd64".
|
# ------------------------------------------------------------------------------
|
||||||
|
# arch_check()
|
||||||
|
#
|
||||||
|
# - Validates system architecture is amd64/x86_64
|
||||||
|
# - Exits with error message for unsupported architectures (e.g., ARM/PiMox)
|
||||||
|
# - Provides link to ARM64-compatible scripts
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
arch_check() {
|
arch_check() {
|
||||||
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
|
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
|
||||||
echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n"
|
echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n"
|
||||||
@ -222,111 +327,165 @@ arch_check() {
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# ssh_check()
|
# ssh_check()
|
||||||
#
|
#
|
||||||
# - Detects if script is running over SSH
|
# - Detects if script is running over SSH connection
|
||||||
# - Warns user and recommends using Proxmox shell
|
# - Warns user for external SSH connections (recommends Proxmox shell)
|
||||||
# - User can choose to continue or abort
|
# - Skips warning for local/same-subnet connections
|
||||||
|
# - Does not abort execution, only warns
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
ssh_check() {
|
ssh_check() {
|
||||||
if [ -n "$SSH_CLIENT" ]; then
|
if [ -n "$SSH_CLIENT" ]; then
|
||||||
local client_ip=$(awk '{print $1}' <<<"$SSH_CLIENT")
|
local client_ip=$(awk '{print $1}' <<<"$SSH_CLIENT")
|
||||||
local host_ip=$(hostname -I | awk '{print $1}')
|
local host_ip=$(hostname -I | awk '{print $1}')
|
||||||
|
|
||||||
if [[ "$client_ip" == "127.0.0.1" || "$client_ip" == "$host_ip" ]]; then
|
# Check if connection is local (Proxmox WebUI or same machine)
|
||||||
|
# - localhost (127.0.0.1, ::1)
|
||||||
|
# - same IP as host
|
||||||
|
# - local network range (10.x, 172.16-31.x, 192.168.x)
|
||||||
|
if [[ "$client_ip" == "127.0.0.1" || "$client_ip" == "::1" || "$client_ip" == "$host_ip" ]]; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check if client is in same local network (optional, safer approach)
|
||||||
|
local host_subnet=$(echo "$host_ip" | cut -d. -f1-3)
|
||||||
|
local client_subnet=$(echo "$client_ip" | cut -d. -f1-3)
|
||||||
|
if [[ "$host_subnet" == "$client_subnet" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Only warn for truly external connections
|
||||||
msg_warn "Running via external SSH (client: $client_ip)."
|
msg_warn "Running via external SSH (client: $client_ip)."
|
||||||
|
msg_warn "For better stability, consider using the Proxmox Shell (Console) instead."
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to download & save header files
|
# ==============================================================================
|
||||||
get_header() {
|
# SECTION 3: EXECUTION HELPERS
|
||||||
local app_name=$(echo "${APP,,}" | tr -d ' ')
|
# ==============================================================================
|
||||||
local app_type=${APP_TYPE:-ct} # Default zu 'ct' falls nicht gesetzt
|
|
||||||
local header_url="https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/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")"
|
# ------------------------------------------------------------------------------
|
||||||
|
# get_active_logfile()
|
||||||
if [ ! -s "$local_header_path" ]; then
|
#
|
||||||
if ! curl -fsSL "$header_url" -o "$local_header_path"; then
|
# - Returns the appropriate log file based on execution context
|
||||||
return 1
|
# - BUILD_LOG: Host operations (container creation)
|
||||||
fi
|
# - INSTALL_LOG: Container operations (application installation)
|
||||||
fi
|
# - Fallback to BUILD_LOG if neither is set
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
cat "$local_header_path" 2>/dev/null || true
|
get_active_logfile() {
|
||||||
}
|
if [[ -n "${INSTALL_LOG:-}" ]]; then
|
||||||
|
echo "$INSTALL_LOG"
|
||||||
header_info() {
|
elif [[ -n "${BUILD_LOG:-}" ]]; then
|
||||||
local app_name=$(echo "${APP,,}" | tr -d ' ')
|
echo "$BUILD_LOG"
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_tput() {
|
|
||||||
if ! command -v tput >/dev/null 2>&1; then
|
|
||||||
if grep -qi 'alpine' /etc/os-release; then
|
|
||||||
apk add --no-cache ncurses >/dev/null 2>&1
|
|
||||||
elif command -v apt-get >/dev/null 2>&1; then
|
|
||||||
apt-get update -qq >/dev/null
|
|
||||||
apt-get install -y -qq ncurses-bin >/dev/null 2>&1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
is_alpine() {
|
|
||||||
local os_id="${var_os:-${PCT_OSTYPE:-}}"
|
|
||||||
|
|
||||||
if [[ -z "$os_id" && -f /etc/os-release ]]; then
|
|
||||||
os_id="$(
|
|
||||||
. /etc/os-release 2>/dev/null
|
|
||||||
echo "${ID:-}"
|
|
||||||
)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
[[ "$os_id" == "alpine" ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
is_verbose_mode() {
|
|
||||||
local verbose="${VERBOSE:-${var_verbose:-no}}"
|
|
||||||
local tty_status
|
|
||||||
if [[ -t 2 ]]; then
|
|
||||||
tty_status="interactive"
|
|
||||||
else
|
else
|
||||||
tty_status="not-a-tty"
|
# Fallback for legacy scripts
|
||||||
|
echo "/tmp/build-$(date +%Y%m%d_%H%M%S).log"
|
||||||
fi
|
fi
|
||||||
[[ "$verbose" != "no" || ! -t 2 ]]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fatal() {
|
# Legacy compatibility: SILENT_LOGFILE points to active log
|
||||||
msg_error "$1"
|
SILENT_LOGFILE="$(get_active_logfile)"
|
||||||
kill -INT $$
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# silent()
|
||||||
|
#
|
||||||
|
# - Executes command with output redirected to active log file
|
||||||
|
# - On error: displays last 10 lines of log and exits with original exit code
|
||||||
|
# - Temporarily disables error trap to capture exit code correctly
|
||||||
|
# - Sources explain_exit_code() for detailed error messages
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
silent() {
|
||||||
|
local cmd="$*"
|
||||||
|
local caller_line="${BASH_LINENO[0]:-unknown}"
|
||||||
|
local logfile="$(get_active_logfile)"
|
||||||
|
|
||||||
|
# Dryrun mode: Show command without executing
|
||||||
|
if [[ "${DEV_MODE_DRYRUN:-false}" == "true" ]]; then
|
||||||
|
if declare -f msg_custom >/dev/null 2>&1; then
|
||||||
|
msg_custom "🔍" "${BL}" "[DRYRUN] $cmd"
|
||||||
|
else
|
||||||
|
echo "[DRYRUN] $cmd" >&2
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
set +Eeuo pipefail
|
||||||
|
trap - ERR
|
||||||
|
|
||||||
|
"$@" >>"$logfile" 2>&1
|
||||||
|
local rc=$?
|
||||||
|
|
||||||
|
set -Eeuo pipefail
|
||||||
|
trap 'error_handler' ERR
|
||||||
|
|
||||||
|
if [[ $rc -ne 0 ]]; then
|
||||||
|
# Source explain_exit_code if needed
|
||||||
|
if ! declare -f explain_exit_code >/dev/null 2>&1; then
|
||||||
|
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/error_handler.func)
|
||||||
|
fi
|
||||||
|
|
||||||
|
local explanation
|
||||||
|
explanation="$(explain_exit_code "$rc")"
|
||||||
|
|
||||||
|
printf "\e[?25h"
|
||||||
|
msg_error "in line ${caller_line}: exit code ${rc} (${explanation})"
|
||||||
|
msg_custom "→" "${YWB}" "${cmd}"
|
||||||
|
|
||||||
|
if [[ -s "$logfile" ]]; then
|
||||||
|
local log_lines=$(wc -l <"$logfile")
|
||||||
|
echo "--- Last 10 lines of silent log ---"
|
||||||
|
tail -n 10 "$logfile"
|
||||||
|
echo "-----------------------------------"
|
||||||
|
|
||||||
|
# Show how to view full log if there are more lines
|
||||||
|
if [[ $log_lines -gt 10 ]]; then
|
||||||
|
msg_custom "📋" "${YW}" "View full log (${log_lines} lines): ${logfile}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit "$rc"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# spinner()
|
||||||
|
#
|
||||||
|
# - Displays animated spinner with rotating characters (⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏)
|
||||||
|
# - Shows SPINNER_MSG alongside animation
|
||||||
|
# - Runs in infinite loop until killed by stop_spinner()
|
||||||
|
# - Uses color_spinner() colors for output
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
spinner() {
|
spinner() {
|
||||||
local chars=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏)
|
local chars=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏)
|
||||||
|
local msg="${SPINNER_MSG:-Processing...}"
|
||||||
local i=0
|
local i=0
|
||||||
while true; do
|
while true; do
|
||||||
local index=$((i++ % ${#chars[@]}))
|
local index=$((i++ % ${#chars[@]}))
|
||||||
printf "\r\033[2K%s %b" "${CS_YWB}${chars[$index]}${CS_CL}" "${CS_YWB}${SPINNER_MSG:-}${CS_CL}"
|
printf "\r\033[2K%s %b" "${CS_YWB}${chars[$index]}${CS_CL}" "${CS_YWB}${msg}${CS_CL}"
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# clear_line()
|
||||||
|
#
|
||||||
|
# - Clears current terminal line using tput or ANSI escape codes
|
||||||
|
# - Moves cursor to beginning of line (carriage return)
|
||||||
|
# - Erases from cursor to end of line
|
||||||
|
# - Fallback to ANSI codes if tput not available
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
clear_line() {
|
clear_line() {
|
||||||
tput cr 2>/dev/null || echo -en "\r"
|
tput cr 2>/dev/null || echo -en "\r"
|
||||||
tput el 2>/dev/null || echo -en "\033[K"
|
tput el 2>/dev/null || echo -en "\033[K"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# stop_spinner()
|
||||||
|
#
|
||||||
|
# - Stops running spinner process by PID
|
||||||
|
# - Reads PID from SPINNER_PID variable or /tmp/.spinner.pid file
|
||||||
|
# - Attempts graceful kill, then forced kill if needed
|
||||||
|
# - Cleans up temp file and resets terminal state
|
||||||
|
# - Unsets SPINNER_PID and SPINNER_MSG variables
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
stop_spinner() {
|
stop_spinner() {
|
||||||
local pid="${SPINNER_PID:-}"
|
local pid="${SPINNER_PID:-}"
|
||||||
[[ -z "$pid" && -f /tmp/.spinner.pid ]] && pid=$(</tmp/.spinner.pid)
|
[[ -z "$pid" && -f /tmp/.spinner.pid ]] && pid=$(</tmp/.spinner.pid)
|
||||||
@ -344,6 +503,19 @@ stop_spinner() {
|
|||||||
stty sane 2>/dev/null || true
|
stty sane 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SECTION 4: MESSAGE OUTPUT
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# msg_info()
|
||||||
|
#
|
||||||
|
# - Displays informational message with spinner animation
|
||||||
|
# - Shows each unique message only once (tracked via MSG_INFO_SHOWN)
|
||||||
|
# - In verbose/Alpine mode: shows hourglass icon instead of spinner
|
||||||
|
# - Stops any existing spinner before starting new one
|
||||||
|
# - Backgrounds spinner process and stores PID for later cleanup
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
msg_info() {
|
msg_info() {
|
||||||
local msg="$1"
|
local msg="$1"
|
||||||
[[ -z "$msg" ]] && return
|
[[ -z "$msg" ]] && return
|
||||||
@ -360,6 +532,12 @@ msg_info() {
|
|||||||
if is_verbose_mode || is_alpine; then
|
if is_verbose_mode || is_alpine; then
|
||||||
local HOURGLASS="${TAB}⏳${TAB}"
|
local HOURGLASS="${TAB}⏳${TAB}"
|
||||||
printf "\r\e[2K%s %b" "$HOURGLASS" "${YW}${msg}${CL}" >&2
|
printf "\r\e[2K%s %b" "$HOURGLASS" "${YW}${msg}${CL}" >&2
|
||||||
|
|
||||||
|
# Pause mode: Wait for Enter after each step
|
||||||
|
if [[ "${DEV_MODE_PAUSE:-false}" == "true" ]]; then
|
||||||
|
echo -en "\n${YWB}[PAUSE]${CL} Press Enter to continue..." >&2
|
||||||
|
read -r
|
||||||
|
fi
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -368,29 +546,68 @@ msg_info() {
|
|||||||
SPINNER_PID=$!
|
SPINNER_PID=$!
|
||||||
echo "$SPINNER_PID" >/tmp/.spinner.pid
|
echo "$SPINNER_PID" >/tmp/.spinner.pid
|
||||||
disown "$SPINNER_PID" 2>/dev/null || true
|
disown "$SPINNER_PID" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Pause mode: Stop spinner and wait
|
||||||
|
if [[ "${DEV_MODE_PAUSE:-false}" == "true" ]]; then
|
||||||
|
stop_spinner
|
||||||
|
echo -en "\n${YWB}[PAUSE]${CL} Press Enter to continue..." >&2
|
||||||
|
read -r
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# msg_ok()
|
||||||
|
#
|
||||||
|
# - Displays success message with checkmark icon
|
||||||
|
# - Stops spinner and clears line before output
|
||||||
|
# - Removes message from MSG_INFO_SHOWN to allow re-display
|
||||||
|
# - Uses green color for success indication
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
msg_ok() {
|
msg_ok() {
|
||||||
local msg="$1"
|
local msg="$1"
|
||||||
[[ -z "$msg" ]] && return
|
[[ -z "$msg" ]] && return
|
||||||
stop_spinner
|
stop_spinner
|
||||||
clear_line
|
clear_line
|
||||||
printf "%s %b\n" "$CM" "${GN}${msg}${CL}" >&2
|
echo -e "$CM ${GN}${msg}${CL}"
|
||||||
unset MSG_INFO_SHOWN["$msg"]
|
unset MSG_INFO_SHOWN["$msg"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# msg_error()
|
||||||
|
#
|
||||||
|
# - Displays error message with cross/X icon
|
||||||
|
# - Stops spinner before output
|
||||||
|
# - Uses red color for error indication
|
||||||
|
# - Outputs to stderr
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
msg_error() {
|
msg_error() {
|
||||||
stop_spinner
|
stop_spinner
|
||||||
local msg="$1"
|
local msg="$1"
|
||||||
echo -e "${BFR:-} ${CROSS:-✖️} ${RD}${msg}${CL}"
|
echo -e "${BFR:-}${CROSS:-✖️} ${RD}${msg}${CL}" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# msg_warn()
|
||||||
|
#
|
||||||
|
# - Displays warning message with info/lightbulb icon
|
||||||
|
# - Stops spinner before output
|
||||||
|
# - Uses bright yellow color for warning indication
|
||||||
|
# - Outputs to stderr
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
msg_warn() {
|
msg_warn() {
|
||||||
stop_spinner
|
stop_spinner
|
||||||
local msg="$1"
|
local msg="$1"
|
||||||
echo -e "${BFR:-} ${INFO:-ℹ️} ${YWB}${msg}${CL}"
|
echo -e "${BFR:-}${INFO:-ℹ️} ${YWB}${msg}${CL}" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# msg_custom()
|
||||||
|
#
|
||||||
|
# - Displays custom message with user-defined symbol and color
|
||||||
|
# - Arguments: symbol, color code, message text
|
||||||
|
# - Stops spinner before output
|
||||||
|
# - Useful for specialized status messages
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
msg_custom() {
|
msg_custom() {
|
||||||
local symbol="${1:-"[*]"}"
|
local symbol="${1:-"[*]"}"
|
||||||
local color="${2:-"\e[36m"}"
|
local color="${2:-"\e[36m"}"
|
||||||
@ -400,13 +617,240 @@ msg_custom() {
|
|||||||
echo -e "${BFR:-} ${symbol} ${color}${msg}${CL:-\e[0m}"
|
echo -e "${BFR:-} ${symbol} ${color}${msg}${CL:-\e[0m}"
|
||||||
}
|
}
|
||||||
|
|
||||||
function msg_debug() {
|
# ------------------------------------------------------------------------------
|
||||||
|
# msg_debug()
|
||||||
|
#
|
||||||
|
# - Displays debug message with timestamp when var_full_verbose=1
|
||||||
|
# - Automatically enables var_verbose if not already set
|
||||||
|
# - Shows date/time prefix for log correlation
|
||||||
|
# - Uses bright yellow color for debug output
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
msg_debug() {
|
||||||
if [[ "${var_full_verbose:-0}" == "1" ]]; then
|
if [[ "${var_full_verbose:-0}" == "1" ]]; then
|
||||||
[[ "${var_verbose:-0}" != "1" ]] && var_verbose=1
|
[[ "${var_verbose:-0}" != "1" ]] && var_verbose=1
|
||||||
echo -e "${YWB}[$(date '+%F %T')] [DEBUG]${CL} $*"
|
echo -e "${YWB}[$(date '+%F %T')] [DEBUG]${CL} $*"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# msg_dev()
|
||||||
|
#
|
||||||
|
# - Display development mode messages with 🔧 icon
|
||||||
|
# - Only shown when dev_mode is active
|
||||||
|
# - Useful for debugging and development-specific output
|
||||||
|
# - Format: [DEV] message with distinct formatting
|
||||||
|
# - Usage: msg_dev "Container ready for debugging"
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
msg_dev() {
|
||||||
|
if [[ -n "${dev_mode:-}" ]]; then
|
||||||
|
echo -e "${SEARCH}${BOLD}${DGN}🔧 [DEV]${CL} $*"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
#
|
||||||
|
# - Displays error message and immediately terminates script
|
||||||
|
# - Sends SIGINT to current process to trigger error handler
|
||||||
|
# - Use for unrecoverable errors that require immediate exit
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
fatal() {
|
||||||
|
msg_error "$1"
|
||||||
|
kill -INT $$
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SECTION 5: UTILITY FUNCTIONS
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# exit_script()
|
||||||
|
#
|
||||||
|
# - Called when user cancels an action
|
||||||
|
# - Clears screen and displays exit message
|
||||||
|
# - Exits with default exit code
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
exit_script() {
|
||||||
|
clear
|
||||||
|
echo -e "\n${CROSS}${RD}User exited script${CL}\n"
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# get_header()
|
||||||
|
#
|
||||||
|
# - Downloads and caches application header ASCII art
|
||||||
|
# - Falls back to local cache if already downloaded
|
||||||
|
# - Determines app type (ct/vm) from APP_TYPE variable
|
||||||
|
# - Returns header content or empty string on failure
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
get_header() {
|
||||||
|
local app_name=$(echo "${APP,,}" | tr -d ' ')
|
||||||
|
local app_type=${APP_TYPE:-ct} # Default zu 'ct' falls nicht gesetzt
|
||||||
|
local header_url="https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/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()
|
||||||
|
#
|
||||||
|
# - Displays application header ASCII art at top of screen
|
||||||
|
# - Clears screen before displaying header
|
||||||
|
# - Detects terminal width for formatting
|
||||||
|
# - Returns silently if header not available
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# ensure_tput()
|
||||||
|
#
|
||||||
|
# - Ensures tput command is available for terminal control
|
||||||
|
# - Installs ncurses-bin on Debian/Ubuntu or ncurses on Alpine
|
||||||
|
# - Required for clear_line() and terminal width detection
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
ensure_tput() {
|
||||||
|
if ! command -v tput >/dev/null 2>&1; then
|
||||||
|
if grep -qi 'alpine' /etc/os-release; then
|
||||||
|
apk add --no-cache ncurses >/dev/null 2>&1
|
||||||
|
elif command -v apt-get >/dev/null 2>&1; then
|
||||||
|
apt-get update -qq >/dev/null
|
||||||
|
apt-get install -y -qq ncurses-bin >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# is_alpine()
|
||||||
|
#
|
||||||
|
# - Detects if running on Alpine Linux
|
||||||
|
# - Checks var_os, PCT_OSTYPE, or /etc/os-release
|
||||||
|
# - Returns 0 if Alpine, 1 otherwise
|
||||||
|
# - Used to adjust behavior for Alpine-specific commands
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
is_alpine() {
|
||||||
|
local os_id="${var_os:-${PCT_OSTYPE:-}}"
|
||||||
|
|
||||||
|
if [[ -z "$os_id" && -f /etc/os-release ]]; then
|
||||||
|
os_id="$(
|
||||||
|
. /etc/os-release 2>/dev/null
|
||||||
|
echo "${ID:-}"
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ "$os_id" == "alpine" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# is_verbose_mode()
|
||||||
|
#
|
||||||
|
# - Determines if script should run in verbose mode
|
||||||
|
# - Checks VERBOSE and var_verbose variables
|
||||||
|
# - Also returns true if not running in TTY (pipe/redirect scenario)
|
||||||
|
# - Used by msg_info() to decide between spinner and static output
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
is_verbose_mode() {
|
||||||
|
local verbose="${VERBOSE:-${var_verbose:-no}}"
|
||||||
|
local tty_status
|
||||||
|
if [[ -t 2 ]]; then
|
||||||
|
tty_status="interactive"
|
||||||
|
else
|
||||||
|
tty_status="not-a-tty"
|
||||||
|
fi
|
||||||
|
[[ "$verbose" != "no" || ! -t 2 ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SECTION 6: CLEANUP & MAINTENANCE
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# cleanup_lxc()
|
||||||
|
#
|
||||||
|
# - Comprehensive cleanup of package managers, caches, and logs
|
||||||
|
# - Supports Alpine (apk), Debian/Ubuntu (apt), and language package managers
|
||||||
|
# - Cleans: Python (pip/uv), Node.js (npm/yarn/pnpm), Go, Rust, Ruby, PHP
|
||||||
|
# - Truncates log files and vacuums systemd journal
|
||||||
|
# - Run at end of container creation to minimize disk usage
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
cleanup_lxc() {
|
||||||
|
msg_info "Cleaning up"
|
||||||
|
|
||||||
|
if is_alpine; then
|
||||||
|
$STD apk cache clean || true
|
||||||
|
rm -rf /var/cache/apk/*
|
||||||
|
else
|
||||||
|
$STD apt -y autoremove || true
|
||||||
|
$STD apt -y autoclean || true
|
||||||
|
$STD apt -y clean || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clear temp artifacts (keep sockets/FIFOs; ignore errors)
|
||||||
|
find /tmp /var/tmp -type f -name 'tmp*' -delete 2>/dev/null || true
|
||||||
|
find /tmp /var/tmp -type f -name 'tempfile*' -delete 2>/dev/null || true
|
||||||
|
|
||||||
|
# Truncate writable log files silently (permission errors ignored)
|
||||||
|
if command -v truncate >/dev/null 2>&1; then
|
||||||
|
find /var/log -type f -writable -print0 2>/dev/null |
|
||||||
|
xargs -0 -n1 truncate -s 0 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Python pip
|
||||||
|
if command -v pip &>/dev/null; then $STD pip cache purge || true; fi
|
||||||
|
# Python uv
|
||||||
|
if command -v uv &>/dev/null; then $STD uv cache clean || true; fi
|
||||||
|
# Node.js npm
|
||||||
|
if command -v npm &>/dev/null; then $STD npm cache clean --force || true; fi
|
||||||
|
# Node.js yarn
|
||||||
|
if command -v yarn &>/dev/null; then $STD yarn cache clean || true; fi
|
||||||
|
# Node.js pnpm
|
||||||
|
if command -v pnpm &>/dev/null; then $STD pnpm store prune || true; fi
|
||||||
|
# Go
|
||||||
|
if command -v go &>/dev/null; then $STD go clean -cache -modcache || true; fi
|
||||||
|
# Rust cargo
|
||||||
|
if command -v cargo &>/dev/null; then $STD cargo clean || true; fi
|
||||||
|
# Ruby gem
|
||||||
|
if command -v gem &>/dev/null; then $STD gem cleanup || true; fi
|
||||||
|
# Composer (PHP)
|
||||||
|
if command -v composer &>/dev/null; then $STD composer clear-cache || true; fi
|
||||||
|
|
||||||
|
if command -v journalctl &>/dev/null; then
|
||||||
|
# Journal rotation may fail if systemd-journald not fully initialized yet
|
||||||
|
journalctl --rotate 2>/dev/null || true
|
||||||
|
journalctl --vacuum-time=10m 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
msg_ok "Cleaned"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# check_or_create_swap()
|
||||||
|
#
|
||||||
|
# - Checks if swap is active on system
|
||||||
|
# - Offers to create swap file if none exists
|
||||||
|
# - Prompts user for swap size in MB
|
||||||
|
# - Creates /swapfile with specified size
|
||||||
|
# - Activates swap immediately
|
||||||
|
# - Returns 0 if swap active or successfully created, 1 if declined/failed
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
check_or_create_swap() {
|
check_or_create_swap() {
|
||||||
msg_info "Checking for active swap"
|
msg_info "Checking for active swap"
|
||||||
|
|
||||||
@ -445,4 +889,8 @@ check_or_create_swap() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SIGNAL TRAPS
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
trap 'stop_spinner' EXIT INT TERM
|
trap 'stop_spinner' EXIT INT TERM
|
||||||
|
|||||||
3516
misc/deferred/build.func.backup-20251029-123804
Normal file
3516
misc/deferred/build.func.backup-20251029-123804
Normal file
File diff suppressed because it is too large
Load Diff
3516
misc/deferred/build.func.backup-20251029-124205
Normal file
3516
misc/deferred/build.func.backup-20251029-124205
Normal file
File diff suppressed because it is too large
Load Diff
3517
misc/deferred/build.func.backup-20251029-124307
Normal file
3517
misc/deferred/build.func.backup-20251029-124307
Normal file
File diff suppressed because it is too large
Load Diff
3517
misc/deferred/build.func.backup-20251029-124334
Normal file
3517
misc/deferred/build.func.backup-20251029-124334
Normal file
File diff suppressed because it is too large
Load Diff
3517
misc/deferred/build.func.backup-refactoring-20251029-125644
Normal file
3517
misc/deferred/build.func.backup-refactoring-20251029-125644
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,44 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Error & Signal Handling for ProxmoxVED Scripts
|
# ERROR HANDLER - ERROR & SIGNAL MANAGEMENT
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
# Author: MickLesk (CanbiZ)
|
# Author: MickLesk (CanbiZ)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Provides comprehensive error handling and signal management for all scripts.
|
||||||
|
# Includes:
|
||||||
|
# - Exit code explanations (shell, package managers, databases, custom codes)
|
||||||
|
# - Error handler with detailed logging
|
||||||
|
# - Signal handlers (EXIT, INT, TERM)
|
||||||
|
# - Initialization function for trap setup
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# source <(curl -fsSL .../error_handler.func)
|
||||||
|
# catch_errors
|
||||||
|
#
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SECTION 1: EXIT CODE EXPLANATIONS
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# explain_exit_code()
|
||||||
|
#
|
||||||
|
# - Maps numeric exit codes to human-readable error descriptions
|
||||||
|
# - Supports:
|
||||||
|
# * Generic/Shell errors (1, 2, 126, 127, 128, 130, 137, 139, 143)
|
||||||
|
# * Package manager errors (APT, DPKG: 100, 101, 255)
|
||||||
|
# * Node.js/npm errors (243-249, 254)
|
||||||
|
# * Python/pip/uv errors (210-212)
|
||||||
|
# * PostgreSQL errors (231-234)
|
||||||
|
# * MySQL/MariaDB errors (241-244)
|
||||||
|
# * MongoDB errors (251-254)
|
||||||
|
# * Proxmox custom codes (200-231)
|
||||||
|
# - Returns description string for given exit code
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
explain_exit_code() {
|
explain_exit_code() {
|
||||||
local code="$1"
|
local code="$1"
|
||||||
case "$code" in
|
case "$code" in
|
||||||
@ -63,23 +95,73 @@ explain_exit_code() {
|
|||||||
203) echo "Custom: Missing CTID variable" ;;
|
203) echo "Custom: Missing CTID variable" ;;
|
||||||
204) echo "Custom: Missing PCT_OSTYPE variable" ;;
|
204) echo "Custom: Missing PCT_OSTYPE variable" ;;
|
||||||
205) echo "Custom: Invalid CTID (<100)" ;;
|
205) echo "Custom: Invalid CTID (<100)" ;;
|
||||||
209) echo "Custom: Container creation failed" ;;
|
206) echo "Custom: CTID already in use (check 'pct list' and /etc/pve/lxc/)" ;;
|
||||||
|
# --- Proxmox Custom Codes ---
|
||||||
|
200) echo "Custom: Failed to create lock file" ;;
|
||||||
|
203) echo "Custom: Missing CTID variable" ;;
|
||||||
|
204) echo "Custom: Missing PCT_OSTYPE variable" ;;
|
||||||
|
205) echo "Custom: Invalid CTID (<100)" ;;
|
||||||
|
206) echo "Custom: CTID already in use (check 'pct list' and /etc/pve/lxc/)" ;;
|
||||||
|
207) echo "Custom: Password contains unescaped special characters (-, /, \\, *, etc.)" ;;
|
||||||
|
208) echo "Custom: Invalid configuration (DNS/MAC/Network format error)" ;;
|
||||||
|
209) echo "Custom: Container creation failed (check logs for pct create output)" ;;
|
||||||
210) echo "Custom: Cluster not quorate" ;;
|
210) echo "Custom: Cluster not quorate" ;;
|
||||||
|
211) echo "Custom: Timeout waiting for template lock (concurrent download in progress)" ;;
|
||||||
214) echo "Custom: Not enough storage space" ;;
|
214) echo "Custom: Not enough storage space" ;;
|
||||||
215) echo "Custom: Container ID not listed" ;;
|
215) echo "Custom: Container created but not listed (ghost state - check /etc/pve/lxc/)" ;;
|
||||||
216) echo "Custom: RootFS entry missing in config" ;;
|
216) echo "Custom: RootFS entry missing in config (incomplete creation)" ;;
|
||||||
217) echo "Custom: Storage does not support rootdir" ;;
|
217) echo "Custom: Storage does not support rootdir (check storage capabilities)" ;;
|
||||||
|
218) echo "Custom: Template file corrupted or incomplete download (size <1MB or invalid archive)" ;;
|
||||||
220) echo "Custom: Unable to resolve template path" ;;
|
220) echo "Custom: Unable to resolve template path" ;;
|
||||||
222) echo "Custom: Template download failed after 3 attempts" ;;
|
221) echo "Custom: Template file exists but not readable (check file permissions)" ;;
|
||||||
223) echo "Custom: Template not available after download" ;;
|
222) echo "Custom: Template download failed after 3 attempts (network/storage issue)" ;;
|
||||||
231) echo "Custom: LXC stack upgrade/retry failed" ;;
|
223) echo "Custom: Template not available after download (storage sync issue)" ;;
|
||||||
|
225) echo "Custom: No template available for OS/Version (check 'pveam available')" ;;
|
||||||
|
231) echo "Custom: LXC stack upgrade/retry failed (outdated pve-container - check https://github.com/community-scripts/ProxmoxVE/discussions/8126)" ;;
|
||||||
|
|
||||||
|
# --- Default ---
|
||||||
|
*) echo "Unknown error" ;;
|
||||||
|
208) echo "Custom: Invalid configuration (DNS/MAC/Network format error)" ;;
|
||||||
|
209) echo "Custom: Container creation failed (check logs for pct create output)" ;;
|
||||||
|
210) echo "Custom: Cluster not quorate" ;;
|
||||||
|
211) echo "Custom: Timeout waiting for template lock (concurrent download in progress)" ;;
|
||||||
|
214) echo "Custom: Not enough storage space" ;;
|
||||||
|
215) echo "Custom: Container created but not listed (ghost state - check /etc/pve/lxc/)" ;;
|
||||||
|
216) echo "Custom: RootFS entry missing in config (incomplete creation)" ;;
|
||||||
|
217) echo "Custom: Storage does not support rootdir (check storage capabilities)" ;;
|
||||||
|
218) echo "Custom: Template file corrupted or incomplete download (size <1MB or invalid archive)" ;;
|
||||||
|
220) echo "Custom: Unable to resolve template path" ;;
|
||||||
|
221) echo "Custom: Template file exists but not readable (check file permissions)" ;;
|
||||||
|
222) echo "Custom: Template download failed after 3 attempts (network/storage issue)" ;;
|
||||||
|
223) echo "Custom: Template not available after download (storage sync issue)" ;;
|
||||||
|
225) echo "Custom: No template available for OS/Version (check 'pveam available')" ;;
|
||||||
|
231) echo "Custom: LXC stack upgrade/retry failed (outdated pve-container - check https://github.com/community-scripts/ProxmoxVE/discussions/8126)" ;;
|
||||||
|
|
||||||
# --- Default ---
|
# --- Default ---
|
||||||
*) echo "Unknown error" ;;
|
*) echo "Unknown error" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
# === Error handler ============================================================
|
# ==============================================================================
|
||||||
|
# SECTION 2: ERROR HANDLERS
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# error_handler()
|
||||||
|
#
|
||||||
|
# - Main error handler triggered by ERR trap
|
||||||
|
# - Arguments: exit_code, command, line_number
|
||||||
|
# - Behavior:
|
||||||
|
# * Returns silently if exit_code is 0 (success)
|
||||||
|
# * Sources explain_exit_code() for detailed error description
|
||||||
|
# * Displays error message with:
|
||||||
|
# - Line number where error occurred
|
||||||
|
# - Exit code with explanation
|
||||||
|
# - Command that failed
|
||||||
|
# * Shows last 20 lines of SILENT_LOGFILE if available
|
||||||
|
# * Copies log to container /root for later inspection
|
||||||
|
# * Exits with original exit code
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
error_handler() {
|
error_handler() {
|
||||||
local exit_code=${1:-$?}
|
local exit_code=${1:-$?}
|
||||||
local command=${2:-${BASH_COMMAND:-unknown}}
|
local command=${2:-${BASH_COMMAND:-unknown}}
|
||||||
@ -95,7 +177,13 @@ error_handler() {
|
|||||||
explanation="$(explain_exit_code "$exit_code")"
|
explanation="$(explain_exit_code "$exit_code")"
|
||||||
|
|
||||||
printf "\e[?25h"
|
printf "\e[?25h"
|
||||||
|
|
||||||
|
# Use msg_error if available, fallback to echo
|
||||||
|
if declare -f msg_error >/dev/null 2>&1; then
|
||||||
|
msg_error "in line ${line_number}: exit code ${exit_code} (${explanation}): while executing command ${command}"
|
||||||
|
else
|
||||||
echo -e "\n${RD}[ERROR]${CL} in line ${RD}${line_number}${CL}: exit code ${RD}${exit_code}${CL} (${explanation}): while executing command ${YWB}${command}${CL}\n"
|
echo -e "\n${RD}[ERROR]${CL} in line ${RD}${line_number}${CL}: exit code ${RD}${exit_code}${CL} (${explanation}): while executing command ${YWB}${command}${CL}\n"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -n "${DEBUG_LOGFILE:-}" ]]; then
|
if [[ -n "${DEBUG_LOGFILE:-}" ]]; then
|
||||||
{
|
{
|
||||||
@ -108,39 +196,145 @@ error_handler() {
|
|||||||
} >>"$DEBUG_LOGFILE"
|
} >>"$DEBUG_LOGFILE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${SILENT_LOGFILE:-}" && -s "$SILENT_LOGFILE" ]]; then
|
# Get active log file (BUILD_LOG or INSTALL_LOG)
|
||||||
echo "--- Last 20 lines of silent log ($SILENT_LOGFILE) ---"
|
local active_log=""
|
||||||
tail -n 20 "$SILENT_LOGFILE"
|
if declare -f get_active_logfile >/dev/null 2>&1; then
|
||||||
echo "---------------------------------------------------"
|
active_log="$(get_active_logfile)"
|
||||||
|
elif [[ -n "${SILENT_LOGFILE:-}" ]]; then
|
||||||
|
active_log="$SILENT_LOGFILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$active_log" && -s "$active_log" ]]; then
|
||||||
|
echo "--- Last 20 lines of silent log ---"
|
||||||
|
tail -n 20 "$active_log"
|
||||||
|
echo "-----------------------------------"
|
||||||
|
|
||||||
|
# Detect context: Container (INSTALL_LOG set + /root exists) vs Host (BUILD_LOG)
|
||||||
|
if [[ -n "${INSTALL_LOG:-}" && -d /root ]]; then
|
||||||
|
# CONTAINER CONTEXT: Copy log and create flag file for host
|
||||||
|
local container_log="/root/.install-${SESSION_ID:-error}.log"
|
||||||
|
cp "$active_log" "$container_log" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Create error flag file with exit code for host detection
|
||||||
|
echo "$exit_code" >"/root/.install-${SESSION_ID:-error}.failed" 2>/dev/null || true
|
||||||
|
|
||||||
|
if declare -f msg_custom >/dev/null 2>&1; then
|
||||||
|
msg_custom "📋" "${YW}" "Log saved to: ${container_log}"
|
||||||
|
else
|
||||||
|
echo -e "${YW}Log saved to:${CL} ${BL}${container_log}${CL}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# HOST CONTEXT: Show local log path and offer container cleanup
|
||||||
|
if declare -f msg_custom >/dev/null 2>&1; then
|
||||||
|
msg_custom "📋" "${YW}" "Full log: ${active_log}"
|
||||||
|
else
|
||||||
|
echo -e "${YW}Full log:${CL} ${BL}${active_log}${CL}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Offer to remove container if it exists (build errors after container creation)
|
||||||
|
if [[ -n "${CTID:-}" ]] && command -v pct &>/dev/null && pct status "$CTID" &>/dev/null; then
|
||||||
|
echo ""
|
||||||
|
echo -en "${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}"
|
||||||
|
|
||||||
|
if read -t 60 -r response; then
|
||||||
|
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
|
||||||
|
echo -e "\n${YW}Removing container ${CTID}${CL}"
|
||||||
|
pct stop "$CTID" &>/dev/null || true
|
||||||
|
pct destroy "$CTID" &>/dev/null || true
|
||||||
|
echo -e "${GN}✔${CL} Container ${CTID} removed"
|
||||||
|
elif [[ "$response" =~ ^[Nn]$ ]]; then
|
||||||
|
echo -e "\n${YW}Container ${CTID} kept for debugging${CL}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Timeout - auto-remove
|
||||||
|
echo -e "\n${YW}No response - auto-removing container${CL}"
|
||||||
|
pct stop "$CTID" &>/dev/null || true
|
||||||
|
pct destroy "$CTID" &>/dev/null || true
|
||||||
|
echo -e "${GN}✔${CL} Container ${CTID} removed"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit "$exit_code"
|
exit "$exit_code"
|
||||||
}
|
}
|
||||||
|
|
||||||
# === Exit handler =============================================================
|
# ==============================================================================
|
||||||
|
# SECTION 3: SIGNAL HANDLERS
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# on_exit()
|
||||||
|
#
|
||||||
|
# - EXIT trap handler
|
||||||
|
# - Cleans up lock files if lockfile variable is set
|
||||||
|
# - Exits with captured exit code
|
||||||
|
# - Always runs on script termination (success or failure)
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
on_exit() {
|
on_exit() {
|
||||||
local exit_code=$?
|
local exit_code=$?
|
||||||
[[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile"
|
[[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile"
|
||||||
exit "$exit_code"
|
exit "$exit_code"
|
||||||
}
|
}
|
||||||
|
|
||||||
# === Signal handlers ==========================================================
|
# ------------------------------------------------------------------------------
|
||||||
|
# on_interrupt()
|
||||||
|
#
|
||||||
|
# - SIGINT (Ctrl+C) trap handler
|
||||||
|
# - Displays "Interrupted by user" message
|
||||||
|
# - Exits with code 130 (128 + SIGINT=2)
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
on_interrupt() {
|
on_interrupt() {
|
||||||
|
if declare -f msg_error >/dev/null 2>&1; then
|
||||||
|
msg_error "Interrupted by user (SIGINT)"
|
||||||
|
else
|
||||||
echo -e "\n${RD}Interrupted by user (SIGINT)${CL}"
|
echo -e "\n${RD}Interrupted by user (SIGINT)${CL}"
|
||||||
|
fi
|
||||||
exit 130
|
exit 130
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# on_terminate()
|
||||||
|
#
|
||||||
|
# - SIGTERM trap handler
|
||||||
|
# - Displays "Terminated by signal" message
|
||||||
|
# - Exits with code 143 (128 + SIGTERM=15)
|
||||||
|
# - Triggered by external process termination
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
on_terminate() {
|
on_terminate() {
|
||||||
|
if declare -f msg_error >/dev/null 2>&1; then
|
||||||
|
msg_error "Terminated by signal (SIGTERM)"
|
||||||
|
else
|
||||||
echo -e "\n${RD}Terminated by signal (SIGTERM)${CL}"
|
echo -e "\n${RD}Terminated by signal (SIGTERM)${CL}"
|
||||||
|
fi
|
||||||
exit 143
|
exit 143
|
||||||
}
|
}
|
||||||
|
|
||||||
# === Init traps ===============================================================
|
# ==============================================================================
|
||||||
|
# SECTION 4: INITIALIZATION
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# catch_errors()
|
||||||
|
#
|
||||||
|
# - Initializes error handling and signal traps
|
||||||
|
# - Enables strict error handling:
|
||||||
|
# * set -Ee: Exit on error, inherit ERR trap in functions
|
||||||
|
# * set -o pipefail: Pipeline fails if any command fails
|
||||||
|
# * set -u: (optional) Exit on undefined variable (if STRICT_UNSET=1)
|
||||||
|
# - Sets up traps:
|
||||||
|
# * ERR → error_handler
|
||||||
|
# * EXIT → on_exit
|
||||||
|
# * INT → on_interrupt
|
||||||
|
# * TERM → on_terminate
|
||||||
|
# - Call this function early in every script
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
catch_errors() {
|
catch_errors() {
|
||||||
set -Ee -o pipefail
|
set -Ee -o pipefail
|
||||||
if [ "${STRICT_UNSET:-0}" = "1" ]; then
|
if [ "${STRICT_UNSET:-0}" = "1" ]; then
|
||||||
set -u
|
set -u
|
||||||
fi
|
fi
|
||||||
|
|
||||||
trap 'error_handler' ERR
|
trap 'error_handler' ERR
|
||||||
trap on_exit EXIT
|
trap on_exit EXIT
|
||||||
trap on_interrupt INT
|
trap on_interrupt INT
|
||||||
|
|||||||
@ -4,6 +4,41 @@
|
|||||||
# Co-Author: michelroegl-brunner
|
# Co-Author: michelroegl-brunner
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# INSTALL.FUNC - CONTAINER INSTALLATION & SETUP
|
||||||
|
# ==============================================================================
|
||||||
|
#
|
||||||
|
# This file provides installation functions executed inside LXC containers
|
||||||
|
# after creation. Handles:
|
||||||
|
#
|
||||||
|
# - Network connectivity verification (IPv4/IPv6)
|
||||||
|
# - OS updates and package installation
|
||||||
|
# - DNS resolution checks
|
||||||
|
# - MOTD and SSH configuration
|
||||||
|
# - Container customization and auto-login
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# - Sourced by <app>-install.sh scripts
|
||||||
|
# - Executes via pct exec inside container
|
||||||
|
# - Requires internet connectivity
|
||||||
|
#
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SECTION 1: INITIALIZATION
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# Ensure INSTALL_LOG is set (exported from build.func, but fallback if missing)
|
||||||
|
if [[ -z "${INSTALL_LOG:-}" ]]; then
|
||||||
|
INSTALL_LOG="/root/.install-${SESSION_ID:-unknown}.log"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Dev mode: Persistent logs directory
|
||||||
|
if [[ "${DEV_MODE_LOGS:-false}" == "true" ]]; then
|
||||||
|
mkdir -p /var/log/community-scripts
|
||||||
|
INSTALL_LOG="/var/log/community-scripts/install-${SESSION_ID:-unknown}-$(date +%Y%m%d_%H%M%S).log"
|
||||||
|
fi
|
||||||
|
|
||||||
if ! command -v curl >/dev/null 2>&1; then
|
if ! command -v curl >/dev/null 2>&1; then
|
||||||
printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2
|
printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2
|
||||||
apt-get update >/dev/null 2>&1
|
apt-get update >/dev/null 2>&1
|
||||||
@ -14,7 +49,20 @@ source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxV
|
|||||||
load_functions
|
load_functions
|
||||||
catch_errors
|
catch_errors
|
||||||
|
|
||||||
# This function enables IPv6 if it's not disabled and sets verbose mode
|
# Re-parse dev_mode in container context (flags exported from host)
|
||||||
|
parse_dev_mode
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SECTION 2: NETWORK & CONNECTIVITY
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# verb_ip6()
|
||||||
|
#
|
||||||
|
# - Configures IPv6 based on DISABLEIPV6 variable
|
||||||
|
# - If DISABLEIPV6=yes: disables IPv6 via sysctl
|
||||||
|
# - Sets verbose mode via set_std_mode()
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
verb_ip6() {
|
verb_ip6() {
|
||||||
set_std_mode # Set STD mode based on VERBOSE
|
set_std_mode # Set STD mode based on VERBOSE
|
||||||
|
|
||||||
@ -24,29 +72,15 @@ verb_ip6() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# # This function sets error handling options and defines the error_handler function to handle errors
|
# ------------------------------------------------------------------------------
|
||||||
# catch_errors() {
|
# setting_up_container()
|
||||||
# set -Eeuo pipefail
|
#
|
||||||
# trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
# - Verifies network connectivity via hostname -I
|
||||||
# }
|
# - Retries up to RETRY_NUM times with RETRY_EVERY seconds delay
|
||||||
|
# - Removes Python EXTERNALLY-MANAGED restrictions
|
||||||
# # This function handles errors
|
# - Disables systemd-networkd-wait-online.service for faster boot
|
||||||
# error_handler() {
|
# - Exits with error if network unavailable after retries
|
||||||
# source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/api.func)
|
# ------------------------------------------------------------------------------
|
||||||
# local exit_code="$1"
|
|
||||||
# local line_number="$2"
|
|
||||||
# local command="${3:-}"
|
|
||||||
|
|
||||||
# if [[ "$exit_code" -eq 0 ]]; then
|
|
||||||
# return 0
|
|
||||||
# fi
|
|
||||||
|
|
||||||
# printf "\e[?25h"
|
|
||||||
# echo -e "\n${RD}[ERROR]${CL} in line ${RD}${line_number}${CL}: exit code ${RD}${exit_code}${CL}: while executing command ${YW}${command}${CL}\n"
|
|
||||||
# exit "$exit_code"
|
|
||||||
#}
|
|
||||||
|
|
||||||
# This function sets up the Container OS by generating the locale, setting the timezone, and checking the network connection
|
|
||||||
setting_up_container() {
|
setting_up_container() {
|
||||||
msg_info "Setting up Container OS"
|
msg_info "Setting up Container OS"
|
||||||
for ((i = RETRY_NUM; i > 0; i--)); do
|
for ((i = RETRY_NUM; i > 0; i--)); do
|
||||||
@ -68,7 +102,17 @@ setting_up_container() {
|
|||||||
msg_ok "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
|
# ------------------------------------------------------------------------------
|
||||||
|
# network_check()
|
||||||
|
#
|
||||||
|
# - Comprehensive network connectivity check for IPv4 and IPv6
|
||||||
|
# - Tests connectivity to multiple DNS servers:
|
||||||
|
# * IPv4: 1.1.1.1 (Cloudflare), 8.8.8.8 (Google), 9.9.9.9 (Quad9)
|
||||||
|
# * IPv6: 2606:4700:4700::1111, 2001:4860:4860::8888, 2620:fe::fe
|
||||||
|
# - Verifies DNS resolution for GitHub and Community-Scripts domains
|
||||||
|
# - Prompts user to continue if no internet detected
|
||||||
|
# - Uses fatal() on DNS resolution failure for critical hosts
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
network_check() {
|
network_check() {
|
||||||
set +e
|
set +e
|
||||||
trap - ERR
|
trap - ERR
|
||||||
@ -78,20 +122,23 @@ network_check() {
|
|||||||
|
|
||||||
# Check IPv4 connectivity to Google, Cloudflare & Quad9 DNS servers.
|
# Check IPv4 connectivity to Google, Cloudflare & Quad9 DNS servers.
|
||||||
if ping -c 1 -W 1 1.1.1.1 &>/dev/null || ping -c 1 -W 1 8.8.8.8 &>/dev/null || ping -c 1 -W 1 9.9.9.9 &>/dev/null; then
|
if ping -c 1 -W 1 1.1.1.1 &>/dev/null || ping -c 1 -W 1 8.8.8.8 &>/dev/null || ping -c 1 -W 1 9.9.9.9 &>/dev/null; then
|
||||||
msg_ok "IPv4 Internet Connected"
|
|
||||||
ipv4_connected=true
|
ipv4_connected=true
|
||||||
|
ipv4_status="${GN}✔${CL} IPv4"
|
||||||
else
|
else
|
||||||
msg_error "IPv4 Internet Not Connected"
|
ipv4_status="${RD}✖${CL} IPv4"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check IPv6 connectivity to Google, Cloudflare & Quad9 DNS servers.
|
# Check IPv6 connectivity to Google, Cloudflare & Quad9 DNS servers.
|
||||||
if ping6 -c 1 -W 1 2606:4700:4700::1111 &>/dev/null || ping6 -c 1 -W 1 2001:4860:4860::8888 &>/dev/null || ping6 -c 1 -W 1 2620:fe::fe &>/dev/null; then
|
if ping6 -c 1 -W 1 2606:4700:4700::1111 &>/dev/null || ping6 -c 1 -W 1 2001:4860:4860::8888 &>/dev/null || ping6 -c 1 -W 1 2620:fe::fe &>/dev/null; then
|
||||||
msg_ok "IPv6 Internet Connected"
|
|
||||||
ipv6_connected=true
|
ipv6_connected=true
|
||||||
|
ipv6_status="${GN}✔${CL} IPv6"
|
||||||
else
|
else
|
||||||
msg_error "IPv6 Internet Not Connected"
|
ipv6_status="${RD}✖${CL} IPv6"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Show combined status
|
||||||
|
msg_ok "Internet: ${ipv4_status} ${ipv6_status}"
|
||||||
|
|
||||||
# If both IPv4 and IPv6 checks fail, prompt the user
|
# If both IPv4 and IPv6 checks fail, prompt the user
|
||||||
if [[ $ipv4_connected == false && $ipv6_connected == false ]]; then
|
if [[ $ipv4_connected == false && $ipv6_connected == false ]]; then
|
||||||
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt
|
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt
|
||||||
@ -128,7 +175,19 @@ network_check() {
|
|||||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function updates the Container OS by running apt-get update and upgrade
|
# ==============================================================================
|
||||||
|
# SECTION 3: OS UPDATE & PACKAGE MANAGEMENT
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# update_os()
|
||||||
|
#
|
||||||
|
# - Updates container OS via apt-get update and dist-upgrade
|
||||||
|
# - Configures APT cacher proxy if CACHER=yes (accelerates package downloads)
|
||||||
|
# - Removes Python EXTERNALLY-MANAGED restrictions for pip
|
||||||
|
# - Sources tools.func for additional setup functions after update
|
||||||
|
# - Uses $STD wrapper to suppress output unless VERBOSE=yes
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
update_os() {
|
update_os() {
|
||||||
msg_info "Updating Container OS"
|
msg_info "Updating Container OS"
|
||||||
if [[ "$CACHER" == "yes" ]]; then
|
if [[ "$CACHER" == "yes" ]]; then
|
||||||
@ -150,7 +209,24 @@ EOF
|
|||||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/tools.func)
|
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/tools.func)
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function modifies the message of the day (motd) and SSH settings
|
# ==============================================================================
|
||||||
|
# SECTION 4: MOTD & SSH CONFIGURATION
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# motd_ssh()
|
||||||
|
#
|
||||||
|
# - Configures Message of the Day (MOTD) with container information
|
||||||
|
# - Creates /etc/profile.d/00_lxc-details.sh with:
|
||||||
|
# * Application name
|
||||||
|
# * Warning banner (DEV repository)
|
||||||
|
# * OS name and version
|
||||||
|
# * Hostname and IP address
|
||||||
|
# * GitHub repository link
|
||||||
|
# - Disables executable flag on /etc/update-motd.d/* scripts
|
||||||
|
# - Enables root SSH access if SSH_ROOT=yes
|
||||||
|
# - Configures TERM environment variable for better terminal support
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
motd_ssh() {
|
motd_ssh() {
|
||||||
grep -qxF "export TERM='xterm-256color'" /root/.bashrc || echo "export TERM='xterm-256color'" >>/root/.bashrc
|
grep -qxF "export TERM='xterm-256color'" /root/.bashrc || echo "export TERM='xterm-256color'" >>/root/.bashrc
|
||||||
|
|
||||||
@ -180,7 +256,19 @@ motd_ssh() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function customizes the container by modifying the getty service and enabling auto-login for the root user
|
# ==============================================================================
|
||||||
|
# SECTION 5: CONTAINER CUSTOMIZATION
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# customize()
|
||||||
|
#
|
||||||
|
# - Customizes container for passwordless root login if PASSWORD is empty
|
||||||
|
# - Configures getty for auto-login via /etc/systemd/system/container-getty@1.service.d/override.conf
|
||||||
|
# - Creates /usr/bin/update script for easy application updates
|
||||||
|
# - Injects SSH authorized keys if SSH_AUTHORIZED_KEY variable is set
|
||||||
|
# - Sets proper permissions on SSH directories and key files
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
customize() {
|
customize() {
|
||||||
if [[ "$PASSWORD" == "" ]]; then
|
if [[ "$PASSWORD" == "" ]]; then
|
||||||
msg_info "Customizing Container"
|
msg_info "Customizing Container"
|
||||||
@ -191,8 +279,7 @@ customize() {
|
|||||||
ExecStart=
|
ExecStart=
|
||||||
ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM
|
ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM
|
||||||
EOF
|
EOF
|
||||||
systemctl daemon-reload
|
$STD systemctl daemon-reload || true
|
||||||
systemctl restart $(basename $(dirname $GETTY_OVERRIDE) | sed 's/\.d//')
|
|
||||||
msg_ok "Customized Container"
|
msg_ok "Customized Container"
|
||||||
fi
|
fi
|
||||||
echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVED/raw/main/ct/${app}.sh)\"" >/usr/bin/update
|
echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVED/raw/main/ct/${app}.sh)\"" >/usr/bin/update
|
||||||
|
|||||||
508
misc/optimize_build_func.py
Normal file
508
misc/optimize_build_func.py
Normal file
@ -0,0 +1,508 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Build.func Optimizer
|
||||||
|
====================
|
||||||
|
Optimizes the build.func file by:
|
||||||
|
- Removing duplicate functions
|
||||||
|
- Sorting and grouping functions logically
|
||||||
|
- Adding section headers
|
||||||
|
- Improving readability
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import List, Tuple, Dict
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# CONFIGURATION
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# Define function groups in desired order
|
||||||
|
FUNCTION_GROUPS = {
|
||||||
|
"CORE_INIT": {
|
||||||
|
"title": "CORE INITIALIZATION & VARIABLES",
|
||||||
|
"functions": [
|
||||||
|
"variables",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"DEPENDENCIES": {
|
||||||
|
"title": "DEPENDENCY LOADING",
|
||||||
|
"functions": [
|
||||||
|
# Bootstrap loader section (commented code)
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"VALIDATION": {
|
||||||
|
"title": "SYSTEM VALIDATION & CHECKS",
|
||||||
|
"functions": [
|
||||||
|
"maxkeys_check",
|
||||||
|
"check_container_resources",
|
||||||
|
"check_container_storage",
|
||||||
|
"check_nvidia_host_setup",
|
||||||
|
"check_storage_support",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"NETWORK": {
|
||||||
|
"title": "NETWORK & IP MANAGEMENT",
|
||||||
|
"functions": [
|
||||||
|
"get_current_ip",
|
||||||
|
"update_motd_ip",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"SSH": {
|
||||||
|
"title": "SSH KEY MANAGEMENT",
|
||||||
|
"functions": [
|
||||||
|
"find_host_ssh_keys",
|
||||||
|
"ssh_discover_default_files",
|
||||||
|
"ssh_extract_keys_from_file",
|
||||||
|
"ssh_build_choices_from_files",
|
||||||
|
"configure_ssh_settings",
|
||||||
|
"install_ssh_keys_into_ct",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"SETTINGS": {
|
||||||
|
"title": "SETTINGS & CONFIGURATION",
|
||||||
|
"functions": [
|
||||||
|
"base_settings",
|
||||||
|
"echo_default",
|
||||||
|
"exit_script",
|
||||||
|
"advanced_settings",
|
||||||
|
"diagnostics_check",
|
||||||
|
"diagnostics_menu",
|
||||||
|
"default_var_settings",
|
||||||
|
"ensure_global_default_vars_file",
|
||||||
|
"settings_menu",
|
||||||
|
"edit_default_storage",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"DEFAULTS": {
|
||||||
|
"title": "DEFAULTS MANAGEMENT (VAR_* FILES)",
|
||||||
|
"functions": [
|
||||||
|
"get_app_defaults_path",
|
||||||
|
"_is_whitelisted_key",
|
||||||
|
"_sanitize_value",
|
||||||
|
"_load_vars_file",
|
||||||
|
"_load_vars_file_to_map",
|
||||||
|
"_build_vars_diff",
|
||||||
|
"_build_current_app_vars_tmp",
|
||||||
|
"maybe_offer_save_app_defaults",
|
||||||
|
"ensure_storage_selection_for_vars_file",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"STORAGE": {
|
||||||
|
"title": "STORAGE DISCOVERY & SELECTION",
|
||||||
|
"functions": [
|
||||||
|
"resolve_storage_preselect",
|
||||||
|
"select_storage",
|
||||||
|
"choose_and_set_storage_for_file",
|
||||||
|
"_write_storage_to_vars",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"GPU": {
|
||||||
|
"title": "GPU & HARDWARE PASSTHROUGH",
|
||||||
|
"functions": [
|
||||||
|
"is_gpu_app",
|
||||||
|
"detect_gpu_devices",
|
||||||
|
"configure_gpu_passthrough",
|
||||||
|
"configure_usb_passthrough",
|
||||||
|
"configure_additional_devices",
|
||||||
|
"fix_gpu_gids",
|
||||||
|
"get_container_gid",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"CONTAINER": {
|
||||||
|
"title": "CONTAINER LIFECYCLE & CREATION",
|
||||||
|
"functions": [
|
||||||
|
"create_lxc_container",
|
||||||
|
"offer_lxc_stack_upgrade_and_maybe_retry",
|
||||||
|
"parse_template_osver",
|
||||||
|
"pkg_ver",
|
||||||
|
"pkg_cand",
|
||||||
|
"ver_ge",
|
||||||
|
"ver_gt",
|
||||||
|
"ver_lt",
|
||||||
|
"build_container",
|
||||||
|
"destroy_lxc",
|
||||||
|
"description",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"MAIN": {
|
||||||
|
"title": "MAIN ENTRY POINTS & ERROR HANDLING",
|
||||||
|
"functions": [
|
||||||
|
"install_script",
|
||||||
|
"start",
|
||||||
|
"api_exit_script",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Functions to exclude from duplication check (intentionally similar)
|
||||||
|
EXCLUDE_FROM_DEDUP = {
|
||||||
|
"_load_vars_file",
|
||||||
|
"_load_vars_file_to_map",
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# HELPER FUNCTIONS
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
def extract_functions(content: str) -> Dict[str, Tuple[str, int, int]]:
|
||||||
|
"""
|
||||||
|
Extract all function definitions from the content.
|
||||||
|
Returns dict: {function_name: (full_code, start_line, end_line)}
|
||||||
|
"""
|
||||||
|
functions = {}
|
||||||
|
lines = content.split('\n')
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i < len(lines):
|
||||||
|
line = lines[i]
|
||||||
|
|
||||||
|
# Match function definition: function_name() {
|
||||||
|
match = re.match(r'^([a-zA-Z_][a-zA-Z0-9_]*)\s*\(\)\s*\{', line)
|
||||||
|
if match:
|
||||||
|
func_name = match.group(1)
|
||||||
|
start_line = i
|
||||||
|
|
||||||
|
# Find function end by counting braces
|
||||||
|
brace_count = 1
|
||||||
|
func_lines = [line]
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
while i < len(lines) and brace_count > 0:
|
||||||
|
current_line = lines[i]
|
||||||
|
func_lines.append(current_line)
|
||||||
|
|
||||||
|
# Count braces (simple method, doesn't handle strings/comments perfectly)
|
||||||
|
brace_count += current_line.count('{') - current_line.count('}')
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
end_line = i
|
||||||
|
functions[func_name] = ('\n'.join(func_lines), start_line, end_line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return functions
|
||||||
|
|
||||||
|
def extract_header_comments(content: str, func_name: str, func_code: str) -> str:
|
||||||
|
"""Extract comment block before function if exists"""
|
||||||
|
lines = content.split('\n')
|
||||||
|
|
||||||
|
# Find function start in original content
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if line.strip().startswith(f"{func_name}()"):
|
||||||
|
# Look backwards for comment block
|
||||||
|
comments = []
|
||||||
|
j = i - 1
|
||||||
|
while j >= 0:
|
||||||
|
prev_line = lines[j]
|
||||||
|
stripped = prev_line.strip()
|
||||||
|
|
||||||
|
# SKIP section headers and copyright - we add our own
|
||||||
|
if (stripped.startswith('# ===') or
|
||||||
|
stripped.startswith('#!/usr/bin/env') or
|
||||||
|
'Copyright' in stripped or
|
||||||
|
'Author:' in stripped or
|
||||||
|
'License:' in stripped or
|
||||||
|
'Revision:' in stripped or
|
||||||
|
'SECTION' in stripped):
|
||||||
|
j -= 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Include function-specific comment lines
|
||||||
|
if (stripped.startswith('# ---') or
|
||||||
|
stripped.startswith('#')):
|
||||||
|
comments.insert(0, prev_line)
|
||||||
|
j -= 1
|
||||||
|
elif stripped == '':
|
||||||
|
# Keep collecting through empty lines
|
||||||
|
comments.insert(0, prev_line)
|
||||||
|
j -= 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Remove leading empty lines from comments
|
||||||
|
while comments and comments[0].strip() == '':
|
||||||
|
comments.pop(0)
|
||||||
|
|
||||||
|
# Remove trailing empty lines from comments
|
||||||
|
while comments and comments[-1].strip() == '':
|
||||||
|
comments.pop()
|
||||||
|
|
||||||
|
if comments:
|
||||||
|
return '\n'.join(comments) + '\n'
|
||||||
|
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def find_duplicate_functions(functions: Dict[str, Tuple[str, int, int]]) -> List[str]:
|
||||||
|
"""Find duplicate function definitions"""
|
||||||
|
seen = {}
|
||||||
|
duplicates = []
|
||||||
|
|
||||||
|
for func_name, (code, start, end) in functions.items():
|
||||||
|
if func_name in EXCLUDE_FROM_DEDUP:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Normalize code for comparison (remove whitespace variations)
|
||||||
|
normalized = re.sub(r'\s+', ' ', code).strip()
|
||||||
|
|
||||||
|
if normalized in seen:
|
||||||
|
duplicates.append(func_name)
|
||||||
|
print(f" ⚠️ Duplicate found: {func_name} (also defined as {seen[normalized]})")
|
||||||
|
else:
|
||||||
|
seen[normalized] = func_name
|
||||||
|
|
||||||
|
return duplicates
|
||||||
|
|
||||||
|
def create_section_header(title: str) -> str:
|
||||||
|
"""Create a formatted section header"""
|
||||||
|
return f"""
|
||||||
|
# ==============================================================================
|
||||||
|
# {title}
|
||||||
|
# ==============================================================================
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_function_group(func_name: str) -> str:
|
||||||
|
"""Determine which group a function belongs to"""
|
||||||
|
for group_key, group_data in FUNCTION_GROUPS.items():
|
||||||
|
if func_name in group_data["functions"]:
|
||||||
|
return group_key
|
||||||
|
return "UNKNOWN"
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# MAIN OPTIMIZATION LOGIC
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
def optimize_build_func(input_file: Path, output_file: Path):
|
||||||
|
"""Main optimization function"""
|
||||||
|
|
||||||
|
print("=" * 80)
|
||||||
|
print("BUILD.FUNC OPTIMIZER")
|
||||||
|
print("=" * 80)
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Read input file
|
||||||
|
print(f"📖 Reading: {input_file}")
|
||||||
|
content = input_file.read_text(encoding='utf-8')
|
||||||
|
original_lines = len(content.split('\n'))
|
||||||
|
print(f" Lines: {original_lines:,}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Extract functions
|
||||||
|
print("🔍 Extracting functions...")
|
||||||
|
functions = extract_functions(content)
|
||||||
|
print(f" Found {len(functions)} functions")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Find duplicates
|
||||||
|
print("🔎 Checking for duplicates...")
|
||||||
|
duplicates = find_duplicate_functions(functions)
|
||||||
|
if duplicates:
|
||||||
|
print(f" Found {len(duplicates)} duplicate(s)")
|
||||||
|
else:
|
||||||
|
print(" ✓ No duplicates found")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Extract header (copyright, etc)
|
||||||
|
print("📝 Extracting file header...")
|
||||||
|
lines = content.split('\n')
|
||||||
|
header_lines = []
|
||||||
|
|
||||||
|
# Extract only the first copyright block
|
||||||
|
in_header = True
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if in_header:
|
||||||
|
# Keep copyright and license lines
|
||||||
|
if (line.strip().startswith('#!') or
|
||||||
|
line.strip().startswith('# Copyright') or
|
||||||
|
line.strip().startswith('# Author:') or
|
||||||
|
line.strip().startswith('# License:') or
|
||||||
|
line.strip().startswith('# Revision:') or
|
||||||
|
line.strip() == ''):
|
||||||
|
header_lines.append(line)
|
||||||
|
else:
|
||||||
|
in_header = False
|
||||||
|
break
|
||||||
|
|
||||||
|
# Remove trailing empty lines
|
||||||
|
while header_lines and header_lines[-1].strip() == '':
|
||||||
|
header_lines.pop()
|
||||||
|
|
||||||
|
header = '\n'.join(header_lines)
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Build optimized content
|
||||||
|
print("🔨 Building optimized structure...")
|
||||||
|
|
||||||
|
optimized_parts = [header]
|
||||||
|
|
||||||
|
# Group functions
|
||||||
|
grouped_functions = {key: [] for key in FUNCTION_GROUPS.keys()}
|
||||||
|
grouped_functions["UNKNOWN"] = []
|
||||||
|
|
||||||
|
for func_name, (func_code, start, end) in functions.items():
|
||||||
|
if func_name in duplicates:
|
||||||
|
continue # Skip duplicates
|
||||||
|
|
||||||
|
group = get_function_group(func_name)
|
||||||
|
|
||||||
|
# Extract comments before function
|
||||||
|
comments = extract_header_comments(content, func_name, func_code)
|
||||||
|
|
||||||
|
grouped_functions[group].append((func_name, comments + func_code))
|
||||||
|
|
||||||
|
# Add grouped sections
|
||||||
|
for group_key, group_data in FUNCTION_GROUPS.items():
|
||||||
|
if grouped_functions[group_key]:
|
||||||
|
optimized_parts.append(create_section_header(group_data["title"]))
|
||||||
|
|
||||||
|
for func_name, func_code in grouped_functions[group_key]:
|
||||||
|
optimized_parts.append(func_code)
|
||||||
|
optimized_parts.append('') # Empty line between functions
|
||||||
|
|
||||||
|
# Add unknown functions at the end
|
||||||
|
if grouped_functions["UNKNOWN"]:
|
||||||
|
optimized_parts.append(create_section_header("UNCATEGORIZED FUNCTIONS"))
|
||||||
|
print(f" ⚠️ {len(grouped_functions['UNKNOWN'])} uncategorized functions:")
|
||||||
|
for func_name, func_code in grouped_functions["UNKNOWN"]:
|
||||||
|
print(f" - {func_name}")
|
||||||
|
optimized_parts.append(func_code)
|
||||||
|
optimized_parts.append('')
|
||||||
|
|
||||||
|
# Add any remaining non-function code (bootstrap, source commands, traps, etc)
|
||||||
|
print("📌 Adding remaining code...")
|
||||||
|
|
||||||
|
# Extract bootstrap/source section
|
||||||
|
bootstrap_lines = []
|
||||||
|
trap_lines = []
|
||||||
|
other_lines = []
|
||||||
|
|
||||||
|
in_function = False
|
||||||
|
brace_count = 0
|
||||||
|
in_bootstrap_comment = False
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
stripped = line.strip()
|
||||||
|
|
||||||
|
# Skip the header we already extracted
|
||||||
|
if (stripped.startswith('#!/usr/bin/env bash') or
|
||||||
|
stripped.startswith('# Copyright') or
|
||||||
|
stripped.startswith('# Author:') or
|
||||||
|
stripped.startswith('# License:') or
|
||||||
|
stripped.startswith('# Revision:')):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check if we're in a function
|
||||||
|
if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*\s*\(\)\s*\{', line):
|
||||||
|
in_function = True
|
||||||
|
brace_count = 1
|
||||||
|
elif in_function:
|
||||||
|
brace_count += line.count('{') - line.count('}')
|
||||||
|
if brace_count == 0:
|
||||||
|
in_function = False
|
||||||
|
elif not in_function:
|
||||||
|
# Collect non-function lines
|
||||||
|
|
||||||
|
# Bootstrap/loader section
|
||||||
|
if ('Community-Scripts bootstrap' in line or
|
||||||
|
'Load core' in line or
|
||||||
|
in_bootstrap_comment):
|
||||||
|
bootstrap_lines.append(line)
|
||||||
|
if '# ---' in line or '# ===' in line:
|
||||||
|
in_bootstrap_comment = not in_bootstrap_comment
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Source commands
|
||||||
|
if (stripped.startswith('source <(') or
|
||||||
|
stripped.startswith('if command -v curl') or
|
||||||
|
stripped.startswith('elif command -v wget') or
|
||||||
|
'load_functions' in stripped or
|
||||||
|
'catch_errors' in stripped):
|
||||||
|
bootstrap_lines.append(line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Traps
|
||||||
|
if stripped.startswith('trap '):
|
||||||
|
trap_lines.append(line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# VAR_WHITELIST declaration
|
||||||
|
if 'declare -ag VAR_WHITELIST' in line or (other_lines and 'VAR_WHITELIST' in other_lines[-1]):
|
||||||
|
other_lines.append(line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Empty lines between sections - keep some
|
||||||
|
if stripped == '' and (bootstrap_lines or trap_lines or other_lines):
|
||||||
|
if bootstrap_lines and bootstrap_lines[-1].strip() != '':
|
||||||
|
bootstrap_lines.append(line)
|
||||||
|
elif trap_lines and trap_lines[-1].strip() != '':
|
||||||
|
trap_lines.append(line)
|
||||||
|
|
||||||
|
# Add bootstrap section if exists
|
||||||
|
if bootstrap_lines:
|
||||||
|
optimized_parts.append(create_section_header("DEPENDENCY LOADING"))
|
||||||
|
optimized_parts.extend(bootstrap_lines)
|
||||||
|
optimized_parts.append('')
|
||||||
|
|
||||||
|
# Add other declarations
|
||||||
|
if other_lines:
|
||||||
|
optimized_parts.extend(other_lines)
|
||||||
|
optimized_parts.append('')
|
||||||
|
|
||||||
|
# Write output
|
||||||
|
optimized_content = '\n'.join(optimized_parts)
|
||||||
|
optimized_lines = len(optimized_content.split('\n'))
|
||||||
|
|
||||||
|
print()
|
||||||
|
print(f"💾 Writing optimized file: {output_file}")
|
||||||
|
output_file.write_text(optimized_content, encoding='utf-8')
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("=" * 80)
|
||||||
|
print("✅ OPTIMIZATION COMPLETE")
|
||||||
|
print("=" * 80)
|
||||||
|
print(f"Original lines: {original_lines:,}")
|
||||||
|
print(f"Optimized lines: {optimized_lines:,}")
|
||||||
|
print(f"Difference: {original_lines - optimized_lines:+,}")
|
||||||
|
print(f"Functions: {len(functions) - len(duplicates)}")
|
||||||
|
print(f"Duplicates removed: {len(duplicates)}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# ENTRY POINT
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main entry point"""
|
||||||
|
|
||||||
|
# Set paths
|
||||||
|
script_dir = Path(__file__).parent
|
||||||
|
input_file = script_dir / "build.func"
|
||||||
|
|
||||||
|
# Create backup first
|
||||||
|
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||||
|
backup_file = script_dir / f"build.func.backup-{timestamp}"
|
||||||
|
|
||||||
|
if not input_file.exists():
|
||||||
|
print(f"❌ Error: {input_file} not found!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"📦 Creating backup: {backup_file.name}")
|
||||||
|
backup_file.write_text(input_file.read_text(encoding='utf-8'), encoding='utf-8')
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Optimize
|
||||||
|
output_file = script_dir / "build.func.optimized"
|
||||||
|
optimize_build_func(input_file, output_file)
|
||||||
|
|
||||||
|
print("📋 Next steps:")
|
||||||
|
print(f" 1. Review: {output_file.name}")
|
||||||
|
print(f" 2. Test the optimized version")
|
||||||
|
print(f" 3. If OK: mv build.func.optimized build.func")
|
||||||
|
print(f" 4. Backup available at: {backup_file.name}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
1139
misc/tools.func
1139
misc/tools.func
File diff suppressed because it is too large
Load Diff
@ -394,9 +394,9 @@ check_root() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pve_check() {
|
pve_check() {
|
||||||
if ! pveversion | grep -Eq "pve-manager/8\.[1-4](\.[0-9]+)*"; then
|
if ! pveversion | grep -Eq "pve-manager/(8\.[1-4]|9\.[0-1])(\.[0-9]+)*"; then
|
||||||
msg_error "This version of Proxmox Virtual Environment is not supported"
|
msg_error "This version of Proxmox Virtual Environment is not supported"
|
||||||
echo -e "Requires Proxmox Virtual Environment Version 8.1 or later."
|
echo -e "Requires Proxmox Virtual Environment Version 8.1 - 8.4 or 9.0 - 9.1."
|
||||||
echo -e "Exiting..."
|
echo -e "Exiting..."
|
||||||
sleep 2
|
sleep 2
|
||||||
exit
|
exit
|
||||||
|
|||||||
@ -51,29 +51,29 @@ pve_check() {
|
|||||||
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
|
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
|
||||||
|
|
||||||
# Proxmox VE 8.x: allow 8.0 – 8.9
|
# Proxmox VE 8.x: allow 8.0 – 8.9
|
||||||
if [[ "$PVE_VER" =~ ^9\.([0-9]+)(\.[0-9]+)?$ ]]; then
|
if [[ "$PVE_VER" =~ ^8\.([0-9]+)(\.[0-9]+)?$ ]]; then
|
||||||
local MINOR="${BASH_REMATCH[1]}"
|
local MINOR="${BASH_REMATCH[1]}"
|
||||||
if ((MINOR != 0)); then
|
if ((MINOR < 0 || MINOR > 9)); then
|
||||||
msg_error "Unsupported Proxmox VE version: $PVE_VER"
|
msg_error "Unsupported Proxmox VE version: $PVE_VER"
|
||||||
msg_error "Supported versions: 8.0 – 8.9 or 9.0.x"
|
msg_error "Supported versions: 8.0 – 8.9 or 9.0 – 9.1"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Proxmox VE 9.x: allow only 9.0
|
# Proxmox VE 9.x: allow 9.0 – 9.1
|
||||||
if [[ "$PVE_VER" =~ ^9\.([0-9]+)$ ]]; then
|
if [[ "$PVE_VER" =~ ^9\.([0-9]+)$ ]]; then
|
||||||
local MINOR="${BASH_REMATCH[1]}"
|
local MINOR="${BASH_REMATCH[1]}"
|
||||||
if ((MINOR != 0)); then
|
if ((MINOR < 0 || MINOR > 1)); then
|
||||||
msg_error "Unsupported Proxmox VE version: $PVE_VER"
|
msg_error "Unsupported Proxmox VE version: $PVE_VER"
|
||||||
msg_error "Supported versions: 8.0 – 8.9 or 9.0"
|
msg_error "Supported versions: 8.0 – 8.9 or 9.0 – 9.1"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
msg_error "Unsupported Proxmox VE version: $PVE_VER"
|
msg_error "Unsupported Proxmox VE version: $PVE_VER"
|
||||||
msg_error "Supported versions: 8.0 – 8.9 or 9.0"
|
msg_error "Supported versions: 8.0 – 8.9 or 9.0 – 9.1"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
147
tools/addon/qbittorrent-exporter.sh
Normal file
147
tools/addon/qbittorrent-exporter.sh
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
|
# Author: CrazyWolf13
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/core.func)
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/tools.func)
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||||
|
|
||||||
|
VERBOSE=${var_verbose:-no}
|
||||||
|
APP="qbittorrent-exporter"
|
||||||
|
APP_TYPE="tools"
|
||||||
|
INSTALL_PATH="/opt/qbittorrent-exporter/src/qbittorrent-exporter"
|
||||||
|
CONFIG_PATH="/opt/qbittorrent-exporter.env"
|
||||||
|
header_info
|
||||||
|
ensure_usr_local_bin_persist
|
||||||
|
get_current_ip &>/dev/null
|
||||||
|
|
||||||
|
# OS Detection
|
||||||
|
if [[ -f "/etc/alpine-release" ]]; then
|
||||||
|
OS="Alpine"
|
||||||
|
SERVICE_PATH="/etc/init.d/qbittorrent-exporter"
|
||||||
|
elif grep -qE 'ID=debian|ID=ubuntu' /etc/os-release; then
|
||||||
|
OS="Debian"
|
||||||
|
SERVICE_PATH="/etc/systemd/system/qbittorrent-exporter.service"
|
||||||
|
else
|
||||||
|
echo -e "${CROSS} Unsupported OS detected. Exiting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Existing installation
|
||||||
|
if [[ -f "$INSTALL_PATH" ]]; then
|
||||||
|
echo -e "${YW}⚠️ qbittorrent-exporter is already installed.${CL}"
|
||||||
|
echo -n "Uninstall ${APP}? (y/N): "
|
||||||
|
read -r uninstall_prompt
|
||||||
|
if [[ "${uninstall_prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||||
|
msg_info "Uninstalling qbittorrent-exporter"
|
||||||
|
if [[ "$OS" == "Debian" ]]; then
|
||||||
|
systemctl disable --now qbittorrent-exporter.service &>/dev/null
|
||||||
|
rm -f "$SERVICE_PATH"
|
||||||
|
else
|
||||||
|
rc-service qbittorrent-exporter stop &>/dev/null
|
||||||
|
rc-update del qbittorrent-exporter &>/dev/null
|
||||||
|
rm -f "$SERVICE_PATH"
|
||||||
|
fi
|
||||||
|
rm -f "$INSTALL_PATH" "$CONFIG_PATH" ~/.qbittorrent-exporter
|
||||||
|
msg_ok "${APP} has been uninstalled."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Update qbittorrent-exporter? (y/N): "
|
||||||
|
read -r update_prompt
|
||||||
|
if [[ "${update_prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||||
|
if check_for_gh_release "qbittorrent-exporter" "martabal/qbittorrent-exporter"; then
|
||||||
|
fetch_and_deploy_gh_release "qbittorrent-exporter" "martabal/qbittorrent-exporter"
|
||||||
|
setup_go
|
||||||
|
msg_info "Updating qbittorrent-exporter"
|
||||||
|
cd /opt/qbittorrent-exporter/src
|
||||||
|
/usr/local/bin/go build -o ./qbittorrent-exporter
|
||||||
|
msg_ok "Updated Successfully!"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo -e "${YW}⚠️ Update skipped. Exiting.${CL}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${YW}⚠️ qbittorrent-exporter is not installed.${CL}"
|
||||||
|
echo -n "Enter URL of qbittorrent example: (http://192.168.1.10:8080): "
|
||||||
|
read -er QBITTORRENT_BASE_URL
|
||||||
|
|
||||||
|
echo -n "Enter qbittorrent username: "
|
||||||
|
read -er QBITTORRENT_USERNAME
|
||||||
|
|
||||||
|
echo -n "Enter qbittorrent password: "
|
||||||
|
read -rs QBITTORRENT_PASSWORD
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo -n "Install qbittorrent-exporter? (y/n): "
|
||||||
|
read -r install_prompt
|
||||||
|
if ! [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||||
|
echo -e "${YW}⚠️ Installation skipped. Exiting.${CL}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "qbittorrent-exporter" "martabal/qbittorrent-exporter" "tarball" "v1.12.0"
|
||||||
|
setup_go
|
||||||
|
msg_info "Installing qbittorrent-exporter on ${OS}"
|
||||||
|
cd /opt/qbittorrent-exporter/src
|
||||||
|
/usr/local/bin/go build -o ./qbittorrent-exporter
|
||||||
|
msg_ok "Installed qbittorrent-exporter"
|
||||||
|
|
||||||
|
msg_info "Creating configuration"
|
||||||
|
cat <<EOF >"$CONFIG_PATH"
|
||||||
|
QBITTORRENT_BASE_URL=${QBITTORRENT_BASE_URL}
|
||||||
|
QBITTORRENT_USERNAME=${QBITTORRENT_USERNAME}
|
||||||
|
QBITTORRENT_PASSWORD=${QBITTORRENT_PASSWORD}
|
||||||
|
EOF
|
||||||
|
msg_ok "Created configuration"
|
||||||
|
|
||||||
|
msg_info "Creating service"
|
||||||
|
if [[ "$OS" == "Debian" ]]; then
|
||||||
|
cat <<EOF >"$SERVICE_PATH"
|
||||||
|
[Unit]
|
||||||
|
Description=qbittorrent-exporter
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/opt/qbittorrent-exporter/src
|
||||||
|
EnvironmentFile=$CONFIG_PATH
|
||||||
|
ExecStart=/opt/qbittorrent-exporter/src/qbittorrent-exporter
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable --now qbittorrent-exporter &>/dev/null
|
||||||
|
else
|
||||||
|
cat <<EOF >"$SERVICE_PATH"
|
||||||
|
#!/sbin/openrc-run
|
||||||
|
|
||||||
|
command="$INSTALL_PATH"
|
||||||
|
command_args=""
|
||||||
|
command_background=true
|
||||||
|
directory="/opt/qbittorrent-exporter/src"
|
||||||
|
pidfile="/opt/qbittorrent-exporter/src/pidfile"
|
||||||
|
|
||||||
|
depend() {
|
||||||
|
need net
|
||||||
|
}
|
||||||
|
|
||||||
|
start_pre() {
|
||||||
|
if [ -f "$CONFIG_PATH" ]; then
|
||||||
|
export \$(grep -v '^#' $CONFIG_PATH | xargs)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
chmod +x "$SERVICE_PATH"
|
||||||
|
rc-update add qbittorrent-exporter default &>/dev/null
|
||||||
|
rc-service qbittorrent-exporter start &>/dev/null
|
||||||
|
fi
|
||||||
|
msg_ok "Service created successfully"
|
||||||
|
|
||||||
|
echo -e "${CM} ${GN}${APP} is reachable at: ${BL}http://$CURRENT_IP:8090/metrics${CL}"
|
||||||
6
tools/headers/qbittorrent-exporter
Normal file
6
tools/headers/qbittorrent-exporter
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
__ _ __ __ __ __
|
||||||
|
____ _/ /_ (_) /_/ /_____ _____________ ____ / /_ ___ _ ______ ____ _____/ /____ _____
|
||||||
|
/ __ `/ __ \/ / __/ __/ __ \/ ___/ ___/ _ \/ __ \/ __/_____/ _ \| |/_/ __ \/ __ \/ ___/ __/ _ \/ ___/
|
||||||
|
/ /_/ / /_/ / / /_/ /_/ /_/ / / / / / __/ / / / /_/_____/ __/> </ /_/ / /_/ / / / /_/ __/ /
|
||||||
|
\__, /_.___/_/\__/\__/\____/_/ /_/ \___/_/ /_/\__/ \___/_/|_/ .___/\____/_/ \__/\___/_/
|
||||||
|
/_/ /_/
|
||||||
@ -103,9 +103,9 @@ function check_root() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function pve_check() {
|
function pve_check() {
|
||||||
if ! pveversion | grep -Eq "pve-manager/8\.[1-3](\.[0-9]+)*"; then
|
if ! pveversion | grep -Eq "pve-manager/(8\.[1-3]|9\.[0-1])(\.[0-9]+)*"; then
|
||||||
msg_error "This version of Proxmox Virtual Environment is not supported"
|
msg_error "This version of Proxmox Virtual Environment is not supported"
|
||||||
echo -e "Requires Proxmox Virtual Environment Version 8.1 or later."
|
echo -e "Requires Proxmox Virtual Environment Version 8.1 - 8.3 or 9.0 - 9.1."
|
||||||
echo -e "Exiting..."
|
echo -e "Exiting..."
|
||||||
sleep 2
|
sleep 2
|
||||||
exit
|
exit
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user