Merge branch 'main' into dramikei/ente-enhancement
This commit is contained in:
commit
06c6536699
@ -1,6 +1,6 @@
|
||||
module proxmox-api
|
||||
|
||||
go 1.23.2
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
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/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
golang.org/x/crypto v0.35.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/crypto v0.45.0 // indirect
|
||||
golang.org/x/sync v0.18.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=
|
||||
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.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
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/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-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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
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.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
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"
|
||||
var_tags="${var_tags:-os;alpine}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_cpu="${var_cpu:-4}"
|
||||
var_ram="${var_ram:-4096}"
|
||||
var_disk="${var_disk:-5}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.22}"
|
||||
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
|
||||
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)
|
||||
# Copyright (c) 2021-2025 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
# Source: https://www.debian.org/
|
||||
# Source:
|
||||
|
||||
APP="Debian"
|
||||
var_tags="${var_tags:-}"
|
||||
@ -30,9 +30,10 @@ function update_script() {
|
||||
exit
|
||||
fi
|
||||
msg_info "Updating $APP LXC"
|
||||
$STD apt-get update
|
||||
$STD apt-get -y upgrade
|
||||
$STD apt update
|
||||
$STD apt upgrade -y
|
||||
msg_ok "Updated $APP LXC"
|
||||
cleanup_lxc
|
||||
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
|
||||
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
|
||||
# Author: Arian Nasr (arian-nasr)
|
||||
# Updated by: Javier Pastor (vsc55)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#!/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
|
||||
# Author: CrazyWolf13
|
||||
# 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_version="${var_version:-12}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
var_app_version="${var_app_version:-latest}"
|
||||
|
||||
header_info "$APP"
|
||||
|
||||
@ -48,10 +47,10 @@ function update_script() {
|
||||
fi
|
||||
|
||||
if [[ ! -f /opt/gitea-mirror.env ]]; then
|
||||
msg_info "Detected old Enviroment, updating files"
|
||||
APP_SECRET=$(openssl rand -base64 32)
|
||||
HOST_IP=$(hostname -I | awk '{print $1}')
|
||||
cat <<EOF >/opt/gitea-mirror.env
|
||||
msg_info "Detected old Enviroment, updating files"
|
||||
APP_SECRET=$(openssl rand -base64 32)
|
||||
HOST_IP=$(hostname -I | awk '{print $1}')
|
||||
cat <<EOF >/opt/gitea-mirror.env
|
||||
# See here for config options: https://github.com/RayLabsHQ/gitea-mirror/blob/main/docs/ENVIRONMENT_VARIABLES.md
|
||||
NODE_ENV=production
|
||||
HOST=0.0.0.0
|
||||
@ -78,7 +77,7 @@ WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
msg_ok "Old Enviroment fixed"
|
||||
fi
|
||||
fi
|
||||
|
||||
if check_for_gh_release "gitea-mirror" "RayLabsHQ/gitea-mirror"; then
|
||||
msg_info "Stopping Services"
|
||||
@ -90,15 +89,10 @@ fi
|
||||
cp /opt/gitea-mirror/data/* /opt/gitea-mirror-backup/data/
|
||||
msg_ok "Backup Data"
|
||||
|
||||
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"
|
||||
NODE_VERSION="22" NODE_MODULES="bun" setup_nodejs
|
||||
|
||||
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}"
|
||||
cd /opt/gitea-mirror
|
||||
@ -116,7 +110,7 @@ fi
|
||||
msg_info "Starting Service"
|
||||
systemctl start gitea-mirror
|
||||
msg_ok "Service Started"
|
||||
msg_ok "Update Successfully"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
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}"
|
||||
24
ct/rybbit.sh
24
ct/rybbit.sh
@ -11,7 +11,7 @@ var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-5}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-12}"
|
||||
var_version="${var_version:-13}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@ -20,18 +20,18 @@ 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"
|
||||
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
|
||||
|
||||
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"
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
|
||||
"integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
|
||||
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"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",
|
||||
versions: [
|
||||
{ name: "11", slug: "bullseye" },
|
||||
{ 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
|
||||
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
|
||||
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
|
||||
|
||||
# Copyright (c) 2021-2025 community-scripts ORG
|
||||
# Author: Test Suite for tools.func
|
||||
# License: MIT
|
||||
# https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
# Purpose: Run comprehensive test suite for all setup_* functions from tools.func
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
# Source:
|
||||
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
@ -18,14 +17,10 @@ msg_info "Installing Base Dependencies"
|
||||
$STD apt-get install -y curl wget ca-certificates
|
||||
msg_ok "Installed Base Dependencies"
|
||||
|
||||
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)
|
||||
msg_ok "Test suite completed"
|
||||
# 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)
|
||||
# msg_ok "Test suite completed"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
|
||||
msg_info "Cleaning up"
|
||||
$STD apt-get -y autoremove
|
||||
$STD apt-get -y autoclean
|
||||
msg_ok "Cleaned"
|
||||
cleanup_lxc
|
||||
|
||||
@ -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"
|
||||
@ -15,17 +15,21 @@ update_os
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt-get install -y \
|
||||
libsodium23 \
|
||||
libsodium-dev \
|
||||
pkg-config \
|
||||
caddy \
|
||||
gcc
|
||||
libsodium23 \
|
||||
libsodium-dev \
|
||||
pkg-config \
|
||||
caddy \
|
||||
gcc \
|
||||
curl \
|
||||
jq
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
PG_VERSION="17" setup_postgresql
|
||||
setup_go
|
||||
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" "$ENTE_CLI_VERSION" "/usr/local/bin/ente" "ente-cli-$ENTE_CLI_VERSION-linux-amd64.tar.gz"
|
||||
|
||||
msg_info "Setting up PostgreSQL"
|
||||
DB_NAME="ente_db"
|
||||
@ -37,10 +41,28 @@ $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 "Ente Credentials"
|
||||
echo "Database Name: $DB_NAME"
|
||||
echo "Database User: $DB_USER"
|
||||
echo "Database Password: $DB_PASS"
|
||||
echo "Ente Credentials"
|
||||
echo "Database Name: $DB_NAME"
|
||||
echo "Database User: $DB_USER"
|
||||
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
|
||||
msg_ok "Set up PostgreSQL"
|
||||
|
||||
@ -78,10 +100,10 @@ export CGO_ENABLED=1
|
||||
CGO_CFLAGS="$(pkg-config --cflags libsodium || true)"
|
||||
CGO_LDFLAGS="$(pkg-config --libs libsodium || true)"
|
||||
if [ -z "$CGO_CFLAGS" ]; then
|
||||
CGO_CFLAGS="-I/usr/include"
|
||||
CGO_CFLAGS="-I/usr/include"
|
||||
fi
|
||||
if [ -z "$CGO_LDFLAGS" ]; then
|
||||
CGO_LDFLAGS="-lsodium"
|
||||
CGO_LDFLAGS="-lsodium"
|
||||
fi
|
||||
export CGO_CFLAGS
|
||||
export CGO_LDFLAGS
|
||||
@ -89,12 +111,13 @@ $STD go build cmd/museum/main.go
|
||||
msg_ok "Built Museum"
|
||||
|
||||
msg_info "Generating Secrets"
|
||||
SECRET_ENC=$($STD go run tools/gen-random-keys/main.go | grep "encryption" | awk '{print $2}')
|
||||
SECRET_HASH=$($STD go run tools/gen-random-keys/main.go | grep "hash" | awk '{print $2}')
|
||||
SECRET_JWT=$($STD go run tools/gen-random-keys/main.go | grep "jwt" | awk '{print $2}')
|
||||
SECRET_ENC=$(go run tools/gen-random-keys/main.go 2>/dev/null | grep "encryption" | awk '{print $2}')
|
||||
SECRET_HASH=$(go run tools/gen-random-keys/main.go 2>/dev/null | grep "hash" | 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_info "Creating museum.yaml"
|
||||
CONTAINER_IP=$(hostname -I | awk '{print $1}')
|
||||
cat <<EOF >/opt/ente/server/museum.yaml
|
||||
db:
|
||||
host: 127.0.0.1
|
||||
@ -114,9 +137,9 @@ s3:
|
||||
bucket: ente-dev
|
||||
|
||||
apps:
|
||||
public-albums: http://localhost:3002
|
||||
cast: http://localhost:3004
|
||||
accounts: http://localhost:3001
|
||||
public-albums: http://${CONTAINER_IP}:3002
|
||||
cast: http://${CONTAINER_IP}:3004
|
||||
accounts: http://${CONTAINER_IP}:3001
|
||||
|
||||
key:
|
||||
encryption: $SECRET_ENC
|
||||
@ -124,6 +147,15 @@ key:
|
||||
|
||||
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
|
||||
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/auth/out /var/www/ente/apps/auth
|
||||
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_info "Creating Museum Service"
|
||||
@ -192,31 +248,82 @@ systemctl enable -q --now ente-museum
|
||||
msg_ok "Created Museum Service"
|
||||
|
||||
msg_info "Configuring Caddy"
|
||||
CONTAINER_IP=$(hostname -I | awk '{print $1}')
|
||||
cat <<EOF >/etc/caddy/Caddyfile
|
||||
# Ente Photos - Main Application
|
||||
:3000 {
|
||||
root * /var/www/ente/apps/photos
|
||||
file_server
|
||||
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 {
|
||||
root * /var/www/ente/apps/accounts
|
||||
file_server
|
||||
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 {
|
||||
root * /var/www/ente/apps/photos
|
||||
file_server
|
||||
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 {
|
||||
root * /var/www/ente/apps/auth
|
||||
file_server
|
||||
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 {
|
||||
root * /var/www/ente/apps/cast
|
||||
file_server
|
||||
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
|
||||
systemctl reload caddy
|
||||
@ -225,7 +332,63 @@ msg_ok "Configured Caddy"
|
||||
motd_ssh
|
||||
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"
|
||||
$STD apt-get -y autoremove
|
||||
$STD apt-get -y autoclean
|
||||
$STD apt -y autoremove
|
||||
$STD apt -y autoclean
|
||||
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
|
||||
update_os
|
||||
|
||||
msg_info "Installing dependencies"
|
||||
$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"
|
||||
|
||||
NODE_VERSION="22" NODE_MODULES="bun" setup_nodejs
|
||||
fetch_and_deploy_gh_release "gitea-mirror" "RayLabsHQ/gitea-mirror"
|
||||
|
||||
msg_info "Installing gitea-mirror"
|
||||
@ -70,8 +56,4 @@ msg_ok "Created Service"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
|
||||
msg_info "Cleaning up"
|
||||
$STD apt-get -y autoremove
|
||||
$STD apt-get -y autoclean
|
||||
msg_ok "Cleaned"
|
||||
cleanup_lxc
|
||||
|
||||
@ -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
|
||||
update_os
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt-get install -y \
|
||||
caddy \
|
||||
apt-transport-https \
|
||||
ca-certificates
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
setup_clickhouse
|
||||
PG_VERSION=17 setup_postgresql
|
||||
NODE_VERSION="20" NODE_MODULE="next" setup_nodejs
|
||||
|
||||
#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"
|
||||
NODE_VERSION="24" NODE_MODULE="next" setup_nodejs
|
||||
PG_DB_NAME="rybbit_db" PG_DB_USER="rybbit" setup_postgresql_db
|
||||
|
||||
fetch_and_deploy_gh_release "rybbit" "rybbit-io/rybbit" "tarball" "latest" "/opt/rybbit"
|
||||
|
||||
msg_info "Building Rybbit Shared Module"
|
||||
cd /opt/rybbit/shared
|
||||
npm install
|
||||
npm run build
|
||||
$STD npm install
|
||||
$STD npm run build
|
||||
msg_ok "Built Shared Module"
|
||||
|
||||
msg_info "Building Rybbit Server"
|
||||
cd /opt/rybbit/server
|
||||
npm ci
|
||||
npm run build
|
||||
$STD npm ci
|
||||
$STD npm run build
|
||||
msg_ok "Built Server"
|
||||
|
||||
msg_info "Building Rybbit Client"
|
||||
cd /opt/rybbit/client
|
||||
npm ci --legacy-peer-deps
|
||||
npm run build
|
||||
NEXT_PUBLIC_BACKEND_URL="http://localhost:3001" \
|
||||
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
|
||||
sed -i "s|^POSTGRES_DB=.*|POSTGRES_DB=$DB_NAME|g" /opt/rybbit/.env
|
||||
sed -i "s|^POSTGRES_USER=.*|POSTGRES_USER=$DB_USER|g" /opt/rybbit/.env
|
||||
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 "Configuring Rybbit"
|
||||
CONTAINER_IP=$(hostname -I | awk '{print $1}')
|
||||
BETTER_AUTH_SECRET=$(openssl rand -hex 32)
|
||||
|
||||
msg_info "Setting up Caddy"
|
||||
mkdir -p /etc/caddy
|
||||
cp /opt/rybbit/Caddyfile /etc/caddy/Caddyfile
|
||||
systemctl enable -q --now caddy
|
||||
msg_ok "Caddy Setup"
|
||||
cat >/opt/rybbit/.env <<EOF
|
||||
# Database Configuration
|
||||
POSTGRES_HOST=localhost
|
||||
POSTGRES_PORT=5432
|
||||
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
|
||||
customize
|
||||
|
||||
msg_info "Cleaning up"
|
||||
$STD apt-get -y autoremove
|
||||
$STD apt-get -y autoclean
|
||||
msg_ok "Cleaned"
|
||||
cleanup_lxc
|
||||
|
||||
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"
|
||||
@ -16,15 +16,15 @@ update_os
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt install -y \
|
||||
dnsutils \
|
||||
iputils-ping \
|
||||
ufw \
|
||||
iproute2
|
||||
dnsutils \
|
||||
iputils-ping \
|
||||
ufw \
|
||||
iproute2
|
||||
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 \
|
||||
transmission-daemon \
|
||||
privoxy
|
||||
transmission-daemon \
|
||||
privoxy
|
||||
rm -f /etc/systemd/system-preset/99-no-autostart.preset
|
||||
$STD systemctl preset-all
|
||||
$STD systemctl disable --now transmission-daemon
|
||||
@ -49,12 +49,13 @@ chmod +x /opt/privoxy/*.sh
|
||||
$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 ip6tables /usr/sbin/ip6tables-legacy
|
||||
rm -rf /opt/docker-transmission-openvpn
|
||||
msg_ok "Configured transmission-openvpn"
|
||||
|
||||
msg_info "Creating Service"
|
||||
LOCAL_SUBNETS=$(
|
||||
ip -o -4 addr show \
|
||||
| awk '!/127.0.0.1/ {
|
||||
ip -o -4 addr show |
|
||||
awk '!/127.0.0.1/ {
|
||||
split($4, a, "/"); ip=a[1]; mask=a[2];
|
||||
split(ip, o, ".");
|
||||
if (mask < 8) {
|
||||
@ -66,12 +67,12 @@ LOCAL_SUBNETS=$(
|
||||
} else {
|
||||
print o[1]"."o[2]"."o[3]".*";
|
||||
}
|
||||
}' \
|
||||
| sort -u | paste -sd, -
|
||||
}' |
|
||||
sort -u | paste -sd, -
|
||||
)
|
||||
TRANSMISSION_RPC_WHITELIST="127.0.0.*,${LOCAL_SUBNETS}"
|
||||
mkdir -p /opt/transmission-openvpn
|
||||
cat <<EOF > "/opt/transmission-openvpn/.env"
|
||||
cat <<EOF >"/opt/transmission-openvpn/.env"
|
||||
OPENVPN_USERNAME="username"
|
||||
OPENVPN_PASSWORD="password"
|
||||
OPENVPN_PROVIDER="PIA"
|
||||
@ -111,7 +112,7 @@ LOG_TO_STDOUT="false"
|
||||
HEALTH_CHECK_HOST="google.com"
|
||||
SELFHEAL="false"
|
||||
EOF
|
||||
cat <<EOF > /etc/systemd/system/openvpn-custom.service
|
||||
cat <<EOF >/etc/systemd/system/openvpn-custom.service
|
||||
[Unit]
|
||||
Description=Custom OpenVPN start service
|
||||
After=network.target
|
||||
@ -126,15 +127,9 @@ EnvironmentFile=/opt/transmission-openvpn/.env
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl enable --now -q openvpn-custom.service
|
||||
systemctl enable -q --now openvpn-custom
|
||||
msg_ok "Created Service"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
|
||||
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"
|
||||
cleanup_lxc
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
# Author: MickLesk (Canbiz)
|
||||
# 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
|
||||
verb_ip6
|
||||
catch_errors
|
||||
@ -14,10 +14,10 @@ update_os
|
||||
|
||||
msg_info "Installing Dependencies (Patience)"
|
||||
$STD apt-get install -y \
|
||||
make \
|
||||
apache2 \
|
||||
libapache2-mod-php \
|
||||
redis
|
||||
make \
|
||||
apache2 \
|
||||
libapache2-mod-php \
|
||||
redis
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
setup_mariadb
|
||||
@ -33,10 +33,10 @@ $STD mariadb -u root -e "CREATE DATABASE $DB_NAME;"
|
||||
$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
|
||||
$STD mariadb -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
|
||||
{
|
||||
echo "Wallabag Credentials"
|
||||
echo "Database User: $DB_USER"
|
||||
echo "Database Password: $DB_PASS"
|
||||
echo "Database Name: $DB_NAME"
|
||||
echo "Wallabag Credentials"
|
||||
echo "Database User: $DB_USER"
|
||||
echo "Database Password: $DB_PASS"
|
||||
echo "Database Name: $DB_NAME"
|
||||
} >>~/wallabag.creds
|
||||
msg_ok "Set up Database"
|
||||
|
||||
@ -48,12 +48,12 @@ useradd -d /opt/wallabag -s /bin/bash -M wallabag
|
||||
chown -R wallabag:wallabag /opt/wallabag
|
||||
mv /opt/wallabag/app/config/parameters.yml.dist /opt/wallabag/app/config/parameters.yml
|
||||
sed -i \
|
||||
-e 's|database_name: wallabag|database_name: wallabag_db|' \
|
||||
-e 's|database_port: ~|database_port: 3306|' \
|
||||
-e 's|database_user: root|database_user: wallabag|' \
|
||||
-e 's|database_password: ~|database_password: '"$DB_PASS"'|' \
|
||||
-e 's|secret: .*|secret: '"$SECRET_KEY"'|' \
|
||||
/opt/wallabag/app/config/parameters.yml
|
||||
-e 's|database_name: wallabag|database_name: wallabag_db|' \
|
||||
-e 's|database_port: ~|database_port: 3306|' \
|
||||
-e 's|database_user: root|database_user: wallabag|' \
|
||||
-e 's|database_password: ~|database_password: '"$DB_PASS"'|' \
|
||||
-e 's|secret: .*|secret: '"$SECRET_KEY"'|' \
|
||||
/opt/wallabag/app/config/parameters.yml
|
||||
|
||||
export COMPOSER_ALLOW_SUPERUSER=1
|
||||
sudo -u wallabag make install --no-interaction
|
||||
|
||||
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
|
||||
@ -5,7 +5,7 @@
|
||||
# https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
apk update && apk add curl >/dev/null 2>&1
|
||||
apk update && apk add curl >/dev/null 2>&1
|
||||
fi
|
||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/core.func)
|
||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/error_handler.func)
|
||||
@ -14,13 +14,13 @@ catch_errors
|
||||
|
||||
# This function enables IPv6 if it's not disabled and sets verbose mode
|
||||
verb_ip6() {
|
||||
set_std_mode # Set STD mode based on VERBOSE
|
||||
set_std_mode # Set STD mode based on VERBOSE
|
||||
|
||||
if [ "$DISABLEIPV6" == "yes" ]; then
|
||||
$STD sysctl -w net.ipv6.conf.all.disable_ipv6=1
|
||||
echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf
|
||||
$STD rc-update add sysctl default
|
||||
fi
|
||||
if [ "$DISABLEIPV6" == "yes" ]; then
|
||||
$STD sysctl -w net.ipv6.conf.all.disable_ipv6=1
|
||||
echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf
|
||||
$STD rc-update add sysctl default
|
||||
fi
|
||||
}
|
||||
|
||||
set -Eeuo pipefail
|
||||
@ -30,149 +30,153 @@ trap on_interrupt INT
|
||||
trap on_terminate TERM
|
||||
|
||||
error_handler() {
|
||||
local exit_code="$1"
|
||||
local line_number="$2"
|
||||
local command="$3"
|
||||
local exit_code="$1"
|
||||
local line_number="$2"
|
||||
local command="$3"
|
||||
|
||||
# Exitcode 0 = kein Fehler → ignorieren
|
||||
if [[ "$exit_code" -eq 0 ]]; then
|
||||
return 0
|
||||
fi
|
||||
# Exitcode 0 = kein Fehler → ignorieren
|
||||
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"
|
||||
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"
|
||||
}
|
||||
|
||||
on_exit() {
|
||||
local exit_code="$?"
|
||||
[[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile"
|
||||
exit "$exit_code"
|
||||
local exit_code="$?"
|
||||
[[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile"
|
||||
exit "$exit_code"
|
||||
}
|
||||
|
||||
on_interrupt() {
|
||||
echo -e "\n${RD}Interrupted by user (SIGINT)${CL}"
|
||||
exit 130
|
||||
echo -e "\n${RD}Interrupted by user (SIGINT)${CL}"
|
||||
exit 130
|
||||
}
|
||||
|
||||
on_terminate() {
|
||||
echo -e "\n${RD}Terminated by signal (SIGTERM)${CL}"
|
||||
exit 143
|
||||
echo -e "\n${RD}Terminated by signal (SIGTERM)${CL}"
|
||||
exit 143
|
||||
}
|
||||
|
||||
# This function sets up the Container OS by generating the locale, setting the timezone, and checking the network connection
|
||||
setting_up_container() {
|
||||
msg_info "Setting up Container OS"
|
||||
while [ $i -gt 0 ]; do
|
||||
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then
|
||||
break
|
||||
fi
|
||||
echo 1>&2 -en "${CROSS}${RD} No Network! "
|
||||
sleep $RETRY_EVERY
|
||||
i=$((i - 1))
|
||||
done
|
||||
|
||||
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then
|
||||
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
|
||||
echo -e "${NETWORK}Check Network Settings"
|
||||
exit 1
|
||||
msg_info "Setting up Container OS"
|
||||
while [ $i -gt 0 ]; do
|
||||
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then
|
||||
break
|
||||
fi
|
||||
msg_ok "Set up Container OS"
|
||||
msg_ok "Network Connected: ${BL}$(ip addr show | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 | tail -n1)${CL}"
|
||||
echo 1>&2 -en "${CROSS}${RD} No Network! "
|
||||
sleep $RETRY_EVERY
|
||||
i=$((i - 1))
|
||||
done
|
||||
|
||||
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then
|
||||
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
|
||||
echo -e "${NETWORK}Check Network Settings"
|
||||
exit 1
|
||||
fi
|
||||
msg_ok "Set up Container OS"
|
||||
msg_ok "Network Connected: ${BL}$(ip addr show | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 | tail -n1)${CL}"
|
||||
}
|
||||
|
||||
# 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() {
|
||||
set +e
|
||||
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
|
||||
msg_ok "Internet Connected"
|
||||
set +e
|
||||
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
|
||||
ipv4_status="${GN}✔${CL} IPv4"
|
||||
else
|
||||
ipv4_status="${RD}✖${CL} IPv4"
|
||||
read -r -p "Internet NOT connected. Continue anyway? <y/N> " prompt
|
||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
|
||||
else
|
||||
msg_error "Internet NOT Connected"
|
||||
read -r -p "Would you like to continue anyway? <y/N> " prompt
|
||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
|
||||
else
|
||||
echo -e "${NETWORK}Check Network Settings"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${NETWORK}Check Network Settings"
|
||||
exit 1
|
||||
fi
|
||||
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
|
||||
set -e
|
||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
||||
fi
|
||||
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
|
||||
if [[ -z "$RESOLVEDIP" ]]; then
|
||||
msg_error "Internet: ${ipv4_status} DNS Failed"
|
||||
else
|
||||
msg_ok "Internet: ${ipv4_status} DNS: ${BL}${RESOLVEDIP}${CL}"
|
||||
fi
|
||||
set -e
|
||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
||||
}
|
||||
|
||||
# This function updates the Container OS by running apt-get update and upgrade
|
||||
update_os() {
|
||||
msg_info "Updating Container OS"
|
||||
$STD apk update && $STD apk upgrade
|
||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/alpine-tools.func)
|
||||
msg_ok "Updated Container OS"
|
||||
msg_info "Updating Container OS"
|
||||
$STD apk update && $STD apk upgrade
|
||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/alpine-tools.func)
|
||||
msg_ok "Updated Container OS"
|
||||
}
|
||||
|
||||
# This function modifies the message of the day (motd) and SSH settings
|
||||
motd_ssh() {
|
||||
echo "export TERM='xterm-256color'" >>/root/.bashrc
|
||||
IP=$(ip -4 addr show eth0 | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1)
|
||||
echo "export TERM='xterm-256color'" >>/root/.bashrc
|
||||
IP=$(ip -4 addr show eth0 | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1)
|
||||
|
||||
if [ -f "/etc/os-release" ]; then
|
||||
OS_NAME=$(grep ^NAME /etc/os-release | cut -d= -f2 | tr -d '"')
|
||||
OS_VERSION=$(grep ^VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '"')
|
||||
else
|
||||
OS_NAME="Alpine Linux"
|
||||
OS_VERSION="Unknown"
|
||||
fi
|
||||
if [ -f "/etc/os-release" ]; then
|
||||
OS_NAME=$(grep ^NAME /etc/os-release | cut -d= -f2 | tr -d '"')
|
||||
OS_VERSION=$(grep ^VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '"')
|
||||
else
|
||||
OS_NAME="Alpine Linux"
|
||||
OS_VERSION="Unknown"
|
||||
fi
|
||||
|
||||
PROFILE_FILE="/etc/profile.d/00_lxc-details.sh"
|
||||
echo "echo -e \"\"" >"$PROFILE_FILE"
|
||||
echo -e "echo -e \"${BOLD}${YW}${APPLICATION} LXC Container - DEV Repository${CL}\"" >>"$PROFILE_FILE"
|
||||
echo -e "echo -e \"${RD}WARNING: This is a DEVELOPMENT version (ProxmoxVED). Do NOT use in production!${CL}\"" >>"$PROFILE_FILE"
|
||||
echo -e "echo -e \"${YW} OS: ${GN}${OS_NAME} - Version: ${OS_VERSION}${CL}\"" >>"$PROFILE_FILE"
|
||||
echo -e "echo -e \"${YW} Hostname: ${GN}\$(hostname)${CL}\"" >>"$PROFILE_FILE"
|
||||
echo -e "echo -e \"${YW} IP Address: ${GN}${IP}${CL}\"" >>"$PROFILE_FILE"
|
||||
echo -e "echo -e \"${YW} Repository: ${GN}https://github.com/community-scripts/ProxmoxVED${CL}\"" >>"$PROFILE_FILE"
|
||||
echo "echo \"\"" >>"$PROFILE_FILE"
|
||||
PROFILE_FILE="/etc/profile.d/00_lxc-details.sh"
|
||||
echo "echo -e \"\"" >"$PROFILE_FILE"
|
||||
echo -e "echo -e \"${BOLD}${YW}${APPLICATION} LXC Container - DEV Repository${CL}\"" >>"$PROFILE_FILE"
|
||||
echo -e "echo -e \"${RD}WARNING: This is a DEVELOPMENT version (ProxmoxVED). Do NOT use in production!${CL}\"" >>"$PROFILE_FILE"
|
||||
echo -e "echo -e \"${YW} OS: ${GN}${OS_NAME} - Version: ${OS_VERSION}${CL}\"" >>"$PROFILE_FILE"
|
||||
echo -e "echo -e \"${YW} Hostname: ${GN}\$(hostname)${CL}\"" >>"$PROFILE_FILE"
|
||||
echo -e "echo -e \"${YW} IP Address: ${GN}${IP}${CL}\"" >>"$PROFILE_FILE"
|
||||
echo -e "echo -e \"${YW} Repository: ${GN}https://github.com/community-scripts/ProxmoxVED${CL}\"" >>"$PROFILE_FILE"
|
||||
echo "echo \"\"" >>"$PROFILE_FILE"
|
||||
|
||||
if [[ "${SSH_ROOT}" == "yes" ]]; then
|
||||
$STD rc-update add sshd
|
||||
sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
|
||||
$STD /etc/init.d/sshd start
|
||||
fi
|
||||
if [[ "${SSH_ROOT}" == "yes" ]]; then
|
||||
$STD rc-update add sshd
|
||||
sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
|
||||
$STD /etc/init.d/sshd start
|
||||
fi
|
||||
}
|
||||
|
||||
# Validate Timezone for some LXC's
|
||||
validate_tz() {
|
||||
[[ -f "/usr/share/zoneinfo/$1" ]]
|
||||
[[ -f "/usr/share/zoneinfo/$1" ]]
|
||||
}
|
||||
|
||||
# This function customizes the container and enables passwordless login for the root user
|
||||
customize() {
|
||||
if [[ "$PASSWORD" == "" ]]; then
|
||||
msg_info "Customizing Container"
|
||||
passwd -d root >/dev/null 2>&1
|
||||
if [[ "$PASSWORD" == "" ]]; then
|
||||
msg_info "Customizing Container"
|
||||
passwd -d root >/dev/null 2>&1
|
||||
|
||||
# Ensure agetty is available
|
||||
apk add --no-cache --force-broken-world util-linux >/dev/null 2>&1
|
||||
# Ensure agetty is available
|
||||
apk add --no-cache --force-broken-world util-linux >/dev/null 2>&1
|
||||
|
||||
# Create persistent autologin boot script
|
||||
mkdir -p /etc/local.d
|
||||
cat <<'EOF' >/etc/local.d/autologin.start
|
||||
# Create persistent autologin boot script
|
||||
mkdir -p /etc/local.d
|
||||
cat <<'EOF' >/etc/local.d/autologin.start
|
||||
#!/bin/sh
|
||||
sed -i 's|^tty1::respawn:.*|tty1::respawn:/sbin/agetty --autologin root --noclear tty1 38400 linux|' /etc/inittab
|
||||
kill -HUP 1
|
||||
EOF
|
||||
touch /root/.hushlogin
|
||||
touch /root/.hushlogin
|
||||
|
||||
chmod +x /etc/local.d/autologin.start
|
||||
rc-update add local >/dev/null 2>&1
|
||||
chmod +x /etc/local.d/autologin.start
|
||||
rc-update add local >/dev/null 2>&1
|
||||
|
||||
# Apply autologin immediately for current session
|
||||
/etc/local.d/autologin.start
|
||||
# Apply autologin immediately for current session
|
||||
/etc/local.d/autologin.start
|
||||
|
||||
msg_ok "Customized Container"
|
||||
fi
|
||||
msg_ok "Customized Container"
|
||||
fi
|
||||
|
||||
echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVED/raw/main/ct/${app}.sh)\"" >/usr/bin/update
|
||||
chmod +x /usr/bin/update
|
||||
echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVED/raw/main/ct/${app}.sh)\"" >/usr/bin/update
|
||||
chmod +x /usr/bin/update
|
||||
}
|
||||
|
||||
242
misc/api.func
242
misc/api.func
@ -2,57 +2,153 @@
|
||||
# Author: michelroegl-brunner
|
||||
# License: MIT | https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/LICENSE
|
||||
|
||||
get_error_description() {
|
||||
local exit_code="$1"
|
||||
case "$exit_code" in
|
||||
0) echo " " ;;
|
||||
1) echo "General error: An unspecified error occurred." ;;
|
||||
2) echo "Incorrect shell usage or invalid command arguments." ;;
|
||||
3) echo "Unexecuted function or invalid shell condition." ;;
|
||||
4) echo "Error opening a file or invalid path." ;;
|
||||
5) echo "I/O error: An input/output failure occurred." ;;
|
||||
6) echo "No such device or address." ;;
|
||||
7) echo "Insufficient memory or resource exhaustion." ;;
|
||||
8) echo "Non-executable file or invalid file format." ;;
|
||||
9) echo "Failed child process execution." ;;
|
||||
18) echo "Connection to a remote server failed." ;;
|
||||
22) echo "Invalid argument or faulty network connection." ;;
|
||||
28) echo "No space left on device." ;;
|
||||
35) echo "Timeout while establishing a connection." ;;
|
||||
56) echo "Faulty TLS connection." ;;
|
||||
60) echo "SSL certificate error." ;;
|
||||
100) echo "LXC install error: Unexpected error in create_lxc.sh." ;;
|
||||
101) echo "LXC install error: No network connection detected." ;;
|
||||
200) echo "LXC creation failed." ;;
|
||||
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." ;;
|
||||
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." ;;
|
||||
125) echo "Docker error: Container could not start." ;;
|
||||
126) echo "Command not executable: Incorrect permissions or missing dependencies." ;;
|
||||
127) echo "Command not found: Incorrect path or missing dependency." ;;
|
||||
128) echo "Invalid exit signal, e.g., incorrect Git command." ;;
|
||||
129) echo "Signal 1 (SIGHUP): Process terminated due to hangup." ;;
|
||||
130) echo "Signal 2 (SIGINT): Manual termination via Ctrl+C." ;;
|
||||
132) echo "Signal 4 (SIGILL): Illegal machine instruction." ;;
|
||||
133) echo "Signal 5 (SIGTRAP): Debugging error or invalid breakpoint signal." ;;
|
||||
134) echo "Signal 6 (SIGABRT): Program aborted itself." ;;
|
||||
135) echo "Signal 7 (SIGBUS): Memory error, invalid memory address." ;;
|
||||
137) echo "Signal 9 (SIGKILL): Process forcibly terminated (OOM-killer or 'kill -9')." ;;
|
||||
139) echo "Signal 11 (SIGSEGV): Segmentation fault, possibly due to invalid pointer access." ;;
|
||||
141) echo "Signal 13 (SIGPIPE): Pipe closed unexpectedly." ;;
|
||||
143) echo "Signal 15 (SIGTERM): Process terminated normally." ;;
|
||||
152) echo "Signal 24 (SIGXCPU): CPU time limit exceeded." ;;
|
||||
255) echo "Unknown critical error, often due to missing permissions or broken scripts." ;;
|
||||
*) echo "Unknown error code ($exit_code)." ;;
|
||||
# ==============================================================================
|
||||
# API.FUNC - TELEMETRY & DIAGNOSTICS API
|
||||
# ==============================================================================
|
||||
#
|
||||
# Provides functions for sending anonymous telemetry data to Community-Scripts
|
||||
# API for analytics and diagnostics purposes.
|
||||
#
|
||||
# Features:
|
||||
# - Container/VM creation statistics
|
||||
# - Installation success/failure tracking
|
||||
# - Error code mapping and reporting
|
||||
# - Privacy-respecting anonymous telemetry
|
||||
#
|
||||
# Usage:
|
||||
# source <(curl -fsSL .../api.func)
|
||||
# post_to_api # Report container creation
|
||||
# post_update_to_api # Report installation status
|
||||
#
|
||||
# Privacy:
|
||||
# - Only anonymous statistics (no personal data)
|
||||
# - User can opt-out via diagnostics settings
|
||||
# - Random UUID for session tracking only
|
||||
#
|
||||
# ==============================================================================
|
||||
|
||||
# ==============================================================================
|
||||
# SECTION 1: ERROR CODE DESCRIPTIONS
|
||||
# ==============================================================================
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# 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
|
||||
# - Shared function with error_handler.func for consistency
|
||||
# ------------------------------------------------------------------------------
|
||||
explain_exit_code() {
|
||||
local code="$1"
|
||||
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
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# 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() {
|
||||
|
||||
if ! command -v curl &>/dev/null; then
|
||||
@ -81,7 +177,6 @@ post_to_api() {
|
||||
"ram_size": $RAM_SIZE,
|
||||
"os_type": "$var_os",
|
||||
"os_version": "$var_version",
|
||||
"disableip6": "$DISABLEIP6",
|
||||
"nsapp": "$NSAPP",
|
||||
"method": "$METHOD",
|
||||
"pve_version": "$pve_version",
|
||||
@ -92,12 +187,24 @@ EOF
|
||||
)
|
||||
if [[ "$DIAGNOSTICS" == "yes" ]]; then
|
||||
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD") || true
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD") || true
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# 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() {
|
||||
|
||||
if [[ ! -f /usr/local/community-scripts/diagnostics ]]; then
|
||||
@ -132,7 +239,6 @@ post_to_api_vm() {
|
||||
"ram_size": $RAM_SIZE,
|
||||
"os_type": "$var_os",
|
||||
"os_version": "$var_version",
|
||||
"disableip6": "",
|
||||
"nsapp": "$NSAPP",
|
||||
"method": "$METHOD",
|
||||
"pve_version": "$pve_version",
|
||||
@ -143,18 +249,38 @@ EOF
|
||||
)
|
||||
if [[ "$DIAGNOSTICS" == "yes" ]]; then
|
||||
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD") || true
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD") || true
|
||||
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() {
|
||||
|
||||
if ! command -v curl &>/dev/null; then
|
||||
return
|
||||
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
|
||||
return 0
|
||||
fi
|
||||
@ -171,7 +297,7 @@ post_update_to_api() {
|
||||
exit_code=1
|
||||
fi
|
||||
|
||||
error=$(get_error_description "$exit_code")
|
||||
error=$(explain_exit_code "$exit_code")
|
||||
|
||||
if [ -z "$error" ]; then
|
||||
error="Unknown error"
|
||||
@ -188,8 +314,8 @@ EOF
|
||||
)
|
||||
if [[ "$DIAGNOSTICS" == "yes" ]]; then
|
||||
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD") || true
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD") || true
|
||||
fi
|
||||
|
||||
POST_UPDATE_DONE=true
|
||||
|
||||
2162
misc/build.func
2162
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
|
||||
# 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
|
||||
_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() {
|
||||
[[ -n "${__FUNCTIONS_LOADED:-}" ]] && return
|
||||
__FUNCTIONS_LOADED=1
|
||||
@ -17,11 +38,14 @@ load_functions() {
|
||||
icons
|
||||
default_vars
|
||||
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() {
|
||||
YW=$(echo "\033[33m")
|
||||
@ -34,7 +58,14 @@ color() {
|
||||
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() {
|
||||
CS_YW=$'\033[33m'
|
||||
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() {
|
||||
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() {
|
||||
CM="${TAB}✔️${TAB}"
|
||||
@ -84,21 +124,29 @@ icons() {
|
||||
ADVANCED="${TAB}🧩${TAB}${CL}"
|
||||
FUSE="${TAB}🗂️${TAB}${CL}"
|
||||
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() {
|
||||
RETRY_NUM=10
|
||||
RETRY_EVERY=3
|
||||
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() {
|
||||
if [ "${VERBOSE:-no}" = "yes" ]; then
|
||||
@ -106,53 +154,93 @@ set_std_mode() {
|
||||
else
|
||||
STD="silent"
|
||||
fi
|
||||
}
|
||||
|
||||
SILENT_LOGFILE="/tmp/silent.$$.log"
|
||||
|
||||
silent() {
|
||||
local cmd="$*"
|
||||
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"
|
||||
# Enable bash tracing if trace mode active
|
||||
if [[ "${DEV_MODE_TRACE:-false}" == "true" ]]; then
|
||||
set -x
|
||||
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
||||
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() {
|
||||
if [[ "$(ps -p $$ -o comm=)" != "bash" ]]; then
|
||||
clear
|
||||
@ -163,7 +251,13 @@ shell_check() {
|
||||
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() {
|
||||
if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
|
||||
clear
|
||||
@ -174,8 +268,13 @@ root_check() {
|
||||
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() {
|
||||
local PVE_VER
|
||||
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
|
||||
@ -191,12 +290,12 @@ pve_check() {
|
||||
return 0
|
||||
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
|
||||
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 "Supported: Proxmox VE version 9.0"
|
||||
msg_error "Supported: Proxmox VE version 9.0 – 9.1"
|
||||
exit 1
|
||||
fi
|
||||
return 0
|
||||
@ -204,11 +303,17 @@ pve_check() {
|
||||
|
||||
# All other unsupported versions
|
||||
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
|
||||
}
|
||||
|
||||
# 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() {
|
||||
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
|
||||
echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n"
|
||||
@ -222,111 +327,165 @@ arch_check() {
|
||||
# ------------------------------------------------------------------------------
|
||||
# ssh_check()
|
||||
#
|
||||
# - Detects if script is running over SSH
|
||||
# - Warns user and recommends using Proxmox shell
|
||||
# - User can choose to continue or abort
|
||||
# - Detects if script is running over SSH connection
|
||||
# - Warns user for external SSH connections (recommends Proxmox shell)
|
||||
# - Skips warning for local/same-subnet connections
|
||||
# - Does not abort execution, only warns
|
||||
# ------------------------------------------------------------------------------
|
||||
ssh_check() {
|
||||
if [ -n "$SSH_CLIENT" ]; then
|
||||
local client_ip=$(awk '{print $1}' <<<"$SSH_CLIENT")
|
||||
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
|
||||
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 "For better stability, consider using the Proxmox Shell (Console) instead."
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to download & save header files
|
||||
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}"
|
||||
# ==============================================================================
|
||||
# SECTION 3: EXECUTION HELPERS
|
||||
# ==============================================================================
|
||||
|
||||
mkdir -p "$(dirname "$local_header_path")"
|
||||
|
||||
if [ ! -s "$local_header_path" ]; then
|
||||
if ! curl -fsSL "$header_url" -o "$local_header_path"; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
cat "$local_header_path" 2>/dev/null || true
|
||||
}
|
||||
|
||||
header_info() {
|
||||
local app_name=$(echo "${APP,,}" | tr -d ' ')
|
||||
local header_content
|
||||
|
||||
header_content=$(get_header "$app_name") || header_content=""
|
||||
|
||||
clear
|
||||
local term_width
|
||||
term_width=$(tput cols 2>/dev/null || echo 120)
|
||||
|
||||
if [ -n "$header_content" ]; then
|
||||
echo "$header_content"
|
||||
fi
|
||||
}
|
||||
|
||||
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"
|
||||
# ------------------------------------------------------------------------------
|
||||
# get_active_logfile()
|
||||
#
|
||||
# - Returns the appropriate log file based on execution context
|
||||
# - BUILD_LOG: Host operations (container creation)
|
||||
# - INSTALL_LOG: Container operations (application installation)
|
||||
# - Fallback to BUILD_LOG if neither is set
|
||||
# ------------------------------------------------------------------------------
|
||||
get_active_logfile() {
|
||||
if [[ -n "${INSTALL_LOG:-}" ]]; then
|
||||
echo "$INSTALL_LOG"
|
||||
elif [[ -n "${BUILD_LOG:-}" ]]; then
|
||||
echo "$BUILD_LOG"
|
||||
else
|
||||
tty_status="not-a-tty"
|
||||
# Fallback for legacy scripts
|
||||
echo "/tmp/build-$(date +%Y%m%d_%H%M%S).log"
|
||||
fi
|
||||
[[ "$verbose" != "no" || ! -t 2 ]]
|
||||
}
|
||||
|
||||
fatal() {
|
||||
msg_error "$1"
|
||||
kill -INT $$
|
||||
# Legacy compatibility: SILENT_LOGFILE points to active log
|
||||
SILENT_LOGFILE="$(get_active_logfile)"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# 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() {
|
||||
local chars=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏)
|
||||
local msg="${SPINNER_MSG:-Processing...}"
|
||||
local i=0
|
||||
while true; do
|
||||
local index=$((i++ % ${#chars[@]}))
|
||||
printf "\r\033[2K%s %b" "${CS_YWB}${chars[$index]}${CS_CL}" "${CS_YWB}${SPINNER_MSG:-}${CS_CL}"
|
||||
printf "\r\033[2K%s %b" "${CS_YWB}${chars[$index]}${CS_CL}" "${CS_YWB}${msg}${CS_CL}"
|
||||
sleep 0.1
|
||||
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() {
|
||||
tput cr 2>/dev/null || echo -en "\r"
|
||||
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() {
|
||||
local pid="${SPINNER_PID:-}"
|
||||
[[ -z "$pid" && -f /tmp/.spinner.pid ]] && pid=$(</tmp/.spinner.pid)
|
||||
@ -344,6 +503,19 @@ stop_spinner() {
|
||||
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() {
|
||||
local msg="$1"
|
||||
[[ -z "$msg" ]] && return
|
||||
@ -360,6 +532,12 @@ msg_info() {
|
||||
if is_verbose_mode || is_alpine; then
|
||||
local HOURGLASS="${TAB}⏳${TAB}"
|
||||
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
|
||||
fi
|
||||
|
||||
@ -368,29 +546,68 @@ msg_info() {
|
||||
SPINNER_PID=$!
|
||||
echo "$SPINNER_PID" >/tmp/.spinner.pid
|
||||
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() {
|
||||
local msg="$1"
|
||||
[[ -z "$msg" ]] && return
|
||||
stop_spinner
|
||||
clear_line
|
||||
printf "%s %b\n" "$CM" "${GN}${msg}${CL}" >&2
|
||||
echo -e "$CM ${GN}${msg}${CL}"
|
||||
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() {
|
||||
stop_spinner
|
||||
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() {
|
||||
stop_spinner
|
||||
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() {
|
||||
local symbol="${1:-"[*]"}"
|
||||
local color="${2:-"\e[36m"}"
|
||||
@ -400,13 +617,240 @@ msg_custom() {
|
||||
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
|
||||
[[ "${var_verbose:-0}" != "1" ]] && var_verbose=1
|
||||
echo -e "${YWB}[$(date '+%F %T')] [DEBUG]${CL} $*"
|
||||
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() {
|
||||
msg_info "Checking for active swap"
|
||||
|
||||
@ -445,4 +889,8 @@ check_or_create_swap() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# SIGNAL TRAPS
|
||||
# ==============================================================================
|
||||
|
||||
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,148 +1,342 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Error & Signal Handling for ProxmoxVED Scripts
|
||||
# ERROR HANDLER - ERROR & SIGNAL MANAGEMENT
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2021-2025 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# 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() {
|
||||
local code="$1"
|
||||
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)" ;;
|
||||
local code="$1"
|
||||
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" ;;
|
||||
# --- 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" ;;
|
||||
# --- 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)" ;;
|
||||
# --- 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" ;;
|
||||
# --- 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" ;;
|
||||
# --- 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" ;;
|
||||
# --- 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)" ;;
|
||||
209) echo "Custom: Container creation failed" ;;
|
||||
210) echo "Custom: Cluster not quorate" ;;
|
||||
214) echo "Custom: Not enough storage space" ;;
|
||||
215) echo "Custom: Container ID not listed" ;;
|
||||
216) echo "Custom: RootFS entry missing in config" ;;
|
||||
217) echo "Custom: Storage does not support rootdir" ;;
|
||||
220) echo "Custom: Unable to resolve template path" ;;
|
||||
222) echo "Custom: Template download failed after 3 attempts" ;;
|
||||
223) echo "Custom: Template not available after download" ;;
|
||||
231) echo "Custom: LXC stack upgrade/retry failed" ;;
|
||||
# --- 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/)" ;;
|
||||
# --- 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
|
||||
# --- 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 ---
|
||||
*) echo "Unknown error" ;;
|
||||
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() {
|
||||
local exit_code=${1:-$?}
|
||||
local command=${2:-${BASH_COMMAND:-unknown}}
|
||||
local line_number=${BASH_LINENO[0]:-unknown}
|
||||
local exit_code=${1:-$?}
|
||||
local command=${2:-${BASH_COMMAND:-unknown}}
|
||||
local line_number=${BASH_LINENO[0]:-unknown}
|
||||
|
||||
command="${command//\$STD/}"
|
||||
command="${command//\$STD/}"
|
||||
|
||||
if [[ "$exit_code" -eq 0 ]]; then
|
||||
return 0
|
||||
fi
|
||||
if [[ "$exit_code" -eq 0 ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local explanation
|
||||
explanation="$(explain_exit_code "$exit_code")"
|
||||
local explanation
|
||||
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"
|
||||
fi
|
||||
|
||||
if [[ -n "${DEBUG_LOGFILE:-}" ]]; then
|
||||
{
|
||||
echo "------ ERROR ------"
|
||||
echo "Timestamp : $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo "Exit Code : $exit_code ($explanation)"
|
||||
echo "Line : $line_number"
|
||||
echo "Command : $command"
|
||||
echo "-------------------"
|
||||
} >>"$DEBUG_LOGFILE"
|
||||
if [[ -n "${DEBUG_LOGFILE:-}" ]]; then
|
||||
{
|
||||
echo "------ ERROR ------"
|
||||
echo "Timestamp : $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo "Exit Code : $exit_code ($explanation)"
|
||||
echo "Line : $line_number"
|
||||
echo "Command : $command"
|
||||
echo "-------------------"
|
||||
} >>"$DEBUG_LOGFILE"
|
||||
fi
|
||||
|
||||
# Get active log file (BUILD_LOG or INSTALL_LOG)
|
||||
local active_log=""
|
||||
if declare -f get_active_logfile >/dev/null 2>&1; then
|
||||
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
|
||||
|
||||
if [[ -n "${SILENT_LOGFILE:-}" && -s "$SILENT_LOGFILE" ]]; then
|
||||
echo "--- Last 20 lines of silent log ($SILENT_LOGFILE) ---"
|
||||
tail -n 20 "$SILENT_LOGFILE"
|
||||
echo "---------------------------------------------------"
|
||||
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() {
|
||||
local exit_code=$?
|
||||
[[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile"
|
||||
exit "$exit_code"
|
||||
local exit_code=$?
|
||||
[[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile"
|
||||
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() {
|
||||
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}"
|
||||
exit 130
|
||||
fi
|
||||
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() {
|
||||
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}"
|
||||
exit 143
|
||||
fi
|
||||
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() {
|
||||
set -Ee -o pipefail
|
||||
if [ "${STRICT_UNSET:-0}" = "1" ]; then
|
||||
set -u
|
||||
fi
|
||||
trap 'error_handler' ERR
|
||||
trap on_exit EXIT
|
||||
trap on_interrupt INT
|
||||
trap on_terminate TERM
|
||||
set -Ee -o pipefail
|
||||
if [ "${STRICT_UNSET:-0}" = "1" ]; then
|
||||
set -u
|
||||
fi
|
||||
|
||||
trap 'error_handler' ERR
|
||||
trap on_exit EXIT
|
||||
trap on_interrupt INT
|
||||
trap on_terminate TERM
|
||||
}
|
||||
|
||||
@ -4,6 +4,41 @@
|
||||
# Co-Author: michelroegl-brunner
|
||||
# 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
|
||||
printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2
|
||||
apt-get update >/dev/null 2>&1
|
||||
@ -14,7 +49,20 @@ source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxV
|
||||
load_functions
|
||||
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() {
|
||||
set_std_mode # Set STD mode based on VERBOSE
|
||||
|
||||
@ -24,29 +72,15 @@ verb_ip6() {
|
||||
fi
|
||||
}
|
||||
|
||||
# # This function sets error handling options and defines the error_handler function to handle errors
|
||||
# catch_errors() {
|
||||
# set -Eeuo pipefail
|
||||
# trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
||||
# }
|
||||
|
||||
# # This function handles errors
|
||||
# error_handler() {
|
||||
# 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()
|
||||
#
|
||||
# - Verifies network connectivity via hostname -I
|
||||
# - Retries up to RETRY_NUM times with RETRY_EVERY seconds delay
|
||||
# - Removes Python EXTERNALLY-MANAGED restrictions
|
||||
# - Disables systemd-networkd-wait-online.service for faster boot
|
||||
# - Exits with error if network unavailable after retries
|
||||
# ------------------------------------------------------------------------------
|
||||
setting_up_container() {
|
||||
msg_info "Setting up Container OS"
|
||||
for ((i = RETRY_NUM; i > 0; i--)); do
|
||||
@ -68,7 +102,17 @@ setting_up_container() {
|
||||
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() {
|
||||
set +e
|
||||
trap - ERR
|
||||
@ -78,20 +122,23 @@ network_check() {
|
||||
|
||||
# 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
|
||||
msg_ok "IPv4 Internet Connected"
|
||||
ipv4_connected=true
|
||||
ipv4_status="${GN}✔${CL} IPv4"
|
||||
else
|
||||
msg_error "IPv4 Internet Not Connected"
|
||||
ipv4_status="${RD}✖${CL} IPv4"
|
||||
fi
|
||||
|
||||
# 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
|
||||
msg_ok "IPv6 Internet Connected"
|
||||
ipv6_connected=true
|
||||
ipv6_status="${GN}✔${CL} IPv6"
|
||||
else
|
||||
msg_error "IPv6 Internet Not Connected"
|
||||
ipv6_status="${RD}✖${CL} IPv6"
|
||||
fi
|
||||
|
||||
# Show combined status
|
||||
msg_ok "Internet: ${ipv4_status} ${ipv6_status}"
|
||||
|
||||
# If both IPv4 and IPv6 checks fail, prompt the user
|
||||
if [[ $ipv4_connected == false && $ipv6_connected == false ]]; then
|
||||
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
|
||||
}
|
||||
|
||||
# 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() {
|
||||
msg_info "Updating Container OS"
|
||||
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)
|
||||
}
|
||||
|
||||
# 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() {
|
||||
grep -qxF "export TERM='xterm-256color'" /root/.bashrc || echo "export TERM='xterm-256color'" >>/root/.bashrc
|
||||
|
||||
@ -180,7 +256,19 @@ motd_ssh() {
|
||||
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() {
|
||||
if [[ "$PASSWORD" == "" ]]; then
|
||||
msg_info "Customizing Container"
|
||||
@ -191,8 +279,7 @@ customize() {
|
||||
ExecStart=
|
||||
ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl restart $(basename $(dirname $GETTY_OVERRIDE) | sed 's/\.d//')
|
||||
$STD systemctl daemon-reload || true
|
||||
msg_ok "Customized Container"
|
||||
fi
|
||||
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()
|
||||
1149
misc/tools.func
1149
misc/tools.func
File diff suppressed because it is too large
Load Diff
@ -394,9 +394,9 @@ check_root() {
|
||||
}
|
||||
|
||||
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"
|
||||
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..."
|
||||
sleep 2
|
||||
exit
|
||||
|
||||
@ -51,29 +51,29 @@ pve_check() {
|
||||
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
|
||||
|
||||
# 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]}"
|
||||
if ((MINOR != 0)); then
|
||||
if ((MINOR < 0 || MINOR > 9)); then
|
||||
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
|
||||
fi
|
||||
return 0
|
||||
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
|
||||
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 "Supported versions: 8.0 – 8.9 or 9.0"
|
||||
msg_error "Supported versions: 8.0 – 8.9 or 9.0 – 9.1"
|
||||
exit 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
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 @@
|
||||
__ _ __ __ __ __
|
||||
____ _/ /_ (_) /_/ /_____ _____________ ____ / /_ ___ _ ______ ____ _____/ /____ _____
|
||||
/ __ `/ __ \/ / __/ __/ __ \/ ___/ ___/ _ \/ __ \/ __/_____/ _ \| |/_/ __ \/ __ \/ ___/ __/ _ \/ ___/
|
||||
/ /_/ / /_/ / / /_/ /_/ /_/ / / / / / __/ / / / /_/_____/ __/> </ /_/ / /_/ / / / /_/ __/ /
|
||||
\__, /_.___/_/\__/\__/\____/_/ /_/ \___/_/ /_/\__/ \___/_/|_/ .___/\____/_/ \__/\___/_/
|
||||
/_/ /_/
|
||||
@ -8,8 +8,8 @@
|
||||
source /dev/stdin <<<$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/api.func)
|
||||
|
||||
function header_info {
|
||||
clear
|
||||
cat <<"EOF"
|
||||
clear
|
||||
cat <<"EOF"
|
||||
___ ____ ____ __ __ _ __ _ ____ ___
|
||||
/ | / / / ___// /_____ ______/ / (_)___ / /__ | | / / |/ /
|
||||
/ /| | / / /\__ \/ __/ __ `/ ___/ / / / __ \/ //_/ | | / / /|_/ /
|
||||
@ -48,306 +48,306 @@ trap cleanup EXIT
|
||||
trap 'post_update_to_api "failed" "INTERRUPTED"' SIGINT
|
||||
trap 'post_update_to_api "failed" "TERMINATED"' SIGTERM
|
||||
function error_handler() {
|
||||
local exit_code="$?"
|
||||
local line_number="$1"
|
||||
local command="$2"
|
||||
post_update_to_api "failed" "${command}"
|
||||
local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
|
||||
echo -e "\n$error_message\n"
|
||||
cleanup_vmid
|
||||
local exit_code="$?"
|
||||
local line_number="$1"
|
||||
local command="$2"
|
||||
post_update_to_api "failed" "${command}"
|
||||
local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
|
||||
echo -e "\n$error_message\n"
|
||||
cleanup_vmid
|
||||
}
|
||||
|
||||
function cleanup_vmid() {
|
||||
if qm status $VMID &>/dev/null; then
|
||||
qm stop $VMID &>/dev/null
|
||||
qm destroy $VMID &>/dev/null
|
||||
fi
|
||||
if qm status $VMID &>/dev/null; then
|
||||
qm stop $VMID &>/dev/null
|
||||
qm destroy $VMID &>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
popd >/dev/null
|
||||
rm -rf $TEMP_DIR
|
||||
popd >/dev/null
|
||||
rm -rf $TEMP_DIR
|
||||
}
|
||||
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
pushd $TEMP_DIR >/dev/null
|
||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "AllStarLink VM" --yesno "This will create a New AllStarLink VM. Proceed?" 10 58; then
|
||||
:
|
||||
:
|
||||
else
|
||||
header_info && echo -e "⚠ User exited script \n" && exit
|
||||
header_info && echo -e "⚠ User exited script \n" && exit
|
||||
fi
|
||||
|
||||
function msg_info() {
|
||||
local msg="$1"
|
||||
echo -ne " ${HOLD} ${YW}${msg}..."
|
||||
local msg="$1"
|
||||
echo -ne " ${HOLD} ${YW}${msg}..."
|
||||
}
|
||||
|
||||
function msg_ok() {
|
||||
local msg="$1"
|
||||
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
|
||||
local msg="$1"
|
||||
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
|
||||
}
|
||||
|
||||
function msg_error() {
|
||||
local msg="$1"
|
||||
echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}"
|
||||
local msg="$1"
|
||||
echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}"
|
||||
}
|
||||
|
||||
function check_root() {
|
||||
if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
|
||||
clear
|
||||
msg_error "Please run this script as root."
|
||||
echo -e "\nExiting..."
|
||||
sleep 2
|
||||
exit
|
||||
fi
|
||||
if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
|
||||
clear
|
||||
msg_error "Please run this script as root."
|
||||
echo -e "\nExiting..."
|
||||
sleep 2
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
function pve_check() {
|
||||
if ! pveversion | grep -Eq "pve-manager/8\.[1-3](\.[0-9]+)*"; then
|
||||
msg_error "This version of Proxmox Virtual Environment is not supported"
|
||||
echo -e "Requires Proxmox Virtual Environment Version 8.1 or later."
|
||||
echo -e "Exiting..."
|
||||
sleep 2
|
||||
exit
|
||||
fi
|
||||
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"
|
||||
echo -e "Requires Proxmox Virtual Environment Version 8.1 - 8.3 or 9.0 - 9.1."
|
||||
echo -e "Exiting..."
|
||||
sleep 2
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
function arch_check() {
|
||||
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
|
||||
if [ "$(dpkg --print-architecture)" != "arm64" ]; then
|
||||
msg_error "This script will not work with your CPU Architekture \n"
|
||||
echo -e "Exiting..."
|
||||
sleep 2
|
||||
exit
|
||||
fi
|
||||
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
|
||||
if [ "$(dpkg --print-architecture)" != "arm64" ]; then
|
||||
msg_error "This script will not work with your CPU Architekture \n"
|
||||
echo -e "Exiting..."
|
||||
sleep 2
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function ssh_check() {
|
||||
if command -v pveversion >/dev/null 2>&1; then
|
||||
if [ -n "${SSH_CLIENT:+x}" ]; then
|
||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then
|
||||
echo "you've been warned"
|
||||
else
|
||||
clear
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
if command -v pveversion >/dev/null 2>&1; then
|
||||
if [ -n "${SSH_CLIENT:+x}" ]; then
|
||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then
|
||||
echo "you've been warned"
|
||||
else
|
||||
clear
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function exit_script() {
|
||||
clear
|
||||
echo -e "⚠ User exited script \n"
|
||||
exit
|
||||
clear
|
||||
echo -e "⚠ User exited script \n"
|
||||
exit
|
||||
}
|
||||
|
||||
function default_settings() {
|
||||
VMID="$NEXTID"
|
||||
FORMAT=",efitype=4m"
|
||||
MACHINE=""
|
||||
DISK_CACHE=""
|
||||
HN="allstarlink"
|
||||
CPU_TYPE=""
|
||||
CORE_COUNT="2"
|
||||
RAM_SIZE="2048"
|
||||
BRG="vmbr0"
|
||||
MAC="$GEN_MAC"
|
||||
VLAN=""
|
||||
MTU=""
|
||||
START_VM="yes"
|
||||
METHOD="default"
|
||||
echo -e "${DGN}Using Virtual Machine ID: ${BGN}${VMID}${CL}"
|
||||
echo -e "${DGN}Using Machine Type: ${BGN}i440fx${CL}"
|
||||
echo -e "${DGN}Using Disk Cache: ${BGN}None${CL}"
|
||||
echo -e "${DGN}Using Hostname: ${BGN}${HN}${CL}"
|
||||
echo -e "${DGN}Using CPU Model: ${BGN}KVM64${CL}"
|
||||
echo -e "${DGN}Allocated Cores: ${BGN}${CORE_COUNT}${CL}"
|
||||
echo -e "${DGN}Allocated RAM: ${BGN}${RAM_SIZE}${CL}"
|
||||
echo -e "${DGN}Using Bridge: ${BGN}${BRG}${CL}"
|
||||
echo -e "${DGN}Using MAC Address: ${BGN}${MAC}${CL}"
|
||||
echo -e "${DGN}Using VLAN: ${BGN}Default${CL}"
|
||||
echo -e "${DGN}Using Interface MTU Size: ${BGN}Default${CL}"
|
||||
echo -e "${DGN}Start VM when completed: ${BGN}yes${CL}"
|
||||
echo -e "${BL}Creating a AllStarLink VM using the above default settings${CL}"
|
||||
VMID="$NEXTID"
|
||||
FORMAT=",efitype=4m"
|
||||
MACHINE=""
|
||||
DISK_CACHE=""
|
||||
HN="allstarlink"
|
||||
CPU_TYPE=""
|
||||
CORE_COUNT="2"
|
||||
RAM_SIZE="2048"
|
||||
BRG="vmbr0"
|
||||
MAC="$GEN_MAC"
|
||||
VLAN=""
|
||||
MTU=""
|
||||
START_VM="yes"
|
||||
METHOD="default"
|
||||
echo -e "${DGN}Using Virtual Machine ID: ${BGN}${VMID}${CL}"
|
||||
echo -e "${DGN}Using Machine Type: ${BGN}i440fx${CL}"
|
||||
echo -e "${DGN}Using Disk Cache: ${BGN}None${CL}"
|
||||
echo -e "${DGN}Using Hostname: ${BGN}${HN}${CL}"
|
||||
echo -e "${DGN}Using CPU Model: ${BGN}KVM64${CL}"
|
||||
echo -e "${DGN}Allocated Cores: ${BGN}${CORE_COUNT}${CL}"
|
||||
echo -e "${DGN}Allocated RAM: ${BGN}${RAM_SIZE}${CL}"
|
||||
echo -e "${DGN}Using Bridge: ${BGN}${BRG}${CL}"
|
||||
echo -e "${DGN}Using MAC Address: ${BGN}${MAC}${CL}"
|
||||
echo -e "${DGN}Using VLAN: ${BGN}Default${CL}"
|
||||
echo -e "${DGN}Using Interface MTU Size: ${BGN}Default${CL}"
|
||||
echo -e "${DGN}Start VM when completed: ${BGN}yes${CL}"
|
||||
echo -e "${BL}Creating a AllStarLink VM using the above default settings${CL}"
|
||||
}
|
||||
|
||||
function advanced_settings() {
|
||||
METHOD="advanced"
|
||||
while true; do
|
||||
if VMID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 $NEXTID --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z "$VMID" ]; then
|
||||
VMID="$NEXTID"
|
||||
fi
|
||||
if pct status "$VMID" &>/dev/null || qm status "$VMID" &>/dev/null; then
|
||||
echo -e "${CROSS}${RD} ID $VMID is already in use${CL}"
|
||||
sleep 2
|
||||
continue
|
||||
fi
|
||||
echo -e "${DGN}Virtual Machine ID: ${BGN}$VMID${CL}"
|
||||
break
|
||||
else
|
||||
exit_script
|
||||
fi
|
||||
done
|
||||
|
||||
if MACH=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \
|
||||
"i440fx" "Machine i440fx" ON \
|
||||
"q35" "Machine q35" OFF \
|
||||
3>&1 1>&2 2>&3); then
|
||||
if [ $MACH = q35 ]; then
|
||||
echo -e "${DGN}Using Machine Type: ${BGN}$MACH${CL}"
|
||||
FORMAT=""
|
||||
MACHINE=" -machine q35"
|
||||
else
|
||||
echo -e "${DGN}Using Machine Type: ${BGN}$MACH${CL}"
|
||||
FORMAT=",efitype=4m"
|
||||
MACHINE=""
|
||||
fi
|
||||
METHOD="advanced"
|
||||
while true; do
|
||||
if VMID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 $NEXTID --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z "$VMID" ]; then
|
||||
VMID="$NEXTID"
|
||||
fi
|
||||
if pct status "$VMID" &>/dev/null || qm status "$VMID" &>/dev/null; then
|
||||
echo -e "${CROSS}${RD} ID $VMID is already in use${CL}"
|
||||
sleep 2
|
||||
continue
|
||||
fi
|
||||
echo -e "${DGN}Virtual Machine ID: ${BGN}$VMID${CL}"
|
||||
break
|
||||
else
|
||||
exit_script
|
||||
exit_script
|
||||
fi
|
||||
done
|
||||
|
||||
if DISK_CACHE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
|
||||
"0" "None (Default)" ON \
|
||||
"1" "Write Through" OFF \
|
||||
3>&1 1>&2 2>&3); then
|
||||
if [ $DISK_CACHE = "1" ]; then
|
||||
echo -e "${DGN}Using Disk Cache: ${BGN}Write Through${CL}"
|
||||
DISK_CACHE="cache=writethrough,"
|
||||
else
|
||||
echo -e "${DGN}Using Disk Cache: ${BGN}None${CL}"
|
||||
DISK_CACHE=""
|
||||
fi
|
||||
if MACH=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \
|
||||
"i440fx" "Machine i440fx" ON \
|
||||
"q35" "Machine q35" OFF \
|
||||
3>&1 1>&2 2>&3); then
|
||||
if [ $MACH = q35 ]; then
|
||||
echo -e "${DGN}Using Machine Type: ${BGN}$MACH${CL}"
|
||||
FORMAT=""
|
||||
MACHINE=" -machine q35"
|
||||
else
|
||||
exit_script
|
||||
echo -e "${DGN}Using Machine Type: ${BGN}$MACH${CL}"
|
||||
FORMAT=",efitype=4m"
|
||||
MACHINE=""
|
||||
fi
|
||||
else
|
||||
exit_script
|
||||
fi
|
||||
|
||||
if VM_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 allstarlink --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $VM_NAME ]; then
|
||||
HN="allstarlink"
|
||||
echo -e "${DGN}Using Hostname: ${BGN}$HN${CL}"
|
||||
else
|
||||
HN=$(echo ${VM_NAME,,} | tr -d ' ')
|
||||
echo -e "${DGN}Using Hostname: ${BGN}$HN${CL}"
|
||||
fi
|
||||
if DISK_CACHE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
|
||||
"0" "None (Default)" ON \
|
||||
"1" "Write Through" OFF \
|
||||
3>&1 1>&2 2>&3); then
|
||||
if [ $DISK_CACHE = "1" ]; then
|
||||
echo -e "${DGN}Using Disk Cache: ${BGN}Write Through${CL}"
|
||||
DISK_CACHE="cache=writethrough,"
|
||||
else
|
||||
exit_script
|
||||
echo -e "${DGN}Using Disk Cache: ${BGN}None${CL}"
|
||||
DISK_CACHE=""
|
||||
fi
|
||||
else
|
||||
exit_script
|
||||
fi
|
||||
|
||||
if CPU_TYPE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
|
||||
"0" "KVM64 (Default)" ON \
|
||||
"1" "Host" OFF \
|
||||
3>&1 1>&2 2>&3); then
|
||||
if [ $CPU_TYPE1 = "1" ]; then
|
||||
echo -e "${DGN}Using CPU Model: ${BGN}Host${CL}"
|
||||
CPU_TYPE=" -cpu host"
|
||||
else
|
||||
echo -e "${DGN}Using CPU Model: ${BGN}KVM64${CL}"
|
||||
CPU_TYPE=""
|
||||
fi
|
||||
if VM_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 allstarlink --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $VM_NAME ]; then
|
||||
HN="allstarlink"
|
||||
echo -e "${DGN}Using Hostname: ${BGN}$HN${CL}"
|
||||
else
|
||||
exit_script
|
||||
HN=$(echo ${VM_NAME,,} | tr -d ' ')
|
||||
echo -e "${DGN}Using Hostname: ${BGN}$HN${CL}"
|
||||
fi
|
||||
else
|
||||
exit_script
|
||||
fi
|
||||
|
||||
if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 2 --title "CORE COUNT" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $CORE_COUNT ]; then
|
||||
CORE_COUNT="2"
|
||||
echo -e "${DGN}Allocated Cores: ${BGN}$CORE_COUNT${CL}"
|
||||
else
|
||||
echo -e "${DGN}Allocated Cores: ${BGN}$CORE_COUNT${CL}"
|
||||
fi
|
||||
if CPU_TYPE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
|
||||
"0" "KVM64 (Default)" ON \
|
||||
"1" "Host" OFF \
|
||||
3>&1 1>&2 2>&3); then
|
||||
if [ $CPU_TYPE1 = "1" ]; then
|
||||
echo -e "${DGN}Using CPU Model: ${BGN}Host${CL}"
|
||||
CPU_TYPE=" -cpu host"
|
||||
else
|
||||
exit_script
|
||||
echo -e "${DGN}Using CPU Model: ${BGN}KVM64${CL}"
|
||||
CPU_TYPE=""
|
||||
fi
|
||||
else
|
||||
exit_script
|
||||
fi
|
||||
|
||||
if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 2048 --title "RAM" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $RAM_SIZE ]; then
|
||||
RAM_SIZE="4096"
|
||||
echo -e "${DGN}Allocated RAM: ${BGN}$RAM_SIZE${CL}"
|
||||
else
|
||||
echo -e "${DGN}Allocated RAM: ${BGN}$RAM_SIZE${CL}"
|
||||
fi
|
||||
if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 2 --title "CORE COUNT" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $CORE_COUNT ]; then
|
||||
CORE_COUNT="2"
|
||||
echo -e "${DGN}Allocated Cores: ${BGN}$CORE_COUNT${CL}"
|
||||
else
|
||||
exit_script
|
||||
echo -e "${DGN}Allocated Cores: ${BGN}$CORE_COUNT${CL}"
|
||||
fi
|
||||
else
|
||||
exit_script
|
||||
fi
|
||||
|
||||
if BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Bridge" 8 58 vmbr0 --title "BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $BRG ]; then
|
||||
BRG="vmbr0"
|
||||
echo -e "${DGN}Using Bridge: ${BGN}$BRG${CL}"
|
||||
else
|
||||
echo -e "${DGN}Using Bridge: ${BGN}$BRG${CL}"
|
||||
fi
|
||||
if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 2048 --title "RAM" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $RAM_SIZE ]; then
|
||||
RAM_SIZE="4096"
|
||||
echo -e "${DGN}Allocated RAM: ${BGN}$RAM_SIZE${CL}"
|
||||
else
|
||||
exit_script
|
||||
echo -e "${DGN}Allocated RAM: ${BGN}$RAM_SIZE${CL}"
|
||||
fi
|
||||
else
|
||||
exit_script
|
||||
fi
|
||||
|
||||
if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address" 8 58 $GEN_MAC --title "MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $MAC1 ]; then
|
||||
MAC="$GEN_MAC"
|
||||
echo -e "${DGN}Using MAC Address: ${BGN}$MAC${CL}"
|
||||
else
|
||||
MAC="$MAC1"
|
||||
echo -e "${DGN}Using MAC Address: ${BGN}$MAC1${CL}"
|
||||
fi
|
||||
if BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Bridge" 8 58 vmbr0 --title "BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $BRG ]; then
|
||||
BRG="vmbr0"
|
||||
echo -e "${DGN}Using Bridge: ${BGN}$BRG${CL}"
|
||||
else
|
||||
exit_script
|
||||
echo -e "${DGN}Using Bridge: ${BGN}$BRG${CL}"
|
||||
fi
|
||||
else
|
||||
exit_script
|
||||
fi
|
||||
|
||||
if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan(leave blank for default)" 8 58 --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $VLAN1 ]; then
|
||||
VLAN1="Default"
|
||||
VLAN=""
|
||||
echo -e "${DGN}Using Vlan: ${BGN}$VLAN1${CL}"
|
||||
else
|
||||
VLAN=",tag=$VLAN1"
|
||||
echo -e "${DGN}Using Vlan: ${BGN}$VLAN1${CL}"
|
||||
fi
|
||||
if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address" 8 58 $GEN_MAC --title "MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $MAC1 ]; then
|
||||
MAC="$GEN_MAC"
|
||||
echo -e "${DGN}Using MAC Address: ${BGN}$MAC${CL}"
|
||||
else
|
||||
exit_script
|
||||
MAC="$MAC1"
|
||||
echo -e "${DGN}Using MAC Address: ${BGN}$MAC1${CL}"
|
||||
fi
|
||||
else
|
||||
exit_script
|
||||
fi
|
||||
|
||||
if MTU1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 --title "MTU SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $MTU1 ]; then
|
||||
MTU1="Default"
|
||||
MTU=""
|
||||
echo -e "${DGN}Using Interface MTU Size: ${BGN}$MTU1${CL}"
|
||||
else
|
||||
MTU=",mtu=$MTU1"
|
||||
echo -e "${DGN}Using Interface MTU Size: ${BGN}$MTU1${CL}"
|
||||
fi
|
||||
if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan(leave blank for default)" 8 58 --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $VLAN1 ]; then
|
||||
VLAN1="Default"
|
||||
VLAN=""
|
||||
echo -e "${DGN}Using Vlan: ${BGN}$VLAN1${CL}"
|
||||
else
|
||||
exit_script
|
||||
VLAN=",tag=$VLAN1"
|
||||
echo -e "${DGN}Using Vlan: ${BGN}$VLAN1${CL}"
|
||||
fi
|
||||
else
|
||||
exit_script
|
||||
fi
|
||||
|
||||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "START VIRTUAL MACHINE" --yesno "Start VM when completed?" 10 58); then
|
||||
echo -e "${DGN}Start VM when completed: ${BGN}yes${CL}"
|
||||
START_VM="yes"
|
||||
if MTU1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 --title "MTU SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||
if [ -z $MTU1 ]; then
|
||||
MTU1="Default"
|
||||
MTU=""
|
||||
echo -e "${DGN}Using Interface MTU Size: ${BGN}$MTU1${CL}"
|
||||
else
|
||||
echo -e "${DGN}Start VM when completed: ${BGN}no${CL}"
|
||||
START_VM="no"
|
||||
MTU=",mtu=$MTU1"
|
||||
echo -e "${DGN}Using Interface MTU Size: ${BGN}$MTU1${CL}"
|
||||
fi
|
||||
else
|
||||
exit_script
|
||||
fi
|
||||
|
||||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create a AllStarLink VM?" --no-button Do-Over 10 58); then
|
||||
echo -e "${RD}Creating a AllStarLink VM using the above advanced settings${CL}"
|
||||
else
|
||||
header_info
|
||||
echo -e "${RD}Using Advanced Settings${CL}"
|
||||
advanced_settings
|
||||
fi
|
||||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "START VIRTUAL MACHINE" --yesno "Start VM when completed?" 10 58); then
|
||||
echo -e "${DGN}Start VM when completed: ${BGN}yes${CL}"
|
||||
START_VM="yes"
|
||||
else
|
||||
echo -e "${DGN}Start VM when completed: ${BGN}no${CL}"
|
||||
START_VM="no"
|
||||
fi
|
||||
|
||||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create a AllStarLink VM?" --no-button Do-Over 10 58); then
|
||||
echo -e "${RD}Creating a AllStarLink VM using the above advanced settings${CL}"
|
||||
else
|
||||
header_info
|
||||
echo -e "${RD}Using Advanced Settings${CL}"
|
||||
advanced_settings
|
||||
fi
|
||||
}
|
||||
|
||||
function start_script() {
|
||||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno "Use Default Settings?" --no-button Advanced 10 58); then
|
||||
header_info
|
||||
echo -e "${BL}Using Default Settings${CL}"
|
||||
default_settings
|
||||
else
|
||||
header_info
|
||||
echo -e "${RD}Using Advanced Settings${CL}"
|
||||
advanced_settings
|
||||
fi
|
||||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno "Use Default Settings?" --no-button Advanced 10 58); then
|
||||
header_info
|
||||
echo -e "${BL}Using Default Settings${CL}"
|
||||
default_settings
|
||||
else
|
||||
header_info
|
||||
echo -e "${RD}Using Advanced Settings${CL}"
|
||||
advanced_settings
|
||||
fi
|
||||
}
|
||||
|
||||
check_root
|
||||
@ -359,29 +359,29 @@ post_to_api_vm
|
||||
|
||||
msg_info "Validating Storage"
|
||||
while read -r line; do
|
||||
TAG=$(echo $line | awk '{print $1}')
|
||||
TYPE=$(echo $line | awk '{printf "%-10s", $2}')
|
||||
FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
|
||||
ITEM=" Type: $TYPE Free: $FREE "
|
||||
OFFSET=2
|
||||
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
|
||||
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
|
||||
fi
|
||||
STORAGE_MENU+=("$TAG" "$ITEM" "OFF")
|
||||
TAG=$(echo $line | awk '{print $1}')
|
||||
TYPE=$(echo $line | awk '{printf "%-10s", $2}')
|
||||
FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
|
||||
ITEM=" Type: $TYPE Free: $FREE "
|
||||
OFFSET=2
|
||||
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
|
||||
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
|
||||
fi
|
||||
STORAGE_MENU+=("$TAG" "$ITEM" "OFF")
|
||||
done < <(pvesm status -content images | awk 'NR>1')
|
||||
VALID=$(pvesm status -content images | awk 'NR>1')
|
||||
if [ -z "$VALID" ]; then
|
||||
msg_error "Unable to detect a valid storage location."
|
||||
exit
|
||||
msg_error "Unable to detect a valid storage location."
|
||||
exit
|
||||
elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
|
||||
STORAGE=${STORAGE_MENU[0]}
|
||||
STORAGE=${STORAGE_MENU[0]}
|
||||
else
|
||||
while [ -z "${STORAGE:+x}" ]; do
|
||||
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
|
||||
"Which storage pool you would like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
|
||||
16 $(($MSG_MAX_LENGTH + 23)) 6 \
|
||||
"${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3) || exit
|
||||
done
|
||||
while [ -z "${STORAGE:+x}" ]; do
|
||||
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
|
||||
"Which storage pool you would like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
|
||||
16 $(($MSG_MAX_LENGTH + 23)) 6 \
|
||||
"${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3) || exit
|
||||
done
|
||||
fi
|
||||
msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location."
|
||||
msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}."
|
||||
@ -397,23 +397,23 @@ msg_ok "Downloaded ${CL}${BL}${FILE}${CL}"
|
||||
STORAGE_TYPE=$(pvesm status -storage $STORAGE | awk 'NR>1 {print $2}')
|
||||
case $STORAGE_TYPE in
|
||||
nfs | dir)
|
||||
DISK_EXT=".qcow2"
|
||||
DISK_REF="$VMID/"
|
||||
DISK_IMPORT="-format qcow2"
|
||||
THIN=""
|
||||
;;
|
||||
DISK_EXT=".qcow2"
|
||||
DISK_REF="$VMID/"
|
||||
DISK_IMPORT="-format qcow2"
|
||||
THIN=""
|
||||
;;
|
||||
btrfs)
|
||||
DISK_EXT=".raw"
|
||||
DISK_REF="$VMID/"
|
||||
DISK_IMPORT="-format raw"
|
||||
FORMAT=",efitype=4m"
|
||||
THIN=""
|
||||
;;
|
||||
DISK_EXT=".raw"
|
||||
DISK_REF="$VMID/"
|
||||
DISK_IMPORT="-format raw"
|
||||
FORMAT=",efitype=4m"
|
||||
THIN=""
|
||||
;;
|
||||
esac
|
||||
for i in {0,1}; do
|
||||
disk="DISK$i"
|
||||
eval DISK${i}=vm-${VMID}-disk-${i}${DISK_EXT:-}
|
||||
eval DISK${i}_REF=${STORAGE}:${DISK_REF:-}${!disk}
|
||||
disk="DISK$i"
|
||||
eval DISK${i}=vm-${VMID}-disk-${i}${DISK_EXT:-}
|
||||
eval DISK${i}_REF=${STORAGE}:${DISK_REF:-}${!disk}
|
||||
done
|
||||
|
||||
msg_info "Installing Pre-Requisite libguestfs-tools onto Host"
|
||||
@ -422,41 +422,41 @@ msg_ok "Installed libguestfs-tools successfully"
|
||||
|
||||
msg_info "Adding ASL Package Repository"
|
||||
virt-customize -q -a "${FILE}" \
|
||||
--run-command "curl -fsSL https://repo.allstarlink.org/public/asl-apt-repos.deb12_all.deb -o /tmp/asl-apt-repos.deb12_all.deb" \
|
||||
--run-command "dpkg -i /tmp/asl-apt-repos.deb12_all.deb" \
|
||||
--update \
|
||||
--run-command "rm -f /tmp/asl-apt-repos.deb12_all.deb" >/dev/null
|
||||
--run-command "curl -fsSL https://repo.allstarlink.org/public/asl-apt-repos.deb12_all.deb -o /tmp/asl-apt-repos.deb12_all.deb" \
|
||||
--run-command "dpkg -i /tmp/asl-apt-repos.deb12_all.deb" \
|
||||
--update \
|
||||
--run-command "rm -f /tmp/asl-apt-repos.deb12_all.deb" >/dev/null
|
||||
msg_ok "Added ASL Package Repository"
|
||||
|
||||
msg_info "Installing AllStarLink (patience)"
|
||||
virt-customize -q -a "${FILE}" \
|
||||
--install asl3 \
|
||||
--run-command "sed -i \"/secret /s/= .*/= $(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)/\" /etc/asterisk/manager.conf" >/dev/null
|
||||
--install asl3 \
|
||||
--run-command "sed -i \"/secret /s/= .*/= $(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)/\" /etc/asterisk/manager.conf" >/dev/null
|
||||
msg_ok "Installed AllStarLink"
|
||||
|
||||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno "Would you like to add Allmon3?" 10 58); then
|
||||
msg_info "Installing Allmon3"
|
||||
virt-customize -q -a "${FILE}" \
|
||||
--install allmon3 \
|
||||
--run-command "sed -i \"s/;pass=.*/;pass=\$(sed -ne 's/^secret = //p' /etc/asterisk/manager.conf)/\" /etc/allmon3/allmon3.ini" >/dev/null
|
||||
msg_ok "Installed Allmon3"
|
||||
msg_info "Installing Allmon3"
|
||||
virt-customize -q -a "${FILE}" \
|
||||
--install allmon3 \
|
||||
--run-command "sed -i \"s/;pass=.*/;pass=\$(sed -ne 's/^secret = //p' /etc/asterisk/manager.conf)/\" /etc/allmon3/allmon3.ini" >/dev/null
|
||||
msg_ok "Installed Allmon3"
|
||||
fi
|
||||
|
||||
msg_info "Creating a AllStarLink VM"
|
||||
qm create $VMID -agent 1${MACHINE} -tablet 0 -localtime 1 -bios ovmf${CPU_TYPE} -cores $CORE_COUNT -memory $RAM_SIZE \
|
||||
-name $HN -tags community-script,debian12,radio -net0 virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU -onboot 1 -ostype l26 -scsihw virtio-scsi-pci
|
||||
-name $HN -tags community-script,debian12,radio -net0 virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU -onboot 1 -ostype l26 -scsihw virtio-scsi-pci
|
||||
pvesm alloc $STORAGE $VMID $DISK0 4M 1>&/dev/null
|
||||
qm importdisk $VMID ${FILE} $STORAGE ${DISK_IMPORT:-} 1>&/dev/null
|
||||
qm set $VMID \
|
||||
-efidisk0 ${DISK0_REF}${FORMAT} \
|
||||
-scsi0 ${DISK1_REF},${DISK_CACHE}${THIN}size=2G \
|
||||
-boot order=scsi0 \
|
||||
-serial0 socket >/dev/null
|
||||
-efidisk0 ${DISK0_REF}${FORMAT} \
|
||||
-scsi0 ${DISK1_REF},${DISK_CACHE}${THIN}size=2G \
|
||||
-boot order=scsi0 \
|
||||
-serial0 socket >/dev/null
|
||||
qm resize $VMID scsi0 8G >/dev/null
|
||||
qm set $VMID --agent enabled=1 >/dev/null
|
||||
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
|
||||
@ -489,9 +489,9 @@ qm set "$VMID" -description "$DESCRIPTION" >/dev/null
|
||||
|
||||
msg_ok "Created a AllStarLink VM ${CL}${BL}(${HN})"
|
||||
if [ "$START_VM" == "yes" ]; then
|
||||
msg_info "Starting AllStarLink VM"
|
||||
qm start $VMID
|
||||
msg_ok "Started AllStarLink VM"
|
||||
msg_info "Starting AllStarLink VM"
|
||||
qm start $VMID
|
||||
msg_ok "Started AllStarLink VM"
|
||||
fi
|
||||
post_update_to_api "done" "none"
|
||||
msg_ok "Completed Successfully!\n"
|
||||
|
||||
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