This commit is contained in:
apulkin
2026-05-28 11:58:28 +03:00
commit 366ccb7b9a
42 changed files with 8475 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
apt install sudo curl mc -y
sudo apt install ca-certificates curl -y
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update -y
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Binary file not shown.
+10
View File
@@ -0,0 +1,10 @@
services:
metube:
image: alexta69/metube
container_name: metube
ports:
- "8081:8081"
volumes:
- /srv/dev-disk-by-uuid-eef2f1b6-0066-44ef-ad54-d187b0dd38a8/Downloads:/downloads
# test
+18
View File
@@ -0,0 +1,18 @@
services:
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
- WEBUI_PORT=8080
- TORRENTING_PORT=6881
volumes:
- /srv/dev-disk-by-uuid-d383ff21-3d21-4d7f-8aea-7ffd8d6ba073/Docker/qbittorrent/appdata:/config
- /srv/dev-disk-by-uuid-eef2f1b6-0066-44ef-ad54-d187b0dd38a8/Downloads:/downloads
ports:
- 8080:8080
- 6881:6881
- 6881:6881/udp
restart: unless-stopped
+17
View File
@@ -0,0 +1,17 @@
services:
victoria-logs:
image: victoriametrics/victoria-logs:latest
volumes:
- ./victoria-logs-data:/victoria-logs-data
command:
- --storageDataPath=/victoria-logs-data
- --retentionPeriod=90d
- --syslog.listenAddr.tcp=:514
- --syslog.listenAddr.udp=:514
- --syslog.streamFields.tcp='["hostname","app_name","priority","facility","severity"]'
- --syslog.streamFields.udp='["hostname","app_name","priority","facility","severity"]'
ports:
- 9428:9428
- 514:514
- 514:514/udp
restart: always
+602
View File
@@ -0,0 +1,602 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/vm/archlinux-vm.sh)"
#!/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 /dev/stdin <<<$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
function header_info {
clear
cat <<"EOF"
___ __ __ _ _ ____ ___
/ | __________/ /_ / / (_)___ __ ___ __ | | / / |/ /
/ /| | / ___/ ___/ __ \ / / / / __ \/ / / / |/_/ | | / / /|_/ /
/ ___ |/ / / /__/ / / / / /___/ / / / / /_/ /> < | |/ / / / /
/_/ |_/_/ \___/_/ /_/ /_____/_/_/ /_/\__,_/_/|_| |___/_/ /_/
EOF
}
header_info
echo -e "\n Loading..."
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
METHOD=""
NSAPP="archlinux-vm"
var_os="arch-linux"
var_version="n.d."
YW=$(echo "\033[33m")
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
BGN=$(echo "\033[4;92m")
GN=$(echo "\033[1;92m")
DGN=$(echo "\033[32m")
CL=$(echo "\033[m")
CL=$(echo "\033[m")
BOLD=$(echo "\033[1m")
BFR="\\r\\033[K"
HOLD=" "
TAB=" "
CM="${TAB}✔️${TAB}${CL}"
CROSS="${TAB}✖️${TAB}${CL}"
INFO="${TAB}💡${TAB}${CL}"
OS="${TAB}🖥️${TAB}${CL}"
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
DISKSIZE="${TAB}💾${TAB}${CL}"
CPUCORE="${TAB}🧠${TAB}${CL}"
RAMSIZE="${TAB}🛠️${TAB}${CL}"
CONTAINERID="${TAB}🆔${TAB}${CL}"
HOSTNAME="${TAB}🏠${TAB}${CL}"
BRIDGE="${TAB}🌉${TAB}${CL}"
GATEWAY="${TAB}🌐${TAB}${CL}"
DEFAULT="${TAB}⚙️${TAB}${CL}"
MACADDRESS="${TAB}🔗${TAB}${CL}"
VLANTAG="${TAB}🏷️${TAB}${CL}"
CREATING="${TAB}🚀${TAB}${CL}"
ADVANCED="${TAB}🧩${TAB}${CL}"
CLOUD="${TAB}☁️${TAB}${CL}"
THIN="discard=on,ssd=1,"
set -e
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
trap cleanup EXIT
trap 'post_update_to_api "failed" "130"' SIGINT
trap 'post_update_to_api "failed" "143"' SIGTERM
trap 'post_update_to_api "failed" "129"; exit 129' SIGHUP
function error_handler() {
local exit_code="$?"
local line_number="$1"
local command="$2"
local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
post_update_to_api "failed" "${exit_code}"
echo -e "\n$error_message\n"
cleanup_vmid
}
function get_valid_nextid() {
local try_id
try_id=$(pvesh get /cluster/nextid)
while true; do
if [ -f "/etc/pve/qemu-server/${try_id}.conf" ] || [ -f "/etc/pve/lxc/${try_id}.conf" ]; then
try_id=$((try_id + 1))
continue
fi
if lvs --noheadings -o lv_name | grep -qE "(^|[-_])${try_id}($|[-_])"; then
try_id=$((try_id + 1))
continue
fi
break
done
echo "$try_id"
}
function cleanup_vmid() {
if qm status $VMID &>/dev/null; then
qm stop $VMID &>/dev/null
qm destroy $VMID &>/dev/null
fi
}
function cleanup() {
local exit_code=$?
popd >/dev/null
if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
if [[ $exit_code -eq 0 ]]; then
post_update_to_api "done" "none"
else
post_update_to_api "failed" "$exit_code"
fi
fi
rm -rf $TEMP_DIR
}
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "Arch Linux VM" --yesno "This will create a New Arch Linux VM. Proceed?" 10 58; then
:
else
header_info && echo -e "${CROSS}${RD}User exited script${CL}\n" && exit
fi
function msg_info() {
local msg="$1"
echo -ne "${TAB}${YW}${HOLD}${msg}${HOLD}"
}
function msg_ok() {
local msg="$1"
echo -e "${BFR}${CM}${GN}${msg}${CL}"
}
function msg_error() {
local msg="$1"
echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
}
function check_root() {
if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
clear
msg_error "Please run this script as root."
echo -e "\nExiting..."
sleep 2
exit
fi
}
# This function checks the version of Proxmox Virtual Environment (PVE) and exits if the version is not supported.
# Supported: Proxmox VE 8.0.x 8.9.x, 9.0 and 9.2
pve_check() {
local PVE_VER
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
# Check for Proxmox VE 8.x: allow 8.08.9
if [[ "$PVE_VER" =~ ^8\.([0-9]+) ]]; then
local MINOR="${BASH_REMATCH[1]}"
if ((MINOR < 0 || MINOR > 9)); then
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported: Proxmox VE version 8.0 8.9"
exit 105
fi
return 0
fi
# Check for Proxmox VE 9.x: allow 9.0 and 9.2
if [[ "$PVE_VER" =~ ^9\.([0-9]+) ]]; then
local MINOR="${BASH_REMATCH[1]}"
if ((MINOR < 0 || MINOR > 2)); then
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported: Proxmox VE version 9.0 9.2"
exit 105
fi
return 0
fi
# All other unsupported versions
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported versions: Proxmox VE 8.0 8.x or 9.0 9.2"
exit 105
}
function arch_check() {
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n"
echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
echo -e "Exiting..."
sleep 2
exit
fi
}
function ssh_check() {
if command -v pveversion >/dev/null 2>&1; then
if [ -n "${SSH_CLIENT:+x}" ]; then
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then
echo "you've been warned"
else
clear
exit
fi
fi
fi
}
function exit-script() {
clear
echo -e "\n${CROSS}${RD}User exited script${CL}\n"
exit
}
function default_settings() {
VMID=$(get_valid_nextid)
MACHINE=""
DISK_SIZE="4G"
DISK_CACHE=""
HN="arch-linux"
CPU_TYPE=""
CORE_COUNT="1"
RAM_SIZE="1024"
BRG="vmbr0"
MAC="$GEN_MAC"
VLAN=""
MTU=""
START_VM="yes"
METHOD="default"
echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}${VMID}${CL}"
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}i440fx${CL}"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE}${CL}"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}${HN}${CL}"
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}KVM64${CL}"
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}"
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE}${CL}"
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}${BRG}${CL}"
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}${MAC}${CL}"
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}Default${CL}"
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}Default${CL}"
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}yes${CL}"
echo -e "${CREATING}${BOLD}${DGN}Creating a Arch Linux VM using the above default settings${CL}"
}
function advanced_settings() {
METHOD="advanced"
[ -z "${VMID:-}" ] && VMID=$(get_valid_nextid)
while true; do
if VMID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 "$VMID" --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$VMID" ]; then
VMID=$(get_valid_nextid)
fi
if pct status "$VMID" &>/dev/null || qm status "$VMID" &>/dev/null; then
echo -e "${CROSS}${RD} ID $VMID is already in use${CL}"
sleep 2
continue
fi
echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}$VMID${CL}"
break
else
exit-script
fi
done
if MACH=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \
"i440fx" "Machine i440fx" ON \
"q35" "Machine q35" OFF \
3>&1 1>&2 2>&3); then
if [ "$MACH" = q35 ]; then
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}$MACH${CL}"
MACHINE=" -machine q35"
else
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}$MACH${CL}"
MACHINE=""
fi
else
exit-script
fi
if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GiB (e.g., 10, 20)" 8 58 "$DISK_SIZE" --title "DISK SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
DISK_SIZE=$(echo "$DISK_SIZE" | tr -d ' ')
if [[ "$DISK_SIZE" =~ ^[0-9]+$ ]]; then
DISK_SIZE="${DISK_SIZE}G"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}$DISK_SIZE${CL}"
elif [[ "$DISK_SIZE" =~ ^[0-9]+G$ ]]; then
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}$DISK_SIZE${CL}"
else
echo -e "${DISKSIZE}${BOLD}${RD}Invalid Disk Size. Please use a number (e.g., 10 or 10G).${CL}"
exit-script
fi
else
exit-script
fi
if DISK_CACHE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
"0" "None (Default)" ON \
"1" "Write Through" OFF \
3>&1 1>&2 2>&3); then
if [ "$DISK_CACHE" = "1" ]; then
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}Write Through${CL}"
DISK_CACHE="cache=writethrough,"
else
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
DISK_CACHE=""
fi
else
exit-script
fi
if VM_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 arch-linux --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$VM_NAME" ]; then
HN="arch-linux"
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
else
HN=$(echo "${VM_NAME,,}" | tr -cs 'a-z0-9-' '-' | sed 's/^-//;s/-$//')
if [ "$HN" != "${VM_NAME,,}" ]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "HOSTNAME ADJUSTED" --msgbox "Invalid characters detected. Hostname has been adjusted to:\n\n $HN" 10 58
fi
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
fi
else
exit-script
fi
if CPU_TYPE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
"0" "KVM64 (Default)" ON \
"1" "Host" OFF \
3>&1 1>&2 2>&3); then
if [ "$CPU_TYPE1" = "1" ]; then
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}"
CPU_TYPE=" -cpu host"
else
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}KVM64${CL}"
CPU_TYPE=""
fi
else
exit-script
fi
while true; do
if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 2 --title "CORE COUNT" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$CORE_COUNT" ]; then CORE_COUNT="2"; fi
if [[ "$CORE_COUNT" =~ ^[1-9][0-9]*$ ]]; then
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "CPU Cores must be a positive integer (e.g., 2)." 8 58
else
exit-script
fi
done
while true; do
if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 2048 --title "RAM" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$RAM_SIZE" ]; then RAM_SIZE="2048"; fi
if [[ "$RAM_SIZE" =~ ^[1-9][0-9]*$ ]]; then
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}$RAM_SIZE${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "RAM Size must be a positive integer in MiB (e.g., 2048)." 8 58
else
exit-script
fi
done
if BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Bridge" 8 58 vmbr0 --title "BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$BRG" ]; then
BRG="vmbr0"
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
else
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
fi
else
exit-script
fi
while true; do
if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address" 8 58 "$GEN_MAC" --title "MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$MAC1" ]; then
MAC="$GEN_MAC"
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC${CL}"
break
fi
if [[ "$MAC1" =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]]; then
MAC="$MAC1"
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC1${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "Invalid MAC address format. Use XX:XX:XX:XX:XX:XX (e.g., AA:BB:CC:DD:EE:FF)." 8 58
else
exit-script
fi
done
while true; do
if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan(leave blank for default)" 8 58 --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$VLAN1" ]; then
VLAN1="Default"
VLAN=""
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$VLAN1${CL}"
break
fi
if [[ "$VLAN1" =~ ^[0-9]+$ ]] && [ "$VLAN1" -ge 1 ] && [ "$VLAN1" -le 4094 ]; then
VLAN=",tag=$VLAN1"
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$VLAN1${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "VLAN must be a number between 1 and 4094, or leave blank for default." 8 58
else
exit-script
fi
done
while true; do
if MTU1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 --title "MTU SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$MTU1" ]; then
MTU1="Default"
MTU=""
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}"
break
fi
if [[ "$MTU1" =~ ^[0-9]+$ ]] && [ "$MTU1" -ge 576 ] && [ "$MTU1" -le 65520 ]; then
MTU=",mtu=$MTU1"
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "MTU Size must be a number between 576 and 65520, or leave blank for default." 8 58
else
exit-script
fi
done
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "START VIRTUAL MACHINE" --yesno "Start VM when completed?" 10 58); then
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}yes${CL}"
START_VM="yes"
else
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}no${CL}"
START_VM="no"
fi
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create a Arch Linux VM?" --no-button Do-Over 10 58); then
echo -e "${CREATING}${BOLD}${DGN}Creating a Arch Linux VM using the above advanced settings${CL}"
else
header_info
echo -e "${ADVANCED}${BOLD}${RD}Using Advanced Settings${CL}"
advanced_settings
fi
}
function start_script() {
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno "Use Default Settings?" --no-button Advanced 10 58); then
header_info
echo -e "${DEFAULT}${BOLD}${BL}Using Default Settings${CL}"
default_settings
else
header_info
echo -e "${ADVANCED}${BOLD}${RD}Using Advanced Settings${CL}"
advanced_settings
fi
}
check_root
arch_check
pve_check
ssh_check
start_script
post_to_api_vm
msg_info "Validating Storage"
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
TYPE=$(echo "$line" | awk '{printf "%-10s", $2}')
FREE=$(echo "$line" | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
ITEM=" Type: $TYPE Free: $FREE "
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
STORAGE_MENU+=("$TAG" "$ITEM" "OFF")
done < <(pvesm status -content images | awk 'NR>1')
VALID=$(pvesm status -content images | awk 'NR>1')
if [ -z "$VALID" ]; then
msg_error "Unable to detect a valid storage location."
exit
elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
STORAGE=${STORAGE_MENU[0]}
else
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 ${HN}?\nTo make a selection, use the Spacebar.\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3)
done
fi
msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location."
msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}."
msg_info "Retrieving the URL for the Arch Linux .iso File"
URL=https://geo.mirror.pkgbuild.com/iso/latest/archlinux-x86_64.iso
sleep 2
msg_ok "${CL}${BL}${URL}${CL}"
curl -f#SL -o "$(basename "$URL")" "$URL"
echo -en "\e[1A\e[0K"
FILE=$(basename $URL)
msg_ok "Downloaded ${CL}${BL}${FILE}${CL}"
STORAGE_TYPE=$(pvesm status -storage "$STORAGE" | awk 'NR>1 {print $2}')
case $STORAGE_TYPE in
nfs | dir | cifs)
DISK_EXT=".qcow2"
DISK_REF="$VMID/"
DISK_IMPORT="--format qcow2"
THIN=""
;;
btrfs)
DISK_EXT=".raw"
DISK_REF="$VMID/"
DISK_IMPORT="--format raw"
THIN=""
;;
*)
DISK_EXT=""
DISK_REF=""
DISK_IMPORT="--format raw"
;;
esac
msg_info "Creating a Arch Linux VM"
qm create $VMID -agent 1${MACHINE} -tablet 0 -localtime 1 -bios ovmf${CPU_TYPE} -cores $CORE_COUNT -memory $RAM_SIZE \
-name $HN -tags community-script -net0 virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU -onboot 1 -ostype l26 -scsihw virtio-scsi-pci
if qm disk import --help >/dev/null 2>&1; then
IMPORT_CMD=(qm disk import)
else
IMPORT_CMD=(qm importdisk)
fi
IMPORT_OUT="$("${IMPORT_CMD[@]}" "$VMID" "${FILE}" "$STORAGE" ${DISK_IMPORT:-} 2>&1 || true)"
DISK_REF_IMPORTED="$(printf '%s\n' "$IMPORT_OUT" | sed -n "s/.*successfully imported disk '\([^']\+\)'.*/\1/p" | tr -d "\r\"'")"
[[ -z "$DISK_REF_IMPORTED" ]] && DISK_REF_IMPORTED="$(pvesm list "$STORAGE" | awk -v id="$VMID" '$5 ~ ("vm-"id"-disk-") {print $1":"$5}' | sort | tail -n1)"
[[ -z "$DISK_REF_IMPORTED" ]] && {
msg_error "Unable to determine imported disk reference."
echo "$IMPORT_OUT"
exit 226
}
msg_ok "Imported disk (${CL}${BL}${DISK_REF_IMPORTED}${CL})"
qm set $VMID \
-efidisk0 ${STORAGE}:0,efitype=4m \
-scsi0 ${DISK_REF_IMPORTED},${DISK_CACHE}${THIN%,} \
-ide2 ${STORAGE}:cloudinit \
-boot order=scsi0 \
-serial0 socket >/dev/null
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' 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>
<h2 style='font-size: 24px; margin: 20px 0;'>Arch Linux VM</h2>
<p style='margin: 16px 0;'>
<a href='https://ko-fi.com/community_scripts' target='_blank' rel='noopener noreferrer'>
<img src='https://img.shields.io/badge/&#x2615;-Buy us a coffee-blue' alt='spend Coffee' />
</a>
</p>
<span style='margin: 0 10px;'>
<i class="fa fa-github fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>GitHub</a>
</span>
<span style='margin: 0 10px;'>
<i class="fa fa-comments fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE/discussions' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Discussions</a>
</span>
<span style='margin: 0 10px;'>
<i class="fa fa-exclamation-circle fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE/issues' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Issues</a>
</span>
</div>
EOF
)
qm set $VMID -description "$DESCRIPTION" >/dev/null
if [ -n "$DISK_SIZE" ]; then
msg_info "Resizing disk to $DISK_SIZE GB"
qm resize $VMID scsi0 ${DISK_SIZE} >/dev/null
else
msg_info "Using default disk size of $DEFAULT_DISK_SIZE GB"
qm resize $VMID scsi0 ${DEFAULT_DISK_SIZE} >/dev/null
fi
msg_ok "Created a Arch Linux VM ${CL}${BL}(${HN})"
if [ "$START_VM" == "yes" ]; then
msg_info "Starting Arch Linux VM"
qm start $VMID
msg_ok "Started Arch Linux VM"
fi
post_update_to_api "done" "none"
msg_ok "Completed successfully!\n"
+40
View File
@@ -0,0 +1,40 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/cloudflare-ddns.sh)"
#!/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: edoardop13
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/favonia/cloudflare-ddns
APP="Cloudflare-DDNS"
var_tags="${var_tags:-network}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-3}"
var_os="${var_os:-debian}"
var_version="${var_version:-12}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /etc/systemd/system/cloudflare-ddns.service ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_error "There is no update function for ${APP}."
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
+75
View File
@@ -0,0 +1,75 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/elementsynapse.sh)"
Port
:8008
#!/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: tremor021
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/element-hq/synapse
APP="Element Synapse"
var_tags="${var_tags:-server}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
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 /etc/matrix-synapse ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs
msg_info "Updating LXC"
$STD apt update
$STD apt -y upgrade
msg_ok "Updated LXC"
if check_for_gh_release "synapse-admin" "etkecc/synapse-admin"; then
msg_info "Stopping Service"
systemctl stop synapse-admin
msg_ok "Stopped Service"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "synapse-admin" "etkecc/synapse-admin" "tarball" "latest" "/opt/synapse-admin"
msg_info "Building Synapse-Admin"
cd /opt/synapse-admin
$STD yarn global add serve
$STD yarn install --ignore-engines
$STD yarn build
mv ./dist ../ && rm -rf * && mv ../dist ./
msg_ok "Built Synapse-Admin"
msg_info "Starting Service"
systemctl start synapse-admin
msg_ok "Started Service"
msg_ok "Updated Synapse-Admin to ${CHECK_UPDATE_RELEASE}"
fi
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8008${CL}"
+68
View File
@@ -0,0 +1,68 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/grafana.sh)"
User
admin
Pass
admin
Port
:3000
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://grafana.com/
APP="Grafana"
var_tags="${var_tags:-monitoring;visualization}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if ! dpkg -s grafana >/dev/null 2>&1; then
msg_error "No ${APP} Installation Found!"
exit 233
fi
if [[ -f /etc/apt/sources.list.d/grafana.list ]] || [[ ! -f /etc/apt/sources.list.d/grafana.sources ]]; then
setup_deb822_repo \
"grafana" \
"https://apt.grafana.com/gpg.key" \
"https://apt.grafana.com" \
"stable" \
"main"
fi
msg_info "Updating Grafana LXC"
$STD apt update
$STD apt --only-upgrade install -y grafana
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
+90
View File
@@ -0,0 +1,90 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/homelable.sh)"
Install Profiles
Port
:3000
Default credentials
User
admin
Pass
admin
#!/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
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/Pouzor/homelable
APP="Homelable"
var_tags="${var_tags:-monitoring;network;visualization}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
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/homelable ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "homelable" "Pouzor/homelable"; then
msg_info "Stopping Service"
systemctl stop homelable
msg_ok "Stopped Service"
msg_info "Backing up Configuration and Data"
cp /opt/homelable/backend/.env /opt/homelable.env.bak
cp -r /opt/homelable/data /opt/homelable_data_bak
msg_ok "Backed up Configuration and Data"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "homelable" "Pouzor/homelable" "tarball" "latest" "/opt/homelable"
msg_info "Updating Python Dependencies"
cd /opt/homelable/backend
$STD uv venv --clear /opt/homelable/backend/.venv
$STD uv pip install --python /opt/homelable/backend/.venv/bin/python -r requirements.txt
msg_ok "Updated Python Dependencies"
msg_info "Rebuilding Frontend"
cd /opt/homelable/frontend
$STD npm ci
$STD npm run build
msg_ok "Rebuilt Frontend"
msg_info "Restoring Configuration and Data"
cp /opt/homelable.env.bak /opt/homelable/backend/.env
cp -r /opt/homelable_data_bak/. /opt/homelable/data/
rm -f /opt/homelable.env.bak
rm -rf /opt/homelable_data_bak
msg_ok "Restored Configuration and Data"
msg_info "Starting Service"
systemctl start homelable
msg_ok "Started Service"
msg_ok "Updated successfully!"
fi
exit
}
start
build_container
description
msg_ok "Completed Successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
+45
View File
@@ -0,0 +1,45 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/podman.sh)"
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://podman.io/
APP="Podman"
var_tags="${var_tags:-container;kubernetes}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /etc/containers/registries.conf ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Updating ${APP} LXC"
$STD apt update
$STD apt upgrade -y
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
+49
View File
@@ -0,0 +1,49 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/proxmox-mail-gateway.sh)"
#!/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: thost96 (thost96)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://www.proxmox.com/en/products/proxmox-mail-gateway
APP="Proxmox-Mail-Gateway"
var_tags="${var_tags:-mail}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}"
var_disk="${var_disk:-10}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -e /usr/bin/pmgproxy ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Updating Proxmox-Mail-Gateway"
$STD apt update
$STD apt upgrade -y
msg_ok "Updated Proxmox-Mail-Gateway"
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:8006/${CL}"
+103
View File
@@ -0,0 +1,103 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/loki.sh)"
Port
:3100
Debian: /etc/loki/config.yml | Alpine: /etc/loki/loki-local-config.yaml
#!/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: hoholms
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/grafana/loki
APP="Loki"
var_tags="${var_tags:-monitoring;logs}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}"
var_disk="${var_disk:-2}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if ! dpkg -s loki >/dev/null 2>&1; then
msg_error "No ${APP} Installation Found!"
exit 233
fi
CHOICE=$(msg_menu "Loki Update Options" \
"1" "Update Loki & Promtail" \
"2" "Allow 0.0.0.0 for listening" \
"3" "Allow only ${LOCAL_IP} for listening")
case $CHOICE in
1)
msg_info "Stopping Loki"
systemctl stop loki
if systemctl is-active --quiet promtail 2>/dev/null || dpkg -s promtail >/dev/null 2>&1; then
systemctl stop promtail
fi
msg_ok "Stopped Loki"
msg_info "Updating Loki"
$STD apt update
$STD apt install -y --only-upgrade loki
if dpkg -s promtail >/dev/null 2>&1; then
$STD apt install -y --only-upgrade promtail
fi
msg_ok "Updated Loki"
msg_info "Starting Loki"
systemctl start loki
if dpkg -s promtail >/dev/null 2>&1; then
systemctl start promtail
fi
msg_ok "Started Loki"
msg_ok "Updated successfully!"
exit
;;
2)
msg_info "Configuring Loki to listen on 0.0.0.0"
sed -i 's/http_listen_address:.*/http_listen_address: 0.0.0.0/' /etc/loki/config.yml
sed -i 's/http_listen_port:.*/http_listen_port: 3100/' /etc/loki/config.yml
systemctl restart loki
msg_ok "Configured Loki to listen on 0.0.0.0"
exit
;;
3)
msg_info "Configuring Loki to listen on ${LOCAL_IP}"
sed -i "s/http_listen_address:.*/http_listen_address: $LOCAL_IP/" /etc/loki/config.yml
sed -i 's/http_listen_port:.*/http_listen_port: 3100/' /etc/loki/config.yml
systemctl restart loki
msg_ok "Configured Loki to listen on ${LOCAL_IP}"
exit
;;
esac
exit 0
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access loki using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3100${CL}\n"
if dpkg -s promtail >/dev/null 2>&1; then
echo -e "${INFO}${YW} Access promtail using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9080${CL}"
fi
+89
View File
@@ -0,0 +1,89 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/mail-archiver.sh)"
Default credentials
User
admin
Pass
secure123!
:5000
#!/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: Slaviša Arežina (tremor021)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/s1t5/mail-archiver
APP="Mail-Archiver"
var_tags="${var_tags:-mail-archiver}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
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/mail-archiver ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
ensure_dependencies libgssapi-krb5-2
if check_for_gh_release "mail-archiver" "s1t5/mail-archiver"; then
msg_info "Stopping Mail-Archiver"
systemctl stop mail-archiver
msg_ok "Stopped Mail-Archiver"
msg_info "Creating Backup"
cp /opt/mail-archiver/appsettings.json /opt/mail-archiver/.env /opt/
[[ -d /opt/mail-archiver/DataProtection-Keys ]] && cp -r /opt/mail-archiver/DataProtection-Keys /opt
msg_ok "Created Backup"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "mail-archiver" "s1t5/mail-archiver" "tarball"
msg_info "Updating Mail-Archiver"
mv /opt/mail-archiver /opt/mail-archiver-build
cd /opt/mail-archiver-build
$STD dotnet restore
$STD dotnet publish -c Release -o /opt/mail-archiver
rm -rf /opt/mail-archiver-build
msg_ok "Updated Mail-Archiver"
msg_info "Restoring Backup"
cp /opt/appsettings.json /opt/.env /opt/mail-archiver
[[ -d /opt/DataProtection-Keys ]] && cp -r /opt/DataProtection-Keys /opt/mail-archiver/
msg_ok "Restored Backup"
msg_info "Starting Mail-Archiver"
systemctl start mail-archiver
msg_ok "Started Mail-Archiver"
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}:5000${CL}"
+50
View File
@@ -0,0 +1,50 @@
Port:5432
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/postgresql.sh)"
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://www.postgresql.org/
APP="PostgreSQL"
var_tags="${var_tags:-database}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if ! command -v psql >/dev/null 2>&1; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Updating ${APP} LXC"
$STD apt update
$STD apt -y upgrade
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}${IP}:5432${CL}"
+56
View File
@@ -0,0 +1,56 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/redis.sh)"
Config paths
Debian /etc/redis/redis.conf | Alpine: /etc/redis.conf
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://redis.io/
APP="Redis"
var_tags="${var_tags:-database}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /lib/systemd/system/redis-server.service ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Updating $APP LXC"
$STD apt update
$STD apt upgrade -y
msg_ok "Updated $APP LXC"
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}${IP}:6379${CL}"
+70
View File
@@ -0,0 +1,70 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/technitiumdns.sh)"
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://technitium.com/dns/
APP="Technitium DNS"
var_tags="${var_tags:-dns}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}"
var_disk="${var_disk:-2}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
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 /etc/dns ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if [[ -f /etc/systemd/system/dns.service ]]; then
mv /etc/systemd/system/dns.service /etc/systemd/system/technitium.service
systemctl daemon-reload
systemctl enable -q --now technitium
fi
if ! is_package_installed "aspnetcore-runtime-10.0"; then
$STD apt remove -y aspnetcore-runtime-8.0 aspnetcore-runtime-9.0 2>/dev/null || true
[ -f /etc/apt/sources.list.d/microsoft-prod.list ] && rm -f /etc/apt/sources.list.d/microsoft-prod.list
[ -f /usr/share/keyrings/microsoft-prod.gpg ] && rm -f /usr/share/keyrings/microsoft-prod.gpg
setup_deb822_repo \
"microsoft" \
"https://packages.microsoft.com/keys/microsoft-2025.asc" \
"https://packages.microsoft.com/debian/13/prod/" \
"trixie" \
"main"
$STD apt install -y aspnetcore-runtime-10.0
fi
RELEASE=$(curl -fsSL https://technitium.com/dns/ | grep -oP 'Version \K[\d.]+')
if [[ ! -f ~/.technitium || ${RELEASE} != "$(cat ~/.technitium 2>/dev/null)" ]]; then
fetch_and_deploy_from_url "https://download.technitium.com/dns/DnsServerPortable.tar.gz" /opt/technitium/dns
echo "${RELEASE}" >~/.technitium
systemctl restart technitium
msg_ok "Updated successfully!"
else
msg_ok "No update required. Technitium DNS is already at v${RELEASE}."
fi
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5380${CL}"
+72
View File
@@ -0,0 +1,72 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/uptimekuma.sh)"
Port
:3001
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://uptime.kuma.pet/ | Github: https://github.com/louislam/uptime-kuma
APP="Uptime Kuma"
var_tags="${var_tags:-analytics;monitoring}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
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/uptime-kuma ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
NODE_VERSION="22" setup_nodejs
ensure_dependencies chromium
if [[ ! -L /opt/uptime-kuma/chromium ]]; then
ln -s /usr/bin/chromium /opt/uptime-kuma/chromium
fi
if check_for_gh_release "uptime-kuma" "louislam/uptime-kuma"; then
msg_info "Stopping Service"
systemctl stop uptime-kuma
msg_ok "Stopped Service"
fetch_and_deploy_gh_release "uptime-kuma" "louislam/uptime-kuma" "tarball"
msg_info "Updating Uptime Kuma"
cd /opt/uptime-kuma
$STD npm install --omit dev
$STD npm run download-dist
msg_ok "Updated Uptime Kuma"
msg_info "Starting Service"
systemctl start uptime-kuma
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}:3001${CL}"
+670
View File
@@ -0,0 +1,670 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/vm/mikrotik-routeros.sh)"
#!/usr/bin/env bash
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
source /dev/stdin <<<$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
function header_info {
clear
cat <<"EOF"
__ ____ __ __ _ __ ____ __ ____ _____ ________ ______
/ |/ (_) /___________ / /_(_) /__ / __ \____ __ __/ /____ _____/ __ \/ ___/ / ____/ / / / __ \
/ /|_/ / / //_/ ___/ __ \/ __/ / //_/ / /_/ / __ \/ / / / __/ _ \/ ___/ / / /\__ \ / / / /_/ / /_/ /
/ / / / / ,< / / / /_/ / /_/ / ,< / _, _/ /_/ / /_/ / /_/ __/ / / /_/ /___/ / / /___/ __ / _, _/
/_/ /_/_/_/|_/_/ \____/\__/_/_/|_| /_/ |_|\____/\__,_/\__/\___/_/ \____//____/ \____/_/ /_/_/ |_|
EOF
}
header_info
echo -e "Loading..."
GEN_MAC=$(echo '00 60 2f'$(od -An -N3 -t xC /dev/urandom) | sed -e 's/ /:/g' | tr '[:lower:]' '[:upper:]')
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
METHOD=""
NSAPP="mikrotik-routeros"
var_os="mikrotik"
var_version=" "
DISK_SIZE="1G"
YW=$(echo "\033[33m")
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
BGN=$(echo "\033[4;92m")
GN=$(echo "\033[1;92m")
DGN=$(echo "\033[32m")
CL=$(echo "\033[m")
CL=$(echo "\033[m")
BOLD=$(echo "\033[1m")
BFR="\\r\\033[K"
HOLD=" "
TAB=" "
CM="${TAB}✔️${TAB}${CL}"
CROSS="${TAB}✖️${TAB}${CL}"
INFO="${TAB}💡${TAB}${CL}"
OS="${TAB}🖥️${TAB}${CL}"
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
DISKSIZE="${TAB}💾${TAB}${CL}"
CPUCORE="${TAB}🧠${TAB}${CL}"
RAMSIZE="${TAB}🛠️${TAB}${CL}"
CONTAINERID="${TAB}🆔${TAB}${CL}"
HOSTNAME="${TAB}🏠${TAB}${CL}"
BRIDGE="${TAB}🌉${TAB}${CL}"
GATEWAY="${TAB}🌐${TAB}${CL}"
DEFAULT="${TAB}⚙️${TAB}${CL}"
MACADDRESS="${TAB}🔗${TAB}${CL}"
VLANTAG="${TAB}🏷️${TAB}${CL}"
CREATING="${TAB}🚀${TAB}${CL}"
ADVANCED="${TAB}🧩${TAB}${CL}"
CLOUD="${TAB}☁️${TAB}${CL}"
THIN="discard=on,ssd=1,"
set -e
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
trap cleanup EXIT
trap 'post_update_to_api "failed" "130"' SIGINT
trap 'post_update_to_api "failed" "143"' SIGTERM
trap 'post_update_to_api "failed" "129"; exit 129' SIGHUP
function error_handler() {
local exit_code="$?"
local line_number="$1"
local command="$2"
local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
post_update_to_api "failed" "${exit_code}"
echo -e "\n$error_message\n"
cleanup_vmid
}
function get_valid_nextid() {
local try_id
try_id=$(pvesh get /cluster/nextid)
while true; do
if [ -f "/etc/pve/qemu-server/${try_id}.conf" ] || [ -f "/etc/pve/lxc/${try_id}.conf" ]; then
try_id=$((try_id + 1))
continue
fi
if lvs --noheadings -o lv_name | grep -qE "(^|[-_])${try_id}($|[-_])"; then
try_id=$((try_id + 1))
continue
fi
break
done
echo "$try_id"
}
function cleanup_vmid() {
if qm status $VMID &>/dev/null; then
qm stop $VMID &>/dev/null
qm destroy $VMID &>/dev/null
fi
}
function cleanup() {
local exit_code=$?
popd >/dev/null
if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
if [[ $exit_code -eq 0 ]]; then
post_update_to_api "done" "none"
else
post_update_to_api "failed" "$exit_code"
fi
fi
rm -rf $TEMP_DIR
}
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "Mikrotik RouterOS CHR VM" --yesno "This will create a Mikrotik RouterOS CHR VM. Proceed?" 10 58; then
:
else
header_info && echo -e "${CROSS}${RD}User exited script${CL}\n" && exit
fi
function msg_info() {
local msg="$1"
echo -ne "${TAB}${YW}${HOLD}${msg}${HOLD}"
}
function msg_ok() {
local msg="$1"
echo -e "${BFR}${CM}${GN}${msg}${CL}"
}
function msg_error() {
local msg="$1"
echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
}
function check_root() {
if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
clear
msg_error "Please run this script as root."
echo -e "\nExiting..."
sleep 2
exit
fi
}
# This function checks the version of Proxmox Virtual Environment (PVE) and exits if the version is not supported.
# Supported: Proxmox VE 8.0.x 8.9.x, 9.0 and 9.2
pve_check() {
local PVE_VER
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
# Check for Proxmox VE 8.x: allow 8.08.9
if [[ "$PVE_VER" =~ ^8\.([0-9]+) ]]; then
local MINOR="${BASH_REMATCH[1]}"
if ((MINOR < 0 || MINOR > 9)); then
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported: Proxmox VE version 8.0 8.9"
exit 105
fi
return 0
fi
# Check for Proxmox VE 9.x: allow 9.0 and 9.2
if [[ "$PVE_VER" =~ ^9\.([0-9]+) ]]; then
local MINOR="${BASH_REMATCH[1]}"
if ((MINOR < 0 || MINOR > 2)); then
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported: Proxmox VE version 9.0 9.2"
exit 105
fi
return 0
fi
# All other unsupported versions
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported versions: Proxmox VE 8.0 8.x or 9.0 9.2"
exit 105
}
function arch_check() {
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n"
echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
echo -e "Exiting..."
sleep 2
exit
fi
}
function ssh_check() {
if command -v pveversion >/dev/null 2>&1; then
if [ -n "${SSH_CLIENT:+x}" ]; then
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then
echo "you've been warned"
else
clear
exit
fi
fi
fi
}
function exit-script() {
clear
echo -e "\n${CROSS}${RD}User exited script${CL}\n"
exit
}
function default_settings() {
VMID=$(get_valid_nextid)
FORMAT=",efitype=4m"
MACHINE=""
DISK_SIZE="8G"
DISK_CACHE=""
HN="mikrotik-routeros-chr"
CPU_TYPE=""
CORE_COUNT="2"
RAM_SIZE="512"
BRG="vmbr0"
MAC="$GEN_MAC"
VLAN=""
MTU=""
START_VM="yes"
CLOUD_INIT="no"
METHOD="default"
echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}${VMID}${CL}"
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}i440fx${CL}"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE}${CL}"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}${HN}${CL}"
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}KVM64${CL}"
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}"
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE}${CL}"
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}${BRG}${CL}"
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}${MAC}${CL}"
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}Default${CL}"
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}Default${CL}"
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}yes${CL}"
echo -e "${CREATING}${BOLD}${DGN}Creating a Mikrotik RouterOS VM using the above default settings${CL}"
}
function get_mikrotik_version() {
local mode="$1"
local rss_url
local tree_name
case "$mode" in
s) rss_url="https://cdn.mikrotik.com/routeros/latest-stable.rss" ;;
d) rss_url="https://cdn.mikrotik.com/routeros/latest-development.rss" ;;
l) rss_url="https://cdn.mikrotik.com/routeros/latest-long-term.rss" ;;
t) rss_url="https://cdn.mikrotik.com/routeros/latest-testing.rss" ;;
*) return 0 ;;
esac
local rss_content
rss_content=$(curl -fsSL $rss_url 2>/dev/null)
if [ -n "$rss_content" ]; then
local version
version=$(echo "$rss_content" | grep -oP '<title>RouterOS \K[0-9.]+(?= \[)' 2>/dev/null || echo "$rss_content" | sed -n 's/.*<title>RouterOS \([0-9.]\+\) \[.*/\1/p' 2>/dev/null)
if [[ "$version" =~ ^[0-9]+\.[0-9]+ ]]; then
echo "$version"
return 0
fi
fi
case "$mode" in
s) tree_name="Stable release tree" ;;
d) tree_name="Development release tree" ;;
l) tree_name="Long-term release tree" ;;
t) tree_name="Testing release tree" ;;
esac
local html
html=$(curl -fsSL "https://mikrotik.com/download/changelogs" 2>/dev/null)
if [ -n "$html" ]; then
local start_line
start_line=$(echo "$html" | grep -n "$tree_name" | cut -d: -f1 | head -n1)
if [[ "$start_line" =~ ^[0-9]+$ ]]; then
local line
line=$(echo "$html" | tail -n +"$start_line" | grep -m 1 -E "c-(stable|longTerm|testing|development)-v|RouterOS [0-9]+\.[0-9]+" 2>/dev/null)
local version
version=$(echo "$line" | sed -n 's/.*c-[^"]*-v\([0-9_.a-zA-Z-]\+\).*/\1/p' | tr '_' '.' 2>/dev/null)
[ -z "$version" ] && version=$(echo "$line" | grep -oP 'RouterOS \K[0-9]+\.[0-9]+(\.[0-9]+)?' 2>/dev/null)
if [[ "$version" =~ ^[0-9]+\.[0-9]+ ]]; then
echo "$version"
return 0
fi
fi
fi
for minor in $(seq 50 -1 15); do
local test_version="7.${minor}"
if curl -fsSL -I "https://download.mikrotik.com/routeros/${test_version}/chr-${test_version}.img.zip" 2>/dev/null | grep -q "200 OK"; then
echo "$test_version"
return 0
fi
done
return 0
}
function advanced_settings() {
METHOD="advanced"
[ -z "${VMID:-}" ] && VMID=$(get_valid_nextid)
while true; do
if VMID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 $VMID --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$VMID" ]; then
VMID=$(get_valid_nextid)
fi
if pct status "$VMID" &>/dev/null || qm status "$VMID" &>/dev/null; then
echo -e "${CROSS}${RD} ID $VMID is already in use${CL}"
sleep 2
continue
fi
echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}$VMID${CL}"
break
else
exit-script
fi
done
if MACH=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \
"i440fx" "Machine i440fx" ON \
"q35" "Machine q35" OFF \
3>&1 1>&2 2>&3); then
if [ $MACH = q35 ]; then
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}$MACH${CL}"
FORMAT=""
MACHINE=" -machine q35"
else
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}$MACH${CL}"
FORMAT=",efitype=4m"
MACHINE=""
fi
else
exit-script
fi
if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GiB (e.g., 10, 20)" 8 58 "$DISK_SIZE" --title "DISK SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
DISK_SIZE=$(echo "$DISK_SIZE" | tr -d ' ')
if [[ "$DISK_SIZE" =~ ^[0-9]+$ ]]; then
DISK_SIZE="${DISK_SIZE}G"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}$DISK_SIZE${CL}"
elif [[ "$DISK_SIZE" =~ ^[0-9]+G$ ]]; then
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}$DISK_SIZE${CL}"
else
echo -e "${DISKSIZE}${BOLD}${RD}Invalid Disk Size. Please use a number (e.g., 10 or 10G).${CL}"
exit-script
fi
else
exit-script
fi
if DISK_CACHE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
"0" "None (Default)" ON \
"1" "Write Through" OFF \
3>&1 1>&2 2>&3); then
if [ $DISK_CACHE = "1" ]; then
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}Write Through${CL}"
DISK_CACHE="cache=writethrough,"
else
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
DISK_CACHE=""
fi
else
exit-script
fi
if VM_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 mikrotik-routeros-chr --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $VM_NAME ]; then
HN="mikrotik-routeros-chr"
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
else
HN=$(echo "${VM_NAME,,}" | tr -cs 'a-z0-9-' '-' | sed 's/^-//;s/-$//')
if [ "$HN" != "${VM_NAME,,}" ]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "HOSTNAME ADJUSTED" --msgbox "Invalid characters detected. Hostname has been adjusted to:\n\n $HN" 10 58
fi
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
fi
else
exit-script
fi
if CPU_TYPE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
"0" "KVM64 (Default)" ON \
"1" "Host" OFF \
3>&1 1>&2 2>&3); then
if [ $CPU_TYPE1 = "1" ]; then
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}"
CPU_TYPE=" -cpu host"
else
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}KVM64${CL}"
CPU_TYPE=""
fi
else
exit-script
fi
while true; do
if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 2 --title "CORE COUNT" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$CORE_COUNT" ]; then CORE_COUNT="2"; fi
if [[ "$CORE_COUNT" =~ ^[1-9][0-9]*$ ]]; then
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "CPU Cores must be a positive integer (e.g., 2)." 8 58
else
exit-script
fi
done
while true; do
if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 2048 --title "RAM" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$RAM_SIZE" ]; then RAM_SIZE="2048"; fi
if [[ "$RAM_SIZE" =~ ^[1-9][0-9]*$ ]]; then
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}$RAM_SIZE${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "RAM Size must be a positive integer in MiB (e.g., 2048)." 8 58
else
exit-script
fi
done
if BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Bridge" 8 58 vmbr0 --title "BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $BRG ]; then
BRG="vmbr0"
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
else
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
fi
else
exit-script
fi
while true; do
if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address" 8 58 $GEN_MAC --title "MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$MAC1" ]; then
MAC="$GEN_MAC"
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC${CL}"
break
fi
if [[ "$MAC1" =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]]; then
MAC="$MAC1"
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC1${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "Invalid MAC address format. Use XX:XX:XX:XX:XX:XX (e.g., AA:BB:CC:DD:EE:FF)." 8 58
else
exit-script
fi
done
while true; do
if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan(leave blank for default)" 8 58 --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$VLAN1" ]; then
VLAN1="Default"
VLAN=""
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$VLAN1${CL}"
break
fi
if [[ "$VLAN1" =~ ^[0-9]+$ ]] && [ "$VLAN1" -ge 1 ] && [ "$VLAN1" -le 4094 ]; then
VLAN=",tag=$VLAN1"
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$VLAN1${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "VLAN must be a number between 1 and 4094, or leave blank for default." 8 58
else
exit-script
fi
done
while true; do
if MTU1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 --title "MTU SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$MTU1" ]; then
MTU1="Default"
MTU=""
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}"
break
fi
if [[ "$MTU1" =~ ^[0-9]+$ ]] && [ "$MTU1" -ge 576 ] && [ "$MTU1" -le 65520 ]; then
MTU=",mtu=$MTU1"
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "MTU Size must be a number between 576 and 65520, or leave blank for default." 8 58
else
exit-script
fi
done
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "START VIRTUAL MACHINE" --yesno "Start VM when completed?" 10 58); then
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}yes${CL}"
START_VM="yes"
else
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}no${CL}"
START_VM="no"
fi
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create a Mikrotik RouterOS CHR VM?" --no-button Do-Over 10 58); then
echo -e "${CREATING}${BOLD}${DGN}Creating a Mikrotik RouterOS CHR VM using the above advanced settings${CL}"
else
header_info
echo -e "${ADVANCED}${BOLD}${RD}Using Advanced Settings${CL}"
advanced_settings
fi
}
function start_script() {
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno "Use Default Settings?" --no-button Advanced 10 58); then
header_info
echo -e "${DEFAULT}${BOLD}${BL}Using Default Settings${CL}"
default_settings
else
header_info
echo -e "${ADVANCED}${BOLD}${RD}Using Advanced Settings${CL}"
advanced_settings
fi
}
check_root
arch_check
pve_check
ssh_check
start_script
post_to_api_vm
msg_info "Validating Storage"
while read -r line; do
TAG=$(echo $line | awk '{print $1}')
TYPE=$(echo $line | awk '{printf "%-10s", $2}')
FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
ITEM=" Type: $TYPE Free: $FREE "
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
STORAGE_MENU+=("$TAG" "$ITEM" "OFF")
done < <(pvesm status -content images | awk 'NR>1')
VALID=$(pvesm status -content images | awk 'NR>1')
if [ -z "$VALID" ]; then
echo -e "\n${RD}⚠ Unable to detect a valid storage location.${CL}"
echo -e "Exiting..."
exit
elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
STORAGE=${STORAGE_MENU[0]}
else
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 Mikrotik RouterOS CHR VM?\n\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3)
done
fi
msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location."
msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}."
msg_info "Getting URL for Latest Mikrotik RouterOS CHR Disk Image"
MIK_VER=$(get_mikrotik_version s)
if [ -n "$MIK_VER" ]; then
msg_ok "Latest stable version: ${CL}${BL}$MIK_VER${CL}."
else
msg_error "Could not get latest version"
msg_ok "Defaulting to version 7.20"
MIK_VER="7.20"
fi
URL=https://download.mikrotik.com/routeros/$MIK_VER/chr-$MIK_VER.img.zip
sleep 2
msg_ok "Downloading from URL: ${CL}${BL}${URL}${CL}"
curl -f#SL -o "$(basename "$URL")" "$URL"
echo -en "\e[1A\e[0K"
FILE=$(basename $URL)
msg_ok "Downloaded ${CL}${BL}$FILE${CL}"
msg_info "Extracting Mikrotik RouterOS CHR Disk Image"
gunzip -f -S .zip $FILE
STORAGE_TYPE=$(pvesm status -storage $STORAGE | awk 'NR>1 {print $2}')
case $STORAGE_TYPE in
nfs | dir)
DISK_EXT=".qcow2"
DISK_REF="$VMID/"
DISK_IMPORT="-format qcow2"
;;
btrfs)
DISK_EXT=".raw"
DISK_REF="$VMID/"
DISK_IMPORT="-format raw"
;;
zfspool)
DISK_EXT=""
DISK_REF=""
DISK_IMPORT="-format raw"
;;
*)
DISK_EXT=""
DISK_REF=""
DISK_IMPORT="-format raw"
;;
esac
DISK_VAR="vm-${VMID}-disk-0${DISK_EXT:-}"
DISK_REF="${STORAGE}:${DISK_REF:-}${DISK_VAR:-}"
msg_ok "Extracted Mikrotik RouterOS CHR Disk Image"
msg_info "Creating Mikrotik RouterOS CHR VM"
qm create $VMID -tablet 0 -localtime 1 -cores $CORE_COUNT -memory $RAM_SIZE -name $HN \
-tags community-script -net0 virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU \
-onboot 1 -ostype l26 -scsihw virtio-scsi-pci
qm importdisk $VMID ${FILE%.*} $STORAGE ${DISK_IMPORT:-} 1>&/dev/null
qm set $VMID \
-scsi0 "$DISK_REF" \
-boot order=scsi0 >/dev/null
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' 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>
<h2 style='font-size: 24px; margin: 20px 0;'>Mikrotik RouterOS CHR</h2>
<p style='margin: 16px 0;'>
<a href='https://ko-fi.com/community_scripts' target='_blank' rel='noopener noreferrer'>
<img src='https://img.shields.io/badge/&#x2615;-Buy us a coffee-blue' alt='spend Coffee' />
</a>
</p>
<span style='margin: 0 10px;'>
<i class="fa fa-github fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>GitHub</a>
</span>
<span style='margin: 0 10px;'>
<i class="fa fa-comments fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE/discussions' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Discussions</a>
</span>
<span style='margin: 0 10px;'>
<i class="fa fa-exclamation-circle fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE/issues' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Issues</a>
</span>
</div>
EOF
)
qm set $VMID -description "$DESCRIPTION" >/dev/null
if [ -n "$DISK_SIZE" ]; then
msg_info "Resizing disk to $DISK_SIZE GB"
qm resize $VMID scsi0 ${DISK_SIZE} >/dev/null
else
msg_info "Using default disk size of $DEFAULT_DISK_SIZE GB"
qm resize $VMID scsi0 ${DEFAULT_DISK_SIZE} >/dev/null
fi
msg_ok "Mikrotik RouterOS CHR VM ${CL}${BL}(${HN})"
if [ "$START_VM" == "yes" ]; then
msg_info "Starting Mikrotik RouterOS CHR VM"
qm start $VMID
msg_ok "Started Mikrotik RouterOS CHR VM"
fi
post_update_to_api "done" "none"
msg_ok "Completed successfully!\n"
+699
View File
@@ -0,0 +1,699 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/vm/openwrt-vm.sh)"
#!/usr/bin/env bash
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# Jon Spriggs (jontheniceguy)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Based on work from https://i12bretro.github.io/tutorials/0405.html
source /dev/stdin <<<$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
function header_info {
clear
cat <<"EOF"
____ _ __ __
/ __ \____ ___ ____| | / /____/ /_
/ / / / __ \/ _ \/ __ \ | /| / / ___/ __/
/ /_/ / /_/ / __/ / / / |/ |/ / / / /_
\____/ .___/\___/_/ /_/|__/|__/_/ \__/
/_/ W I R E L E S S F R E E D O M
EOF
}
header_info
echo -e "\n Loading..."
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
METHOD=""
NSAPP="openwrt-vm"
var_os="openwrt"
var_version=" "
DISK_SIZE="1G"
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
GEN_MAC_LAN=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
YW=$(echo "\033[33m")
BL=$(echo "\033[36m")
HA=$(echo "\033[1;34m")
RD=$(echo "\033[01;31m")
BGN=$(echo "\033[4;92m")
GN=$(echo "\033[1;92m")
DGN=$(echo "\033[32m")
CL=$(echo "\033[m")
BOLD=$(echo "\033[1m")
BFR="\\r\\033[K"
HOLD=" "
TAB=" "
CM="${TAB}✔️${TAB}${CL}"
CROSS="${TAB}✖️${TAB}${CL}"
INFO="${TAB}💡${TAB}${CL}"
OS="${TAB}🖥️${TAB}${CL}"
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
DISKSIZE="${TAB}💾${TAB}${CL}"
CPUCORE="${TAB}🧠${TAB}${CL}"
RAMSIZE="${TAB}🛠️${TAB}${CL}"
CONTAINERID="${TAB}🆔${TAB}${CL}"
HOSTNAME="${TAB}🏠${TAB}${CL}"
BRIDGE="${TAB}🌉${TAB}${CL}"
GATEWAY="${TAB}🌐${TAB}${CL}"
DEFAULT="${TAB}⚙️${TAB}${CL}"
MACADDRESS="${TAB}🔗${TAB}${CL}"
VLANTAG="${TAB}🏷️${TAB}${CL}"
CREATING="${TAB}🚀${TAB}${CL}"
ADVANCED="${TAB}🧩${TAB}${CL}"
CLOUD="${TAB}☁️${TAB}${CL}"
set -Eeo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
trap cleanup EXIT
trap 'post_update_to_api "failed" "130"' SIGINT
trap 'post_update_to_api "failed" "143"' SIGTERM
trap 'post_update_to_api "failed" "129"; exit 129' SIGHUP
function error_handler() {
local exit_code="$?"
local line_number="$1"
local command="$2"
post_update_to_api "failed" "$exit_code"
local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
echo -e "\n$error_message\n"
cleanup_vmid
}
function get_valid_nextid() {
local try_id
try_id=$(pvesh get /cluster/nextid)
while true; do
if [ -f "/etc/pve/qemu-server/${try_id}.conf" ] || [ -f "/etc/pve/lxc/${try_id}.conf" ]; then
try_id=$((try_id + 1))
continue
fi
if lvs --noheadings -o lv_name | grep -qE "(^|[-_])${try_id}($|[-_])"; then
try_id=$((try_id + 1))
continue
fi
break
done
echo "$try_id"
}
function cleanup_vmid() {
if qm status $VMID &>/dev/null; then
qm stop $VMID &>/dev/null
qm destroy $VMID &>/dev/null
fi
}
function cleanup() {
local exit_code=$?
popd >/dev/null
if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
if [[ $exit_code -eq 0 ]]; then
post_update_to_api "done" "none"
else
post_update_to_api "failed" "$exit_code"
fi
fi
rm -rf $TEMP_DIR
}
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
function send_line_to_vm() {
echo -e "${DGN}Sending line: ${YW}$1${CL}"
for ((i = 0; i < ${#1}; i++)); do
character=${1:i:1}
case $character in
" ") character="spc" ;;
"-") character="minus" ;;
"=") character="equal" ;;
",") character="comma" ;;
".") character="dot" ;;
"/") character="slash" ;;
"'") character="apostrophe" ;;
";") character="semicolon" ;;
'\') character="backslash" ;;
'`') character="grave_accent" ;;
"[") character="bracket_left" ;;
"]") character="bracket_right" ;;
"_") character="shift-minus" ;;
"+") character="shift-equal" ;;
"?") character="shift-slash" ;;
"<") character="shift-comma" ;;
">") character="shift-dot" ;;
'"') character="shift-apostrophe" ;;
":") character="shift-semicolon" ;;
"|") character="shift-backslash" ;;
"~") character="shift-grave_accent" ;;
"{") character="shift-bracket_left" ;;
"}") character="shift-bracket_right" ;;
"A") character="shift-a" ;;
"B") character="shift-b" ;;
"C") character="shift-c" ;;
"D") character="shift-d" ;;
"E") character="shift-e" ;;
"F") character="shift-f" ;;
"G") character="shift-g" ;;
"H") character="shift-h" ;;
"I") character="shift-i" ;;
"J") character="shift-j" ;;
"K") character="shift-k" ;;
"L") character="shift-l" ;;
"M") character="shift-m" ;;
"N") character="shift-n" ;;
"O") character="shift-o" ;;
"P") character="shift-p" ;;
"Q") character="shift-q" ;;
"R") character="shift-r" ;;
"S") character="shift-s" ;;
"T") character="shift-t" ;;
"U") character="shift-u" ;;
"V") character="shift-v" ;;
"W") character="shift-w" ;;
"X") character="shift=x" ;;
"Y") character="shift-y" ;;
"Z") character="shift-z" ;;
"!") character="shift-1" ;;
"@") character="shift-2" ;;
"#") character="shift-3" ;;
'$') character="shift-4" ;;
"%") character="shift-5" ;;
"^") character="shift-6" ;;
"&") character="shift-7" ;;
"*") character="shift-8" ;;
"(") character="shift-9" ;;
")") character="shift-0" ;;
esac
qm sendkey $VMID "$character"
done
qm sendkey $VMID ret
}
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "OpenWrt VM" --yesno "This will create a New OpenWrt VM. Proceed?" 10 58); then
:
else
header_info && echo -e "⚠ User exited script \n" && exit
fi
function msg_info() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
function msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
function msg_error() {
local msg="$1"
echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}"
}
# This function checks the version of Proxmox Virtual Environment (PVE) and exits if the version is not supported.
# Supported: Proxmox VE 8.0.x 8.9.x, 9.0 and 9.2
pve_check() {
local PVE_VER
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
# Check for Proxmox VE 8.x: allow 8.08.9
if [[ "$PVE_VER" =~ ^8\.([0-9]+) ]]; then
local MINOR="${BASH_REMATCH[1]}"
if ((MINOR < 0 || MINOR > 9)); then
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported: Proxmox VE version 8.0 8.9"
exit 105
fi
return 0
fi
# Check for Proxmox VE 9.x: allow 9.0 and 9.2
if [[ "$PVE_VER" =~ ^9\.([0-9]+) ]]; then
local MINOR="${BASH_REMATCH[1]}"
if ((MINOR < 0 || MINOR > 2)); then
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported: Proxmox VE version 9.0 9.2"
exit 105
fi
return 0
fi
# All other unsupported versions
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported versions: Proxmox VE 8.0 8.x or 9.0 9.2"
exit 105
}
function arch_check() {
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
echo -e "\n ${CROSS} This script will not work with PiMox! \n"
echo -e "Exiting..."
sleep 2
exit
fi
}
function ssh_check() {
if command -v pveversion >/dev/null 2>&1; then
if [ -n "${SSH_CLIENT:+x}" ]; then
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then
echo "you've been warned"
else
clear
exit
fi
fi
fi
}
function exit-script() {
clear
echo -e "⚠ User exited script \n"
exit
}
function default_settings() {
VMID=$(get_valid_nextid)
HN="openwrt"
CORE_COUNT="1"
RAM_SIZE="256"
BRG="vmbr0"
LAN_BRG="vmbr0"
MAC=$GEN_MAC
LAN_MAC=$GEN_MAC_LAN
VLAN=""
LAN_VLAN=""
LAN_IP_ADDR="192.168.1.1"
LAN_NETMASK="255.255.255.0"
MTU=""
START_VM="yes"
METHOD="default"
DISK_SIZE="1G"
echo -e "${CONTAINERID}${BOLD}${DGN}VMID: ${BGN}${VMID}${CL}"
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}${HN}${CL}"
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}"
echo -e "${RAMSIZE}${BOLD}${DGN}RAM: ${BGN}${RAM_SIZE}${CL}"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE}${CL}"
echo -e "${BRIDGE}${BOLD}${DGN}WAN Bridge: ${BGN}${BRG}${CL}"
echo -e "${BRIDGE}${BOLD}${DGN}LAN Bridge: ${BGN}${LAN_BRG}${CL}"
echo -e "${MACADDRESS}${BOLD}${DGN}WAN MAC: ${BGN}${MAC}${CL}"
echo -e "${MACADDRESS}${BOLD}${DGN}LAN MAC: ${BGN}${LAN_MAC}${CL}"
}
function advanced_settings() {
METHOD="advanced"
[ -z "${VMID:-}" ] && VMID=$(get_valid_nextid)
while true; do
if VMID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 $VMID --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$VMID" ]; then
VMID=$(get_valid_nextid)
fi
if pct status "$VMID" &>/dev/null || qm status "$VMID" &>/dev/null; then
echo -e "${CROSS}${RD} ID $VMID is already in use${CL}"
sleep 2
continue
fi
echo -e "${DGN}Virtual Machine ID: ${BGN}$VMID${CL}"
break
else
exit-script
fi
done
if VM_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 openwrt --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $VM_NAME ]; then
HN="openwrt"
else
HN=$(echo "${VM_NAME,,}" | tr -cs 'a-z0-9-' '-' | sed 's/^-//;s/-$//')
if [ "$HN" != "${VM_NAME,,}" ]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "HOSTNAME ADJUSTED" --msgbox "Invalid characters detected. Hostname has been adjusted to:\n\n $HN" 10 58
fi
fi
echo -e "${DGN}Using Hostname: ${BGN}$HN${CL}"
else
exit-script
fi
while true; do
if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 1 --title "CORE COUNT" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$CORE_COUNT" ]; then CORE_COUNT="1"; fi
if [[ "$CORE_COUNT" =~ ^[1-9][0-9]*$ ]]; then
echo -e "${DGN}Allocated Cores: ${BGN}$CORE_COUNT${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "CPU Cores must be a positive integer (e.g., 1)." 8 58
else
exit-script
fi
done
while true; do
if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 256 --title "RAM" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$RAM_SIZE" ]; then RAM_SIZE="256"; fi
if [[ "$RAM_SIZE" =~ ^[1-9][0-9]*$ ]]; then
echo -e "${DGN}Allocated RAM: ${BGN}$RAM_SIZE${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "RAM Size must be a positive integer in MiB (e.g., 256)." 8 58
else
exit-script
fi
done
if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" \
--inputbox "Set Disk Size in GiB (e.g., 1, 2, 4)" 8 58 "1" \
--title "DISK SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [[ "$DISK_SIZE" =~ ^[0-9]+$ ]]; then
DISK_SIZE="${DISK_SIZE}G"
fi
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE}${CL}"
else
exit-script
fi
if BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN Bridge" 8 58 vmbr0 --title "WAN BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $BRG ]; then
BRG="vmbr0"
fi
echo -e "${DGN}Using WAN Bridge: ${BGN}$BRG${CL}"
else
exit-script
fi
if LAN_BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN Bridge" 8 58 vmbr0 --title "LAN BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $LAN_BRG ]; then
LAN_BRG="vmbr0"
fi
echo -e "${DGN}Using LAN Bridge: ${BGN}$LAN_BRG${CL}"
else
exit-script
fi
if LAN_IP_ADDR=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a router IP" 8 58 $LAN_IP_ADDR --title "LAN IP ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $LAN_IP_ADDR ]; then
LAN_IP_ADDR="192.168.1.1"
fi
echo -e "${DGN}Using LAN IP ADDRESS: ${BGN}$LAN_IP_ADDR${CL}"
else
exit-script
fi
if LAN_NETMASK=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a router netmask" 8 58 $LAN_NETMASK --title "LAN NETMASK" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $LAN_NETMASK ]; then
LAN_NETMASK="255.255.255.0"
fi
echo -e "${DGN}Using LAN NETMASK: ${BGN}$LAN_NETMASK${CL}"
else
exit-script
fi
if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN MAC Address" 8 58 $GEN_MAC --title "WAN MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $MAC1 ]; then
MAC="$GEN_MAC"
else
MAC="$MAC1"
fi
echo -e "${DGN}Using WAN MAC Address: ${BGN}$MAC${CL}"
else
exit-script
fi
if MAC2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN MAC Address" 8 58 $GEN_MAC_LAN --title "LAN MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $MAC2 ]; then
LAN_MAC="$GEN_MAC_LAN"
else
LAN_MAC="$MAC2"
fi
echo -e "${DGN}Using LAN MAC Address: ${BGN}$LAN_MAC${CL}"
else
exit-script
fi
while true; do
if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN Vlan (leave blank for default)" 8 58 --title "WAN VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$VLAN1" ]; then
VLAN1="Default"
VLAN=""
echo -e "${DGN}Using WAN Vlan: ${BGN}$VLAN1${CL}"
break
fi
if [[ "$VLAN1" =~ ^[0-9]+$ ]] && [ "$VLAN1" -ge 1 ] && [ "$VLAN1" -le 4094 ]; then
VLAN=",tag=$VLAN1"
echo -e "${DGN}Using WAN Vlan: ${BGN}$VLAN1${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "VLAN must be a number between 1 and 4094, or leave blank for default." 8 58
else
exit-script
fi
done
while true; do
if VLAN2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN Vlan" 8 58 999 --title "LAN VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$VLAN2" ]; then
VLAN2="Default"
LAN_VLAN=""
echo -e "${DGN}Using LAN Vlan: ${BGN}$VLAN2${CL}"
break
fi
if [[ "$VLAN2" =~ ^[0-9]+$ ]] && [ "$VLAN2" -ge 1 ] && [ "$VLAN2" -le 4094 ]; then
LAN_VLAN=",tag=$VLAN2"
echo -e "${DGN}Using LAN Vlan: ${BGN}$VLAN2${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "VLAN must be a number between 1 and 4094, or leave blank for default." 8 58
else
exit-script
fi
done
while true; do
if MTU1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 --title "MTU SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$MTU1" ]; then
MTU1="Default"
MTU=""
echo -e "${DGN}Using Interface MTU Size: ${BGN}$MTU1${CL}"
break
fi
if [[ "$MTU1" =~ ^[0-9]+$ ]] && [ "$MTU1" -ge 576 ] && [ "$MTU1" -le 65520 ]; then
MTU=",mtu=$MTU1"
echo -e "${DGN}Using Interface MTU Size: ${BGN}$MTU1${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "MTU Size must be a number between 576 and 65520, or leave blank for default." 8 58
else
exit-script
fi
done
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "START VIRTUAL MACHINE" --yesno "Start VM when completed?" 10 58); then
START_VM="yes"
else
START_VM="no"
fi
echo -e "${DGN}Start VM when completed: ${BGN}$START_VM${CL}"
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create OpenWrt VM?" --no-button Do-Over 10 58); then
echo -e "${RD}Creating a OpenWrt VM using the above advanced settings${CL}"
else
header_info
echo -e "${RD}Using Advanced Settings${CL}"
advanced_settings
fi
}
function start_script() {
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno "Use Default Settings?" --no-button Advanced 10 58); then
header_info
echo -e "${BL}Using Default Settings${CL}"
default_settings
else
header_info
echo -e "${RD}Using Advanced Settings${CL}"
advanced_settings
fi
}
arch_check
pve_check
ssh_check
start_script
post_to_api_vm
msg_info "Validating Storage"
while read -r line; do
TAG=$(echo $line | awk '{print $1}')
TYPE=$(echo $line | awk '{printf "%-10s", $2}')
FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
ITEM=" Type: $TYPE Free: $FREE "
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
STORAGE_MENU+=("$TAG" "$ITEM" "OFF")
done < <(pvesm status -content images | awk 'NR>1')
VALID=$(pvesm status -content images | awk 'NR>1')
if [ -z "$VALID" ]; then
echo -e "\n${RD}⚠ Unable to detect a valid storage location.${CL}"
echo -e "Exiting..."
exit
elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
STORAGE=${STORAGE_MENU[0]}
else
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 OpenWrt VM?\n\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3)
done
fi
msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location."
msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}."
msg_info "Getting URL for OpenWrt Disk Image"
response=$(curl -fsSL https://openwrt.org)
stableversion=$(echo "$response" | sed -n 's/.*Current stable release - OpenWrt \([0-9.]\+\).*/\1/p' | head -n 1)
URL="https://downloads.openwrt.org/releases/$stableversion/targets/x86/64/openwrt-$stableversion-x86-64-generic-ext4-combined.img.gz"
msg_ok "${CL}${BL}${URL}${CL}"
curl -f#SL -o "$(basename "$URL")" "$URL"
FILE=$(basename "$URL")
msg_ok "Downloaded ${CL}${BL}$FILE${CL}"
gunzip -f "$FILE" >/dev/null 2>&1 || true
FILE="${FILE%.*}"
msg_ok "Extracted OpenWrt Disk Image ${CL}${BL}$FILE${CL}"
msg_info "Creating OpenWrt VM"
qm create $VMID -cores $CORE_COUNT -memory $RAM_SIZE -name $HN \
-onboot 1 -ostype l26 -scsihw virtio-scsi-pci --tablet 0
if [[ "$(pvesm status | awk -v s=$STORAGE '$1==s {print $2}')" == "dir" ]]; then
qm set $VMID -efidisk0 ${STORAGE}:0,efitype=4m,size=4M
else
pvesm alloc $STORAGE $VMID vm-$VMID-disk-0 4M >/dev/null
qm set $VMID -efidisk0 ${STORAGE}:vm-$VMID-disk-0,efitype=4m,size=4M
fi
IMPORT_OUT="$(qm importdisk $VMID $FILE $STORAGE --format raw 2>&1 || true)"
DISK_REF="$(printf '%s\n' "$IMPORT_OUT" | sed -n "s/.*successfully imported disk '\([^']\+\)'.*/\1/p")"
if [[ -z "$DISK_REF" ]]; then
DISK_REF="$(pvesm list "$STORAGE" | awk -v id="$VMID" '$1 ~ ("vm-"id"-disk-") {print $1}' | sort | tail -n1)"
fi
if [[ -z "$DISK_REF" ]]; then
msg_error "Unable to determine imported disk reference."
echo "$IMPORT_OUT"
exit 226
fi
qm set $VMID \
-efidisk0 ${STORAGE}:0,efitype=4m,size=4M \
-scsi0 ${DISK_REF} \
-boot order=scsi0 \
-tags community-script >/dev/null
msg_ok "Attached disk"
msg_info "Resizing disk to ${DISK_SIZE}"
qm disk resize "$VMID" scsi0 "${DISK_SIZE}" >/dev/null
msg_ok "Resized disk to ${DISK_SIZE}"
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' 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>
<h2 style='font-size: 24px; margin: 20px 0;'>OpenWrt VM</h2>
<p style='margin: 16px 0;'>
<a href='https://ko-fi.com/community_scripts' target='_blank' rel='noopener noreferrer'>
<img src='https://img.shields.io/badge/&#x2615;-Buy us a coffee-blue' alt='spend Coffee' />
</a>
</p>
<span style='margin: 0 10px;'>
<i class="fa fa-github fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>GitHub</a>
</span>
<span style='margin: 0 10px;'>
<i class="fa fa-comments fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE/discussions' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Discussions</a>
</span>
<span style='margin: 0 10px;'>
<i class="fa fa-exclamation-circle fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE/issues' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Issues</a>
</span>
</div>
EOF
)
qm set $VMID -description "$DESCRIPTION" >/dev/null
msg_ok "Created OpenWrt VM ${CL}${BL}(${HN})"
msg_info "OpenWrt is being started in order to configure the network interfaces."
qm start $VMID
sleep 15
msg_info "Waiting for OpenWrt to boot..."
for i in {1..30}; do
if qm status "$VMID" | grep -q "running"; then
sleep 5
msg_ok "OpenWrt is running"
break
fi
sleep 1
done
msg_ok "Network interfaces are being configured as OpenWrt initiates."
if qm status "$VMID" | grep -q "running"; then
send_line_to_vm ""
send_line_to_vm "uci delete network.@device[0]"
send_line_to_vm "uci set network.wan=interface"
send_line_to_vm "uci set network.wan.device=eth1"
send_line_to_vm "uci set network.wan.proto=dhcp"
send_line_to_vm "uci delete network.lan"
send_line_to_vm "uci set network.lan=interface"
send_line_to_vm "uci set network.lan.device=eth0"
send_line_to_vm "uci set network.lan.proto=static"
send_line_to_vm "uci set network.lan.ipaddr=${LAN_IP_ADDR}"
send_line_to_vm "uci set network.lan.netmask=${LAN_NETMASK}"
send_line_to_vm "uci commit"
send_line_to_vm "poweroff"
msg_ok "Network interfaces configured in OpenWrt"
else
msg_error "VM is not running"
exit 226
fi
msg_info "Waiting for OpenWrt to shut down..."
until qm status "$VMID" | grep -q "stopped"; do
sleep 2
done
msg_ok "OpenWrt has shut down"
msg_info "Adding bridge interfaces on Proxmox side"
qm set $VMID \
-net0 virtio,bridge=${LAN_BRG},macaddr=${LAN_MAC}${LAN_VLAN}${MTU} \
-net1 virtio,bridge=${BRG},macaddr=${MAC}${VLAN}${MTU} >/dev/null
msg_ok "Bridge interfaces added"
if [ "$START_VM" = "yes" ]; then
msg_info "Starting OpenWrt VM"
qm start $VMID
msg_ok "Started OpenWrt VM"
fi
VLAN_FINISH=""
if [ -z "$VLAN" ] && [ "$VLAN2" != "999" ]; then
VLAN_FINISH=" Please remember to adjust the VLAN tags to suit your network."
fi
post_update_to_api "done" "none"
msg_ok "Completed Successfully!${VLAN_FINISH:+\n$VLAN_FINISH}"
+46
View File
@@ -0,0 +1,46 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/unifi-os-server.sh)"
#!/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://ui.com/
APP="UniFi-OS-Server"
var_tags="${var_tags:-network}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}"
var_disk="${var_disk:-20}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-0}"
var_tun="${var_tun:-yes}"
var_nesting="${var_nesting:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /usr/local/sbin/unifi-os-server.bin && ! -d /data/unifi ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_custom "🚀" "${GN}" "The app offers a built-in updater. Please use it."
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:11443${CL}"
+58
View File
@@ -0,0 +1,58 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/zerotier-one.sh)"
#!/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: tremor021
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://www.zerotier.com/
APP="Zerotier-One"
var_tags="${var_tags:-networking}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /usr/sbin/zerotier-one ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Stopping Service"
systemctl stop zerotier-one
msg_ok "Stopping Service"
msg_info "Updating Zerotier-One"
$STD apt update
$STD apt upgrade -y
msg_ok "Updated Zerotier-One"
msg_info "Starting Service"
systemctl start zerotier-one
msg_ok "Started Service"
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:3443${CL}"
+53
View File
@@ -0,0 +1,53 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/ddclient.sh)"
ddclient — это клиент на Perl, используемый для обновления динамических DNS-записей для учетных записей у широкого круга поставщиков услуг динамического DNS. Он поддерживает множество протоколов и поставщиков, позволяя автоматически обновлять IP-адреса для ваших доменных имен.
#!/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: mitchscobell
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://ddclient.net/
APP="ddclient"
var_tags="${var_tags:-network}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}"
var_disk="${var_disk:-2}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /etc/ddclient.conf ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Updating ddclient"
$STD apt update
$STD apt install --only-upgrade -y ddclient
$STD systemctl restart ddclient
msg_ok "Updated ddclient"
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
+1357
View File
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
:1080
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/hev-socks5-server.sh)"
#!/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: miviro
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/heiher/hev-socks5-server
APP="hev-socks5-server"
var_tags="${var_tags:-proxy;socks5}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}"
var_disk="${var_disk:-2}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /opt/${APP} ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "hev-socks5-server" "heiher/hev-socks5-server"; then
msg_info "Stopping Service"
systemctl stop hev-socks5-server
msg_ok "Stopped Service"
fetch_and_deploy_gh_release "hev-socks5-server" "heiher/hev-socks5-server" "singlefile" "latest" "/opt" "hev-socks5-server-linux-x86_64"
msg_info "Starting Service"
systemctl start hev-socks5-server
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 with a SOCKS5 client using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}${IP}:1080${CL}"
echo -e "${INFO}${YW} and the credentials stored at /root/hev.creds${CL}"
+73
View File
@@ -0,0 +1,73 @@
#pve
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/proxmox-datacenter-manager.sh)"
#!/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: CrazyWolf13
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: Proxmox Server Solution GmbH
APP="Proxmox-Datacenter-Manager"
var_tags="${var_tags:-datacenter}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-10}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -e /usr/sbin/proxmox-datacenter-manager-admin ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if grep -q 'Debian GNU/Linux 12' /etc/os-release && [ -f /etc/apt/sources.list.d/proxmox-release-bookworm.list ] && [ -f /etc/apt/sources.list.d/pdm-test.list ]; then
msg_info "Updating outdated outdated source formats"
echo "deb [signed-by=/usr/share/keyrings/proxmox-archive-keyring.gpg] http://download.proxmox.com/debian/pdm bookworm pdm-test" >/etc/apt/sources.list.d/pdm-test.list
curl -fsSL https://enterprise.proxmox.com/debian/proxmox-archive-keyring-trixie.gpg -o /usr/share/keyrings/proxmox-archive-keyring.gpg
rm -f /etc/apt/keyrings/proxmox-release-bookworm.gpg /etc/apt/sources.list.d/proxmox-release-bookworm.list
$STD apt update
msg_ok "Updated old sources"
fi
if grep -q 'Debian GNU/Linux 13' /etc/os-release; then
if [ -f "/etc/apt/sources.list.d/pdm-test.sources" ]; then
if ! grep -qx "Enabled: false" "/etc/apt/sources.list.d/pdm-test.sources"; then
echo "Enabled: false" >> "/etc/apt/sources.list.d/pdm-test.sources"
setup_deb822_repo \
"pdm" \
"https://enterprise.proxmox.com/debian/proxmox-archive-keyring-trixie.gpg" \
"http://download.proxmox.com/debian/pdm" \
"trixie" \
"pdm-no-subscription"
fi
fi
fi
msg_info "Updating $APP LXC"
$STD apt update
$STD apt -y upgrade
msg_ok "Updated $APP LXC"
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:8443${CL}"
+72
View File
@@ -0,0 +1,72 @@
Регулятор масштабирования ЦП определяет, как регулируется частота ЦП в зависимости от рабочей нагрузки, с целью либо экономии энергии, либо повышения производительности. Изменяя частоту в большую или меньшую сторону, операционная система может оптимизировать использование ЦП и, по возможности, экономить энергию. Типичные регуляторы масштабирования
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/scaling-governor.sh)"
#!/usr/bin/env bash
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
set -e
# Telemetry
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "scaling-governor" "pve"
header_info() {
clear
cat <<EOF
________ __ __ _____
/ ___/ _ \/ / / / / ___/__ _ _____ _______ ___ _______
/ /__/ ___/ /_/ / / (_ / _ \ |/ / -_) __/ _ \/ _ \/ __(_-<
\___/_/ \____/ \___/\___/___/\__/_/ /_//_/\___/_/ /___/
EOF
}
header_info
whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU Scaling Governors" --yesno "View/Change CPU Scaling Governors. Proceed?" 10 58
current_governor=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
GOVERNORS_MENU=()
MSG_MAX_LENGTH=0
while read -r TAG ITEM; do
OFFSET=2
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=${#ITEM}+OFFSET
GOVERNORS_MENU+=("$TAG" "$ITEM " "OFF")
done < <(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors | tr ' ' '\n' | grep -v "$current_governor")
scaling_governor=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Current CPU Scaling Governor is set to $current_governor" --checklist "\nSelect the Scaling Governor to use:\n" 16 $((MSG_MAX_LENGTH + 58)) 6 "${GOVERNORS_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
[ -z "$scaling_governor" ] && {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No CPU Scaling Governor Selected" --msgbox "It appears that no CPU Scaling Governor was selected" 10 68
clear
exit
}
echo "${scaling_governor}" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor >/dev/null
current_governor=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "Current CPU Scaling Governor" "\nCurrent CPU Scaling Governor has been set to $current_governor\n" 10 60
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU Scaling Governor" --menu "This will establish a crontab to maintain the CPU Scaling Governor configuration across reboots.\n \nSetup a crontab?" 14 68 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
set +e
NEW_CRONTAB_COMMAND="(sleep 60 && echo \"$current_governor\" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor)"
EXISTING_CRONTAB=$(crontab -l 2>/dev/null)
if [[ -n "$EXISTING_CRONTAB" ]]; then
TEMP_CRONTAB_FILE=$(mktemp)
echo "$EXISTING_CRONTAB" | grep -v "@reboot (sleep 60 && echo*" >"$TEMP_CRONTAB_FILE"
crontab "$TEMP_CRONTAB_FILE"
rm "$TEMP_CRONTAB_FILE"
fi
(
crontab -l 2>/dev/null
echo "@reboot $NEW_CRONTAB_COMMAND"
) | crontab -
echo -e "\nCrontab Set (use 'crontab -e' to check)"
;;
no)
echo -e "\n\033[31mNOTE: Settings return to default after reboot\033[m\n"
;;
esac
echo -e "Current CPU Scaling Governor is set to \033[36m$current_governor\033[m\n"
+99
View File
@@ -0,0 +1,99 @@
# Этот скрипт помогает пользователям Proxmox выявлять и удалять "осиротевшие" тома LVM,
# которые больше не связаны ни с одной виртуальной машиной или контейнером LXC.
# Он сканирует все тома LVM, обнаруживает неиспользуемые и предоставляет интерактивное приглашение для их безопасного
# удаления. Критически важные для системы тома, такие как корневой раздел, раздел подкачки и раздел
# данных, исключаются, чтобы предотвратить случайное удаление.
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/clean-orphaned-lvm.sh)"
#!/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
function header_info {
clear
cat <<"EOF"
____ ________ ____ __ __ __ _ ____ ___
/ __ \_________ _ ______ ___ ____ _ __ / ____/ /__ ____ _____ / __ \_________ / /_ ____ _____ ___ ____/ / / /| | / / |/ /____
/ /_/ / ___/ __ \| |/_/ __ `__ \/ __ \| |/_/ / / / / _ \/ __ `/ __ \ / / / / ___/ __ \/ __ \/ __ `/ __ \/ _ \/ __ / / / | | / / /|_/ / ___/
/ ____/ / / /_/ /> </ / / / / / /_/ /> < / /___/ / __/ /_/ / / / / / /_/ / / / /_/ / / / / /_/ / / / / __/ /_/ / / /__| |/ / / / (__ )
/_/ /_/ \____/_/|_/_/ /_/ /_/\____/_/|_| \____/_/\___/\__,_/_/ /_/ \____/_/ / .___/_/ /_/\__,_/_/ /_/\___/\__,_/ /_____/___/_/ /_/____/
/_/
EOF
}
# Telemetry
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "clean-orphaned-lvm" "pve"
# Function to check for orphaned LVM volumes
function find_orphaned_lvm {
echo -e "\n🔍 Scanning for orphaned LVM volumes...\n"
orphaned_volumes=()
while read -r lv vg size seg_type; do
# Exclude system-critical LVs and Ceph OSDs
if [[ "$lv" == "data" || "$lv" == "root" || "$lv" == "swap" || "$lv" =~ ^osd-block- ]]; then
continue
fi
# Exclude thin pools (any name)
if [[ "$seg_type" == "thin-pool" ]]; then
continue
fi
container_id=$(echo "$lv" | grep -oE "[0-9]+" | head -1)
# Check if the ID exists as a VM or LXC container on any cluster node
if compgen -G "/etc/pve/nodes/*/lxc/${container_id}.conf" >/dev/null 2>&1 ||
compgen -G "/etc/pve/nodes/*/qemu-server/${container_id}.conf" >/dev/null 2>&1; then
continue
fi
orphaned_volumes+=("$lv" "$vg" "$size")
done < <(lvs --noheadings -o lv_name,vg_name,lv_size,seg_type --separator ' ' 2>/dev/null | awk '{print $1, $2, $3, $4}')
# Display orphaned volumes
echo -e "❗ The following orphaned LVM volumes were found:\n"
printf "%-25s %-10s %-10s\n" "LV Name" "VG" "Size"
printf "%-25s %-10s %-10s\n" "-------------------------" "----------" "----------"
for ((i = 0; i < ${#orphaned_volumes[@]}; i += 3)); do
printf "%-25s %-10s %-10s\n" "${orphaned_volumes[i]}" "${orphaned_volumes[i + 1]}" "${orphaned_volumes[i + 2]}"
done
echo ""
}
# Function to delete selected volumes
function delete_orphaned_lvm {
for ((i = 0; i < ${#orphaned_volumes[@]}; i += 3)); do
lv="${orphaned_volumes[i]}"
vg="${orphaned_volumes[i + 1]}"
size="${orphaned_volumes[i + 2]}"
read -p "❓ Do you want to delete $lv (VG: $vg, Size: $size)? [y/N]: " confirm
if [[ "$confirm" =~ ^[Yy]$ ]]; then
echo -e "🗑️ Deleting $lv from $vg..."
lvremove -f "$vg/$lv"
if [ $? -eq 0 ]; then
echo -e "✅ Successfully deleted $lv.\n"
else
echo -e "❌ Failed to delete $lv.\n"
fi
else
echo -e "⚠️ Skipping $lv.\n"
fi
done
}
# Run script
header_info
find_orphaned_lvm
delete_orphaned_lvm
echo -e "✅ Cleanup process completed!\n"
+355
View File
@@ -0,0 +1,355 @@
# Этот скрипт добавит/удалит расписание crontab, которое обновляет операционную систему всех LXC каждое воскресенье в полночь.
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/cron-update-lxcs.sh)"
#!/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
#
# This script manages a local cron job for automatic LXC container OS updates.
# The update script is downloaded once, displayed for review, and installed
# locally. Cron runs the local copy — no remote code execution at runtime.
#
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/cron-update-lxcs.sh)"
set -euo pipefail
REPO_URL="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main"
SCRIPT_URL="${REPO_URL}/tools/pve/update-lxcs-cron.sh"
LOCAL_SCRIPT="/usr/local/bin/update-lxcs.sh"
CONF_FILE="/etc/update-lxcs.conf"
LOG_FILE="/var/log/update-lxcs-cron.log"
CRON_ENTRY="0 0 * * 0 ${LOCAL_SCRIPT} >>${LOG_FILE} 2>&1"
clear
cat <<"EOF"
______ __ __ __ __ __ _ ________
/ ____/________ ____ / / / /___ ____/ /___ _/ /____ / / | |/ / ____/____
/ / / ___/ __ \/ __ \ / / / / __ \/ __ / __ `/ __/ _ \ / / | / / / ___/
/ /___/ / / /_/ / / / / / /_/ / /_/ / /_/ / /_/ / /_/ __/ / /___/ / /___(__ )
\____/_/ \____/_/ /_/ \____/ .___/\__,_/\__,_/\__/\___/ /_____/_/|_\____/____/
/_/
EOF
info() { echo -e "\n \e[36m[Info]\e[0m $1"; }
ok() { echo -e " \e[32m[OK]\e[0m $1"; }
err() { echo -e " \e[31m[Error]\e[0m $1" >&2; }
confirm() {
local prompt="${1:-Proceed?}"
while true; do
read -rp " ${prompt} (y/n): " yn
case $yn in
[Yy]*) return 0 ;;
[Nn]*) return 1 ;;
*) echo " Please answer yes or no." ;;
esac
done
}
download_script() {
local tmp
tmp=$(mktemp)
if ! curl -fsSL -o "$tmp" "$SCRIPT_URL"; then
err "Failed to download script from:\n ${SCRIPT_URL}"
rm -f "$tmp"
return 1
fi
echo "$tmp"
}
review_script() {
local file="$1"
local hash
hash=$(sha256sum "$file" | awk '{print $1}')
echo ""
echo -e " \e[1;33m─── Script Content ───────────────────────────────────────────\e[0m"
cat "$file"
echo -e " \e[1;33m──────────────────────────────────────────────────────────────\e[0m"
echo -e " \e[36mSHA256:\e[0m ${hash}"
echo -e " \e[36mSource:\e[0m ${SCRIPT_URL}"
echo ""
}
remove_legacy_cron() {
if crontab -l -u root 2>/dev/null | grep -q "update-lxcs-cron.sh"; then
(crontab -l -u root 2>/dev/null | grep -v "update-lxcs-cron.sh") | crontab -u root -
ok "Removed legacy curl-based cron entry"
fi
}
add() {
info "Downloading update script..."
local tmp
tmp=$(download_script) || exit 1
local hash
hash=$(sha256sum "$tmp" | awk '{print $1}')
echo ""
echo -e " \e[1;33m─── Installation Summary ─────────────────────────────────────\e[0m"
echo -e " \e[36mSource:\e[0m ${SCRIPT_URL}"
echo -e " \e[36mSHA256:\e[0m ${hash}"
echo -e " \e[36mInstall to:\e[0m ${LOCAL_SCRIPT}"
echo -e " \e[36mConfig:\e[0m ${CONF_FILE}"
echo -e " \e[36mLog file:\e[0m ${LOG_FILE}"
echo -e " \e[36mCron schedule:\e[0m Every Sunday at midnight (0 0 * * 0)"
echo -e " \e[1;33m──────────────────────────────────────────────────────────────\e[0m"
echo ""
if confirm "Review script content before installing?"; then
review_script "$tmp"
fi
if ! confirm "Install this script and activate cron schedule?"; then
rm -f "$tmp"
echo " Aborted."
exit 0
fi
remove_legacy_cron
install -m 0755 "$tmp" "$LOCAL_SCRIPT"
rm -f "$tmp"
ok "Installed script to ${LOCAL_SCRIPT}"
if [[ ! -f "$CONF_FILE" ]]; then
cat >"$CONF_FILE" <<'CONF'
# Configuration for automatic LXC container OS updates.
# Add container IDs to exclude from updates (comma-separated):
# EXCLUDE=100,101,102
EXCLUDE=
CONF
ok "Created config ${CONF_FILE}"
fi
(
crontab -l -u root 2>/dev/null | grep -v "${LOCAL_SCRIPT}" || true
echo "${CRON_ENTRY}"
) | crontab -u root -
ok "Added cron schedule: Every Sunday at midnight"
echo ""
echo -e " \e[36mLocal script:\e[0m ${LOCAL_SCRIPT}"
echo -e " \e[36mConfig:\e[0m ${CONF_FILE}"
echo -e " \e[36mLog file:\e[0m ${LOG_FILE}"
echo ""
}
remove() {
if crontab -l -u root 2>/dev/null | grep -q "${LOCAL_SCRIPT}"; then
(crontab -l -u root 2>/dev/null | grep -v "${LOCAL_SCRIPT}") | crontab -u root -
ok "Removed cron schedule"
fi
remove_legacy_cron
[[ -f "$LOCAL_SCRIPT" ]] && rm -f "$LOCAL_SCRIPT" && ok "Removed ${LOCAL_SCRIPT}"
[[ -f "$LOG_FILE" ]] && rm -f "$LOG_FILE" && ok "Removed ${LOG_FILE}"
echo -e "\n Cron Update LXCs has been fully removed."
echo -e " \e[90mNote: ${CONF_FILE} was kept (remove manually if desired).\e[0m"
}
update_script() {
if [[ ! -f "$LOCAL_SCRIPT" ]]; then
err "No local script found at ${LOCAL_SCRIPT}. Use 'Add' first."
exit 1
fi
info "Downloading latest version..."
local tmp
tmp=$(download_script) || exit 1
if command -v diff &>/dev/null; then
local changes
changes=$(diff --color=auto "$LOCAL_SCRIPT" "$tmp" 2>/dev/null || true)
if [[ -z "$changes" ]]; then
ok "Script is already up-to-date (no changes)."
rm -f "$tmp"
return
fi
echo ""
echo -e " \e[1;33m─── Changes ──────────────────────────────────────────────────\e[0m"
echo "$changes"
echo -e " \e[1;33m──────────────────────────────────────────────────────────────\e[0m"
else
review_script "$tmp"
fi
local new_hash old_hash
new_hash=$(sha256sum "$tmp" | awk '{print $1}')
old_hash=$(sha256sum "$LOCAL_SCRIPT" | awk '{print $1}')
echo -e " \e[36mCurrent SHA256:\e[0m ${old_hash}"
echo -e " \e[36mNew SHA256:\e[0m ${new_hash}"
echo ""
if ! confirm "Apply update?"; then
rm -f "$tmp"
echo " Aborted."
return
fi
install -m 0755 "$tmp" "$LOCAL_SCRIPT"
rm -f "$tmp"
ok "Updated ${LOCAL_SCRIPT}"
}
view_script() {
if [[ ! -f "$LOCAL_SCRIPT" ]]; then
err "No local script found at ${LOCAL_SCRIPT}. Use 'Add' first."
exit 1
fi
local view_choice
view_choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "View Script" --menu "What do you want to view?" 12 60 3 \
"Worker" "Installed update script (${LOCAL_SCRIPT##*/})" \
"Cron" "Cron schedule & configuration" \
"Both" "Show everything" \
3>&1 1>&2 2>&3) || return 0
case "$view_choice" in
"Worker") view_worker_script ;;
"Cron") view_cron_config ;;
"Both") view_cron_config && echo "" && view_worker_script ;;
esac
}
view_worker_script() {
local hash
hash=$(sha256sum "$LOCAL_SCRIPT" | awk '{print $1}')
echo ""
echo -e " \e[1;33m─── ${LOCAL_SCRIPT} ───\e[0m"
cat "$LOCAL_SCRIPT"
echo -e " \e[1;33m──────────────────────────────────────────────────────────────\e[0m"
echo -e " \e[36mSHA256:\e[0m ${hash}"
echo -e " \e[36mInstalled:\e[0m $(stat -c '%y' "$LOCAL_SCRIPT" 2>/dev/null | cut -d. -f1)"
echo ""
}
view_cron_config() {
echo ""
echo -e " \e[1;33m─── Cron Configuration ───────────────────────────────────────\e[0m"
if crontab -l -u root 2>/dev/null | grep -q "${LOCAL_SCRIPT}"; then
local entry
entry=$(crontab -l -u root 2>/dev/null | grep "${LOCAL_SCRIPT}")
echo -e " \e[36mCron entry:\e[0m ${entry}"
local schedule
schedule=$(echo "$entry" | awk '{print $1,$2,$3,$4,$5}')
echo -e " \e[36mSchedule:\e[0m ${schedule} ($(cron_to_human "$schedule"))"
else
echo -e " \e[31mCron:\e[0m Not configured"
fi
if [[ -f "$CONF_FILE" ]]; then
echo -e " \e[36mConfig file:\e[0m ${CONF_FILE}"
local excludes
excludes=$(grep -oP '^\s*EXCLUDE\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null || true)
echo -e " \e[36mExcluded:\e[0m ${excludes:-(none)}"
echo ""
echo -e " \e[90m--- ${CONF_FILE} ---\e[0m"
cat "$CONF_FILE"
else
echo -e " \e[36mConfig file:\e[0m (not created yet)"
fi
if [[ -f "$LOG_FILE" ]]; then
local log_size
log_size=$(du -h "$LOG_FILE" | awk '{print $1}')
echo -e " \e[36mLog file:\e[0m ${LOG_FILE} (${log_size})"
fi
echo -e " \e[1;33m──────────────────────────────────────────────────────────────\e[0m"
echo ""
}
cron_to_human() {
local schedule="$1"
case "$schedule" in
"0 0 * * 0") echo "Every Sunday at midnight" ;;
"0 0 * * *") echo "Daily at midnight" ;;
"0 * * * *") echo "Every hour" ;;
*) echo "Custom schedule" ;;
esac
}
show_status() {
echo ""
if [[ -f "$LOCAL_SCRIPT" ]]; then
local hash
hash=$(sha256sum "$LOCAL_SCRIPT" | awk '{print $1}')
ok "Script installed: ${LOCAL_SCRIPT}"
echo -e " \e[36mSHA256:\e[0m ${hash}"
echo -e " \e[36mInstalled:\e[0m $(stat -c '%y' "$LOCAL_SCRIPT" 2>/dev/null | cut -d. -f1)"
else
err "Script not installed"
fi
if crontab -l -u root 2>/dev/null | grep -q "${LOCAL_SCRIPT}"; then
local schedule
schedule=$(crontab -l -u root 2>/dev/null | grep "${LOCAL_SCRIPT}" | awk '{print $1,$2,$3,$4,$5}')
ok "Cron active: ${schedule}"
else
err "Cron not configured"
fi
if [[ -f "$CONF_FILE" ]]; then
local excludes
excludes=$(grep -oP '^\s*EXCLUDE\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null || echo "(none)")
echo -e " \e[36mExcluded:\e[0m ${excludes:-"(none)"}"
fi
if [[ -f "$LOG_FILE" ]]; then
local log_size last_run
log_size=$(du -h "$LOG_FILE" | awk '{print $1}')
last_run=$(grep -oP '^\s+\K\w.*' "$LOG_FILE" | tail -1)
echo -e " \e[36mLog file:\e[0m ${LOG_FILE} (${log_size})"
[[ -n "${last_run:-}" ]] && echo -e " \e[36mLast run:\e[0m ${last_run}"
else
echo -e " \e[36mLog file:\e[0m (no runs yet)"
fi
echo ""
}
run_now() {
if [[ ! -f "$LOCAL_SCRIPT" ]]; then
err "No local script found at ${LOCAL_SCRIPT}. Use 'Add' first."
exit 1
fi
info "Running update script now..."
bash "$LOCAL_SCRIPT" | tee -a "$LOG_FILE"
ok "Run completed. Log appended to ${LOG_FILE}"
}
rotate_log() {
if [[ ! -f "$LOG_FILE" ]]; then
info "No log file to rotate."
return
fi
local log_size
log_size=$(stat -c '%s' "$LOG_FILE" 2>/dev/null || echo 0)
local log_size_h
log_size_h=$(du -h "$LOG_FILE" | awk '{print $1}')
if confirm "Rotate log file? (current size: ${log_size_h})"; then
mv "$LOG_FILE" "${LOG_FILE}.old"
ok "Rotated: ${LOG_FILE}${LOG_FILE}.old"
fi
}
OPTIONS=(
Add "Download, review & install cron schedule"
Remove "Remove cron schedule & local script"
Update "Update local script from repository"
Status "Show installation status & last run"
Run "Run update script now (manual trigger)"
View "View cron config & installed script"
Rotate "Rotate log file"
)
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Cron Update LXCs" --menu "Select an option:" 16 68 7 \
"${OPTIONS[@]}" 3>&1 1>&2 2>&3) || exit 0
case $CHOICE in
"Add") add ;;
"Remove") remove ;;
"Update") update_script ;;
"Status") show_status ;;
"Run") run_now ;;
"View") view_script ;;
"Rotate") rotate_log ;;
esac
+93
View File
@@ -0,0 +1,93 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/host-backup.sh)"
#!/usr/bin/env bash
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
__ __ __ ___ __
/ // /__ ___ / /_ / _ )___ _____/ /____ _____
/ _ / _ \(_-</ __/ / _ / _ `/ __/ '_/ // / _ \
/_//_/\___/___/\__/ /____/\_,_/\__/_/\_\\_,_/ .__/
/_/
EOF
}
# Telemetry
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "host-backup" "pve"
# Function to perform backup
function perform_backup {
local BACKUP_PATH
local DIR
local DIR_DASH
local BACKUP_FILE
local selected_directories=()
# Get backup path from user
BACKUP_PATH=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "\nDefaults to /root/\ne.g. /mnt/backups/" 11 68 --title "Directory to backup to:" 3>&1 1>&2 2>&3) || return
# Default to /root/ if no input
BACKUP_PATH="${BACKUP_PATH:-/root/}"
# Get directory to work in from user
DIR=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "\nDefaults to /etc/\ne.g. /root/, /var/lib/pve-cluster/ etc." 11 68 --title "Directory to work in:" 3>&1 1>&2 2>&3) || return
# Default to /etc/ if no input
DIR="${DIR:-/etc/}"
DIR_DASH=$(echo "$DIR" | tr '/' '-')
BACKUP_FILE="$(hostname)${DIR_DASH}backup"
# Build a list of directories for backup
local CTID_MENU=()
CTID_MENU=("ALL" "Backup all folders" "OFF")
while read -r dir; do
CTID_MENU+=("$(basename "$dir")" "$dir " "OFF")
done < <(ls -d "${DIR}"*)
# Allow the user to select directories
local HOST_BACKUP
while [ -z "${HOST_BACKUP:+x}" ]; do
HOST_BACKUP=$(whiptail --backtitle "Proxmox VE Host Backup" --title "Working in the ${DIR} directory " --checklist \
"\nSelect what files/directories to backup:\n" 16 $(((${#DIRNAME} + 2) + 88)) 6 "${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || return
for selected_dir in ${HOST_BACKUP//\"/}; do
if [[ "$selected_dir" == "ALL" ]]; then
# if ALL was chosen, secure all folders
selected_directories=("${DIR}"*/)
break
else
selected_directories+=("${DIR}$selected_dir")
fi
done
done
# Perform the backup
header_info
echo -e "This will create a backup in\e[1;33m $BACKUP_PATH \e[0mfor these files and directories\e[1;33m ${selected_directories[*]} \e[0m"
read -p "Press ENTER to continue..."
header_info
echo "Working..."
tar -czf "$BACKUP_PATH$BACKUP_FILE-$(date +%Y_%m_%dT%H_%M).tar.gz" --absolute-names "${selected_directories[@]}"
header_info
echo -e "\nFinished"
echo -e "\e[1;33m \nA backup is rendered ineffective when it remains stored on the host.\n \e[0m"
sleep 2
}
# Main script execution loop
while true; do
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE Host Backup" --yesno "This will create backups for particular files and directories located within a designated directory. Proceed?" 10 88); then
perform_backup
else
break
fi
done
+122
View File
@@ -0,0 +1,122 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/kernel-clean.sh)"
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
__ __ __ ________
/ //_/__ _________ ___ / / / ____/ /__ ____ _____
/ ,< / _ \/ ___/ __ \/ _ \/ / / / / / _ \/ __ `/ __ \
/ /| / __/ / / / / / __/ / / /___/ / __/ /_/ / / / /
/_/ |_\___/_/ /_/ /_/\___/_/ \____/_/\___/\__,_/_/ /_/
EOF
}
# Color variables
YW="\033[33m"
GN="\033[1;92m"
RD="\033[01;31m"
CL="\033[m"
# Telemetry
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "kernel-clean" "pve"
# Detect current kernel
current_kernel=$(uname -r)
# Only list fully-installed (ii) versioned kernel packages; the pattern
# proxmox-kernel-X.Y.Z matches versioned kernels while excluding the
# two-segment meta-packages (proxmox-kernel-X.Y) and proxmox-kernel-helper.
available_kernels=$(dpkg --list |
awk '/^ii/ {print $2}' |
grep -E '^proxmox-kernel-[0-9]+\.[0-9]+\.[0-9]' |
grep -v "$current_kernel" |
sort -V)
header_info
if [ -z "$available_kernels" ]; then
echo -e "${GN}No old kernels detected. Current kernel: ${current_kernel}${CL}"
exit 0
fi
echo -e "${GN}Currently running kernel: ${current_kernel}${CL}"
echo -e "${YW}Available kernels for removal:${CL}"
echo "$available_kernels" | nl -w 2 -s '. '
echo -e "\n${YW}Select kernels to remove (e.g. 1,3 or 1-5 or 1-3,7):${CL}"
read -r selected
# Parse selection: supports single indices, ranges (e.g., 1-5), and combinations (e.g., 1,3-5,7)
selected_indices=()
IFS=',' read -r -a tokens <<<"$selected"
for token in "${tokens[@]}"; do
if [[ "$token" =~ ^([0-9]+)-([0-9]+)$ ]]; then
for ((i = BASH_REMATCH[1]; i <= BASH_REMATCH[2]; i++)); do
selected_indices+=("$i")
done
else
selected_indices+=("$token")
fi
done
kernels_to_remove=()
for index in "${selected_indices[@]}"; do
kernel=$(echo "$available_kernels" | sed -n "${index}p")
if [ -n "$kernel" ]; then
kernels_to_remove+=("$kernel")
fi
done
if [ ${#kernels_to_remove[@]} -eq 0 ]; then
echo -e "${RD}No valid selection made. Exiting.${CL}"
exit 0
fi
# Confirm removal
echo -e "${YW}Kernels to be removed:${CL}"
printf "%s\n" "${kernels_to_remove[@]}"
read -rp "Proceed with removal? (y/n): " confirm
if [[ "$confirm" != "y" ]]; then
echo -e "${RD}Aborted.${CL}"
exit 0
fi
# Remove kernels
for kernel in "${kernels_to_remove[@]}"; do
echo -e "${YW}Removing $kernel...${CL}"
# Derive the major.minor meta-package name (e.g. proxmox-kernel-6.14)
# from a versioned name like proxmox-kernel-6.14.11-9-pve-signed.
minor_version=$(echo "$kernel" | sed -E 's/^proxmox-kernel-([0-9]+\.[0-9]+)\..*/\1/')
meta="proxmox-kernel-${minor_version}"
pkgs_to_remove=("$kernel")
# Include the meta-package in the purge when it is installed and when
# no other versioned kernel of the same minor version will remain
# (the running kernel keeps it alive if it shares the same minor).
if dpkg -l "$meta" 2>/dev/null | grep -q '^ii'; then
remaining=$(dpkg --list |
awk '/^ii/ {print $2}' |
grep -E "^proxmox-kernel-${minor_version}\." |
grep -v "^${kernel}$" |
wc -l)
if [ "$remaining" -eq 0 ]; then
pkgs_to_remove+=("$meta")
fi
fi
if apt-get purge -y "${pkgs_to_remove[@]}" >/dev/null 2>&1; then
echo -e "${GN}Successfully removed: ${pkgs_to_remove[*]}${CL}"
else
echo -e "${RD}Failed to remove: ${pkgs_to_remove[*]}. Check dependencies.${CL}"
fi
done
# Clean up and update GRUB
echo -e "${YW}Cleaning up...${CL}"
apt-get autoremove -y >/dev/null 2>&1 && update-grub >/dev/null 2>&1
echo -e "${GN}Cleanup and GRUB update complete.${CL}"
+680
View File
@@ -0,0 +1,680 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/update-apps.sh)"
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: BvdBerg01 | Co-Author: remz1337
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/core.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "update-apps" "pve"
# =============================================================================
# CONFIGURATION VARIABLES
# Set these variables to skip interactive prompts (Whiptail dialogs)
# =============================================================================
# var_backup: Enable/disable backup before update
# Options: "yes" | "no" | "" (empty = interactive prompt)
var_backup="${var_backup:-}"
# var_backup_storage: Storage location for backups (only used if var_backup=yes)
# Options: Storage name from /etc/pve/storage.cfg (e.g., "local", "nas-backup")
# Leave empty for interactive selection
var_backup_storage="${var_backup_storage:-}"
# var_container: Which containers to update
# Options:
# - "all" : All containers with community-scripts tags
# - "all_running" : Only running containers with community-scripts tags
# - "all_stopped" : Only stopped containers with community-scripts tags
# - "101,102,109" : Comma-separated list of specific container IDs
# - "" : Interactive selection via Whiptail
var_container="${var_container:-}"
# var_unattended: Run updates without user interaction inside containers
# Options: "yes" | "no" | "" (empty = interactive prompt)
var_unattended="${var_unattended:-}"
# var_skip_confirm: Skip initial confirmation dialog
# Options: "yes" | "no" (default: no)
var_skip_confirm="${var_skip_confirm:-no}"
# var_auto_reboot: Automatically reboot containers that require it after update
# Options: "yes" | "no" | "" (empty = interactive prompt)
var_auto_reboot="${var_auto_reboot:-}"
# var_continue_on_error: Continue updating remaining containers if one update fails
# Options: "yes" | "no" (default: no = stop on first error)
# Note: containers with backups always attempt restore on failure regardless of this setting
var_continue_on_error="${var_continue_on_error:-no}"
# var_dry_run: Check for available updates without applying them
# Options: "yes" | "no" (default: no)
# Output: lists each container with current vs. latest version
# Note: requires the container to be running; does not modify any container
var_dry_run="${var_dry_run:-no}"
# var_tags: Optionally override the tags used for auto-detection
# Options: "community-script|proxmox-helper-scripts" (default)
var_tags="${var_tags:-community-script|proxmox-helper-scripts}"
# =============================================================================
# JSON CONFIG EXPORT
# Run with --export-config to output current configuration as JSON
# =============================================================================
function export_config_json() {
cat <<EOF
{
"var_backup": "${var_backup}",
"var_backup_storage": "${var_backup_storage}",
"var_container": "${var_container}",
"var_unattended": "${var_unattended}",
"var_skip_confirm": "${var_skip_confirm}",
"var_auto_reboot": "${var_auto_reboot}",
"var_continue_on_error": "${var_continue_on_error}",
"var_dry_run": "${var_dry_run}",
"var_tags": "${var_tags}"
}
EOF
}
function print_usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
Update LXC containers created with community-scripts.
Options:
--help Show this help message
--export-config Export current configuration as JSON
Environment Variables:
var_backup Enable backup before update (yes/no)
var_backup_storage Storage location for backups
var_container Container selection (all/all_running/all_stopped/101,102,...)
var_unattended Run updates unattended (yes/no)
var_skip_confirm Skip initial confirmation (yes/no)
var_auto_reboot Auto-reboot containers if required (yes/no)
var_continue_on_error Continue to next container on update failure (yes/no)
var_dry_run Check for updates without applying them (yes/no)
var_tags Optionally override auto-detection tags ("prod|smb|community-script")
Examples:
# Run interactively
$(basename "$0")
# Update all running containers unattended with backup
var_backup=yes var_backup_storage=local var_container=all_running var_unattended=yes var_skip_confirm=yes $(basename "$0")
# Update specific containers without backup
var_backup=no var_container=101,102,105 var_unattended=yes var_skip_confirm=yes $(basename "$0")
# Unattended cron-style: skip confirm, continue on error, no backup
var_backup=no var_container=all_running var_unattended=yes var_skip_confirm=yes var_continue_on_error=yes $(basename "$0")
# Dry-run: show available updates for all running containers without applying
var_container=all_running var_skip_confirm=yes var_dry_run=yes $(basename "$0")
# Export current configuration
$(basename "$0") --export-config
EOF
}
# Handle command line arguments
case "${1:-}" in
--help | -h)
print_usage
exit 0
;;
--export-config)
export_config_json
exit 0
;;
esac
# =============================================================================
function header_info {
clear
cat <<"EOF"
__ _ ________ __ __ __ __
/ / | |/ / ____/ / / / /___ ____/ /___ _/ /____
/ / | / / / / / / __ \/ __ / __ `/ __/ _ \
/ /___/ / /___ / /_/ / /_/ / /_/ / /_/ / /_/ __/
/_____/_/|_\____/ \____/ .___/\__,_/\__,_/\__/\___/
/_/
EOF
}
function detect_service() {
pushd $(mktemp -d) >/dev/null
pct pull "$1" /usr/bin/update update 2>/dev/null
service=$(cat update | sed 's|.*/ct/||g' | sed 's|\.sh).*||g')
popd >/dev/null
}
function dry_run_container() {
local container="$1"
local service="$2"
# Extract app name and source repo directly from check_for_gh_release call in the ct script
# Pattern: check_for_gh_release "appname" "owner/repo"
local check_line app_name app_lc source_repo
check_line=$(echo "$script" | grep -m1 'check_for_gh_release')
if [[ -z "$check_line" ]]; then
echo -e "${YW}[DRY-RUN]${CL} Container $container ($service): no check_for_gh_release found — skipping"
DRY_RUN_RESULT="no check_for_gh_release found — skipping"
return
fi
app_name=$(echo "$check_line" | cut -d'"' -f2)
source_repo=$(echo "$check_line" | cut -d'"' -f4)
app_lc=$(echo "${app_name,,}" | tr -d ' ')
if [[ -z "$source_repo" || "$source_repo" != *"/"* ]]; then
echo -e "${YW}[DRY-RUN]${CL} Container $container ($service): cannot parse source repo — skipping"
DRY_RUN_RESULT="cannot parse source repo — skipping"
return
fi
# Read installed version from container (stored by check_for_gh_release as ~/.<appname>)
local current_version
current_version=$(pct exec "$container" -- bash -c "cat \$HOME/.${app_lc} 2>/dev/null" 2>/dev/null || true)
current_version="${current_version#v}"
# Query latest release from GitHub API
local latest_version
latest_version=$(curl -sSL --max-time 10 \
-H 'Accept: application/vnd.github+json' \
-H 'X-GitHub-Api-Version: 2022-11-28' \
"https://api.github.com/repos/${source_repo}/releases/latest" 2>/dev/null |
grep '"tag_name"' | head -1 | cut -d'"' -f4 | sed 's/^v//')
if [[ -z "$latest_version" ]]; then
echo -e "${YW}[DRY-RUN]${CL} Container $container ($service): cannot fetch latest version from $source_repo"
DRY_RUN_RESULT="cannot fetch latest version from $source_repo"
return
fi
if [[ -z "$current_version" ]]; then
echo -e "${BL}[DRY-RUN]${CL} Container $container ($service): installed version unknown, latest: ${latest_version} (${source_repo})"
DRY_RUN_RESULT="version unknown — latest: ${latest_version}"
elif [[ "$current_version" == "$latest_version" ]]; then
echo -e "${GN}[DRY-RUN]${CL} Container $container ($service): up to date (${current_version})"
DRY_RUN_RESULT="up to date (${current_version})"
else
echo -e "${YW}[DRY-RUN]${CL} Container $container ($service): update available ${current_version}${latest_version}"
DRY_RUN_RESULT="update available ${current_version}${latest_version}"
fi
}
function backup_container() {
msg_info "Creating backup for container $1"
vzdump $1 --compress zstd --storage $STORAGE_CHOICE -notes-template "{{guestname}} - community-scripts backup updater" >/dev/null 2>&1
status=$?
if [ $status -eq 0 ]; then
msg_ok "Backup created"
else
msg_error "Backup failed for container $1"
exit 235
fi
}
function get_backup_storages() {
STORAGES=$(awk '
/^[a-z]+:/ {
if (name != "") {
if (has_backup || (!has_content && type == "dir")) print name
}
split($0, a, ":")
type = a[1]
name = a[2]
gsub(/^[ \t]+|[ \t]+$/, "", name)
has_content = 0
has_backup = 0
}
/^[ \t]*content/ {
has_content = 1
if ($0 ~ /backup/) has_backup = 1
}
END {
if (name != "") {
if (has_backup || (!has_content && type == "dir")) print name
}
}
' /etc/pve/storage.cfg)
}
# Structured result tracking for the final summary report
# Each entry: "CTID|service|STATUS|details"
declare -a UPDATE_RESULTS=()
function log_result() {
# log_result <ctid> <service> <STATUS> <details>
UPDATE_RESULTS+=("${1}|${2}|${3}|${4}")
}
header_info
# =============================================================================
# LOGGING SETUP
# Key events are written directly to a timestamped log file under
# /usr/local/community-scripts/update_apps/ — this avoids any stdout
# redirection that would break interactive spinners or whiptail dialogs.
# The full summary table is appended at the end of the run.
# =============================================================================
LOG_DIR="/usr/local/community-scripts/update_apps"
mkdir -p "$LOG_DIR"
LOG_FILE="${LOG_DIR}/$(date '+%Y%m%d_%H%M%S').log"
echo "Update started: $(date '+%Y-%m-%d %H:%M:%S')" >"$LOG_FILE"
function log_write() {
echo "[$(date '+%H:%M:%S')] $*" >>"$LOG_FILE"
}
# Skip confirmation if var_skip_confirm is set to yes
if [[ "$var_skip_confirm" != "yes" ]]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "LXC App Update" --yesno "This will update apps in LXCs installed by Helper-Scripts. Proceed?" 10 58 || exit
fi
tags_formatted="${var_tags//|/, }"
msg_info "Loading all possible LXC containers from Proxmox VE with tags: ${tags_formatted}. This may take a few seconds..."
NODE=$(hostname)
containers=$(pct list | tail -n +2 | awk '{print $0 " " $4}')
if [ -z "$containers" ]; then
whiptail --title "LXC Container Update" --msgbox "No LXC containers available!" 10 60
exit 234
fi
menu_items=()
FORMAT="%-10s %-15s %-10s"
TAGS="${var_tags:-community-script|proxmox-helper-scripts}"
while read -r container; do
container_id=$(echo $container | awk '{print $1}')
container_name=$(echo $container | awk '{print $2}')
container_status=$(echo $container | awk '{print $3}')
formatted_line=$(printf "$FORMAT" "$container_name" "$container_status")
if pct config "$container_id" | grep -qE "[^-][; ](${TAGS}).*"; then
menu_items+=("$container_id" "$formatted_line" "OFF")
fi
done <<<"$containers"
msg_ok "Loaded $((${#menu_items[@]} / 3)) containers"
# Determine container selection based on var_container
if [[ -n "$var_container" ]]; then
case "$var_container" in
all)
# Select all containers with matching tags
CHOICE=""
for ((i = 0; i < ${#menu_items[@]}; i += 3)); do
CHOICE="$CHOICE ${menu_items[$i]}"
done
CHOICE=$(echo "$CHOICE" | xargs)
;;
all_running)
# Select only running containers with matching tags
CHOICE=""
for ((i = 0; i < ${#menu_items[@]}; i += 3)); do
cid="${menu_items[$i]}"
if pct status "$cid" 2>/dev/null | grep -q "running"; then
CHOICE="$CHOICE $cid"
fi
done
CHOICE=$(echo "$CHOICE" | xargs)
;;
all_stopped)
# Select only stopped containers with matching tags
CHOICE=""
for ((i = 0; i < ${#menu_items[@]}; i += 3)); do
cid="${menu_items[$i]}"
if pct status "$cid" 2>/dev/null | grep -q "stopped"; then
CHOICE="$CHOICE $cid"
fi
done
CHOICE=$(echo "$CHOICE" | xargs)
;;
*)
# Assume comma-separated list of container IDs
CHOICE=$(echo "$var_container" | tr ',' ' ')
;;
esac
if [[ -z "$CHOICE" ]]; then
msg_error "No containers matched the selection criteria: $var_container ${var_tags:-community-script|proxmox-helper-scripts}"
exit 234
fi
msg_ok "Selected containers: $CHOICE"
else
CHOICE=$(whiptail --title "LXC Container Update" \
--checklist "Select LXC containers to update:" 25 60 13 \
"${menu_items[@]}" 3>&2 2>&1 1>&3 | tr -d '"')
if [ -z "$CHOICE" ]; then
whiptail --title "LXC Container Update" \
--msgbox "No containers selected!" 10 60
exit 0
fi
fi
header_info
# Determine backup choice based on var_backup
# Dry-run never needs a backup — skip the prompt entirely
if [[ "$var_dry_run" == "yes" ]]; then
BACKUP_CHOICE="no"
elif [[ -n "$var_backup" ]]; then
BACKUP_CHOICE="$var_backup"
else
BACKUP_CHOICE="no"
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "LXC Container Update" --yesno "Do you want to backup your containers before update?" 10 58); then
BACKUP_CHOICE="yes"
fi
fi
# Determine unattended update based on var_unattended
# Dry-run never executes updates — skip the prompt entirely
if [[ "$var_dry_run" == "yes" ]]; then
UNATTENDED_UPDATE="no"
elif [[ -n "$var_unattended" ]]; then
UNATTENDED_UPDATE="$var_unattended"
else
UNATTENDED_UPDATE="no"
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "LXC Container Update" --yesno "Run updates unattended?" 10 58); then
UNATTENDED_UPDATE="yes"
fi
fi
if [ "$BACKUP_CHOICE" == "yes" ]; then
get_backup_storages
if [ -z "$STORAGES" ]; then
msg_error "No storage with 'backup' support found!"
exit 119
fi
# Determine storage based on var_backup_storage
if [[ -n "$var_backup_storage" ]]; then
# Validate that the specified storage exists and supports backups
if echo "$STORAGES" | grep -qw "$var_backup_storage"; then
STORAGE_CHOICE="$var_backup_storage"
msg_ok "Using backup storage: $STORAGE_CHOICE"
else
msg_error "Specified backup storage '$var_backup_storage' not found or doesn't support backups!"
msg_info "Available storages: $(echo $STORAGES | tr '\n' ' ')"
exit 119
fi
else
MENU_ITEMS=()
for STORAGE in $STORAGES; do
MENU_ITEMS+=("$STORAGE" "")
done
STORAGE_CHOICE=$(whiptail --title "Select storage device" --menu "Select a storage device (Only storage devices with 'backup' support are listed):" 15 50 5 "${MENU_ITEMS[@]}" 3>&1 1>&2 2>&3)
if [ -z "$STORAGE_CHOICE" ]; then
msg_error "No storage selected!"
exit 0
fi
fi
fi
UPDATE_CMD="update;"
if [ "$UNATTENDED_UPDATE" == "yes" ]; then
UPDATE_CMD="export PHS_SILENT=1;update;"
fi
containers_needing_reboot=()
for container in $CHOICE; do
echo -e "${BL}[INFO]${CL} Updating container $container"
log_write "Container $container: starting"
if [ "$BACKUP_CHOICE" == "yes" ]; then
backup_container $container
fi
os=$(pct config "$container" | awk '/^ostype/ {print $2}')
status=$(pct status $container)
template=$(pct config $container | grep -q "template:" && echo "true" || echo "false")
if [ "$template" == "false" ] && [ "$status" == "status: stopped" ]; then
echo -e "${BL}[Info]${GN} Starting${BL} $container ${CL} \n"
pct start $container
echo -e "${BL}[Info]${GN} Waiting For${BL} $container${CL}${GN} To Start ${CL} \n"
sleep 5
fi
#1) Detect service using the service name in the update command
detect_service $container
#1.1) If update script not detected, return
if [ -z "${service}" ]; then
echo -e "${YW}[WARN]${CL} Update script not found. Skipping to next container"
log_result "$container" "(unknown)" "SKIPPED" "No update script found in container"
log_write "Container $container: SKIPPED — no update script found"
continue
else
echo -e "${BL}[INFO]${CL} Detected service: ${GN}${service}${CL}"
log_write "Container $container: detected service '$service'"
fi
#2) Extract service build/update resource requirements from config/installation file
script=$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${service}.sh)
#2.1) Check if the script downloaded successfully
if [ $? -ne 0 ]; then
echo -e "${RD}[ERROR]${CL} Issue while downloading install script."
echo -e "${YW}[WARN]${CL} Unable to assess build resource requirements. Proceeding with current resources."
fi
config=$(pct config "$container")
build_cpu=$(echo "$script" | { grep -m 1 "var_cpu" || test $? = 1; } | sed 's|.*=||g' | sed 's|"||g' | sed 's|.*var_cpu:-||g' | sed 's|}||g')
build_ram=$(echo "$script" | { grep -m 1 "var_ram" || test $? = 1; } | sed 's|.*=||g' | sed 's|"||g' | sed 's|.*var_ram:-||g' | sed 's|}||g')
run_cpu=$(echo "$script" | { grep -m 1 "pct set \$CTID -cores" || test $? = 1; } | sed 's|.*cores ||g')
run_ram=$(echo "$script" | { grep -m 1 "pct set \$CTID -memory" || test $? = 1; } | sed 's|.*memory ||g')
current_cpu=$(echo "$config" | grep -m 1 "cores:" | sed 's|cores: ||g')
current_ram=$(echo "$config" | grep -m 1 "memory:" | sed 's|memory: ||g')
#Test if all values are valid (>0)
if [ -z "${run_cpu}" ] || [ "$run_cpu" -le 0 ]; then
#echo "No valid value found for run_cpu. Assuming same as current configuration."
run_cpu=$current_cpu
fi
if [ -z "${run_ram}" ] || [ "$run_ram" -le 0 ]; then
#echo "No valid value found for run_ram. Assuming same as current configuration."
run_ram=$current_ram
fi
if [ -z "${build_cpu}" ] || [ "$build_cpu" -le 0 ]; then
#echo "No valid value found for build_cpu. Assuming same as current configuration."
build_cpu=$current_cpu
fi
if [ -z "${build_ram}" ] || [ "$build_ram" -le 0 ]; then
#echo "No valid value found for build_ram. Assuming same as current configuration."
build_ram=$current_ram
fi
UPDATE_BUILD_RESOURCES=0
if [ "$build_cpu" -gt "$run_cpu" ] || [ "$build_ram" -gt "$run_ram" ]; then
UPDATE_BUILD_RESOURCES=1
fi
#3) if build resources are different than run resources, then:
if [ "$UPDATE_BUILD_RESOURCES" -eq "1" ] && [[ "$var_dry_run" != "yes" ]]; then
pct set "$container" --cores "$build_cpu" --memory "$build_ram"
fi
#3.5) Dry-run: report update availability without applying
if [[ "$var_dry_run" == "yes" ]]; then
DRY_RUN_RESULT=""
dry_run_container "$container" "$service"
log_result "$container" "$service" "DRY-RUN" "${DRY_RUN_RESULT:-version check only}"
log_write "Container $container ($service): DRY-RUN — ${DRY_RUN_RESULT:-version check only}"
continue
fi
#4) Update service, using the update command
# Prepend a no-op 'clear' wrapper to PATH so update scripts calling clear
# don't fail without a TTY — works for all shells incl. ash (no export -f)
SETUP_CMD="mkdir -p /tmp/.nc; printf '#!/bin/sh\n:\n' > /tmp/.nc/clear; chmod +x /tmp/.nc/clear; export PATH=/tmp/.nc:\$PATH; export TERM=dumb; "
case "$os" in
alpine) pct exec "$container" -- ash -c "${SETUP_CMD}${UPDATE_CMD}" ;;
archlinux) pct exec "$container" -- bash -c "${SETUP_CMD}${UPDATE_CMD}" ;;
fedora | rocky | centos | alma) pct exec "$container" -- bash -c "${SETUP_CMD}${UPDATE_CMD}" ;;
ubuntu | debian | devuan) pct exec "$container" -- bash -c "${SETUP_CMD}${UPDATE_CMD}" ;;
opensuse) pct exec "$container" -- bash -c "${SETUP_CMD}${UPDATE_CMD}" ;;
esac
exit_code=$?
#5) if build resources are different than run resources, then:
if [ "$UPDATE_BUILD_RESOURCES" -eq "1" ]; then
pct set "$container" --cores "$run_cpu" --memory "$run_ram"
fi
if pct exec "$container" -- [ -e "/var/run/reboot-required" ]; then
# Get the container's hostname and add it to the list
container_hostname=$(pct exec "$container" hostname)
containers_needing_reboot+=("$container ($container_hostname)")
fi
if [ "$template" == "false" ] && [ "$status" == "status: stopped" ]; then
echo -e "${BL}[Info]${GN} Shutting down${BL} $container ${CL} \n"
pct shutdown $container &>/dev/null &
fi
if [ $exit_code -eq 0 ]; then
msg_ok "Updated container $container"
log_result "$container" "$service" "OK" "Updated successfully"
log_write "Container $container ($service): OK"
elif [ $exit_code -eq 75 ]; then
echo -e "${YW}[WARN]${CL} Container $container skipped (requires interactive mode)"
log_result "$container" "$service" "SKIPPED" "Requires interactive mode (exit 75)"
log_write "Container $container ($service): SKIPPED — requires interactive mode"
elif [ $exit_code -eq 113 ]; then
echo -e "${YW}[WARN]${CL} Container $container skipped (under-provisioned: increase CPU/RAM to match template)"
log_result "$container" "$service" "SKIPPED" "Under-provisioned — increase CPU/RAM to match template"
log_write "Container $container ($service): SKIPPED — under-provisioned"
elif [ $exit_code -eq 114 ]; then
echo -e "${YW}[WARN]${CL} Container $container skipped (storage critically low on /boot)"
log_result "$container" "$service" "SKIPPED" "Storage critically low on /boot (>80%)"
log_write "Container $container ($service): SKIPPED — storage critically low on /boot"
elif [ "$BACKUP_CHOICE" == "yes" ]; then
msg_error "Update failed for container $container (exit code: $exit_code) — attempting restore"
log_write "Container $container ($service): FAILED (exit $exit_code) — attempting restore"
msg_info "Restoring LXC $container from backup ($STORAGE_CHOICE)"
pct stop $container
LXC_STORAGE=$(pct config $container | awk -F '[:,]' '/rootfs/ {print $2}')
BACKUP_ENTRY=$(pvesm list "$STORAGE_CHOICE" 2>/dev/null | awk -v ctid="$container" '$1 ~ "vzdump-lxc-"ctid"-" || $1 ~ "/ct/"ctid"/" {print $1}' | sort -r | head -n1)
if [ -z "$BACKUP_ENTRY" ]; then
msg_error "No backup found in storage $STORAGE_CHOICE for container $container"
log_result "$container" "$service" "FAILED" "Update failed (exit $exit_code) — no backup found for restore"
log_write "Container $container ($service): FAILED — no backup found for restore"
exit 235
fi
msg_info "Restoring from: $BACKUP_ENTRY"
pct restore $container "$BACKUP_ENTRY" --storage $LXC_STORAGE --force >/dev/null 2>&1
restorestatus=$?
if [ $restorestatus -eq 0 ]; then
pct start $container
msg_ok "Container $container successfully restored from backup"
log_result "$container" "$service" "RESTORED" "Update failed (exit $exit_code) — restored from backup"
log_write "Container $container ($service): RESTORED from $BACKUP_ENTRY"
else
msg_error "Restore failed for container $container"
log_result "$container" "$service" "FAILED" "Update failed (exit $exit_code) — restore also failed"
log_write "Container $container ($service): FAILED — restore also failed"
exit 235
fi
else
msg_error "Update failed for container $container (exit code: $exit_code)"
log_result "$container" "$service" "FAILED" "Exit code $exit_code"
log_write "Container $container ($service): FAILED (exit $exit_code)"
if [[ "$var_continue_on_error" == "yes" ]]; then
echo -e "${YW}[WARN]${CL} Continuing to next container (var_continue_on_error=yes)"
continue
else
exit "$exit_code"
fi
fi
done
wait
header_info
if [[ "$var_dry_run" == "yes" ]]; then
echo -e "${GN}Dry-run complete. No containers were modified.${CL}\n"
else
echo -e "${GN}The process is complete, and the containers have been successfully updated.${CL}\n"
fi
# =============================================================================
# SUMMARY REPORT
# =============================================================================
if [ "${#UPDATE_RESULTS[@]}" -gt 0 ]; then
SEPARATOR="━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
HEADER=$(printf " %-8s %-22s %-10s %s" "CTID" "Service" "Status" "Details")
# terminal output (with colours)
echo ""
echo "$SEPARATOR"
echo "$HEADER"
echo "$SEPARATOR"
for entry in "${UPDATE_RESULTS[@]}"; do
IFS='|' read -r _ctid _svc _status _details <<<"$entry"
case "$_status" in
OK) _color="${GN}" ;;
FAILED) _color="${RD}" ;;
RESTORED) _color="${YW}" ;;
*) _color="${YW}" ;;
esac
printf " %-8s %-22s ${_color}%-10s${CL} %s\n" "$_ctid" "$_svc" "$_status" "$_details"
done
echo "$SEPARATOR"
echo ""
echo "Full log: $LOG_FILE"
echo ""
# append plain-text summary to log file
{
echo ""
echo "Update finished: $(date '+%Y-%m-%d %H:%M:%S')"
echo "$SEPARATOR"
echo "$HEADER"
echo "$SEPARATOR"
for entry in "${UPDATE_RESULTS[@]}"; do
IFS='|' read -r _ctid _svc _status _details <<<"$entry"
printf " %-8s %-22s %-10s %s\n" "$_ctid" "$_svc" "$_status" "$_details"
done
echo "$SEPARATOR"
} >>"$LOG_FILE"
fi
if [ "${#containers_needing_reboot[@]}" -gt 0 ]; then
echo -e "${RD}The following containers require a reboot:${CL}"
for container_name in "${containers_needing_reboot[@]}"; do
echo "$container_name"
done
# Determine reboot choice based on var_auto_reboot
REBOOT_CHOICE="no"
if [[ -n "$var_auto_reboot" ]]; then
REBOOT_CHOICE="$var_auto_reboot"
else
echo -ne "${INFO} Do you wish to reboot these containers? <yes/No> "
read -r prompt
if [[ ${prompt,,} =~ ^(yes)$ ]]; then
REBOOT_CHOICE="yes"
fi
fi
if [[ "$REBOOT_CHOICE" == "yes" ]]; then
echo -e "${CROSS}${HOLD} ${YWB}Rebooting containers.${CL}"
for container_name in "${containers_needing_reboot[@]}"; do
container=$(echo $container_name | cut -d " " -f 1)
pct reboot ${container}
done
fi
fi
+124
View File
@@ -0,0 +1,124 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/clean-lxcs.sh)"
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info() {
clear
cat <<"EOF"
________ __ _ ________
/ ____/ /__ ____ _____ / / | |/ / ____/
/ / / / _ \/ __ `/ __ \ / / | / /
/ /___/ / __/ /_/ / / / / / /___/ / /___
\____/_/\___/\__,_/_/ /_/ /_____/_/|_\____/
EOF
}
set -eEuo pipefail
BL="\033[36m"
RD="\033[01;31m"
CM='\xE2\x9C\x94\033'
GN="\033[1;92m"
CL="\033[m"
# Telemetry
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "clean-lxcs" "pve"
header_info
echo "Loading..."
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Updater" --yesno "This will clean logs, cache and update package lists on selected LXC Containers. Proceed?" 10 58
NODE=$(hostname)
EXCLUDE_MENU=()
MSG_MAX_LENGTH=0
while read -r TAG ITEM; do
OFFSET=2
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=${#ITEM}+OFFSET
EXCLUDE_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
excluded_containers=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Containers on $NODE" --checklist "\nSelect containers to skip from cleaning:\n" \
16 $((MSG_MAX_LENGTH + 23)) 6 "${EXCLUDE_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
if [ $? -ne 0 ]; then
exit
fi
function run_lxc_clean() {
local container=$1
header_info
name=$(pct exec "$container" hostname)
pct exec "$container" -- bash -c '
BL="\033[36m"; GN="\033[1;92m"; CL="\033[m"
name=$(hostname)
if [ -e /etc/alpine-release ]; then
echo -e "${BL}[Info]${GN} Cleaning $name (Alpine)${CL}\n"
apk cache clean
find /var/log -type f -delete 2>/dev/null
find /tmp -mindepth 1 -delete 2>/dev/null
apk update
elif [ -e /etc/redhat-release ]; then
echo -e "${BL}[Info]${GN} Cleaning $name (CentOS)${CL}\n"
yum clean all
find /var/log -type f -delete 2>/dev/null
find /tmp -mindepth 1 -delete 2>/dev/null
yum update
yum upgrade -y
else
echo -e "${BL}[Info]${GN} Cleaning $name (Debian/Ubuntu)${CL}\n"
find /var/cache -type f -delete 2>/dev/null
find /var/log -type f -delete 2>/dev/null
find /tmp -mindepth 1 -delete 2>/dev/null
apt -y --purge autoremove
apt -y autoclean
rm -rf /var/lib/apt/lists/*
apt update
fi
'
}
for container in $(pct list | awk '{if(NR>1) print $1}'); do
if [[ " ${excluded_containers[@]} " =~ " $container " ]]; then
header_info
echo -e "${BL}[Info]${GN} Skipping ${BL}$container${CL}"
sleep 1
continue
fi
os=$(pct config "$container" | awk '/^ostype/ {print $2}')
# Supported: debian, ubuntu, alpine, centos
if [ "$os" != "debian" ] && [ "$os" != "ubuntu" ] && [ "$os" != "alpine" ] && [ "$os" != "centos" ]; then
header_info
echo -e "${BL}[Info]${GN} Skipping ${RD}$container is not Debian, Ubuntu, Alpine or Red Hat Compatible${CL} \n"
sleep 1
continue
fi
status=$(pct status "$container")
template=$(pct config "$container" | grep -q "template:" && echo "true" || echo "false")
if [ "$template" == "false" ] && [ "$status" == "status: stopped" ]; then
echo -e "${BL}[Info]${GN} Starting${BL} $container ${CL} \n"
pct start "$container"
echo -e "${BL}[Info]${GN} Waiting For${BL} $container${CL}${GN} To Start ${CL} \n"
sleep 5
run_lxc_clean "$container"
echo -e "${BL}[Info]${GN} Shutting down${BL} $container ${CL} \n"
pct shutdown "$container" &
elif [ "$status" == "status: running" ]; then
run_lxc_clean "$container"
fi
done
wait
header_info
echo -e "${GN} Finished, Selected Containers Cleaned. ${CL} \n"
+94
View File
@@ -0,0 +1,94 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/execute.sh)"
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: jeroenzwart
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info() {
clear
cat <<"EOF"
______ __ __ _ ________
/ ____/ _____ _______ __/ /____ / / | |/ / ____/
/ __/ | |/_/ _ \/ ___/ / / / __/ _ \ / / | / /
/ /____> </ __/ /__/ /_/ / /_/ __/ / /___/ / /___
/_____/_/|_|\___/\___/\__,_/\__/\___/ /_____/_/|_\____/
EOF
}
set -eEuo pipefail
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
CM='\xE2\x9C\x94\033'
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
# Telemetry
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "execute-lxcs" "pve"
header_info
echo "Loading..."
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Execute" --yesno "This will execute a command inside selected LXC Containers. Proceed?" 10 58
NODE=$(hostname)
EXCLUDE_MENU=()
MSG_MAX_LENGTH=0
while read -r TAG ITEM; do
OFFSET=2
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=${#ITEM}+OFFSET
EXCLUDE_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
excluded_containers=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Containers on $NODE" --checklist "\nSelect containers to skip from executing:\n" \
16 $((MSG_MAX_LENGTH + 23)) 6 "${EXCLUDE_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
if [ $? -ne 0 ]; then
exit
fi
read -r -p "Enter here command for inside the containers: " custom_command
header_info
echo "One moment please...\n"
function execute_in() {
container=$1
name=$(pct exec "$container" hostname)
echo -e "${BL}[Info]${GN} Execute inside${BL} ${name}${GN} with output: ${CL}"
if ! pct exec "$container" -- bash -c "command ${custom_command} >/dev/null 2>&1"; then
echo -e "${BL}[Info]${GN} Skipping ${name} ${RD}$container has no command: ${custom_command}"
else
pct exec "$container" -- bash -c "${custom_command}" | tee
fi
}
for container in $(pct list | awk '{if(NR>1) print $1}'); do
if [[ " ${excluded_containers[@]} " =~ " $container " ]]; then
echo -e "${BL}[Info]${GN} Skipping ${BL}$container${CL}"
else
os=$(pct config "$container" | awk '/^ostype/ {print $2}')
if [ "$os" != "debian" ] && [ "$os" != "ubuntu" ]; then
echo -e "${BL}[Info]${GN} Skipping ${name} ${RD}$container is not Debian or Ubuntu ${CL}"
continue
fi
status=$(pct status "$container")
template=$(pct config "$container" | grep -q "template:" && echo "true" || echo "false")
if [ "$template" == "false" ] && [ "$status" == "status: stopped" ]; then
echo -e "${BL}[Info]${GN} Starting${BL} $container ${CL}"
pct start "$container"
echo -e "${BL}[Info]${GN} Waiting For${BL} $container${CL}${GN} To Start ${CL}"
sleep 5
execute_in "$container"
echo -e "${BL}[Info]${GN} Shutting down${BL} $container ${CL}"
pct shutdown "$container" &
elif [ "$status" == "status: running" ]; then
execute_in "$container"
fi
fi
done
wait
echo -e "${GN} Finished, execute command inside selected containers. ${CL} \n"
+197
View File
@@ -0,0 +1,197 @@
# Это позволяет поддерживать производительность SSD за счет управления неиспользуемыми блоками. Системы хранения с тонким выделением ресурсов также требуют управления для предотвращения ненужного использования хранилища. Виртуальные машины автоматизируют fstrim, в то время как контейнеры LXC требуют ручных или автоматизированных процессов fstrim для оптимальной производительности.
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/fstrim.sh)"
#!/usr/bin/env bash
set -eEuo pipefail
function header_info() {
clear
cat <<"EOF"
_______ __ __ ______ _
/ ____(_) /__ _______ _______/ /____ ____ ___ /_ __/____(_)___ ___
/ /_ / / / _ \/ ___/ / / / ___/ __/ _ \/ __ `__ \ / / / ___/ / __ `__ \
/ __/ / / / __(__ ) /_/ (__ ) /_/ __/ / / / / / / / / / / / / / / / /
/_/ /_/_/\___/____/\__, /____/\__/\___/_/ /_/ /_/ /_/ /_/ /_/_/ /_/ /_/
/____/
EOF
}
BL="\033[36m"
RD="\033[01;31m"
GN="\033[1;92m"
CL="\033[m"
# Telemetry
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "fstrim" "pve"
LOGFILE="/var/log/fstrim.log"
touch "$LOGFILE"
chmod 600 "$LOGFILE"
echo -e "\n----- $(date '+%Y-%m-%d %H:%M:%S') | fstrim Run by $(whoami) on $(hostname) -----" >>"$LOGFILE"
header_info
echo "Loading..."
whiptail --backtitle "Proxmox VE Helper Scripts" \
--title "About fstrim (LXC)" \
--msgbox "The 'fstrim' command releases unused blocks back to the storage device. This only makes sense for containers on SSD, NVMe, Thin-LVM, or storage with discard/TRIM support.\n\nIf your root filesystem or container disks are on classic HDDs, thick LVM, or unsupported storage types, running fstrim will have no effect.\n\nRecommended:\n- Use fstrim only on SSD, NVMe, or thin-provisioned storage with discard enabled.\n- For ZFS, ensure 'autotrim=on' is set on your pool.\n" 16 88
ROOT_FS=$(df -Th "/" | awk 'NR==2 {print $2}')
if [ "$ROOT_FS" != "ext4" ]; then
whiptail --backtitle "Proxmox VE Helper Scripts" \
--title "Warning" \
--yesno "Root filesystem is not ext4 ($ROOT_FS).\nContinue anyway?" 12 80 || exit 0
fi
NODE=$(hostname)
EXCLUDE_MENU=()
STOPPED_MENU=()
MAX_NAME_LEN=0
MAX_STAT_LEN=0
# Build arrays with one pct list
mapfile -t CTLINES < <(pct list | awk 'NR>1')
for LINE in "${CTLINES[@]}"; do
CTID=$(awk '{print $1}' <<<"$LINE")
STATUS=$(awk '{print $2}' <<<"$LINE")
NAME=$(awk '{print $3}' <<<"$LINE")
((${#NAME} > MAX_NAME_LEN)) && MAX_NAME_LEN=${#NAME}
((${#STATUS} > MAX_STAT_LEN)) && MAX_STAT_LEN=${#STATUS}
done
FMT="%-${MAX_NAME_LEN}s | %-${MAX_STAT_LEN}s"
for LINE in "${CTLINES[@]}"; do
CTID=$(awk '{print $1}' <<<"$LINE")
STATUS=$(awk '{print $2}' <<<"$LINE")
NAME=$(awk '{print $3}' <<<"$LINE")
DESC=$(printf "$FMT" "$NAME" "$STATUS")
EXCLUDE_MENU+=("$CTID" "$DESC" "OFF")
if [[ "$STATUS" == "stopped" ]]; then
STOPPED_MENU+=("$CTID" "$DESC" "OFF")
fi
done
excluded_containers_raw=$(whiptail --backtitle "Proxmox VE Helper Scripts" \
--title "Containers on $NODE" \
--checklist "\nSelect containers to skip from trimming:\n" \
20 $((MAX_NAME_LEN + MAX_STAT_LEN + 20)) 12 "${EXCLUDE_MENU[@]}" 3>&1 1>&2 2>&3)
[ $? -ne 0 ] && exit
read -ra EXCLUDED <<<$(echo "$excluded_containers_raw" | tr -d '"')
TO_START=()
if [ ${#STOPPED_MENU[@]} -gt 0 ]; then
for ((i = 0; i < ${#STOPPED_MENU[@]}; i += 3)); do
CTID="${STOPPED_MENU[i]}"
DESC="${STOPPED_MENU[i + 1]}"
if [[ " ${EXCLUDED[*]} " =~ " $CTID " ]]; then
continue
fi
header_info
echo -e "${BL}[Info]${GN} Container $CTID ($DESC) is currently stopped.${CL}"
read -rp "Temporarily start for fstrim? [y/N]: " answer
if [[ "$answer" =~ ^[Yy]$ ]]; then
TO_START+=("$CTID")
fi
done
fi
declare -A WAS_STOPPED
for ct in "${TO_START[@]}"; do
WAS_STOPPED["$ct"]=1
done
function trim_container() {
local container="$1"
local name="$2"
header_info
echo -e "${BL}[Info]${GN} Trimming ${BL}$container${CL} \n"
local before_trim after_trim
local lv_name="vm-${container}-disk-0"
if lvs --noheadings -o lv_name 2>/dev/null | grep -qw "$lv_name"; then
before_trim=$(lvs --noheadings -o lv_name,data_percent 2>/dev/null | awk -v ctid="$lv_name" '$1 == ctid {gsub(/%/, "", $2); print $2}')
[[ -n "$before_trim" ]] && echo -e "${RD}Data before trim $before_trim%${CL}" || echo -e "${RD}Data before trim: not available${CL}"
else
before_trim=""
echo -e "${RD}Data before trim: not available (non-LVM storage)${CL}"
fi
local fstrim_output
fstrim_output=$(pct fstrim "$container" 2>&1)
if echo "$fstrim_output" | grep -qi "not supported"; then
echo -e "${RD}fstrim isnt supported on this storage!${CL}"
elif echo "$fstrim_output" | grep -Eq '([0-9]+(\.[0-9]+)?\s*[KMGT]?B)'; then
echo -e "${GN}fstrim result: $fstrim_output${CL}"
else
echo -e "${RD}fstrim result: $fstrim_output${CL}"
fi
if lvs --noheadings -o lv_name 2>/dev/null | grep -qw "$lv_name"; then
after_trim=$(lvs --noheadings -o lv_name,data_percent 2>/dev/null | awk -v ctid="$lv_name" '$1 == ctid {gsub(/%/, "", $2); print $2}')
[[ -n "$after_trim" ]] && echo -e "${GN}Data after trim $after_trim%${CL}" || echo -e "${GN}Data after trim: not available${CL}"
else
after_trim=""
echo -e "${GN}Data after trim: not available (non-LVM storage)${CL}"
fi
# Logging
echo "$(date '+%Y-%m-%d %H:%M:%S') | CTID=$container | Name=$name | Before=${before_trim:-N/A}% | After=${after_trim:-N/A}% | fstrim: $fstrim_output" >>"$LOGFILE"
sleep 0.5
}
for LINE in "${CTLINES[@]}"; do
CTID=$(awk '{print $1}' <<<"$LINE")
STATUS=$(awk '{print $2}' <<<"$LINE")
NAME=$(awk '{print $3}' <<<"$LINE")
if [[ " ${EXCLUDED[*]} " =~ " $CTID " ]]; then
header_info
echo -e "${BL}[Info]${GN} Skipping $CTID ($NAME, excluded)${CL}"
sleep 0.5
continue
fi
if pct config "$CTID" | grep -q "template:"; then
header_info
echo -e "${BL}[Info]${GN} Skipping $CTID ($NAME, template)${CL}\n"
sleep 0.5
continue
fi
if [[ "$STATUS" != "running" ]]; then
if [[ -n "${WAS_STOPPED[$CTID]:-}" ]]; then
header_info
echo -e "${BL}[Info]${GN} Starting $CTID ($NAME) for trim...${CL}"
pct start "$CTID"
sleep 2
else
header_info
echo -e "${BL}[Info]${GN} Skipping $CTID ($NAME, not running, not selected)${CL}"
sleep 0.5
continue
fi
fi
trim_container "$CTID" "$NAME"
if [[ -n "${WAS_STOPPED[$CTID]:-}" ]]; then
read -rp "Stop LXC $CTID ($NAME) again after trim? [Y/n]: " answer
if [[ ! "$answer" =~ ^[Nn]$ ]]; then
header_info
echo -e "${BL}[Info]${GN} Stopping $CTID ($NAME) again...${CL}"
pct stop "$CTID"
sleep 1
else
header_info
echo -e "${BL}[Info]${GN} Leaving $CTID ($NAME) running as requested.${CL}"
sleep 1
fi
fi
done
header_info
echo -e "${GN}Finished, LXC Containers Trimmed.${CL} \n"
echo -e "${BL}If you want to see the complete log: cat $LOGFILE${CL}"
exit 0
File diff suppressed because it is too large Load Diff
+171
View File
@@ -0,0 +1,171 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/netdata.sh)"
#!/usr/bin/env bash
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://www.netdata.cloud/ | Github: https://github.com/netdata/netdata
function header_info {
clear
cat <<"EOF"
_ __ __ ____ __
/ | / /__ / /_/ __ \____ _/ /_____ _
/ |/ / _ \/ __/ / / / __ `/ __/ __ `/
/ /| / __/ /_/ /_/ / /_/ / /_/ /_/ /
/_/ |_/\___/\__/_____/\__,_/\__/\__,_/
EOF
}
YW=$(echo "\033[33m")
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
silent() { "$@" >/dev/null 2>&1; }
# Telemetry
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "netdata" "addon"
set -e
header_info
echo "Loading..."
function msg_info() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
function msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
function msg_error() { echo -e "${RD}$1${CL}"; }
# This function checks the version of Proxmox Virtual Environment (PVE) and exits if the version is not supported.
# Supported: Proxmox VE 8.0.x 8.9.x and 9.09.x
pve_check() {
local PVE_VER
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
# Check for Proxmox VE 8.x: allow 8.08.9
if [[ "$PVE_VER" =~ ^8\.([0-9]+) ]]; then
local MINOR="${BASH_REMATCH[1]}"
if ((MINOR < 0 || MINOR > 9)); then
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported: Proxmox VE version 8.0 8.9"
exit 105
fi
return 0
fi
# Check for Proxmox VE 9.x: allow 9.09.x
if [[ "$PVE_VER" =~ ^9\.([0-9]+) ]]; then
return 0
fi
# All other unsupported versions
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported versions: Proxmox VE 8.0 8.9 or 9.09.x"
exit 105
}
detect_codename() {
source /etc/os-release
if [[ "$ID" != "debian" ]]; then
msg_error "Unsupported base OS: $ID (only Proxmox VE / Debian supported)."
exit 238
fi
CODENAME="${VERSION_CODENAME:-}"
if [[ -z "$CODENAME" ]]; then
msg_error "Could not detect Debian codename."
exit 71
fi
echo "$CODENAME"
}
get_latest_repo_pkg() {
local REPO_URL=$1
curl -fsSL "$REPO_URL" |
grep -oP 'netdata-repo_[^"]+all\.deb' |
sort -V |
tail -n1
}
install() {
header_info
while true; do
read -p "Are you sure you want to install NetData on Proxmox VE host. Proceed(y/n)? " yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
read -r -p "Verbose mode? <y/N> " prompt
[[ ${prompt,,} =~ ^(y|yes)$ ]] && STD="" || STD="silent"
CODENAME=$(detect_codename)
REPO_URL="https://repo.netdata.cloud/repos/repoconfig/debian/${CODENAME}/"
msg_info "Setting up repository"
$STD apt-get install -y debian-keyring
PKG=$(get_latest_repo_pkg "$REPO_URL")
if [[ -z "$PKG" ]]; then
msg_error "Could not find netdata-repo package for Debian $CODENAME"
exit 237
fi
curl -fsSL "${REPO_URL}${PKG}" -o "$PKG"
$STD dpkg -i "$PKG"
rm -f "$PKG"
msg_ok "Set up repository"
msg_info "Installing Netdata"
$STD apt-get update
$STD apt-get install -y netdata
msg_ok "Installed Netdata"
msg_ok "Completed successfully!\n"
echo -e "\n Netdata should be reachable at${BL} http://$(hostname -I | awk '{print $1}'):19999 ${CL}\n"
}
uninstall() {
header_info
read -r -p "Verbose mode? <y/N> " prompt
[[ ${prompt,,} =~ ^(y|yes)$ ]] && STD="" || STD="silent"
msg_info "Uninstalling Netdata"
systemctl stop netdata || true
rm -rf /var/log/netdata /var/lib/netdata /var/cache/netdata /etc/netdata/go.d
rm -rf /etc/apt/trusted.gpg.d/netdata-archive-keyring.gpg /etc/apt/sources.list.d/netdata.list
$STD apt-get remove --purge -y netdata netdata-repo
systemctl daemon-reload
$STD apt autoremove -y
$STD userdel netdata || true
msg_ok "Uninstalled Netdata"
msg_ok "Completed successfully!\n"
}
header_info
pve_check
OPTIONS=(Install "Install NetData on Proxmox VE"
Uninstall "Uninstall NetData from Proxmox VE")
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "NetData" \
--menu "Select an option:" 10 58 2 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
case $CHOICE in
"Install") install ;;
"Uninstall") uninstall ;;
*)
echo "Exiting..."
exit 0
;;
esac
+72
View File
@@ -0,0 +1,72 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/update-repo.sh)"
#!/usr/bin/env bash
# Copyright (c) 2021-2026 tteck
# Author: MickLesk
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
__ __ __ __ ____
/ / / /___ ____/ /___ _/ /____ / __ \___ ____ ____
/ / / / __ \/ __ / __ `/ __/ _ \ / /_/ / _ \/ __ \/ __ \
/ /_/ / /_/ / /_/ / /_/ / /_/ __/ / _, _/ __/ /_/ / /_/ /
\____/ .___/\__,_/\__,_/\__/\___/ /_/ |_|\___/ .___/\____/
/_/ /_/
EOF
}
set -eEuo pipefail
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
# Telemetry
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "update-repo" "pve"
header_info
echo "Loading..."
NODE=$(hostname)
function update_container() {
container=$1
os=$(pct config "$container" | awk '/^ostype/ {print $2}')
if [[ "$os" == "ubuntu" || "$os" == "debian" ]]; then
echo -e "${BL}[Info]${GN} Checking /usr/bin/update in ${BL}$container${CL} (OS: ${GN}$os${CL})"
if pct exec "$container" -- [ -e /usr/bin/update ]; then
if pct exec "$container" -- grep -q "community-scripts/ProxmoxVE" /usr/bin/update; then
echo -e "${RD}[No Change]${CL} /usr/bin/update is already up to date in ${BL}$container${CL}.\n"
elif pct exec "$container" -- grep -q -v "tteck" /usr/bin/update; then
echo -e "${RD}[Warning]${CL} /usr/bin/update in ${BL}$container${CL} contains a different entry (${RD}tteck${CL}). No changes made.\n"
else
pct exec "$container" -- bash -c "sed -i 's/tteck\\/Proxmox/community-scripts\\/ProxmoxVE/g' /usr/bin/update"
if pct exec "$container" -- grep -q "community-scripts/ProxmoxVE" /usr/bin/update; then
echo -e "${GN}[Success]${CL} /usr/bin/update updated in ${BL}$container${CL}.\n"
else
echo -e "${RD}[Error]${CL} /usr/bin/update in ${BL}$container${CL} could not be updated properly.\n"
fi
fi
else
echo -e "${RD}[Error]${CL} /usr/bin/update not found in container ${BL}$container${CL}.\n"
fi
else
echo -e "${BL}[Info]${GN} Skipping ${BL}$container${CL} (not Debian/Ubuntu)\n"
fi
}
header_info
for container in $(pct list | awk '{if(NR>1) print $1}'); do
update_container "$container"
done
header_info
echo -e "${GN}The process is complete. The repositories have been switched to community-scripts/ProxmoxVE.${CL}\n"
+188
View File
@@ -0,0 +1,188 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/pbs-microcode.sh)"
# Микрокод процессора — это низкоуровневый программный слой, работающий на процессоре и предоставляющий исправления или обновления для его микропрограммы. Обновления микрокода могут исправлять аппаратные ошибки,
# повышать производительность и улучшать функции безопасности процессора. Этот скрипт адаптирован для среды Proxmox Backup Server и будет работать только на физических системах. При запуске в виртуализированной среде скрипт завершит работу.
# Обратите внимание, что механизмы обновления микропрограммы, такие как Intel Management Engine (ME) или AMD Platform Security Processor (PSP), могут различаться в зависимости от вашего процессора и его реализации. Пожалуйста, обратитесь к
# документации вашего процессора, чтобы проверить, можно ли применить обновления микропрограммы через операционную систему.
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: DonPablo1010 | Co-Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
____ __ ____ __
/ __ \_________ ________ ______________ _____ / |/ (_)_____________ _________ ____/ /__
/ /_/ / ___/ __ \/ ___/ _ \/ ___/ ___/ __ \/ ___/ / /|_/ / / ___/ ___/ __ \/ ___/ __ \/ __ / _ \
/ ____/ / / /_/ / /__/ __(__ |__ ) /_/ / / / / / / / /__/ / / /_/ / /__/ /_/ / /_/ / __/
/_/ /_/ \____/\___/\___/____/____/\____/_/ /_/ /_/_/\___/_/ \____/\___/\____/\__,_/\___/
Proxmox Backup Server Processor Microcode Updater
EOF
}
# Color definitions
RD=$(echo "\033[01;31m")
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
CROSS="${RD}${CL}"
msg_info() { echo -ne " ${HOLD} ${YW}$1..."; }
# Telemetry
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "pbs-microcode" "pve"
msg_ok() { echo -e "${BFR} ${CM} ${GN}$1${CL}"; }
msg_error() { echo -e "${BFR} ${CROSS} ${RD}$1${CL}"; }
header_info
# Check if running on bare metal using systemd-detect-virt.
virt=$(systemd-detect-virt)
if [ "$virt" != "none" ]; then
msg_error "This script must be run on bare metal. Detected virtual environment: $virt"
exit 232
fi
# Attempt to obtain the current loaded microcode revision
current_microcode=$(journalctl -k | grep -i 'microcode: Current revision:' | grep -oP 'Current revision: \K0x[0-9a-f]+')
[ -z "$current_microcode" ] && current_microcode="Not found."
intel() {
if ! dpkg -s iucode-tool >/dev/null 2>&1; then
msg_info "Installing iucode-tool (Intel microcode updater)"
apt-get install -y iucode-tool &>/dev/null
msg_ok "Installed iucode-tool"
else
msg_ok "Intel iucode-tool is already installed"
sleep 1
fi
intel_microcode=$(curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode/" | grep -o 'href="[^"]*amd64.deb"' | sed 's/href="//;s/"//')
[ -z "$intel_microcode" ] && {
whiptail --backtitle "Proxmox Backup Server Helper Scripts" --title "No Microcode Found" --msgbox "No microcode packages were found.\nTry again later." 10 68
msg_info "Exiting"
sleep 1
msg_ok "Done"
exit
}
MICROCODE_MENU=()
MSG_MAX_LENGTH=0
while read -r TAG ITEM; do
OFFSET=2
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=$((${#ITEM} + OFFSET))
MICROCODE_MENU+=("$TAG" "$ITEM " "OFF")
done < <(echo "$intel_microcode")
microcode=$(whiptail --backtitle "Proxmox Backup Server Helper Scripts" \
--title "Current Microcode Revision: ${current_microcode}" \
--radiolist "\nSelect a microcode package to install:\n" \
16 $((MSG_MAX_LENGTH + 58)) 6 "${MICROCODE_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
[ -z "$microcode" ] && {
whiptail --backtitle "Proxmox Backup Server Helper Scripts" --title "No Microcode Selected" --msgbox "No microcode package was selected." 10 68
msg_info "Exiting"
sleep 1
msg_ok "Done"
exit
}
msg_info "Downloading Intel processor microcode package $microcode"
curl -fsSL "http://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode/$microcode" -o $(basename "http://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode/$microcode")
msg_ok "Downloaded Intel processor microcode package $microcode"
msg_info "Installing $microcode (this might take a while)"
dpkg -i $microcode &>/dev/null
msg_ok "Installed $microcode"
msg_info "Cleaning up"
rm $microcode
msg_ok "Clean up complete"
echo -e "\nA system reboot is required to apply the changes.\n"
}
amd() {
amd_microcode=$(curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/" | grep -o 'href="[^"]*amd64.deb"' | sed 's/href="//;s/"//')
[ -z "$amd_microcode" ] && {
whiptail --backtitle "Proxmox Backup Server Helper Scripts" --title "No Microcode Found" --msgbox "No microcode packages were found.\nTry again later." 10 68
msg_info "Exiting"
sleep 1
msg_ok "Done"
exit
}
MICROCODE_MENU=()
MSG_MAX_LENGTH=0
while read -r TAG ITEM; do
OFFSET=2
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=$((${#ITEM} + OFFSET))
MICROCODE_MENU+=("$TAG" "$ITEM " "OFF")
done < <(echo "$amd_microcode")
microcode=$(whiptail --backtitle "Proxmox Backup Server Helper Scripts" \
--title "Current Microcode Revision: ${current_microcode}" \
--radiolist "\nSelect a microcode package to install:\n" \
16 $((MSG_MAX_LENGTH + 58)) 6 "${MICROCODE_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
[ -z "$microcode" ] && {
whiptail --backtitle "Proxmox Backup Server Helper Scripts" --title "No Microcode Selected" --msgbox "No microcode package was selected." 10 68
msg_info "Exiting"
sleep 1
msg_ok "Done"
exit
}
msg_info "Downloading AMD processor microcode package $microcode"
curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode" -o $(basename "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode")
msg_ok "Downloaded AMD processor microcode package $microcode"
msg_info "Installing $microcode (this might take a while)"
dpkg -i $microcode &>/dev/null
msg_ok "Installed $microcode"
msg_info "Cleaning up"
rm $microcode
msg_ok "Clean up complete"
echo -e "\nA system reboot is required to apply the changes.\n"
}
# Check if this is a Proxmox Backup Server by verifying the presence of the datastore config.
if [ ! -f /etc/proxmox-backup/user.cfg ]; then
header_info
msg_error "Proxmox Backup Server not detected!"
exit
fi
whiptail --backtitle "Proxmox Backup Server Helper Scripts" \
--title "Proxmox Backup Server Processor Microcode" \
--yesno "This script searches for CPU microcode packages and offers the option to install them.\nProceed?" 10 68
msg_info "Checking CPU vendor"
cpu=$(lscpu | grep -oP 'Vendor ID:\s*\K\S+' | head -n 1)
if [ "$cpu" == "GenuineIntel" ]; then
msg_ok "${cpu} detected"
sleep 1
intel
elif [ "$cpu" == "AuthenticAMD" ]; then
msg_ok "${cpu} detected"
sleep 1
amd
else
msg_error "CPU vendor ${cpu} is not supported"
exit
fi
+341
View File
@@ -0,0 +1,341 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/post-pbs-install.sh)"
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: tteck (tteckster) | MickLesk (CanbiZ) | thost96
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
header_info() {
clear
cat <<"EOF"
____ ____ _____ ____ __ ____ __ ____
/ __ \/ __ ) ___/ / __ \____ _____/ /_ / _/___ _____/ /_____ _/ / /
/ /_/ / __ \__ \ / /_/ / __ \/ ___/ __/ / // __ \/ ___/ __/ __ `/ / /
/ ____/ /_/ /__/ / / ____/ /_/ (__ ) /_ _/ // / / (__ ) /_/ /_/ / / /
/_/ /_____/____/ /_/ \____/____/\__/ /___/_/ /_/____/\__/\__,_/_/_/
EOF
}
RD=$(echo "\033[01;31m")
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
CROSS="${RD}${CL}"
set -euo pipefail
shopt -s inherit_errexit nullglob
msg_info() { echo -ne " ${HOLD} ${YW}$1..."; }
msg_ok() { echo -e "${BFR} ${CM} ${GN}$1${CL}"; }
msg_error() { echo -e "${BFR} ${CROSS} ${RD}$1${CL}"; }
# Telemetry
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "post-pbs-install" "pve"
# ---- helpers ----
get_pbs_codename() {
awk -F'=' '/^VERSION_CODENAME=/{print $2}' /etc/os-release
}
repo_state_list() {
local repo="$1"
local file=""
local state="missing"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*.list; do
[[ -f "$f" ]] || continue
if grep -q "$repo" "$f"; then
file="$f"
if grep -qE "^[^#].*${repo}" "$f"; then
state="active"
elif grep -qE "^#.*${repo}" "$f"; then
state="disabled"
fi
break
fi
done
echo "$state $file"
}
component_exists_in_sources() {
local component="$1"
grep -h -E "^[^#]*Components:[^#]*\b${component}\b" /etc/apt/sources.list.d/*.sources 2>/dev/null | grep -q .
}
require_whiptail() {
if ! command -v whiptail >/dev/null 2>&1; then
msg_error "Missing dependency: whiptail"
echo -e "Install it first (e.g. apt update && apt install -y whiptail), then re-run this script."
exit 127
fi
}
# ---- main ----
main() {
header_info
echo -e "\nThis script will Perform Post Install Routines.\n"
while true; do
read -rp "Start the Proxmox Backup Server Post Install Script (y/n)? " yn
case $yn in
[Yy]*) break ;;
[Nn]*)
clear
exit
;;
*) echo "Please answer yes or no." ;;
esac
done
if command -v pveversion >/dev/null 2>&1; then
echo -e "\n🛑 PVE Detected, Wrong Script!\n"
exit 232
fi
local CODENAME
CODENAME="$(get_pbs_codename)"
case "$CODENAME" in
bookworm)
require_whiptail
start_routines_3
;;
trixie)
require_whiptail
start_routines_4
;;
*)
msg_error "Unsupported Debian codename: $CODENAME"
echo -e "Supported: bookworm (PBS 3.x) and trixie (PBS 4.x)"
exit 105
;;
esac
}
# ---- PBS 3.x (Bookworm) ----
start_routines_3() {
header_info
local VERSION="bookworm"
# --- Debian sources ---
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS SOURCES" --menu \
"Correct Debian sources for Proxmox Backup Server 3.x?" 14 58 2 "yes" " " "no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Correcting Debian Sources"
cat <<EOF >/etc/apt/sources.list
deb http://deb.debian.org/debian ${VERSION} main contrib
deb http://deb.debian.org/debian ${VERSION}-updates main contrib
deb http://security.debian.org/debian-security ${VERSION}-security main contrib
EOF
msg_ok "Corrected Debian Sources"
;;
no) msg_error "Selected no to Correcting Debian Sources" ;;
esac
# --- Enterprise repo ---
read -r state file <<<"$(repo_state_list pbs-enterprise)"
case $state in
active)
sed -i "s/^[^#].*pbs-enterprise/# &/" "$file"
msg_ok "Disabled 'pbs-enterprise' repository"
;;
disabled) msg_ok "'pbs-enterprise' already disabled" ;;
missing)
cat >/etc/apt/sources.list.d/pbs-enterprise.list <<EOF
# deb https://enterprise.proxmox.com/debian/pbs ${VERSION} pbs-enterprise
EOF
msg_ok "Added 'pbs-enterprise' repository (disabled)"
;;
esac
# --- No-subscription repo ---
read -r state file <<<"$(repo_state_list pbs-no-subscription)"
if [[ "$state" == "missing" ]]; then
cat >/etc/apt/sources.list.d/pbs-install-repo.list <<EOF
deb http://download.proxmox.com/debian/pbs ${VERSION} pbs-no-subscription
EOF
msg_ok "Enabled 'pbs-no-subscription' repository"
else
msg_ok "'pbs-no-subscription' repository already present"
fi
# --- Test repo (legacy name pbstest) ---
read -r state file <<<"$(repo_state_list pbstest)"
if [[ "$state" == "missing" ]]; then
cat >/etc/apt/sources.list.d/pbstest-for-beta.list <<EOF
# deb http://download.proxmox.com/debian/pbs ${VERSION} pbstest
EOF
msg_ok "Added 'pbstest' repository (disabled)"
else
msg_ok "'pbstest' repository already exists"
fi
post_routines_common
}
# ---- PBS 4.x (Trixie, deb822) ----
start_routines_4() {
header_info
local VERSION="trixie"
# --- Debian sources (deb822) ---
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS SOURCES" --menu \
"Correct Debian sources for Proxmox Backup Server 4.x (deb822)?" 14 58 2 "yes" " " "no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Correcting Debian Sources (deb822)"
rm -f /etc/apt/sources.list.d/*.list
if [ -f /etc/apt/sources.list ]; then
sed -i '/proxmox/d;/bookworm/d' /etc/apt/sources.list
fi
cat >/etc/apt/sources.list.d/debian.sources <<EOF
Types: deb
URIs: http://deb.debian.org/debian/
Suites: trixie trixie-updates
Components: main contrib non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Types: deb
URIs: http://security.debian.org/debian-security/
Suites: trixie-security
Components: main contrib non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
EOF
msg_ok "Corrected Debian Sources"
;;
no) msg_error "Selected no to Correcting Debian Sources" ;;
esac
# --- Enterprise repo ---
if component_exists_in_sources "pbs-enterprise"; then
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS Enterprise Repository" --menu \
"Enterprise repository detected.
You normally need a valid subscription for this.
Disable it (recommended)?" 14 58 2 "yes" " " "no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Disabling 'pbs-enterprise' repository"
# Use Enabled: false instead of commenting to avoid malformed entry
if grep -q "^Enabled:" /etc/apt/sources.list.d/pbs-enterprise.sources 2>/dev/null; then
sed -i 's/^Enabled:.*/Enabled: false/' /etc/apt/sources.list.d/pbs-enterprise.sources
else
echo "Enabled: false" >>/etc/apt/sources.list.d/pbs-enterprise.sources
fi
msg_ok "Disabled 'pbs-enterprise' repository"
;;
no)
msg_error "Keeping 'pbs-enterprise' active (subscription required!)"
;;
esac
else
cat >/etc/apt/sources.list.d/pbs-enterprise.sources <<EOF
Types: deb
URIs: https://enterprise.proxmox.com/debian/pbs
Suites: trixie
Components: pbs-enterprise
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
Enabled: false
EOF
msg_ok "Added 'pbs-enterprise' repository (disabled)"
fi
# --- No-subscription repo ---
if ! component_exists_in_sources "pbs-no-subscription"; then
cat >/etc/apt/sources.list.d/proxmox.sources <<EOF
Types: deb
URIs: http://download.proxmox.com/debian/pbs
Suites: trixie
Components: pbs-no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF
msg_ok "Added 'pbs-no-subscription' repository"
else
msg_ok "'pbs-no-subscription' repository already present"
fi
# --- Test repo (pbs-test, renamed) ---
if ! component_exists_in_sources "pbs-test"; then
cat >/etc/apt/sources.list.d/pbs-test.sources <<EOF
Types: deb
URIs: http://download.proxmox.com/debian/pbs
Suites: trixie
Components: pbs-test
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
Enabled: false
EOF
msg_ok "Added 'pbs-test' repository (disabled)"
else
msg_ok "'pbs-test' repository already present"
fi
post_routines_common
}
# ---- Shared routines ----
post_routines_common() {
# Subscription nag
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "SUBSCRIPTION NAG" --menu \
"Disable subscription nag in PBS UI?" 14 58 2 "yes" " " "no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox \
"Supporting the software's development team is essential.\nPlease consider buying a subscription." 10 58
msg_info "Disabling subscription nag"
echo "DPkg::Post-Invoke { \"if [ -s /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js ] && ! grep -q -F 'NoMoreNagging' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; then sed -i '/data\\.status/{s/\\!//;s/active/NoMoreNagging/}' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; fi\" };" >/etc/apt/apt.conf.d/no-nag-script
msg_ok "Disabled subscription nag (clear browser cache!)"
;;
no)
msg_error "Selected no to Disabling subscription nag"
rm -f /etc/apt/apt.conf.d/no-nag-script 2>/dev/null
;;
esac
apt --reinstall install proxmox-widget-toolkit &>/dev/null || msg_error "Widget toolkit reinstall failed"
# Update
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "UPDATE" --menu \
"Update Proxmox Backup Server now?" 11 58 2 "yes" " " "no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Updating Proxmox Backup Server (Patience)"
apt update &>/dev/null || msg_error "apt update failed"
apt -y dist-upgrade &>/dev/null || msg_error "apt dist-upgrade failed"
msg_ok "Updated Proxmox Backup Server"
;;
no) msg_error "Selected no to updating Proxmox Backup Server" ;;
esac
# Reminder
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Post-Install Reminder" --msgbox \
"IMPORTANT:
Please run this script on every PBS node individually if you have multiple nodes.
After completing these steps, it is strongly recommended to REBOOT your node.
After the upgrade or post-install routines, always clear your browser cache or perform a hard reload (Ctrl+Shift+R) before using the PBS Web UI to avoid UI display issues." 20 80
# Reboot
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "REBOOT" --menu \
"Reboot Proxmox Backup Server now? (recommended)" 11 58 2 "yes" " " "no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Rebooting PBS"
sleep 2
msg_ok "Completed Post Install Routines"
reboot
;;
no)
msg_error "Selected no to Reboot (Reboot recommended)"
msg_ok "Completed Post Install Routines"
;;
esac
}
main
+49
View File
@@ -0,0 +1,49 @@
#pve
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/proxmox-backup-server.sh)"
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://www.proxmox.com/en/proxmox-backup-server
APP="Proxmox-Backup-Server"
var_tags="${var_tags:-backup}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-10}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -e /usr/sbin/proxmox-backup-manager ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Updating $APP LXC"
$STD apt update
$STD apt -y upgrade
msg_ok "Updated $APP LXC"
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:8007${CL}"
+191
View File
@@ -0,0 +1,191 @@
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/pbs4-upgrade.sh)"
#!/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
header_info() {
clear
cat <<"EOF"
____ ____ _____ __ __ __ __ __
/ __ \/ __ ) ___// // / / / / /___ ____ __________ _____/ /__
/ /_/ / __ \__ \/ // /_ / / / / __ \/ __ `/ ___/ __ `/ __ / _ \
/ ____/ /_/ /__/ /__ __/ / /_/ / /_/ / /_/ / / / /_/ / /_/ / __/
/_/ /_____/____/ /_/ \____/ .___/\__, /_/ \__,_/\__,_/\___/
/_/ /____/
EOF
}
RD=$(echo "\033[01;31m")
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
CROSS="${RD}${CL}"
set -euo pipefail
shopt -s inherit_errexit nullglob
msg_info() { echo -ne " ${HOLD} ${YW}$1..."; }
msg_ok() { echo -e "${BFR} ${CM} ${GN}$1${CL}"; }
msg_error() { echo -e "${BFR} ${CROSS} ${RD}$1${CL}"; }
# Telemetry
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "pbs4-upgrade" "pve"
start_routines() {
header_info
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS 3 BACKUP" --menu \
"\nMake a backup of /etc/proxmox-backup to ensure recovery in worst case?" 14 58 2 \
"yes" " " "no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Backing up Proxmox Backup Server 3"
tar czf "pbs3-etc-backup-$(date -I).tar.gz" -C "/etc" "proxmox-backup"
msg_ok "Backed up Proxmox Backup Server 3"
;;
no) msg_error "Selected no to Backup" ;;
esac
# --- Debian 13 Sources ---
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS 4 SOURCES" --menu \
"Switch to Debian 13 (Trixie) sources for PBS 4?" 14 58 2 "yes" " " "no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Switching to Debian 13 (Trixie) Sources"
rm -f /etc/apt/sources.list.d/*.list
if [ -f /etc/apt/sources.list ]; then
sed -i '/proxmox/d;/bookworm/d' /etc/apt/sources.list
fi
cat >/etc/apt/sources.list.d/debian.sources <<EOF
Types: deb
URIs: http://deb.debian.org/debian
Suites: trixie
Components: main contrib
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Types: deb
URIs: http://security.debian.org/debian-security
Suites: trixie-security
Components: main contrib
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Types: deb
URIs: http://deb.debian.org/debian
Suites: trixie-updates
Components: main contrib
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
EOF
msg_ok "Configured Debian 13 (Trixie) Sources"
;;
no) msg_error "Selected no to Sources update" ;;
esac
# --- Enterprise Repo ---
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS4-ENTERPRISE" --menu \
"Add 'pbs-enterprise' repository (for subscription users)?" 14 58 2 "yes" " " "no" " " \
3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Adding 'pbs-enterprise' repository"
cat >/etc/apt/sources.list.d/pbs-enterprise.sources <<EOF
Types: deb
URIs: https://enterprise.proxmox.com/debian/pbs
Suites: trixie
Components: pbs-enterprise
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF
msg_ok "Added 'pbs-enterprise' repository"
;;
no) msg_error "Skipped enterprise repo" ;;
esac
# --- No-Subscription Repo ---
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS4-NO-SUBSCRIPTION" --menu \
"Enable 'pbs-no-subscription' repository?" 14 58 2 "yes" " " "no" " " \
3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Adding 'pbs-no-subscription' repository"
cat >/etc/apt/sources.list.d/proxmox.sources <<EOF
Types: deb
URIs: http://download.proxmox.com/debian/pbs
Suites: trixie
Components: pbs-no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF
msg_ok "Added 'pbs-no-subscription' repository"
;;
no) msg_error "Skipped no-subscription repo" ;;
esac
# --- Test Repo ---
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS4 TEST" --menu \
"Add 'pbs-test' repository (disabled by default)?" 14 58 2 "yes" " " "no" " " \
3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Adding 'pbs-test' repository (disabled)"
cat >/etc/apt/sources.list.d/pbs-test.sources <<EOF
# Types: deb
# URIs: http://download.proxmox.com/debian/pbs
# Suites: trixie
# Components: pbs-test
# Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF
msg_ok "Added 'pbs-test' repository"
;;
no) msg_error "Skipped test repo" ;;
esac
# --- Upgrade ---
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS 4 UPGRADE" --menu \
"\nUpgrade to Proxmox Backup Server 4 now?" 11 58 2 "yes" " " "no" " " \
3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Upgrading to Proxmox Backup Server 4 (Patience)"
apt update
DEBIAN_FRONTEND=noninteractive apt -o Dpkg::Options::="--force-confold" dist-upgrade -y
msg_ok "System upgraded to PBS 4"
;;
no) msg_error "Selected no to upgrade" ;;
esac
# --- Reboot ---
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "REBOOT" --menu \
"\nReboot Proxmox Backup Server 4 now? (recommended)" 11 58 2 "yes" " " "no" " " \
3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Rebooting PBS 4"
sleep 2
msg_ok "Upgrade Complete"
reboot
;;
no)
msg_error "Selected no to Reboot (Reboot recommended)"
msg_ok "Upgrade Complete"
;;
esac
}
header_info
while true; do
read -rp "Start the Upgrade to Proxmox Backup Server 4 Script (y/n)? " yn
case $yn in
[Yy]*) break ;;
[Nn]*)
clear
exit
;;
*) echo "Please answer yes or no." ;;
esac
done
start_routines