472 lines
20 KiB
Bash
472 lines
20 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
set -e
|
|
export NEWT_COLORS='
|
|
root=,black
|
|
window=,black
|
|
border=color127,black
|
|
title=color178,black
|
|
button=white,color127
|
|
actbutton=black,color178
|
|
compactbutton=black,white
|
|
checkbox=color178,black
|
|
actcheckbox=black,color178
|
|
entry=color45,black
|
|
disentry=gray,black
|
|
label=white,black
|
|
listbox=white,black
|
|
actlistbox=black,color45
|
|
sellistbox=color178,black
|
|
actsellistbox=black,color178
|
|
textbox=white,black
|
|
acttextbox=black,white
|
|
scaleline=color127,black
|
|
'
|
|
|
|
BP=$(echo -e "\033[38;5;127m")
|
|
BG=$(echo -e "\033[38;5;178m")
|
|
BB=$(echo -e "\033[38;5;45m")
|
|
BR=$(echo -e "\033[38;5;196m")
|
|
BC=$(echo -e "\033[m")
|
|
BOLD=$(echo -e "\033[1m")
|
|
|
|
TAB=" "
|
|
CM="${TAB}${BG}✅${BC}${TAB}"
|
|
CROSS="${TAB}${BR}❌${BC}${TAB}"
|
|
INFO="${TAB}${BB}💡${BC}${TAB}"
|
|
|
|
# build.func
|
|
WHIPTITLE="Dynasty Revolution Provisioning"
|
|
APP="ARR Stack"
|
|
NSAPP="arr-stack"
|
|
|
|
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
|
trap cleanup EXIT
|
|
|
|
function error_handler() {
|
|
local exit_code="$?"
|
|
local line_number="$1"
|
|
local command="$2"
|
|
echo -e "\n${CROSS}${BR}[ERROR]${BC} Line ${line_number} | Exit: ${exit_code} | Cmd: ${command}\n"
|
|
cleanup_vmid
|
|
}
|
|
|
|
function header_info() {
|
|
clear
|
|
echo -ne "${BP}${BOLD}"
|
|
cat <<"EOF"
|
|
_ ____ ____ ____ _____ _ ____ _ __ __ ____ __
|
|
/ \ | _ \| _ \ / ___|_ _|/ \ / ___| |/ / \ \ / / \/ |
|
|
/ _ \ | |_) | |_) | \___ \ | | / _ \| | | ' / \ \ / /| |\/| |
|
|
/ ___ \| _ <| _ < ___) || |/ ___ \ |___| . \ \ V / | | | |
|
|
/_/ \_\_| \_\_| \_\ |____/ |_/_/ \_\____|_|\_\ \_/ |_| |_|
|
|
|
|
|
|
|
|
Debian 13(Trixie)
|
|
EOF
|
|
echo -e "${BG} DYNASTY PROVISIONING${BC}\n"
|
|
}
|
|
|
|
function fetch_wotd() {
|
|
local wotd_html=$(curl -s --connect-timeout 3 https://www.merriam-webster.com/word-of-the-day)
|
|
local word=$(echo "$wotd_html" | grep -oP '(?<=<title>Word of the Day: ).*?(?= \|)' | head -n1)
|
|
local def=$(echo "$wotd_html" | grep -A 1 "<h2>What It Means</h2>" | tail -n1 | sed 's/<[^>]*>//g' | xargs)
|
|
if [ -n "$word" ]; then
|
|
echo -e "${BG}Word of the Day: ${BB}${word}${BC}"
|
|
echo -e "${TAB}${def}\n"
|
|
fi
|
|
}
|
|
|
|
function cleanup_vmid() {
|
|
if qm status $VMID &>/dev/null; then
|
|
qm stop $VMID &>/dev/null
|
|
qm destroy $VMID &>/dev/null
|
|
fi
|
|
}
|
|
|
|
function cleanup() {
|
|
popd >/dev/null 2>&1 || true
|
|
if [[ -n "$TEMP_DIR" && "$TEMP_DIR" != "/" ]]; then
|
|
rm -rf "$TEMP_DIR"
|
|
fi
|
|
}
|
|
|
|
function get_valid_nextid() {
|
|
local try_id
|
|
try_id=$(pvesh get /cluster/nextid)
|
|
while [ -f "/etc/pve/qemu-server/${try_id}.conf" ] || [ -f "/etc/pve/lxc/${try_id}.conf" ]; do
|
|
try_id=$((try_id + 1))
|
|
done
|
|
echo "$try_id"
|
|
}
|
|
|
|
function remote_provisioning_ui() {
|
|
local title="$WHIPTITLE"
|
|
local prompt="$1"
|
|
local default="$2"
|
|
if command -v osascript &>/dev/null && [[ "$OSTYPE" == "darwin"* ]]; then
|
|
osascript -e "display dialog \"$prompt\" default answer \"$default\" with title \"$title\" buttons {\"Cancel\", \"Next\"} default button \"Next\"" -e "text returned of result" 2>/dev/null
|
|
elif command -v whiptail &>/dev/null; then
|
|
whiptail --backtitle "$title" --title "INPUT" --inputbox "$prompt" 10 58 "$default" 3>&1 1>&2 2>&3
|
|
else
|
|
read -p "$prompt [$default]: " val </dev/tty
|
|
echo "${val:-$default}"
|
|
fi
|
|
}
|
|
|
|
function Beginning_Remote_Provisioning() {
|
|
local target_host=$(remote_provisioning_ui "Enter Proxmox IP/FQDN:" "")
|
|
[ -z "$target_host" ] && exit
|
|
local target_user=$(remote_provisioning_ui "Enter SSH User:" "root")
|
|
[ -z "$target_user" ] && exit
|
|
header_info
|
|
echo -e "${INFO}${BB}Beginning Remote Provisioning to ${target_host}...${BC}"
|
|
}
|
|
|
|
header_info
|
|
|
|
if ! command -v pveversion >/dev/null 2>&1; then
|
|
Beginning_Remote_Provisioning
|
|
exit
|
|
fi
|
|
|
|
if ! command -v virt-customize &>/dev/null; then
|
|
echo -e "${INFO}${BB}Installing Provisioning Tools 🛠️....${BC}"
|
|
apt-get update >/dev/null 2>&1
|
|
apt-get install -y libguestfs-tools >/dev/null 2>&1
|
|
fi
|
|
|
|
if whiptail --backtitle "$WHIPTITLE" --title "ARR STACK DEPLOYMENT" --yesno "Continue Arr Stack VM Deployment?" 10 58; then
|
|
:
|
|
else
|
|
header_info && echo -e "${CROSS}${BR}User exited script.${BC}\n" && exit
|
|
fi
|
|
|
|
CHOICES=$(whiptail --backtitle "$WHIPTITLE" --title "ARR STACK SELECTION" --checklist \
|
|
"Select modules to install:" 20 65 10 \
|
|
"RADARR" "Radarr (7878)" ON \
|
|
"RADARR4K" "Radarr 4K (7879)" OFF \
|
|
"SONARR" "Sonarr (8989)" ON \
|
|
"SONARR4K" "Sonarr 4K (8990)" OFF \
|
|
"QBT" "Qbittorrent (8090)" ON \
|
|
"SABNZBD" "Sabnzbd (7777)" OFF \
|
|
"NZBGET" "NZBGet (6789)" OFF \
|
|
"GLUETUN" "VPN Subsystem" OFF \
|
|
"PORTAINER" "Portainer UI (9443)" ON 3>&1 1>&2 2>&3)
|
|
|
|
INSTALL_METHOD=$(whiptail --backtitle "$WHIPTITLE" --title "INSTALLATION METHOD" --radiolist \
|
|
"Select Installation Method:" 12 58 2 \
|
|
"DOCKER" "Docker Compose (Dynamic)" ON \
|
|
"BINARY" "Native Debian Binaries" OFF 3>&1 1>&2 2>&3)
|
|
|
|
VMID=$(get_valid_nextid)
|
|
DISK_SIZE_NUM="100"
|
|
HN="ARR-Stack"
|
|
CORE_COUNT="6"
|
|
RAM_SIZE="10240"
|
|
BRG="vmbr0"
|
|
VLAN=""
|
|
START_VM="yes"
|
|
CLOUD_INIT="no"
|
|
AUTOLOGIN="no"
|
|
ROOT_PASS=""
|
|
SSH_KEY=""
|
|
|
|
if whiptail --backtitle "$WHIPTITLE" --title "SETTINGS" --yesno "Provisioning with Defaults for ${HN}? (100GB Disk Recommended)" --yes-button "Default" --no-button "Advanced" 10 65; then
|
|
DISK_SIZE_NUM="100"
|
|
BRG=$(whiptail --backtitle "$WHIPTITLE" --inputbox "Network Bridge" 8 58 "vmbr0" --title "BRIDGE" 3>&1 1>&2 2>&3)
|
|
VLAN_ID=$(whiptail --backtitle "$WHIPTITLE" --inputbox "VLAN Tag" 8 58 "" --title "VLAN" 3>&1 1>&2 2>&3)
|
|
[ -n "$VLAN_ID" ] && VLAN=",tag=$VLAN_ID"
|
|
if whiptail --backtitle "$WHIPTITLE" --title "SSH" --yesno "Inject SSH Public Key?" 10 58; then
|
|
SSH_KEY=$(whiptail --backtitle "$WHIPTITLE" --inputbox "Paste Public Key:" 10 58 --title "SSH KEY" 3>&1 1>&2 2>&3)
|
|
fi
|
|
if whiptail --backtitle "$WHIPTITLE" --title "CLOUD-INIT" --yesno "Enable Cloud-Init?" 10 58; then
|
|
CLOUD_INIT="yes"
|
|
else
|
|
if whiptail --backtitle "$WHIPTITLE" --title "AUTO LOGIN" --yesno "Enable Passwordless Auto-login?" 10 58; then
|
|
AUTOLOGIN="yes"
|
|
else
|
|
ROOT_PASS=$(whiptail --backtitle "$WHIPTITLE" --passwordbox "Set Root Password" 8 58 --title "PASSWORD" 3>&1 1>&2 2>&3)
|
|
fi
|
|
fi
|
|
else
|
|
VMID=$(whiptail --backtitle "$WHIPTITLE" --inputbox "Set VM ID" 8 58 "$VMID" --title "VM ID" 3>&1 1>&2 2>&3)
|
|
HN=$(whiptail --backtitle "$WHIPTITLE" --inputbox "Set Hostname" 8 58 "arr-stack" --title "HOSTNAME" 3>&1 1>&2 2>&3)
|
|
CORE_COUNT=$(whiptail --backtitle "$WHIPTITLE" --inputbox "CPU Cores" 8 58 "6" --title "CORES" 3>&1 1>&2 2>&3)
|
|
RAM_SIZE=$(whiptail --backtitle "$WHIPTITLE" --inputbox "RAM MiB" 8 58 "10240" --title "RAM" 3>&1 1>&2 2>&3)
|
|
DISK_SIZE_NUM=$(whiptail --backtitle "$WHIPTITLE" --inputbox "Disk Size GiB" 8 58 "100" --title "DISK" 3>&1 1>&2 2>&3)
|
|
BRG=$(whiptail --backtitle "$WHIPTITLE" --inputbox "Network Bridge" 8 58 "vmbr0" --title "BRIDGE" 3>&1 1>&2 2>&3)
|
|
VLAN_ID=$(whiptail --backtitle "$WHIPTITLE" --inputbox "VLAN Tag" 8 58 "" --title "VLAN" 3>&1 1>&2 2>&3)
|
|
[ -n "$VLAN_ID" ] && VLAN=",tag=$VLAN_ID"
|
|
if whiptail --backtitle "$WHIPTITLE" --title "SSH" --yesno "Inject SSH Public Key?" 10 58; then
|
|
SSH_KEY=$(whiptail --backtitle "$WHIPTITLE" --inputbox "Paste Public Key:" 10 58 --title "SSH KEY" 3>&1 1>&2 2>&3)
|
|
fi
|
|
if whiptail --backtitle "$WHIPTITLE" --title "CLOUD-INIT" --yesno "Enable Cloud-Init?" 10 58; then
|
|
CLOUD_INIT="yes"
|
|
else
|
|
if whiptail --backtitle "$WHIPTITLE" --title "AUTO LOGIN" --yesno "Enable Passwordless Auto-login?" 10 58; then
|
|
AUTOLOGIN="yes"
|
|
else
|
|
ROOT_PASS=$(whiptail --backtitle "$WHIPTITLE" --passwordbox "Set Root Password" 8 58 --title "PASSWORD" 3>&1 1>&2 2>&3)
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
DISK_SIZE="${DISK_SIZE_NUM}G"
|
|
|
|
while true; do
|
|
STORAGE_MENU=()
|
|
while read -r line; do
|
|
TAG=$(echo "$line" | awk '{print $1}')
|
|
TYPE=$(echo "$line" | awk '{printf "%-10s", $2}')
|
|
FREE_HUMAN=$(echo "$line" | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
|
|
STORAGE_MENU+=("$TAG" "Type: $TYPE | Free: $FREE_HUMAN" "OFF")
|
|
done < <(pvesm status -content images | awk 'NR>1')
|
|
STORAGE=$(whiptail --backtitle "$WHIPTITLE" --title "STORAGE" --radiolist "Select storage (Min ${DISK_SIZE} Required):" 16 60 6 "${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3)
|
|
[ -z "$STORAGE" ] && exit 1
|
|
STORAGE_FREE_KB=$(pvesm status -storage "$STORAGE" | awk 'NR==2 {print $6}')
|
|
REQUIRED_KB=$((DISK_SIZE_NUM * 1024 * 1024))
|
|
if [ "$STORAGE_FREE_KB" -lt "$REQUIRED_KB" ]; then
|
|
FREE_GB=$((STORAGE_FREE_KB / 1024 / 1024))
|
|
whiptail --backtitle "$WHIPTITLE" --title "INSUFFICIENT SPACE" --msgbox "Selected storage ($STORAGE) only has ${FREE_GB}GB available.\nDeployment requires ${DISK_SIZE_NUM}GB." 12 58
|
|
else
|
|
break
|
|
fi
|
|
done
|
|
|
|
TEMP_DIR=$(mktemp -d -p /opt)
|
|
pushd "$TEMP_DIR" >/dev/null
|
|
header_info
|
|
echo -e "${INFO}${BB}Loading Provision Method...${BC}"
|
|
|
|
cat <<EOF > dynr-arrstack-setup.sh
|
|
#!/usr/bin/env bash
|
|
apt-get update
|
|
apt-get install -y curl sudo gnupg2 ca-certificates lsb-release sqlite3 jq tar p7zip-full unrar-free mono-devel golang-go openvpn wireguard-tools iptables python3-venv git qemu-guest-agent
|
|
mkdir -p /mnt/arr /opt/DYNR
|
|
touch /opt/DYNR/urls.txt
|
|
cd /opt
|
|
systemctl enable --now qemu-guest-agent
|
|
|
|
if [ "$INSTALL_METHOD" == "DOCKER" ]; then
|
|
curl -fsSL https://get.docker.com | sh
|
|
mkdir -p /opt/Docker
|
|
cat <<DYNR > /opt/Docker/docker-compose.yml
|
|
services:
|
|
DYNR
|
|
|
|
function add_docker_service() {
|
|
local name=\$1
|
|
local image=\$2
|
|
local port=\$3
|
|
local url_port=\${port%%:*}
|
|
mkdir -p /opt/Docker/\$name/config /mnt/arr/\$name/data
|
|
cat <<DYNR >> /opt/Docker/docker-compose.yml
|
|
\$name:
|
|
image: \$image
|
|
container_name: \$name
|
|
environment:
|
|
- PUID=1000
|
|
- PGID=1000
|
|
- TZ=UTC
|
|
volumes:
|
|
- /opt/Docker/\$name/config:/config
|
|
- /mnt/arr/\$name/data:/data
|
|
ports:
|
|
- \$port
|
|
restart: unless-stopped
|
|
DYNR
|
|
echo "\$name: http://localhost:\$url_port" >> /opt/DYNR/urls.txt
|
|
}
|
|
|
|
[[ "$CHOICES" == *"RADARR"* ]] && add_docker_service "radarr" "lscr.io/linuxserver/radarr:latest" "7878:7878"
|
|
[[ "$CHOICES" == *"RADARR4K"* ]] && add_docker_service "radarr4k" "lscr.io/linuxserver/radarr:latest" "7879:7878"
|
|
[[ "$CHOICES" == *"SONARR"* ]] && add_docker_service "sonarr" "lscr.io/linuxserver/sonarr:latest" "8989:8989"
|
|
[[ "$CHOICES" == *"SONARR4K"* ]] && add_docker_service "sonarr4k" "lscr.io/linuxserver/sonarr:latest" "8990:8989"
|
|
[[ "$CHOICES" == *"QBT"* ]] && add_docker_service "qbittorrent" "lscr.io/linuxserver/qbittorrent:latest" "8090:8090"
|
|
[[ "$CHOICES" == *"SABNZBD"* ]] && add_docker_service "sabnzbd" "lscr.io/linuxserver/sabnzbd:latest" "7777:7777"
|
|
[[ "$CHOICES" == *"NZBGET"* ]] && add_docker_service "nzbget" "lscr.io/linuxserver/nzbget:latest" "6789:6789"
|
|
[[ "$CHOICES" == *"GLUETUN"* ]] && add_docker_service "gluetun" "qdm12/gluetun" "8000:8000"
|
|
|
|
if [[ "$CHOICES" == *"PORTAINER"* ]]; then
|
|
docker volume create portainer_data
|
|
docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/var/lib/portainer portainer/portainer-ce:latest
|
|
echo "Portainer: https://localhost:9443" >> /opt/DYNR/urls.txt
|
|
fi
|
|
cd /opt/Docker && docker compose up -d
|
|
else
|
|
# Binary Installation Logic (FULL EXPANSION)
|
|
[[ "$CHOICES" == *"RADARR"* ]] && { mkdir -p /opt/Radarr/config; curl -L "https://radarr.servarr.com/v1/update/master/updatefile?os=linux&runtime=netcore&arch=x64" -o radarr.tar.gz; tar -xzf radarr.tar.gz -C /opt/; cat <<DYNR > /etc/systemd/system/radarr.service
|
|
[Unit]
|
|
Description=Radarr Daemon
|
|
After=network.target
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=/opt/Radarr/Radarr -nobrowser -data=/opt/Radarr/config
|
|
Restart=always
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
DYNR
|
|
systemctl enable --now radarr; echo "Radarr: http://localhost:7878" >> /opt/DYNR/urls.txt; }
|
|
|
|
[[ "$CHOICES" == *"RADARR4K"* ]] && { mkdir -p /opt/Radarr4K/config; curl -L "https://radarr.servarr.com/v1/update/master/updatefile?os=linux&runtime=netcore&arch=x64" -o radarr4k.tar.gz; tar -xzf radarr4k.tar.gz -C /opt/; mv /opt/Radarr /opt/Radarr4K; cat <<DYNR > /etc/systemd/system/radarr4k.service
|
|
[Unit]
|
|
Description=Radarr 4K Daemon
|
|
After=network.target
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=/opt/Radarr4K/Radarr -nobrowser -data=/opt/Radarr4K/config
|
|
Restart=always
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
DYNR
|
|
systemctl enable --now radarr4k; sleep 5; sed -i "s|<Port>7878</Port>|<Port>7879</Port>|g" /opt/Radarr4K/config/config.xml || true; systemctl restart radarr4k; echo "Radarr 4K: http://localhost:7879" >> /opt/DYNR/urls.txt; }
|
|
|
|
[[ "$CHOICES" == *"SONARR"* ]] && { mkdir -p /opt/Sonarr/config; curl -L "https://services.sonarr.tv/v1/update/main/updatefile?os=linux&runtime=netcore&arch=x64" -o sonarr.tar.gz; tar -xzf sonarr.tar.gz -C /opt/; cat <<DYNR > /etc/systemd/system/sonarr.service
|
|
[Unit]
|
|
Description=Sonarr Daemon
|
|
After=network.target
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=/opt/Sonarr/Sonarr -nobrowser -data=/opt/Sonarr/config
|
|
Restart=always
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
DYNR
|
|
systemctl enable --now sonarr; echo "Sonarr: http://localhost:8989" >> /opt/DYNR/urls.txt; }
|
|
|
|
[[ "$CHOICES" == *"SONARR4K"* ]] && { mkdir -p /opt/Sonarr4K/config; curl -L "https://services.sonarr.tv/v1/update/main/updatefile?os=linux&runtime=netcore&arch=x64" -o sonarr4k.tar.gz; tar -xzf sonarr4k.tar.gz -C /opt/; mv /opt/Sonarr /opt/Sonarr4K; cat <<DYNR > /etc/systemd/system/sonarr4k.service
|
|
[Unit]
|
|
Description=Sonarr 4K Daemon
|
|
After=network.target
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=/opt/Sonarr4K/Sonarr -nobrowser -data=/opt/Sonarr4K/config
|
|
Restart=always
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
DYNR
|
|
systemctl enable --now sonarr4k; sleep 5; sed -i "s|<Port>8989</Port>|<Port>8990</Port>|g" /opt/Sonarr4K/config/config.xml || true; systemctl restart sonarr4k; echo "Sonarr 4K: http://localhost:8990" >> /opt/DYNR/urls.txt; }
|
|
|
|
[[ "$CHOICES" == *"QBT"* ]] && { mkdir -p /opt/qbittorrent/config; curl -L "https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/x86_64-qbittorrent-nox" -o /opt/qbittorrent-nox; chmod +x /opt/qbittorrent-nox; mv /opt/qbittorrent-nox /opt/qbittorrent/qbittorrent-nox; cat <<DYNR > /etc/systemd/system/qbittorrent-nox.service
|
|
[Unit]
|
|
Description=qBittorrent client
|
|
After=network.target
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=/opt/qbittorrent/qbittorrent-nox --profile=/opt/qbittorrent/config
|
|
Restart=always
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
DYNR
|
|
systemctl enable --now qbittorrent-nox; echo "Qbittorrent: http://localhost:8090" >> /opt/DYNR/urls.txt; }
|
|
|
|
[[ "$CHOICES" == *"SABNZBD"* ]] && { mkdir -p /opt/sabnzbd/config; cat <<DYNR >/etc/apt/sources.list.d/non-free.sources
|
|
Types: deb
|
|
URIs: http://deb.debian.org/debian/
|
|
Suites: trixie
|
|
Components: non-free
|
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
|
DYNR
|
|
apt update && apt install -y unrar p7zip-full; python3 -m venv /opt/sabnzbd/venv; curl -L "https://github.com/sabnzbd/sabnzbd/releases/latest/download/SABnzbd-src.tar.gz" | tar xz -C /opt/sabnzbd --strip-components=1; /opt/sabnzbd/venv/bin/pip install -r /opt/sabnzbd/requirements.txt; cat <<DYNR > /etc/systemd/system/sabnzbd.service
|
|
[Unit]
|
|
Description=SABnzbd
|
|
After=network.target
|
|
[Service]
|
|
WorkingDirectory=/opt/sabnzbd
|
|
ExecStart=/opt/sabnzbd/venv/bin/python SABnzbd.py -s 0.0.0.0:7777 -f /opt/sabnzbd/config
|
|
Restart=always
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
DYNR
|
|
systemctl enable --now sabnzbd; echo "Sabnzbd: http://localhost:7777" >> /opt/DYNR/urls.txt; }
|
|
|
|
[[ "$CHOICES" == *"NZBGET"* ]] && { mkdir -p /opt/nzbget; curl -fsSL https://nzbgetcom.github.io/nzbgetcom.asc | gpg --dearmor -o /usr/share/keyrings/nzbget.gpg; echo "deb [signed-by=/usr/share/keyrings/nzbget.gpg] https://nzbgetcom.github.io/deb stable main" > /etc/apt/sources.list.d/nzbget.list; apt update && apt install -y nzbget; systemctl enable --now nzbget; echo "NZBGet: http://localhost:6789" >> /opt/DYNR/urls.txt; }
|
|
|
|
[[ "$CHOICES" == *"GLUETUN"* ]] && { mkdir -p /opt/gluetun-data; git clone https://github.com/qdm12/gluetun.git /opt/gluetun; cd /opt/gluetun && CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /usr/local/bin/gluetun ./cmd/gluetun/; cat <<DYNR > /etc/systemd/system/gluetun.service
|
|
[Unit]
|
|
Description=Gluetun VPN Client
|
|
After=network.target
|
|
[Service]
|
|
Type=simple
|
|
WorkingDirectory=/opt/gluetun-data
|
|
ExecStart=/usr/local/bin/gluetun
|
|
Restart=on-failure
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
DYNR
|
|
systemctl enable --now gluetun; echo "Gluetun (Control): http://localhost:8000" >> /opt/DYNR/urls.txt; }
|
|
fi
|
|
EOF
|
|
|
|
URL=https://cloud.debian.org/images/cloud/trixie/latest/debian-13-nocloud-amd64.qcow2
|
|
curl -f#SL -o "debian13.qcow2" "$URL"
|
|
FILE="debian13.qcow2"
|
|
|
|
echo -e "${INFO}${BP}Customizing Disk Metadata...${BC}"
|
|
virt-customize -q -a "$FILE" --hostname "${HN}"
|
|
[ -n "$ROOT_PASS" ] && virt-customize -q -a "$FILE" --root-password password:"$ROOT_PASS" >/dev/null 2>&1
|
|
[ -n "$SSH_KEY" ] && virt-customize -q -a "$FILE" --ssh-inject root:string:"$SSH_KEY" >/dev/null 2>&1
|
|
|
|
if [ "$CLOUD_INIT" == "no" ] && [ "$AUTOLOGIN" == "yes" ]; then
|
|
virt-customize -q -a "$FILE" --run-command "mkdir -p /etc/systemd/system/serial-getty@ttyS0.service.d" >/dev/null 2>&1
|
|
virt-customize -q -a "$FILE" --run-command 'cat > /etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf << EOF
|
|
[Service]
|
|
ExecStart=
|
|
ExecStart=-/sbin/agetty --autologin root --noclear %I \$TERM
|
|
EOF' >/dev/null 2>&1
|
|
virt-customize -q -a "$FILE" --run-command "mkdir -p /etc/systemd/system/getty@tty1.service.d" >/dev/null 2>&1
|
|
virt-customize -q -a "$FILE" --run-command 'cat > /etc/systemd/system/getty@tty1.service.d/autologin.conf << EOF
|
|
[Service]
|
|
ExecStart=
|
|
ExecStart=-/sbin/agetty --autologin root --noclear %I \$TERM
|
|
EOF' >/dev/null 2>&1
|
|
fi
|
|
|
|
virt-customize -q -a "$FILE" --upload dynr-arrstack-setup.sh:/opt/dynr-arrstack-setup.sh
|
|
virt-customize -q -a "$FILE" --run-command "chmod +x /opt/dynr-arrstack-setup.sh"
|
|
virt-customize -q -a "$FILE" --firstboot /opt/dynr-arrstack-setup.sh
|
|
|
|
STORAGE_TYPE=$(pvesm status -storage "$STORAGE" | awk 'NR>1 {print $2}')
|
|
case $STORAGE_TYPE in
|
|
nfs|dir) DISK_EXT=".qcow2"; DISK_IMPORT="-format qcow2"; DISK_REF="${VMID}/";;
|
|
*) DISK_EXT=""; DISK_IMPORT="-format raw"; DISK_REF="" ;;
|
|
esac
|
|
|
|
echo -e "${INFO}${BB}Welding Structure....${BC}"
|
|
qm create $VMID -agent 1 -tablet 0 -localtime 1 -bios ovmf -cores $CORE_COUNT -memory $RAM_SIZE \
|
|
-name "$HN" -tags DYNR-STACK,Debian13 -net0 virtio,bridge=$BRG$VLAN -onboot 1 -ostype l26 -scsihw virtio-scsi-pci
|
|
pvesm alloc $STORAGE $VMID vm-$VMID-disk-0${DISK_EXT} 4M >/dev/null
|
|
qm importdisk $VMID "$FILE" $STORAGE ${DISK_IMPORT} >/dev/null
|
|
qm set $VMID -efidisk0 ${STORAGE}:${DISK_REF}vm-$VMID-disk-0${DISK_EXT},efitype=4m -scsi0 ${STORAGE}:${DISK_REF}vm-$VMID-disk-1${DISK_EXT},size=${DISK_SIZE} -boot order=scsi0 -serial0 socket >/dev/null
|
|
|
|
header_info
|
|
echo -e "${CM}${BG}Provision Successful: ${HN}${BC}"
|
|
qm start $VMID
|
|
|
|
echo -e "${INFO}${BB}⌚️ Checking Network Connectivity....${BC}"
|
|
fetch_wotd
|
|
|
|
VM_IP="localhost"
|
|
ITERATION=0
|
|
while [ $ITERATION -lt 15 ]; do
|
|
if qm guest exec $VMID -- ping -c 1 -W 2 1.1.1.1 &>/dev/null; then
|
|
NEW_IP=$(qm guest network-get-interfaces $VMID --output-format json 2>/dev/null | jq -r '.[] | select(.name=="eth0") | .["ip-addresses"][] | select(.["ip-address-type"]=="ipv4") | .["ip-address"]' | cut -d/ -f1 | head -n 1)
|
|
if [ -n "$NEW_IP" ]; then
|
|
VM_IP="$NEW_IP"
|
|
echo -e "${CM}${BG}✅ Network Connection Succeeded${BC}"
|
|
echo -e "${TAB}IP Address of ${HN}: ${VM_IP} v4\n"
|
|
break
|
|
fi
|
|
fi
|
|
sleep 10
|
|
ITERATION=$((ITERATION+1))
|
|
done
|
|
|
|
[ "$VM_IP" == "localhost" ] && echo -e "${CROSS}${BR}❌ Network Connection Failed${BC}"
|
|
|
|
echo -e "\n${BB}Access Using IP Provided with App Specific Port:${BC}"
|
|
echo -e "${TAB}Portainer: ${BB}https://${VM_IP}:9443${BC}"
|
|
echo -e "${TAB} Run 'cat /opt/DYNR/urls.txt' to get ports of Installed apps.${BC}"
|
|
echo -e "\n${BG}${BOLD}COMPLETED SUCCESSFULLY! She is firing on all cylinders.${BC}\n" |