2026-05-21 19:04:47 +02:00
#!/usr/bin/env bash
2025-02-11 20:07:51 +01:00
2026-01-06 13:28:12 +01:00
# Copyright (c) 2021-2026 community-scripts ORG
2025-02-11 20:07:51 +01:00
# Author: michelroegl-brunner
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
2025-04-01 10:25:46 +02:00
source /dev/stdin <<< $( curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
2025-02-11 20:07:51 +01:00
function header_info {
clear
2025-04-15 15:20:46 +02:00
cat <<"EOF"
2025-12-03 04:48:12 -03:00
____ ____ _ __
/ __ \/ __ \/ | / /_______ ____ ________
2025-02-11 20:07:51 +01:00
/ / / / /_/ / | / / ___/ _ \/ __ \/ ___/ _ \
/ /_/ / ____/ /| ( __ ) __/ / / ( __ ) __/
2025-12-03 04:48:12 -03:00
\_ ___/_/ /_/ | _/____/\_ __/_/ /_/____/\_ __/
2025-02-11 20:07:51 +01:00
EOF
}
header_info
echo -e "Loading..."
#API VARIABLES
RANDOM_UUID = " $( cat /proc/sys/kernel/random/uuid) "
METHOD = ""
NSAPP = "opnsense-vm"
var_os = "opnsense"
2026-07-19 14:52:42 +02:00
var_version = "26.7"
2026-07-22 08:59:05 +02:00
FREEBSD_MAJOR = "15"
2025-02-11 20:07:51 +01:00
#
GEN_MAC = 02:$( openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//' )
GEN_MAC_LAN = 02:$( openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//' )
2025-05-07 12:37:46 +02:00
2025-02-11 20:07:51 +01:00
YW = $( echo "\033[33m" )
BL = $( echo "\033[36m" )
HA = $( echo "\033[1;34m" )
RD = $( echo "\033[01;31m" )
BGN = $( echo "\033[4;92m" )
GN = $( echo "\033[1;92m" )
DGN = $( echo "\033[32m" )
CL = $( echo "\033[m" )
BFR = "\\r\\033[K"
HOLD = "-"
CM = " ${ GN } ✓ ${ CL } "
CROSS = " ${ RD } ✗ ${ CL } "
set -Eeo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
trap cleanup EXIT
2026-02-23 14:30:48 +01:00
trap 'post_update_to_api "failed" "130"' SIGINT
trap 'post_update_to_api "failed" "143"' SIGTERM
trap 'post_update_to_api "failed" "129"; exit 129' SIGHUP
2025-02-11 20:07:51 +01:00
function error_handler() {
local exit_code = " $? "
local line_number = " $1 "
local command = " $2 "
2026-02-12 20:06:02 +01:00
post_update_to_api "failed" " $exit_code "
2025-02-11 20:07:51 +01:00
local error_message = " ${ RD } [ERROR] ${ CL } in line ${ RD } $line_number ${ CL } : exit code ${ RD } $exit_code ${ CL } : while executing command ${ YW } $command ${ CL } "
echo -e "\n $error_message \n"
cleanup_vmid
}
2025-05-07 12:37:46 +02:00
function get_valid_nextid() {
local try_id
try_id = $( pvesh get /cluster/nextid)
while true; do
if [ -f "/etc/pve/qemu-server/ ${ try_id } .conf" ] || [ -f "/etc/pve/lxc/ ${ try_id } .conf" ] ; then
try_id = $(( try_id + 1 ))
continue
fi
if lvs --noheadings -o lv_name | grep -qE "(^|[-_]) ${ try_id } ( $|[-_])" ; then
try_id = $(( try_id + 1 ))
continue
fi
break
done
echo " $try_id "
}
2025-02-11 20:07:51 +01:00
function cleanup_vmid() {
2025-04-09 18:35:17 +02:00
if qm status $VMID & >/dev/null; then
qm stop $VMID & >/dev/null
qm destroy $VMID & >/dev/null
2025-02-11 20:07:51 +01:00
fi
}
function cleanup() {
2026-02-16 17:14:00 +01:00
local exit_code = $?
2025-02-11 20:07:51 +01:00
popd >/dev/null
2026-02-16 17:14:00 +01:00
if [[ " ${ POST_TO_API_DONE :- } " == "true" && " ${ POST_UPDATE_DONE :- } " != "true" ]] ; then
if [[ $exit_code -eq 0 ]] ; then
post_update_to_api "done" "none"
else
post_update_to_api "failed" " $exit_code "
fi
fi
2025-04-09 18:35:17 +02:00
rm -rf $TEMP_DIR
2025-02-11 20:07:51 +01:00
}
2026-02-18 22:06:04 +01:00
function check_disk_space() {
local path = " $1 "
local required_gb = " $2 "
local available_kb = $( df -k " $path " | awk 'NR==2 {print $4}' )
local available_gb = $(( available_kb / 1024 / 1024 ))
if [ $available_gb -lt $required_gb ] ; then
return 1
fi
return 0
}
2026-03-03 15:48:50 +01:00
# Use disk-backed temp directory to avoid tmpfs/RAM size limits in /tmp
if [ -d "/var/tmp" ] && check_disk_space "/var/tmp" 20; then
TEMP_DIR = $( mktemp -d /var/tmp/opnsense-vm.XXXXXX)
elif [ -d "/tmp" ] && check_disk_space "/tmp" 20; then
TEMP_DIR = $( mktemp -d)
else
# Fallback: try /var/tmp anyway, disk space check will catch it later
TEMP_DIR = $( mktemp -d /var/tmp/opnsense-vm.XXXXXX)
fi
2025-04-09 18:35:17 +02:00
pushd $TEMP_DIR >/dev/null
2025-02-11 20:07:51 +01:00
function send_line_to_vm() {
echo -e " ${ DGN } Sending line: ${ YW } $1 ${ CL } "
for (( i = 0; i < ${# 1 } ; i++)) ; do
character = ${ 1 : i : 1 }
case $character in
" " ) character = "spc" ;;
"-" ) character = "minus" ;;
"=" ) character = "equal" ;;
"," ) character = "comma" ;;
"." ) character = "dot" ;;
"/" ) character = "slash" ;;
"'" ) character = "apostrophe" ;;
";" ) character = "semicolon" ;;
'\' ) character = "backslash" ;;
'`' ) character = "grave_accent" ;;
"[" ) character = "bracket_left" ;;
"]" ) character = "bracket_right" ;;
"_" ) character = "shift-minus" ;;
"+" ) character = "shift-equal" ;;
"?" ) character = "shift-slash" ;;
"<" ) character = "shift-comma" ;;
">" ) character = "shift-dot" ;;
'"' ) character = "shift-apostrophe" ;;
":" ) character = "shift-semicolon" ;;
"|" ) character = "shift-backslash" ;;
"~" ) character = "shift-grave_accent" ;;
"{" ) character = "shift-bracket_left" ;;
"}" ) character = "shift-bracket_right" ;;
"A" ) character = "shift-a" ;;
"B" ) character = "shift-b" ;;
"C" ) character = "shift-c" ;;
"D" ) character = "shift-d" ;;
"E" ) character = "shift-e" ;;
"F" ) character = "shift-f" ;;
"G" ) character = "shift-g" ;;
"H" ) character = "shift-h" ;;
"I" ) character = "shift-i" ;;
"J" ) character = "shift-j" ;;
"K" ) character = "shift-k" ;;
"L" ) character = "shift-l" ;;
"M" ) character = "shift-m" ;;
"N" ) character = "shift-n" ;;
"O" ) character = "shift-o" ;;
"P" ) character = "shift-p" ;;
"Q" ) character = "shift-q" ;;
"R" ) character = "shift-r" ;;
"S" ) character = "shift-s" ;;
"T" ) character = "shift-t" ;;
"U" ) character = "shift-u" ;;
"V" ) character = "shift-v" ;;
"W" ) character = "shift-w" ;;
2025-12-03 04:48:12 -03:00
"X" ) character = "shift-x" ;;
2025-02-11 20:07:51 +01:00
"Y" ) character = "shift-y" ;;
"Z" ) character = "shift-z" ;;
"!" ) character = "shift-1" ;;
"@" ) character = "shift-2" ;;
"#" ) character = "shift-3" ;;
'$' ) character = "shift-4" ;;
"%" ) character = "shift-5" ;;
"^" ) character = "shift-6" ;;
"&" ) character = "shift-7" ;;
"*" ) character = "shift-8" ;;
"(" ) character = "shift-9" ;;
")" ) character = "shift-0" ;;
esac
2025-04-09 18:35:17 +02:00
qm sendkey $VMID " $character "
2025-02-11 20:07:51 +01:00
done
2025-04-09 18:35:17 +02:00
qm sendkey $VMID ret
2025-02-11 20:07:51 +01:00
}
2025-02-12 11:05:08 +01:00
if ( whiptail --backtitle "Proxmox VE Helper Scripts" --title "OPNsense VM" --yesno "This will create a New OPNsense VM. Proceed?" 10 58) ; then
2025-02-11 20:07:51 +01:00
:
else
header_info && echo -e "⚠ User exited script \n" && exit
fi
function msg_info() {
local msg = " $1 "
echo -ne " ${ HOLD } ${ YW }${ msg } ..."
}
function msg_ok() {
local msg = " $1 "
echo -e " ${ BFR } ${ CM } ${ GN }${ msg }${ CL } "
}
function msg_error() {
local msg = " $1 "
echo -e " ${ BFR } ${ CROSS } ${ RD }${ msg }${ CL } "
}
2025-08-06 13:46:07 +02:00
# This function checks the version of Proxmox Virtual Environment (PVE) and exits if the version is not supported.
2026-05-21 19:04:47 +02:00
# Supported: Proxmox VE 8.0.x – 8.9.x, 9.0 and 9.2
2025-07-28 11:00:09 +02:00
pve_check() {
local PVE_VER
PVE_VER = " $( pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}' ) "
2025-08-06 13:46:07 +02:00
# Check for Proxmox VE 8.x: allow 8.0– 8.9
2025-07-28 11:00:09 +02:00
if [[ " $PVE_VER " = ~ ^8\. ([ 0-9] +) ]] ; then
local MINOR = " ${ BASH_REMATCH [1] } "
2025-08-06 13:46:07 +02:00
if (( MINOR < 0 || MINOR > 9)) ; then
2025-07-28 11:00:09 +02:00
msg_error "This version of Proxmox VE is not supported."
2025-08-06 13:46:07 +02:00
msg_error "Supported: Proxmox VE version 8.0 – 8.9"
2026-03-02 10:55:20 +01:00
exit 105
2025-07-28 11:00:09 +02:00
fi
return 0
2025-02-11 20:07:51 +01:00
fi
2025-07-28 11:00:09 +02:00
2026-05-21 19:04:47 +02:00
# Check for Proxmox VE 9.x: allow 9.0 and 9.2
2025-07-28 11:00:09 +02:00
if [[ " $PVE_VER " = ~ ^9\. ([ 0-9] +) ]] ; then
2025-08-06 13:46:07 +02:00
local MINOR = " ${ BASH_REMATCH [1] } "
2026-05-21 19:04:47 +02:00
if (( MINOR < 0 || MINOR > 2)) ; then
2025-11-22 14:35:13 +01:00
msg_error "This version of Proxmox VE is not supported."
2026-05-21 19:04:47 +02:00
msg_error "Supported: Proxmox VE version 9.0 – 9.2"
2026-03-02 10:55:20 +01:00
exit 105
2025-07-28 11:00:09 +02:00
fi
2025-08-06 13:46:07 +02:00
return 0
2025-07-28 11:00:09 +02:00
fi
# All other unsupported versions
msg_error "This version of Proxmox VE is not supported."
2026-05-21 19:04:47 +02:00
msg_error "Supported versions: Proxmox VE 8.0 – 8.x or 9.0 – 9.2"
2026-03-02 10:55:20 +01:00
exit 105
2025-02-11 20:07:51 +01:00
}
function arch_check() {
if [ " $( dpkg --print-architecture) " != "amd64" ] ; then
echo -e "\n ${ CROSS } This script will not work with PiMox! \n"
echo -e "Exiting..."
sleep 2
exit
fi
}
function ssh_check() {
if command -v pveversion >/dev/null 2>& 1; then
if [ -n " ${ SSH_CLIENT :+x } " ] ; then
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then
echo "you've been warned"
else
clear
exit
fi
fi
fi
}
function exit-script() {
clear
echo -e "⚠ User exited script \n"
exit
}
2026-03-03 15:48:50 +01:00
function get_available_bridges() {
ip -o link show type bridge 2>/dev/null | awk -F': ' '{print $2}' | sort
}
2025-02-11 20:07:51 +01:00
function default_settings() {
2025-05-07 12:37:46 +02:00
VMID = $( get_valid_nextid)
2025-02-11 20:07:51 +01:00
FORMAT = ",efitype=4m"
MACHINE = ""
DISK_CACHE = ""
HN = "opnsense"
CPU_TYPE = ""
CORE_COUNT = "4"
RAM_SIZE = "8192"
BRG = "vmbr0"
IP_ADDR = ""
WAN_IP_ADDR = ""
LAN_GW = ""
WAN_GW = ""
NETMASK = ""
WAN_NETMASK = ""
VLAN = ""
MAC = $GEN_MAC
WAN_MAC = $GEN_MAC_LAN
2026-03-03 15:48:50 +01:00
WAN_BRG = ""
2025-02-11 20:07:51 +01:00
MTU = ""
START_VM = "yes"
METHOD = "default"
2026-03-03 15:48:50 +01:00
# Detect available bridges
local AVAILABLE_BRIDGES
AVAILABLE_BRIDGES = $( get_available_bridges)
local BRIDGE_COUNT
BRIDGE_COUNT = $( echo " $AVAILABLE_BRIDGES " | wc -l)
2025-02-11 20:07:51 +01:00
echo -e " ${ DGN } Using Virtual Machine ID: ${ BGN }${ VMID }${ CL } "
echo -e " ${ DGN } Using Hostname: ${ BGN }${ HN }${ CL } "
echo -e " ${ DGN } Allocated Cores: ${ BGN }${ CORE_COUNT }${ CL } "
echo -e " ${ DGN } Allocated RAM: ${ BGN }${ RAM_SIZE }${ CL } "
2026-02-25 17:31:41 +01:00
if ! ip link show " ${ BRG } " & >/dev/null; then
msg_error "Bridge ' ${ BRG } ' does not exist"
2025-04-15 15:20:46 +02:00
exit
2025-02-11 20:07:51 +01:00
else
echo -e " ${ DGN } Using LAN Bridge: ${ BGN }${ BRG }${ CL } "
fi
echo -e " ${ DGN } Using LAN VLAN: ${ BGN } Default ${ CL } "
echo -e " ${ DGN } Using LAN MAC Address: ${ BGN }${ MAC }${ CL } "
2025-12-03 04:48:12 -03:00
2026-03-03 15:48:50 +01:00
# Determine available network modes based on bridge count
local DEFAULT_WAN_BRG
2026-04-13 16:31:36 +02:00
DEFAULT_WAN_BRG = $( echo " $AVAILABLE_BRIDGES " | grep -v "^ ${ BRG } $" | head -n1 || true )
2026-03-03 15:48:50 +01:00
if [ " $BRIDGE_COUNT " -ge 2 ] ; then
# Multiple bridges available - offer dual or single mode
if NETWORK_MODE = $( whiptail --backtitle "Proxmox VE Helper Scripts" --title "NETWORK CONFIGURATION" --radiolist --cancel-button Exit-Script \
"Choose network setup mode for OPNsense:\n" 14 70 2 \
"dual" "Dual Interface (Firewall/Router) - uses ${ DEFAULT_WAN_BRG } " ON \
"single" "Single Interface (Proxy/VPN/IDS Server)" OFF \
3>& 1 1>& 2 2>& 3) ; then
if [ " $NETWORK_MODE " = "dual" ] ; then
WAN_BRG = " $DEFAULT_WAN_BRG "
echo -e " ${ DGN } Network Mode: ${ BGN } Dual Interface (Firewall) ${ CL } "
2025-12-03 04:48:12 -03:00
echo -e " ${ DGN } Using WAN Bridge: ${ BGN }${ WAN_BRG }${ CL } "
2026-03-03 15:48:50 +01:00
echo -e " ${ DGN } Using WAN MAC Address: ${ BGN }${ WAN_MAC }${ CL } "
else
echo -e " ${ DGN } Network Mode: ${ BGN } Single Interface (Proxy/VPN/IDS) ${ CL } "
WAN_BRG = ""
2025-12-03 04:48:12 -03:00
fi
else
2026-03-03 15:48:50 +01:00
exit-script
2025-12-03 04:48:12 -03:00
fi
2025-02-11 20:07:51 +01:00
else
2026-03-03 15:48:50 +01:00
# Only one bridge available - single interface mode only
echo -e " ${ DGN } Network Mode: ${ BGN } Single Interface (Proxy/VPN/IDS) ${ CL } "
echo -e " ${ YW } (Only one bridge detected, dual interface requires a second bridge) ${ CL } "
WAN_BRG = ""
2025-02-11 20:07:51 +01:00
fi
echo -e " ${ DGN } Using Interface MTU Size: ${ BGN } Default ${ CL } "
echo -e " ${ DGN } Start VM when completed: ${ BGN } yes ${ CL } "
2025-02-12 11:05:08 +01:00
echo -e " ${ BL } Creating a OPNsense VM using the above default settings ${ CL } "
2025-02-11 20:07:51 +01:00
}
function advanced_settings() {
local ip_regex = '^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$'
METHOD = "advanced"
2025-05-07 12:37:46 +02:00
[ -z " ${ VMID :- } " ] && VMID = $( get_valid_nextid)
2025-02-11 20:07:51 +01:00
while true; do
2025-05-07 12:37:46 +02:00
if VMID = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 $VMID --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
2025-02-11 20:07:51 +01:00
if [ -z " $VMID " ] ; then
2025-05-07 12:37:46 +02:00
VMID = $( get_valid_nextid)
2025-02-11 20:07:51 +01:00
fi
if pct status " $VMID " & >/dev/null || qm status " $VMID " & >/dev/null; then
echo -e " ${ CROSS }${ RD } ID $VMID is already in use ${ CL } "
sleep 2
continue
fi
echo -e " ${ DGN } Virtual Machine ID: ${ BGN } $VMID ${ CL } "
break
else
exit-script
fi
done
if MACH = $( whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \
"i440fx" "Machine i440fx" ON \
"q35" "Machine q35" OFF \
3>& 1 1>& 2 2>& 3) ; then
2025-04-09 18:35:17 +02:00
if [ $MACH = q35 ] ; then
2025-02-11 20:07:51 +01:00
echo -e " ${ DGN } Using Machine Type: ${ BGN } $MACH ${ CL } "
FORMAT = ""
MACHINE = " -machine q35"
else
echo -e " ${ DGN } Using Machine Type: ${ BGN } $MACH ${ CL } "
FORMAT = ",efitype=4m"
MACHINE = ""
fi
else
exit-script
fi
if CPU_TYPE1 = $( whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
"0" "KVM64 (Default)" ON \
"1" "Host" OFF \
3>& 1 1>& 2 2>& 3) ; then
2025-04-09 18:35:17 +02:00
if [ $CPU_TYPE1 = "1" ] ; then
2025-02-11 20:07:51 +01:00
echo -e " ${ DGN } Using CPU Model: ${ BGN } Host ${ CL } "
CPU_TYPE = " -cpu host"
else
echo -e " ${ DGN } Using CPU Model: ${ BGN } KVM64 ${ CL } "
CPU_TYPE = ""
fi
else
exit-script
fi
if DISK_CACHE = $( whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
"0" "None (Default)" ON \
"1" "Write Through" OFF \
3>& 1 1>& 2 2>& 3) ; then
2025-04-09 18:35:17 +02:00
if [ $DISK_CACHE = "1" ] ; then
2025-02-11 20:07:51 +01:00
echo -e " ${ DGN } Using Disk Cache: ${ BGN } Write Through ${ CL } "
DISK_CACHE = "cache=writethrough,"
else
echo -e " ${ DGN } Using Disk Cache: ${ BGN } None ${ CL } "
DISK_CACHE = ""
fi
else
exit-script
fi
2025-02-12 11:05:08 +01:00
if VM_NAME = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 OPNsense --title "HOSTNAME" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
2025-12-03 04:48:12 -03:00
if [ -z " $VM_NAME " ] ; then
2025-02-12 11:05:08 +01:00
HN = "OPNsense"
2025-02-11 20:07:51 +01:00
else
2026-03-20 13:18:01 +01:00
HN = $( echo " ${ VM_NAME ,, } " | tr -cs 'a-z0-9-' '-' | sed 's/^-//;s/-$//' )
if [ " $HN " != " ${ VM_NAME ,, } " ] ; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "HOSTNAME ADJUSTED" --msgbox "Invalid characters detected. Hostname has been adjusted to:\n\n $HN " 10 58
fi
2025-02-11 20:07:51 +01:00
fi
echo -e " ${ DGN } Using Hostname: ${ BGN } $HN ${ CL } "
else
exit-script
fi
2026-03-20 13:18:01 +01:00
while true; do
if CORE_COUNT = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 4 --title "CORE COUNT" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z " $CORE_COUNT " ] ; then CORE_COUNT = "4" ; fi
if [[ " $CORE_COUNT " = ~ ^[ 1-9][ 0-9] *$ ]] ; then
echo -e " ${ DGN } Allocated Cores: ${ BGN } $CORE_COUNT ${ CL } "
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "CPU Cores must be a positive integer (e.g., 4)." 8 58
else
exit-script
2025-02-11 20:07:51 +01:00
fi
2026-03-20 13:18:01 +01:00
done
2025-02-11 20:07:51 +01:00
2026-03-20 13:18:01 +01:00
while true; do
if RAM_SIZE = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 8192 --title "RAM" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z " $RAM_SIZE " ] ; then RAM_SIZE = "8192" ; fi
if [[ " $RAM_SIZE " = ~ ^[ 1-9][ 0-9] *$ ]] ; then
echo -e " ${ DGN } Allocated RAM: ${ BGN } $RAM_SIZE ${ CL } "
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "RAM Size must be a positive integer in MiB (e.g., 8192)." 8 58
else
exit-script
2025-02-11 20:07:51 +01:00
fi
2026-03-20 13:18:01 +01:00
done
2025-02-11 20:07:51 +01:00
if BRG = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN Bridge" 8 58 vmbr0 --title "LAN BRIDGE" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
2025-04-09 18:35:17 +02:00
if [ -z $BRG ] ; then
2025-02-11 20:07:51 +01:00
BRG = "vmbr0"
fi
2026-02-25 17:31:41 +01:00
if ! ip link show " ${ BRG } " & >/dev/null; then
msg_error "Bridge ' ${ BRG } ' does not exist"
2025-02-11 20:07:51 +01:00
exit
fi
echo -e " ${ DGN } Using LAN Bridge: ${ BGN } $BRG ${ CL } "
else
exit-script
fi
2025-04-09 18:35:17 +02:00
if IP_ADDR = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN IP" 8 58 $IP_ADDR --title "LAN IP ADDRESS" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z $IP_ADDR ] ; then
2025-02-11 20:07:51 +01:00
echo -e " ${ DGN } Using DHCP AS LAN IP ADDRESS ${ CL } "
else
if [[ -n " $IP_ADDR " && ! " $IP_ADDR " = ~ $ip_regex ]] ; then
msg_error "Invalid IP Address format for LAN IP. Needs to be 0.0.0.0, was $IP_ADDR "
exit
fi
echo -e " ${ DGN } Using LAN IP ADDRESS: ${ BGN } $IP_ADDR ${ CL } "
2025-04-09 18:35:17 +02:00
if LAN_GW = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN GATEWAY IP" 8 58 $LAN_GW --title "LAN GATEWAY IP ADDRESS" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z $LAN_GW ] ; then
2025-02-11 20:07:51 +01:00
echo -e " ${ DGN } Gateway needs to be set if ip is not dhcp ${ CL } "
exit-script
fi
if [[ -n " $LAN_GW " && ! " $LAN_GW " = ~ $ip_regex ]] ; then
msg_error "Invalid IP Address format for Gateway. Needs to be 0.0.0.0, was $LAN_GW "
exit
fi
echo -e " ${ DGN } Using LAN GATEWAY ADDRESS: ${ BGN } $LAN_GW ${ CL } "
fi
2026-07-22 08:59:05 +02:00
if NETMASK = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN netmask (24 for example)" 8 58 $NETMASK --title "LAN NETMASK" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
2025-04-09 18:35:17 +02:00
if [ -z $NETMASK ] ; then
2025-02-11 20:07:51 +01:00
echo -e " ${ DGN } Netmask needs to be set if ip is not dhcp ${ CL } "
fi
if [[ -n " $NETMASK " && ! ( " $NETMASK " = ~ ^[ 0-9] +$ && " $NETMASK " -ge 1 && " $NETMASK " -le 32) ]] ; then
msg_error "Invalid LAN NETMASK format. Needs to be 1-32, was $NETMASK "
exit
fi
echo -e " ${ DGN } Using LAN NETMASK: ${ BGN } $NETMASK ${ CL } "
else
exit-script
fi
fi
else
exit-script
fi
2026-03-03 15:48:50 +01:00
# Build WAN bridge selection from available bridges (excluding LAN bridge)
local WAN_BRIDGES
2026-04-13 16:31:36 +02:00
WAN_BRIDGES = $( get_available_bridges | grep -v "^ ${ BRG } $" || true )
2026-03-03 15:48:50 +01:00
if [ -z " $WAN_BRIDGES " ] ; then
msg_error "No additional bridge available for WAN. Only ' ${ BRG } ' exists."
msg_error "Create a second bridge (e.g. vmbr1) in Proxmox network config first."
exit
fi
local WAN_MENU =()
local first = true
while IFS = read -r brg; do
if $first ; then
WAN_MENU +=( " $brg " "" "ON" )
first = false
else
WAN_MENU +=( " $brg " "" "OFF" )
2025-02-11 20:07:51 +01:00
fi
2026-03-03 15:48:50 +01:00
done <<< " $WAN_BRIDGES "
if WAN_BRG = $( whiptail --backtitle "Proxmox VE Helper Scripts" --title "WAN BRIDGE" --radiolist "Select WAN Bridge" 14 58 6 \
" ${ WAN_MENU [@] } " 3>& 1 1>& 2 2>& 3) ; then
if [ -z " $WAN_BRG " ] ; then
WAN_BRG = $( echo " $WAN_BRIDGES " | head -n1)
2025-02-11 20:07:51 +01:00
fi
echo -e " ${ DGN } Using WAN Bridge: ${ BGN } $WAN_BRG ${ CL } "
else
exit-script
fi
2025-04-09 18:35:17 +02:00
if WAN_IP_ADDR = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN IP" 8 58 $WAN_IP_ADDR --title "WAN IP ADDRESS" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z $WAN_IP_ADDR ] ; then
2025-02-11 20:07:51 +01:00
echo -e " ${ DGN } Using DHCP AS WAN IP ADDRESS ${ CL } "
else
if [[ -n " $WAN_IP_ADDR " && ! " $WAN_IP_ADDR " = ~ $ip_regex ]] ; then
msg_error "Invalid IP Address format for WAN IP. Needs to be 0.0.0.0, was $WAN_IP_ADDR "
exit
fi
echo -e " ${ DGN } Using WAN IP ADDRESS: ${ BGN } $WAN_IP_ADDR ${ CL } "
2025-04-09 18:35:17 +02:00
if WAN_GW = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN GATEWAY IP" 8 58 $WAN_GW --title "WAN GATEWAY IP ADDRESS" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z $WAN_GW ] ; then
2025-02-11 20:07:51 +01:00
echo -e " ${ DGN } Gateway needs to be set if ip is not dhcp ${ CL } "
exit-script
fi
if [[ -n " $WAN_GW " && ! " $WAN_GW " = ~ $ip_regex ]] ; then
msg_error "Invalid IP Address format for WAN Gateway. Needs to be 0.0.0.0, was $WAN_GW "
exit
fi
echo -e " ${ DGN } Using WAN GATEWAY ADDRESS: ${ BGN } $WAN_GW ${ CL } "
else
exit-script
fi
2026-07-22 08:59:05 +02:00
if WAN_NETMASK = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN netmask (24 for example)" 8 58 $WAN_NETMASK --title "WAN NETMASK" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
2025-04-09 18:35:17 +02:00
if [ -z $WAN_NETMASK ] ; then
2025-02-11 20:07:51 +01:00
echo -e " ${ DGN } WAN Netmask needs to be set if ip is not dhcp ${ CL } "
fi
if [[ -n " $WAN_NETMASK " && ! ( " $WAN_NETMASK " = ~ ^[ 0-9] +$ && " $WAN_NETMASK " -ge 1 && " $WAN_NETMASK " -le 32) ]] ; then
msg_error "Invalid WAN NETMASK format. Needs to be 1-32, was $WAN_NETMASK "
exit
fi
echo -e " ${ DGN } Using WAN NETMASK: ${ BGN } $WAN_NETMASK ${ CL } "
else
exit-script
fi
fi
else
exit-script
fi
2026-07-22 08:59:05 +02:00
if MAC1 = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN MAC Address" 8 58 $GEN_MAC --title "LAN MAC ADDRESS" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
2025-04-09 18:35:17 +02:00
if [ -z $MAC1 ] ; then
2025-02-11 20:07:51 +01:00
MAC = " $GEN_MAC "
else
MAC = " $MAC1 "
fi
echo -e " ${ DGN } Using LAN MAC Address: ${ BGN } $MAC ${ CL } "
else
exit-script
fi
2026-07-22 08:59:05 +02:00
if MAC2 = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN MAC Address" 8 58 $GEN_MAC_LAN --title "WAN MAC ADDRESS" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
2025-04-09 18:35:17 +02:00
if [ -z $MAC2 ] ; then
2025-02-11 20:07:51 +01:00
WAN_MAC = " $GEN_MAC_LAN "
else
WAN_MAC = " $MAC2 "
fi
echo -e " ${ DGN } Using WAN MAC Address: ${ BGN } $WAN_MAC ${ CL } "
else
exit-script
fi
2025-02-12 11:05:08 +01:00
if ( whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create OPNsense VM?" --no-button Do-Over 10 58) ; then
echo -e " ${ RD } Creating a OPNsense VM using the above advanced settings ${ CL } "
2025-02-11 20:07:51 +01:00
else
header_info
echo -e " ${ RD } Using Advanced Settings ${ CL } "
advanced_settings
fi
}
function start_script() {
if ( whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno "Use Default Settings?" --no-button Advanced 10 58) ; then
header_info
echo -e " ${ BL } Using Default Settings ${ CL } "
default_settings
else
header_info
echo -e " ${ RD } Using Advanced Settings ${ CL } "
advanced_settings
fi
}
arch_check
pve_check
ssh_check
start_script
post_to_api_vm
msg_info "Validating Storage"
while read -r line; do
2025-04-09 18:35:17 +02:00
TAG = $( echo $line | awk '{print $1}' )
TYPE = $( echo $line | awk '{printf "%-10s", $2}' )
FREE = $( echo $line | numfmt --field 4-6 --from-unit= K --to= iec --format %.2f | awk '{printf( "%9sB", $6)}' )
2025-02-11 20:07:51 +01:00
ITEM = " Type: $TYPE Free: $FREE "
OFFSET = 2
if [[ $(( ${# ITEM } + $OFFSET )) -gt ${ MSG_MAX_LENGTH :- } ]] ; then
MSG_MAX_LENGTH = $(( ${# ITEM } + $OFFSET ))
fi
STORAGE_MENU +=( " $TAG " " $ITEM " "OFF" )
done < <( pvesm status -content images | awk 'NR>1' )
VALID = $( pvesm status -content images | awk 'NR>1' )
if [ -z " $VALID " ] ; then
msg_error "Unable to detect a valid storage location."
exit
elif [ $(( ${# STORAGE_MENU [@] } / 3 )) -eq 1 ] ; then
STORAGE = ${ STORAGE_MENU [0] }
else
while [ -z " ${ STORAGE :+x } " ] ; do
STORAGE = $( whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
2025-04-17 02:49:55 -04:00
"Which storage pool would you like to use for ${ HN } ?\nTo make a selection, use the Spacebar.\n" \
2025-02-11 20:07:51 +01:00
16 $(( $MSG_MAX_LENGTH + 23 )) 6 \
2025-04-15 15:20:46 +02:00
" ${ STORAGE_MENU [@] } " 3>& 1 1>& 2 2>& 3)
2025-02-11 20:07:51 +01:00
done
fi
msg_ok "Using ${ CL }${ BL } $STORAGE ${ CL } ${ GN } for Storage Location."
msg_ok "Virtual Machine ID is ${ CL }${ BL } $VMID ${ CL } ."
2025-02-12 11:05:08 +01:00
msg_info "Retrieving the URL for the OPNsense Qcow2 Disk Image"
2026-07-22 08:59:05 +02:00
# Use latest stable FreeBSD amd64 qcow2 VM image matching FREEBSD_MAJOR
2026-01-08 15:10:57 +01:00
RELEASE_LIST = " $( curl -s https://download.freebsd.org/releases/VM-IMAGES/ |
2026-07-22 08:59:05 +02:00
grep -Eo " ${ FREEBSD_MAJOR } \.[0-9]+-RELEASE" |
2026-01-08 15:10:57 +01:00
sort -Vr |
uniq) "
2025-12-15 09:10:29 -07:00
URL = ""
FREEBSD_VER = ""
for ver in $RELEASE_LIST ; do
2026-07-22 08:59:05 +02:00
# FreeBSD 15+ publishes separate -ufs/-zfs images instead of a generic one
for variant in "" "-ufs" "-zfs" ; do
candidate = "https://download.freebsd.org/releases/VM-IMAGES/ ${ ver } /amd64/Latest/FreeBSD- ${ ver } -amd64 ${ variant } .qcow2.xz"
if curl -fsI " $candidate " >/dev/null 2>& 1; then
FREEBSD_VER = " $ver "
URL = " $candidate "
break 2
fi
done
2025-12-15 09:10:29 -07:00
done
if [ -z " $URL " ] ; then
2026-07-22 08:59:05 +02:00
msg_error "Could not find a FreeBSD ${ FREEBSD_MAJOR } .x amd64 qcow2 image."
2026-03-02 10:55:20 +01:00
exit 115
2025-12-15 09:10:29 -07:00
fi
2025-12-03 04:48:12 -03:00
msg_ok "Download URL: ${ CL }${ BL }${ URL }${ CL } "
2026-02-18 22:06:04 +01:00
# Check available disk space (require at least 20GB for safety)
if ! check_disk_space " $TEMP_DIR " 20; then
AVAILABLE_GB = $( df -h " $TEMP_DIR " | awk 'NR==2 {print $4}' )
msg_error "Insufficient disk space in temporary directory ( $TEMP_DIR )."
msg_error "Available: ${ AVAILABLE_GB } , Required: ~20GB for FreeBSD image decompression."
msg_error "Please free up space or ensure /tmp has sufficient storage."
2026-03-02 10:55:20 +01:00
exit 214
2026-02-18 22:06:04 +01:00
fi
msg_info "Downloading FreeBSD Image"
2025-04-03 16:01:23 +02:00
curl -f#SL -o " $( basename " $URL " ) " " $URL "
2025-02-11 20:07:51 +01:00
echo -en "\e[1A\e[0K"
2026-02-18 22:06:04 +01:00
msg_ok "Downloaded ${ CL }${ BL } $( basename " $URL " ) ${ CL } "
# Check disk space again before decompression
if ! check_disk_space " $TEMP_DIR " 15; then
AVAILABLE_GB = $( df -h " $TEMP_DIR " | awk 'NR==2 {print $4}' )
msg_error "Insufficient disk space for decompression."
msg_error "Available: ${ AVAILABLE_GB } , Required: ~15GB for decompressed image."
2026-03-02 10:55:20 +01:00
exit 214
2026-02-18 22:06:04 +01:00
fi
msg_info "Decompressing FreeBSD Image (this may take a few minutes)"
2025-12-03 04:48:12 -03:00
FILE = FreeBSD.qcow2
2026-02-18 22:06:04 +01:00
if ! unxz -cv $( basename $URL ) >${ FILE } ; then
msg_error "Failed to decompress FreeBSD image."
msg_error "This is usually caused by insufficient disk space."
df -h " $TEMP_DIR "
2026-03-02 10:55:20 +01:00
exit 115
2026-02-18 22:06:04 +01:00
fi
# Remove the compressed file to save space
rm -f " $( basename " $URL " ) "
msg_ok "Decompressed ${ CL }${ BL }${ FILE }${ CL } "
2025-02-11 20:07:51 +01:00
2025-04-09 18:35:17 +02:00
STORAGE_TYPE = $( pvesm status -storage $STORAGE | awk 'NR>1 {print $2}' )
2025-02-11 20:07:51 +01:00
case $STORAGE_TYPE in
nfs | dir)
DISK_EXT = ".qcow2"
DISK_REF = " $VMID /"
DISK_IMPORT = "-format qcow2"
THIN = ""
;;
btrfs)
DISK_EXT = ".raw"
DISK_REF = " $VMID /"
DISK_IMPORT = "-format raw"
FORMAT = ",efitype=4m"
THIN = ""
;;
2026-02-12 20:06:02 +01:00
*)
DISK_EXT = ""
DISK_REF = ""
DISK_IMPORT = "-format raw"
;;
2025-02-11 20:07:51 +01:00
esac
for i in { 0,1} ; do
disk = "DISK $i "
2025-04-09 18:35:17 +02:00
eval DISK${ i } = vm-${ VMID } -disk-${ i }${ DISK_EXT :- }
eval DISK${ i } _REF = ${ STORAGE } :${ DISK_REF :- }${ !disk }
2025-02-11 20:07:51 +01:00
done
2025-02-12 11:05:08 +01:00
msg_info "Creating a OPNsense VM"
2025-04-09 18:35:17 +02:00
qm create $VMID -agent 1${ MACHINE } -tablet 0 -localtime 1 -bios ovmf${ CPU_TYPE } -cores $CORE_COUNT -memory $RAM_SIZE \
2026-03-24 20:50:40 +01:00
-name $HN -tags community-script -net0 virtio,bridge= $BRG ,macaddr= $MAC$VLAN$MTU -onboot 1 -ostype l26 -scsihw virtio-scsi-pci
2026-05-02 13:40:49 +02:00
# Retry pvesm alloc on transient zfs_request "got timeout" errors (#14127)
alloc_attempt = 1
alloc_max = 4
alloc_delay = 5
while :; do
alloc_err = $( pvesm alloc $STORAGE $VMID $DISK0 4M 2>& 1 >/dev/null) && break
if [[ " $alloc_err " == *"got timeout" * && $alloc_attempt -lt $alloc_max ]] ; then
2026-05-16 00:45:10 +02:00
echo -e " ${ YW } [WARN] ${ CL } pvesm alloc hit zfs timeout (attempt $alloc_attempt / $alloc_max ), retrying in ${ alloc_delay } s..."
2026-05-02 13:40:49 +02:00
pvesm free " ${ DISK0_REF } " & >/dev/null || true
sleep " $alloc_delay "
alloc_attempt = $(( alloc_attempt + 1 ))
alloc_delay = $(( alloc_delay * 2 ))
continue
fi
echo -e " $alloc_err " >& 2
exit 220
done
2026-04-13 16:31:36 +02:00
qm importdisk $VMID ${ FILE } $STORAGE ${ DISK_IMPORT :- } & >/dev/null
2025-04-09 18:35:17 +02:00
qm set $VMID \
-efidisk0 ${ DISK0_REF }${ FORMAT } \
-scsi0 ${ DISK1_REF } ,${ DISK_CACHE }${ THIN } size = 2G \
2025-02-11 20:07:51 +01:00
-boot order = scsi0 \
2025-04-15 15:20:46 +02:00
-serial0 socket \
-tags community-script >/dev/null
2026-02-18 22:06:04 +01:00
qm resize $VMID scsi0 20G >/dev/null
2025-04-15 15:20:46 +02:00
DESCRIPTION = $(
cat <<EOF
2025-02-11 20:07:51 +01:00
<div align='center'>
2026-03-25 17:48:03 +01:00
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
2026-07-22 08:59:05 +02:00
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
2025-02-11 20:07:51 +01:00
</a>
2025-02-12 11:05:08 +01:00
<h2 style='font-size: 24px; margin: 20px 0;'>OPNsense VM</h2>
2025-02-11 20:07:51 +01:00
<p style='margin: 16px 0;'>
<a href='https://ko-fi.com/community_scripts' target='_blank' rel='noopener noreferrer'>
<img src='https://img.shields.io/badge/☕-Buy us a coffee-blue' alt='spend Coffee' />
</a>
</p>
2025-12-03 04:48:12 -03:00
2025-02-11 20:07:51 +01:00
<span style='margin: 0 10px;'>
<i class="fa fa-github fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>GitHub</a>
</span>
<span style='margin: 0 10px;'>
<i class="fa fa-comments fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE/discussions' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Discussions</a>
</span>
<span style='margin: 0 10px;'>
<i class="fa fa-exclamation-circle fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE/issues' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Issues</a>
</span>
</div>
EOF
)
2026-01-08 15:10:57 +01:00
qm set $VMID -description " $DESCRIPTION " >/dev/null
2025-02-11 20:07:51 +01:00
msg_info "Bridge interfaces are being added."
2025-04-09 18:35:17 +02:00
qm set $VMID \
-net0 virtio,bridge= ${ BRG } ,macaddr= ${ MAC }${ VLAN }${ MTU } 2>/dev/null
2025-02-11 20:07:51 +01:00
msg_ok "Bridge interfaces have been successfully added."
2025-04-15 15:20:46 +02:00
2025-02-12 11:05:08 +01:00
msg_ok "Created a OPNsense VM ${ CL }${ BL } ( ${ HN } )"
2025-04-15 15:20:46 +02:00
msg_ok "Starting OPNsense VM (Patience this takes 20-30 minutes)"
qm start $VMID
sleep 90
send_line_to_vm "root"
2026-07-26 16:57:29 +02:00
sleep 2
send_line_to_vm ""
2025-04-15 15:20:46 +02:00
send_line_to_vm "fetch https://raw.githubusercontent.com/opnsense/update/master/src/bootstrap/opnsense-bootstrap.sh.in"
2025-12-03 04:48:12 -03:00
if [ -n " $WAN_BRG " ] ; then
msg_info "Adding WAN interface"
qm set $VMID \
-net1 virtio,bridge= ${ WAN_BRG } ,macaddr= ${ WAN_MAC } & >/dev/null
msg_ok "WAN interface added"
2026-01-08 15:10:57 +01:00
sleep 5 # Brief pause after adding network interface
2025-12-03 04:48:12 -03:00
fi
2026-07-22 08:59:05 +02:00
# FreeBSD 15+ VM images ship the base system as pkgbase packages; the bootstrap's
# "delete all packages" step would remove the running base system (/bin/rm etc.)
# and brick the VM. Deregister them from the pkg db first - the files stay in
# place and OPNsense replaces base and kernel with its own sets afterwards.
send_line_to_vm "echo \"PRAGMA foreign_keys=ON; DELETE FROM packages WHERE name LIKE 'FreeBSD-%';\" | pkg shell"
sleep 5
send_line_to_vm "sh ./opnsense-bootstrap.sh.in -y -f -r ${ var_version } "
2025-04-15 15:20:46 +02:00
msg_ok "OPNsense VM is being installed, do not close the terminal, or the installation will fail."
2026-07-22 08:59:05 +02:00
# The bootstrap ends with an automatic reboot into OPNsense. While it runs the
# console keeps changing (download progress, package installs); once the VM has
# settled at the login prompt the screen stays static. Poll a screendump hash
# and continue after 3 minutes without change, bounded by a floor (the build
# never finishes faster) and a ceiling for slow machines. If no screendump can
# be captured at all, fall back to a fixed wait.
SCREEN_PPM = " ${ TEMP_DIR } /screen- ${ VMID } .ppm"
function screen_hash() {
# Remove the previous dump first: a stale file from an earlier successful
# dump must not simulate a static screen when later dumps start failing.
# Note: "qm monitor" is unusable here - its readline attaches to /dev/tty
# even with piped stdin and captures the terminal, so use the API instead.
rm -f " $SCREEN_PPM "
timeout 10 pvesh create /nodes/$( hostname -s) /qemu/$VMID /monitor --command "screendump ${ SCREEN_PPM } " >/dev/null 2>& 1 || true
md5sum " $SCREEN_PPM " 2>/dev/null | cut -d' ' -f1 || true
}
build_elapsed = 300
build_stable = 0
screen_ok = 0
hash_a = ""
hash_b = ""
sleep 300
while [ $build_stable -lt 6 ] && [ $build_elapsed -lt 2400 ] ; do
sleep 30
build_elapsed = $(( build_elapsed + 30 ))
new_hash = $( screen_hash)
if [ -n " $new_hash " ] ; then
screen_ok = 1
# The login prompt cursor may blink: a screen alternating between the same
# two frames (A/B/A/B) counts as stable, anything new resets the counter
if [ " $new_hash " = " $hash_a " ] || [ " $new_hash " = " $hash_b " ] ; then
build_stable = $(( build_stable + 1 ))
else
build_stable = 0
fi
else
build_stable = 0
fi
hash_b = " $hash_a "
hash_a = " $new_hash "
if [ -n " $new_hash " ] ; then
echo -e " ${ DGN } Waiting for OPNsense build: ${ YW } $(( build_elapsed / 60 )) min elapsed, screen ${ new_hash : 0 : 8 } , stable ${ build_stable } /6 ${ CL } "
else
echo -e " ${ DGN } Waiting for OPNsense build: ${ YW } $(( build_elapsed / 60 )) min elapsed, screendump failed ${ CL } "
fi
# No working screendump after several attempts: fixed wait instead
if [ $screen_ok -eq 0 ] && [ $build_elapsed -ge 480 ] ; then
msg_error "Console screendump not available on this system - falling back to a fixed wait (12 minutes)."
sleep 720
build_elapsed = $(( build_elapsed + 720 ))
break
fi
done
msg_ok "OPNsense build finished after $(( build_elapsed / 60 )) minutes"
2025-04-15 15:20:46 +02:00
send_line_to_vm "root"
send_line_to_vm "opnsense"
send_line_to_vm "2"
2025-04-09 19:29:12 +02:00
2025-04-15 15:20:46 +02:00
if [ " $IP_ADDR " != "" ] ; then
send_line_to_vm "1"
send_line_to_vm "n"
send_line_to_vm " ${ IP_ADDR } "
send_line_to_vm " ${ NETMASK } "
send_line_to_vm " ${ LAN_GW } "
send_line_to_vm "n"
send_line_to_vm " "
send_line_to_vm "n"
send_line_to_vm "n"
send_line_to_vm " "
send_line_to_vm "n"
send_line_to_vm "n"
send_line_to_vm "n"
send_line_to_vm "n"
send_line_to_vm "n"
else
send_line_to_vm "1"
send_line_to_vm "y"
send_line_to_vm "n"
send_line_to_vm "n"
send_line_to_vm " "
send_line_to_vm "n"
send_line_to_vm "n"
send_line_to_vm "n"
fi
2025-12-03 04:48:12 -03:00
#Wait for config changes to be saved
2025-04-15 15:20:46 +02:00
sleep 20
2025-12-03 04:48:12 -03:00
if [ -n " $WAN_BRG " ] && [ " $WAN_IP_ADDR " != "" ] ; then
2025-04-15 15:20:46 +02:00
send_line_to_vm "2"
send_line_to_vm "2"
send_line_to_vm "n"
send_line_to_vm " ${ WAN_IP_ADDR } "
2026-07-22 08:59:05 +02:00
send_line_to_vm " ${ WAN_NETMASK } "
send_line_to_vm " ${ WAN_GW } "
2025-04-15 15:20:46 +02:00
send_line_to_vm "n"
send_line_to_vm " "
send_line_to_vm "n"
send_line_to_vm " "
send_line_to_vm "n"
send_line_to_vm "n"
send_line_to_vm "n"
fi
sleep 10
send_line_to_vm "0"
msg_ok "Started OPNsense VM"
2025-02-11 20:07:51 +01:00
2026-01-06 22:57:40 +01:00
msg_ok "Completed successfully!\n"
2025-02-11 20:07:51 +01:00
if [ " $IP_ADDR " != "" ] ; then
echo -e " ${ INFO }${ YW } Access it using the following URL: ${ CL } "
echo -e " ${ TAB }${ GATEWAY }${ BGN } http:// ${ IP_ADDR }${ CL } "
else
echo -e " ${ INFO }${ YW } LAN IP was DHCP. ${ CL } "
echo -e " ${ INFO }${ BGN } To find the IP login to the VM shell ${ CL } "
fi