core: move misc scripts to structured addon/pve paths | Refactor JSON Editor & Script Mapping (#3765)

* Move Scripts to Tools / Add-Ons

* fix json editor slug generating

* update type in jsons

* remove wrong method

* move copy-data to tools
This commit is contained in:
CanbiZ 2025-04-09 13:10:02 +02:00 committed by GitHub
parent f2f10376ac
commit 3dffd02f08
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
88 changed files with 1327 additions and 1481 deletions

View file

@ -0,0 +1,90 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# Co-Author: MickLesk (Canbiz)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
_ __ __ ____ _ __
/ | / /__ / /_/ __ )(_)________/ /
/ |/ / _ \/ __/ __ / / ___/ __ /
/ /| / __/ /_/ /_/ / / / / /_/ /
/_/ |_/\___/\__/_____/_/_/ \__,_/
EOF
}
header_info
set -e
while true; do
read -p "This will add NetBird to an existing LXC Container ONLY. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
header_info
echo "Loading..."
function msg() {
local TEXT="$1"
echo -e "$TEXT"
}
NODE=$(hostname)
MSG_MAX_LENGTH=0
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
ITEM=$(echo "$line" | awk '{print substr($0,36)}')
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
CTID_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
while [ -z "${CTID:+x}" ]; do
CTID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Containers on $NODE" --radiolist \
"\nSelect a container to add NetBird to:\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
LXC_STATUS=$(pct status "$CTID" | awk '{print $2}')
if [[ "$LXC_STATUS" != "running" ]]; then
msg "\e[1;33m The container $CTID is not running. Starting it now...\e[0m"
pct start "$CTID"
while [[ "$(pct status "$CTID" | awk '{print $2}')" != "running" ]]; do
msg "\e[1;33m Waiting for the container to start...\e[0m"
sleep 2
done
msg "\e[1;32m Container $CTID is now running.\e[0m"
fi
DISTRO=$(pct exec "$CTID" -- cat /etc/os-release | grep -w "ID" | cut -d'=' -f2 | tr -d '"')
if [[ "$DISTRO" != "debian" && "$DISTRO" != "ubuntu" ]]; then
msg "\e[1;31m Error: This script only supports Debian or Ubuntu LXC containers. Detected: $DISTRO. Aborting...\e[0m"
exit 1
fi
CTID_CONFIG_PATH=/etc/pve/lxc/${CTID}.conf
cat <<EOF >>$CTID_CONFIG_PATH
lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file
EOF
header_info
msg "Installing NetBird..."
pct exec "$CTID" -- bash -c '
apt install -y ca-certificates gpg &>/dev/null
curl -fsSL "https://pkgs.netbird.io/debian/public.key" | gpg --dearmor >/usr/share/keyrings/netbird-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/netbird-archive-keyring.gpg] https://pkgs.netbird.io/debian stable main" >/etc/apt/sources.list.d/netbird.list
apt-get update &>/dev/null
apt-get install -y netbird-ui &>/dev/null
' || exit
msg "\e[1;32m ✔ Installed NetBird.\e[0m"
sleep 2
msg "\e[1;31m Reboot ${CTID} LXC to apply the changes, then run netbird up in the LXC console\e[0m"

View file

@ -0,0 +1,75 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
______ _ __ __
/_ __/___ _(_) /_____________ _/ /__
/ / / __ `/ / / ___/ ___/ __ `/ / _ \
/ / / /_/ / / (__ ) /__/ /_/ / / __/
/_/ \__,_/_/_/____/\___/\__,_/_/\___/
EOF
}
header_info
set -e
while true; do
read -p "This will add Tailscale to an existing LXC Container ONLY. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
header_info
echo "Loading..."
function msg() {
local TEXT="$1"
echo -e "$TEXT"
}
NODE=$(hostname)
MSG_MAX_LENGTH=0
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
ITEM=$(echo "$line" | awk '{print substr($0,36)}')
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
CTID_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
while [ -z "${CTID:+x}" ]; do
CTID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Containers on $NODE" --radiolist \
"\nSelect a container to add Tailscale to:\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
CTID_CONFIG_PATH=/etc/pve/lxc/${CTID}.conf
cat <<EOF >>$CTID_CONFIG_PATH
lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file
EOF
header_info
msg "Installing Tailscale..."
pct exec "$CTID" -- bash -c '
ID=$(grep "^ID=" /etc/os-release | cut -d"=" -f2)
VER=$(grep "^VERSION_CODENAME=" /etc/os-release | cut -d"=" -f2)
curl -fsSL https://pkgs.tailscale.com/stable/$ID/$VER.noarmor.gpg | tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/tailscale-archive-keyring.gpg] https://pkgs.tailscale.com/stable/$ID $VER main" >/etc/apt/sources.list.d/tailscale.list
apt-get update &>/dev/null
apt-get install -y tailscale &>/dev/null
' || exit
TAGS=$(awk -F': ' '/^tags:/ {print $2}' /etc/pve/lxc/${CTID}.conf)
TAGS="${TAGS:+$TAGS; }tailscale"
pct set "$CTID" -tags "${TAGS}"
msg "\e[1;32m ✔ Installed Tailscale\e[0m"
msg "\e[1;31m Reboot ${CTID} LXC to apply the changes, then run tailscale up in the LXC console\e[0m"

View file

@ -0,0 +1,209 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
___ ____ ______ __ __
/ _ | / / / /_ __/__ __ _ ___ / /__ _/ /____ ___
/ __ |/ / / / / / -_) ' \/ _ \/ / _ `/ __/ -_|_-<
/_/ |_/_/_/ /_/ \__/_/_/_/ .__/_/\_,_/\__/\__/___/
/_/
EOF
}
set -eEuo pipefail
shopt -s expand_aliases
alias die='EXIT=$? LINE=$LINENO error_exit'
trap die ERR
function error_exit() {
trap - ERR
local DEFAULT='Unknown failure occured.'
local REASON="\e[97m${1:-$DEFAULT}\e[39m"
local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE"
msg "$FLAG $REASON" 1>&2
[ ! -z ${CTID-} ] && cleanup_ctid
exit $EXIT
}
function warn() {
local REASON="\e[97m$1\e[39m"
local FLAG="\e[93m[WARNING]\e[39m"
msg "$FLAG $REASON"
}
function info() {
local REASON="$1"
local FLAG="\e[36m[INFO]\e[39m"
msg "$FLAG $REASON"
}
function msg() {
local TEXT="$1"
echo -e "$TEXT"
}
function cleanup_ctid() {
if pct status $CTID &>/dev/null; then
if [ "$(pct status $CTID | awk '{print $2}')" == "running" ]; then
pct stop $CTID
fi
pct destroy $CTID
fi
}
# Stop Proxmox VE Monitor-All if running
if systemctl is-active -q ping-instances.service; then
systemctl stop ping-instances.service
fi
header_info
echo "Loading..."
pveam update >/dev/null 2>&1
whiptail --backtitle "Proxmox VE Helper Scripts" --title "All Templates" --yesno "This will allow for the creation of one of the many Template LXC Containers. Proceed?" 10 68 || exit
TEMPLATE_MENU=()
MSG_MAX_LENGTH=0
while read -r TAG ITEM; do
OFFSET=2
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=${#ITEM}+OFFSET
TEMPLATE_MENU+=("$ITEM" "$TAG " "OFF")
done < <(pveam available)
TEMPLATE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "All Template LXCs" --radiolist "\nSelect a Template LXC to create:\n" 16 $((MSG_MAX_LENGTH + 58)) 10 "${TEMPLATE_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"') || exit
[ -z "$TEMPLATE" ] && {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Template LXC Selected" --msgbox "It appears that no Template LXC container was selected" 10 68
msg "Done"
exit
}
# Setup script environment
NAME=$(echo "$TEMPLATE" | grep -oE '^[^-]+-[^-]+')
PASS="$(openssl rand -base64 8)"
CTID=$(pvesh get /cluster/nextid)
PCT_OPTIONS="
-features keyctl=1,nesting=1
-hostname $NAME
-tags proxmox-helper-scripts
-onboot 0
-cores 2
-memory 2048
-password $PASS
-net0 name=eth0,bridge=vmbr0,ip=dhcp
-unprivileged 1
"
DEFAULT_PCT_OPTIONS=(
-arch $(dpkg --print-architecture)
)
# Set the CONTENT and CONTENT_LABEL variables
function select_storage() {
local CLASS=$1
local CONTENT
local CONTENT_LABEL
case $CLASS in
container)
CONTENT='rootdir'
CONTENT_LABEL='Container'
;;
template)
CONTENT='vztmpl'
CONTENT_LABEL='Container template'
;;
*) false || die "Invalid storage class." ;;
esac
# Query all storage locations
local -a MENU
while read -r line; do
local TAG=$(echo $line | awk '{print $1}')
local TYPE=$(echo $line | awk '{printf "%-10s", $2}')
local FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
local ITEM=" Type: $TYPE Free: $FREE "
local OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
local MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
MENU+=("$TAG" "$ITEM" "OFF")
done < <(pvesm status -content $CONTENT | awk 'NR>1')
# Select storage location
if [ $((${#MENU[@]} / 3)) -eq 0 ]; then
warn "'$CONTENT_LABEL' needs to be selected for at least one storage location."
die "Unable to detect valid storage location."
elif [ $((${#MENU[@]} / 3)) -eq 1 ]; then
printf ${MENU[0]}
else
local STORAGE
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for the ${CONTENT_LABEL,,}?\n\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${MENU[@]}" 3>&1 1>&2 2>&3) || die "Menu aborted."
done
printf $STORAGE
fi
}
header_info
# Get template storage
TEMPLATE_STORAGE=$(select_storage template) || exit
info "Using '$TEMPLATE_STORAGE' for template storage."
# Get container storage
CONTAINER_STORAGE=$(select_storage container) || exit
info "Using '$CONTAINER_STORAGE' for container storage."
# Download template
msg "Downloading LXC template (Patience)..."
pveam download $TEMPLATE_STORAGE $TEMPLATE >/dev/null || die "A problem occured while downloading the LXC template."
# Create variable for 'pct' options
PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}})
[[ " ${PCT_OPTIONS[@]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs $CONTAINER_STORAGE:${PCT_DISK_SIZE:-8})
# Create LXC
msg "Creating LXC container..."
pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} ${PCT_OPTIONS[@]} >/dev/null ||
die "A problem occured while trying to create container."
# Save password
echo "$NAME password: ${PASS}" >>~/$NAME.creds # file is located in the Proxmox root directory
# Start container
msg "Starting LXC Container..."
pct start "$CTID"
sleep 5
# Get container IP
set +eEuo pipefail
max_attempts=5
attempt=1
IP=""
while [[ $attempt -le $max_attempts ]]; do
IP=$(pct exec $CTID ip a show dev eth0 | grep -oP 'inet \K[^/]+')
if [[ -n $IP ]]; then
break
else
warn "Attempt $attempt: IP address not found. Pausing for 5 seconds..."
sleep 5
((attempt++))
fi
done
if [[ -z $IP ]]; then
warn "Maximum number of attempts reached. IP address not found."
IP="NOT FOUND"
fi
set -eEuo pipefail
# Start Proxmox VE Monitor-All if available
if [[ -f /etc/systemd/system/ping-instances.service ]]; then
systemctl start ping-instances.service
fi
# Success message
header_info
echo
info "LXC container '$CTID' was successfully created, and its IP address is ${IP}."
echo
info "Proceed to the LXC console to complete the setup."
echo
info "login: root"
info "password: $PASS"
echo

102
tools/addon/code-server.sh Normal file
View file

@ -0,0 +1,102 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
cat <<"EOF"
______ __ _____
/ ____/___ ____/ /__ / ___/___ ______ _____ _____
/ / / __ \/ __ / _ \ \__ \/ _ \/ ___/ | / / _ \/ ___/
/ /___/ /_/ / /_/ / __/ ___/ / __/ / | |/ / __/ /
\____/\____/\__,_/\___/ /____/\___/_/ |___/\___/_/
EOF
}
IP=$(hostname -I | awk '{print $1}')
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")
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
APP="Code Server"
hostname="$(hostname)"
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
shopt -s expand_aliases
alias die='EXIT=$? LINE=$LINENO error_exit'
trap die ERR
function error_exit() {
trap - ERR
local reason="Unknown failure occured."
local msg="${1:-$reason}"
local flag="${RD}‼ ERROR ${CL}$EXIT@$LINE"
echo -e "$flag $msg" 1>&2
exit $EXIT
}
clear
header_info
if command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Can't Install on Proxmox "
exit
fi
if [ -e /etc/alpine-release ]; then
echo -e "⚠️ Can't Install on Alpine"
exit
fi
while true; do
read -p "This will Install ${APP} on $hostname. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
function msg_info() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
function msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
msg_info "Installing Dependencies"
apt-get update &>/dev/null
apt-get install -y curl &>/dev/null
apt-get install -y git &>/dev/null
msg_ok "Installed Dependencies"
VERSION=$(curl -fsSL https://api.github.com/repos/coder/code-server/releases/latest |
grep "tag_name" |
awk '{print substr($2, 3, length($2)-4) }')
msg_info "Installing Code-Server v${VERSION}"
curl -fOL https://github.com/coder/code-server/releases/download/v$VERSION/code-server_${VERSION}_amd64.deb &>/dev/null
dpkg -i code-server_${VERSION}_amd64.deb &>/dev/null
rm -rf code-server_${VERSION}_amd64.deb
mkdir -p ~/.config/code-server/
systemctl enable -q --now code-server@$USER
cat <<EOF >~/.config/code-server/config.yaml
bind-addr: 0.0.0.0:8680
auth: none
password:
cert: false
EOF
systemctl restart code-server@$USER
msg_ok "Installed Code-Server v${VERSION} on $hostname"
echo -e "${APP} should be reachable by going to the following URL.
${BL}http://$IP:8680${CL} \n"

88
tools/addon/crowdsec.sh Normal file
View file

@ -0,0 +1,88 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
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")
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
APP="CrowdSec"
hostname="$(hostname)"
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
shopt -s expand_aliases
alias die='EXIT=$? LINE=$LINENO error_exit'
trap die ERR
function error_exit() {
trap - ERR
local reason="Unknown failure occured."
local msg="${1:-$reason}"
local flag="${RD}‼ ERROR ${CL}$EXIT@$LINE"
echo -e "$flag $msg" 1>&2
exit "$EXIT"
}
if command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Can't Install on Proxmox "
exit
fi
while true; do
read -p "This will Install ${APP} on $hostname. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
clear
function header_info() {
echo -e "${BL}
_____ _ _____
/ ____| | |/ ____|
| | _ __ _____ ____| | (___ ___ ___
| | | __/ _ \ \ /\ / / _ |\___ \ / _ \/ __|
| |____| | | (_) \ V V / (_| |____) | __/ (__
\_____|_| \___/ \_/\_/ \__ _|_____/ \___|\___|
${CL}"
}
header_info
function msg_info() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
function msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
msg_info "Setting up ${APP} Repository"
apt-get update &>/dev/null
apt-get install -y curl &>/dev/null
apt-get install -y gnupg &>/dev/null
curl -fsSL "https://install.crowdsec.net" | bash &>/dev/null
msg_ok "Setup ${APP} Repository"
msg_info "Installing ${APP}"
apt-get update &>/dev/null
apt-get install -y crowdsec &>/dev/null
msg_ok "Installed ${APP} on $hostname"
msg_info "Installing ${APP} Common Bouncer"
apt-get install -y crowdsec-firewall-bouncer-iptables &>/dev/null
msg_ok "Installed ${APP} Common Bouncer"
msg_ok "Completed Successfully!\n"

184
tools/addon/filebrowser.sh Normal file
View file

@ -0,0 +1,184 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: tteck (tteckster) | Co-Author: MickLesk
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
_______ __ ____
/ ____(_) /__ / __ )_________ _ __________ _____
/ /_ / / / _ \/ __ / ___/ __ \ | /| / / ___/ _ \/ ___/
/ __/ / / / __/ /_/ / / / /_/ / |/ |/ (__ ) __/ /
/_/ /_/_/\___/_____/_/ \____/|__/|__/____/\___/_/
EOF
}
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
RD=$(echo "\033[01;31m")
BL=$(echo "\033[36m")
CL=$(echo "\033[m")
CM="${GN}✔️${CL}"
CROSS="${RD}✖️${CL}"
INFO="${BL}${CL}"
APP="FileBrowser"
INSTALL_PATH="/usr/local/bin/filebrowser"
DB_PATH="/usr/local/community-scripts/filebrowser.db"
DEFAULT_PORT=8080
# Get first non-loopback IP & Detect primary network interface dynamically
IFACE=$(ip -4 route | awk '/default/ {print $5; exit}')
IP=$(ip -4 addr show "$IFACE" | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1)
[[ -z "$IP" ]] && IP=$(hostname -I | awk '{print $1}')
[[ -z "$IP" ]] && IP="127.0.0.1"
# Detect OS
if [[ -f "/etc/alpine-release" ]]; then
OS="Alpine"
SERVICE_PATH="/etc/init.d/filebrowser"
PKG_MANAGER="apk add --no-cache"
elif [[ -f "/etc/debian_version" ]]; then
OS="Debian"
SERVICE_PATH="/etc/systemd/system/filebrowser.service"
PKG_MANAGER="apt-get install -y"
else
echo -e "${CROSS} Unsupported OS detected. Exiting."
exit 1
fi
header_info
function msg_info() {
local msg="$1"
echo -e "${INFO} ${YW}${msg}...${CL}"
}
function msg_ok() {
local msg="$1"
echo -e "${CM} ${GN}${msg}${CL}"
}
function msg_error() {
local msg="$1"
echo -e "${CROSS} ${RD}${msg}${CL}"
}
if [ -f "$INSTALL_PATH" ]; then
echo -e "${YW}⚠️ ${APP} is already installed.${CL}"
read -r -p "Would you like to uninstall ${APP}? (y/N): " uninstall_prompt
if [[ "${uninstall_prompt,,}" =~ ^(y|yes)$ ]]; then
msg_info "Uninstalling ${APP}"
if [[ "$OS" == "Debian" ]]; then
systemctl disable --now filebrowser.service &>/dev/null
rm -f "$SERVICE_PATH"
else
rc-service filebrowser stop &>/dev/null
rc-update del filebrowser &>/dev/null
rm -f "$SERVICE_PATH"
fi
rm -f "$INSTALL_PATH" "$DB_PATH"
msg_ok "${APP} has been uninstalled."
exit 0
fi
read -r -p "Would you like to update ${APP}? (y/N): " update_prompt
if [[ "${update_prompt,,}" =~ ^(y|yes)$ ]]; then
msg_info "Updating ${APP}"
curl -fsSL "https://github.com/filebrowser/filebrowser/releases/latest/download/linux-amd64-filebrowser.tar.gz" | tar -xzv -C /usr/local/bin &>/dev/null
chmod +x "$INSTALL_PATH"
msg_ok "Updated ${APP}"
exit 0
else
echo -e "${YW}⚠️ Update skipped. Exiting.${CL}"
exit 0
fi
fi
echo -e "${YW}⚠️ ${APP} is not installed.${CL}"
read -r -p "Enter port number (Default: ${DEFAULT_PORT}): " PORT
PORT=${PORT:-$DEFAULT_PORT}
read -r -p "Would you like to install ${APP}? (y/n): " install_prompt
if [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then
msg_info "Installing ${APP} on ${OS}"
$PKG_MANAGER wget tar curl &>/dev/null
curl -fsSL "https://github.com/filebrowser/filebrowser/releases/latest/download/linux-amd64-filebrowser.tar.gz" | tar -xzv -C /usr/local/bin &>/dev/null
chmod +x "$INSTALL_PATH"
msg_ok "Installed ${APP}"
msg_info "Creating FileBrowser directory"
mkdir -p /usr/local/community-scripts
chown root:root /usr/local/community-scripts
chmod 755 /usr/local/community-scripts
touch "$DB_PATH"
chown root:root "$DB_PATH"
chmod 644 "$DB_PATH"
msg_ok "Directory created successfully"
read -r -p "Would you like to use No Authentication? (y/N): " auth_prompt
if [[ "${auth_prompt,,}" =~ ^(y|yes)$ ]]; then
msg_info "Configuring No Authentication"
cd /usr/local/community-scripts
filebrowser config init -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null
filebrowser config set -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null
filebrowser config init --auth.method=noauth &>/dev/null
filebrowser config set --auth.method=noauth &>/dev/null
filebrowser users add ID 1 --perm.admin &>/dev/null
msg_ok "No Authentication configured"
else
msg_info "Setting up default authentication"
cd /usr/local/community-scripts
filebrowser config init -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null
filebrowser config set -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null
filebrowser users add admin helper-scripts.com --perm.admin --database "$DB_PATH" &>/dev/null
msg_ok "Default authentication configured (admin:helper-scripts.com)"
fi
msg_info "Creating service"
if [[ "$OS" == "Debian" ]]; then
cat <<EOF >"$SERVICE_PATH"
[Unit]
Description=Filebrowser
After=network-online.target
[Service]
User=root
WorkingDirectory=/usr/local/community-scripts
ExecStartPre=/bin/touch /usr/local/community-scripts/filebrowser.db
ExecStartPre=/usr/local/bin/filebrowser config set -a "0.0.0.0" -p ${PORT} -d /usr/local/community-scripts/filebrowser.db
ExecStart=/usr/local/bin/filebrowser -r / -d /usr/local/community-scripts/filebrowser.db -p ${PORT}
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now filebrowser
else
cat <<EOF >"$SERVICE_PATH"
#!/sbin/openrc-run
command="/usr/local/bin/filebrowser"
command_args="-r / -d $DB_PATH -p $PORT"
command_background=true
pidfile="/var/run/filebrowser.pid"
directory="/usr/local/community-scripts"
depend() {
need net
}
EOF
chmod +x "$SERVICE_PATH"
rc-update add filebrowser default &>/dev/null
rc-service filebrowser start &>/dev/null
fi
msg_ok "Service created successfully"
echo -e "${CM} ${GN}${APP} is reachable at: ${BL}http://$IP:$PORT${CL}"
else
echo -e "${YW}⚠️ Installation skipped. Exiting.${CL}"
exit 0
fi

125
tools/addon/glances.sh Normal file
View file

@ -0,0 +1,125 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
________
/ ____/ /___ _____ ________ _____
/ / __/ / __ `/ __ \/ ___/ _ \/ ___/
/ /_/ / / /_/ / / / / /__/ __(__ )
\____/_/\__,_/_/ /_/\___/\___/____/
EOF
}
IP=$(hostname -I | awk '{print $1}')
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")
BFR="\\r\\033[K"
HOLD=" "
CM="${GN}${CL}"
APP="Glances"
hostname="$(hostname)"
silent() { "$@" >/dev/null 2>&1; }
set -e
spinner() {
local chars="/-\|"
local spin_i=0
printf "\e[?25l"
while true; do
printf "\r \e[36m%s\e[0m" "${chars:spin_i++%${#chars}:1}"
sleep 0.1
done
}
msg_info() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg} "
spinner &
SPINNER_PID=$!
}
msg_ok() {
if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then kill $SPINNER_PID >/dev/null; fi
printf "\e[?25h"
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
install() {
header_info
while true; do
read -p "This will Install ${APP} on $hostname. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
header_info
read -r -p "Verbose mode? <y/N> " prompt
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
STD=""
else
STD="silent"
fi
msg_info "Installing $APP"
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
$STD bash -c "$(curl -fsSL https://raw.githubusercontent.com/nicolargo/glancesautoinstall/master/install.sh)"
cat <<EOF >/etc/systemd/system/glances.service
[Unit]
Description=Glances - An eye on your system
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/glances -w
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now glances.service
msg_ok "Installed $APP on $hostname"
echo -e "${APP} should be reachable by going to the following URL.
${BL}http://$IP:61208${CL} \n"
}
uninstall() {
header_info
msg_info "Uninstalling $APP"
if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then kill $SPINNER_PID >/dev/null; fi
systemctl disable -q --now glances
bash -c "$(curl -fsSL https://raw.githubusercontent.com/nicolargo/glancesautoinstall/master/uninstall.sh)"
rm -rf /etc/systemd/system/glances.service
msg_ok "Uninstalled $APP"
msg_ok "Completed Successfully!\n"
}
OPTIONS=(Install "Install $APP"
Uninstall "Uninstall $APP")
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$APP" --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

123
tools/addon/netdata.sh Normal file
View file

@ -0,0 +1,123 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
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; }
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}"
}
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
header_info
read -r -p "Verbose mode? <y/N> " prompt
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
STD=""
else
STD="silent"
fi
header_info
msg_info "Setting up repository"
$STD apt-get install -y debian-keyring
curl -fsSL "https://repo.netdata.cloud/repos/repoconfig/debian/bookworm/netdata-repo_5-1+debian12_all.deb" -o $(basename "https://repo.netdata.cloud/repos/repoconfig/debian/bookworm/netdata-repo_5-1+debian12_all.deb")
$STD dpkg -i netdata-repo_5-1+debian12_all.deb
rm -rf netdata-repo_5-1+debian12_all.deb
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
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
STD=""
else
STD="silent"
fi
header_info
msg_info "Uninstalling Netdata"
systemctl stop netdata
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
msg_ok "Uninstalled Netdata"
msg_ok "Completed Successfully!\n"
}
if ! pveversion | grep -Eq "pve-manager/(8\.[0-9])"; then
echo -e "This version of Proxmox Virtual Environment is not supported"
echo -e "Requires PVE Version 8.0 or higher"
echo -e "Exiting..."
sleep 2
exit
fi
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

62
tools/addon/olivetin.sh Normal file
View file

@ -0,0 +1,62 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
____ ___ _______
/ __ \/ (_) _____/_ __(_)___
/ / / / / / | / / _ \/ / / / __ \
/ /_/ / / /| |/ / __/ / / / / / /
\____/_/_/ |___/\___/_/ /_/_/ /_/
EOF
}
IP=$(hostname -I | awk '{print $1}')
YW=$(echo "\033[33m")
BL=$(echo "\033[36m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
APP="OliveTin"
hostname="$(hostname)"
set-e
header_info
while true; do
read -p "This will Install ${APP} on $hostname. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
header_info
function msg_info() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
function msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
msg_info "Installing ${APP}"
curl -fsSL "https://github.com/OliveTin/OliveTin/releases/latest/download/OliveTin_linux_amd64.deb" -o $(basename "https://github.com/OliveTin/OliveTin/releases/latest/download/OliveTin_linux_amd64.deb")
dpkg -i OliveTin_linux_amd64.deb &>/dev/null
systemctl enable --now OliveTin &>/dev/null
rm OliveTin_linux_amd64.deb
msg_ok "Installed ${APP} on $hostname"
msg_ok "Completed Successfully!\n"
echo -e "${APP} should be reachable by going to the following URL.
${BL}http://$IP:1337${CL} \n"

162
tools/addon/pyenv.sh Normal file
View file

@ -0,0 +1,162 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
set -e
YW=$(echo "\033[33m")
RD=$(echo "\033[01;31m")
BL=$(echo "\033[36m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
CM="${GN}${CL}"
CROSS="${RD}${CL}"
BFR="\\r\\033[K"
HOLD="-"
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}"
}
if command -v pveversion >/dev/null 2>&1; then
msg_error "Can't Install on Proxmox "
exit
fi
msg_info "Installing pyenv"
apt-get install -y \
make \
build-essential \
libjpeg-dev \
libpcap-dev \
libssl-dev \
zlib1g-dev \
libbz2-dev \
libreadline-dev \
libsqlite3-dev \
autoconf \
git \
curl \
sudo \
llvm \
libncursesw5-dev \
xz-utils \
tk-dev \
libxml2-dev \
libxmlsec1-dev \
libffi-dev \
libopenjp2-7 \
libtiff5 \
libturbojpeg0-dev \
liblzma-dev &>/dev/null
git clone https://github.com/pyenv/pyenv.git ~/.pyenv &>/dev/null
set +e
echo 'export PYENV_ROOT="$HOME/.pyenv"' >>~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >>~/.bashrc
echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init --path)"\nfi' >>~/.bashrc
msg_ok "Installed pyenv"
. ~/.bashrc
set -e
msg_info "Installing Python 3.11.1"
pyenv install 3.11.1 &>/dev/null
pyenv global 3.11.1
msg_ok "Installed Python 3.11.1"
read -r -p "Would you like to install Home Assistant Beta? <y/N> " prompt
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
msg_info "Installing Home Assistant Beta"
cat <<EOF >/etc/systemd/system/homeassistant.service
[Unit]
Description=Home Assistant
After=network-online.target
[Service]
Type=simple
WorkingDirectory=/root/.homeassistant
ExecStart=/srv/homeassistant/bin/hass -c "/root/.homeassistant"
RestartForceExitStatus=100
[Install]
WantedBy=multi-user.target
EOF
mkdir /srv/homeassistant
cd /srv/homeassistant
python3 -m venv .
source bin/activate
python3 -m pip install wheel &>/dev/null
pip3 install --upgrade pip &>/dev/null
pip3 install psycopg2-binary &>/dev/null
pip3 install --pre homeassistant &>/dev/null
systemctl enable homeassistant &>/dev/null
msg_ok "Installed Home Assistant Beta"
echo -e " Go to $(hostname -I | awk '{print $1}'):8123"
hass
fi
read -r -p "Would you like to install ESPHome Beta? <y/N> " prompt
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
msg_info "Installing ESPHome Beta"
mkdir /srv/esphome
cd /srv/esphome
python3 -m venv .
source bin/activate
python3 -m pip install wheel &>/dev/null
pip3 install --upgrade pip &>/dev/null
pip3 install --pre esphome &>/dev/null
cat <<EOF >/srv/esphome/start.sh
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
source /srv/esphome/bin/activate
esphome dashboard /srv/esphome/
EOF
chmod +x start.sh
cat <<EOF >/etc/systemd/system/esphomedashboard.service
[Unit]
Description=ESPHome Dashboard Service
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/srv/esphome
ExecStart=/srv/esphome/start.sh
RestartSec=30
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now esphomedashboard &>/dev/null
msg_ok "Installed ESPHome Beta"
echo -e " Go to $(hostname -I | awk '{print $1}'):6052"
exec $SHELL
fi
read -r -p "Would you like to install Matter-Server (Beta)? <y/N> " prompt
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
msg_info "Installing Matter Server"
apt-get install -y \
libcairo2-dev \
libjpeg62-turbo-dev \
libgirepository1.0-dev \
libpango1.0-dev \
libgif-dev \
g++ &>/dev/null
python3 -m pip install wheel
pip3 install --upgrade pip
pip install python-matter-server[server]
msg_ok "Installed Matter Server"
echo -e "Start server > python -m matter_server.server"
fi
msg_ok "\nFinished\n"
exec $SHELL

61
tools/addon/webmin.sh Normal file
View file

@ -0,0 +1,61 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
_ __ __ _
| | /| / /__ / / __ _ (_)__
| |/ |/ / -_) _ \/ ' \/ / _ \
|__/|__/\__/_.__/_/_/_/_/_//_/
EOF
}
set -eEuo pipefail
YW=$(echo "\033[33m")
BL=$(echo "\033[36m")
BGN=$(echo "\033[4;92m")
GN=$(echo "\033[1;92m")
DGN=$(echo "\033[32m")
CL=$(echo "\033[m")
CM="${GN}${CL}"
BFR="\\r\\033[K"
HOLD="-"
msg_info() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
header_info
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Webmin Installer" --yesno "This Will Install Webmin on this LXC Container. Proceed?" 10 58 || exit
msg_info "Installing Prerequisites"
apt update &>/dev/null
apt-get -y install libnet-ssleay-perl libauthen-pam-perl libio-pty-perl unzip shared-mime-info &>/dev/null
msg_ok "Installed Prerequisites"
LATEST=$(curl -fsSL https://api.github.com/repos/webmin/webmin/releases/latest | grep '"tag_name":' | cut -d'"' -f4)
msg_info "Downloading Webmin"
curl -fsSL "https://github.com/webmin/webmin/releases/download/$LATEST/webmin_${LATEST}_all.deb" -o $(basename "https://github.com/webmin/webmin/releases/download/$LATEST/webmin_${LATEST}_all.deb")
msg_ok "Downloaded Webmin"
msg_info "Installing Webmin"
dpkg -i webmin_${LATEST}_all.deb &>/dev/null
/usr/share/webmin/changepass.pl /etc/webmin root root &>/dev/null
rm -rf /root/webmin_${LATEST}_all.deb
msg_ok "Installed Webmin"
IP=$(hostname -I | cut -f1 -d ' ')
echo -e "Successfully Installed!! Webmin should be reachable by going to ${BL}https://${IP}:10000${CL}"

46
tools/copy-data/README.md Normal file
View file

@ -0,0 +1,46 @@
<h2><p align="center">Copy data to another LXC (run in the Proxmox Shell)</p></h2>
<div align="center"> To copy data from Home Assistant Container to Home Assistant Container </div>
```
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/copy-data/home-assistant-container-copy-data-home-assistant-container.sh)"
```
<div align="center"> To copy data from Home Assistant Container to Home Assistant Core </div>
```
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/copy-data/home-assistant-container-copy-data-home-assistant-core.sh)"
```
<div align="center"> To copy data from Home Assistant Container to Podman Home Assistant </div>
```
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/copy-data/home-assistant-container-copy-data-podman-home-assistant.sh)"
```
<div align="center"> To copy data from Podman Home Assistant to Home Assistant Container </div>
```
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/copy-data/podman-home-assistant-copy-data-home-assistant-container.sh)"
```
<div align="center"> To copy data from Home Assistant Core to Home Assistant Container </div>
```
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/copy-data/home-assistant-core-copy-data-home-assistant-container.sh)"
```
<div align="center"> To copy data from Home Assistant Core to Home Assistant Core </div>
```
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/copy-data/home-assistant-core-copy-data-home-assistant-core.sh)"
```
<div align="center"> To copy data from Plex to Plex </div>
```
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/copy-data/plex-copy-data-plex.sh)"
```
<div align="center"> To copy data from Zigbee2MQTT to Zigbee2MQTT </div>
```
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/copy-data/z2m-copy-data-z2m.sh)"
```
<div align="center"> To copy data from Zwavejs2MQTT to Zwave JS UI </div>
```
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/copy-data/zwavejs2mqtt-copy-data-zwavejsui.sh)"
```

View file

@ -0,0 +1,131 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Use to copy all data from one Home Assistant LXC to another
# run from the Proxmox Shell
clear
if ! command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Run from the Proxmox Shell"
exit
fi
while true; do
read -p "Use to copy all data from one Home Assistant LXC to another. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
shopt -s expand_aliases
alias die='EXIT=$? LINE=$LINENO error_exit'
trap die ERR
trap cleanup EXIT
function error_exit() {
trap - ERR
local DEFAULT='Unknown failure occured.'
local REASON="\e[97m${1:-$DEFAULT}\e[39m"
local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE"
msg "$FLAG $REASON"
exit "$EXIT"
}
function warn() {
local REASON="\e[97m$1\e[39m"
local FLAG="\e[93m[WARNING]\e[39m"
msg "$FLAG $REASON"
}
function info() {
local REASON="$1"
local FLAG="\e[36m[INFO]\e[39m"
msg "$FLAG $REASON"
}
function msg() {
local TEXT="$1"
echo -e "$TEXT"
}
function cleanup() {
[ -d "${CTID_FROM_PATH:-}" ] && pct unmount "$CTID_FROM"
[ -d "${CTID_TO_PATH:-}" ] && pct unmount "$CTID_TO"
popd >/dev/null
rm -rf "$TEMP_DIR"
}
TEMP_DIR=$(mktemp -d)
pushd "$TEMP_DIR" >/dev/null
TITLE="Home Assistant LXC Data Copy"
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
ITEM=$(echo "$line" | awk '{print substr($0,36)}')
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
CTID_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
while [ -z "${CTID_FROM:+x}" ]; do
CTID_FROM=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich HA LXC would you like to copy FROM?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
while [ -z "${CTID_TO:+x}" ]; do
CTID_TO=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich HA LXC would you like to copy TO?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
for i in ${!CTID_MENU[@]}; do
[ "${CTID_MENU[$i]}" == "$CTID_FROM" ] &&
CTID_FROM_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<"${CTID_MENU[$i + 1]}")
[ "${CTID_MENU[$i]}" == "$CTID_TO" ] &&
CTID_TO_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<"${CTID_MENU[$i + 1]}")
done
whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "$TITLE" --yesno \
"Are you sure you want to copy data between the following LXCs?
$CTID_FROM (${CTID_FROM_HOSTNAME}) -> $CTID_TO (${CTID_TO_HOSTNAME})
Version: 2022.01.23" 13 50 || exit
info "Home Assistant Data from '$CTID_FROM' to '$CTID_TO'"
if [ $(pct status "$CTID_TO" | sed 's/.* //') == 'running' ]; then
msg "Stopping '$CTID_TO'..."
pct stop "$CTID_TO"
fi
msg "Mounting Container Disks..."
DOCKER_PATH=/var/lib/docker/volumes/hass_config/
CTID_FROM_PATH=$(pct mount "$CTID_FROM" | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_FROM}'."
[ -d "${CTID_FROM_PATH}${DOCKER_PATH}" ] ||
die "Home Assistant directories in '$CTID_FROM' not found."
CTID_TO_PATH=$(pct mount "$CTID_TO" | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_TO}'."
[ -d "${CTID_TO_PATH}${DOCKER_PATH}" ] ||
die "Home Assistant directories in '$CTID_TO' not found."
rm -rf "${CTID_TO_PATH}"${DOCKER_PATH}
mkdir "${CTID_TO_PATH}"${DOCKER_PATH}
msg "Copying Data Between Containers..."
RSYNC_OPTIONS=(
--archive
--hard-links
--sparse
--xattrs
--no-inc-recursive
--info=progress2
)
msg "<======== Docker Data ========>"
rsync "${RSYNC_OPTIONS[*]}" "${CTID_FROM_PATH}"${DOCKER_PATH} "${CTID_TO_PATH}"${DOCKER_PATH}
echo -en "\e[1A\e[0K\e[1A\e[0K"
info "Successfully Transferred Data."
# Use to copy all data from one Home Assistant LXC to another
# run from the Proxmox Shell
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/mainmain/tools/copy-data//home-assistant-container-copy-data-home-assistant-container.sh)"

View file

@ -0,0 +1,127 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
clear
if ! command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Run from the Proxmox Shell"
exit
fi
while true; do
read -p "Use to copy all data from a Home Assistant Container LXC to a Home Assistant Core LXC. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
shopt -s expand_aliases
alias die='EXIT=$? LINE=$LINENO error_exit'
trap die ERR
trap cleanup EXIT
function error_exit() {
trap - ERR
local DEFAULT='Unknown failure occured.'
local REASON="\e[97m${1:-$DEFAULT}\e[39m"
local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE"
msg "$FLAG $REASON"
exit $EXIT
}
function warn() {
local REASON="\e[97m$1\e[39m"
local FLAG="\e[93m[WARNING]\e[39m"
msg "$FLAG $REASON"
}
function info() {
local REASON="$1"
local FLAG="\e[36m[INFO]\e[39m"
msg "$FLAG $REASON"
}
function msg() {
local TEXT="$1"
echo -e "$TEXT"
}
function cleanup() {
[ -d "${CTID_FROM_PATH:-}" ] && pct unmount $CTID_FROM
[ -d "${CTID_TO_PATH:-}" ] && pct unmount $CTID_TO
popd >/dev/null
rm -rf $TEMP_DIR
}
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
TITLE="Home Assistant LXC Data Copy"
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
ITEM=$(echo "$line" | awk '{print substr($0,36)}')
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
CTID_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
while [ -z "${CTID_FROM:+x}" ]; do
CTID_FROM=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich HA Container LXC would you like to copy FROM?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
while [ -z "${CTID_TO:+x}" ]; do
CTID_TO=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich HA Core LXC would you like to copy TO?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
for i in ${!CTID_MENU[@]}; do
[ "${CTID_MENU[$i]}" == "$CTID_FROM" ] &&
CTID_FROM_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
[ "${CTID_MENU[$i]}" == "$CTID_TO" ] &&
CTID_TO_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
done
whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "$TITLE" --yesno \
"Are you sure you want to copy data between the following LXCs?
$CTID_FROM (${CTID_FROM_HOSTNAME}) -> $CTID_TO (${CTID_TO_HOSTNAME})
Version: 2022.10.02" 13 50 || exit
info "Home Assistant Data from '$CTID_FROM' to '$CTID_TO'"
if [ $(pct status $CTID_TO | sed 's/.* //') == 'running' ]; then
msg "Stopping '$CTID_TO'..."
pct stop $CTID_TO
fi
msg "Mounting Container Disks..."
DOCKER_PATH=/var/lib/docker/volumes/hass_config/_data
CORE_PATH=/root/.homeassistant
CTID_FROM_PATH=$(pct mount $CTID_FROM | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_FROM}'."
[ -d "${CTID_FROM_PATH}${DOCKER_PATH}" ] ||
die "Home Assistant directories in '$CTID_FROM' not found."
CTID_TO_PATH=$(pct mount $CTID_TO | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_TO}'."
[ -d "${CTID_TO_PATH}${CORE_PATH}" ] ||
die "Home Assistant directories in '$CTID_TO' not found."
msg "Copying Data..."
RSYNC_OPTIONS=(
--archive
--hard-links
--sparse
--xattrs
--no-inc-recursive
--info=progress2
)
msg "<======== Docker Data ========>"
rsync ${RSYNC_OPTIONS[*]} ${CTID_FROM_PATH}${DOCKER_PATH} ${CTID_TO_PATH}${CORE_PATH}
echo -en "\e[1A\e[0K\e[1A\e[0K"
info "Successfully Transferred Data."
# Use to copy all data from a Home Assistant Container LXC to a Home Assistant Core LXC
# run from the Proxmox Shell
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/mainmain/tools/copy-data//home-assistant-container-copy-data-home-assistant-core.sh)"

View file

@ -0,0 +1,132 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Use to copy all data from a Home Assistant LXC to a Podman Home Assistant LXC.
# run from the Proxmox Shell
clear
if ! command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Run from the Proxmox Shell"
exit
fi
while true; do
read -p "Use to copy all data from a Home Assistant LXC to a Podman Home Assistant LXC. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
shopt -s expand_aliases
alias die='EXIT=$? LINE=$LINENO error_exit'
trap die ERR
trap cleanup EXIT
function error_exit() {
trap - ERR
local DEFAULT='Unknown failure occured.'
local REASON="\e[97m${1:-$DEFAULT}\e[39m"
local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE"
msg "$FLAG $REASON"
exit $EXIT
}
function warn() {
local REASON="\e[97m$1\e[39m"
local FLAG="\e[93m[WARNING]\e[39m"
msg "$FLAG $REASON"
}
function info() {
local REASON="$1"
local FLAG="\e[36m[INFO]\e[39m"
msg "$FLAG $REASON"
}
function msg() {
local TEXT="$1"
echo -e "$TEXT"
}
function cleanup() {
[ -d "${CTID_FROM_PATH:-}" ] && pct unmount $CTID_FROM
[ -d "${CTID_TO_PATH:-}" ] && pct unmount $CTID_TO
popd >/dev/null
rm -rf $TEMP_DIR
}
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
TITLE="Home Assistant LXC Data Copy"
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
ITEM=$(echo "$line" | awk '{print substr($0,36)}')
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
CTID_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
while [ -z "${CTID_FROM:+x}" ]; do
CTID_FROM=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich HA LXC would you like to copy FROM?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
while [ -z "${CTID_TO:+x}" ]; do
CTID_TO=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich HA Podman LXC would you like to copy TO?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
for i in ${!CTID_MENU[@]}; do
[ "${CTID_MENU[$i]}" == "$CTID_FROM" ] &&
CTID_FROM_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
[ "${CTID_MENU[$i]}" == "$CTID_TO" ] &&
CTID_TO_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
done
whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "$TITLE" --yesno \
"Are you sure you want to copy data between the following LXCs?
$CTID_FROM (${CTID_FROM_HOSTNAME}) -> $CTID_TO (${CTID_TO_HOSTNAME})
Version: 2022.02.12" 13 50 || exit
info "Home Assistant Data from '$CTID_FROM' to '$CTID_TO'"
if [ $(pct status $CTID_TO | sed 's/.* //') == 'running' ]; then
msg "Stopping '$CTID_TO'..."
pct stop $CTID_TO
fi
msg "Mounting Container Disks..."
DOCKER_PATH=/var/lib/docker/volumes/hass_config/
PODMAN_PATH=/var/lib/containers/storage/volumes/hass_config/
CTID_FROM_PATH=$(pct mount $CTID_FROM | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_FROM}'."
[ -d "${CTID_FROM_PATH}${DOCKER_PATH}" ] ||
die "Home Assistant directories in '$CTID_FROM' not found."
CTID_TO_PATH=$(pct mount $CTID_TO | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_TO}'."
[ -d "${CTID_TO_PATH}${PODMAN_PATH}" ] ||
die "Home Assistant directories in '$CTID_TO' not found."
rm -rf ${CTID_TO_PATH}${PODMAN_PATH}
mkdir ${CTID_TO_PATH}${PODMAN_PATH}
msg "Copying Data Between Containers..."
RSYNC_OPTIONS=(
--archive
--hard-links
--sparse
--xattrs
--no-inc-recursive
--info=progress2
)
msg "<======== Docker Data ========>"
rsync ${RSYNC_OPTIONS[*]} ${CTID_FROM_PATH}${DOCKER_PATH} ${CTID_TO_PATH}${PODMAN_PATH}
echo -en "\e[1A\e[0K\e[1A\e[0K"
info "Successfully Transferred Data."
# Use to copy all data from a Home Assistant LXC to a Podman Home Assistant LXC
# run from the Proxmox Shell
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/mainmain/tools/copy-data//home-assistant-container-copy-data-podman-home-assistant.sh)"

View file

@ -0,0 +1,127 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
clear
if ! command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Run from the Proxmox Shell"
exit
fi
while true; do
read -p "Use to copy all data from a Home Assistant Core LXC to a Home Assistant Container LXC. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
shopt -s expand_aliases
alias die='EXIT=$? LINE=$LINENO error_exit'
trap die ERR
trap cleanup EXIT
function error_exit() {
trap - ERR
local DEFAULT='Unknown failure occured.'
local REASON="\e[97m${1:-$DEFAULT}\e[39m"
local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE"
msg "$FLAG $REASON"
exit $EXIT
}
function warn() {
local REASON="\e[97m$1\e[39m"
local FLAG="\e[93m[WARNING]\e[39m"
msg "$FLAG $REASON"
}
function info() {
local REASON="$1"
local FLAG="\e[36m[INFO]\e[39m"
msg "$FLAG $REASON"
}
function msg() {
local TEXT="$1"
echo -e "$TEXT"
}
function cleanup() {
[ -d "${CTID_FROM_PATH:-}" ] && pct unmount $CTID_FROM
[ -d "${CTID_TO_PATH:-}" ] && pct unmount $CTID_TO
popd >/dev/null
rm -rf $TEMP_DIR
}
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
TITLE="Home Assistant LXC Data Copy"
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
ITEM=$(echo "$line" | awk '{print substr($0,36)}')
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
CTID_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
while [ -z "${CTID_FROM:+x}" ]; do
CTID_FROM=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich HA Core LXC would you like to copy FROM?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
while [ -z "${CTID_TO:+x}" ]; do
CTID_TO=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich HA Container LXC would you like to copy TO?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
for i in ${!CTID_MENU[@]}; do
[ "${CTID_MENU[$i]}" == "$CTID_FROM" ] &&
CTID_FROM_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
[ "${CTID_MENU[$i]}" == "$CTID_TO" ] &&
CTID_TO_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
done
whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "$TITLE" --yesno \
"Are you sure you want to copy data between the following LXCs?
$CTID_FROM (${CTID_FROM_HOSTNAME}) -> $CTID_TO (${CTID_TO_HOSTNAME})
Version: 2022.10.02" 13 50 || exit
info "Home Assistant Data from '$CTID_FROM' to '$CTID_TO'"
if [ $(pct status $CTID_TO | sed 's/.* //') == 'running' ]; then
msg "Stopping '$CTID_TO'..."
pct stop $CTID_TO
fi
msg "Mounting Container Disks..."
DOCKER_PATH=/var/lib/docker/volumes/hass_config/_data
CORE_PATH=/root/.homeassistant
CTID_FROM_PATH=$(pct mount $CTID_FROM | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_FROM}'."
[ -d "${CTID_FROM_PATH}${CORE_PATH}" ] ||
die "Home Assistant directories in '$CTID_FROM' not found."
CTID_TO_PATH=$(pct mount $CTID_TO | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_TO}'."
[ -d "${CTID_TO_PATH}${DOCKER_PATH}" ] ||
die "Home Assistant directories in '$CTID_TO' not found."
msg "Copying Data..."
RSYNC_OPTIONS=(
--archive
--hard-links
--sparse
--xattrs
--no-inc-recursive
--info=progress2
)
msg "<======== Docker Data ========>"
rsync ${RSYNC_OPTIONS[*]} ${CTID_FROM_PATH}${CORE_PATH} ${CTID_TO_PATH}${DOCKER_PATH}
echo -en "\e[1A\e[0K\e[1A\e[0K"
info "Successfully Transferred Data."
# Use to copy all data from a Home Assistant Core LXC to a Home Assistant Container LXC
# run from the Proxmox Shell
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/mainmain/tools/copy-data//home-assistant-core-copy-data-home-assistant-container.sh)"

View file

@ -0,0 +1,126 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
clear
if ! command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Run from the Proxmox Shell"
exit
fi
while true; do
read -p "Use to copy all data from a Home Assistant Core LXC to a Home Assistant Core LXC. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
shopt -s expand_aliases
alias die='EXIT=$? LINE=$LINENO error_exit'
trap die ERR
trap cleanup EXIT
function error_exit() {
trap - ERR
local DEFAULT='Unknown failure occured.'
local REASON="\e[97m${1:-$DEFAULT}\e[39m"
local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE"
msg "$FLAG $REASON"
exit $EXIT
}
function info() {
local REASON="$1"
local FLAG="\e[36m[INFO]\e[39m"
msg "$FLAG $REASON"
}
function msg() {
local TEXT="$1"
echo -e "$TEXT"
}
function cleanup() {
[ -d "${CTID_FROM_PATH:-}" ] && pct unmount $CTID_FROM
[ -d "${CTID_TO_PATH:-}" ] && pct unmount $CTID_TO
popd >/dev/null
rm -rf $TEMP_DIR
}
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
TITLE="Home Assistant LXC Data Copy"
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
ITEM=$(echo "$line" | awk '{print substr($0,36)}')
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
CTID_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
while [ -z "${CTID_FROM:+x}" ]; do
CTID_FROM=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich HA Core LXC would you like to copy FROM?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
while [ -z "${CTID_TO:+x}" ]; do
CTID_TO=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich HA Core LXC would you like to copy TO?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
for i in ${!CTID_MENU[@]}; do
[ "${CTID_MENU[$i]}" == "$CTID_FROM" ] &&
CTID_FROM_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
[ "${CTID_MENU[$i]}" == "$CTID_TO" ] &&
CTID_TO_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
done
whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "$TITLE" --yesno \
"Are you sure you want to copy data between the following LXCs?
$CTID_FROM (${CTID_FROM_HOSTNAME}) -> $CTID_TO (${CTID_TO_HOSTNAME})
Version: 2022.10.03" 13 50 || exit
info "Home Assistant Data from '$CTID_FROM' to '$CTID_TO'"
if [ $(pct status $CTID_FROM | sed 's/.* //') == 'running' ]; then
msg "Stopping '$CTID_FROM'..."
pct stop $CTID_FROM
fi
if [ $(pct status $CTID_TO | sed 's/.* //') == 'running' ]; then
msg "Stopping '$CTID_TO'..."
pct stop $CTID_TO
fi
msg "Mounting Container Disks..."
CORE_PATH=/root/.homeassistant
CORE_PATH2=/root/
CTID_FROM_PATH=$(pct mount $CTID_FROM | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_FROM}'."
[ -d "${CTID_FROM_PATH}${CORE_PATH}" ] ||
die "Home Assistant directories in '$CTID_FROM' not found."
CTID_TO_PATH=$(pct mount $CTID_TO | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_TO}'."
[ -d "${CTID_TO_PATH}${CORE_PATH2}" ] ||
die "Home Assistant directories in '$CTID_TO' not found."
msg "Copying Data..."
RSYNC_OPTIONS=(
--archive
--hard-links
--sparse
--xattrs
--no-inc-recursive
--info=progress2
)
msg "<======== Docker Data ========>"
rsync ${RSYNC_OPTIONS[*]} ${CTID_FROM_PATH}${CORE_PATH} ${CTID_TO_PATH}${CORE_PATH2}
echo -en "\e[1A\e[0K\e[1A\e[0K"
info "Successfully Transferred Data."
# Use to copy all data from a Home Assistant Core LXC to a Home Assistant Container LXC
# run from the Proxmox Shell
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/mainmain/tools/copy-data//home-assistant-core-copy-data-home-assistant-core.sh)"

View file

@ -0,0 +1,131 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Use to copy all data from one Plex Media Server LXC to another
# run from the Proxmox Shell
clear
if ! command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Run from the Proxmox Shell"
exit
fi
while true; do
read -p "Use to copy all data from one Plex Media Server LXC to another. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
shopt -s expand_aliases
alias die='EXIT=$? LINE=$LINENO error_exit'
trap die ERR
trap cleanup EXIT
function error_exit() {
trap - ERR
local DEFAULT='Unknown failure occured.'
local REASON="\e[97m${1:-$DEFAULT}\e[39m"
local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE"
msg "$FLAG $REASON"
exit $EXIT
}
function warn() {
local REASON="\e[97m$1\e[39m"
local FLAG="\e[93m[WARNING]\e[39m"
msg "$FLAG $REASON"
}
function info() {
local REASON="$1"
local FLAG="\e[36m[INFO]\e[39m"
msg "$FLAG $REASON"
}
function msg() {
local TEXT="$1"
echo -e "$TEXT"
}
function cleanup() {
[ -d "${CTID_FROM_PATH:-}" ] && pct unmount $CTID_FROM
[ -d "${CTID_TO_PATH:-}" ] && pct unmount $CTID_TO
popd >/dev/null
rm -rf $TEMP_DIR
}
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
TITLE="Plex Media Server LXC Data Copy"
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
ITEM=$(echo "$line" | awk '{print substr($0,36)}')
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
CTID_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
while [ -z "${CTID_FROM:+x}" ]; do
CTID_FROM=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich Plex Media Server LXC would you like to copy FROM?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
while [ -z "${CTID_TO:+x}" ]; do
CTID_TO=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich Plex Media Server LXC would you like to copy TO?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
for i in ${!CTID_MENU[@]}; do
[ "${CTID_MENU[$i]}" == "$CTID_FROM" ] &&
CTID_FROM_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
[ "${CTID_MENU[$i]}" == "$CTID_TO" ] &&
CTID_TO_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
done
whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "$TITLE" --yesno \
"Are you sure you want to copy data between the following LXCs?
$CTID_FROM (${CTID_FROM_HOSTNAME}) -> $CTID_TO (${CTID_TO_HOSTNAME})
Version: 2022.01.24" 13 50 || exit
info "Plex Media Server Data from '$CTID_FROM' to '$CTID_TO'"
if [ $(pct status $CTID_TO | sed 's/.* //') == 'running' ]; then
msg "Stopping '$CTID_TO'..."
pct stop $CTID_TO
fi
msg "Mounting Container Disks..."
DATA_PATH=/var/lib/plexmediaserver/Library/
CTID_FROM_PATH=$(pct mount $CTID_FROM | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_FROM}'."
[ -d "${CTID_FROM_PATH}${DATA_PATH}" ] ||
die "Plex Media Server directories in '$CTID_FROM' not found."
CTID_TO_PATH=$(pct mount $CTID_TO | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_TO}'."
[ -d "${CTID_TO_PATH}${DATA_PATH}" ] ||
die "Plex Media Server directories in '$CTID_TO' not found."
#rm -rf ${CTID_TO_PATH}${DATA_PATH}
#mkdir ${CTID_TO_PATH}${DATA_PATH}
msg "Copying Data Between Containers..."
RSYNC_OPTIONS=(
--archive
--hard-links
--sparse
--xattrs
--no-inc-recursive
--info=progress2
)
msg "<======== Plex Media Server Data ========>"
rsync ${RSYNC_OPTIONS[*]} ${CTID_FROM_PATH}${DATA_PATH} ${CTID_TO_PATH}${DATA_PATH}
echo -en "\e[1A\e[0K\e[1A\e[0K"
info "Successfully Transferred Data."
# Use to copy all data from one Plex Media Server LXC to another
# run from the Proxmox Shell
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/mainmain/tools/copy-data//plex-copy-data-plex.sh)"

View file

@ -0,0 +1,132 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Use to copy all data from a Podman Home Assistant LXC to a Docker Home Assistant LXC.
# run from the Proxmox Shell
clear
if ! command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Run from the Proxmox Shell"
exit
fi
while true; do
read -p "Use to copy all data from a Podman Home Assistant LXC to a Docker Home Assistant LXC. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
shopt -s expand_aliases
alias die='EXIT=$? LINE=$LINENO error_exit'
trap die ERR
trap cleanup EXIT
function error_exit() {
trap - ERR
local DEFAULT='Unknown failure occured.'
local REASON="\e[97m${1:-$DEFAULT}\e[39m"
local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE"
msg "$FLAG $REASON"
exit $EXIT
}
function warn() {
local REASON="\e[97m$1\e[39m"
local FLAG="\e[93m[WARNING]\e[39m"
msg "$FLAG $REASON"
}
function info() {
local REASON="$1"
local FLAG="\e[36m[INFO]\e[39m"
msg "$FLAG $REASON"
}
function msg() {
local TEXT="$1"
echo -e "$TEXT"
}
function cleanup() {
[ -d "${CTID_FROM_PATH:-}" ] && pct unmount $CTID_FROM
[ -d "${CTID_TO_PATH:-}" ] && pct unmount $CTID_TO
popd >/dev/null
rm -rf $TEMP_DIR
}
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
TITLE="Home Assistant LXC Data Copy"
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
ITEM=$(echo "$line" | awk '{print substr($0,36)}')
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
CTID_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
while [ -z "${CTID_FROM:+x}" ]; do
CTID_FROM=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich HA Podman LXC would you like to copy FROM?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
while [ -z "${CTID_TO:+x}" ]; do
CTID_TO=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich HA LXC would you like to copy TO?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
for i in ${!CTID_MENU[@]}; do
[ "${CTID_MENU[$i]}" == "$CTID_FROM" ] &&
CTID_FROM_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
[ "${CTID_MENU[$i]}" == "$CTID_TO" ] &&
CTID_TO_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
done
whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "$TITLE" --yesno \
"Are you sure you want to copy data between the following LXCs?
$CTID_FROM (${CTID_FROM_HOSTNAME}) -> $CTID_TO (${CTID_TO_HOSTNAME})
Version: 2022.03.31" 13 50 || exit
info "Home Assistant Data from '$CTID_FROM' to '$CTID_TO'"
if [ $(pct status $CTID_TO | sed 's/.* //') == 'running' ]; then
msg "Stopping '$CTID_TO'..."
pct stop $CTID_TO
fi
msg "Mounting Container Disks..."
DOCKER_PATH=/var/lib/docker/volumes/hass_config/
PODMAN_PATH=/var/lib/containers/storage/volumes/hass_config/
CTID_FROM_PATH=$(pct mount $CTID_FROM | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_FROM}'."
[ -d "${CTID_FROM_PATH}${PODMAN_PATH}" ] ||
die "Home Assistant directories in '$CTID_FROM' not found."
CTID_TO_PATH=$(pct mount $CTID_TO | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_TO}'."
[ -d "${CTID_TO_PATH}${DOCKER_PATH}" ] ||
die "Home Assistant directories in '$CTID_TO' not found."
rm -rf ${CTID_TO_PATH}${DOCKER_PATH}
mkdir ${CTID_TO_PATH}${DOCKER_PATH}
msg "Copying Data Between Containers..."
RSYNC_OPTIONS=(
--archive
--hard-links
--sparse
--xattrs
--no-inc-recursive
--info=progress2
)
msg "<======== Data ========>"
rsync ${RSYNC_OPTIONS[*]} ${CTID_FROM_PATH}${PODMAN_PATH} ${CTID_TO_PATH}${DOCKER_PATH}
echo -en "\e[1A\e[0K\e[1A\e[0K"
info "Successfully Transferred Data."
# Use to copy all data from a Podman Home Assistant LXC to a Docker Home Assistant LXC.
# run from the Proxmox Shell
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/mainmain/tools/copy-data//podman-home-assistant-copy-data-home-assistant-container.sh)"

View file

@ -0,0 +1,131 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Use to copy all data from one Zigbee2MQTT LXC to another
# run from the Proxmox Shell
clear
if ! command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Run from the Proxmox Shell"
exit
fi
while true; do
read -p "Use to copy all data from one Zigbee2MQTT LXC to another. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
shopt -s expand_aliases
alias die='EXIT=$? LINE=$LINENO error_exit'
trap die ERR
trap cleanup EXIT
function error_exit() {
trap - ERR
local DEFAULT='Unknown failure occured.'
local REASON="\e[97m${1:-$DEFAULT}\e[39m"
local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE"
msg "$FLAG $REASON"
exit $EXIT
}
function warn() {
local REASON="\e[97m$1\e[39m"
local FLAG="\e[93m[WARNING]\e[39m"
msg "$FLAG $REASON"
}
function info() {
local REASON="$1"
local FLAG="\e[36m[INFO]\e[39m"
msg "$FLAG $REASON"
}
function msg() {
local TEXT="$1"
echo -e "$TEXT"
}
function cleanup() {
[ -d "${CTID_FROM_PATH:-}" ] && pct unmount $CTID_FROM
[ -d "${CTID_TO_PATH:-}" ] && pct unmount $CTID_TO
popd >/dev/null
rm -rf $TEMP_DIR
}
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
TITLE="Zigbee2MQTT LXC Data Copy"
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
ITEM=$(echo "$line" | awk '{print substr($0,36)}')
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
CTID_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
while [ -z "${CTID_FROM:+x}" ]; do
CTID_FROM=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich Zigbee2MQTT LXC would you like to copy FROM?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
while [ -z "${CTID_TO:+x}" ]; do
CTID_TO=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich Zigbee2MQTT LXC would you like to copy TO?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
for i in ${!CTID_MENU[@]}; do
[ "${CTID_MENU[$i]}" == "$CTID_FROM" ] &&
CTID_FROM_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
[ "${CTID_MENU[$i]}" == "$CTID_TO" ] &&
CTID_TO_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<${CTID_MENU[$i + 1]})
done
whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "$TITLE" --yesno \
"Are you sure you want to copy data between the following LXCs?
$CTID_FROM (${CTID_FROM_HOSTNAME}) -> $CTID_TO (${CTID_TO_HOSTNAME})
Version: 2022.01.23" 13 50 || exit
info "Zigbee2MQTT Data from '$CTID_FROM' to '$CTID_TO'"
if [ $(pct status $CTID_TO | sed 's/.* //') == 'running' ]; then
msg "Stopping '$CTID_TO'..."
pct stop $CTID_TO
fi
msg "Mounting Container Disks..."
DATA_PATH=/opt/zigbee2mqtt/data/
CTID_FROM_PATH=$(pct mount $CTID_FROM | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_FROM}'."
[ -d "${CTID_FROM_PATH}${DATA_PATH}" ] ||
die "Zigbee2igbee2MQTT directories in '$CTID_FROM' not found."
CTID_TO_PATH=$(pct mount $CTID_TO | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_TO}'."
[ -d "${CTID_TO_PATH}${DATA_PATH}" ] ||
die "Zigbee2MQTT directories in '$CTID_TO' not found."
#rm -rf ${CTID_TO_PATH}${DATA_PATH}
#mkdir ${CTID_TO_PATH}${DATA_PATH}
msg "Copying Data Between Containers..."
RSYNC_OPTIONS=(
--archive
--hard-links
--sparse
--xattrs
--no-inc-recursive
--info=progress2
)
msg "<======== Zigbee2MQTT Data ========>"
rsync ${RSYNC_OPTIONS[*]} ${CTID_FROM_PATH}${DATA_PATH} ${CTID_TO_PATH}${DATA_PATH}
echo -en "\e[1A\e[0K\e[1A\e[0K"
info "Successfully Transferred Data."
# Use to copy all data from one Zigbee2MQTT LXC to another
# run from the Proxmox Shell
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/mainmain/tools/copy-data//z2m-copy-data-z2m.sh)"

View file

@ -0,0 +1,133 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Use to copy all data from a Zwavejs2MQTT LXC to a Z-wave JS UI LXC
# run from the Proxmox Shell
clear
if ! command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Run from the Proxmox Shell"
exit
fi
while true; do
read -p "Use to copy all data from a Zwavejs2MQTT LXC to a Z-wave JS UI LXC. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
clear
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
shopt -s expand_aliases
alias die='EXIT=$? LINE=$LINENO error_exit'
trap die ERR
trap cleanup EXIT
function error_exit() {
trap - ERR
local DEFAULT='Unknown failure occured.'
local REASON="\e[97m${1:-$DEFAULT}\e[39m"
local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE"
msg "$FLAG $REASON"
exit "$EXIT"
}
function warn() {
local REASON="\e[97m$1\e[39m"
local FLAG="\e[93m[WARNING]\e[39m"
msg "$FLAG $REASON"
}
function info() {
local REASON="$1"
local FLAG="\e[36m[INFO]\e[39m"
msg "$FLAG $REASON"
}
function msg() {
local TEXT="$1"
echo -e "$TEXT"
}
function cleanup() {
[ -d "${CTID_FROM_PATH:-}" ] && pct unmount "$CTID_FROM"
[ -d "${CTID_TO_PATH:-}" ] && pct unmount "$CTID_TO"
popd >/dev/null
rm -rf "$TEMP_DIR"
}
TEMP_DIR=$(mktemp -d)
pushd "$TEMP_DIR" >/dev/null
TITLE="Zigbee2MQTT to Z-wave JS UI Data Copy"
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
ITEM=$(echo "$line" | awk '{print substr($0,36)}')
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
CTID_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
while [ -z "${CTID_FROM:+x}" ]; do
CTID_FROM=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich Zwavejs2MQTT LXC would you like to copy FROM?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
while [ -z "${CTID_TO:+x}" ]; do
CTID_TO=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "$TITLE" --radiolist \
"\nWhich Z-wave JS UI LXC would you like to copy TO?\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
for i in ${!CTID_MENU[@]}; do
[ "${CTID_MENU[$i]}" == "$CTID_FROM" ] &&
CTID_FROM_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<"${CTID_MENU[$i + 1]}")
[ "${CTID_MENU[$i]}" == "$CTID_TO" ] &&
CTID_TO_HOSTNAME=$(sed 's/[[:space:]]*$//' <<<"${CTID_MENU[$i + 1]}")
done
whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "$TITLE" --yesno \
"Are you sure you want to copy data between the following LXCs?
$CTID_FROM (${CTID_FROM_HOSTNAME}) -> $CTID_TO (${CTID_TO_HOSTNAME})
Version: 2022.09.21" 13 50 || exit
info "Zwavejs2MQTT Data from '$CTID_FROM' to '$CTID_TO'"
if [ $(pct status "$CTID_TO" | sed 's/.* //') == 'running' ]; then
msg "Stopping '$CTID_TO'..."
pct stop "$CTID_TO"
fi
msg "Mounting Container Disks..."
DATA_PATH=/opt/zwavejs2mqtt/store/
DATA_PATH_NEW=/opt/zwave-js-ui/store/
CTID_FROM_PATH=$(pct mount "$CTID_FROM" | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_FROM}'."
[ -d "${CTID_FROM_PATH}${DATA_PATH}" ] ||
die "Zwavejs2MQTT directories in '$CTID_FROM' not found."
CTID_TO_PATH=$(pct mount "$CTID_TO" | sed -n "s/.*'\(.*\)'/\1/p") ||
die "There was a problem mounting the root disk of LXC '${CTID_TO}'."
[ -d "${CTID_TO_PATH}${DATA_PATH_NEW}" ] ||
die "Zwavejs2MQTT directories in '$CTID_TO' not found."
#rm -rf ${CTID_TO_PATH}${DATA_PATH}
#mkdir ${CTID_TO_PATH}${DATA_PATH}
msg "Copying Data Between Containers..."
RSYNC_OPTIONS=(
--archive
--hard-links
--sparse
--xattrs
--no-inc-recursive
--info=progress2
)
msg "<======== Zwavejs Data ========>"
rsync "${RSYNC_OPTIONS[*]}" "${CTID_FROM_PATH}"${DATA_PATH} "${CTID_TO_PATH}"${DATA_PATH_NEW}
echo -en "\e[1A\e[0K\e[1A\e[0K"
info "Successfully Transferred Data."
# Use to copy all data from a Zwavejs2MQTT LXC to a Z-wave JS UI LXC
# run from the Proxmox Shell
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/mainmain/tools/copy-data//zwavejs2mqtt-copy-data-zwavejsui.sh)"

357
tools/pve/add-lxc-iptag.sh Normal file
View file

@ -0,0 +1,357 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: MickLesk (Canbiz)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/gitsang/lxc-iptag
function header_info {
clear
cat <<"EOF"
__ _ ________ ________ ______
/ / | |/ / ____/ / _/ __ \ /_ __/___ _____ _
/ / | / / / // /_/ /_____/ / / __ `/ __ `/
/ /___/ / /___ _/ // ____/_____/ / / /_/ / /_/ /
/_____/_/|_\____/ /___/_/ /_/ \__,_/\__, /
/____/
EOF
}
clear
header_info
APP="LXC IP-Tag"
hostname=$(hostname)
# Farbvariablen
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
RD=$(echo "\033[01;31m")
CL=$(echo "\033[m")
BFR="\\r\\033[K"
HOLD=" "
CM=" ✔️ ${CL}"
CROSS=" ✖️ ${CL}"
# This function enables error handling in the script by setting options and defining a trap for the ERR signal.
catch_errors() {
set -Eeuo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
# This function is called when an error occurs. It receives the exit code, line number, and command that caused the error, and displays an error message.
error_handler() {
if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then kill $SPINNER_PID >/dev/null; fi
printf "\e[?25h"
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}"
echo -e "\n$error_message\n"
}
# This function displays a spinner.
spinner() {
local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
local spin_i=0
local interval=0.1
printf "\e[?25l"
local color="${YWB}"
while true; do
printf "\r ${color}%s${CL}" "${frames[spin_i]}"
spin_i=$(((spin_i + 1) % ${#frames[@]}))
sleep "$interval"
done
}
# This function displays an informational message with a yellow color.
msg_info() {
local msg="$1"
echo -ne "${TAB}${YW}${HOLD}${msg}${HOLD}"
spinner &
SPINNER_PID=$!
}
# This function displays a success message with a green color.
msg_ok() {
if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then kill $SPINNER_PID >/dev/null; fi
printf "\e[?25h"
local msg="$1"
echo -e "${BFR}${CM}${GN}${msg}${CL}"
}
# This function displays a error message with a red color.
msg_error() {
if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then kill $SPINNER_PID >/dev/null; fi
printf "\e[?25h"
local msg="$1"
echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
}
while true; do
read -p "This will install ${APP} on ${hostname}. Proceed? (y/n): " yn
case $yn in
[Yy]*) break ;;
[Nn]*)
msg_error "Installation cancelled."
exit
;;
*) msg_error "Please answer yes or no." ;;
esac
done
if ! pveversion | grep -Eq "pve-manager/8\.[0-3](\.[0-9]+)*"; then
msg_error "This version of Proxmox Virtual Environment is not supported"
msg_error "⚠️ Requires Proxmox Virtual Environment Version 8.0 or later."
msg_error "Exiting..."
sleep 2
exit
fi
FILE_PATH="/usr/local/bin/iptag"
if [[ -f "$FILE_PATH" ]]; then
msg_info "The file already exists: '$FILE_PATH'. Skipping installation."
exit 0
fi
msg_info "Installing Dependencies"
apt-get update &>/dev/null
apt-get install -y ipcalc net-tools &>/dev/null
msg_ok "Installed Dependencies"
msg_info "Setting up IP-Tag Scripts"
mkdir -p /opt/lxc-iptag
msg_ok "Setup IP-Tag Scripts"
msg_info "Setup Default Config"
if [[ ! -f /opt/lxc-iptag/iptag.conf ]]; then
cat <<EOF >/opt/lxc-iptag/iptag.conf
# Configuration file for LXC IP tagging
# List of allowed CIDRs
CIDR_LIST=(
192.168.0.0/16
172.16.0.0/12
10.0.0.0/8
100.64.0.0/10
)
# Interval settings (in seconds)
LOOP_INTERVAL=60
FW_NET_INTERFACE_CHECK_INTERVAL=60
LXC_STATUS_CHECK_INTERVAL=-1
FORCE_UPDATE_INTERVAL=1800
EOF
msg_ok "Setup default config"
else
msg_ok "Default config already exists"
fi
msg_info "Setup Main Function"
if [[ ! -f /opt/lxc-iptag/iptag ]]; then
cat <<'EOF' >/opt/lxc-iptag/iptag
#!/bin/bash
# =============== CONFIGURATION =============== #
CONFIG_FILE="/opt/lxc-iptag/iptag.conf"
# Load the configuration file if it exists
if [ -f "$CONFIG_FILE" ]; then
# shellcheck source=./lxc-iptag.conf
source "$CONFIG_FILE"
fi
# Convert IP to integer for comparison
ip_to_int() {
local ip="${1}"
local a b c d
IFS=. read -r a b c d <<< "${ip}"
echo "$((a << 24 | b << 16 | c << 8 | d))"
}
# Check if IP is in CIDR
ip_in_cidr() {
local ip="${1}"
local cidr="${2}"
ip_int=$(ip_to_int "${ip}")
netmask_int=$(ip_to_int "$(ipcalc -b "${cidr}" | grep Broadcast | awk '{print $2}')")
masked_ip_int=$(( "${ip_int}" & "${netmask_int}" ))
[[ ${ip_int} -eq ${masked_ip_int} ]] && return 0 || return 1
}
# Check if IP is in any CIDRs
ip_in_cidrs() {
local ip="${1}"
local cidrs=()
mapfile -t cidrs < <(echo "${2}" | tr ' ' '\n')
for cidr in "${cidrs[@]}"; do
ip_in_cidr "${ip}" "${cidr}" && return 0
done
return 1
}
# Check if IP is valid
is_valid_ipv4() {
local ip=$1
local regex="^([0-9]{1,3}\.){3}[0-9]{1,3}$"
if [[ $ip =~ $regex ]]; then
IFS='.' read -r -a parts <<< "$ip"
for part in "${parts[@]}"; do
if ! [[ $part =~ ^[0-9]+$ ]] || ((part < 0 || part > 255)); then
return 1
fi
done
return 0
else
return 1
fi
}
lxc_status_changed() {
current_lxc_status=$(pct list 2>/dev/null)
if [ "${last_lxc_status}" == "${current_lxc_status}" ]; then
return 1
else
last_lxc_status="${current_lxc_status}"
return 0
fi
}
fw_net_interface_changed() {
current_net_interface=$(ifconfig | grep "^fw")
if [ "${last_net_interface}" == "${current_net_interface}" ]; then
return 1
else
last_net_interface="${current_net_interface}"
return 0
fi
}
# =============== MAIN =============== #
update_lxc_iptags() {
vmid_list=$(pct list 2>/dev/null | grep -v VMID | awk '{print $1}')
for vmid in ${vmid_list}; do
last_tagged_ips=()
current_valid_ips=()
next_tags=()
# Parse current tags
mapfile -t current_tags < <(pct config "${vmid}" | grep tags | awk '{print $2}' | sed 's/;/\n/g')
for current_tag in "${current_tags[@]}"; do
if is_valid_ipv4 "${current_tag}"; then
last_tagged_ips+=("${current_tag}")
continue
fi
next_tags+=("${current_tag}")
done
# Get current IPs
current_ips_full=$(lxc-info -n "${vmid}" -i | awk '{print $2}')
for ip in ${current_ips_full}; do
if is_valid_ipv4 "${ip}" && ip_in_cidrs "${ip}" "${CIDR_LIST[*]}"; then
current_valid_ips+=("${ip}")
next_tags+=("${ip}")
fi
done
# Skip if no ip change
if [[ "$(echo "${last_tagged_ips[@]}" | tr ' ' '\n' | sort -u)" == "$(echo "${current_valid_ips[@]}" | tr ' ' '\n' | sort -u)" ]]; then
echo "Skipping ${vmid} cause ip no changes"
continue
fi
# Set tags
echo "Setting ${vmid} tags from ${current_tags[*]} to ${next_tags[*]}"
pct set "${vmid}" -tags "$(IFS=';'; echo "${next_tags[*]}")"
done
}
check() {
current_time=$(date +%s)
time_since_last_lxc_status_check=$((current_time - last_lxc_status_check_time))
if [[ "${LXC_STATUS_CHECK_INTERVAL}" -gt 0 ]] \
&& [[ "${time_since_last_lxc_status_check}" -ge "${STATUS_CHECK_INTERVAL}" ]]; then
echo "Checking lxc status..."
last_lxc_status_check_time=${current_time}
if lxc_status_changed; then
update_lxc_iptags
last_update_time=${current_time}
return
fi
fi
time_since_last_fw_net_interface_check=$((current_time - last_fw_net_interface_check_time))
if [[ "${FW_NET_INTERFACE_CHECK_INTERVAL}" -gt 0 ]] \
&& [[ "${time_since_last_fw_net_interface_check}" -ge "${FW_NET_INTERFACE_CHECK_INTERVAL}" ]]; then
echo "Checking fw net interface..."
last_fw_net_interface_check_time=${current_time}
if fw_net_interface_changed; then
update_lxc_iptags
last_update_time=${current_time}
return
fi
fi
time_since_last_update=$((current_time - last_update_time))
if [ ${time_since_last_update} -ge ${FORCE_UPDATE_INTERVAL} ]; then
echo "Force updating lxc iptags..."
update_lxc_iptags
last_update_time=${current_time}
return
fi
}
# main: Set the IP tags for all LXC containers
main() {
while true; do
check
sleep "${LOOP_INTERVAL}"
done
}
main
EOF
msg_ok "Setup Main Function"
else
msg_ok "Main Function already exists"
fi
chmod +x /opt/lxc-iptag/iptag
msg_info "Creating Service"
if [[ ! -f /lib/systemd/system/iptag.service ]]; then
cat <<EOF >/lib/systemd/system/iptag.service
[Unit]
Description=LXC IP-Tag service
After=network.target
[Service]
Type=simple
ExecStart=/opt/lxc-iptag/iptag
Restart=always
[Install]
WantedBy=multi-user.target
EOF
msg_ok "Created Service"
else
msg_ok "Service already exists."
fi
msg_ok "Setup IP-Tag Scripts"
msg_info "Starting Service"
systemctl daemon-reload &>/dev/null
systemctl enable -q --now iptag.service &>/dev/null
msg_ok "Started Service"
SPINNER_PID=""
echo -e "\n${APP} installation completed successfully! ${CL}\n"

77
tools/pve/clean-lxcs.sh Normal file
View file

@ -0,0 +1,77 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info() {
clear
cat <<"EOF"
________ __ _ ________
/ ____/ /__ ____ _____ / / | |/ / ____/
/ / / / _ \/ __ `/ __ \ / / | / /
/ /___/ / __/ /_/ / / / / / /___/ / /___
\____/_/\___/\__,_/_/ /_/ /_____/_/|_\____/
EOF
}
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
CM='\xE2\x9C\x94\033'
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
header_info
echo "Loading..."
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Updater" --yesno "This Will Clean logs, cache and update apt lists on selected LXC Containers. Proceed?" 10 58 || exit
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 '"') || exit
function clean_container() {
container=$1
header_info
name=$(pct exec "$container" hostname)
echo -e "${BL}[Info]${GN} Cleaning ${name} ${CL} \n"
pct exec $container -- bash -c "apt-get -y --purge autoremove && apt-get -y autoclean && bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/clean.sh) && rm -rf /var/lib/apt/lists/* && apt-get update"
}
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
else
os=$(pct config "$container" | awk '/^ostype/ {print $2}')
if [ "$os" != "debian" ] && [ "$os" != "ubuntu" ]; then
header_info
echo -e "${BL}[Info]${GN} Skipping ${name} ${RD}$container is not Debian or Ubuntu ${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
clean_container $container
echo -e "${BL}[Info]${GN} Shutting down${BL} $container ${CL} \n"
pct shutdown $container &
elif [ "$status" == "status: running" ]; then
clean_container $container
fi
fi
done
wait
header_info
echo -e "${GN} Finished, Selected Containers Cleaned. ${CL} \n"

View file

@ -0,0 +1,75 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
____ ________ ____ __ __ __ _ ____ ___
/ __ \_________ _ ______ ___ ____ _ __ / ____/ /__ ____ _____ / __ \_________ / /_ ____ _____ ___ ____/ / / /| | / / |/ /____
/ /_/ / ___/ __ \| |/_/ __ `__ \/ __ \| |/_/ / / / / _ \/ __ `/ __ \ / / / / ___/ __ \/ __ \/ __ `/ __ \/ _ \/ __ / / / | | / / /|_/ / ___/
/ ____/ / / /_/ /> </ / / / / / /_/ /> < / /___/ / __/ /_/ / / / / / /_/ / / / /_/ / / / / /_/ / / / / __/ /_/ / / /__| |/ / / / (__ )
/_/ /_/ \____/_/|_/_/ /_/ /_/\____/_/|_| \____/_/\___/\__,_/_/ /_/ \____/_/ / .___/_/ /_/\__,_/_/ /_/\___/\__,_/ /_____/___/_/ /_/____/
/_/
EOF
}
# 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; do
# Exclude system-critical LVs and Ceph OSDs
if [[ "$lv" == "data" || "$lv" == "root" || "$lv" == "swap" || "$lv" =~ ^osd-block- ]]; then
continue
fi
container_id=$(echo "$lv" | grep -oE "[0-9]+" | head -1)
# Check if the ID exists as a VM or LXC container
if [ -f "/etc/pve/lxc/${container_id}.conf" ] || [ -f "/etc/pve/qemu-server/${container_id}.conf" ]; then
continue
fi
orphaned_volumes+=("$lv" "$vg" "$size")
done < <(lvs --noheadings -o lv_name,vg_name,lv_size --separator ' ' | awk '{print $1, $2, $3}')
# 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"

47
tools/pve/clean.sh Normal file
View file

@ -0,0 +1,47 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info() {
clear
cat <<"EOF"
________ __ _ ________
/ ____/ /__ ____ _____ / / | |/ / ____/
/ / / / _ \/ __ `/ __ \ / / | / /
/ /___/ / __/ /_/ / / / / / /___/ / /___
\____/_/\___/\__,_/_/ /_/ /_____/_/|_\____/
EOF
}
BL=$(echo "\033[36m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
name=$(hostname)
header_info
echo -e "${BL}[Info]${GN} Cleaning $name${CL} \n"
cache=$(find /var/cache/ -type f)
if [[ -z "$cache" ]]; then
echo -e "It appears there are no cached files on your system. \n"
sleep 2
else
find /var/cache -type f -delete
echo "Successfully Removed Cache"
sleep 2
fi
header_info
echo -e "${BL}[Info]${GN} Cleaning $name${CL} \n"
logs=$(find /var/log/ -type f)
if [[ -z "$logs" ]]; then
echo -e "It appears there are no logs on your system. \n"
sleep 2
else
find /var/log -type f -delete
echo "Successfully Removed Logs"
sleep 2
fi
header_info
echo -e "${BL}[Info]${GN} Cleaning $name${CL} \n"
echo -e "${GN}Populating apt lists${CL} \n"

View file

@ -0,0 +1,89 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
clear
if command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Can't Run from the Proxmox Shell"
exit
fi
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")
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
CROSS="${RD}${CL}"
APP="Home Assistant Container"
while true; do
read -p "This will restore ${APP} from a backup. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
clear
function header_info {
cat <<"EOF"
__ __ ___ _ __ __
/ / / /___ ____ ___ ___ / | __________(_)____/ /_____ _____ / /_
/ /_/ / __ \/ __ `__ \/ _ \ / /| | / ___/ ___/ / ___/ __/ __ `/ __ \/ __/
/ __ / /_/ / / / / / / __/ / ___ |(__ |__ ) (__ ) /_/ /_/ / / / / /_
/_/ /_/\____/_/ /_/ /_/\___/ /_/ |_/____/____/_/____/\__/\__,_/_/ /_/\__/
RESTORE FROM BACKUP
EOF
}
header_info
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}"
}
if [ -z "$(ls -A /var/lib/docker/volumes/hass_config/_data/backups/)" ]; then
msg_error "No backups found! \n"
exit 1
fi
DIR=/var/lib/docker/volumes/hass_config/_data/restore
if [ -d "$DIR" ]; then
msg_ok "Restore Directory Exists."
else
mkdir -p /var/lib/docker/volumes/hass_config/_data/restore
msg_ok "Created Restore Directory."
fi
cd /var/lib/docker/volumes/hass_config/_data/backups/
PS3="Please enter your choice: "
files="$(ls -A .)"
select filename in ${files}; do
msg_ok "You selected ${BL}${filename}${CL}"
break
done
msg_info "Stopping Home Assistant"
docker stop homeassistant &>/dev/null
msg_ok "Stopped Home Assistant"
msg_info "Restoring Home Assistant using ${filename}"
tar xvf ${filename} -C /var/lib/docker/volumes/hass_config/_data/restore &>/dev/null
cd /var/lib/docker/volumes/hass_config/_data/restore
tar -xvf homeassistant.tar.gz &>/dev/null
if ! command -v rsync >/dev/null 2>&1; then apt-get install -y rsync &>/dev/null; fi
rsync -a /var/lib/docker/volumes/hass_config/_data/restore/data/ /var/lib/docker/volumes/hass_config/_data
rm -rf /var/lib/docker/volumes/hass_config/_data/restore/*
msg_ok "Restore Complete"
msg_ok "Starting Home Assistant \n"
docker start homeassistant

View file

@ -0,0 +1,89 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
clear
if command -v pveversion >/dev/null 2>&1; then
echo -e "⚠️ Can't Run from the Proxmox Shell"
exit
fi
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")
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
CROSS="${RD}${CL}"
APP="Home Assistant Core"
while true; do
read -p "This will restore ${APP} from a backup. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
clear
function header_info {
cat <<"EOF"
__ __ ___ _ __ __ ______
/ / / /___ ____ ___ ___ / | __________(_)____/ /_____ _____ / /_ / ____/___ ________
/ /_/ / __ \/ __ `__ \/ _ \ / /| | / ___/ ___/ / ___/ __/ __ `/ __ \/ __/ / / / __ \/ ___/ _ \
/ __ / /_/ / / / / / / __/ / ___ |(__ |__ ) (__ ) /_/ /_/ / / / / /_ / /___/ /_/ / / / __/
/_/ /_/\____/_/ /_/ /_/\___/ /_/ |_/____/____/_/____/\__/\__,_/_/ /_/\__/ \____/\____/_/ \___/
RESTORE FROM BACKUP
EOF
}
header_info
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}"
}
if [ -z "$(ls -A /root/.homeassistant/backups/)" ]; then
msg_error "No backups found! \n"
exit 1
fi
DIR=/root/.homeassistant/restore
if [ -d "$DIR" ]; then
msg_ok "Restore Directory Exists."
else
mkdir -p /root/.homeassistant/restore
msg_ok "Created Restore Directory."
fi
cd /root/.homeassistant/backups/
PS3="Please enter your choice: "
files="$(ls -A .)"
select filename in ${files}; do
msg_ok "You selected ${BL}${filename}${CL}"
break
done
msg_info "Stopping Home Assistant"
sudo service homeassistant stop
msg_ok "Stopped Home Assistant"
msg_info "Restoring Home Assistant using ${filename}"
tar xvf ${filename} -C /root/.homeassistant/restore &>/dev/null
cd /root/.homeassistant/restore
tar -xvf homeassistant.tar.gz &>/dev/null
if ! command -v rsync >/dev/null 2>&1; then apt-get install -y rsync &>/dev/null; fi
rsync -a /root/.homeassistant/restore/data/ /root/.homeassistant
rm -rf /root/.homeassistant/restore/*
msg_ok "Restore Complete"
msg_ok "Starting Home Assistant \n"
sudo service homeassistant start

View file

@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/cron-update-lxcs.sh)"
clear
cat <<"EOF"
______ __ __ __ __ __ _ ________
/ ____/________ ____ / / / /___ ____/ /___ _/ /____ / / | |/ / ____/____
/ / / ___/ __ \/ __ \ / / / / __ \/ __ / __ `/ __/ _ \ / / | / / / ___/
/ /___/ / / /_/ / / / / / /_/ / /_/ / /_/ / /_/ / /_/ __/ / /___/ / /___(__ )
\____/_/ \____/_/ /_/ \____/ .___/\__,_/\__,_/\__/\___/ /_____/_/|_\____/____/
/_/
EOF
add() {
while true; do
read -p "This script will add a crontab schedule that updates all LXCs every Sunday at midnight. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
sh -c '(crontab -l -u root 2>/dev/null; echo "0 0 * * 0 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/update-lxcs-cron.sh)\" >>/var/log/update-lxcs-cron.log 2>/dev/null") | crontab -u root -'
clear
echo -e "\n To view Cron Update LXCs logs: cat /var/log/update-lxcs-cron.log"
}
remove() {
(crontab -l | grep -v "github.com/community-scripts/ProxmoxVE/raw/main/misc/update-lxcs-cron.sh") | crontab -
rm -rf /var/log/update-lxcs-cron.log
echo "Removed Crontab Schedule from Proxmox VE"
}
OPTIONS=(Add "Add Crontab Schedule"
Remove "Remove Crontab Schedule")
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Cron Update LXCs" --menu "Select an option:" 10 58 2 \
"${OPTIONS[@]}" 3>&1 1>&2 2>&3)
case $CHOICE in
"Add")
add
;;
"Remove")
remove
;;
*)
echo "Exiting..."
exit 0
;;
esac

View file

@ -0,0 +1,93 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
____ _ __ ____ __
/ __/___(_)__ ____ _/ /____ / __/_ _____ ___ ___ ____/ /_
/ _// __/ / _ `/ _ `/ __/ -_) _\ \/ // / _ \/ _ \/ _ \/ __/ __/
/_/ /_/ /_/\_, /\_,_/\__/\__/ /___/\_,_/ .__/ .__/\___/_/ \__/
/___/ /_/ /_/
EOF
}
header_info
while true; do
read -p "This will Prepare a LXC Container for Frigate. Proceed (y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
header_info
# The array of device types
# CHAR_DEVS+=(major:minor)
CHAR_DEVS+=("1:1") # mem
CHAR_DEVS+=("29:0") # fb0
CHAR_DEVS+=("188:.*") # ttyUSB*
CHAR_DEVS+=("189:.*") # bus/usb/*
CHAR_DEVS+=("226:0") # card0
CHAR_DEVS+=("226:128") # renderD128
# Proccess char device string
for char_dev in ${CHAR_DEVS[@]}; do
[ ! -z "${CHAR_DEV_STRING-}" ] && CHAR_DEV_STRING+=" -o"
CHAR_DEV_STRING+=" -regex \".*/${char_dev}\""
done
# Store autodev hook script in a variable
read -r -d '' HOOK_SCRIPT <<-EOF || true
for char_dev in \$(find /sys/dev/char -regextype sed $CHAR_DEV_STRING); do
dev="/dev/\$(sed -n "/DEVNAME/ s/^.*=\(.*\)$/\1/p" \${char_dev}/uevent)";
mkdir -p \$(dirname \${LXC_ROOTFS_MOUNT}\${dev});
for link in \$(udevadm info --query=property \$dev | sed -n "s/DEVLINKS=//p"); do
mkdir -p \${LXC_ROOTFS_MOUNT}\$(dirname \$link);
cp -dpR \$link \${LXC_ROOTFS_MOUNT}\${link};
done;
cp -dpR \$dev \${LXC_ROOTFS_MOUNT}\${dev};
done;
EOF
# Remove newline char from the variable
HOOK_SCRIPT=${HOOK_SCRIPT//$'\n'/}
# Generate menu of LXC containers in current node
NODE=$(hostname)
while read -r line; do
TAG=$(echo "$line" | awk '{print $1}')
ITEM=$(echo "$line" | awk '{print substr($0,36)}')
OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
CTID_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
# Selection menu for LXC containers
while [ -z "${CTID:+x}" ]; do
CTID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Containers on $NODE" --radiolist \
"\nSelect a container to add support:\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${CTID_MENU[@]}" 3>&1 1>&2 2>&3) || exit
done
# Add autodev settings
CTID_CONFIG_PATH=/etc/pve/lxc/${CTID}.conf
sed '/autodev/d' $CTID_CONFIG_PATH >CTID.conf
cat CTID.conf >$CTID_CONFIG_PATH
cat <<EOF >>$CTID_CONFIG_PATH
lxc.autodev: 1
lxc.hook.autodev: bash -c '$HOOK_SCRIPT'
EOF
echo -e "\e[1;33m \nFinished....Reboot ${CTID} LXC to apply the changes.\n \e[0m"
# In the Proxmox web shell run
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/frigate-support.sh)"
# Reboot the LXC to apply the changes

97
tools/pve/fstrim.sh Normal file
View file

@ -0,0 +1,97 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
set -o pipefail
function header_info() {
clear
cat <<"EOF"
_______ __ __ ______ _
/ ____(_) /__ _______ _______/ /____ ____ ___ /_ __/____(_)___ ___
/ /_ / / / _ \/ ___/ / / / ___/ __/ _ \/ __ `__ \ / / / ___/ / __ `__ \
/ __/ / / / __(__ ) /_/ (__ ) /_/ __/ / / / / / / / / / / / / / / / /
/_/ /_/_/\___/____/\__, /____/\__/\___/_/ /_/ /_/ /_/ /_/ /_/_/ /_/ /_/
/____/
EOF
}
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
CM='\xE2\x9C\x94\033'
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
header_info
echo "Loading..."
ROOT_FS=$(df -Th "/" | awk 'NR==2 {print $2}')
if [ "$ROOT_FS" != "ext4" ]; then
echo "Root filesystem is not ext4. Exiting script."
exit 1
fi
whiptail --backtitle "Proxmox VE Helper Scripts" \
--title "Proxmox VE LXC Filesystem Trim" \
--yesno "The LXC containers will undergo the fstrim command. Proceed?" 10 58 || exit
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_raw=$(whiptail --backtitle "Proxmox VE Helper Scripts" \
--title "Containers on $NODE" \
--checklist "\nSelect containers to skip from trimming:\n" \
16 $((MSG_MAX_LENGTH + 23)) 6 "${EXCLUDE_MENU[@]}" 3>&1 1>&2 2>&3)
if [ $? -ne 0 ]; then
exit
fi
excluded_containers=$(echo "$excluded_containers_raw" | tr -d '"')
function trim_container() {
local container=$1
header_info
echo -e "${BL}[Info]${GN} Trimming ${BL}$container${CL} \n"
local before_trim
before_trim=$(lvs | awk -F '[[:space:]]+' 'NR>1 && (/Data%|'"vm-$container"'/) {gsub(/%/, "", $7); print $7}')
echo -e "${RD}Data before trim $before_trim%${CL}"
pct fstrim "$container"
local after_trim
after_trim=$(lvs | awk -F '[[:space:]]+' 'NR>1 && (/Data%|'"vm-$container"'/) {gsub(/%/, "", $7); print $7}')
echo -e "${GN}Data after trim $after_trim%${CL}"
sleep 1.5
}
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
else
template=$(pct config "$container" | grep -q "template:" && echo "true" || echo "false")
if [ "$template" == "true" ]; then
header_info
echo -e "${BL}[Info]${GN} Skipping ${container} ${RD}$container is a template ${CL} \n"
sleep 1
continue
fi
trim_container "$container"
fi
done
wait
header_info
echo -e "${GN}Finished, LXC Containers Trimmed.${CL} \n"

79
tools/pve/host-backup.sh Normal file
View file

@ -0,0 +1,79 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
__ __ __ ___ __
/ // /__ ___ / /_ / _ )___ _____/ /____ _____
/ _ / _ \(_-</ __/ / _ / _ `/ __/ '_/ // / _ \
/_//_/\___/___/\__/ /____/\_,_/\__/_/\_\\_,_/ .__/
/_/
EOF
}
# 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=()
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
selected_directories+=("${DIR}$selected_dir")
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_%d).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

View file

@ -0,0 +1,116 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Execute within the Proxmox shell
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/hw-acceleration.sh)"
set -e
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}"
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}"
}
if ! pveversion | grep -Eq "pve-manager/(8\.[1-3])"; then
msg_error "This version of Proxmox Virtual Environment is not supported"
echo -e "Requires PVE Version 8.1 or higher"
echo -e "Exiting..."
sleep 2
exit
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Add Intel HW Acceleration" --yesno "This Will Add Intel HW Acceleration to an existing LXC Container. Proceed?" 8 72 || exit
NODE=$(hostname)
PREV_MENU=()
MSG_MAX_LENGTH=0
privileged_containers=$(pct list | awk 'NR>1 && system("grep -q \047unprivileged: 1\047 /etc/pve/lxc/" $1 ".conf")')
if [ -z "$privileged_containers" ]; then
whiptail --msgbox "No Privileged Containers Found." 10 58
exit
fi
while read -r TAG ITEM; do
OFFSET=2
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=${#ITEM}+OFFSET
PREV_MENU+=("$TAG" "$ITEM " "OFF")
done < <(echo "$privileged_containers")
privileged_container=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Privileged Containers on $NODE" --checklist "\nSelect a Container To Add Intel HW Acceleration:\n" 16 $((MSG_MAX_LENGTH + 23)) 6 "${PREV_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"') || exit
header_info
read -r -p "Verbose mode? <y/N> " prompt
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
STD=""
else
STD="silent"
fi
header_info
cat <<EOF >>/etc/pve/lxc/${privileged_container}.conf
lxc.cgroup2.devices.allow: c 226:0 rwm
lxc.cgroup2.devices.allow: c 226:128 rwm
lxc.cgroup2.devices.allow: c 29:0 rwm
lxc.mount.entry: /dev/fb0 dev/fb0 none bind,optional,create=file
lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir
lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file
EOF
read -r -p "Do you need the intel-media-va-driver-non-free driver (Debian 12 only)? <y/N> " prompt
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
header_info
msg_info "Installing Hardware Acceleration (non-free)"
pct exec ${privileged_container} -- bash -c "cat <<EOF >/etc/apt/sources.list.d/non-free.list
deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb http://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
EOF"
pct exec ${privileged_container} -- bash -c "silent() { \"\$@\" >/dev/null 2>&1; } && $STD apt-get update && $STD apt-get install -y intel-media-va-driver-non-free ocl-icd-libopencl1 intel-opencl-icd vainfo intel-gpu-tools && $STD adduser \$(id -u -n) video && $STD adduser \$(id -u -n) render"
msg_ok "Installed Hardware Acceleration (non-free)"
else
header_info
msg_info "Installing Hardware Acceleration"
pct exec ${privileged_container} -- bash -c "silent() { \"\$@\" >/dev/null 2>&1; } && $STD apt-get install -y va-driver-all ocl-icd-libopencl1 intel-opencl-icd vainfo intel-gpu-tools && chgrp video /dev/dri && chmod 755 /dev/dri && $STD adduser \$(id -u -n) video && $STD adduser \$(id -u -n) render"
msg_ok "Installed Hardware Acceleration"
fi
sleep 1
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "Added tools" "vainfo, execute command 'vainfo'\nintel-gpu-tools, execute command 'intel_gpu_top'" 8 58
msg_ok "Completed Successfully!\n"
echo -e "Reboot container ${BL}$privileged_container${CL} to apply the new settings\n"

80
tools/pve/kernel-clean.sh Normal file
View file

@ -0,0 +1,80 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 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"
# Detect current kernel
current_kernel=$(uname -r)
available_kernels=$(dpkg --list | grep 'kernel-.*-pve' | awk '{print $2}' | 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 "${YW}Available kernels for removal:${CL}"
echo "$available_kernels" | nl -w 2 -s '. '
echo -e "\n${YW}Select kernels to remove (comma-separated, e.g., 1,2):${CL}"
read -r selected
# Parse selection
IFS=',' read -r -a selected_indices <<<"$selected"
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 1
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 1
fi
# Remove kernels
for kernel in "${kernels_to_remove[@]}"; do
echo -e "${YW}Removing $kernel...${CL}"
if apt-get purge -y "$kernel" >/dev/null 2>&1; then
echo -e "${GN}Successfully removed: $kernel${CL}"
else
echo -e "${RD}Failed to remove: $kernel. 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}"

70
tools/pve/kernel-pin.sh Normal file
View file

@ -0,0 +1,70 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
__ __ __ ____ _
/ //_/__ _________ ___ / / / __ \(_)___
/ ,< / _ \/ ___/ __ \/ _ \/ / / /_/ / / __ \
/ /| / __/ / / / / / __/ / / ____/ / / / /
/_/ |_\___/_/ /_/ /_/\___/_/ /_/ /_/_/ /_/
EOF
}
YW=$(echo "\033[33m")
RD=$(echo "\033[01;31m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
current_kernel=$(uname -r)
available_kernels=$(dpkg --list | grep 'kernel-.*-pve' | awk '{print substr($2, 16, length($2)-22)}')
header_info
function msg_info() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
function msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE Kernel Pin" --yesno "This will Pin/Unpin Kernel Images, Proceed?" 10 68 || exit
KERNEL_MENU=()
MSG_MAX_LENGTH=0
while read -r TAG ITEM; do
OFFSET=2
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=${#ITEM}+OFFSET
KERNEL_MENU+=("$TAG" "$ITEM " "OFF")
done < <(echo "$available_kernels")
pin_kernel=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Current Kernel $current_kernel" --radiolist "\nSelect Kernel to pin:\nCancel to Unpin any Kernel" 16 $((MSG_MAX_LENGTH + 58)) 6 "${KERNEL_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"') || exit
[ -z "$pin_kernel" ] && {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Kernel Selected" --msgbox "It appears that no Kernel was selected\nUnpinning any pinned Kernel" 10 68
msg_info "Unpinning any Kernel"
proxmox-boot-tool kernel unpin &>/dev/null
msg_ok "Unpinned any Kernel\n"
proxmox-boot-tool kernel list
echo ""
msg_ok "Finished\n"
echo -e "${RD} REBOOT${CL}"
exit
}
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE Kernel Pin" --yesno "Would you like to pin the $pin_kernel Kernel?" 10 68 || exit
msg_info "Pinning $pin_kernel"
proxmox-boot-tool kernel pin $pin_kernel &>/dev/null
msg_ok "Successfully Pinned $pin_kernel\n"
proxmox-boot-tool kernel list
echo ""
msg_ok "Finished\n"
echo -e "${RD} REBOOT${CL}"

110
tools/pve/lxc-delete.sh Normal file
View file

@ -0,0 +1,110 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
____ __ _ ________ ____ __ __
/ __ \_________ _ ______ ___ ____ _ __ / / | |/ / ____/ / __ \___ / /__ / /____
/ /_/ / ___/ __ \| |/_/ __ `__ \/ __ \| |/_/ / / | / / / / / / _ \/ / _ \/ __/ _ \
/ ____/ / / /_/ /> </ / / / / / /_/ /> < / /___/ / /___ / /_/ / __/ / __/ /_/ __/
/_/ /_/ \____/_/|_/_/ /_/ /_/\____/_/|_| /_____/_/|_\____/ /_____/\___/_/\___/\__/\___/
EOF
}
spinner() {
local pid=$1
local delay=0.1
local spinstr='|/-\'
while ps -p $pid >/dev/null; do
printf " [%c] " "$spinstr"
spinstr=${spinstr#?}${spinstr%"${spinstr#?}"}
sleep $delay
printf "\r"
done
printf " \r"
}
set -eEuo pipefail
YW=$(echo "\033[33m")
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
TAB=" "
CM="${TAB}✔️${TAB}${CL}"
header_info
echo "Loading..."
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Deletion" --yesno "This will delete LXC containers. Proceed?" 10 58 || exit
NODE=$(hostname)
containers=$(pct list | tail -n +2 | awk '{print $0 " " $4}')
if [ -z "$containers" ]; then
whiptail --title "LXC Container Delete" --msgbox "No LXC containers available!" 10 60
exit 1
fi
menu_items=()
FORMAT="%-10s %-15s %-10s"
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")
menu_items+=("$container_id" "$formatted_line" "OFF")
done <<<"$containers"
CHOICES=$(whiptail --title "LXC Container Delete" \
--checklist "Select LXC containers to delete:" 25 60 13 \
"${menu_items[@]}" 3>&2 2>&1 1>&3)
if [ -z "$CHOICES" ]; then
whiptail --title "LXC Container Delete" \
--msgbox "No containers selected!" 10 60
exit 1
fi
read -p "Delete containers manually or automatically? (Default: manual) m/a: " DELETE_MODE
DELETE_MODE=${DELETE_MODE:-m}
selected_ids=$(echo "$CHOICES" | tr -d '"' | tr -s ' ' '\n')
for container_id in $selected_ids; do
status=$(pct status $container_id)
if [ "$status" == "status: running" ]; then
echo -e "${BL}[Info]${GN} Stopping container $container_id...${CL}"
pct stop $container_id &
sleep 5
echo -e "${BL}[Info]${GN} Container $container_id stopped.${CL}"
fi
if [[ "$DELETE_MODE" == "a" ]]; then
echo -e "${BL}[Info]${GN} Automatically deleting container $container_id...${CL}"
pct destroy "$container_id" -f &
pid=$!
spinner $pid
[ $? -eq 0 ] && echo "Container $container_id deleted." || whiptail --title "Error" --msgbox "Failed to delete container $container_id." 10 60
else
read -p "Delete container $container_id? (y/N): " CONFIRM
if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
echo -e "${BL}[Info]${GN} Deleting container $container_id...${CL}"
pct destroy "$container_id" -f &
pid=$!
spinner $pid
[ $? -eq 0 ] && echo "Container $container_id deleted." || whiptail --title "Error" --msgbox "Failed to delete container $container_id." 10 60
else
echo -e "${BL}[Info]${RD} Skipping container $container_id...${CL}"
fi
fi
done
header_info
echo -e "${GN}Deletion process completed.${CL}\n"

153
tools/pve/microcode.sh Normal file
View file

@ -0,0 +1,153 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function 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}"
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}"; }
header_info
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 VE Helper Scripts" --title "No Microcode Found" --msgbox "It appears there were no microcode packages found\n Try 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 VE 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 '"') || exit
[ -z "$microcode" ] && {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Microcode Selected" --msgbox "It appears that no microcode packages were selected" 10 68
msg_info "Exiting"
sleep 1
msg_ok "Done"
exit
}
msg_info "Downloading the 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 the Intel Processor Microcode Package $microcode"
msg_info "Installing $microcode (Patience)"
dpkg -i $microcode &>/dev/null
msg_ok "Installed $microcode"
msg_info "Cleaning up"
rm $microcode
msg_ok "Cleaned"
echo -e "\nIn order to apply the changes, a system reboot will be necessary.\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 VE Helper Scripts" --title "No Microcode Found" --msgbox "It appears there were no microcode packages found\n Try 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 VE 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 '"') || exit
[ -z "$microcode" ] && {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Microcode Selected" --msgbox "It appears that no microcode packages were selected" 10 68
msg_info "Exiting"
sleep 1
msg_ok "Done"
exit
}
msg_info "Downloading the 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 the AMD Processor Microcode Package $microcode"
msg_info "Installing $microcode (Patience)"
dpkg -i $microcode &>/dev/null
msg_ok "Installed $microcode"
msg_info "Cleaning up"
rm $microcode
msg_ok "Cleaned"
echo -e "\nIn order to apply the changes, a system reboot will be necessary.\n"
}
if ! command -v pveversion >/dev/null 2>&1; then
header_info
msg_error "No PVE Detected!"
exit
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE Processor Microcode" --yesno "This will check for CPU microcode packages with the option to install. Proceed?" 10 58 || exit
msg_info "Checking CPU Vendor"
cpu=$(lscpu | grep -oP 'Vendor ID:\s*\K\S+' | head -n 1)
if [ "$cpu" == "GenuineIntel" ]; then
msg_ok "${cpu} was detected"
sleep 1
intel
elif [ "$cpu" == "AuthenticAMD" ]; then
msg_ok "${cpu} was detected"
sleep 1
amd
else
msg_error "${cpu} is not supported"
exit
fi

163
tools/pve/monitor-all.sh Normal file
View file

@ -0,0 +1,163 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
clear
cat <<"EOF"
__ ___ _ __ ___ ____
/ |/ /___ ____ (_) /_____ _____ / | / / /
/ /|_/ / __ \/ __ \/ / __/ __ \/ ___/ / /| | / / /
/ / / / /_/ / / / / / /_/ /_/ / / / ___ |/ / /
/_/ /_/\____/_/ /_/_/\__/\____/_/ /_/ |_/_/_/
EOF
add() {
while true; do
read -p "This script will add Monitor All to Proxmox VE. Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
echo '#!/usr/bin/env bash
# Read excluded instances from command line arguments
excluded_instances=("$@")
echo "Excluded instances: ${excluded_instances[@]}"
while true; do
for instance in $(pct list | awk '\''{if(NR>1) print $1}'\''; qm list | awk '\''{if(NR>1) print $1}'\''); do
# Skip excluded instances
if [[ " ${excluded_instances[@]} " =~ " ${instance} " ]]; then
echo "Skipping $instance because it is excluded"
continue
fi
# Determine the type of the instance (container or virtual machine)
if pct status $instance >/dev/null 2>&1; then
# It is a container
config_cmd="pct config"
IP=$(pct exec $instance ip a s dev eth0 | awk '\''/inet / {print $2}'\'' | cut -d/ -f1)
else
# It is a virtual machine
config_cmd="qm config"
IP=$(qm guest cmd $instance network-get-interfaces | egrep -o "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -E "192\.|10\." | head -n 1)
fi
# Skip instances based on onboot and templates
onboot=$($config_cmd $instance | grep -q "onboot: 0" || ( ! $config_cmd $instance | grep -q "onboot" ) && echo "true" || echo "false")
template=$($config_cmd $instance | grep template | grep -q "template:" && echo "true" || echo "false")
if [ "$onboot" == "true" ]; then
echo "Skipping $instance because it is set not to boot"
continue
elif [ "$template" == "true" ]; then
echo "Skipping $instance because it is a template"
continue
fi
# Ping the instance
if ! ping -c 1 $IP >/dev/null 2>&1; then
# If the instance can not be pinged, stop and start it
if pct status $instance >/dev/null 2>&1; then
# It is a container
echo "$(date): CT $instance is not responding, restarting..."
pct stop $instance >/dev/null 2>&1
sleep 5
pct start $instance >/dev/null 2>&1
else
# It is a virtual machine
if qm status $instance | grep -q "status: running"; then
echo "$(date): VM $instance is not responding, restarting..."
qm stop $instance >/dev/null 2>&1
sleep 5
else
echo "$(date): VM $instance is not running, starting..."
fi
qm start $instance >/dev/null 2>&1
fi
fi
done
# Wait for 5 minutes. (Edit to your needs)
echo "$(date): Pausing for 5 minutes..."
sleep 300
done >/var/log/ping-instances.log 2>&1' >/usr/local/bin/ping-instances.sh
touch /var/log/ping-instances.log
# Change file permissions to executable
chmod +x /usr/local/bin/ping-instances.sh
cat <<EOF >/etc/systemd/system/ping-instances.timer
[Unit]
Description=Delay ping-instances.service by 5 minutes
[Timer]
OnBootSec=300
OnUnitActiveSec=300
[Install]
WantedBy=timers.target
EOF
# Create ping-instances.service
cat <<EOF >/etc/systemd/system/ping-instances.service
[Unit]
Description=Ping instances every 5 minutes and restarts if necessary
After=ping-instances.timer
Requires=ping-instances.timer
[Service]
Type=simple
# To specify which CT/VM should be excluded, add the CT/VM ID at the end of the line where ExecStart=/usr/local/bin/ping-instances.sh is specified.
# For example: ExecStart=/usr/local/bin/ping-instances.sh 100 102
# Virtual machines without the QEMU guest agent installed must be excluded.
ExecStart=/usr/local/bin/ping-instances.sh
Restart=always
StandardOutput=file:/var/log/ping-instances.log
StandardError=file:/var/log/ping-instances.log
[Install]
WantedBy=multi-user.target
EOF
# Reload daemon, enable and start ping-instances.service
systemctl daemon-reload
systemctl enable -q --now ping-instances.timer
systemctl enable -q --now ping-instances.service
clear
echo -e "\n To view Monitor All logs: cat /var/log/ping-instances.log"
}
remove() {
systemctl disable -q --now ping-instances.timer
systemctl disable -q --now ping-instances.service
rm /etc/systemd/system/ping-instances.service /etc/systemd/system/ping-instances.timer /usr/local/bin/ping-instances.sh /var/log/ping-instances.log
echo "Removed Monitor All from Proxmox VE"
}
# Define options for the whiptail menu
OPTIONS=(Add "Add Monitor-All to Proxmox VE"
Remove "Remove Monitor-All from Proxmox VE")
# Show the whiptail menu and save the user's choice
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Monitor-All for Proxmox VE" --menu "Select an option:" 10 58 2 \
"${OPTIONS[@]}" 3>&1 1>&2 2>&3)
# Check the user's choice and perform the corresponding action
case $CHOICE in
"Add")
add
;;
"Remove")
remove
;;
*)
echo "Exiting..."
exit 0
;;
esac

174
tools/pve/pbs3-upgrade.sh Normal file
View file

@ -0,0 +1,174 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# 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() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
msg_error() {
local msg="$1"
echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}"
}
start_routines() {
header_info
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS 2 BACKUP" --menu "\nMake a backup of /etc/proxmox-backup to ensure that in the worst case, any relevant configuration can be recovered?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Backing up Proxmox Backup Server 2"
tar czf "pbs2-etc-backup-$(date -I).tar.gz" -C "/etc" "proxmox-backup"
msg_ok "Backed up Proxmox Backup Server 2"
;;
no)
msg_error "Selected no to Backing up Proxmox Backup Server 2"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS 3 SOURCES" --menu "This will set the correct sources to update and install Proxmox Backup Server 3.\n \nChange to Proxmox Backup Server 3 sources?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Changing to Proxmox Backup Server 3 Sources"
cat <<EOF >/etc/apt/sources.list
deb http://deb.debian.org/debian bookworm main contrib
deb http://deb.debian.org/debian bookworm-updates main contrib
deb http://security.debian.org/debian-security bookworm-security main contrib
EOF
msg_ok "Changed to Proxmox Backup Server 3 Sources"
;;
no)
msg_error "Selected no to Correcting Proxmox Backup Server 3 Sources"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS3-ENTERPRISE" --menu "The 'pbs-enterprise' repository is only available to users who have purchased a Proxmox VE subscription.\n \nDisable 'pbs-enterprise' repository?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Disabling 'pbs-enterprise' repository"
cat <<EOF >/etc/apt/sources.list.d/pbs-enterprise.list
# deb https://enterprise.proxmox.com/debian/pbs bookworm pbs-enterprise
EOF
msg_ok "Disabled 'pbs-enterprise' repository"
;;
no)
msg_error "Selected no to Disabling 'pbs-enterprise' repository"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS3-NO-SUBSCRIPTION" --menu "The 'pbs-no-subscription' repository provides access to all of the open-source components of Proxmox Backup Server.\n \nEnable 'pbs-no-subscription' repository?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Enabling 'pbs-no-subscription' repository"
cat <<EOF >/etc/apt/sources.list.d/pbs-install-repo.list
deb http://download.proxmox.com/debian/pbs bookworm pbs-no-subscription
EOF
msg_ok "Enabled 'pbs-no-subscription' repository"
;;
no)
msg_error "Selected no to Enabling 'pbs-no-subscription' repository"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS3 TEST" --menu "The 'pbstest' repository can give advanced users access to new features and updates before they are officially released.\n \nAdd (Disabled) 'pbstest' repository?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Adding 'pbstest' repository and set disabled"
cat <<EOF >/etc/apt/sources.list.d/pbstest-for-beta.list
# deb http://download.proxmox.com/debian/pbs bookworm pbstest
EOF
msg_ok "Added 'pbstest' repository"
;;
no)
msg_error "Selected no to Adding 'pbstest' repository"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS 3 UPDATE" --menu "\nUpdate to Proxmox Backup Server 3 now?" 11 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Updating to Proxmox Backup Server 3 (Patience)"
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confold" dist-upgrade -y
msg_ok "Updated to Proxmox Backup Server 3"
;;
no)
msg_error "Selected no to Updating to Proxmox Backup Server 3"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "REBOOT" --menu "\nReboot Proxmox Backup Server 3 now? (recommended)" 11 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Rebooting Proxmox Backup Server 3"
sleep 2
msg_ok "Completed Install Routines"
reboot
;;
no)
msg_error "Selected no to Rebooting Proxmox Backup Server 3 (Reboot recommended)"
msg_ok "Completed Install Routines"
;;
esac
}
header_info
while true; do
read -p "Start the Update to Proxmox Backup Server 3 Script (y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*)
clear
exit
;;
*) echo "Please answer yes or no." ;;
esac
done
start_routines

176
tools/pve/pbs_microcode.sh Normal file
View file

@ -0,0 +1,176 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Copyright (c) 2025 DonPablo1010
# Adapted for the Proxmox Backup Server - Baremetal Only
# License: MIT
# This script searches for CPU microcode packages (Intel/AMD) and offers the option to install them.
# A system reboot is required to apply the changes.
# IMPORTANT: This script will only proceed if running on bare metal. If running in a VM, it will exit.
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..."; }
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 1
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 '"') || exit
[ -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 '"') || exit
[ -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 || exit
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

View file

@ -0,0 +1,186 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# 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() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
msg_error() {
local msg="$1"
echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}"
}
start_routines() {
header_info
VERSION="$(awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release)"
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS SOURCES" --menu "This will set the correct sources to update and install Proxmox Backup Server.\n \nChange to Proxmox Backup Server sources?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Changing to Proxmox Backup Server 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 "Changed to Proxmox Backup Server Sources"
;;
no)
msg_error "Selected no to Correcting Proxmox Backup Server Sources"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS-ENTERPRISE" --menu "The 'pbs-enterprise' repository is only available to users who have purchased a Proxmox VE subscription.\n \nDisable 'pbs-enterprise' repository?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Disabling 'pbs-enterprise' repository"
cat <<EOF >/etc/apt/sources.list.d/pbs-enterprise.list
# deb https://enterprise.proxmox.com/debian/pbs ${VERSION} pbs-enterprise
EOF
msg_ok "Disabled 'pbs-enterprise' repository"
;;
no)
msg_error "Selected no to Disabling 'pbs-enterprise' repository"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS-NO-SUBSCRIPTION" --menu "The 'pbs-no-subscription' repository provides access to all of the open-source components of Proxmox Backup Server.\n \nEnable 'pbs-no-subscription' repository?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Enabling 'pbs-no-subscription' repository"
cat <<EOF >/etc/apt/sources.list.d/pbs-install-repo.list
deb http://download.proxmox.com/debian/pbs ${VERSION} pbs-no-subscription
EOF
msg_ok "Enabled 'pbs-no-subscription' repository"
;;
no)
msg_error "Selected no to Enabling 'pbs-no-subscription' repository"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS TEST" --menu "The 'pbstest' repository can give advanced users access to new features and updates before they are officially released.\n \nAdd (Disabled) 'pbstest' repository?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Adding 'pbstest' repository and set disabled"
cat <<EOF >/etc/apt/sources.list.d/pbstest-for-beta.list
# deb http://download.proxmox.com/debian/pbs ${VERSION} pbstest
EOF
msg_ok "Added 'pbstest' repository"
;;
no)
msg_error "Selected no to Adding 'pbstest' repository"
;;
esac
if [[ ! -f /etc/apt/apt.conf.d/no-nag-script ]]; then
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "SUBSCRIPTION NAG" --menu "This will disable the nag message reminding you to purchase a subscription every time you log in to the web interface.\n \nDisable subscription nag?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "Support Subscriptions" "Supporting the software's development team is essential. Check their official website's Support Subscriptions for pricing. Without their dedicated work, we wouldn't have this exceptional software." 10 58
msg_info "Disabling subscription nag"
echo "DPkg::Post-Invoke { \"dpkg -V proxmox-widget-toolkit | grep -q '/proxmoxlib\.js$'; if [ \$? -eq 1 ]; then { echo 'Removing subscription nag from UI...'; 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
apt --reinstall install proxmox-widget-toolkit &>/dev/null
msg_ok "Disabled subscription nag (Delete browser cache)"
;;
no)
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "Support Subscriptions" "Supporting the software's development team is essential. Check their official website's Support Subscriptions for pricing. Without their dedicated work, we wouldn't have this exceptional software." 10 58
msg_error "Selected no to Disabling subscription nag"
;;
esac
fi
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "UPDATE" --menu "\nUpdate 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-get update &>/dev/null
apt-get -y dist-upgrade &>/dev/null
msg_ok "Updated Proxmox Backup Server"
;;
no)
msg_error "Selected no to Updating Proxmox Backup Server"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "REBOOT" --menu "\nReboot Proxmox Backup Server now? (recommended)" 11 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Rebooting Proxmox Backup Server"
sleep 2
msg_ok "Completed Post Install Routines"
reboot
;;
no)
msg_error "Selected no to Rebooting Proxmox Backup Server (Reboot recommended)"
msg_ok "Completed Post Install Routines"
;;
esac
}
header_info
echo -e "\nThis script will Perform Post Install Routines.\n"
while true; do
read -p "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 1
fi
start_routines

View file

@ -0,0 +1,183 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: thost96 (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() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
msg_error() {
local msg="$1"
echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}"
}
start_routines() {
header_info
VERSION="$(awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release)"
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PMG SOURCES" --menu "This will set the correct sources to update and install Proxmox Mail Gateway.\n \nChange to Proxmox Mail Gateway sources?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Changing to Proxmox Mail Gateway 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 "Changed to Proxmox Mail Gateway Sources"
;;
no)
msg_error "Selected no to Correcting Proxmox Mail Gateway Sources"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PMG-ENTERPRISE" --menu "The 'pmg-enterprise' repository is only available to users who have purchased a Proxmox Mail Gateway subscription.\n \nDisable 'pmg-enterprise' repository?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Disabling 'pmg-enterprise' repository"
cat <<EOF >/etc/apt/sources.list.d/pmg-enterprise.list
# deb https://enterprise.proxmox.com/debian/pmg ${VERSION} pmg-enterprise
EOF
msg_ok "Disabled 'pmg-enterprise' repository"
;;
no)
msg_error "Selected no to disabling 'pmg-enterprise' repository"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PMG-NO-SUBSCRIPTION" --menu "The 'pmg-no-subscription' repository provides access to all of the open-source components of Proxmox Mail Gateway.\n \nEnable 'pmg-no-subscription' repository?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Enabling 'pmg-no-subscription' repository"
cat <<EOF >/etc/apt/sources.list.d/pmg-install-repo.list
deb http://download.proxmox.com/debian/pmg ${VERSION} pmg-no-subscription
EOF
msg_ok "Enabled 'pmg-no-subscription' repository"
;;
no)
msg_error "Selected no to enabling 'pmg-no-subscription' repository"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PMG TEST" --menu "The 'pmgtest' repository can give advanced users access to new features and updates before they are officially released.\n \nAdd (Disabled) 'pmgtest' repository?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Adding 'pmgtest' repository and set disabled"
cat <<EOF >/etc/apt/sources.list.d/pmgtest-for-beta.list
# deb http://download.proxmox.com/debian/pmg ${VERSION} pmgtest
EOF
msg_ok "Added 'pmgtest' repository"
;;
no)
msg_error "Selected no to adding 'pmgtest' repository"
;;
esac
if [[ ! -f /etc/apt/apt.conf.d/no-nag-script ]]; then
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "SUBSCRIPTION NAG" --menu "This will disable the nag message reminding you to purchase a subscription every time you log in to the web interface.\n \nDisable subscription nag?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "Support Subscriptions" "Supporting the software's development team is essential. Check their official website's Support Subscriptions for pricing. Without their dedicated work, we wouldn't have this exceptional software." 10 58
msg_info "Disabling subscription nag"
# Normal GUI:
echo "DPkg::Post-Invoke { \"dpkg -V proxmox-widget-toolkit | grep -q '/proxmoxlib\.js$'; if [ \$? -eq 1 ]; then { echo 'Removing subscription nag from UI...'; 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
# JS-Library used when accessing via mobile device browser
echo "DPkg::Post-Invoke { \"dpkg -V pmg-gui | grep -q '/pmgmanagerlib-mobile\.js$'; if [ \$? -eq 1 ]; then { echo 'Removing subscription nag from Mobile UI...'; sed -i '/data\.status.*{/{s/\!//;s/active/NoMoreNagging/}' /usr/share/javascript/pmg-gui/js/pmgmanagerlib-mobile.js; }; fi\"; };" >>/etc/apt/apt.conf.d/no-nag-script
apt --reinstall install proxmox-widget-toolkit pmg-gui &>/dev/null
msg_ok "Disabled subscription nag (Delete browser cache)"
;;
no)
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "Support Subscriptions" "Supporting the software's development team is essential. Check their official website's Support Subscriptions for pricing. Without their dedicated work, we wouldn't have this exceptional software." 10 58
msg_error "Selected no to disabling subscription nag"
;;
esac
fi
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "UPDATE" --menu "\nUpdate Proxmox Mail Gateway now?" 11 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Updating Proxmox Mail Gateway (Patience)"
apt-get update &>/dev/null
apt-get -y dist-upgrade &>/dev/null
msg_ok "Updated Proxmox Mail Gateway"
;;
no)
msg_error "Selected no to updating Proxmox Mail Gateway"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "REBOOT" --menu "\nReboot Proxmox Mail Gateway now? (recommended)" 11 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Rebooting Proxmox Mail Gateway"
sleep 2
msg_ok "Completed Post Install Routines"
reboot
;;
no)
msg_error "Selected no to reboot Proxmox Mail Gateway (Reboot recommended)"
msg_ok "Completed Post Install Routines"
;;
esac
}
header_info
echo -e "\nThis script will Perform Post Install Routines.\n"
while true; do
read -p "Start the Proxmox Mail Gateway Post Install Script (y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*)
clear
exit
;;
*) echo "Please answer yes or no." ;;
esac
done
start_routines

View file

@ -0,0 +1,245 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# 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() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
msg_error() {
local msg="$1"
echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}"
}
start_routines() {
header_info
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "SOURCES" --menu "The package manager will use the correct sources to update and install packages on your Proxmox VE server.\n \nCorrect Proxmox VE sources?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Correcting Proxmox VE Sources"
cat <<EOF >/etc/apt/sources.list
deb http://deb.debian.org/debian bookworm main contrib
deb http://deb.debian.org/debian bookworm-updates main contrib
deb http://security.debian.org/debian-security bookworm-security main contrib
EOF
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' >/etc/apt/apt.conf.d/no-bookworm-firmware.conf
msg_ok "Corrected Proxmox VE Sources"
;;
no)
msg_error "Selected no to Correcting Proxmox VE Sources"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PVE-ENTERPRISE" --menu "The 'pve-enterprise' repository is only available to users who have purchased a Proxmox VE subscription.\n \nDisable 'pve-enterprise' repository?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Disabling 'pve-enterprise' repository"
cat <<EOF >/etc/apt/sources.list.d/pve-enterprise.list
# deb https://enterprise.proxmox.com/debian/pve bookworm pve-enterprise
EOF
msg_ok "Disabled 'pve-enterprise' repository"
;;
no)
msg_error "Selected no to Disabling 'pve-enterprise' repository"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PVE-NO-SUBSCRIPTION" --menu "The 'pve-no-subscription' repository provides access to all of the open-source components of Proxmox VE.\n \nEnable 'pve-no-subscription' repository?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Enabling 'pve-no-subscription' repository"
cat <<EOF >/etc/apt/sources.list.d/pve-install-repo.list
deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription
EOF
msg_ok "Enabled 'pve-no-subscription' repository"
;;
no)
msg_error "Selected no to Enabling 'pve-no-subscription' repository"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CEPH PACKAGE REPOSITORIES" --menu "The 'Ceph Package Repositories' provides access to both the 'no-subscription' and 'enterprise' repositories (initially disabled).\n \nCorrect 'ceph package sources?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Correcting 'ceph package repositories'"
cat <<EOF >/etc/apt/sources.list.d/ceph.list
# deb https://enterprise.proxmox.com/debian/ceph-quincy bookworm enterprise
# deb http://download.proxmox.com/debian/ceph-quincy bookworm no-subscription
# deb https://enterprise.proxmox.com/debian/ceph-reef bookworm enterprise
# deb http://download.proxmox.com/debian/ceph-reef bookworm no-subscription
EOF
msg_ok "Corrected 'ceph package repositories'"
;;
no)
msg_error "Selected no to Correcting 'ceph package repositories'"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PVETEST" --menu "The 'pvetest' repository can give advanced users access to new features and updates before they are officially released.\n \nAdd (Disabled) 'pvetest' repository?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Adding 'pvetest' repository and set disabled"
cat <<EOF >/etc/apt/sources.list.d/pvetest-for-beta.list
# deb http://download.proxmox.com/debian/pve bookworm pvetest
EOF
msg_ok "Added 'pvetest' repository"
;;
no)
msg_error "Selected no to Adding 'pvetest' repository"
;;
esac
if [[ ! -f /etc/apt/apt.conf.d/no-nag-script ]]; then
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "SUBSCRIPTION NAG" --menu "This will disable the nag message reminding you to purchase a subscription every time you log in to the web interface.\n \nDisable subscription nag?" 14 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "Support Subscriptions" "Supporting the software's development team is essential. Check their official website's Support Subscriptions for pricing. Without their dedicated work, we wouldn't have this exceptional software." 10 58
msg_info "Disabling subscription nag"
echo "DPkg::Post-Invoke { \"dpkg -V proxmox-widget-toolkit | grep -q '/proxmoxlib\.js$'; if [ \$? -eq 1 ]; then { echo 'Removing subscription nag from UI...'; 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
apt --reinstall install proxmox-widget-toolkit &>/dev/null
msg_ok "Disabled subscription nag (Delete browser cache)"
;;
no)
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "Support Subscriptions" "Supporting the software's development team is essential. Check their official website's Support Subscriptions for pricing. Without their dedicated work, we wouldn't have this exceptional software." 10 58
msg_error "Selected no to Disabling subscription nag"
;;
esac
fi
if ! systemctl is-active --quiet pve-ha-lrm; then
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "HIGH AVAILABILITY" --menu "Enable high availability?" 10 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Enabling high availability"
systemctl enable -q --now pve-ha-lrm
systemctl enable -q --now pve-ha-crm
systemctl enable -q --now corosync
msg_ok "Enabled high availability"
;;
no)
msg_error "Selected no to Enabling high availability"
;;
esac
fi
if systemctl is-active --quiet pve-ha-lrm; then
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "HIGH AVAILABILITY" --menu "If you plan to utilize a single node instead of a clustered environment, you can disable unnecessary high availability (HA) services, thus reclaiming system resources.\n\nIf HA becomes necessary at a later stage, the services can be re-enabled.\n\nDisable high availability?" 18 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Disabling high availability"
systemctl disable -q --now pve-ha-lrm
systemctl disable -q --now pve-ha-crm
systemctl disable -q --now corosync
msg_ok "Disabled high availability"
;;
no)
msg_error "Selected no to Disabling high availability"
;;
esac
fi
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "UPDATE" --menu "\nUpdate Proxmox VE now?" 11 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Updating Proxmox VE (Patience)"
apt-get update &>/dev/null
apt-get -y dist-upgrade &>/dev/null
msg_ok "Updated Proxmox VE"
;;
no)
msg_error "Selected no to Updating Proxmox VE"
;;
esac
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "REBOOT" --menu "\nReboot Proxmox VE now? (recommended)" 11 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Rebooting Proxmox VE"
sleep 2
msg_ok "Completed Post Install Routines"
reboot
;;
no)
msg_error "Selected no to Rebooting Proxmox VE (Reboot recommended)"
msg_ok "Completed Post Install Routines"
;;
esac
}
header_info
echo -e "\nThis script will Perform Post Install Routines.\n"
while true; do
read -p "Start the Proxmox VE Post Install Script (y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*)
clear
exit
;;
*) echo "Please answer yes or no." ;;
esac
done
if ! pveversion | grep -Eq "pve-manager/8\.[0-3](\.[0-9]+)*"; then
msg_error "This version of Proxmox Virtual Environment is not supported"
echo -e "Requires Proxmox Virtual Environment Version 8.0 or later."
echo -e "Exiting..."
sleep 2
exit
fi
start_routines

139
tools/pve/pve8-upgrade.sh Normal file
View file

@ -0,0 +1,139 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# 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() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
msg_error() {
local msg="$1"
echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}"
}
start_routines() {
header_info
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "PVE8 SOURCES" "This will set the correct sources to update and install Proxmox VE 8." 10 58
msg_info "Changing to Proxmox VE 8 Sources"
cat <<EOF >/etc/apt/sources.list
deb http://ftp.debian.org/debian bookworm main contrib
deb http://ftp.debian.org/debian bookworm-updates main contrib
deb http://security.debian.org/debian-security bookworm-security main contrib
EOF
msg_ok "Changed to Proxmox VE 8 Sources"
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "PVE8-ENTERPRISE" "The 'pve-enterprise' repository is only available to users who have purchased a Proxmox VE subscription." 10 58
msg_info "Disabling 'pve-enterprise' repository"
cat <<EOF >/etc/apt/sources.list.d/pve-enterprise.list
# deb https://enterprise.proxmox.com/debian/pve bookworm pve-enterprise
EOF
msg_ok "Disabled 'pve-enterprise' repository"
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "PVE8-NO-SUBSCRIPTION" "The 'pve-no-subscription' repository provides access to all of the open-source components of Proxmox VE." 10 58
msg_info "Enabling 'pve-no-subscription' repository"
cat <<EOF >/etc/apt/sources.list.d/pve-install-repo.list
deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription
EOF
msg_ok "Enabled 'pve-no-subscription' repository"
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "PVE8 CEPH PACKAGE REPOSITORIES" "The 'Ceph Package Repositories' provides access to both the 'no-subscription' and 'enterprise' repositories." 10 58
msg_info "Enabling 'ceph package repositories'"
cat <<EOF >/etc/apt/sources.list.d/ceph.list
# deb https://enterprise.proxmox.com/debian/ceph-quincy bookworm enterprise
deb http://download.proxmox.com/debian/ceph-quincy bookworm no-subscription
EOF
msg_ok "Enabled 'ceph package repositories'"
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "PVE8 TEST" "The 'pvetest' repository can give advanced users access to new features and updates before they are officially released (Disabled)." 10 58
msg_info "Adding 'pvetest' repository and set disabled"
cat <<EOF >/etc/apt/sources.list.d/pvetest-for-beta.list
# deb http://download.proxmox.com/debian/pve bookworm pvetest
EOF
msg_ok "Added 'pvetest' repository"
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "PVE8 UPDATE" "Updating to Proxmox VE 8" 10 58
msg_info "Updating to Proxmox VE 8 (Patience)"
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confold" dist-upgrade -y
msg_ok "Updated to Proxmox VE 8"
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "REBOOT" --menu "\nReboot Proxmox VE 8 now? (recommended)" 11 58 2 \
"yes" " " \
"no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Rebooting Proxmox VE 8"
sleep 2
msg_ok "Completed Install Routines"
reboot
;;
no)
msg_error "Selected no to Rebooting Proxmox VE 8 (Reboot recommended)"
msg_ok "Completed Install Routines"
;;
esac
}
header_info
while true; do
read -p "Start the Update to Proxmox VE 8 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
header_info
msg_error "\n No PVE Detected!\n"
exit
fi
if ! pveversion | grep -Eq "pve-manager/(7\.4-(16|17|18|19))"; then
header_info
msg_error "This version of Proxmox Virtual Environment is not supported"
echo -e " PVE Version 7.4-16 or higher is required."
echo -e "\nExiting..."
sleep 3
exit
fi
start_routines

View file

@ -0,0 +1,61 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
set -e
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 || exit
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 '"') || exit
[ -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"

View file

@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
echo -e "\n $(date)"
excluded_containers=("$@")
function update_container() {
container=$1
name=$(pct exec "$container" hostname)
echo -e "\n [Info] Updating $container : $name \n"
os=$(pct config "$container" | awk '/^ostype/ {print $2}')
case "$os" in
alpine) pct exec "$container" -- ash -c "apk update && apk upgrade" ;;
archlinux) pct exec "$container" -- bash -c "pacman -Syyu --noconfirm" ;;
fedora | rocky | centos | alma) pct exec "$container" -- bash -c "dnf -y update && dnf -y upgrade" ;;
ubuntu | debian | devuan) pct exec "$container" -- bash -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confold" dist-upgrade -y; rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED" ;;
opensuse) pct exec "$container" -- bash -c "zypper ref && zypper --non-interactive dup" ;;
esac
}
for container in $(pct list | awk '{if(NR>1) print $1}'); do
excluded=false
for excluded_container in "${excluded_containers[@]}"; do
if [ "$container" == "$excluded_container" ]; then
excluded=true
break
fi
done
if [ "$excluded" == true ]; then
echo -e "[Info] Skipping $container"
sleep 1
else
status=$(pct status $container)
template=$(pct config $container | grep -q "template:" && echo "true" || echo "false")
if [ "$template" == "false" ] && [ "$status" == "status: stopped" ]; then
echo -e "[Info] Starting $container"
pct start $container
sleep 5
update_container $container
echo -e "[Info] Shutting down $container"
pct shutdown $container &
elif [ "$status" == "status: running" ]; then
update_container $container
fi
fi
done
wait

112
tools/pve/update-lxcs.sh Normal file
View file

@ -0,0 +1,112 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
function header_info {
clear
cat <<"EOF"
__ __ __ __ __ _ ________
/ / / /___ ____/ /___ _/ /____ / / | |/ / ____/
/ / / / __ \/ __ / __ `/ __/ _ \ / / | / /
/ /_/ / /_/ / /_/ / /_/ / /_/ __/ / /___/ / /___
\____/ .___/\__,_/\__,_/\__/\___/ /_____/_/|_\____/
/_/
EOF
}
set -eEuo pipefail
YW=$(echo "\033[33m")
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
CM='\xE2\x9C\x94\033'
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
header_info
echo "Loading..."
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Updater" --yesno "This Will Update LXC Containers. Proceed?" 10 58 || exit
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 updates:\n" 16 $((MSG_MAX_LENGTH + 23)) 6 "${EXCLUDE_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"') || exit
function needs_reboot() {
local container=$1
local os=$(pct config "$container" | awk '/^ostype/ {print $2}')
local reboot_required_file="/var/run/reboot-required.pkgs"
if [ -f "$reboot_required_file" ]; then
if [[ "$os" == "ubuntu" || "$os" == "debian" ]]; then
if pct exec "$container" -- [ -s "$reboot_required_file" ]; then
return 0
fi
fi
fi
return 1
}
function update_container() {
container=$1
header_info
name=$(pct exec "$container" hostname)
os=$(pct config "$container" | awk '/^ostype/ {print $2}')
if [[ "$os" == "ubuntu" || "$os" == "debian" || "$os" == "fedora" ]]; then
disk_info=$(pct exec "$container" df /boot | awk 'NR==2{gsub("%","",$5); printf "%s %.1fG %.1fG %.1fG", $5, $3/1024/1024, $2/1024/1024, $4/1024/1024 }')
read -ra disk_info_array <<<"$disk_info"
echo -e "${BL}[Info]${GN} Updating ${BL}$container${CL} : ${GN}$name${CL} - ${YW}Boot Disk: ${disk_info_array[0]}% full [${disk_info_array[1]}/${disk_info_array[2]} used, ${disk_info_array[3]} free]${CL}\n"
else
echo -e "${BL}[Info]${GN} Updating ${BL}$container${CL} : ${GN}$name${CL} - ${YW}[No disk info for ${os}]${CL}\n"
fi
case "$os" in
alpine) pct exec "$container" -- ash -c "apk update && apk upgrade" ;;
archlinux) pct exec "$container" -- bash -c "pacman -Syyu --noconfirm" ;;
fedora | rocky | centos | alma) pct exec "$container" -- bash -c "dnf -y update && dnf -y upgrade" ;;
ubuntu | debian | devuan) pct exec "$container" -- bash -c "apt-get update 2>/dev/null | grep 'packages.*upgraded'; apt list --upgradable && apt-get -yq dist-upgrade 2>&1; rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED" ;;
opensuse) pct exec "$container" -- bash -c "zypper ref && zypper --non-interactive dup" ;;
esac
}
containers_needing_reboot=()
header_info
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
else
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
update_container $container
echo -e "${BL}[Info]${GN} Shutting down${BL} $container ${CL} \n"
pct shutdown $container &
elif [ "$status" == "status: running" ]; then
update_container $container
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
fi
done
wait
header_info
echo -e "${GN}The process is complete, and the containers have been successfully updated.${CL}\n"
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
fi
echo ""

65
tools/pve/update-repo.sh Normal file
View file

@ -0,0 +1,65 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 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")
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"

View file

@ -0,0 +1,51 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
echo -e "\e[1;33m This script will allow USB passthrough to a PRIVILEGED LXC Container ONLY\e[0m"
while true; do
read -p "Did you replace 106 with your LXC ID? Proceed(y/n)?" yn
case $yn in
[Yy]*) break ;;
[Nn]*) exit ;;
*) echo "Please answer yes or no." ;;
esac
done
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
CHAR_DEVS+=("166:.*")
CHAR_DEVS+=("188:.*")
CHAR_DEVS+=("189:.*")
for char_dev in ${CHAR_DEVS[@]}; do
[ ! -z "${CHAR_DEV_STRING-}" ] && CHAR_DEV_STRING+=" -o"
CHAR_DEV_STRING+=" -regex \".*/${char_dev}\""
done
read -r -d '' HOOK_SCRIPT <<-EOF || true
for char_dev in \$(find /sys/dev/char -regextype sed $CHAR_DEV_STRING); do
dev="/dev/\$(sed -n "/DEVNAME/ s/^.*=\(.*\)$/\1/p" \${char_dev}/uevent)";
mkdir -p \$(dirname \${LXC_ROOTFS_MOUNT}\${dev});
for link in \$(udevadm info --query=property \$dev | sed -n "s/DEVLINKS=//p"); do
mkdir -p \${LXC_ROOTFS_MOUNT}\$(dirname \$link);
cp -dpR \$link \${LXC_ROOTFS_MOUNT}\${link};
done;
cp -dpR \$dev \${LXC_ROOTFS_MOUNT}\${dev};
done;
EOF
HOOK_SCRIPT=${HOOK_SCRIPT//$'\n'/}
CTID=$1
CTID_CONFIG_PATH=/etc/pve/lxc/${CTID}.conf
sed '/autodev/d' $CTID_CONFIG_PATH >CTID.conf
cat CTID.conf >$CTID_CONFIG_PATH
cat <<EOF >>$CTID_CONFIG_PATH
lxc.autodev: 1
lxc.hook.autodev: bash -c '$HOOK_SCRIPT'
EOF
echo -e "\e[1;33m Finished....Reboot ${CTID} LXC to apply the changes \e[0m"