mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-03-25 03:13:01 +01:00
Compare commits
31 Commits
improve/bu
...
2026-03-24
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e4d174a65 | ||
|
|
d7112450c7 | ||
|
|
caf03fe274 | ||
|
|
e731ddf61d | ||
|
|
86f5c48fc2 | ||
|
|
d1d786cbc7 | ||
|
|
1c3c223e51 | ||
|
|
0980a85021 | ||
|
|
81547bb7a1 | ||
|
|
c62e1ba882 | ||
|
|
201a26a19e | ||
|
|
1dda554e40 | ||
|
|
6b1b255ff6 | ||
|
|
5d2fea107d | ||
|
|
86c658909a | ||
|
|
9aa0390553 | ||
|
|
c8606e9fcc | ||
|
|
283e762b83 | ||
|
|
15b5542ad6 | ||
|
|
b1604ceae0 | ||
|
|
89c205d57c | ||
|
|
5c795395ca | ||
|
|
1512711435 | ||
|
|
a2616ee258 | ||
|
|
4ce6271ec0 | ||
|
|
da932e62d0 | ||
|
|
c2838b69ce | ||
|
|
676397add0 | ||
|
|
ec7f2a2e33 | ||
|
|
e2027a43b4 | ||
|
|
f29606ae87 |
2
.github/workflows/close-tteck-issues.yaml
generated
vendored
2
.github/workflows/close-tteck-issues.yaml
generated
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
const message = `Hello, it looks like you are referencing the **old tteck repo**.
|
||||
|
||||
This repository is no longer used for active scripts.
|
||||
**Please update your bookmarks** and use: [https://helper-scripts.com](https://helper-scripts.com)
|
||||
**Please update your bookmarks** and use: [https://community-scripts.com](https://community-scripts.com)
|
||||
|
||||
Also make sure your Bash command starts with:
|
||||
\`\`\`bash
|
||||
|
||||
25
CHANGELOG.md
25
CHANGELOG.md
@@ -426,19 +426,34 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
||||
|
||||
</details>
|
||||
|
||||
## 2026-03-23
|
||||
## 2026-03-24
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Alpine-Borgbackup-Server ([#13219](https://github.com/community-scripts/ProxmoxVE/pull/13219))
|
||||
- Homebrew (Addon) ([#13249](https://github.com/community-scripts/ProxmoxVE/pull/13249))
|
||||
- NextExplorer ([#13252](https://github.com/community-scripts/ProxmoxVE/pull/13252))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- NginxProxyManager: build OpenResty from source via GitHub releases [@MickLesk](https://github.com/MickLesk) ([#13134](https://github.com/community-scripts/ProxmoxVE/pull/13134))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Kometa: optimize config.yml sed patterns, add Quickstart integration [@MickLesk](https://github.com/MickLesk) ([#13198](https://github.com/community-scripts/ProxmoxVE/pull/13198))
|
||||
- Turnkey: modernize turnkey.sh with shared libraries [@MickLesk](https://github.com/MickLesk) ([#13242](https://github.com/community-scripts/ProxmoxVE/pull/13242))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- chore: replace helper-scripts.com with community-scripts.com [@MickLesk](https://github.com/MickLesk) ([#13244](https://github.com/community-scripts/ProxmoxVE/pull/13244))
|
||||
|
||||
### 🗑️ Deleted Scripts
|
||||
|
||||
- Remove: Booklore [@MickLesk](https://github.com/MickLesk) ([#13265](https://github.com/community-scripts/ProxmoxVE/pull/13265))
|
||||
|
||||
## 2026-03-23
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- core: harden shell scripts against injection and insecure permissions [@MickLesk](https://github.com/MickLesk) ([#13239](https://github.com/community-scripts/ProxmoxVE/pull/13239))
|
||||
|
||||
## 2026-03-22
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<p><em>A Community Legacy in Memory of @tteck</em></p>
|
||||
|
||||
<p>
|
||||
<a href="https://helper-scripts.com">
|
||||
<a href="https://community-scripts.com">
|
||||
<img src="https://img.shields.io/badge/🌐_Website-Visit-4c9b3f?style=for-the-badge&labelColor=2d3748" alt="Website" />
|
||||
</a>
|
||||
<a href="https://discord.gg/3AnUqsXnmK">
|
||||
|
||||
113
ct/booklore.sh
113
ct/booklore.sh
@@ -1,113 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/booklore-app/BookLore
|
||||
|
||||
APP="BookLore"
|
||||
var_tags="${var_tags:-books;library}"
|
||||
var_cpu="${var_cpu:-3}"
|
||||
var_ram="${var_ram:-3072}"
|
||||
var_disk="${var_disk:-7}"
|
||||
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/booklore ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "booklore" "booklore-app/BookLore"; then
|
||||
JAVA_VERSION="25" setup_java
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
setup_mariadb
|
||||
setup_yq
|
||||
ensure_dependencies ffmpeg
|
||||
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop booklore
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
if grep -qE "^BOOKLORE_(DATA_PATH|BOOKDROP_PATH|BOOKS_PATH|PORT)=" /opt/booklore_storage/.env 2>/dev/null; then
|
||||
msg_info "Migrating old environment variables"
|
||||
sed -i 's/^BOOKLORE_DATA_PATH=/APP_PATH_CONFIG=/g' /opt/booklore_storage/.env
|
||||
sed -i 's/^BOOKLORE_BOOKDROP_PATH=/APP_BOOKDROP_FOLDER=/g' /opt/booklore_storage/.env
|
||||
sed -i '/^BOOKLORE_BOOKS_PATH=/d' /opt/booklore_storage/.env
|
||||
sed -i '/^BOOKLORE_PORT=/d' /opt/booklore_storage/.env
|
||||
msg_ok "Migrated old environment variables"
|
||||
fi
|
||||
|
||||
msg_info "Backing up old installation"
|
||||
mv /opt/booklore /opt/booklore_bak
|
||||
msg_ok "Backed up old installation"
|
||||
|
||||
fetch_and_deploy_gh_release "booklore" "booklore-app/BookLore" "tarball"
|
||||
|
||||
msg_info "Building Frontend"
|
||||
cd /opt/booklore/booklore-ui
|
||||
$STD npm install --force
|
||||
$STD npm run build --configuration=production
|
||||
msg_ok "Built Frontend"
|
||||
|
||||
msg_info "Embedding Frontend into Backend"
|
||||
mkdir -p /opt/booklore/booklore-api/src/main/resources/static
|
||||
cp -r /opt/booklore/booklore-ui/dist/booklore/browser/* /opt/booklore/booklore-api/src/main/resources/static/
|
||||
msg_ok "Embedded Frontend into Backend"
|
||||
|
||||
msg_info "Building Backend"
|
||||
cd /opt/booklore/booklore-api
|
||||
APP_VERSION=$(get_latest_github_release "booklore-app/BookLore")
|
||||
yq eval ".app.version = \"${APP_VERSION}\"" -i src/main/resources/application.yaml
|
||||
$STD ./gradlew clean build -x test --no-daemon
|
||||
mkdir -p /opt/booklore/dist
|
||||
JAR_PATH=$(find /opt/booklore/booklore-api/build/libs -maxdepth 1 -type f -name "booklore-api-*.jar" ! -name "*plain*" | head -n1)
|
||||
if [[ -z "$JAR_PATH" ]]; then
|
||||
msg_error "Backend JAR not found"
|
||||
exit
|
||||
fi
|
||||
cp "$JAR_PATH" /opt/booklore/dist/app.jar
|
||||
msg_ok "Built Backend"
|
||||
|
||||
if systemctl is-active --quiet nginx 2>/dev/null; then
|
||||
msg_info "Removing Nginx (no longer needed)"
|
||||
systemctl disable --now nginx
|
||||
$STD apt-get purge -y nginx nginx-common
|
||||
msg_ok "Removed Nginx"
|
||||
fi
|
||||
|
||||
if ! grep -q "^SERVER_PORT=" /opt/booklore_storage/.env 2>/dev/null; then
|
||||
echo "SERVER_PORT=6060" >>/opt/booklore_storage/.env
|
||||
fi
|
||||
|
||||
sed -i 's|ExecStart=.*|ExecStart=/usr/bin/java -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+UseCompactObjectHeaders -XX:MaxRAMPercentage=75.0 -XX:+ExitOnOutOfMemoryError -jar /opt/booklore/dist/app.jar|' /etc/systemd/system/booklore.service
|
||||
systemctl daemon-reload
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start booklore
|
||||
rm -rf /opt/booklore_bak
|
||||
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}:6060${CL}"
|
||||
@@ -1,6 +0,0 @@
|
||||
____ __ __
|
||||
/ __ )____ ____ / /__/ / ____ ________
|
||||
/ __ / __ \/ __ \/ //_/ / / __ \/ ___/ _ \
|
||||
/ /_/ / /_/ / /_/ / ,< / /___/ /_/ / / / __/
|
||||
/_____/\____/\____/_/|_/_____/\____/_/ \___/
|
||||
|
||||
6
ct/headers/nextexplorer
Normal file
6
ct/headers/nextexplorer
Normal file
@@ -0,0 +1,6 @@
|
||||
__ ______ __
|
||||
____ ___ _ __/ /_/ ____/ ______ / /___ ________ _____
|
||||
/ __ \/ _ \| |/_/ __/ __/ | |/_/ __ \/ / __ \/ ___/ _ \/ ___/
|
||||
/ / / / __/> </ /_/ /____> </ /_/ / / /_/ / / / __/ /
|
||||
/_/ /_/\___/_/|_|\__/_____/_/|_/ .___/_/\____/_/ \___/_/
|
||||
/_/
|
||||
@@ -73,7 +73,7 @@ function update_script() {
|
||||
$STD curl -fsSL https://github.com/filebrowser/filebrowser/releases/download/v2.23.0/linux-amd64-filebrowser.tar.gz | tar -xzv -C /usr/local/bin
|
||||
$STD filebrowser config init -a '0.0.0.0'
|
||||
$STD filebrowser config set -a '0.0.0.0'
|
||||
$STD filebrowser users add admin helper-scripts.com --perm.admin
|
||||
$STD filebrowser users add admin community-scripts.com --perm.admin
|
||||
msg_ok "Installed FileBrowser"
|
||||
|
||||
msg_info "Creating Service"
|
||||
@@ -93,7 +93,7 @@ WantedBy=default.target" >$service_path
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "FileBrowser should be reachable by going to the following URL.
|
||||
${BL}http://$LOCAL_IP:8080${CL} admin|helper-scripts.com\n"
|
||||
${BL}http://$LOCAL_IP:8080${CL} admin|community-scripts.com\n"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
76
ct/nextexplorer.sh
Normal file
76
ct/nextexplorer.sh
Normal file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: vhsdream
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/nxzai/nextExplorer
|
||||
|
||||
APP="nextExplorer"
|
||||
var_tags="${var_tags:-files;documents}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-3072}"
|
||||
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/nextExplorer ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
|
||||
if check_for_gh_release "nextExplorer" "nxzai/nextExplorer"; then
|
||||
msg_info "Stopping nextExplorer"
|
||||
$STD systemctl stop nextexplorer
|
||||
msg_ok "Stopped nextExplorer"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "nextExplorer" "nxzai/nextExplorer" "tarball" "latest" "/opt/nextExplorer"
|
||||
|
||||
msg_info "Updating nextExplorer"
|
||||
APP_DIR="/opt/nextExplorer/app"
|
||||
mkdir -p "$APP_DIR"
|
||||
cd /opt/nextExplorer
|
||||
export NODE_ENV=production
|
||||
$STD npm ci --omit=dev --workspace backend
|
||||
mv node_modules "$APP_DIR"
|
||||
mv backend/{src,package.json} "$APP_DIR"
|
||||
unset NODE_ENV
|
||||
export NODE_ENV=development
|
||||
$STD npm ci --workspace frontend
|
||||
$STD npm run -w frontend build -- --sourcemap false
|
||||
unset NODE_ENV
|
||||
mv frontend/dist/ "$APP_DIR"/src/public
|
||||
chown -R explorer:explorer "$APP_DIR" /etc/nextExplorer
|
||||
sed -i "\|version|s|$(jq -cr '.version' ${APP_DIR}/package.json)|$(cat ~/.nextexplorer)|" "$APP_DIR"/package.json
|
||||
sed -i 's/app.js/server.js/' /etc/systemd/system/nextexplorer.service && systemctl daemon-reload
|
||||
msg_ok "Updated nextExplorer"
|
||||
|
||||
msg_info "Starting nextExplorer"
|
||||
$STD systemctl start nextexplorer
|
||||
msg_ok "Started nextExplorer"
|
||||
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}"
|
||||
@@ -49,41 +49,25 @@ function update_script() {
|
||||
|
||||
NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs
|
||||
|
||||
RELEASE=$(get_latest_github_release "NginxProxyManager/nginx-proxy-manager")
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "nginxproxymanager" "NginxProxyManager/nginx-proxy-manager" "tarball" "v${RELEASE}" "/opt/nginxproxymanager"
|
||||
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop openresty
|
||||
systemctl stop npm
|
||||
msg_ok "Stopped Services"
|
||||
|
||||
msg_info "Cleaning old files"
|
||||
$STD rm -rf /app \
|
||||
/var/www/html \
|
||||
/etc/nginx \
|
||||
/var/log/nginx \
|
||||
/var/lib/nginx \
|
||||
/var/cache/nginx
|
||||
msg_ok "Cleaned old files"
|
||||
|
||||
msg_info "Migrating to OpenResty from source"
|
||||
rm -f /etc/apt/trusted.gpg.d/openresty-archive-keyring.gpg /etc/apt/trusted.gpg.d/openresty.gpg
|
||||
rm -f /etc/apt/sources.list.d/openresty.list /etc/apt/sources.list.d/openresty.sources
|
||||
if dpkg -l openresty &>/dev/null; then
|
||||
if dpkg -s openresty &>/dev/null 2>&1; then
|
||||
msg_info "Migrating from packaged OpenResty to source"
|
||||
rm -f /etc/apt/trusted.gpg.d/openresty-archive-keyring.gpg /etc/apt/trusted.gpg.d/openresty.gpg
|
||||
rm -f /etc/apt/sources.list.d/openresty.list /etc/apt/sources.list.d/openresty.sources
|
||||
$STD apt remove -y openresty
|
||||
$STD apt autoremove -y
|
||||
rm -f ~/.openresty
|
||||
msg_ok "Migrated from packaged OpenResty to source"
|
||||
fi
|
||||
|
||||
local pcre_pkg="libpcre3-dev"
|
||||
if grep -qE 'VERSION_ID="1[3-9]"' /etc/os-release 2>/dev/null; then
|
||||
pcre_pkg="libpcre2-dev"
|
||||
fi
|
||||
$STD apt install -y build-essential "$pcre_pkg" libssl-dev zlib1g-dev
|
||||
msg_ok "Migrated to OpenResty from source"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "openresty" "openresty/openresty" "prebuild" "latest" "/opt/openresty" "openresty-*.tar.gz"
|
||||
if check_for_gh_release "openresty" "openresty/openresty"; then
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "openresty" "openresty/openresty" "prebuild" "${CHECK_UPDATE_RELEASE}" "/opt/openresty" "openresty-*.tar.gz"
|
||||
|
||||
if [[ -d /opt/openresty ]]; then
|
||||
msg_info "Building OpenResty"
|
||||
cd /opt/openresty
|
||||
$STD ./configure \
|
||||
@@ -114,75 +98,101 @@ ExecStart=/usr/local/openresty/nginx/sbin/nginx -g 'daemon off;'
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl restart openresty
|
||||
msg_ok "Built OpenResty"
|
||||
fi
|
||||
|
||||
msg_info "Setting up Environment"
|
||||
ln -sf /usr/bin/python3 /usr/bin/python
|
||||
ln -sf /usr/local/openresty/nginx/sbin/nginx /usr/sbin/nginx
|
||||
ln -sf /usr/local/openresty/nginx/ /etc/nginx
|
||||
sed -i "0,/\"version\": \"[^\"]*\"/s|\"version\": \"[^\"]*\"|\"version\": \"$RELEASE\"|" /opt/nginxproxymanager/backend/package.json
|
||||
sed -i "0,/\"version\": \"[^\"]*\"/s|\"version\": \"[^\"]*\"|\"version\": \"$RELEASE\"|" /opt/nginxproxymanager/frontend/package.json
|
||||
sed -i 's+^daemon+#daemon+g' /opt/nginxproxymanager/docker/rootfs/etc/nginx/nginx.conf
|
||||
NGINX_CONFS=$(find /opt/nginxproxymanager -type f -name "*.conf")
|
||||
for NGINX_CONF in $NGINX_CONFS; do
|
||||
sed -i 's+include conf.d+include /etc/nginx/conf.d+g' "$NGINX_CONF"
|
||||
done
|
||||
|
||||
mkdir -p /var/www/html /etc/nginx/logs
|
||||
cp -r /opt/nginxproxymanager/docker/rootfs/var/www/html/* /var/www/html/
|
||||
cp -r /opt/nginxproxymanager/docker/rootfs/etc/nginx/* /etc/nginx/
|
||||
cp /opt/nginxproxymanager/docker/rootfs/etc/letsencrypt.ini /etc/letsencrypt.ini
|
||||
cp /opt/nginxproxymanager/docker/rootfs/etc/logrotate.d/nginx-proxy-manager /etc/logrotate.d/nginx-proxy-manager
|
||||
ln -sf /etc/nginx/nginx.conf /etc/nginx/conf/nginx.conf
|
||||
rm -f /etc/nginx/conf.d/dev.conf
|
||||
|
||||
mkdir -p /tmp/nginx/body \
|
||||
/run/nginx \
|
||||
/data/nginx \
|
||||
/data/custom_ssl \
|
||||
/data/logs \
|
||||
/data/access \
|
||||
/data/nginx/default_host \
|
||||
/data/nginx/default_www \
|
||||
/data/nginx/proxy_host \
|
||||
/data/nginx/redirection_host \
|
||||
/data/nginx/stream \
|
||||
/data/nginx/dead_host \
|
||||
/data/nginx/temp \
|
||||
/var/lib/nginx/cache/public \
|
||||
/var/lib/nginx/cache/private \
|
||||
/var/cache/nginx/proxy_temp
|
||||
|
||||
chmod -R 777 /var/cache/nginx
|
||||
chown root /tmp/nginx
|
||||
|
||||
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" {print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf);" >/etc/nginx/conf.d/include/resolvers.conf
|
||||
|
||||
if [ ! -f /data/nginx/dummycert.pem ] || [ ! -f /data/nginx/dummykey.pem ]; then
|
||||
$STD openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj "/O=Nginx Proxy Manager/OU=Dummy Certificate/CN=localhost" -keyout /data/nginx/dummykey.pem -out /data/nginx/dummycert.pem
|
||||
cd /root
|
||||
if [ -d /opt/certbot ]; then
|
||||
msg_info "Updating Certbot"
|
||||
$STD /opt/certbot/bin/pip install --upgrade pip setuptools wheel
|
||||
$STD /opt/certbot/bin/pip install --upgrade certbot certbot-dns-cloudflare
|
||||
msg_ok "Updated Certbot"
|
||||
fi
|
||||
|
||||
mkdir -p /app/frontend/images
|
||||
cp -r /opt/nginxproxymanager/backend/* /app
|
||||
msg_ok "Set up Environment"
|
||||
if check_for_gh_release "nginxproxymanager" "NginxProxyManager/nginx-proxy-manager"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop openresty
|
||||
systemctl stop npm
|
||||
msg_ok "Stopped Services"
|
||||
|
||||
msg_info "Building Frontend"
|
||||
export NODE_OPTIONS="--max_old_space_size=2048 --openssl-legacy-provider"
|
||||
cd /opt/nginxproxymanager/frontend
|
||||
# Replace node-sass with sass in package.json before installation
|
||||
sed -E -i 's/"node-sass" *: *"([^"]*)"/"sass": "\1"/g' package.json
|
||||
$STD yarn install --network-timeout 600000
|
||||
$STD yarn locale-compile
|
||||
$STD yarn build
|
||||
cp -r /opt/nginxproxymanager/frontend/dist/* /app/frontend
|
||||
cp -r /opt/nginxproxymanager/frontend/public/images/* /app/frontend/images
|
||||
msg_ok "Built Frontend"
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "nginxproxymanager" "NginxProxyManager/nginx-proxy-manager" "tarball" "${CHECK_UPDATE_RELEASE}" "/opt/nginxproxymanager"
|
||||
|
||||
msg_info "Initializing Backend"
|
||||
rm -rf /app/config/default.json
|
||||
if [ ! -f /app/config/production.json ]; then
|
||||
cat <<'EOF' >/app/config/production.json
|
||||
msg_info "Cleaning old files"
|
||||
$STD rm -rf /app \
|
||||
/var/www/html \
|
||||
/etc/nginx \
|
||||
/var/log/nginx \
|
||||
/var/lib/nginx \
|
||||
/var/cache/nginx
|
||||
msg_ok "Cleaned old files"
|
||||
|
||||
local RELEASE="${CHECK_UPDATE_RELEASE#v}"
|
||||
msg_info "Setting up Environment"
|
||||
ln -sf /usr/bin/python3 /usr/bin/python
|
||||
ln -sf /usr/local/openresty/nginx/sbin/nginx /usr/sbin/nginx
|
||||
ln -sf /usr/local/openresty/nginx/ /etc/nginx
|
||||
sed -i "0,/\"version\": \"[^\"]*\"/s|\"version\": \"[^\"]*\"|\"version\": \"$RELEASE\"|" /opt/nginxproxymanager/backend/package.json
|
||||
sed -i "0,/\"version\": \"[^\"]*\"/s|\"version\": \"[^\"]*\"|\"version\": \"$RELEASE\"|" /opt/nginxproxymanager/frontend/package.json
|
||||
sed -i 's+^daemon+#daemon+g' /opt/nginxproxymanager/docker/rootfs/etc/nginx/nginx.conf
|
||||
NGINX_CONFS=$(find /opt/nginxproxymanager -type f -name "*.conf")
|
||||
for NGINX_CONF in $NGINX_CONFS; do
|
||||
sed -i 's+include conf.d+include /etc/nginx/conf.d+g' "$NGINX_CONF"
|
||||
done
|
||||
|
||||
mkdir -p /var/www/html /etc/nginx/logs
|
||||
cp -r /opt/nginxproxymanager/docker/rootfs/var/www/html/* /var/www/html/
|
||||
cp -r /opt/nginxproxymanager/docker/rootfs/etc/nginx/* /etc/nginx/
|
||||
cp /opt/nginxproxymanager/docker/rootfs/etc/letsencrypt.ini /etc/letsencrypt.ini
|
||||
cp /opt/nginxproxymanager/docker/rootfs/etc/logrotate.d/nginx-proxy-manager /etc/logrotate.d/nginx-proxy-manager
|
||||
ln -sf /etc/nginx/nginx.conf /etc/nginx/conf/nginx.conf
|
||||
rm -f /etc/nginx/conf.d/dev.conf
|
||||
|
||||
mkdir -p /tmp/nginx/body \
|
||||
/run/nginx \
|
||||
/data/nginx \
|
||||
/data/custom_ssl \
|
||||
/data/logs \
|
||||
/data/access \
|
||||
/data/nginx/default_host \
|
||||
/data/nginx/default_www \
|
||||
/data/nginx/proxy_host \
|
||||
/data/nginx/redirection_host \
|
||||
/data/nginx/stream \
|
||||
/data/nginx/dead_host \
|
||||
/data/nginx/temp \
|
||||
/var/lib/nginx/cache/public \
|
||||
/var/lib/nginx/cache/private \
|
||||
/var/cache/nginx/proxy_temp
|
||||
|
||||
chmod -R 777 /var/cache/nginx
|
||||
chown root /tmp/nginx
|
||||
|
||||
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" {print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf);" >/etc/nginx/conf.d/include/resolvers.conf
|
||||
|
||||
if [ ! -f /data/nginx/dummycert.pem ] || [ ! -f /data/nginx/dummykey.pem ]; then
|
||||
$STD openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj "/O=Nginx Proxy Manager/OU=Dummy Certificate/CN=localhost" -keyout /data/nginx/dummykey.pem -out /data/nginx/dummycert.pem
|
||||
fi
|
||||
|
||||
mkdir -p /app/frontend/images
|
||||
cp -r /opt/nginxproxymanager/backend/* /app
|
||||
msg_ok "Set up Environment"
|
||||
|
||||
msg_info "Building Frontend"
|
||||
export NODE_OPTIONS="--max_old_space_size=2048 --openssl-legacy-provider"
|
||||
cd /opt/nginxproxymanager/frontend
|
||||
sed -E -i 's/"node-sass" *: *"([^"]*)"/"sass": "\1"/g' package.json
|
||||
$STD yarn install --network-timeout 600000
|
||||
$STD yarn locale-compile
|
||||
$STD yarn build
|
||||
cp -r /opt/nginxproxymanager/frontend/dist/* /app/frontend
|
||||
cp -r /opt/nginxproxymanager/frontend/public/images/* /app/frontend/images
|
||||
msg_ok "Built Frontend"
|
||||
|
||||
msg_info "Initializing Backend"
|
||||
rm -rf /app/config/default.json
|
||||
if [ ! -f /app/config/production.json ]; then
|
||||
cat <<'EOF' >/app/config/production.json
|
||||
{
|
||||
"database": {
|
||||
"engine": "knex-native",
|
||||
@@ -196,28 +206,21 @@ EOF
|
||||
}
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
sed -i 's/"client": "sqlite3"/"client": "better-sqlite3"/' /app/config/production.json
|
||||
cd /app
|
||||
$STD yarn install --network-timeout 600000
|
||||
msg_ok "Initialized Backend"
|
||||
|
||||
msg_info "Starting Services"
|
||||
sed -i 's/user npm/user root/g; s/^pid/#pid/g' /usr/local/openresty/nginx/conf/nginx.conf
|
||||
sed -r -i 's/^([[:space:]]*)su npm npm/\1#su npm npm/g;' /etc/logrotate.d/nginx-proxy-manager
|
||||
systemctl daemon-reload
|
||||
systemctl enable -q --now openresty
|
||||
systemctl enable -q --now npm
|
||||
msg_ok "Started Services"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
sed -i 's/"client": "sqlite3"/"client": "better-sqlite3"/' /app/config/production.json
|
||||
cd /app
|
||||
$STD yarn install --network-timeout 600000
|
||||
msg_ok "Initialized Backend"
|
||||
|
||||
msg_info "Updating Certbot"
|
||||
if [ -d /opt/certbot ]; then
|
||||
$STD /opt/certbot/bin/pip install --upgrade pip setuptools wheel
|
||||
$STD /opt/certbot/bin/pip install --upgrade certbot certbot-dns-cloudflare
|
||||
fi
|
||||
msg_ok "Updated Certbot"
|
||||
|
||||
msg_info "Starting Services"
|
||||
sed -i 's/user npm/user root/g; s/^pid/#pid/g' /usr/local/openresty/nginx/conf/nginx.conf
|
||||
sed -r -i 's/^([[:space:]]*)su npm npm/\1#su npm npm/g;' /etc/logrotate.d/nginx-proxy-manager
|
||||
systemctl daemon-reload
|
||||
systemctl enable -q --now openresty
|
||||
systemctl enable -q --now npm
|
||||
msg_ok "Started Services"
|
||||
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
}
|
||||
|
||||
|
||||
@@ -27,36 +27,27 @@ function update_script() {
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
RELEASE=$(get_latest_github_release "Part-DB/Part-DB-server")
|
||||
|
||||
if check_for_gh_release "partdb" "Part-DB/Part-DB-server"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop apache2
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Updating $APP to v${RELEASE}"
|
||||
cd /opt
|
||||
mv /opt/partdb/ /opt/partdb-backup
|
||||
curl -fsSL "https://github.com/Part-DB/Part-DB-server/archive/refs/tags/v${RELEASE}.zip" -o "/opt/v${RELEASE}.zip"
|
||||
$STD unzip "v${RELEASE}.zip"
|
||||
mv /opt/Part-DB-server-${RELEASE}/ /opt/partdb
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "partdb" "Part-DB/Part-DB-server" "prebuild" "latest" "/opt/partdb" "partdb_with_assets.zip"
|
||||
|
||||
msg_info "Updating Part-DB"
|
||||
cd /opt/partdb/
|
||||
cp -r "/opt/partdb-backup/.env.local" /opt/partdb/
|
||||
cp -r "/opt/partdb-backup/public/media" /opt/partdb/public/
|
||||
cp -r "/opt/partdb-backup/config/banner.md" /opt/partdb/config/
|
||||
|
||||
cp -r /opt/partdb-backup/.env.local /opt/partdb/
|
||||
cp -r /opt/partdb-backup/public/media /opt/partdb/public/
|
||||
cp -r /opt/partdb-backup/config/banner.md /opt/partdb/config/
|
||||
export COMPOSER_ALLOW_SUPERUSER=1
|
||||
$STD composer install --no-dev -o --no-interaction
|
||||
$STD yarn install
|
||||
$STD yarn build
|
||||
$STD php bin/console cache:clear
|
||||
$STD php bin/console doctrine:migrations:migrate -n
|
||||
chown -R www-data:www-data /opt/partdb
|
||||
rm -r "/opt/v${RELEASE}.zip"
|
||||
rm -r /opt/partdb-backup
|
||||
echo "${RELEASE}" >~/.partdb
|
||||
msg_ok "Updated $APP to v${RELEASE}"
|
||||
msg_ok "Updated Part-DB"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start apache2
|
||||
|
||||
@@ -68,7 +68,7 @@ function update_script() {
|
||||
$STD curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash
|
||||
$STD filebrowser config init -a '0.0.0.0'
|
||||
$STD filebrowser config set -a '0.0.0.0'
|
||||
$STD filebrowser users add admin helper-scripts.com --perm.admin
|
||||
$STD filebrowser users add admin community-scripts.com --perm.admin
|
||||
msg_ok "Installed FileBrowser"
|
||||
|
||||
msg_info "Creating Service"
|
||||
@@ -90,7 +90,7 @@ EOF
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "FileBrowser should be reachable by going to the following URL.
|
||||
${BL}http://$LOCAL_IP:8080${CL} admin|helper-scripts.com\n"
|
||||
${BL}http://$LOCAL_IP:8080${CL} admin|community-scripts.com\n"
|
||||
exit
|
||||
fi
|
||||
if [ "$UPD" == "4" ]; then
|
||||
|
||||
@@ -50,7 +50,7 @@ function update_script() {
|
||||
/opt/semaphore/config.json
|
||||
SEM_PW=$(cat ~/semaphore.creds)
|
||||
systemctl start semaphore
|
||||
$STD semaphore user add --admin --login admin --email admin@helper-scripts.com --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json
|
||||
$STD semaphore user add --admin --login admin --email admin@community-scripts.com --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json
|
||||
|
||||
msg_ok "Moved from BoltDB to SQLite"
|
||||
fi
|
||||
|
||||
@@ -8,7 +8,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
||||
APP="Tracearr"
|
||||
var_tags="${var_tags:-media}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-4096}"
|
||||
var_ram="${var_ram:-8192}"
|
||||
var_disk="${var_disk:-10}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
@@ -102,7 +102,7 @@ EOF
|
||||
|
||||
if check_for_gh_release "tracearr" "connorgallopo/Tracearr"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop tracearr postgresql redis
|
||||
systemctl stop tracearr postgresql redis-server
|
||||
msg_ok "Stopped Services"
|
||||
|
||||
msg_info "Updating pnpm"
|
||||
@@ -115,6 +115,7 @@ EOF
|
||||
|
||||
msg_info "Building Tracearr"
|
||||
export TZ=$(cat /etc/timezone)
|
||||
export NODE_OPTIONS="--max-old-space-size=4096"
|
||||
cd /opt/tracearr.build
|
||||
$STD pnpm install --frozen-lockfile --force
|
||||
$STD pnpm turbo telemetry disable
|
||||
@@ -148,7 +149,7 @@ EOF
|
||||
msg_ok "Configured Tracearr"
|
||||
|
||||
msg_info "Starting services"
|
||||
systemctl start postgresql redis tracearr
|
||||
systemctl start postgresql redis-server tracearr
|
||||
msg_ok "Started services"
|
||||
msg_ok "Updated successfully!"
|
||||
else
|
||||
|
||||
@@ -62,10 +62,10 @@ expect "Email address"
|
||||
send "\r"
|
||||
|
||||
expect "Password"
|
||||
send "helper-scripts.com\r"
|
||||
send "community-scripts.com\r"
|
||||
|
||||
expect "Password (again)"
|
||||
send "helper-scripts.com\r"
|
||||
send "community-scripts.com\r"
|
||||
|
||||
expect eof
|
||||
EOF
|
||||
|
||||
@@ -58,7 +58,7 @@ service:
|
||||
use_prerelease: false
|
||||
dashboard:
|
||||
icon: https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/images/logo.png
|
||||
icon_link_to: https://helper-scripts.com/
|
||||
icon_link_to: https://community-scripts.com/
|
||||
web_url: https://github.com/community-scripts/ProxmoxVE/releases
|
||||
EOF
|
||||
msg_ok "Setup Config"
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/booklore-app/BookLore
|
||||
|
||||
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 ffmpeg
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
JAVA_VERSION="25" setup_java
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
setup_mariadb
|
||||
setup_yq
|
||||
MARIADB_DB_NAME="booklore_db" MARIADB_DB_USER="booklore_user" MARIADB_DB_EXTRA_GRANTS="GRANT SELECT ON \`mysql\`.\`time_zone_name\`" setup_mariadb_db
|
||||
fetch_and_deploy_gh_release "booklore" "booklore-app/BookLore" "tarball"
|
||||
|
||||
msg_info "Building Frontend"
|
||||
cd /opt/booklore/booklore-ui
|
||||
$STD npm install --force
|
||||
$STD npm run build --configuration=production
|
||||
msg_ok "Built Frontend"
|
||||
|
||||
msg_info "Embedding Frontend into Backend"
|
||||
mkdir -p /opt/booklore/booklore-api/src/main/resources/static
|
||||
cp -r /opt/booklore/booklore-ui/dist/booklore/browser/* /opt/booklore/booklore-api/src/main/resources/static/
|
||||
msg_ok "Embedded Frontend into Backend"
|
||||
|
||||
msg_info "Creating Environment"
|
||||
mkdir -p /opt/booklore_storage/{data,books,bookdrop}
|
||||
cat <<EOF >/opt/booklore_storage/.env
|
||||
# Database Configuration
|
||||
DATABASE_URL=jdbc:mariadb://localhost:3306/${MARIADB_DB_NAME}
|
||||
DATABASE_USERNAME=${MARIADB_DB_USER}
|
||||
DATABASE_PASSWORD=${MARIADB_DB_PASS}
|
||||
|
||||
# App Configuration (Spring Boot mapping from app.* properties)
|
||||
APP_PATH_CONFIG=/opt/booklore_storage/data
|
||||
APP_BOOKDROP_FOLDER=/opt/booklore_storage/bookdrop
|
||||
SERVER_PORT=6060
|
||||
EOF
|
||||
msg_ok "Created Environment"
|
||||
|
||||
msg_info "Building Backend"
|
||||
cd /opt/booklore/booklore-api
|
||||
APP_VERSION=$(get_latest_github_release "booklore-app/BookLore")
|
||||
yq eval ".app.version = \"${APP_VERSION}\"" -i src/main/resources/application.yaml
|
||||
$STD ./gradlew clean build -x test --no-daemon
|
||||
mkdir -p /opt/booklore/dist
|
||||
JAR_PATH=$(find /opt/booklore/booklore-api/build/libs -maxdepth 1 -type f -name "booklore-api-*.jar" ! -name "*plain*" | head -n1)
|
||||
if [[ -z "$JAR_PATH" ]]; then
|
||||
msg_error "Backend JAR not found"
|
||||
exit 153
|
||||
fi
|
||||
cp "$JAR_PATH" /opt/booklore/dist/app.jar
|
||||
msg_ok "Built Backend"
|
||||
|
||||
msg_info "Creating Service"
|
||||
cat <<EOF >/etc/systemd/system/booklore.service
|
||||
[Unit]
|
||||
Description=BookLore Java Service
|
||||
After=network.target mariadb.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/opt/booklore/dist
|
||||
ExecStart=/usr/bin/java -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+UseCompactObjectHeaders -XX:MaxRAMPercentage=75.0 -XX:+ExitOnOutOfMemoryError -jar /opt/booklore/dist/app.jar
|
||||
EnvironmentFile=/opt/booklore_storage/.env
|
||||
SuccessExitStatus=143
|
||||
TimeoutStopSec=10
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl enable -q --now booklore
|
||||
msg_ok "Created Service"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
@@ -35,7 +35,7 @@ PG_DB_NAME="healthchecks_db" PG_DB_USER="hc_user" PG_DB_PASS=$(openssl rand -bas
|
||||
|
||||
msg_info "Setup Keys (Admin / Secret)"
|
||||
SECRET_KEY="$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | cut -c1-32)"
|
||||
ADMIN_EMAIL="admin@helper-scripts.local"
|
||||
ADMIN_EMAIL="admin@community-scripts.com"
|
||||
ADMIN_PASSWORD="$PG_DB_PASS"
|
||||
{
|
||||
echo "healthchecks Admin Email: $ADMIN_EMAIL"
|
||||
|
||||
@@ -17,7 +17,7 @@ fetch_and_deploy_gh_release "inspircd" "inspircd/inspircd" "binary" "latest" "/o
|
||||
|
||||
msg_info "Configuring InspIRCd"
|
||||
cat <<EOF >/etc/inspircd/inspircd.conf
|
||||
<define name="networkDomain" value="helper-scripts.com">
|
||||
<define name="networkDomain" value="community-scripts.com">
|
||||
<define name="networkName" value="Proxmox VE Helper-Scripts">
|
||||
|
||||
<server
|
||||
|
||||
@@ -55,10 +55,10 @@ $STD expect <<EOF
|
||||
set timeout -1
|
||||
log_user 0
|
||||
|
||||
spawn bin/console kimai:user:create admin admin@helper-scripts.com ROLE_SUPER_ADMIN
|
||||
spawn bin/console kimai:user:create admin admin@community-scripts.com ROLE_SUPER_ADMIN
|
||||
|
||||
expect "Please enter the password:"
|
||||
send "helper-scripts.com\r"
|
||||
send "community-scripts.com\r"
|
||||
|
||||
expect eof
|
||||
EOF
|
||||
|
||||
@@ -35,7 +35,7 @@ fetch_and_deploy_gh_release "kometa-quickstart" "Kometa-Team/Quickstart" "tarbal
|
||||
msg_info "Installing Kometa Quickstart"
|
||||
cd /opt/kometa-quickstart
|
||||
$STD uv venv /opt/kometa-quickstart/.venv
|
||||
$STD /opt/kometa-quickstart/.venv/bin/python -m pip install -r requirements.txt
|
||||
$STD uv pip install -r requirements.txt -p /opt/kometa-quickstart/.venv/bin/python
|
||||
msg_ok "Installed Kometa Quickstart"
|
||||
|
||||
msg_info "Creating Service"
|
||||
|
||||
@@ -33,7 +33,7 @@ $STD yarn config set ignore-engines true
|
||||
$STD yarn install
|
||||
$STD yarn run production
|
||||
$STD php artisan key:generate
|
||||
$STD php artisan setup:production --email=admin@helper-scripts.com --password=helper-scripts.com --force
|
||||
$STD php artisan setup:production --email=admin@community-scripts.com --password=community-scripts.com --force
|
||||
chown -R www-data:www-data /opt/monica
|
||||
chmod -R 775 /opt/monica/storage
|
||||
echo "* * * * * root php /opt/monica/artisan schedule:run >> /dev/null 2>&1" >>/etc/crontab
|
||||
|
||||
164
install/nextexplorer-install.sh
Normal file
164
install/nextexplorer-install.sh
Normal file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: vhsdream
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/nxzai/nextExplorer
|
||||
|
||||
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 \
|
||||
ripgrep \
|
||||
imagemagick \
|
||||
ffmpeg \
|
||||
libva-drm2 \
|
||||
libva2 \
|
||||
mesa-va-drivers \
|
||||
vainfo
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
|
||||
fetch_and_deploy_gh_release "nextExplorer" "nxzai/nextExplorer" "tarball" "latest" "/opt/nextExplorer"
|
||||
|
||||
msg_info "Building nextExplorer"
|
||||
APP_DIR="/opt/nextExplorer/app"
|
||||
LOCAL_IP="$(hostname -I | awk '{print $1}')"
|
||||
mkdir -p "$APP_DIR"
|
||||
mkdir -p /etc/nextExplorer
|
||||
cd /opt/nextExplorer
|
||||
export NODE_ENV=production
|
||||
$STD npm ci --omit=dev --workspace backend
|
||||
mv node_modules "$APP_DIR"
|
||||
mv backend/{src,package.json} "$APP_DIR"
|
||||
unset NODE_ENV
|
||||
|
||||
export NODE_ENV=development
|
||||
export NODE_OPTIONS="--max-old-space-size=2048"
|
||||
$STD npm ci --workspace frontend
|
||||
$STD npm run -w frontend build -- --sourcemap false
|
||||
unset NODE_ENV
|
||||
mv frontend/dist/ "$APP_DIR"/src/public
|
||||
msg_ok "Built nextExplorer"
|
||||
|
||||
msg_info "Configuring nextExplorer"
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
cat <<EOF >/etc/nextExplorer/.env
|
||||
NODE_ENV=production
|
||||
PORT=3000
|
||||
|
||||
VOLUME_ROOT=/mnt
|
||||
CONFIG_DIR=/etc/nextExplorer
|
||||
CACHE_DIR=/etc/nextExplorer/cache
|
||||
# USER_ROOT=
|
||||
|
||||
PUBLIC_URL=${LOCAL_IP}:3000
|
||||
# TRUST_PROXY=
|
||||
# CORS_ORIGINS=
|
||||
|
||||
TERMINAL_ENABLED=false
|
||||
|
||||
LOG_LEVEL=info
|
||||
DEBUG=false
|
||||
ENABLE_HTTP_LOGGING=false
|
||||
|
||||
AUTH_ENABLED=true
|
||||
AUTH_MODE=both
|
||||
SESSION_SECRET="${SECRET}"
|
||||
# AUTH_MAX_FAILED=
|
||||
# AUTH_LOCK_MINUTES=
|
||||
# AUTH_USER_EMAIL=
|
||||
# AUTH_USER_PASSWORD=
|
||||
|
||||
# OIDC_ENABLED=
|
||||
# OIDC_ISSUER=
|
||||
# OIDC_AUTHORIZATION_URL=
|
||||
# OIDC_TOKEN_URL=
|
||||
# OIDC_USERINFO_URL=
|
||||
# OIDC_CLIENT_ID=
|
||||
# OIDC_CLIENT_SECRET=
|
||||
# OIDC_CALLBACK_URL=
|
||||
# OIDC_LOGOUT_URL=
|
||||
# OIDC_SCOPES=
|
||||
# OIDC_AUTO_CREATE_USERS=true
|
||||
|
||||
# SEARCH_DEEP=
|
||||
# SEARCH_RIPGREP=
|
||||
# SEARCH_MAX_FILESIZE=
|
||||
|
||||
# ONLYOFFICE_URL=
|
||||
# ONLYOFFICE_SECRET=
|
||||
# ONLYOFFICE_LANG=
|
||||
# ONLYOFFICE_FORCE_SAVE=
|
||||
# ONLYOFFICE_FILE_EXTENSIONS=
|
||||
|
||||
# COLLABORA_URL=
|
||||
# COLLABORA_DISCOVERY_URL=
|
||||
# COLLABORA_SECRET=
|
||||
# COLLABORA_LANG=
|
||||
# COLLABORA_FILE_EXTENSIONS=
|
||||
|
||||
SHOW_VOLUME_USAGE=true
|
||||
# USER_DIR_ENABLED=
|
||||
# SKIP_HOME=
|
||||
|
||||
# EDITOR_EXTENSIONS=
|
||||
|
||||
# FFMPEG_PATH=
|
||||
# FFPROBE_PATH=
|
||||
|
||||
## Hardware acceleration
|
||||
# FFMPEG_HWACCEL=vaapi
|
||||
# FFMPEG_HWACCEL_DEVICE=/dev/dri/renderD128
|
||||
# FFMPEG_HWACCEL_OUTPUT_FORMAT=nv12
|
||||
|
||||
FAVORITES_DEFAULT_ICON=outline.StarIcon
|
||||
|
||||
SHARES_ENABLED=true
|
||||
# SHARES_TOKEN_LENGTH=10
|
||||
# SHARES_MAX_PER_USER=100
|
||||
# SHARES_DEFAULT_EXPIRY_DAYS=30
|
||||
# SHARES_GUEST_SESSION_HOURS=24
|
||||
# SHARES_ALLOW_PASSWORD=true
|
||||
# SHARES_ALLOW_ANONYMOUS=true
|
||||
EOF
|
||||
chmod 600 /etc/nextExplorer/.env
|
||||
$STD useradd -U -s /usr/sbin/nologin -m -d /home/explorer explorer
|
||||
chown -R explorer:explorer "$APP_DIR" /etc/nextExplorer
|
||||
sed -i "\|version|s|$(jq -cr '.version' ${APP_DIR}/package.json)|$(cat ~/.nextexplorer)|" "$APP_DIR"/package.json
|
||||
msg_ok "Configured nextExplorer"
|
||||
|
||||
msg_info "Creating nextExplorer Service"
|
||||
cat <<EOF >/etc/systemd/system/nextexplorer.service
|
||||
[Unit]
|
||||
Description=nextExplorer Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=explorer
|
||||
Group=explorer
|
||||
WorkingDirectory=/opt/nextExplorer/app
|
||||
EnvironmentFile=/etc/nextExplorer/.env
|
||||
ExecStart=/usr/bin/node ./src/server.js
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
$STD systemctl enable -q --now nextexplorer
|
||||
msg_ok "Created nextExplorer Service"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
@@ -91,16 +91,16 @@ expect "Format: mongodb://*" {
|
||||
send "$MONGO_CONNECTION_STRING\r"
|
||||
}
|
||||
expect "Administrator username" {
|
||||
send "helper-scripts\r"
|
||||
send "community-scripts\r"
|
||||
}
|
||||
expect "Administrator email address" {
|
||||
send "helper-scripts@local.com\r"
|
||||
send "admin@community-scripts.com\r"
|
||||
}
|
||||
expect "Password" {
|
||||
send "helper-scripts\r"
|
||||
send "community-scripts\r"
|
||||
}
|
||||
expect "Confirm Password" {
|
||||
send "helper-scripts\r"
|
||||
send "community-scripts\r"
|
||||
}
|
||||
expect eof
|
||||
EOF
|
||||
|
||||
@@ -60,7 +60,7 @@ read -r -p "${TAB3}Enter your ACME Email: " ACME_EMAIL_INPUT
|
||||
yq -i "
|
||||
.services.npmplus.environment |=
|
||||
(map(select(. != \"TZ=*\" and . != \"ACME_EMAIL=*\" and . != \"INITIAL_ADMIN_EMAIL=*\" and . != \"INITIAL_ADMIN_PASSWORD=*\")) +
|
||||
[\"TZ=$TZ_INPUT\", \"ACME_EMAIL=$ACME_EMAIL_INPUT\", \"INITIAL_ADMIN_EMAIL=admin@local.com\", \"INITIAL_ADMIN_PASSWORD=helper-scripts.com\"])
|
||||
[\"TZ=$TZ_INPUT\", \"ACME_EMAIL=$ACME_EMAIL_INPUT\", \"INITIAL_ADMIN_EMAIL=admin@local.com\", \"INITIAL_ADMIN_PASSWORD=community-scripts.com\"])
|
||||
" /opt/compose.yaml
|
||||
|
||||
msg_info "Building and Starting NPMplus (Patience)"
|
||||
|
||||
@@ -13,27 +13,19 @@ setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
NODE_VERSION="22" NODE_MODULE="yarn@latest" setup_nodejs
|
||||
PG_VERSION="16" setup_postgresql
|
||||
PG_DB_NAME="partdb" PG_DB_USER="partdb" setup_postgresql_db
|
||||
PHP_VERSION="8.4" PHP_APACHE="YES" PHP_MODULE="xsl" PHP_POST_MAX_SIZE="100M" PHP_UPLOAD_MAX_FILESIZE="100M" setup_php
|
||||
setup_composer
|
||||
|
||||
msg_info "Installing Part-DB (Patience)"
|
||||
cd /opt
|
||||
RELEASE=$(get_latest_github_release "Part-DB/Part-DB-server")
|
||||
curl -fsSL "https://github.com/Part-DB/Part-DB-server/archive/refs/tags/v${RELEASE}.zip" -o "/opt/v${RELEASE}.zip"
|
||||
$STD unzip "v${RELEASE}.zip"
|
||||
mv /opt/Part-DB-server-${RELEASE}/ /opt/partdb
|
||||
fetch_and_deploy_gh_release "partdb" "Part-DB/Part-DB-server" "prebuild" "latest" "/opt/partdb" "partdb_with_assets.zip"
|
||||
|
||||
msg_info "Installing Part-DB"
|
||||
cd /opt/partdb/
|
||||
cp .env .env.local
|
||||
sed -i "s|DATABASE_URL=\"sqlite:///%kernel.project_dir%/var/app.db\"|DATABASE_URL=\"postgresql://${PG_DB_USER}:${PG_DB_PASS}@127.0.0.1:5432/${PG_DB_NAME}?serverVersion=12.19&charset=utf8\"|" .env.local
|
||||
|
||||
export COMPOSER_ALLOW_SUPERUSER=1
|
||||
$STD composer install --no-dev -o --no-interaction
|
||||
$STD yarn install
|
||||
$STD yarn build
|
||||
$STD php bin/console cache:clear
|
||||
php bin/console doctrine:migrations:migrate -n >~/database-migration-output
|
||||
chown -R www-data:www-data /opt/partdb
|
||||
@@ -44,8 +36,6 @@ ADMIN_PASS=$(grep -oP 'The initial password for the "admin" user is: \K\w+' ~/da
|
||||
echo "Part-DB Admin Password: $ADMIN_PASS"
|
||||
} >>~/partdb.creds
|
||||
rm -rf ~/database-migration-output
|
||||
rm -rf "/opt/v${RELEASE}.zip"
|
||||
echo "${RELEASE}" >~/.partdb
|
||||
msg_ok "Installed Part-DB"
|
||||
|
||||
msg_info "Creating Service"
|
||||
|
||||
@@ -99,7 +99,7 @@ PHOTOPRISM_DEBUG='false'
|
||||
PHOTOPRISM_LOG_LEVEL='info'
|
||||
|
||||
# Site Info
|
||||
PHOTOPRISM_SITE_CAPTION='https://Helper-Scripts.com'
|
||||
PHOTOPRISM_SITE_CAPTION='https://community-scripts.com'
|
||||
PHOTOPRISM_SITE_DESCRIPTION=''
|
||||
PHOTOPRISM_SITE_AUTHOR=''
|
||||
EOF
|
||||
|
||||
@@ -40,7 +40,7 @@ cat <<EOF >/opt/semaphore/config.json
|
||||
"access_key_encryption": "${SEM_KEY}"
|
||||
}
|
||||
EOF
|
||||
$STD semaphore user add --admin --login admin --email admin@helper-scripts.com --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json
|
||||
$STD semaphore user add --admin --login admin --email admin@community-scripts.com --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json
|
||||
echo "${SEM_PW}" >~/semaphore.creds
|
||||
msg_ok "Setup Semaphore"
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ cd Shinobi
|
||||
gitVersionNumber=$(git rev-parse HEAD)
|
||||
theDateRightNow=$(date)
|
||||
touch version.json
|
||||
chmod 777 version.json
|
||||
chmod 644 version.json
|
||||
echo '{"Product" : "'"Shinobi"'" , "Branch" : "'"master"'" , "Version" : "'"$gitVersionNumber"'" , "Date" : "'"$theDateRightNow"'" , "Repository" : "'"https://gitlab.com/Shinobi-Systems/Shinobi.git"'"}' >version.json
|
||||
msg_ok "Cloned Shinobi"
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ fetch_and_deploy_gh_release "tasmoadmin" "TasmoAdmin/TasmoAdmin" "prebuild" "lat
|
||||
msg_info "Configuring TasmoAdmin"
|
||||
rm -rf /etc/php/8.4/apache2/conf.d/10-opcache.ini
|
||||
chown -R www-data:www-data /var/www/tasmoadmin
|
||||
chmod 777 /var/www/tasmoadmin/tmp /var/www/tasmoadmin/data
|
||||
chmod 775 /var/www/tasmoadmin/tmp /var/www/tasmoadmin/data
|
||||
cat <<EOF >/etc/apache2/sites-available/tasmoadmin.conf
|
||||
<VirtualHost *:9999>
|
||||
ServerName tasmoadmin
|
||||
|
||||
@@ -62,6 +62,7 @@ fetch_and_deploy_gh_release "tracearr" "connorgallopo/Tracearr" "tarball" "lates
|
||||
|
||||
msg_info "Building Tracearr"
|
||||
export TZ=$(cat /etc/timezone)
|
||||
export NODE_OPTIONS="--max-old-space-size=4096"
|
||||
cd /opt/tracearr.build
|
||||
$STD pnpm install --frozen-lockfile --force
|
||||
$STD pnpm turbo telemetry disable
|
||||
|
||||
@@ -67,22 +67,22 @@ EOF
|
||||
# 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"
|
||||
local _ip=""
|
||||
while [ $i -gt 0 ]; do
|
||||
_ip=$(ip -4 addr show 2>/dev/null | awk '/inet [0-9]/ && !/127\.0\.0\.1/ {sub(/\/.*/, "", $2); print $2; exit}')
|
||||
[[ -n "$_ip" ]] && break
|
||||
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 [[ -z "$_ip" ]]; then
|
||||
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 121
|
||||
fi
|
||||
msg_ok "Set up Container OS"
|
||||
msg_ok "Network Connected: ${BL}${_ip}${CL}"
|
||||
msg_ok "Network Connected: ${BL}$(ip addr show | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 | tail -n1)${CL}"
|
||||
post_progress_to_api
|
||||
}
|
||||
|
||||
@@ -90,11 +90,18 @@ setting_up_container() {
|
||||
network_check() {
|
||||
set +e
|
||||
trap - ERR
|
||||
ipv4_connected=false
|
||||
|
||||
# Check IPv4 connectivity to Cloudflare, Google & 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
|
||||
ipv4_status="${GN}✔${CL} IPv4"
|
||||
msg_ok "IPv4 Internet Connected"
|
||||
ipv4_connected=true
|
||||
else
|
||||
ipv4_status="${RD}✖${CL} IPv4"
|
||||
read -r -p "Internet NOT connected. Continue anyway? <y/N> " prompt
|
||||
msg_error "IPv4 Internet Not Connected"
|
||||
fi
|
||||
|
||||
if [[ $ipv4_connected == false ]]; then
|
||||
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt
|
||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
|
||||
else
|
||||
@@ -102,12 +109,28 @@ network_check() {
|
||||
exit 122
|
||||
fi
|
||||
fi
|
||||
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
|
||||
if [[ -z "$RESOLVEDIP" ]]; then
|
||||
msg_error "Internet: ${ipv4_status} DNS Failed"
|
||||
|
||||
# DNS resolution checks for GitHub-related domains
|
||||
GIT_HOSTS=("github.com" "raw.githubusercontent.com" "api.github.com" "git.community-scripts.org")
|
||||
GIT_STATUS="Git DNS:"
|
||||
DNS_FAILED=false
|
||||
|
||||
for HOST in "${GIT_HOSTS[@]}"; do
|
||||
RESOLVEDIP=$(getent hosts "$HOST" | awk '{ print $1 }' | grep -E '(^([0-9]{1,3}\.){3}[0-9]{1,3}$)|(^[a-fA-F0-9:]+$)' | head -n1)
|
||||
if [[ -z "$RESOLVEDIP" ]]; then
|
||||
GIT_STATUS+="$HOST:($DNSFAIL)"
|
||||
DNS_FAILED=true
|
||||
else
|
||||
GIT_STATUS+=" $HOST:($DNSOK)"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$DNS_FAILED" == true ]]; then
|
||||
fatal "$GIT_STATUS"
|
||||
else
|
||||
msg_ok "Internet: ${ipv4_status} DNS: ${BL}${RESOLVEDIP}${CL}"
|
||||
msg_ok "$GIT_STATUS"
|
||||
fi
|
||||
|
||||
set -e
|
||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ download_with_progress() {
|
||||
# $1 url, $2 dest
|
||||
local url="$1" out="$2" cl
|
||||
need_tool curl pv || return 1
|
||||
cl=$(curl -fsSLI "$url" 2>/dev/null | awk 'tolower($0) ~ /^content-length:/ {gsub(/\r/,""); print $2}')
|
||||
cl=$(curl -fsSLI "$url" 2>/dev/null | awk 'tolower($0) ~ /^content-length:/ {print $2}' | tr -d '\r')
|
||||
if [ -n "$cl" ]; then
|
||||
curl -fsSL "$url" | pv -s "$cl" >"$out" || {
|
||||
msg_error "Download failed: $url"
|
||||
|
||||
@@ -401,7 +401,7 @@ get_error_text() {
|
||||
fi
|
||||
|
||||
if [[ -n "$logfile" && -s "$logfile" ]]; then
|
||||
tail -n 20 "$logfile" 2>/dev/null | sed -E 's/\r$//; s/\x1b\[[0-9;]*[a-zA-Z]//g'
|
||||
tail -n 20 "$logfile" 2>/dev/null | sed 's/\r$//' | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g'
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -508,8 +508,7 @@ detect_gpu() {
|
||||
|
||||
if [[ -n "$gpu_line" ]]; then
|
||||
# Extract model: everything after the colon, clean up
|
||||
GPU_MODEL=$(echo "$gpu_line" | sed -E 's/.*: //; s/ \(rev .*\)$//')
|
||||
GPU_MODEL="${GPU_MODEL:0:64}"
|
||||
GPU_MODEL=$(echo "$gpu_line" | sed 's/.*: //' | sed 's/ (rev .*)$//' | cut -c1-64)
|
||||
|
||||
# Detect vendor and passthrough type
|
||||
if echo "$gpu_line" | grep -qi "Intel"; then
|
||||
@@ -558,8 +557,7 @@ detect_cpu() {
|
||||
esac
|
||||
|
||||
# Extract model name and clean it up
|
||||
CPU_MODEL=$(grep -m1 "model name" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed -E 's/^ *//; s/\(R\)//g; s/\(TM\)//g; s/ +/ /g')
|
||||
CPU_MODEL="${CPU_MODEL:0:64}"
|
||||
CPU_MODEL=$(grep -m1 "model name" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^ *//' | sed 's/(R)//g' | sed 's/(TM)//g' | sed 's/ */ /g' | cut -c1-64)
|
||||
fi
|
||||
|
||||
export CPU_VENDOR CPU_MODEL
|
||||
@@ -629,8 +627,8 @@ post_to_api() {
|
||||
|
||||
[[ "${DEV_MODE:-}" == "true" ]] && echo "[DEBUG] post_to_api() DIAGNOSTICS=$DIAGNOSTICS RANDOM_UUID=$RANDOM_UUID NSAPP=$NSAPP" >&2
|
||||
|
||||
# Set type for later status updates
|
||||
TELEMETRY_TYPE="lxc"
|
||||
# Set type for later status updates (preserve if already set, e.g. turnkey)
|
||||
TELEMETRY_TYPE="${TELEMETRY_TYPE:-lxc}"
|
||||
|
||||
local pve_version=""
|
||||
if command -v pveversion &>/dev/null; then
|
||||
@@ -666,7 +664,7 @@ post_to_api() {
|
||||
{
|
||||
"random_id": "${RANDOM_UUID}",
|
||||
"execution_id": "${EXECUTION_ID:-${RANDOM_UUID}}",
|
||||
"type": "lxc",
|
||||
"type": "${TELEMETRY_TYPE}",
|
||||
"nsapp": "${NSAPP:-unknown}",
|
||||
"status": "installing",
|
||||
"ct_type": ${CT_TYPE:-1},
|
||||
@@ -694,6 +692,7 @@ EOF
|
||||
# Send initial "installing" record with retry.
|
||||
# This record MUST exist for all subsequent updates to succeed.
|
||||
local http_code="" attempt
|
||||
local _post_success=false
|
||||
for attempt in 1 2 3; do
|
||||
if [[ "${DEV_MODE:-}" == "true" ]]; then
|
||||
http_code=$(curl -sS -w "%{http_code}" -m "${TELEMETRY_TIMEOUT}" -X POST "${TELEMETRY_URL}" \
|
||||
@@ -705,11 +704,19 @@ EOF
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD" -o /dev/null 2>/dev/null) || http_code="000"
|
||||
fi
|
||||
[[ "$http_code" =~ ^2[0-9]{2}$ ]] && break
|
||||
if [[ "$http_code" =~ ^2[0-9]{2}$ ]]; then
|
||||
_post_success=true
|
||||
break
|
||||
fi
|
||||
[[ "$attempt" -lt 3 ]] && sleep 1
|
||||
done
|
||||
|
||||
POST_TO_API_DONE=true
|
||||
# Only mark done if at least one attempt succeeded.
|
||||
# If all 3 failed, POST_TO_API_DONE stays false so post_update_to_api
|
||||
# and on_exit() know the initial record was never created.
|
||||
# The server has fallback logic to create a new record on status updates,
|
||||
# so subsequent calls can still succeed even without the initial record.
|
||||
POST_TO_API_DONE=${_post_success}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -800,15 +807,19 @@ EOF
|
||||
|
||||
# Send initial "installing" record with retry (must succeed for updates to work)
|
||||
local http_code="" attempt
|
||||
local _post_success=false
|
||||
for attempt in 1 2 3; do
|
||||
http_code=$(curl -sS -w "%{http_code}" -m "${TELEMETRY_TIMEOUT}" -X POST "${TELEMETRY_URL}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD" -o /dev/null 2>/dev/null) || http_code="000"
|
||||
[[ "$http_code" =~ ^2[0-9]{2}$ ]] && break
|
||||
if [[ "$http_code" =~ ^2[0-9]{2}$ ]]; then
|
||||
_post_success=true
|
||||
break
|
||||
fi
|
||||
[[ "$attempt" -lt 3 ]] && sleep 1
|
||||
done
|
||||
|
||||
POST_TO_API_DONE=true
|
||||
POST_TO_API_DONE=${_post_success}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -1085,6 +1096,12 @@ EOF
|
||||
# - Used to group errors in dashboard
|
||||
# ------------------------------------------------------------------------------
|
||||
categorize_error() {
|
||||
# Allow build.func to override category based on log analysis (exit code 1 subclassification)
|
||||
if [[ -n "${ERROR_CATEGORY_OVERRIDE:-}" ]]; then
|
||||
echo "$ERROR_CATEGORY_OVERRIDE"
|
||||
return
|
||||
fi
|
||||
|
||||
local code="$1"
|
||||
case "$code" in
|
||||
# Network errors (curl/wget)
|
||||
@@ -1327,16 +1344,11 @@ post_addon_to_api() {
|
||||
error_category=$(categorize_error "$exit_code")
|
||||
fi
|
||||
|
||||
# Detect OS info (single read)
|
||||
# Detect OS info
|
||||
local os_type="" os_version=""
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
while IFS='=' read -r _k _v; do
|
||||
_v="${_v//\"/}"
|
||||
case "$_k" in
|
||||
ID) os_type="$_v" ;;
|
||||
VERSION_ID) os_version="$_v" ;;
|
||||
esac
|
||||
done </etc/os-release
|
||||
os_type=$(grep "^ID=" /etc/os-release | cut -d= -f2 | tr -d '"')
|
||||
os_version=$(grep "^VERSION_ID=" /etc/os-release | cut -d= -f2 | tr -d '"')
|
||||
fi
|
||||
|
||||
local JSON_PAYLOAD
|
||||
|
||||
976
misc/build.func
976
misc/build.func
File diff suppressed because it is too large
Load Diff
@@ -1644,7 +1644,7 @@ function get_lxc_ip() {
|
||||
local ip
|
||||
|
||||
# Try direct interface lookup for eth0 FIRST (most reliable for LXC) - IPv4
|
||||
ip=$(ip -4 addr show eth0 2>/dev/null | awk '/inet / {sub(/\/.*/, "", $2); print $2; exit}')
|
||||
ip=$(ip -4 addr show eth0 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1 | head -n1)
|
||||
if [[ -n "$ip" && "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "$ip"
|
||||
return 0
|
||||
@@ -1652,14 +1652,11 @@ function get_lxc_ip() {
|
||||
|
||||
# Fallback: Try hostname -I (returns IPv4 first if available)
|
||||
if command -v hostname >/dev/null 2>&1; then
|
||||
local -a _ips
|
||||
read -ra _ips <<<"$(hostname -I 2>/dev/null)"
|
||||
for ip in "${_ips[@]}"; do
|
||||
if [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "$ip"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
ip=$(hostname -I 2>/dev/null | awk '{print $1}')
|
||||
if [[ -n "$ip" && "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "$ip"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try routing table with IPv4 targets
|
||||
@@ -1677,7 +1674,7 @@ function get_lxc_ip() {
|
||||
done
|
||||
|
||||
# IPv6 fallback: Try direct interface lookup for eth0
|
||||
ip=$(ip -6 addr show eth0 scope global 2>/dev/null | awk '/inet6 / {sub(/\/.*/, "", $2); print $2; exit}')
|
||||
ip=$(ip -6 addr show eth0 scope global 2>/dev/null | awk '/inet6 / {print $2}' | cut -d/ -f1 | head -n1)
|
||||
if [[ -n "$ip" && "$ip" =~ : ]]; then
|
||||
echo "$ip"
|
||||
return 0
|
||||
@@ -1685,14 +1682,11 @@ function get_lxc_ip() {
|
||||
|
||||
# IPv6 fallback: Try hostname -I for IPv6
|
||||
if command -v hostname >/dev/null 2>&1; then
|
||||
local -a _ips6
|
||||
read -ra _ips6 <<<"$(hostname -I 2>/dev/null)"
|
||||
for ip in "${_ips6[@]}"; do
|
||||
[[ "$ip" == *:* ]] && {
|
||||
echo "$ip"
|
||||
return 0
|
||||
}
|
||||
done
|
||||
ip=$(hostname -I 2>/dev/null | tr ' ' '\n' | grep -E ':' | head -n1)
|
||||
if [[ -n "$ip" && "$ip" =~ : ]]; then
|
||||
echo "$ip"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# IPv6 fallback: Use routing table with IPv6 targets
|
||||
|
||||
@@ -507,14 +507,23 @@ _stop_container_if_installing() {
|
||||
on_exit() {
|
||||
local exit_code=$?
|
||||
|
||||
# Report orphaned "installing" records to telemetry API
|
||||
# Catches ALL exit paths: errors, signals, AND clean exits where
|
||||
# post_to_api was called but post_update_to_api was never called
|
||||
if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
|
||||
if [[ $exit_code -ne 0 ]]; then
|
||||
_send_abort_telemetry "$exit_code"
|
||||
elif declare -f post_update_to_api >/dev/null 2>&1; then
|
||||
post_update_to_api "done" "0" 2>/dev/null || true
|
||||
# Report orphaned telemetry records
|
||||
# Two scenarios handled:
|
||||
# 1. POST_TO_API_DONE=true but POST_UPDATE_DONE=false: Record was created but
|
||||
# never got a final status update → send abort/done now.
|
||||
# 2. POST_TO_API_DONE=false but DIAGNOSTICS=yes: Initial post failed (server
|
||||
# unreachable/timeout), but the server has fallback create-on-update logic,
|
||||
# so a status update can still create the record. Worth one last try.
|
||||
if [[ "${POST_UPDATE_DONE:-}" != "true" ]]; then
|
||||
if [[ "${POST_TO_API_DONE:-}" == "true" || "${DIAGNOSTICS:-no}" == "yes" ]]; then
|
||||
if [[ $exit_code -ne 0 ]]; then
|
||||
_send_abort_telemetry "$exit_code"
|
||||
elif [[ "${INSTALL_COMPLETE:-}" == "true" ]] && declare -f post_update_to_api >/dev/null 2>&1; then
|
||||
# Only report success if the install was explicitly marked complete.
|
||||
# Without this guard, early bailouts (e.g. user cancelled) with exit 0
|
||||
# would be falsely reported as successful installations.
|
||||
post_update_to_api "done" "0" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -116,14 +116,14 @@ setting_up_container() {
|
||||
(chown root:root / 2>/dev/null) || true
|
||||
fi
|
||||
|
||||
local _host_ip=""
|
||||
for ((i = RETRY_NUM; i > 0; i--)); do
|
||||
_host_ip=$(hostname -I 2>/dev/null | awk '{print $1}')
|
||||
[[ -n "$_host_ip" ]] && break
|
||||
if [ "$(hostname -I)" != "" ]; then
|
||||
break
|
||||
fi
|
||||
echo 1>&2 -en "${CROSS}${RD} No Network! "
|
||||
sleep $RETRY_EVERY
|
||||
done
|
||||
if [[ -z "$_host_ip" ]]; then
|
||||
if [ "$(hostname -I)" = "" ]; then
|
||||
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
|
||||
echo -e "${NETWORK}Check Network Settings"
|
||||
exit 121
|
||||
@@ -131,7 +131,8 @@ setting_up_container() {
|
||||
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
|
||||
systemctl disable -q --now systemd-networkd-wait-online.service
|
||||
msg_ok "Set up Container OS"
|
||||
msg_ok "Network Connected: ${BL}${_host_ip}"
|
||||
#msg_custom "${CM}" "${GN}" "Network Connected: ${BL}$(hostname -I)"
|
||||
msg_ok "Network Connected: ${BL}$(hostname -I)"
|
||||
post_progress_to_api
|
||||
}
|
||||
|
||||
@@ -308,14 +309,14 @@ customize() {
|
||||
if [[ "$PASSWORD" == "" ]]; then
|
||||
msg_info "Customizing Container"
|
||||
GETTY_OVERRIDE="/etc/systemd/system/container-getty@1.service.d/override.conf"
|
||||
mkdir -p $(dirname $GETTY_OVERRIDE)
|
||||
cat <<EOF >$GETTY_OVERRIDE
|
||||
mkdir -p "$(dirname "$GETTY_OVERRIDE")"
|
||||
cat <<EOF >"$GETTY_OVERRIDE"
|
||||
[Service]
|
||||
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//')
|
||||
systemctl restart "$(basename "$(dirname "$GETTY_OVERRIDE")" | sed 's/\.d//')"
|
||||
msg_ok "Customized Container"
|
||||
fi
|
||||
echo "bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)\"" >/usr/bin/update
|
||||
|
||||
@@ -242,7 +242,7 @@ download_gpg_key() {
|
||||
|
||||
# Process based on mode
|
||||
if [[ "$mode" == "dearmor" ]]; then
|
||||
if gpg --dearmor --yes -o "$output" <"$temp_key" 2>/dev/null; then
|
||||
if gpg --dearmor --yes -o "$output" <"$temp_key" 2>/dev/null && [[ -s "$output" ]]; then
|
||||
rm -f "$temp_key"
|
||||
debug_log "GPG key installed (dearmored): $output"
|
||||
return 0
|
||||
@@ -700,7 +700,7 @@ manage_tool_repository() {
|
||||
local gpg_key_url="${4:-}"
|
||||
local distro_id repo_component suite
|
||||
|
||||
distro_id=$(get_os_info id)
|
||||
distro_id=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"')
|
||||
|
||||
case "$tool_name" in
|
||||
mariadb)
|
||||
@@ -714,7 +714,7 @@ manage_tool_repository() {
|
||||
|
||||
# Get suite for fallback handling
|
||||
local distro_codename
|
||||
distro_codename=$(get_os_info codename)
|
||||
distro_codename=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)
|
||||
suite=$(get_fallback_suite "$distro_id" "$distro_codename" "$repo_url/$distro_id")
|
||||
|
||||
# Setup new repository using deb822 format
|
||||
@@ -745,7 +745,7 @@ manage_tool_repository() {
|
||||
|
||||
# Setup repository
|
||||
local distro_codename
|
||||
distro_codename=$(get_os_info codename)
|
||||
distro_codename=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)
|
||||
|
||||
# Suite mapping with fallback for newer releases not yet supported by upstream
|
||||
if [[ "$distro_id" == "debian" ]]; then
|
||||
@@ -816,7 +816,7 @@ EOF
|
||||
|
||||
# NodeSource uses deb822 format with GPG from repo
|
||||
local distro_codename
|
||||
distro_codename=$(get_os_info codename)
|
||||
distro_codename=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)
|
||||
|
||||
# Download GPG key from NodeSource with retry logic
|
||||
if ! download_gpg_key "$gpg_key_url" "/etc/apt/keyrings/nodesource.gpg" "dearmor"; then
|
||||
@@ -858,7 +858,7 @@ EOF
|
||||
|
||||
# Setup repository
|
||||
local distro_codename
|
||||
distro_codename=$(get_os_info codename)
|
||||
distro_codename=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)
|
||||
cat <<EOF >/etc/apt/sources.list.d/php.sources
|
||||
Types: deb
|
||||
URIs: https://packages.sury.org/php
|
||||
@@ -886,7 +886,7 @@ EOF
|
||||
|
||||
# Setup repository
|
||||
local distro_codename
|
||||
distro_codename=$(get_os_info codename)
|
||||
distro_codename=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)
|
||||
cat <<EOF >/etc/apt/sources.list.d/postgresql.sources
|
||||
Types: deb
|
||||
URIs: http://apt.postgresql.org/pub/repos/apt
|
||||
@@ -1323,16 +1323,10 @@ get_os_info() {
|
||||
|
||||
# Cache OS info to avoid repeated file reads
|
||||
if [[ -z "${_OS_ID:-}" ]]; then
|
||||
local _line
|
||||
while IFS='=' read -r _key _val; do
|
||||
_val="${_val//\"/}"
|
||||
case "$_key" in
|
||||
ID) export _OS_ID="$_val" ;;
|
||||
VERSION_CODENAME) export _OS_CODENAME="$_val" ;;
|
||||
VERSION_ID) export _OS_VERSION="$_val" ;;
|
||||
VERSION) export _OS_VERSION_FULL="$_val" ;;
|
||||
esac
|
||||
done </etc/os-release
|
||||
export _OS_ID=$(awk -F= '/^ID=/{gsub(/"/,"",$2); print $2}' /etc/os-release)
|
||||
export _OS_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{gsub(/"/,"",$2); print $2}' /etc/os-release)
|
||||
export _OS_VERSION=$(awk -F= '/^VERSION_ID=/{gsub(/"/,"",$2); print $2}' /etc/os-release)
|
||||
export _OS_VERSION_FULL=$(awk -F= '/^VERSION=/{gsub(/"/,"",$2); print $2}' /etc/os-release)
|
||||
fi
|
||||
|
||||
case "$field" in
|
||||
@@ -2150,8 +2144,8 @@ fetch_and_deploy_gh_tag() {
|
||||
local repo="$2"
|
||||
local version="${3:-latest}"
|
||||
local target="${4:-/opt/$app}"
|
||||
local app_lc="${app,,}"
|
||||
app_lc="${app_lc// /}"
|
||||
local app_lc=""
|
||||
app_lc="$(echo "${app,,}" | tr -d ' ')"
|
||||
local version_file="$HOME/.${app_lc}"
|
||||
|
||||
if [[ "$version" == "latest" ]]; then
|
||||
@@ -2227,8 +2221,8 @@ check_for_gh_tag() {
|
||||
local app="$1"
|
||||
local repo="$2"
|
||||
local prefix="${3:-}"
|
||||
local app_lc="${app,,}"
|
||||
app_lc="${app_lc// /}"
|
||||
local app_lc=""
|
||||
app_lc="$(echo "${app,,}" | tr -d ' ')"
|
||||
local current_file="$HOME/.${app_lc}"
|
||||
|
||||
msg_info "Checking for update: ${app}"
|
||||
@@ -2278,8 +2272,8 @@ check_for_gh_release() {
|
||||
local source="$2"
|
||||
local pinned_version_in="${3:-}" # optional
|
||||
local pin_reason="${4:-}" # optional reason shown to user
|
||||
local app_lc="${app,,}"
|
||||
app_lc="${app_lc// /}"
|
||||
local app_lc=""
|
||||
app_lc="$(echo "${app,,}" | tr -d ' ')"
|
||||
local current_file="$HOME/.${app_lc}"
|
||||
|
||||
msg_info "Checking for update: ${app}"
|
||||
@@ -2606,8 +2600,7 @@ create_self_signed_cert() {
|
||||
local APP_NAME="${1:-${APPLICATION}}"
|
||||
local HOSTNAME="$(hostname -f)"
|
||||
local IP="$(hostname -I | awk '{print $1}')"
|
||||
local APP_NAME_LC="${APP_NAME,,}"
|
||||
APP_NAME_LC="${APP_NAME_LC// /}"
|
||||
local APP_NAME_LC=$(echo "${APP_NAME,,}" | tr -d ' ')
|
||||
local CERT_DIR="/etc/ssl/${APP_NAME_LC}"
|
||||
local CERT_KEY="${CERT_DIR}/${APP_NAME_LC}.key"
|
||||
local CERT_CRT="${CERT_DIR}/${APP_NAME_LC}.crt"
|
||||
@@ -2654,7 +2647,7 @@ function download_with_progress() {
|
||||
|
||||
# Content-Length aus HTTP-Header holen
|
||||
local content_length
|
||||
content_length=$(curl -fsSLI "$url" | awk '/Content-Length/ {gsub(/\r/,""); print $2}' || true)
|
||||
content_length=$(curl -fsSLI "$url" | awk '/Content-Length/ {print $2}' | tr -d '\r' || true)
|
||||
|
||||
if [[ -z "$content_length" ]]; then
|
||||
if ! curl -fL# -o "$output" "$url"; then
|
||||
@@ -2773,8 +2766,7 @@ function fetch_and_deploy_codeberg_release() {
|
||||
local target="${5:-/opt/$app}"
|
||||
local asset_pattern="${6:-}"
|
||||
|
||||
local app_lc="${app,,}"
|
||||
app_lc="${app_lc// /}"
|
||||
local app_lc=$(echo "${app,,}" | tr -d ' ')
|
||||
local version_file="$HOME/.${app_lc}"
|
||||
|
||||
local api_timeouts=(60 120 240)
|
||||
@@ -3326,8 +3318,7 @@ function fetch_and_deploy_gh_release() {
|
||||
fi
|
||||
fi
|
||||
|
||||
local app_lc="${app,,}"
|
||||
app_lc="${app_lc// /}"
|
||||
local app_lc=$(echo "${app,,}" | tr -d ' ')
|
||||
local version_file="$HOME/.${app_lc}"
|
||||
|
||||
local api_timeouts=(60 120 240)
|
||||
@@ -4418,7 +4409,7 @@ function setup_hwaccel() {
|
||||
# Parse comma-separated numbers
|
||||
IFS=',' read -ra nums <<<"$selection"
|
||||
for num in "${nums[@]}"; do
|
||||
num="${num// /}"
|
||||
num=$(echo "$num" | tr -d ' ')
|
||||
if [[ "$num" =~ ^[0-9]+$ ]] && ((num >= 1 && num <= gpu_count)); then
|
||||
SELECTED_INDICES+=("$((num - 1))")
|
||||
fi
|
||||
@@ -4460,9 +4451,9 @@ function setup_hwaccel() {
|
||||
# OS Detection
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
local os_id os_codename os_version
|
||||
os_id=$(get_os_info id)
|
||||
os_codename=$(get_os_info codename)
|
||||
os_version=$(get_os_info version)
|
||||
os_id=$(grep -oP '(?<=^ID=).+' /etc/os-release 2>/dev/null | tr -d '"' || echo "debian")
|
||||
os_codename=$(grep -oP '(?<=^VERSION_CODENAME=).+' /etc/os-release 2>/dev/null | tr -d '"' || echo "unknown")
|
||||
os_version=$(grep -oP '(?<=^VERSION_ID=).+' /etc/os-release 2>/dev/null | tr -d '"' || echo "")
|
||||
[[ -z "$os_id" ]] && os_id="debian"
|
||||
|
||||
local in_ct="${CTTYPE:-0}"
|
||||
@@ -5201,7 +5192,7 @@ _setup_gpu_permissions() {
|
||||
for nvidia_dev in /dev/nvidia*; do
|
||||
[[ -e "$nvidia_dev" ]] && {
|
||||
chgrp video "$nvidia_dev" 2>/dev/null || true
|
||||
chmod 666 "$nvidia_dev" 2>/dev/null || true
|
||||
chmod 660 "$nvidia_dev" 2>/dev/null || true
|
||||
}
|
||||
done
|
||||
if [[ -d /dev/nvidia-caps ]]; then
|
||||
@@ -5209,7 +5200,7 @@ _setup_gpu_permissions() {
|
||||
for caps_dev in /dev/nvidia-caps/*; do
|
||||
[[ -e "$caps_dev" ]] && {
|
||||
chgrp video "$caps_dev" 2>/dev/null || true
|
||||
chmod 666 "$caps_dev" 2>/dev/null || true
|
||||
chmod 660 "$caps_dev" 2>/dev/null || true
|
||||
}
|
||||
done
|
||||
fi
|
||||
@@ -5226,7 +5217,8 @@ _setup_gpu_permissions() {
|
||||
|
||||
# /dev/kfd permissions (AMD ROCm)
|
||||
if [[ -e /dev/kfd ]]; then
|
||||
chmod 666 /dev/kfd 2>/dev/null || true
|
||||
chgrp render /dev/kfd 2>/dev/null || true
|
||||
chmod 660 /dev/kfd 2>/dev/null || true
|
||||
msg_info "AMD ROCm compute device configured"
|
||||
fi
|
||||
|
||||
@@ -5348,8 +5340,8 @@ function setup_imagemagick() {
|
||||
function setup_java() {
|
||||
local JAVA_VERSION="${JAVA_VERSION:-21}"
|
||||
local DISTRO_ID DISTRO_CODENAME
|
||||
DISTRO_ID=$(get_os_info id)
|
||||
DISTRO_CODENAME=$(get_os_info codename)
|
||||
DISTRO_ID=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"')
|
||||
DISTRO_CODENAME=$(awk -F= '/VERSION_CODENAME/ { print $2 }' /etc/os-release)
|
||||
local DESIRED_PACKAGE="temurin-${JAVA_VERSION}-jdk"
|
||||
|
||||
# Prepare repository (cleanup + validation)
|
||||
@@ -5604,7 +5596,7 @@ EOF
|
||||
if [[ -n "$CURRENT_VERSION" ]]; then
|
||||
# Get available distro version
|
||||
local DISTRO_VERSION=""
|
||||
DISTRO_VERSION=$(apt-cache policy mariadb-server 2>/dev/null | awk '/Candidate:/ {sub(/^[0-9]+:/, "", $2); print $2}' || echo "")
|
||||
DISTRO_VERSION=$(apt-cache policy mariadb-server 2>/dev/null | grep -E "Candidate:" | awk '{print $2}' | grep -oP '^\d+:\K\d+\.\d+\.\d+' || echo "")
|
||||
|
||||
if [[ -n "$DISTRO_VERSION" ]]; then
|
||||
# Compare versions - if current is higher, keep it
|
||||
@@ -6005,8 +5997,8 @@ function setup_mysql() {
|
||||
local MYSQL_VERSION="${MYSQL_VERSION:-8.0}"
|
||||
local USE_MYSQL_REPO="${USE_MYSQL_REPO:-true}"
|
||||
local DISTRO_ID DISTRO_CODENAME
|
||||
DISTRO_ID=$(get_os_info id)
|
||||
DISTRO_CODENAME=$(get_os_info codename)
|
||||
DISTRO_ID=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"')
|
||||
DISTRO_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)
|
||||
|
||||
# Ensure non-interactive mode for all apt operations
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
@@ -6352,7 +6344,7 @@ function setup_nodejs() {
|
||||
|
||||
# Check if the module is already installed
|
||||
if $STD npm list -g --depth=0 "$MODULE_NAME" 2>&1 | grep -q "$MODULE_NAME@"; then
|
||||
MODULE_INSTALLED_VERSION="$(npm list -g --depth=0 "$MODULE_NAME" 2>&1 | awk -F@ -v mod="$MODULE_NAME" '$0 ~ mod"@" {gsub(/[[:space:]]/, "", $2); print $2}' || echo '')"
|
||||
MODULE_INSTALLED_VERSION="$(npm list -g --depth=0 "$MODULE_NAME" 2>&1 | grep "$MODULE_NAME@" | awk -F@ '{print $2}' 2>/dev/null | tr -d '[:space:]' || echo '')"
|
||||
if [[ "$MODULE_REQ_VERSION" != "latest" && "$MODULE_REQ_VERSION" != "$MODULE_INSTALLED_VERSION" ]]; then
|
||||
msg_info "Updating $MODULE_NAME from v$MODULE_INSTALLED_VERSION to v$MODULE_REQ_VERSION"
|
||||
if ! $STD npm install -g "${MODULE_NAME}@${MODULE_REQ_VERSION}" 2>/dev/null; then
|
||||
@@ -6423,8 +6415,8 @@ function setup_php() {
|
||||
local PHP_APACHE="${PHP_APACHE:-NO}"
|
||||
local PHP_FPM="${PHP_FPM:-NO}"
|
||||
local DISTRO_ID DISTRO_CODENAME
|
||||
DISTRO_ID=$(get_os_info id)
|
||||
DISTRO_CODENAME=$(get_os_info codename)
|
||||
DISTRO_ID=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"')
|
||||
DISTRO_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)
|
||||
|
||||
# Parse version for compatibility checks
|
||||
local PHP_MAJOR="${PHP_VERSION%%.*}"
|
||||
@@ -6471,7 +6463,7 @@ function setup_php() {
|
||||
local FILTERED_MODULES=""
|
||||
IFS=',' read -ra ALL_MODULES <<<"$COMBINED_MODULES"
|
||||
for mod in "${ALL_MODULES[@]}"; do
|
||||
mod="${mod//[[:space:]]/}"
|
||||
mod=$(echo "$mod" | tr -d '[:space:]')
|
||||
[[ -z "$mod" ]] && continue
|
||||
|
||||
# Skip if it's a known built-in module
|
||||
@@ -6488,7 +6480,7 @@ function setup_php() {
|
||||
done
|
||||
|
||||
# Deduplicate
|
||||
COMBINED_MODULES=$(awk -v RS=',' '!seen[$0]++{printf "%s%s", sep, $0; sep=","}' <<<"$FILTERED_MODULES")
|
||||
COMBINED_MODULES=$(echo "$FILTERED_MODULES" | tr ',' '\n' | awk '!seen[$0]++' | paste -sd, -)
|
||||
|
||||
# Get current PHP-CLI version
|
||||
local CURRENT_PHP=""
|
||||
@@ -6557,7 +6549,7 @@ EOF
|
||||
|
||||
IFS=',' read -ra MODULES <<<"$COMBINED_MODULES"
|
||||
for mod in "${MODULES[@]}"; do
|
||||
mod="${mod//[[:space:]]/}"
|
||||
mod=$(echo "$mod" | tr -d '[:space:]')
|
||||
[[ -z "$mod" ]] && continue
|
||||
|
||||
local pkg_name="php${PHP_VERSION}-${mod}"
|
||||
@@ -6736,8 +6728,8 @@ setup_postgresql() {
|
||||
local PG_MODULES="${PG_MODULES:-}"
|
||||
local USE_PGDG_REPO="${USE_PGDG_REPO:-true}"
|
||||
local DISTRO_ID DISTRO_CODENAME
|
||||
DISTRO_ID=$(get_os_info id)
|
||||
DISTRO_CODENAME=$(get_os_info codename)
|
||||
DISTRO_ID=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"')
|
||||
DISTRO_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)
|
||||
|
||||
# Ensure non-interactive mode for all apt operations
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
@@ -7580,8 +7572,8 @@ EOF
|
||||
function setup_clickhouse() {
|
||||
local CLICKHOUSE_VERSION="${CLICKHOUSE_VERSION:-latest}"
|
||||
local DISTRO_ID DISTRO_CODENAME
|
||||
DISTRO_ID=$(get_os_info id)
|
||||
DISTRO_CODENAME=$(get_os_info codename)
|
||||
DISTRO_ID=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"')
|
||||
DISTRO_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)
|
||||
|
||||
# Ensure non-interactive mode for all apt operations
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
@@ -7795,7 +7787,7 @@ function setup_rust() {
|
||||
|
||||
# Check if already installed
|
||||
if echo "$CRATE_LIST" | grep -q "^${NAME} "; then
|
||||
INSTALLED_VER=$(echo "$CRATE_LIST" | grep "^${NAME} " | head -1 | awk '{gsub(/[v:]/, "", $2); print $2}' || echo '')
|
||||
INSTALLED_VER=$(echo "$CRATE_LIST" | grep "^${NAME} " | head -1 | awk '{print $2}' 2>/dev/null | tr -d 'v:' || echo '')
|
||||
|
||||
if [[ -n "$VER" && "$VER" != "$INSTALLED_VER" ]]; then
|
||||
msg_info "Upgrading $NAME from v$INSTALLED_VER to v$VER"
|
||||
|
||||
@@ -594,7 +594,7 @@ set_description() {
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ fi
|
||||
PCT_OPTIONS="
|
||||
-features keyctl=1,nesting=1
|
||||
-hostname $NAME
|
||||
-tags proxmox-helper-scripts
|
||||
-tags community-script
|
||||
-onboot 0
|
||||
-cores 2
|
||||
-memory 2048
|
||||
|
||||
@@ -165,9 +165,9 @@ function install() {
|
||||
else
|
||||
read -rp "${TAB}Set admin username [admin]: " admin_user
|
||||
admin_user=${admin_user:-admin}
|
||||
read -rsp "${TAB}Set admin password [helper-scripts.com]: " admin_pass
|
||||
read -rsp "${TAB}Set admin password [community-scripts.com]: " admin_pass
|
||||
echo ""
|
||||
admin_pass=${admin_pass:-helper-scripts.com}
|
||||
admin_pass=${admin_pass:-community-scripts.com}
|
||||
msg_ok "Configured with admin user: ${admin_user}"
|
||||
fi
|
||||
|
||||
|
||||
@@ -201,9 +201,9 @@ server:
|
||||
- neverWatchPath: "/lost+found"
|
||||
auth:
|
||||
adminUsername: admin
|
||||
adminPassword: helper-scripts.com
|
||||
adminPassword: community-scripts.com
|
||||
EOF
|
||||
msg_ok "Configured with default admin (admin / helper-scripts.com)"
|
||||
msg_ok "Configured with default admin (admin / community-scripts.com)"
|
||||
fi
|
||||
|
||||
msg_info "Creating service"
|
||||
|
||||
@@ -140,8 +140,8 @@ if [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||
cd /usr/local/community-scripts
|
||||
filebrowser config init -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null
|
||||
filebrowser config set -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null
|
||||
filebrowser users add admin helper-scripts.com --perm.admin --database "$DB_PATH" &>/dev/null
|
||||
msg_ok "Default authentication configured (admin:helper-scripts.com)"
|
||||
filebrowser users add admin community-scripts.com --perm.admin --database "$DB_PATH" &>/dev/null
|
||||
msg_ok "Default authentication configured (admin:community-scripts.com)"
|
||||
fi
|
||||
|
||||
msg_info "Creating service"
|
||||
|
||||
173
tools/addon/homebrew.sh
Normal file
173
tools/addon/homebrew.sh
Normal file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MorganCSIT | MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://brew.sh | Github: https://github.com/Homebrew/brew
|
||||
|
||||
if ! command -v curl &>/dev/null; then
|
||||
printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2
|
||||
apt-get update >/dev/null 2>&1
|
||||
apt-get install -y curl >/dev/null 2>&1
|
||||
fi
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func)
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
|
||||
|
||||
# Enable error handling
|
||||
set -Eeuo pipefail
|
||||
trap 'error_handler' ERR
|
||||
load_functions
|
||||
init_tool_telemetry "" "addon"
|
||||
|
||||
# ==============================================================================
|
||||
# CONFIGURATION
|
||||
# ==============================================================================
|
||||
VERBOSE=${var_verbose:-no}
|
||||
APP="homebrew"
|
||||
APP_TYPE="tools"
|
||||
INSTALL_PATH="/home/linuxbrew/.linuxbrew"
|
||||
|
||||
# ==============================================================================
|
||||
# OS DETECTION
|
||||
# ==============================================================================
|
||||
if [[ -f "/etc/alpine-release" ]]; then
|
||||
echo -e "${CROSS} Alpine is not supported by Homebrew. Exiting."
|
||||
exit 1
|
||||
elif grep -qE 'ID=debian|ID=ubuntu' /etc/os-release; then
|
||||
OS="Debian"
|
||||
else
|
||||
echo -e "${CROSS} Unsupported OS detected. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ==============================================================================
|
||||
# UNINSTALL
|
||||
# ==============================================================================
|
||||
function uninstall() {
|
||||
msg_info "Uninstalling Homebrew"
|
||||
|
||||
BREW_USER=$(awk -F: '$3 >= 1000 && $3 < 65534 { print $1; exit }' /etc/passwd)
|
||||
if [[ -n "$BREW_USER" ]]; then
|
||||
BREW_USER_HOME=$(getent passwd "$BREW_USER" | cut -d: -f6)
|
||||
for rc_file in "$BREW_USER_HOME/.bashrc" "$BREW_USER_HOME/.profile"; do
|
||||
if [[ -f "$rc_file" ]]; then
|
||||
sed -i '/# Homebrew (Linuxbrew)/,/^fi$/d' "$rc_file"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
rm -rf /home/linuxbrew
|
||||
rm -f /etc/profile.d/homebrew.sh
|
||||
groupdel linuxbrew &>/dev/null || true
|
||||
|
||||
msg_ok "Homebrew has been uninstalled"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# INSTALL
|
||||
# ==============================================================================
|
||||
function install() {
|
||||
msg_info "Detecting Non-Root User"
|
||||
BREW_USER=$(awk -F: '$3 >= 1000 && $3 < 65534 { print $1; exit }' /etc/passwd)
|
||||
if [[ -z "$BREW_USER" ]]; then
|
||||
msg_warn "No non-root user found (uid >= 1000). Homebrew cannot run as root."
|
||||
read -r -p "${TAB}Create a 'brew' user automatically? (y/N): " create_user_prompt
|
||||
if [[ "${create_user_prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||
msg_info "Creating user 'brew'"
|
||||
useradd -m -s /bin/bash brew
|
||||
BREW_USER="brew"
|
||||
msg_ok "Created user 'brew'"
|
||||
else
|
||||
msg_error "Cannot install Homebrew without a non-root user. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
msg_ok "Detected User: $BREW_USER"
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt update
|
||||
$STD apt install -y build-essential git file procps
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
msg_info "Setting Up Homebrew Prefix"
|
||||
export PATH="/usr/sbin:$PATH"
|
||||
groupadd -f linuxbrew
|
||||
mkdir -p /home/linuxbrew/.linuxbrew
|
||||
chown -R "$BREW_USER":linuxbrew /home/linuxbrew
|
||||
chmod 2775 /home/linuxbrew
|
||||
chmod 2775 /home/linuxbrew/.linuxbrew
|
||||
usermod -aG linuxbrew "$BREW_USER"
|
||||
msg_ok "Set Up Homebrew Prefix"
|
||||
|
||||
msg_info "Installing Homebrew"
|
||||
$STD su - "$BREW_USER" -c 'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
|
||||
msg_ok "Installed Homebrew"
|
||||
|
||||
msg_info "Configuring Shell Integration"
|
||||
cat <<'EOF' >/etc/profile.d/homebrew.sh
|
||||
#!/bin/bash
|
||||
if [ -d "/home/linuxbrew/.linuxbrew" ]; then
|
||||
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
||||
fi
|
||||
EOF
|
||||
chmod +x /etc/profile.d/homebrew.sh
|
||||
|
||||
BREW_USER_HOME=$(getent passwd "$BREW_USER" | cut -d: -f6)
|
||||
BREW_SHELL_BLOCK='\n# Homebrew (Linuxbrew)\nif [ -d "/home/linuxbrew/.linuxbrew" ]; then\n eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"\nfi'
|
||||
for rc_file in "$BREW_USER_HOME/.bashrc" "$BREW_USER_HOME/.profile"; do
|
||||
if ! grep -q 'linuxbrew' "$rc_file" 2>/dev/null; then
|
||||
echo -e "$BREW_SHELL_BLOCK" >>"$rc_file"
|
||||
fi
|
||||
done
|
||||
msg_ok "Configured Shell Integration"
|
||||
|
||||
msg_info "Verifying Installation"
|
||||
$STD su - "$BREW_USER" -c 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" && brew --version'
|
||||
msg_ok "Homebrew Verified"
|
||||
|
||||
echo ""
|
||||
msg_ok "Homebrew installed successfully"
|
||||
msg_ok "Ready for user: ${BL}${BREW_USER}${CL}"
|
||||
echo ""
|
||||
echo -e "${TAB}${INFO} Usage: Switch to the brew user with a login shell:"
|
||||
echo -e "${TAB} ${BL}su - ${BREW_USER}${CL}"
|
||||
echo -e "${TAB} Then run: ${BL}brew install <package>${CL}"
|
||||
echo -e "${TAB} Update with: ${BL}brew update${CL}"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# MAIN
|
||||
# ==============================================================================
|
||||
header_info
|
||||
|
||||
if [[ -d "$INSTALL_PATH" ]]; then
|
||||
msg_warn "Homebrew is already installed."
|
||||
echo ""
|
||||
|
||||
read -r -p "${TAB}Uninstall Homebrew? (y/N): " uninstall_prompt
|
||||
if [[ "${uninstall_prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||
uninstall
|
||||
exit 0
|
||||
fi
|
||||
|
||||
msg_warn "No action selected. Exiting."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Fresh installation
|
||||
msg_warn "Homebrew is not installed."
|
||||
echo ""
|
||||
echo -e "${TAB}${INFO} This will install:"
|
||||
echo -e "${TAB} - Homebrew (Linuxbrew) package manager"
|
||||
echo -e "${TAB} - Shell integration for the detected non-root user"
|
||||
echo ""
|
||||
|
||||
read -r -p "${TAB}Install Homebrew? (y/N): " install_prompt
|
||||
if [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||
install
|
||||
else
|
||||
msg_warn "Installation cancelled. Exiting."
|
||||
exit 0
|
||||
fi
|
||||
@@ -150,7 +150,7 @@ function install() {
|
||||
curl -fsSL "https://raw.githubusercontent.com/runtipi/runtipi/master/scripts/install.sh" -o "install.sh"
|
||||
chmod +x install.sh
|
||||
$STD ./install.sh
|
||||
chmod 666 /opt/runtipi/state/settings.json 2>/dev/null || true
|
||||
chmod 660 /opt/runtipi/state/settings.json 2>/dev/null || true
|
||||
rm -f /opt/install.sh
|
||||
msg_ok "Installed ${APP}"
|
||||
|
||||
|
||||
6
tools/headers/homebrew
Normal file
6
tools/headers/homebrew
Normal file
@@ -0,0 +1,6 @@
|
||||
__ __
|
||||
/ /_ ____ ____ ___ ___ / /_ ________ _ __
|
||||
/ __ \/ __ \/ __ `__ \/ _ \/ __ \/ ___/ _ \ | /| / /
|
||||
/ / / / /_/ / / / / / / __/ /_/ / / / __/ |/ |/ /
|
||||
/_/ /_/\____/_/ /_/ /_/\___/_.___/_/ \___/|__/|__/
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2021-2026 tteck
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: tteck (tteckster)
|
||||
# License: MIT
|
||||
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
|
||||
function header_info {
|
||||
# Source shared libraries
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func)
|
||||
load_functions
|
||||
catch_errors
|
||||
|
||||
APP="TurnKey LXC"
|
||||
NSAPP="turnkey"
|
||||
DIAGNOSTICS="no"
|
||||
METHOD="default"
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
EXECUTION_ID="${RANDOM_UUID}"
|
||||
|
||||
header_info() {
|
||||
clear
|
||||
cat <<"EOF"
|
||||
______ __ __ __ _ _______
|
||||
@@ -15,281 +28,343 @@ function header_info {
|
||||
EOF
|
||||
}
|
||||
|
||||
set -euo pipefail
|
||||
shopt -s expand_aliases
|
||||
alias die='EXIT=$? LINE=$LINENO error_exit'
|
||||
trap die ERR
|
||||
function error_exit() {
|
||||
trap - ERR
|
||||
local DEFAULT='Unknown failure occured.'
|
||||
local REASON="\e[97m${1:-$DEFAULT}\e[39m"
|
||||
local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE"
|
||||
msg "$FLAG $REASON" 1>&2
|
||||
[ ! -z ${CTID-} ] && cleanup_ctid
|
||||
exit $EXIT
|
||||
}
|
||||
function warn() {
|
||||
local REASON="\e[97m$1\e[39m"
|
||||
local FLAG="\e[93m[WARNING]\e[39m"
|
||||
msg "$FLAG $REASON"
|
||||
}
|
||||
function info() {
|
||||
local REASON="$1"
|
||||
local FLAG="\e[36m[INFO]\e[39m"
|
||||
msg "$FLAG $REASON"
|
||||
}
|
||||
function msg() {
|
||||
local TEXT="$1"
|
||||
echo -e "$TEXT"
|
||||
}
|
||||
function validate_container_id() {
|
||||
# Validate if a container ID is available (cluster-aware)
|
||||
validate_container_id() {
|
||||
local ctid="$1"
|
||||
# Check if ID is numeric
|
||||
if ! [[ "$ctid" =~ ^[0-9]+$ ]]; then
|
||||
return 1
|
||||
[[ "$ctid" =~ ^[0-9]+$ ]] || return 1
|
||||
|
||||
# Cluster-wide check via pvesh
|
||||
if command -v pvesh &>/dev/null; then
|
||||
local cluster_ids
|
||||
cluster_ids=$(pvesh get /cluster/resources --type vm --output-format json 2>/dev/null |
|
||||
grep -oP '"vmid":\s*\K[0-9]+' 2>/dev/null || true)
|
||||
if [[ -n "$cluster_ids" ]] && echo "$cluster_ids" | grep -qw "$ctid"; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
# Check if config file exists for VM or LXC
|
||||
|
||||
# Local fallback
|
||||
if [[ -f "/etc/pve/qemu-server/${ctid}.conf" ]] || [[ -f "/etc/pve/lxc/${ctid}.conf" ]]; then
|
||||
return 1
|
||||
fi
|
||||
# Check if ID is used in LVM logical volumes
|
||||
|
||||
# Check all cluster nodes
|
||||
if [[ -d "/etc/pve/nodes" ]]; then
|
||||
for node_dir in /etc/pve/nodes/*/; do
|
||||
if [[ -f "${node_dir}qemu-server/${ctid}.conf" ]] || [[ -f "${node_dir}lxc/${ctid}.conf" ]]; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Check LVM volumes
|
||||
if lvs --noheadings -o lv_name 2>/dev/null | grep -qE "(^|[-_])${ctid}($|[-_])"; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
function get_valid_container_id() {
|
||||
local suggested_id="${1:-$(pvesh get /cluster/nextid)}"
|
||||
|
||||
get_valid_container_id() {
|
||||
local suggested_id="${1:-$(pvesh get /cluster/nextid 2>/dev/null || echo 100)}"
|
||||
while ! validate_container_id "$suggested_id"; do
|
||||
suggested_id=$((suggested_id + 1))
|
||||
done
|
||||
echo "$suggested_id"
|
||||
}
|
||||
function cleanup_ctid() {
|
||||
if pct status $CTID &>/dev/null; then
|
||||
if [ "$(pct status $CTID | awk '{print $2}')" == "running" ]; then
|
||||
pct stop $CTID
|
||||
|
||||
cleanup_ctid() {
|
||||
if pct status "$CTID" &>/dev/null; then
|
||||
if [[ "$(pct status "$CTID" | awk '{print $2}')" == "running" ]]; then
|
||||
pct stop "$CTID"
|
||||
fi
|
||||
pct destroy $CTID
|
||||
pct destroy "$CTID"
|
||||
fi
|
||||
}
|
||||
|
||||
select_storage() {
|
||||
local class="$1" content content_label
|
||||
case "$class" in
|
||||
container)
|
||||
content='rootdir'
|
||||
content_label='Container'
|
||||
;;
|
||||
template)
|
||||
content='vztmpl'
|
||||
content_label='Container template'
|
||||
;;
|
||||
*)
|
||||
msg_error "Invalid storage class '$class'"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
local -a MENU=()
|
||||
local MSG_MAX_LENGTH=0
|
||||
|
||||
while read -r line; do
|
||||
local TAG TYPE FREE ITEM OFFSET=2
|
||||
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 "
|
||||
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=$((${#ITEM} + OFFSET))
|
||||
MENU+=("$TAG" "$ITEM" "OFF")
|
||||
done < <(pvesm status -content "$content" | awk 'NR>1')
|
||||
|
||||
if [[ $((${#MENU[@]} / 3)) -eq 0 ]]; then
|
||||
msg_error "'$content_label' needs to be selected for at least one storage location."
|
||||
return 1
|
||||
elif [[ $((${#MENU[@]} / 3)) -eq 1 ]]; then
|
||||
printf '%s' "${MENU[0]}"
|
||||
else
|
||||
local STORAGE
|
||||
while [[ -z "${STORAGE:+x}" ]]; do
|
||||
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
|
||||
"Which storage pool for the ${content_label,,}?\n\n" \
|
||||
16 $((MSG_MAX_LENGTH + 23)) 6 \
|
||||
"${MENU[@]}" 3>&1 1>&2 2>&3) || exit_script
|
||||
done
|
||||
printf '%s' "$STORAGE"
|
||||
fi
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# MAIN
|
||||
# ==============================================================================
|
||||
|
||||
# Cleanup on error: destroy container, report telemetry, and restart monitor
|
||||
turnkey_cleanup() {
|
||||
local exit_code=$?
|
||||
if [[ $exit_code -ne 0 ]]; then
|
||||
# Report failure to telemetry
|
||||
if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
|
||||
post_update_to_api "failed" "$exit_code" 2>/dev/null || true
|
||||
fi
|
||||
# Destroy failed container
|
||||
if [[ -n "${CTID:-}" ]]; then
|
||||
cleanup_ctid 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
if [[ -f /etc/systemd/system/ping-instances.service ]]; then
|
||||
systemctl start ping-instances.service 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
trap turnkey_cleanup EXIT
|
||||
|
||||
# Stop Proxmox VE Monitor-All if running
|
||||
if systemctl is-active -q ping-instances.service; then
|
||||
systemctl stop ping-instances.service
|
||||
fi
|
||||
|
||||
pve_check
|
||||
shell_check
|
||||
root_check
|
||||
|
||||
# Read diagnostics preference (same logic as build.func diagnostics_check)
|
||||
DIAG_CONFIG="/usr/local/community-scripts/diagnostics"
|
||||
if [[ -f "$DIAG_CONFIG" ]]; then
|
||||
DIAGNOSTICS=$(awk -F '=' '/^DIAGNOSTICS/ {print $2}' "$DIAG_CONFIG") || true
|
||||
DIAGNOSTICS="${DIAGNOSTICS:-no}"
|
||||
fi
|
||||
|
||||
header_info
|
||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "TurnKey LXCs" --yesno "This will allow for the creation of one of the many TurnKey LXC Containers. Proceed?" 10 68
|
||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "TurnKey LXCs" --yesno \
|
||||
"This will allow for the creation of one of the many TurnKey LXC Containers. Proceed?" 10 68 || exit_script
|
||||
|
||||
# Update template catalog early so the menu reflects the latest available templates
|
||||
msg_info "Updating LXC template list"
|
||||
pveam update >/dev/null
|
||||
msg_ok "Updated LXC template list"
|
||||
|
||||
# Build TurnKey selection menu dynamically from available templates
|
||||
declare -A TURNKEY_TEMPLATES
|
||||
TURNKEY_MENU=()
|
||||
MSG_MAX_LENGTH=0
|
||||
while read -r TAG ITEM; do
|
||||
while IFS=$'\t' read -r TEMPLATE_FILE TAG ITEM; do
|
||||
TURNKEY_TEMPLATES["$TAG"]="$TEMPLATE_FILE"
|
||||
OFFSET=2
|
||||
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=${#ITEM}+OFFSET
|
||||
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=$((${#ITEM} + OFFSET))
|
||||
TURNKEY_MENU+=("$TAG" "$ITEM " "OFF")
|
||||
done < <(
|
||||
cat <<EOF
|
||||
ansible Ansible
|
||||
bookstack BookStack
|
||||
core Core
|
||||
faveo-helpdesk Faveo Helpdesk
|
||||
fileserver File Server
|
||||
gallery Gallery
|
||||
gameserver Game Server
|
||||
gitea Gitea
|
||||
gitlab GitLab
|
||||
invoice-ninja Invoice Ninja
|
||||
mediaserver Media Server
|
||||
nextcloud Nextcloud
|
||||
observium Observium
|
||||
odoo Odoo
|
||||
openldap OpenLDAP
|
||||
openvpn OpenVPN
|
||||
owncloud ownCloud
|
||||
phpbb phpBB
|
||||
torrentserver Torrent Server
|
||||
wireguard WireGuard
|
||||
wordpress Wordpress
|
||||
zoneminder ZoneMinder
|
||||
EOF
|
||||
)
|
||||
turnkey=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "TurnKey LXCs" --radiolist "\nSelect a TurnKey LXC to create:\n" 16 $((MSG_MAX_LENGTH + 58)) 6 "${TURNKEY_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
|
||||
[ -z "$turnkey" ] && {
|
||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No TurnKey LXC Selected" --msgbox "It appears that no TurnKey LXC container was selected" 10 68
|
||||
msg "Done"
|
||||
exit
|
||||
}
|
||||
done < <(pveam available -section turnkeylinux | awk '{
|
||||
tpl = $2
|
||||
if (match(tpl, /debian-([0-9]+)-turnkey-([^_]+)_([^_]+)_/, m)) {
|
||||
app = m[2]; deb = m[1]; ver = m[3]
|
||||
display = app
|
||||
gsub(/-/, " ", display)
|
||||
n = split(display, words, " ")
|
||||
display = ""
|
||||
for (i = 1; i <= n; i++) {
|
||||
words[i] = toupper(substr(words[i], 1, 1)) substr(words[i], 2)
|
||||
display = display (i > 1 ? " " : "") words[i]
|
||||
}
|
||||
tag = app "-" deb
|
||||
printf "%s\t%s\t%s | Debian %s | %s\n", tpl, tag, display, deb, ver
|
||||
}
|
||||
}' | sort -t$'\t' -k2,2)
|
||||
|
||||
# Setup script environment
|
||||
if [[ ${#TURNKEY_MENU[@]} -eq 0 ]]; then
|
||||
msg_error "No TurnKey templates found. Check your internet connection or template repository."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
selected=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "TurnKey LXCs" --radiolist \
|
||||
"\nSelect a TurnKey LXC to create:\n" 20 $((MSG_MAX_LENGTH + 58)) 12 \
|
||||
"${TURNKEY_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"') || exit_script
|
||||
|
||||
if [[ -z "$selected" ]]; then
|
||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No TurnKey LXC Selected" \
|
||||
--msgbox "It appears that no TurnKey LXC container was selected" 10 68
|
||||
exit_script
|
||||
fi
|
||||
|
||||
# Extract template filename and app name from selection
|
||||
TEMPLATE="${TURNKEY_TEMPLATES[$selected]}"
|
||||
turnkey="${selected%-*}"
|
||||
|
||||
# Generate random password
|
||||
PASS="$(openssl rand -base64 8)"
|
||||
# Prompt user to confirm container ID
|
||||
|
||||
# Prompt for Container ID
|
||||
NEXT_ID=$(pvesh get /cluster/nextid 2>/dev/null || echo 100)
|
||||
while true; do
|
||||
CTID=$(whiptail --backtitle "Container ID" --title "Choose the Container ID" --inputbox "Enter the container ID..." 8 40 $(pvesh get /cluster/nextid) 3>&1 1>&2 2>&3)
|
||||
CTID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Container ID" \
|
||||
--inputbox "Enter the container ID..." 8 40 "$NEXT_ID" 3>&1 1>&2 2>&3) || exit_script
|
||||
|
||||
# Check if user cancelled
|
||||
[ -z "$CTID" ] && die "No Container ID selected"
|
||||
if [[ -z "$CTID" ]]; then
|
||||
msg_error "No Container ID selected"
|
||||
exit_script
|
||||
fi
|
||||
|
||||
# Validate Container ID
|
||||
if ! validate_container_id "$CTID"; then
|
||||
SUGGESTED_ID=$(get_valid_container_id "$CTID")
|
||||
if whiptail --backtitle "Container ID" --title "ID Already In Use" --yesno "Container/VM ID $CTID is already in use.\n\nWould you like to use the next available ID ($SUGGESTED_ID)?" 10 58; then
|
||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "ID Already In Use" --yesno \
|
||||
"Container/VM ID $CTID is already in use.\n\nWould you like to use the next available ID ($SUGGESTED_ID)?" 10 58; then
|
||||
CTID="$SUGGESTED_ID"
|
||||
break
|
||||
fi
|
||||
# User declined, loop back to input
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
# Prompt user to confirm Hostname
|
||||
HOST_NAME=$(whiptail --backtitle "Hostname" --title "Choose the Hostname" --inputbox "Enter the containers Hostname..." 8 40 "turnkey-${turnkey}" 3>&1 1>&2 2>&3)
|
||||
PCT_OPTIONS="
|
||||
-features keyctl=1,nesting=1
|
||||
-hostname $HOST_NAME
|
||||
-tags community-script
|
||||
-onboot 1
|
||||
-cores 2
|
||||
-memory 2048
|
||||
-password $PASS
|
||||
-net0 name=eth0,bridge=vmbr0,ip=dhcp
|
||||
-unprivileged 1
|
||||
"
|
||||
DEFAULT_PCT_OPTIONS=(
|
||||
-arch $(dpkg --print-architecture)
|
||||
|
||||
# Prompt for Hostname
|
||||
HOST_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Hostname" \
|
||||
--inputbox "Enter the container hostname..." 8 40 "turnkey-${turnkey}" 3>&1 1>&2 2>&3) || exit_script
|
||||
|
||||
# Container options
|
||||
PCT_OPTIONS=(
|
||||
-features keyctl=1,nesting=1
|
||||
-hostname "$HOST_NAME"
|
||||
-tags community-script
|
||||
-onboot 1
|
||||
-cores 2
|
||||
-memory 2048
|
||||
-password "$PASS"
|
||||
-net0 name=eth0,bridge=vmbr0,ip=dhcp
|
||||
-unprivileged 1
|
||||
-arch "$(dpkg --print-architecture)"
|
||||
)
|
||||
|
||||
# Set the CONTENT and CONTENT_LABEL variables
|
||||
function select_storage() {
|
||||
local CLASS=$1
|
||||
local CONTENT
|
||||
local CONTENT_LABEL
|
||||
case $CLASS in
|
||||
container)
|
||||
CONTENT='rootdir'
|
||||
CONTENT_LABEL='Container'
|
||||
;;
|
||||
template)
|
||||
CONTENT='vztmpl'
|
||||
CONTENT_LABEL='Container template'
|
||||
;;
|
||||
*) false || die "Invalid storage class." ;;
|
||||
esac
|
||||
|
||||
# Query all storage locations
|
||||
local -a MENU
|
||||
while read -r line; do
|
||||
local TAG=$(echo $line | awk '{print $1}')
|
||||
local TYPE=$(echo $line | awk '{printf "%-10s", $2}')
|
||||
local FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
|
||||
local ITEM=" Type: $TYPE Free: $FREE "
|
||||
local OFFSET=2
|
||||
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
|
||||
local MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
|
||||
fi
|
||||
MENU+=("$TAG" "$ITEM" "OFF")
|
||||
done < <(pvesm status -content $CONTENT | awk 'NR>1')
|
||||
|
||||
# Select storage location
|
||||
if [ $((${#MENU[@]} / 3)) -eq 0 ]; then
|
||||
warn "'$CONTENT_LABEL' needs to be selected for at least one storage location."
|
||||
die "Unable to detect valid storage location."
|
||||
elif [ $((${#MENU[@]} / 3)) -eq 1 ]; then
|
||||
printf ${MENU[0]}
|
||||
else
|
||||
local STORAGE
|
||||
while [ -z "${STORAGE:+x}" ]; do
|
||||
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
|
||||
"Which storage pool would you like to use for the ${CONTENT_LABEL,,}?\n\n" \
|
||||
16 $(($MSG_MAX_LENGTH + 23)) 6 \
|
||||
"${MENU[@]}" 3>&1 1>&2 2>&3) || die "Menu aborted."
|
||||
done
|
||||
printf $STORAGE
|
||||
fi
|
||||
# Storage selection
|
||||
TEMPLATE_STORAGE=$(select_storage template) || {
|
||||
msg_error "Failed to select template storage"
|
||||
exit 1
|
||||
}
|
||||
msg_ok "Using '${BL}${TEMPLATE_STORAGE}${CL}' for template storage"
|
||||
|
||||
# Get template storage
|
||||
TEMPLATE_STORAGE=$(select_storage template)
|
||||
info "Using '$TEMPLATE_STORAGE' for template storage."
|
||||
CONTAINER_STORAGE=$(select_storage container) || {
|
||||
msg_error "Failed to select container storage"
|
||||
exit 1
|
||||
}
|
||||
msg_ok "Using '${BL}${CONTAINER_STORAGE}${CL}' for container storage"
|
||||
|
||||
# Get container storage
|
||||
CONTAINER_STORAGE=$(select_storage container)
|
||||
info "Using '$CONTAINER_STORAGE' for container storage."
|
||||
|
||||
# Update LXC template list
|
||||
msg "Updating LXC template list..."
|
||||
pveam update >/dev/null
|
||||
|
||||
# Get LXC template string
|
||||
mapfile -t TEMPLATES < <(pveam available -section turnkeylinux | awk -v turnkey="${turnkey}" '$0 ~ turnkey {print $2}' | sort -t - -k 2 -V)
|
||||
[ ${#TEMPLATES[@]} -gt 0 ] || die "Unable to find a template when searching for '${turnkey}'."
|
||||
TEMPLATE="${TEMPLATES[-1]}"
|
||||
|
||||
# Download LXC template
|
||||
if ! pveam list $TEMPLATE_STORAGE | grep -q $TEMPLATE; then
|
||||
msg "Downloading LXC template (Patience)..."
|
||||
pveam download $TEMPLATE_STORAGE $TEMPLATE >/dev/null ||
|
||||
die "A problem occured while downloading the LXC template."
|
||||
# Download template if not already cached
|
||||
if ! pveam list "$TEMPLATE_STORAGE" | grep -q "$TEMPLATE"; then
|
||||
msg_info "Downloading LXC template"
|
||||
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null || {
|
||||
msg_error "Failed to download LXC template '${TEMPLATE}'"
|
||||
exit 1
|
||||
}
|
||||
msg_ok "Downloaded LXC template"
|
||||
fi
|
||||
|
||||
# Create variable for 'pct' options
|
||||
PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}})
|
||||
[[ " ${PCT_OPTIONS[@]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs $CONTAINER_STORAGE:${PCT_DISK_SIZE:-8})
|
||||
# Add rootfs if not specified
|
||||
[[ " ${PCT_OPTIONS[*]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs "${CONTAINER_STORAGE}:${PCT_DISK_SIZE:-8}")
|
||||
|
||||
# Create LXC
|
||||
msg "Creating LXC container..."
|
||||
pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} ${PCT_OPTIONS[@]} >/dev/null ||
|
||||
die "A problem occured while trying to create container."
|
||||
# Set telemetry variables for the selected turnkey
|
||||
TELEMETRY_TYPE="turnkey"
|
||||
NSAPP="turnkey-${turnkey}"
|
||||
CT_TYPE=1
|
||||
DISK_SIZE="${PCT_DISK_SIZE:-8}"
|
||||
CORE_COUNT=2
|
||||
RAM_SIZE=2048
|
||||
var_os="turnkey"
|
||||
var_version="${turnkey}"
|
||||
|
||||
# Save password
|
||||
echo "TurnKey ${turnkey} password: ${PASS}" >>~/turnkey-${turnkey}.creds # file is located in the Proxmox root directory
|
||||
# Report installation start to telemetry
|
||||
post_to_api
|
||||
|
||||
# If turnkey is "OpenVPN", add access to the tun device
|
||||
TUN_DEVICE_REQUIRED=("openvpn") # Setup this way in case future turnkeys also need tun access
|
||||
# Create LXC container
|
||||
msg_info "Creating LXC container"
|
||||
pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >/dev/null || {
|
||||
msg_error "Failed to create container"
|
||||
exit 1
|
||||
}
|
||||
msg_ok "Created LXC container (ID: ${BL}${CTID}${CL})"
|
||||
|
||||
# Save credentials securely
|
||||
CREDS_FILE=~/turnkey-${turnkey}.creds
|
||||
echo "TurnKey ${turnkey} password: ${PASS}" >>"$CREDS_FILE"
|
||||
chmod 600 "$CREDS_FILE"
|
||||
|
||||
# Configure TUN device access for VPN-based turnkeys
|
||||
TUN_DEVICE_REQUIRED=("openvpn")
|
||||
if printf '%s\n' "${TUN_DEVICE_REQUIRED[@]}" | grep -qw "${turnkey}"; then
|
||||
info "${turnkey} requires access to /dev/net/tun on the host. Modifying the container configuration to allow this."
|
||||
echo "lxc.cgroup2.devices.allow: c 10:200 rwm" >>/etc/pve/lxc/${CTID}.conf
|
||||
echo "lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file 0 0" >>/etc/pve/lxc/${CTID}.conf
|
||||
msg_info "Configuring TUN device access for ${turnkey}"
|
||||
{
|
||||
echo "lxc.cgroup2.devices.allow: c 10:200 rwm"
|
||||
echo "lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file 0 0"
|
||||
} >>"/etc/pve/lxc/${CTID}.conf"
|
||||
msg_ok "TUN device access configured"
|
||||
sleep 5
|
||||
fi
|
||||
|
||||
# Start container
|
||||
msg "Starting LXC Container..."
|
||||
msg_info "Starting LXC container"
|
||||
pct start "$CTID"
|
||||
msg_ok "Started LXC container"
|
||||
sleep 10
|
||||
|
||||
# Get container IP
|
||||
set +euo pipefail # Turn off error checking
|
||||
max_attempts=5
|
||||
attempt=1
|
||||
# Detect container IP
|
||||
msg_info "Detecting IP address"
|
||||
IP=""
|
||||
while [[ $attempt -le $max_attempts ]]; do
|
||||
IP=$(pct exec $CTID ip a show dev eth0 | grep -oP 'inet \K[^/]+')
|
||||
if [[ -n $IP ]]; then
|
||||
for attempt in $(seq 1 5); do
|
||||
IP=$(pct exec "$CTID" -- ip -4 a show dev eth0 2>/dev/null | grep -oP 'inet \K[^/]+' || true)
|
||||
if [[ -n "$IP" ]]; then
|
||||
break
|
||||
else
|
||||
warn "Attempt $attempt: IP address not found. Pausing for 5 seconds..."
|
||||
sleep 5
|
||||
((attempt++))
|
||||
fi
|
||||
[[ $attempt -lt 5 ]] && sleep 5
|
||||
done
|
||||
|
||||
if [[ -z $IP ]]; then
|
||||
warn "Maximum number of attempts reached. IP address not found."
|
||||
if [[ -z "$IP" ]]; then
|
||||
msg_warn "IP address not found after 5 attempts"
|
||||
IP="NOT FOUND"
|
||||
else
|
||||
msg_ok "IP address: ${BL}${IP}${CL}"
|
||||
fi
|
||||
|
||||
# Start Proxmox VE Monitor-All if available
|
||||
if [[ -f /etc/systemd/system/ping-instances.service ]]; then
|
||||
systemctl start ping-instances.service
|
||||
fi
|
||||
# Report success to telemetry
|
||||
post_update_to_api "done" "none"
|
||||
|
||||
# Success message
|
||||
# Success summary
|
||||
header_info
|
||||
echo
|
||||
info "LXC container '$CTID' was successfully created, and its IP address is ${IP}."
|
||||
msg_ok "TurnKey ${BL}${turnkey}${CL} LXC container '${BL}${CTID}${CL}' was successfully created."
|
||||
echo
|
||||
info "Proceed to the LXC console to complete the setup."
|
||||
echo -e " ${TAB}${YW}IP Address:${CL} ${BL}${IP}${CL}"
|
||||
echo -e " ${TAB}${YW}Login:${CL} ${GN}root${CL}"
|
||||
echo -e " ${TAB}${YW}Password:${CL} ${GN}${PASS}${CL}"
|
||||
echo
|
||||
info "login: root"
|
||||
info "password: $PASS"
|
||||
info "(credentials also stored in the root user's root directory in the 'turnkey-${turnkey}.creds' file.)"
|
||||
echo -e " ${TAB}Proceed to the LXC console to complete the TurnKey setup."
|
||||
echo -e " ${TAB}Credentials stored in: ${BL}~/turnkey-${turnkey}.creds${CL}"
|
||||
echo
|
||||
|
||||
@@ -551,7 +551,7 @@ qm set $VMID \
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -631,7 +631,7 @@ rm -f "$WORK_FILE"
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -568,7 +568,7 @@ fi
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -639,7 +639,7 @@ msg_ok "Resized disk"
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -622,7 +622,7 @@ qm set $VMID \
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -546,7 +546,7 @@ qm set $VMID \
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -605,7 +605,7 @@ msg_ok "Resized disk to ${DISK_SIZE}"
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -737,7 +737,7 @@ done
|
||||
|
||||
msg_info "Creating a OPNsense VM"
|
||||
qm create $VMID -agent 1${MACHINE} -tablet 0 -localtime 1 -bios ovmf${CPU_TYPE} -cores $CORE_COUNT -memory $RAM_SIZE \
|
||||
-name $HN -tags proxmox-helper-scripts -net0 virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU -onboot 1 -ostype l26 -scsihw virtio-scsi-pci
|
||||
-name $HN -tags community-script -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 \
|
||||
@@ -750,7 +750,7 @@ qm resize $VMID scsi0 20G >/dev/null
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<img src='https://raw.githubusercontent.com/michelroegl-brunner/ProxmoxVE/refs/heads/develop/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -560,7 +560,7 @@ qm set $VMID \
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -462,7 +462,7 @@ qm set $VMID \
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -610,7 +610,7 @@ fi
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -542,7 +542,7 @@ qm set $VMID \
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@ qm set $VMID \
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -543,7 +543,7 @@ qm set $VMID \
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@ qm resize $VMID scsi0 ${DISK_SIZE} >/dev/null
|
||||
DESCRIPTION=$(
|
||||
cat <<EOF
|
||||
<div align='center'>
|
||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||
<a href='https://community-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;'/>
|
||||
</a>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user