From 087f817bf614d521c0d003895295d32e3269894f Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Sat, 7 Mar 2026 15:44:44 +1000
Subject: [PATCH 01/22] misc scripts: add support for arm64
---
misc/build.func | 541 ++++++++++++++++++++++++++++------------------
misc/core.func | 7 +-
misc/install.func | 1 +
misc/tools.func | 2 +-
4 files changed, 334 insertions(+), 217 deletions(-)
diff --git a/misc/build.func b/misc/build.func
index 706e5b57c50..16bebd78279 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -3425,6 +3425,9 @@ start() {
set_std_mode
ensure_profile_loaded
get_lxc_ip
+ if [[ "$(dpkg --print-architecture)" == "arm64" ]] && declare -f update_script_arm64 >/dev/null 2>&1; then
+ update_script_arm64
+ fi
update_script
update_motd_ip
cleanup_lxc
@@ -3453,6 +3456,9 @@ start() {
esac
ensure_profile_loaded
get_lxc_ip
+ if [[ "$(dpkg --print-architecture)" == "arm64" ]] && declare -f update_script_arm64 >/dev/null 2>&1; then
+ update_script_arm64
+ fi
update_script
update_motd_ip
cleanup_lxc
@@ -4096,7 +4102,16 @@ EOF'
# that sends "configuring" status AFTER the host already reported "failed"
export CONTAINER_INSTALLING=true
- lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh)"
+ local _install_script
+ _install_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh")"
+ if [[ "$ARCH" == "arm64" ]]; then
+ local _arm_script
+ _arm_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/arm/${var_install}.sh" 2>/dev/null || true)"
+ if [[ -n "$_arm_script" ]]; then
+ _install_script="${_arm_script}"$'\n'"${_install_script}"
+ fi
+ fi
+ lxc-attach -n "$CTID" -- bash -c "$_install_script"
local lxc_exit=$?
unset CONTAINER_INSTALLING
@@ -4474,7 +4489,16 @@ EOF'
# Re-run install script in existing container (don't destroy/recreate)
set +Eeuo pipefail
trap - ERR
- lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh)"
+ local _install_script
+ _install_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh")"
+ if [[ "$ARCH" == "arm64" ]]; then
+ local _arm_script
+ _arm_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/arm/${var_install}.sh" 2>/dev/null || true)"
+ if [[ -n "$_arm_script" ]]; then
+ _install_script="${_arm_script}"$'\n'"${_install_script}"
+ fi
+ fi
+ lxc-attach -n "$CTID" -- bash -c "$_install_script"
local apt_retry_exit=$?
set -Eeuo pipefail
trap 'error_handler' ERR
@@ -4993,6 +5017,64 @@ create_lxc_container() {
esac
}
+ ARCH="$(dpkg --print-architecture)"
+
+ # Maps OS type + version to the release variant name used by ARM64 template sources.
+ arm64_template_variant() {
+ case "$1" in
+ debian)
+ case "$2" in
+ 11 | 11.*) echo "bullseye" ;; 12 | 12.*) echo "bookworm" ;;
+ 13 | 13.*) echo "trixie" ;; *) echo "trixie" ;;
+ esac ;;
+ alpine) echo "3.22" ;;
+ ubuntu)
+ case "$2" in
+ 20.04* | focal) echo "focal" ;; 24.04* | noble) echo "noble" ;;
+ 24.10* | oracular) echo "oracular" ;; *) echo "jammy" ;;
+ esac ;;
+ *) return 1 ;;
+ esac
+ }
+
+ # Downloads an ARM64 LXC rootfs template to $1.
+ # Debian: fetches latest release from asylumexp/debian-ifupdown2-lxc on GitHub.
+ # Others: fetches from jenkins.linuxcontainers.org.
+ download_arm64_template() {
+ local dest="$1" url
+
+ mkdir -p "$(dirname "$dest")" || { msg_error "Cannot create template dir."; exit 207; }
+
+ if [[ "$PCT_OSTYPE" == "debian" ]]; then
+ url=$(curl -fsSL "https://api.github.com/repos/asylumexp/debian-ifupdown2-lxc/releases/latest" \
+ | grep -Eo "https://[^\"]*debian-${CUSTOM_TEMPLATE_VARIANT}-arm64-rootfs\.tar\.xz" | head -n1)
+ [[ -n "$url" ]] || { msg_error "Could not find Debian ${CUSTOM_TEMPLATE_VARIANT} ARM64 template URL."; exit 207; }
+ else
+ url="https://jenkins.linuxcontainers.org/job/image-${PCT_OSTYPE}/architecture=arm64,release=${CUSTOM_TEMPLATE_VARIANT},variant=default/lastStableBuild/artifact/rootfs.tar.xz"
+ fi
+
+ msg_info "Downloading ${PCT_OSTYPE^} ${CUSTOM_TEMPLATE_VARIANT} ARM64 template"
+ if ! curl -fsSL -o "$dest" "$url"; then
+ msg_error "Failed to download ARM64 template from: $url"
+ exit 208
+ fi
+ msg_ok "Downloaded ARM64 LXC template"
+ }
+
+ # Architecture-aware template download wrapper.
+ # Optional $1 overrides destination path (for local-storage fallback).
+ download_template() {
+ local dest="${1:-$TEMPLATE_PATH}"
+ if [[ "$ARCH" == "arm64" ]]; then
+ download_arm64_template "$dest"
+ else
+ pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 || {
+ msg_error "Failed to download template '$TEMPLATE' to storage '$TEMPLATE_STORAGE'"
+ exit 222
+ }
+ fi
+ }
+
# ------------------------------------------------------------------------------
# Required input variables
# ------------------------------------------------------------------------------
@@ -5129,153 +5211,116 @@ create_lxc_container() {
# ------------------------------------------------------------------------------
# Template discovery & validation
# ------------------------------------------------------------------------------
- TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
- case "$PCT_OSTYPE" in
- debian | ubuntu) TEMPLATE_PATTERN="-standard_" ;;
- alpine | fedora | rocky | centos) TEMPLATE_PATTERN="-default_" ;;
- *) TEMPLATE_PATTERN="" ;;
- esac
+ CUSTOM_TEMPLATE_VARIANT=""
- msg_info "Searching for template '$TEMPLATE_SEARCH'"
+ if [[ "$ARCH" == "arm64" ]]; then
+ # ARM64: use custom template download from linuxcontainers.org / GitHub
+ msg_info "Preparing ARM64 template"
- # Initialize variables
- ONLINE_TEMPLATE=""
- ONLINE_TEMPLATES=()
+ CUSTOM_TEMPLATE_VARIANT=$(arm64_template_variant "$PCT_OSTYPE" "${PCT_OSVERSION:-}") || {
+ msg_error "No ARM64 template mapping for ${PCT_OSTYPE} ${PCT_OSVERSION:-latest}"
+ exit 207
+ }
- # Step 1: Check local templates first (instant)
- mapfile -t LOCAL_TEMPLATES < <(
- pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
- awk -v search="${TEMPLATE_SEARCH}" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
- sed 's|.*/||' | sort -t - -k 2 -V
- )
+ TEMPLATE="${PCT_OSTYPE}-${CUSTOM_TEMPLATE_VARIANT}-rootfs.tar.xz"
+ TEMPLATE_SOURCE="custom-arm64"
- # Step 2: If local template found, use it immediately (skip pveam update)
- if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
- TEMPLATE="${LOCAL_TEMPLATES[-1]}"
- TEMPLATE_SOURCE="local"
- msg_ok "Template search completed"
- else
- # Step 3: No local template - need to check online (this may be slow)
- msg_info "No local template found, checking online catalog..."
+ # Resolve template path: pvesm â storage.cfg fallback â default
+ TEMPLATE_PATH="$(pvesm path "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" 2>/dev/null || true)"
+ if [[ -z "$TEMPLATE_PATH" ]]; then
+ local _tpl_base
+ _tpl_base=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
+ TEMPLATE_PATH="${_tpl_base:-/var/lib/vz}/template/cache/$TEMPLATE"
+ fi
- # Update catalog with timeout to prevent long hangs
- if command -v timeout &>/dev/null; then
- if ! timeout 30 pveam update >/dev/null 2>&1; then
- msg_warn "Template catalog update timed out (possible network/DNS issue). Run 'pveam update' manually to diagnose."
- fi
+ # Download if missing, too small, or corrupt (single pass)
+ if [[ ! -f "$TEMPLATE_PATH" ]]; then
+ download_arm64_template "$TEMPLATE_PATH"
+ elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]] || ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
+ msg_warn "Local template invalid â re-downloading."
+ rm -f "$TEMPLATE_PATH"
+ download_arm64_template "$TEMPLATE_PATH"
else
- pveam update >/dev/null 2>&1 || msg_warn "Could not update template catalog (pveam update failed)"
+ msg_ok "Template ${BL}$TEMPLATE${CL} found locally."
fi
- ONLINE_TEMPLATES=()
- mapfile -t ONLINE_TEMPLATES < <(pveam available -section system 2>/dev/null | grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' | awk '{print $2}' | grep -E "^${TEMPLATE_SEARCH}.*${TEMPLATE_PATTERN}" | sort -t - -k 2 -V 2>/dev/null || true)
- [[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
-
- TEMPLATE="$ONLINE_TEMPLATE"
- TEMPLATE_SOURCE="online"
- msg_ok "Template search completed"
- fi
-
- # If still no template, try to find alternatives
- if [[ -z "$TEMPLATE" ]]; then
- msg_warn "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}, searching for alternatives..."
-
- # Get all available versions for this OS type
- AVAILABLE_VERSIONS=()
- mapfile -t AVAILABLE_VERSIONS < <(
- pveam available -section system 2>/dev/null |
- grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
- awk -F'\t' '{print $1}' |
- grep "^${PCT_OSTYPE}-" |
- sed -E "s/.*${PCT_OSTYPE}-([0-9]+(\.[0-9]+)?).*/\1/" |
- sort -u -V 2>/dev/null
- )
+ else
+ TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
+ case "$PCT_OSTYPE" in
+ debian | ubuntu) TEMPLATE_PATTERN="-standard_" ;;
+ alpine | fedora | rocky | centos) TEMPLATE_PATTERN="-default_" ;;
+ *) TEMPLATE_PATTERN="" ;;
+ esac
- if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
- echo ""
- echo "${BL}Available ${PCT_OSTYPE} versions:${CL}"
- for i in "${!AVAILABLE_VERSIONS[@]}"; do
- echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}"
- done
- echo ""
- read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or press Enter to cancel: " choice /dev/null |
- grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
- awk '{print $2}' |
- grep -E "^${TEMPLATE_SEARCH}-.*${TEMPLATE_PATTERN}" |
- sort -t - -k 2 -V 2>/dev/null || true
- )
+ # Step 1: Check local templates first (instant)
+ mapfile -t LOCAL_TEMPLATES < <(
+ pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
+ awk -v search="${TEMPLATE_SEARCH}" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
+ sed 's|.*/||' | sort -t - -k 2 -V
+ )
- if [[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]]; then
- TEMPLATE="${ONLINE_TEMPLATES[-1]}"
- TEMPLATE_SOURCE="online"
- else
- msg_error "No templates available for ${PCT_OSTYPE} ${PCT_OSVERSION}"
- exit 225
+ # Step 2: If local template found, use it immediately (skip pveam update)
+ if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
+ TEMPLATE="${LOCAL_TEMPLATES[-1]}"
+ TEMPLATE_SOURCE="local"
+ msg_ok "Template search completed"
+ else
+ # Step 3: No local template - need to check online (this may be slow)
+ msg_info "No local template found, checking online catalog..."
+
+ # Update catalog with timeout to prevent long hangs
+ if command -v timeout &>/dev/null; then
+ if ! timeout 30 pveam update >/dev/null 2>&1; then
+ msg_warn "Template catalog update timed out (possible network/DNS issue). Run 'pveam update' manually to diagnose."
fi
else
- msg_custom "đĢ" "${YW}" "Installation cancelled"
- exit 0
+ pveam update >/dev/null 2>&1 || msg_warn "Could not update template catalog (pveam update failed)"
fi
- else
- msg_error "No ${PCT_OSTYPE} templates available at all"
- exit 225
- fi
- fi
- TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
- if [[ -z "$TEMPLATE_PATH" ]]; then
- TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
- [[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
- fi
+ ONLINE_TEMPLATES=()
+ mapfile -t ONLINE_TEMPLATES < <(pveam available -section system 2>/dev/null | grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' | awk '{print $2}' | grep -E "^${TEMPLATE_SEARCH}.*${TEMPLATE_PATTERN}" | sort -t - -k 2 -V 2>/dev/null || true)
+ [[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
- # If we still don't have a path but have a valid template name, construct it
- if [[ -z "$TEMPLATE_PATH" && -n "$TEMPLATE" ]]; then
- TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
- fi
+ TEMPLATE="$ONLINE_TEMPLATE"
+ TEMPLATE_SOURCE="online"
+ msg_ok "Template search completed"
+ fi
- [[ -n "$TEMPLATE_PATH" ]] || {
+ # If still no template, try to find alternatives
if [[ -z "$TEMPLATE" ]]; then
- msg_error "Template ${PCT_OSTYPE} ${PCT_OSVERSION} not available"
+ msg_warn "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}, searching for alternatives..."
- # Get available versions
+ # Get all available versions for this OS type
+ AVAILABLE_VERSIONS=()
mapfile -t AVAILABLE_VERSIONS < <(
pveam available -section system 2>/dev/null |
+ grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
+ awk -F'\t' '{print $1}' |
grep "^${PCT_OSTYPE}-" |
- sed -E 's/.*'"${PCT_OSTYPE}"'-([0-9]+\.[0-9]+).*/\1/' |
- grep -E '^[0-9]+\.[0-9]+$' |
- sort -u -V 2>/dev/null || sort -u
+ sed -E "s/.*${PCT_OSTYPE}-([0-9]+(\.[0-9]+)?).*/\1/" |
+ sort -u -V 2>/dev/null
)
if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
- echo -e "\n${BL}Available versions:${CL}"
+ echo ""
+ echo "${BL}Available ${PCT_OSTYPE} versions:${CL}"
for i in "${!AVAILABLE_VERSIONS[@]}"; do
echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}"
done
-
echo ""
- read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or Enter to exit: " choice /dev/null |
- awk -v search="${TEMPLATE_SEARCH}-" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
- sed 's|.*/||' | sort -t - -k 2 -V
- )
+ ONLINE_TEMPLATES=()
mapfile -t ONLINE_TEMPLATES < <(
pveam available -section system 2>/dev/null |
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
@@ -5283,109 +5328,181 @@ create_lxc_container() {
grep -E "^${TEMPLATE_SEARCH}-.*${TEMPLATE_PATTERN}" |
sort -t - -k 2 -V 2>/dev/null || true
)
- ONLINE_TEMPLATE=""
- [[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
- if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
- TEMPLATE="${LOCAL_TEMPLATES[-1]}"
- TEMPLATE_SOURCE="local"
- else
- TEMPLATE="$ONLINE_TEMPLATE"
+ if [[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]]; then
+ TEMPLATE="${ONLINE_TEMPLATES[-1]}"
TEMPLATE_SOURCE="online"
+ else
+ msg_error "No templates available for ${PCT_OSTYPE} ${PCT_OSVERSION}"
+ exit 225
fi
-
- TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
- if [[ -z "$TEMPLATE_PATH" ]]; then
- TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
- [[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
- fi
-
- # If we still don't have a path but have a valid template name, construct it
- if [[ -z "$TEMPLATE_PATH" && -n "$TEMPLATE" ]]; then
- TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
- fi
-
- [[ -n "$TEMPLATE_PATH" ]] || {
- msg_error "Template still not found after version change"
- exit 220
- }
else
msg_custom "đĢ" "${YW}" "Installation cancelled"
exit 0
fi
else
- msg_error "No ${PCT_OSTYPE} templates available"
- exit 220
+ msg_error "No ${PCT_OSTYPE} templates available at all"
+ exit 225
fi
fi
- }
- # Validate that we found a template
- if [[ -z "$TEMPLATE" ]]; then
- msg_error "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}"
- msg_custom "âšī¸" "${YW}" "Please check:"
- msg_custom " âĸ" "${YW}" "Is pveam catalog available? (run: pveam available -section system)"
- msg_custom " âĸ" "${YW}" "Does the template exist for your OS version?"
- exit 225
- fi
-
- msg_ok "Template ${BL}$TEMPLATE${CL} [$TEMPLATE_SOURCE]"
- msg_debug "Resolved TEMPLATE_PATH=$TEMPLATE_PATH"
-
- NEED_DOWNLOAD=0
- if [[ ! -f "$TEMPLATE_PATH" ]]; then
- msg_info "Template not present locally â will download."
- NEED_DOWNLOAD=1
- elif [[ ! -r "$TEMPLATE_PATH" ]]; then
- msg_error "Template file exists but is not readable â check permissions."
- exit 221
- elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
- if [[ -n "$ONLINE_TEMPLATE" ]]; then
- msg_warn "Template file too small (<1MB) â re-downloading."
- NEED_DOWNLOAD=1
- else
- msg_warn "Template looks too small, but no online version exists. Keeping local file."
+ TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
+ if [[ -z "$TEMPLATE_PATH" ]]; then
+ TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
+ [[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
fi
- elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
- if [[ -n "$ONLINE_TEMPLATE" ]]; then
- msg_warn "Template appears corrupted â re-downloading."
- NEED_DOWNLOAD=1
- else
- msg_warn "Template appears corrupted, but no online version exists. Keeping local file."
+
+ # If we still don't have a path but have a valid template name, construct it
+ if [[ -z "$TEMPLATE_PATH" && -n "$TEMPLATE" ]]; then
+ TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
fi
- else
- $STD msg_ok "Template $TEMPLATE is present and valid."
- fi
- if [[ "$TEMPLATE_SOURCE" == "local" && -n "$ONLINE_TEMPLATE" && "$TEMPLATE" != "$ONLINE_TEMPLATE" ]]; then
- msg_warn "Local template is outdated: $TEMPLATE (latest available: $ONLINE_TEMPLATE)"
- if whiptail --yesno "A newer template is available:\n$ONLINE_TEMPLATE\n\nDo you want to download and use it instead?" 12 70; then
- TEMPLATE="$ONLINE_TEMPLATE"
+ [[ -n "$TEMPLATE_PATH" ]] || {
+ if [[ -z "$TEMPLATE" ]]; then
+ msg_error "Template ${PCT_OSTYPE} ${PCT_OSVERSION} not available"
+
+ # Get available versions
+ mapfile -t AVAILABLE_VERSIONS < <(
+ pveam available -section system 2>/dev/null |
+ grep "^${PCT_OSTYPE}-" |
+ sed -E 's/.*'"${PCT_OSTYPE}"'-([0-9]+\.[0-9]+).*/\1/' |
+ grep -E '^[0-9]+\.[0-9]+$' |
+ sort -u -V 2>/dev/null || sort -u
+ )
+
+ if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
+ echo -e "\n${BL}Available versions:${CL}"
+ for i in "${!AVAILABLE_VERSIONS[@]}"; do
+ echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}"
+ done
+
+ echo ""
+ read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or Enter to exit: " choice /dev/null |
+ awk -v search="${TEMPLATE_SEARCH}-" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
+ sed 's|.*/||' | sort -t - -k 2 -V
+ )
+ mapfile -t ONLINE_TEMPLATES < <(
+ pveam available -section system 2>/dev/null |
+ grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
+ awk '{print $2}' |
+ grep -E "^${TEMPLATE_SEARCH}-.*${TEMPLATE_PATTERN}" |
+ sort -t - -k 2 -V 2>/dev/null || true
+ )
+ ONLINE_TEMPLATE=""
+ [[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
+
+ if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
+ TEMPLATE="${LOCAL_TEMPLATES[-1]}"
+ TEMPLATE_SOURCE="local"
+ else
+ TEMPLATE="$ONLINE_TEMPLATE"
+ TEMPLATE_SOURCE="online"
+ fi
+
+ TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
+ if [[ -z "$TEMPLATE_PATH" ]]; then
+ TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
+ [[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
+ fi
+
+ # If we still don't have a path but have a valid template name, construct it
+ if [[ -z "$TEMPLATE_PATH" && -n "$TEMPLATE" ]]; then
+ TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
+ fi
+
+ [[ -n "$TEMPLATE_PATH" ]] || {
+ msg_error "Template still not found after version change"
+ exit 220
+ }
+ else
+ msg_custom "đĢ" "${YW}" "Installation cancelled"
+ exit 0
+ fi
+ else
+ msg_error "No ${PCT_OSTYPE} templates available"
+ exit 220
+ fi
+ fi
+ }
+
+ # Validate that we found a template
+ if [[ -z "$TEMPLATE" ]]; then
+ msg_error "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}"
+ msg_custom "âšī¸" "${YW}" "Please check:"
+ msg_custom " âĸ" "${YW}" "Is pveam catalog available? (run: pveam available -section system)"
+ msg_custom " âĸ" "${YW}" "Does the template exist for your OS version?"
+ exit 225
+ fi
+
+ msg_ok "Template ${BL}$TEMPLATE${CL} [$TEMPLATE_SOURCE]"
+ msg_debug "Resolved TEMPLATE_PATH=$TEMPLATE_PATH"
+
+ NEED_DOWNLOAD=0
+ if [[ ! -f "$TEMPLATE_PATH" ]]; then
+ msg_info "Template not present locally â will download."
NEED_DOWNLOAD=1
+ elif [[ ! -r "$TEMPLATE_PATH" ]]; then
+ msg_error "Template file exists but is not readable â check permissions."
+ exit 221
+ elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
+ if [[ -n "$ONLINE_TEMPLATE" ]]; then
+ msg_warn "Template file too small (<1MB) â re-downloading."
+ NEED_DOWNLOAD=1
+ else
+ msg_warn "Template looks too small, but no online version exists. Keeping local file."
+ fi
+ elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
+ if [[ -n "$ONLINE_TEMPLATE" ]]; then
+ msg_warn "Template appears corrupted â re-downloading."
+ NEED_DOWNLOAD=1
+ else
+ msg_warn "Template appears corrupted, but no online version exists. Keeping local file."
+ fi
else
- msg_custom "âšī¸" "${BL}" "Continuing with local template $TEMPLATE"
+ $STD msg_ok "Template $TEMPLATE is present and valid."
fi
- fi
- if [[ "$NEED_DOWNLOAD" -eq 1 ]]; then
- [[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
- for attempt in {1..3}; do
- msg_info "Attempt $attempt: Downloading template $TEMPLATE to $TEMPLATE_STORAGE"
- if pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1; then
- msg_ok "Template download successful."
- break
- fi
- if [[ $attempt -eq 3 ]]; then
- msg_error "Failed after 3 attempts. Please check network access, permissions, or manually run:\n pveam download $TEMPLATE_STORAGE $TEMPLATE"
- exit 222
+ if [[ "$TEMPLATE_SOURCE" == "local" && -n "$ONLINE_TEMPLATE" && "$TEMPLATE" != "$ONLINE_TEMPLATE" ]]; then
+ msg_warn "Local template is outdated: $TEMPLATE (latest available: $ONLINE_TEMPLATE)"
+ if whiptail --yesno "A newer template is available:\n$ONLINE_TEMPLATE\n\nDo you want to download and use it instead?" 12 70; then
+ TEMPLATE="$ONLINE_TEMPLATE"
+ NEED_DOWNLOAD=1
+ else
+ msg_custom "âšī¸" "${BL}" "Continuing with local template $TEMPLATE"
fi
- sleep $((attempt * 5))
- done
- fi
+ fi
+
+ if [[ "$NEED_DOWNLOAD" -eq 1 ]]; then
+ [[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
+ for attempt in {1..3}; do
+ msg_info "Attempt $attempt: Downloading template $TEMPLATE to $TEMPLATE_STORAGE"
+ if pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1; then
+ msg_ok "Template download successful."
+ break
+ fi
+ if [[ $attempt -eq 3 ]]; then
+ msg_error "Failed after 3 attempts. Please check network access, permissions, or manually run:\n pveam download $TEMPLATE_STORAGE $TEMPLATE"
+ exit 222
+ fi
+ sleep $((attempt * 5))
+ done
+ fi
- if ! pveam list "$TEMPLATE_STORAGE" 2>/dev/null | grep -q "$TEMPLATE"; then
- msg_error "Template $TEMPLATE not available in storage $TEMPLATE_STORAGE after download."
- exit 223
+ if ! pveam list "$TEMPLATE_STORAGE" 2>/dev/null | grep -q "$TEMPLATE"; then
+ msg_error "Template $TEMPLATE not available in storage $TEMPLATE_STORAGE after download."
+ exit 223
+ fi
fi
# ------------------------------------------------------------------------------
@@ -5464,19 +5581,13 @@ create_lxc_container() {
if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH" 2>/dev/null || echo 0)" -lt 1000000 ]]; then
msg_info "Template file missing or too small â downloading"
rm -f "$TEMPLATE_PATH"
- pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 || {
- msg_error "Failed to download template '$TEMPLATE' to storage '$TEMPLATE_STORAGE'"
- exit 222
- }
+ download_template
msg_ok "Template downloaded"
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
- if [[ -n "$ONLINE_TEMPLATE" ]]; then
+ if [[ "$ARCH" == "arm64" || -n "$ONLINE_TEMPLATE" ]]; then
msg_info "Template appears corrupted â re-downloading"
rm -f "$TEMPLATE_PATH"
- pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 || {
- msg_error "Failed to re-download template '$TEMPLATE'"
- exit 222
- }
+ download_template
msg_ok "Template re-downloaded"
else
msg_warn "Template appears corrupted, but no online version exists. Skipping re-download."
@@ -5497,7 +5608,7 @@ create_lxc_container() {
if grep -qiE 'unable to open|corrupt|invalid' "$LOGFILE"; then
msg_info "Template may be corrupted â re-downloading"
rm -f "$TEMPLATE_PATH"
- pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1
+ download_template
msg_ok "Template re-downloaded"
fi
@@ -5510,7 +5621,11 @@ create_lxc_container() {
if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then
msg_ok "Trying local storage fallback"
msg_info "Downloading template to local"
- pveam download local "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1
+ if [[ "$ARCH" == "arm64" ]]; then
+ download_arm64_template "$LOCAL_TEMPLATE_PATH"
+ else
+ pveam download local "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1
+ fi
msg_ok "Template downloaded to local"
else
msg_ok "Trying local storage fallback"
@@ -5646,15 +5761,15 @@ description() {
- GitHub
+ GitHub
- Discussions
+ Discussions
- Issues
+ Issues
EOF
diff --git a/misc/core.func b/misc/core.func
index e3b9d2cff2e..980dfe11124 100644
--- a/misc/core.func
+++ b/misc/core.func
@@ -344,9 +344,10 @@ pve_check() {
# - Provides link to ARM64-compatible scripts
# ------------------------------------------------------------------------------
arch_check() {
- if [ "$(dpkg --print-architecture)" != "amd64" ]; then
- msg_error "This script will not work with PiMox (ARM architecture detected)."
- msg_warn "Visit https://github.com/asylumexp/Proxmox for ARM64 support."
+ local arch
+ arch="$(dpkg --print-architecture)"
+ if [[ "$arch" != "amd64" && "$arch" != "arm64" ]]; then
+ msg_error "This script requires amd64 or arm64 (detected: $arch)."
sleep 2
exit 106
fi
diff --git a/misc/install.func b/misc/install.func
index 94f005b26f9..4e39b69daae 100644
--- a/misc/install.func
+++ b/misc/install.func
@@ -235,6 +235,7 @@ EOF
fi
apt_update_safe
$STD apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade
+ $STD apt-get install -y sudo curl mc gnupg2 openssh-server wget gcc
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
msg_ok "Updated Container OS"
post_progress_to_api
diff --git a/misc/tools.func b/misc/tools.func
index cce5f303bee..c4de1036cae 100644
--- a/misc/tools.func
+++ b/misc/tools.func
@@ -3267,7 +3267,7 @@ function fetch_and_deploy_gh_release() {
fi
if [[ -z "$url_match" ]]; then
for u in $assets; do
- if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then
+ if [[ "$u" =~ ($arch|aarch64|arm64).*\.deb$ ]]; then
url_match="$u"
break
fi
From 6f62656c96d33e4571ef03477d7882ac5b74a377 Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Sat, 7 Mar 2026 15:55:21 +1000
Subject: [PATCH 02/22] Replace tools.func call that checks arch
---
misc/tools.func | 33 +++++++++++++++++++++++----------
1 file changed, 23 insertions(+), 10 deletions(-)
diff --git a/misc/tools.func b/misc/tools.func
index c4de1036cae..95ab71bc479 100644
--- a/misc/tools.func
+++ b/misc/tools.func
@@ -2735,10 +2735,13 @@ function fetch_and_deploy_codeberg_release() {
# Fall back to architecture heuristic
if [[ -z "$url_match" ]]; then
for u in $assets; do
- if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then
- url_match="$u"
- break
+ if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
+ [[ "$u" =~ (amd64|x86_64).*\.deb$ ]] || continue
+ elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
+ [[ "$u" =~ (arm64|aarch64).*\.deb$ ]] || continue
fi
+ url_match="$u"
+ break
done
fi
@@ -3035,7 +3038,11 @@ _gh_scan_older_releases() {
done)
fi
if [[ "$has_match" != "true" ]]; then
- has_match=$(echo "$releases_list" | jq -r ".[$i].assets[].browser_download_url" | grep -qE "($arch|amd64|x86_64|aarch64|arm64).*\.deb$" && echo true)
+ if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
+ has_match=$(echo "$releases_list" | jq -r ".[$i].assets[].browser_download_url" | grep -qE '(amd64|x86_64).*\.deb$' && echo true)
+ elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
+ has_match=$(echo "$releases_list" | jq -r ".[$i].assets[].browser_download_url" | grep -qE '(arm64|aarch64).*\.deb$' && echo true)
+ fi
fi
if [[ "$has_match" != "true" ]]; then
has_match=$(echo "$releases_list" | jq -r ".[$i].assets[].browser_download_url" | grep -qE '\.deb$' && echo true)
@@ -3233,10 +3240,13 @@ function fetch_and_deploy_gh_release() {
# If no match via explicit pattern, fall back to architecture heuristic
if [[ -z "$url_match" ]]; then
for u in $assets; do
- if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then
- url_match="$u"
- break
+ if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
+ [[ "$u" =~ (amd64|x86_64).*\.deb$ ]] || continue
+ elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
+ [[ "$u" =~ (arm64|aarch64).*\.deb$ ]] || continue
fi
+ url_match="$u"
+ break
done
fi
@@ -3267,10 +3277,13 @@ function fetch_and_deploy_gh_release() {
fi
if [[ -z "$url_match" ]]; then
for u in $assets; do
- if [[ "$u" =~ ($arch|aarch64|arm64).*\.deb$ ]]; then
- url_match="$u"
- break
+ if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
+ [[ "$u" =~ (amd64|x86_64).*\.deb$ ]] || continue
+ elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
+ [[ "$u" =~ (arm64|aarch64).*\.deb$ ]] || continue
fi
+ url_match="$u"
+ break
done
fi
if [[ -z "$url_match" ]]; then
From b9d401b17821d27b046dd67f18e902a09ea012f9 Mon Sep 17 00:00:00 2001
From: Sam Heinz
Date: Wed, 11 Mar 2026 09:56:18 +1000
Subject: [PATCH 03/22] Update misc/build.func
Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>
---
misc/build.func | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/misc/build.func b/misc/build.func
index 16bebd78279..97fefada9e4 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -5453,7 +5453,7 @@ create_lxc_container() {
msg_info "Template not present locally â will download."
NEED_DOWNLOAD=1
elif [[ ! -r "$TEMPLATE_PATH" ]]; then
- msg_error "Template file exists but is not readable â check permissions."
+ msg_error "Template file exists but is not readable, check permissions."
exit 221
elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
if [[ -n "$ONLINE_TEMPLATE" ]]; then
From e4db6be2573b7fe407fd9f0b9b655f2daa8555d5 Mon Sep 17 00:00:00 2001
From: Sam Heinz
Date: Wed, 11 Mar 2026 09:56:34 +1000
Subject: [PATCH 04/22] Update misc/build.func
Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>
---
misc/build.func | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/misc/build.func b/misc/build.func
index 97fefada9e4..fc3d6e89c15 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -5450,7 +5450,7 @@ create_lxc_container() {
NEED_DOWNLOAD=0
if [[ ! -f "$TEMPLATE_PATH" ]]; then
- msg_info "Template not present locally â will download."
+ msg_info "Template not present locally, will download it."
NEED_DOWNLOAD=1
elif [[ ! -r "$TEMPLATE_PATH" ]]; then
msg_error "Template file exists but is not readable, check permissions."
From a6a83b9541f30dd61d5588078ae95f5481e6044a Mon Sep 17 00:00:00 2001
From: Sam Heinz
Date: Wed, 11 Mar 2026 09:59:42 +1000
Subject: [PATCH 05/22] Update misc/build.func
Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>
---
misc/build.func | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/misc/build.func b/misc/build.func
index fc3d6e89c15..56aa7c5c662 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -5457,7 +5457,7 @@ create_lxc_container() {
exit 221
elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
if [[ -n "$ONLINE_TEMPLATE" ]]; then
- msg_warn "Template file too small (<1MB) â re-downloading."
+ msg_warn "Template file too small (<1MB), re-downloading."
NEED_DOWNLOAD=1
else
msg_warn "Template looks too small, but no online version exists. Keeping local file."
From 78979189c1ee622707788133a8624fd8b057bcdd Mon Sep 17 00:00:00 2001
From: Sam Heinz
Date: Wed, 11 Mar 2026 10:19:58 +1000
Subject: [PATCH 06/22] Update misc/build.func
Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>
---
misc/build.func | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/misc/build.func b/misc/build.func
index 56aa7c5c662..f846a7535da 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -5464,7 +5464,7 @@ create_lxc_container() {
fi
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
if [[ -n "$ONLINE_TEMPLATE" ]]; then
- msg_warn "Template appears corrupted â re-downloading."
+ msg_warn "Template appears corrupted, re-downloading."
NEED_DOWNLOAD=1
else
msg_warn "Template appears corrupted, but no online version exists. Keeping local file."
From 35b3b93ca61da66ba1721106e10d837711221aa5 Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Wed, 11 Mar 2026 20:59:33 +1000
Subject: [PATCH 07/22] build.func: change back to VE
---
misc/build.func | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/misc/build.func b/misc/build.func
index f846a7535da..1c3f5f78d19 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -5341,7 +5341,7 @@ create_lxc_container() {
exit 0
fi
else
- msg_error "No ${PCT_OSTYPE} templates available at all"
+ msg_error "No ${PCT_OSTYPE} templates available"
exit 225
fi
fi
@@ -5377,7 +5377,7 @@ create_lxc_container() {
done
echo ""
- read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or Enter to exit: " choice
- GitHub
+ GitHub
- Discussions
+ Discussions
- Issues
+ Issues
EOF
From 6f8aa6eadc142dd81a07275d86e3b59821436973 Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Wed, 11 Mar 2026 21:17:38 +1000
Subject: [PATCH 08/22] build.func: remove arm64 support for focal, bullseye
Legacy support removed since no cts use them anymore.
---
misc/build.func | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/misc/build.func b/misc/build.func
index 1c3f5f78d19..1bf45a69f3f 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -5024,14 +5024,14 @@ create_lxc_container() {
case "$1" in
debian)
case "$2" in
- 11 | 11.*) echo "bullseye" ;; 12 | 12.*) echo "bookworm" ;;
- 13 | 13.*) echo "trixie" ;; *) echo "trixie" ;;
+ 12 | 12.*) echo "bookworm" ;; 13 | 13.*) echo "trixie" ;;
+ *) echo "trixie" ;;
esac ;;
alpine) echo "3.22" ;;
ubuntu)
case "$2" in
- 20.04* | focal) echo "focal" ;; 24.04* | noble) echo "noble" ;;
- 24.10* | oracular) echo "oracular" ;; *) echo "jammy" ;;
+ 24.04* | noble) echo "noble" ;; 24.10* | oracular) echo "oracular" ;;
+ *) echo "jammy" ;;
esac ;;
*) return 1 ;;
esac
From 7c051fb64891f72ce030896a3ac14375031c98b4 Mon Sep 17 00:00:00 2001
From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com>
Date: Wed, 11 Mar 2026 14:23:56 +0100
Subject: [PATCH 09/22] Improve arm64 support and arch-specific downloads
Add clearer architecture error messages and gate arm64 usage, plus implement architecture-aware behavior across the toolkit. Changes include: update exit-code messages to reference amd64/arm64, refuse arm64 unless explicitly enabled, show architecture in summaries, and use arch-specific package lists when installing in containers. Make downloads for FFmpeg and yq choose the correct amd64/arm64 binaries, tighten template download error handling and formatting, and clean up minor whitespace/comment issues. These changes aim to make arm64 handling explicit and downloads/installations more robust for non-amd64 systems.
---
misc/api.func | 10 +--
misc/build.func | 153 +++++++++++++++++++++-------------------
misc/core.func | 5 ++
misc/error_handler.func | 2 +-
misc/install.func | 1 -
misc/tools.func | 21 +++++-
6 files changed, 110 insertions(+), 82 deletions(-)
diff --git a/misc/api.func b/misc/api.func
index e29975e2cc6..7815d4a33e1 100644
--- a/misc/api.func
+++ b/misc/api.func
@@ -196,7 +196,7 @@ explain_exit_code() {
103) echo "Validation: Shell is not Bash" ;;
104) echo "Validation: Not running as root (or invoked via sudo)" ;;
105) echo "Validation: Proxmox VE version not supported" ;;
- 106) echo "Validation: Architecture not supported (ARM / PiMox)" ;;
+ 106) echo "Validation: Unsupported architecture (requires amd64 or arm64)" ;;
107) echo "Validation: Kernel key parameters unreadable" ;;
108) echo "Validation: Kernel key limits exceeded" ;;
109) echo "Proxmox: No available container ID after max attempts" ;;
@@ -348,10 +348,10 @@ explain_exit_code() {
json_escape() {
# Escape a string for safe JSON embedding using awk (handles any input size).
# Pipeline: strip ANSI â remove control chars â escape \ " TAB â join lines with \n
- printf '%s' "$1" \
- | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' \
- | tr -d '\000-\010\013\014\016-\037\177\r' \
- | awk '
+ printf '%s' "$1" |
+ sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' |
+ tr -d '\000-\010\013\014\016-\037\177\r' |
+ awk '
BEGIN { ORS = "" }
{
gsub(/\\/, "\\\\") # backslash â \\
diff --git a/misc/build.func b/misc/build.func
index 1bf45a69f3f..5ce216cd94d 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -1826,9 +1826,9 @@ advanced_settings() {
while [ $STEP -le $MAX_STEP ]; do
case $STEP in
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 1: Container Type
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
1)
local default_on="ON"
local default_off="OFF"
@@ -1851,9 +1851,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 2: Root Password
- # ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââīŋŊīŋŊīŋŊââ
+ # ------------------------------------------------------------------------------
2)
if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "ROOT PASSWORD" \
@@ -1905,9 +1905,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 3: Container ID
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
3)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "CONTAINER ID" \
@@ -1939,9 +1939,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 4: Hostname
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
4)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "HOSTNAME" \
@@ -1962,9 +1962,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 5: Disk Size
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
5)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "DISK SIZE" \
@@ -1983,9 +1983,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 6: CPU Cores
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
6)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "CPU CORES" \
@@ -2004,9 +2004,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 7: RAM Size
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
7)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "RAM SIZE" \
@@ -2025,9 +2025,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 8: Network Bridge
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
8)
if [[ ${#BRIDGE_MENU_OPTIONS[@]} -eq 0 ]]; then
# Validate default bridge exists
@@ -2063,9 +2063,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 9: IPv4 Configuration
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
9)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "IPv4 CONFIGURATION" \
@@ -2160,9 +2160,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 10: IPv6 Configuration
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
10)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "IPv6 CONFIGURATION" \
@@ -2235,9 +2235,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 11: MTU Size
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
11)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "MTU SIZE" \
@@ -2255,9 +2255,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 12: DNS Search Domain
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
12)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "DNS SEARCH DOMAIN" \
@@ -2271,9 +2271,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 13: DNS Server
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
13)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "DNS SERVER" \
@@ -2287,9 +2287,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 14: MAC Address
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
14)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "MAC ADDRESS" \
@@ -2307,9 +2307,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 15: VLAN Tag
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
15)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "VLAN TAG" \
@@ -2327,9 +2327,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 16: Tags
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
16)
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "CONTAINER TAGS" \
@@ -2349,18 +2349,18 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 17: SSH Settings
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
17)
configure_ssh_settings "Step $STEP/$MAX_STEP"
# configure_ssh_settings handles its own flow, always advance
((STEP++))
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 18: FUSE Support
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
18)
local fuse_default_flag="--defaultno"
[[ "$_enable_fuse" == "yes" || "$_enable_fuse" == "1" ]] && fuse_default_flag=""
@@ -2382,9 +2382,9 @@ advanced_settings() {
((STEP++))
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 19: TUN/TAP Support
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
19)
local tun_default_flag="--defaultno"
[[ "$_enable_tun" == "yes" || "$_enable_tun" == "1" ]] && tun_default_flag=""
@@ -2406,9 +2406,9 @@ advanced_settings() {
((STEP++))
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 20: Nesting Support
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
20)
local nesting_default_flag=""
[[ "$_enable_nesting" == "0" || "$_enable_nesting" == "no" ]] && nesting_default_flag="--defaultno"
@@ -2436,9 +2436,9 @@ advanced_settings() {
((STEP++))
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 21: GPU Passthrough
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
21)
local gpu_default_flag="--defaultno"
[[ "$_enable_gpu" == "yes" ]] && gpu_default_flag=""
@@ -2460,9 +2460,9 @@ advanced_settings() {
((STEP++))
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 22: Keyctl Support (Docker/systemd)
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
22)
local keyctl_default_flag="--defaultno"
[[ "$_enable_keyctl" == "1" ]] && keyctl_default_flag=""
@@ -2484,9 +2484,9 @@ advanced_settings() {
((STEP++))
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 23: APT Cacher Proxy
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
23)
local apt_cacher_default_flag="--defaultno"
[[ "$_apt_cacher" == "yes" ]] && apt_cacher_default_flag=""
@@ -2516,9 +2516,9 @@ advanced_settings() {
((STEP++))
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 24: Container Timezone
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
24)
local tz_hint="$_ct_timezone"
[[ -z "$tz_hint" ]] && tz_hint="(empty - will use host timezone)"
@@ -2541,9 +2541,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 25: Container Protection
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
25)
local protect_default_flag="--defaultno"
[[ "$_protect_ct" == "yes" || "$_protect_ct" == "1" ]] && protect_default_flag=""
@@ -2565,9 +2565,9 @@ advanced_settings() {
((STEP++))
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 26: Device Node Creation (mknod)
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
26)
local mknod_default_flag="--defaultno"
[[ "$_enable_mknod" == "1" ]] && mknod_default_flag=""
@@ -2589,9 +2589,9 @@ advanced_settings() {
((STEP++))
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 27: Mount Filesystems
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
27)
local mount_hint=""
[[ -n "$_mount_fs" ]] && mount_hint="$_mount_fs" || mount_hint="(none)"
@@ -2608,9 +2608,9 @@ advanced_settings() {
fi
;;
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# STEP 28: Verbose Mode & Confirmation
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
28)
local verbose_default_flag="--defaultno"
[[ "$_verbose" == "yes" ]] && verbose_default_flag=""
@@ -2676,9 +2676,9 @@ Advanced:
esac
done
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
# Apply all collected values to global variables
- # âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ # ------------------------------------------------------------------------------
CT_TYPE="$_ct_type"
PW="$_pw"
CT_ID="$_ct_id"
@@ -2895,6 +2895,9 @@ echo_default() {
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}"
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
+ if [[ "$(dpkg --print-architecture)" == "arm64" ]]; then
+ echo -e "${INFO}${BOLD}${DGN}Architecture: ${BGN}arm64${CL}"
+ fi
if [[ -n "${var_gpu:-}" && "${var_gpu}" == "yes" ]]; then
echo -e "${GPU}${BOLD}${DGN}GPU Passthrough: ${BGN}Enabled${CL}"
fi
@@ -3425,9 +3428,6 @@ start() {
set_std_mode
ensure_profile_loaded
get_lxc_ip
- if [[ "$(dpkg --print-architecture)" == "arm64" ]] && declare -f update_script_arm64 >/dev/null 2>&1; then
- update_script_arm64
- fi
update_script
update_motd_ip
cleanup_lxc
@@ -3456,9 +3456,6 @@ start() {
esac
ensure_profile_loaded
get_lxc_ip
- if [[ "$(dpkg --print-architecture)" == "arm64" ]] && declare -f update_script_arm64 >/dev/null 2>&1; then
- update_script_arm64
- fi
update_script
update_motd_ip
cleanup_lxc
@@ -4071,7 +4068,11 @@ EOF'
msg_warn "Skipping timezone setup â zone '$tz' not found in container"
fi
- pct exec "$CTID" -- bash -c "apt-get update 2>&1 && apt-get install -y sudo curl mc gnupg2 jq 2>&1" >>"$BUILD_LOG" 2>&1 || {
+ local _base_pkgs="sudo curl mc gnupg2 jq"
+ if [[ "${ARCH:-amd64}" == "arm64" ]]; then
+ _base_pkgs+=" openssh-server wget gcc"
+ fi
+ pct exec "$CTID" -- bash -c "apt-get update 2>&1 && apt-get install -y ${_base_pkgs} 2>&1" >>"$BUILD_LOG" 2>&1 || {
msg_error "apt-get base packages installation failed"
install_exit_code=1
}
@@ -5026,13 +5027,15 @@ create_lxc_container() {
case "$2" in
12 | 12.*) echo "bookworm" ;; 13 | 13.*) echo "trixie" ;;
*) echo "trixie" ;;
- esac ;;
+ esac
+ ;;
alpine) echo "3.22" ;;
ubuntu)
case "$2" in
- 24.04* | noble) echo "noble" ;; 24.10* | oracular) echo "oracular" ;;
+ 24.04* | noble) echo "noble" ;; 24.10* | oracular) echo "oracular" ;;
*) echo "jammy" ;;
- esac ;;
+ esac
+ ;;
*) return 1 ;;
esac
}
@@ -5043,12 +5046,18 @@ create_lxc_container() {
download_arm64_template() {
local dest="$1" url
- mkdir -p "$(dirname "$dest")" || { msg_error "Cannot create template dir."; exit 207; }
+ mkdir -p "$(dirname "$dest")" || {
+ msg_error "Cannot create template dir."
+ exit 207
+ }
if [[ "$PCT_OSTYPE" == "debian" ]]; then
- url=$(curl -fsSL "https://api.github.com/repos/asylumexp/debian-ifupdown2-lxc/releases/latest" \
- | grep -Eo "https://[^\"]*debian-${CUSTOM_TEMPLATE_VARIANT}-arm64-rootfs\.tar\.xz" | head -n1)
- [[ -n "$url" ]] || { msg_error "Could not find Debian ${CUSTOM_TEMPLATE_VARIANT} ARM64 template URL."; exit 207; }
+ url=$(curl -fsSL "https://api.github.com/repos/asylumexp/debian-ifupdown2-lxc/releases/latest" |
+ grep -Eo "https://[^\"]*debian-${CUSTOM_TEMPLATE_VARIANT}-arm64-rootfs\.tar\.xz" | head -n1)
+ [[ -n "$url" ]] || {
+ msg_error "Could not find Debian ${CUSTOM_TEMPLATE_VARIANT} ARM64 template URL."
+ exit 207
+ }
else
url="https://jenkins.linuxcontainers.org/job/image-${PCT_OSTYPE}/architecture=arm64,release=${CUSTOM_TEMPLATE_VARIANT},variant=default/lastStableBuild/artifact/rootfs.tar.xz"
fi
diff --git a/misc/core.func b/misc/core.func
index 980dfe11124..7d44395d69b 100644
--- a/misc/core.func
+++ b/misc/core.func
@@ -351,6 +351,11 @@ arch_check() {
sleep 2
exit 106
fi
+ if [[ "$arch" == "arm64" && "${var_arm64:-}" != "yes" ]]; then
+ msg_error "This script does not yet support arm64."
+ sleep 2
+ exit 106
+ fi
}
# ------------------------------------------------------------------------------
diff --git a/misc/error_handler.func b/misc/error_handler.func
index 39e5e667f35..e547a15737e 100644
--- a/misc/error_handler.func
+++ b/misc/error_handler.func
@@ -99,7 +99,7 @@ if ! declare -f explain_exit_code &>/dev/null; then
103) echo "Validation: Shell is not Bash" ;;
104) echo "Validation: Not running as root (or invoked via sudo)" ;;
105) echo "Validation: Proxmox VE version not supported" ;;
- 106) echo "Validation: Architecture not supported (ARM / PiMox)" ;;
+ 106) echo "Validation: Unsupported architecture (requires amd64 or arm64)" ;;
107) echo "Validation: Kernel key parameters unreadable" ;;
108) echo "Validation: Kernel key limits exceeded" ;;
109) echo "Proxmox: No available container ID after max attempts" ;;
diff --git a/misc/install.func b/misc/install.func
index 4e39b69daae..94f005b26f9 100644
--- a/misc/install.func
+++ b/misc/install.func
@@ -235,7 +235,6 @@ EOF
fi
apt_update_safe
$STD apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade
- $STD apt-get install -y sudo curl mc gnupg2 openssh-server wget gcc
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
msg_ok "Updated Container OS"
post_progress_to_api
diff --git a/misc/tools.func b/misc/tools.func
index 95ab71bc479..09cd7786e51 100644
--- a/misc/tools.func
+++ b/misc/tools.func
@@ -3651,7 +3651,12 @@ function setup_ffmpeg() {
# Binary fallback mode
if [[ "$TYPE" == "binary" ]]; then
- if ! CURL_TIMEOUT=300 curl_with_retry "https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz" "$TMP_DIR/ffmpeg.tar.xz"; then
+ local ffmpeg_arch
+ case "$(dpkg --print-architecture 2>/dev/null || echo amd64)" in
+ arm64) ffmpeg_arch="arm64" ;;
+ *) ffmpeg_arch="amd64" ;;
+ esac
+ if ! CURL_TIMEOUT=300 curl_with_retry "https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-${ffmpeg_arch}-static.tar.xz" "$TMP_DIR/ffmpeg.tar.xz"; then
msg_error "Failed to download FFmpeg binary"
rm -rf "$TMP_DIR"
return 1
@@ -3733,7 +3738,12 @@ function setup_ffmpeg() {
# If no source download (either VERSION empty or download failed), use binary
if [[ -z "$VERSION" ]]; then
msg_info "Setup FFmpeg from pre-built binary"
- if ! CURL_TIMEOUT=300 curl_with_retry "https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz" "$TMP_DIR/ffmpeg.tar.xz"; then
+ local ffmpeg_arch
+ case "$(dpkg --print-architecture 2>/dev/null || echo amd64)" in
+ arm64) ffmpeg_arch="arm64" ;;
+ *) ffmpeg_arch="amd64" ;;
+ esac
+ if ! CURL_TIMEOUT=300 curl_with_retry "https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-${ffmpeg_arch}-static.tar.xz" "$TMP_DIR/ffmpeg.tar.xz"; then
msg_error "Failed to download FFmpeg pre-built binary"
rm -rf "$TMP_DIR"
return 1
@@ -7706,7 +7716,12 @@ function setup_yq() {
msg_info "Setup yq $LATEST_VERSION"
fi
- if ! curl_with_retry "https://github.com/${GITHUB_REPO}/releases/download/v${LATEST_VERSION}/yq_linux_amd64" "$TMP_DIR/yq"; then
+ local yq_arch
+ case "$(dpkg --print-architecture 2>/dev/null || echo amd64)" in
+ arm64) yq_arch="arm64" ;;
+ *) yq_arch="amd64" ;;
+ esac
+ if ! curl_with_retry "https://github.com/${GITHUB_REPO}/releases/download/v${LATEST_VERSION}/yq_linux_${yq_arch}" "$TMP_DIR/yq"; then
msg_error "Failed to download yq"
rm -rf "$TMP_DIR"
return 1
From 231945dfa740955f3068b5027d6a33e7552b436c Mon Sep 17 00:00:00 2001
From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com>
Date: Wed, 11 Mar 2026 14:26:03 +0100
Subject: [PATCH 10/22] remove arm64 overlay
---
misc/build.func | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/misc/build.func b/misc/build.func
index 5ce216cd94d..5eb93a1aed3 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -4105,13 +4105,6 @@ EOF'
local _install_script
_install_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh")"
- if [[ "$ARCH" == "arm64" ]]; then
- local _arm_script
- _arm_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/arm/${var_install}.sh" 2>/dev/null || true)"
- if [[ -n "$_arm_script" ]]; then
- _install_script="${_arm_script}"$'\n'"${_install_script}"
- fi
- fi
lxc-attach -n "$CTID" -- bash -c "$_install_script"
local lxc_exit=$?
@@ -4492,13 +4485,6 @@ EOF'
trap - ERR
local _install_script
_install_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh")"
- if [[ "$ARCH" == "arm64" ]]; then
- local _arm_script
- _arm_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/arm/${var_install}.sh" 2>/dev/null || true)"
- if [[ -n "$_arm_script" ]]; then
- _install_script="${_arm_script}"$'\n'"${_install_script}"
- fi
- fi
lxc-attach -n "$CTID" -- bash -c "$_install_script"
local apt_retry_exit=$?
set -Eeuo pipefail
From 44ec223d20bffc1deed7bc64f2755837508f09d6 Mon Sep 17 00:00:00 2001
From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com>
Date: Wed, 11 Mar 2026 14:37:43 +0100
Subject: [PATCH 11/22] update ifupdown2 source
---
misc/build.func | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/misc/build.func b/misc/build.func
index e8884ad798f..33de914026d 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -5038,7 +5038,7 @@ create_lxc_container() {
}
# Downloads an ARM64 LXC rootfs template to $1.
- # Debian: fetches latest release from asylumexp/debian-ifupdown2-lxc on GitHub.
+ # Debian: fetches latest release from community-scripts/debian-arm64-lxc on GitHub.
# Others: fetches from jenkins.linuxcontainers.org.
download_arm64_template() {
local dest="$1" url
@@ -5049,7 +5049,7 @@ create_lxc_container() {
}
if [[ "$PCT_OSTYPE" == "debian" ]]; then
- url=$(curl -fsSL "https://api.github.com/repos/asylumexp/debian-ifupdown2-lxc/releases/latest" |
+ url=$(curl -fsSL "https://api.github.com/repos/community-scripts/debian-arm64-lxc/releases/latest" |
grep -Eo "https://[^\"]*debian-${CUSTOM_TEMPLATE_VARIANT}-arm64-rootfs\.tar\.xz" | head -n1)
[[ -n "$url" ]] || {
msg_error "Could not find Debian ${CUSTOM_TEMPLATE_VARIANT} ARM64 template URL."
From 866b6950c0e7a7cae5b746b3e864dd80525358d2 Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Thu, 12 Mar 2026 16:42:41 +1000
Subject: [PATCH 12/22] Revert "remove arm64 overlay"
This reverts commit 231945dfa740955f3068b5027d6a33e7552b436c.
---
misc/build.func | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/misc/build.func b/misc/build.func
index 33de914026d..d4c06bbdfac 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -4116,6 +4116,13 @@ EOF'
local _install_script
_install_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh")"
+ if [[ "$ARCH" == "arm64" ]]; then
+ local _arm_script
+ _arm_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/arm/${var_install}.sh" 2>/dev/null || true)"
+ if [[ -n "$_arm_script" ]]; then
+ _install_script="${_arm_script}"$'\n'"${_install_script}"
+ fi
+ fi
lxc-attach -n "$CTID" -- bash -c "$_install_script"
local lxc_exit=$?
@@ -4496,6 +4503,13 @@ EOF'
trap - ERR
local _install_script
_install_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh")"
+ if [[ "$ARCH" == "arm64" ]]; then
+ local _arm_script
+ _arm_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/arm/${var_install}.sh" 2>/dev/null || true)"
+ if [[ -n "$_arm_script" ]]; then
+ _install_script="${_arm_script}"$'\n'"${_install_script}"
+ fi
+ fi
lxc-attach -n "$CTID" -- bash -c "$_install_script"
local apt_retry_exit=$?
set -Eeuo pipefail
From 24f134799017763ccf2eafc5d72b98a858bc7de1 Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Thu, 12 Mar 2026 16:45:00 +1000
Subject: [PATCH 13/22] Revert changes from "Improve arm64 support and
arch-specific downloads"
---
misc/build.func | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/misc/build.func b/misc/build.func
index d4c06bbdfac..a3e3dba2f7e 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -3428,6 +3428,9 @@ start() {
set_std_mode
ensure_profile_loaded
get_lxc_ip
+ if [[ "$(dpkg --print-architecture)" == "arm64" ]] && declare -f update_script_arm64 >/dev/null 2>&1; then
+ update_script_arm64
+ fi
update_script
update_motd_ip
cleanup_lxc
@@ -3456,6 +3459,9 @@ start() {
esac
ensure_profile_loaded
get_lxc_ip
+ if [[ "$(dpkg --print-architecture)" == "arm64" ]] && declare -f update_script_arm64 >/dev/null 2>&1; then
+ update_script_arm64
+ fi
update_script
update_motd_ip
cleanup_lxc
From 73e121b67980e0ade64817fe6805372c6634e5d7 Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Tue, 12 May 2026 14:16:02 +1000
Subject: [PATCH 14/22] Reapply "Improve arm64 support and arch-specific
downloads"
This reapplies commit 7c051fb64891f72ce030896a3ac14375031c98b4.
---
misc/build.func | 6 ------
1 file changed, 6 deletions(-)
diff --git a/misc/build.func b/misc/build.func
index a3e3dba2f7e..d4c06bbdfac 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -3428,9 +3428,6 @@ start() {
set_std_mode
ensure_profile_loaded
get_lxc_ip
- if [[ "$(dpkg --print-architecture)" == "arm64" ]] && declare -f update_script_arm64 >/dev/null 2>&1; then
- update_script_arm64
- fi
update_script
update_motd_ip
cleanup_lxc
@@ -3459,9 +3456,6 @@ start() {
esac
ensure_profile_loaded
get_lxc_ip
- if [[ "$(dpkg --print-architecture)" == "arm64" ]] && declare -f update_script_arm64 >/dev/null 2>&1; then
- update_script_arm64
- fi
update_script
update_motd_ip
cleanup_lxc
From 314b1b843b2efe58fb01f3f4a6d4e182946fa882 Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Tue, 12 May 2026 14:16:04 +1000
Subject: [PATCH 15/22] Reapply "remove arm64 overlay"
This reverts commit 866b6950c0e7a7cae5b746b3e864dd80525358d2.
---
misc/build.func | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/misc/build.func b/misc/build.func
index d4c06bbdfac..33de914026d 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -4116,13 +4116,6 @@ EOF'
local _install_script
_install_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh")"
- if [[ "$ARCH" == "arm64" ]]; then
- local _arm_script
- _arm_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/arm/${var_install}.sh" 2>/dev/null || true)"
- if [[ -n "$_arm_script" ]]; then
- _install_script="${_arm_script}"$'\n'"${_install_script}"
- fi
- fi
lxc-attach -n "$CTID" -- bash -c "$_install_script"
local lxc_exit=$?
@@ -4503,13 +4496,6 @@ EOF'
trap - ERR
local _install_script
_install_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh")"
- if [[ "$ARCH" == "arm64" ]]; then
- local _arm_script
- _arm_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/arm/${var_install}.sh" 2>/dev/null || true)"
- if [[ -n "$_arm_script" ]]; then
- _install_script="${_arm_script}"$'\n'"${_install_script}"
- fi
- fi
lxc-attach -n "$CTID" -- bash -c "$_install_script"
local apt_retry_exit=$?
set -Eeuo pipefail
From 9f7b951ec6ebe7456110a91bc7689bbc4d57bd09 Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Tue, 12 May 2026 15:12:59 +1000
Subject: [PATCH 16/22] Redo template name handling
---
misc/build.func | 43 ++++++++++++++++++++++---------------------
1 file changed, 22 insertions(+), 21 deletions(-)
diff --git a/misc/build.func b/misc/build.func
index 33de914026d..b2269e987d9 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -52,6 +52,10 @@ variables() {
# as "/tmp/${NSAPP}-${CTID}-${SESSION_ID}.log" (requires CTID, not available here)
CTTYPE="${CTTYPE:-${CT_TYPE:-1}}"
+ # ARM64 Template default variables
+ DEBIAN_DEFAULT_CODENAME="trixie"
+ UBUNTU_DEFAULT_CODENAME="noble"
+
# Parse dev_mode early
parse_dev_mode
@@ -5019,21 +5023,18 @@ create_lxc_container() {
# Maps OS type + version to the release variant name used by ARM64 template sources.
arm64_template_variant() {
- case "$1" in
- debian)
- case "$2" in
- 12 | 12.*) echo "bookworm" ;; 13 | 13.*) echo "trixie" ;;
- *) echo "trixie" ;;
- esac
- ;;
- alpine) echo "3.22" ;;
- ubuntu)
- case "$2" in
- 24.04* | noble) echo "noble" ;; 24.10* | oracular) echo "oracular" ;;
- *) echo "jammy" ;;
- esac
- ;;
- *) return 1 ;;
+ case "$1:$2" in
+ debian:12) echo "bookworm" ;;
+ debian:13) echo "trixie" ;;
+ debian:) echo "$(DEBIAN_DEFAULT_CODENAME)" ;;
+
+ ubuntu:24.04) echo "noble" ;;
+ ubuntu:26.04) echo "questing" ;;
+ ubuntu:) echo "$(UBUNTU_DEFAULT_CODENAME)" ;;
+
+ alpine:*) echo "$2" ;;
+
+ *) return 1 ;;
esac
}
@@ -5231,7 +5232,7 @@ create_lxc_container() {
TEMPLATE="${PCT_OSTYPE}-${CUSTOM_TEMPLATE_VARIANT}-rootfs.tar.xz"
TEMPLATE_SOURCE="custom-arm64"
- # Resolve template path: pvesm â storage.cfg fallback â default
+ # Resolve template path
TEMPLATE_PATH="$(pvesm path "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" 2>/dev/null || true)"
if [[ -z "$TEMPLATE_PATH" ]]; then
local _tpl_base
@@ -5239,11 +5240,11 @@ create_lxc_container() {
TEMPLATE_PATH="${_tpl_base:-/var/lib/vz}/template/cache/$TEMPLATE"
fi
- # Download if missing, too small, or corrupt (single pass)
+ # Download if missing, too small, or corrupt
if [[ ! -f "$TEMPLATE_PATH" ]]; then
download_arm64_template "$TEMPLATE_PATH"
elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]] || ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
- msg_warn "Local template invalid â re-downloading."
+ msg_warn "Local template invalid - re-downloading."
rm -f "$TEMPLATE_PATH"
download_arm64_template "$TEMPLATE_PATH"
else
@@ -5585,13 +5586,13 @@ create_lxc_container() {
# Validate template before pct create (while holding lock)
if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH" 2>/dev/null || echo 0)" -lt 1000000 ]]; then
- msg_info "Template file missing or too small â downloading"
+ msg_info "Template file missing or too small - downloading"
rm -f "$TEMPLATE_PATH"
download_template
msg_ok "Template downloaded"
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
if [[ "$ARCH" == "arm64" || -n "$ONLINE_TEMPLATE" ]]; then
- msg_info "Template appears corrupted â re-downloading"
+ msg_info "Template appears corrupted - re-downloading"
rm -f "$TEMPLATE_PATH"
download_template
msg_ok "Template re-downloaded"
@@ -5612,7 +5613,7 @@ create_lxc_container() {
# Check if template issue - retry with fresh download
if grep -qiE 'unable to open|corrupt|invalid' "$LOGFILE"; then
- msg_info "Template may be corrupted â re-downloading"
+ msg_info "Template may be corrupted - re-downloading"
rm -f "$TEMPLATE_PATH"
download_template
msg_ok "Template re-downloaded"
From 0aeaa5ae97277ca81d07eb738aeeccf75d0a4692 Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Tue, 12 May 2026 15:24:21 +1000
Subject: [PATCH 17/22] fix template name handling change
---
misc/build.func | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/misc/build.func b/misc/build.func
index b2269e987d9..1b1741da06e 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -52,9 +52,10 @@ variables() {
# as "/tmp/${NSAPP}-${CTID}-${SESSION_ID}.log" (requires CTID, not available here)
CTTYPE="${CTTYPE:-${CT_TYPE:-1}}"
- # ARM64 Template default variables
- DEBIAN_DEFAULT_CODENAME="trixie"
- UBUNTU_DEFAULT_CODENAME="noble"
+ # ARM64 Template default variables
+ DEBIAN_DEFAULT_CODENAME="trixie"
+ UBUNTU_DEFAULT_CODENAME="noble"
+ ALPINE_DEFAULT_VERSION="3.23"
# Parse dev_mode early
parse_dev_mode
@@ -5026,13 +5027,13 @@ create_lxc_container() {
case "$1:$2" in
debian:12) echo "bookworm" ;;
debian:13) echo "trixie" ;;
- debian:) echo "$(DEBIAN_DEFAULT_CODENAME)" ;;
+ debian:) echo "$DEBIAN_DEFAULT_CODENAME" ;;
ubuntu:24.04) echo "noble" ;;
ubuntu:26.04) echo "questing" ;;
- ubuntu:) echo "$(UBUNTU_DEFAULT_CODENAME)" ;;
+ ubuntu:) echo "$UBUNTU_DEFAULT_CODENAME" ;;
- alpine:*) echo "$2" ;;
+ alpine:*) echo "${2:-$ALPINE_DEFAULT_VERSION}" ;;
*) return 1 ;;
esac
@@ -5050,8 +5051,13 @@ create_lxc_container() {
}
if [[ "$PCT_OSTYPE" == "debian" ]]; then
- url=$(curl -fsSL "https://api.github.com/repos/community-scripts/debian-arm64-lxc/releases/latest" |
- grep -Eo "https://[^\"]*debian-${CUSTOM_TEMPLATE_VARIANT}-arm64-rootfs\.tar\.xz" | head -n1)
+ url=$(
+ curl -fsSL "https://api.github.com/repos/community-scripts/debian-arm64-lxc/releases/latest" |
+ jq -r --arg v "$CUSTOM_TEMPLATE_VARIANT" \
+ '.assets[].browser_download_url | select(test("debian-" + $v + "-arm64-rootfs\\.tar\\.xz$"))' |
+ head -n1
+ )
+
[[ -n "$url" ]] || {
msg_error "Could not find Debian ${CUSTOM_TEMPLATE_VARIANT} ARM64 template URL."
exit 207
From 079afa46009e529fd9ae3530f57403265abdc9c3 Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Tue, 12 May 2026 15:28:43 +1000
Subject: [PATCH 18/22] add ensure_whiptail function
This is required as some arm64 systems will not have whiptail installed, as it is not installed by default.
---
misc/build.func | 3 +--
misc/core.func | 19 +++++++++++++++++++
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/misc/build.func b/misc/build.func
index 1b1741da06e..8f21f071cc0 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -2939,6 +2939,7 @@ install_script() {
pve_check
shell_check
root_check
+ ensure_whiptail
arch_check
ssh_check
maxkeys_check
@@ -5074,8 +5075,6 @@ create_lxc_container() {
msg_ok "Downloaded ARM64 LXC template"
}
- # Architecture-aware template download wrapper.
- # Optional $1 overrides destination path (for local-storage fallback).
download_template() {
local dest="${1:-$TEMPLATE_PATH}"
if [[ "$ARCH" == "arm64" ]]; then
diff --git a/misc/core.func b/misc/core.func
index 7d44395d69b..3257ace210e 100644
--- a/misc/core.func
+++ b/misc/core.func
@@ -1718,6 +1718,25 @@ function get_lxc_ip() {
export LOCAL_IP
}
+# ------------------------------------------------------------------------------
+# ensure_whiptail()
+#
+# - Ensures whiptail is installed
+# - Some ARM64 systems will not have whiptail installed.
+# - Exits with error message if installation fails
+# ------------------------------------------------------------------------------
+ensure_whiptail() {
+ command -v whiptail >/dev/null 2>&1 && return 0
+
+ msg_info "Installing whiptail"
+ apt_update_safe
+ $STD apt-get install -y whiptail || {
+ msg_error "Failed to install whiptail"
+ exit 115
+ }
+ msg_ok "Installed whiptail"
+}
+
# ==============================================================================
# SIGNAL TRAPS
# ==============================================================================
From 5f6a02986d40939decd25b9ea709b546d9ceb93c Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Tue, 12 May 2026 15:38:38 +1000
Subject: [PATCH 19/22] add arm64_notice function
---
misc/build.func | 1 +
misc/core.func | 15 ++++++++++++++-
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/misc/build.func b/misc/build.func
index 8f21f071cc0..41e53bcacc2 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -2941,6 +2941,7 @@ install_script() {
root_check
ensure_whiptail
arch_check
+ arm64_notice
ssh_check
maxkeys_check
diagnostics_check
diff --git a/misc/core.func b/misc/core.func
index 3257ace210e..2c991b3e30a 100644
--- a/misc/core.func
+++ b/misc/core.func
@@ -1722,7 +1722,7 @@ function get_lxc_ip() {
# ensure_whiptail()
#
# - Ensures whiptail is installed
-# - Some ARM64 systems will not have whiptail installed.
+# - Some ARM64 systems will not have whiptail installed
# - Exits with error message if installation fails
# ------------------------------------------------------------------------------
ensure_whiptail() {
@@ -1737,6 +1737,19 @@ ensure_whiptail() {
msg_ok "Installed whiptail"
}
+# ------------------------------------------------------------------------------
+# arm64_notice()
+#
+# - Shows a short warning when running scripts on ARM64 systems
+# ------------------------------------------------------------------------------
+arm64_notice() {
+ [[ "$(dpkg --print-architecture)" == "arm64" ]] || return 0
+
+ whiptail --backtitle "Proxmox VE Helper Scripts" \
+ --title "ARM64 SUPPORT" \
+ --ok-button "Continue" \
+ --msgbox "ARM64 support is in active development.\n\nSome scripts, packages, or application releases may not be fully tested or working yet." 10 68
+}
# ==============================================================================
# SIGNAL TRAPS
# ==============================================================================
From 16ac4407e28273b8cf81d1d10260ece2821f5ddc Mon Sep 17 00:00:00 2001
From: Sam Heinz
Date: Wed, 13 May 2026 00:45:53 +1000
Subject: [PATCH 20/22] Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---
misc/tools.func | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/misc/tools.func b/misc/tools.func
index 887db46711c..7c30afda85b 100644
--- a/misc/tools.func
+++ b/misc/tools.func
@@ -4076,9 +4076,14 @@ function setup_ffmpeg() {
# If no source download (either VERSION empty or download failed), use binary
if [[ -z "$VERSION" ]]; then
msg_info "Setup FFmpeg from pre-built binary"
- local ffmpeg_arch
- case "$(dpkg --print-architecture 2>/dev/null || echo amd64)" in
- arm64) ffmpeg_arch="arm64" ;;
+ local ffmpeg_arch detected_arch
+ detected_arch="$(dpkg --print-architecture 2>/dev/null || true)"
+ if [[ -z "$detected_arch" ]]; then
+ detected_arch="$(uname -m 2>/dev/null || true)"
+ fi
+ case "$detected_arch" in
+ arm64 | aarch64) ffmpeg_arch="arm64" ;;
+ amd64 | x86_64) ffmpeg_arch="amd64" ;;
*) ffmpeg_arch="amd64" ;;
esac
if ! CURL_TIMEOUT=300 curl_with_retry "https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-${ffmpeg_arch}-static.tar.xz" "$TMP_DIR/ffmpeg.tar.xz"; then
From 2c1f2161894b546e0913c84d63a40561440759a5 Mon Sep 17 00:00:00 2001
From: Sam Heinz
Date: Wed, 13 May 2026 00:46:44 +1000
Subject: [PATCH 21/22] Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---
misc/tools.func | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/misc/tools.func b/misc/tools.func
index 7c30afda85b..38b5a7b07da 100644
--- a/misc/tools.func
+++ b/misc/tools.func
@@ -8262,9 +8262,16 @@ function setup_yq() {
msg_info "Setup yq $LATEST_VERSION"
fi
- local yq_arch
- case "$(dpkg --print-architecture 2>/dev/null || echo amd64)" in
- arm64) yq_arch="arm64" ;;
+ local yq_arch detected_arch
+ if command -v dpkg &>/dev/null; then
+ detected_arch="$(dpkg --print-architecture 2>/dev/null)"
+ else
+ detected_arch="$(uname -m 2>/dev/null)"
+ fi
+
+ case "$detected_arch" in
+ arm64 | aarch64) yq_arch="arm64" ;;
+ amd64 | x86_64) yq_arch="amd64" ;;
*) yq_arch="amd64" ;;
esac
if ! curl_with_retry "https://github.com/${GITHUB_REPO}/releases/download/v${LATEST_VERSION}/yq_linux_${yq_arch}" "$TMP_DIR/yq"; then
From 88a6b07334c74df443ac7a574a7ab31e55514de3 Mon Sep 17 00:00:00 2001
From: Sam Heinz <54530346+asylumexp@users.noreply.github.com>
Date: Wed, 13 May 2026 00:47:01 +1000
Subject: [PATCH 22/22] fix for copilot detected bugs
---
misc/build.func | 6 +++++-
misc/core.func | 2 +-
misc/tools.func | 3 +++
3 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/misc/build.func b/misc/build.func
index c6b3e6006df..0298d639b8a 100644
--- a/misc/build.func
+++ b/misc/build.func
@@ -5934,7 +5934,11 @@ create_lxc_container() {
TEMPLATE_PATH="$(pvesm path "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" 2>/dev/null || true)"
if [[ -z "$TEMPLATE_PATH" ]]; then
local _tpl_base
- _tpl_base=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
+ _tpl_base=$(awk -v s="$TEMPLATE_STORAGE" '
+ $0 ~ "^[^:]+:[[:space:]]*" s "$" {f=1; next}
+ f && /^[^[:space:]]/ {f=0}
+ f && $1 == "path" {print $2; exit}
+ ' /etc/pve/storage.cfg)
TEMPLATE_PATH="${_tpl_base:-/var/lib/vz}/template/cache/$TEMPLATE"
fi
diff --git a/misc/core.func b/misc/core.func
index be9a65955a8..c30ad1945a5 100644
--- a/misc/core.func
+++ b/misc/core.func
@@ -1732,7 +1732,7 @@ ensure_whiptail() {
apt_update_safe
$STD apt-get install -y whiptail || {
msg_error "Failed to install whiptail"
- exit 115
+ exit 100
}
msg_ok "Installed whiptail"
}
diff --git a/misc/tools.func b/misc/tools.func
index 38b5a7b07da..8d70e09b3af 100644
--- a/misc/tools.func
+++ b/misc/tools.func
@@ -3060,6 +3060,7 @@ function fetch_and_deploy_codeberg_release() {
# Fall back to architecture heuristic
if [[ -z "$url_match" ]]; then
for u in $assets; do
+ [[ "$u" =~ \.deb$ ]] || continue
if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
[[ "$u" =~ (amd64|x86_64).*\.deb$ ]] || continue
elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
@@ -3573,6 +3574,7 @@ function fetch_and_deploy_gh_release() {
# If no match via explicit pattern, fall back to architecture heuristic
if [[ -z "$url_match" ]]; then
for u in $assets; do
+ [[ "$u" =~ \.deb$ ]] || continue
if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
[[ "$u" =~ (amd64|x86_64).*\.deb$ ]] || continue
elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
@@ -3610,6 +3612,7 @@ function fetch_and_deploy_gh_release() {
fi
if [[ -z "$url_match" ]]; then
for u in $assets; do
+ [[ "$u" =~ \.deb$ ]] || continue
if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
[[ "$u" =~ (amd64|x86_64).*\.deb$ ]] || continue
elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then