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}"