mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-05-14 04:55:01 +00:00
update beta ProxMenux 1.2.1.1-beta
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# Version : 1.0
|
||||
# Last Updated: 08/04/2026
|
||||
# ==========================================================
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# Version : 1.0
|
||||
# Last Updated: 08/04/2026
|
||||
# ==========================================================
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# Version : 1.3-dialog
|
||||
# Last Updated: 13/12/2024
|
||||
# ==========================================================
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# Version : 1.0
|
||||
# Last Updated: 11/04/2026
|
||||
# ==========================================================
|
||||
|
||||
@@ -5,8 +5,18 @@ if [[ -n "${__PROXMENUX_GPU_HOOK_GUARD_HELPERS__}" ]]; then
|
||||
fi
|
||||
__PROXMENUX_GPU_HOOK_GUARD_HELPERS__=1
|
||||
|
||||
PROXMENUX_GPU_HOOK_STORAGE_REF="local:snippets/proxmenux-gpu-guard.sh"
|
||||
PROXMENUX_GPU_HOOK_ABS_PATH="/var/lib/vz/snippets/proxmenux-gpu-guard.sh"
|
||||
# Issue #195: snippets used to live at the hard-coded `local:snippets/`
|
||||
# path, which broke LXC/VM migration between cluster nodes — `local` is
|
||||
# node-specific, so the hookscript reference was dangling on the target
|
||||
# node. The path now resolves dynamically through
|
||||
# `_resolve_snippets_storage` and is cached per-process. Callers should
|
||||
# invoke `_compute_snippets_paths` (interactive flag optional) before
|
||||
# referencing the two PROXMENUX_GPU_HOOK_* variables.
|
||||
PROXMENUX_GPU_HOOK_FILENAME="proxmenux-gpu-guard.sh"
|
||||
PROXMENUX_GPU_HOOK_STORAGE_REF=""
|
||||
PROXMENUX_GPU_HOOK_ABS_PATH=""
|
||||
|
||||
PROXMENUX_CONFIG_JSON="${PROXMENUX_CONFIG_JSON:-/usr/local/share/proxmenux/config.json}"
|
||||
|
||||
_gpu_guard_msg_warn() {
|
||||
if declare -F msg_warn >/dev/null 2>&1; then
|
||||
@@ -24,6 +34,164 @@ _gpu_guard_msg_ok() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ────────────────────────────────────────────────────────────────────
|
||||
# Snippets storage resolution (issue #195)
|
||||
# ────────────────────────────────────────────────────────────────────
|
||||
|
||||
_save_snippets_storage_preference() {
|
||||
local storage="$1"
|
||||
command -v jq >/dev/null 2>&1 || return 0
|
||||
mkdir -p "$(dirname "$PROXMENUX_CONFIG_JSON")" 2>/dev/null || true
|
||||
[[ -f "$PROXMENUX_CONFIG_JSON" ]] || echo "{}" > "$PROXMENUX_CONFIG_JSON"
|
||||
jq --arg s "$storage" '.snippets_storage = $s' "$PROXMENUX_CONFIG_JSON" \
|
||||
> "${PROXMENUX_CONFIG_JSON}.tmp" 2>/dev/null \
|
||||
&& mv "${PROXMENUX_CONFIG_JSON}.tmp" "$PROXMENUX_CONFIG_JSON"
|
||||
}
|
||||
|
||||
# Decide which PVE storage backs ProxMenux snippets (hookscripts).
|
||||
#
|
||||
# Outcomes (in order):
|
||||
# 1. Cached resolution in this shell → reuse, no work.
|
||||
# 2. No active storage with content=snippets → fall back to "local".
|
||||
# 3. Single candidate (standalone host with only `local`) → use it silently.
|
||||
# 4. Multiple candidates + saved preference → use saved.
|
||||
# 5. Multiple candidates, no preference, $1 == "interactive" + whiptail
|
||||
# available → prompt the user, save the choice, use it.
|
||||
# 6. Otherwise (non-interactive auto-call from sync_*, cron, etc.) →
|
||||
# use the first listed candidate. Avoids blocking on a dialog from
|
||||
# a non-tty context.
|
||||
_list_snippets_candidates() {
|
||||
pvesm status -content snippets 2>/dev/null \
|
||||
| awk 'NR>1 && $3=="active" {print $1}'
|
||||
}
|
||||
|
||||
# PVE 9 ships `local` without `snippets` in its content list, so a fresh
|
||||
# install has zero candidates and ProxMenux can't write a hookscript
|
||||
# anywhere. This silently appends `snippets` to local's content set so
|
||||
# the GPU passthrough flow works out of the box. We only touch `local`
|
||||
# (the always-present default storage) and only when there's nothing
|
||||
# else to choose — never modifies a custom storage definition.
|
||||
_ensure_local_supports_snippets() {
|
||||
local current
|
||||
current=$(pvesh get /storage/local --output-format json 2>/dev/null | jq -r '.content // empty' 2>/dev/null)
|
||||
[[ -z "$current" ]] && return 1
|
||||
echo "$current" | tr ',' '\n' | grep -qx 'snippets' && return 0
|
||||
|
||||
local new_content="${current},snippets"
|
||||
if pvesm set local --content "$new_content" >/dev/null 2>&1; then
|
||||
_gpu_guard_msg_ok "Enabled 'snippets' on the 'local' storage so ProxMenux can install hookscripts."
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_resolve_snippets_storage() {
|
||||
local interactive="${1:-}"
|
||||
|
||||
if [[ -n "${__PROXMENUX_RESOLVED_SNIPPETS_STORAGE:-}" ]]; then
|
||||
echo "$__PROXMENUX_RESOLVED_SNIPPETS_STORAGE"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local candidates
|
||||
candidates=$(_list_snippets_candidates)
|
||||
|
||||
if [[ -z "$candidates" ]]; then
|
||||
# Fresh PVE 9 host — `local` doesn't include `snippets` by default.
|
||||
# Auto-enable it; if that succeeds, re-list and continue.
|
||||
if _ensure_local_supports_snippets; then
|
||||
candidates=$(_list_snippets_candidates)
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "$candidates" ]]; then
|
||||
# Still nothing usable — fall back to `local` and let the caller
|
||||
# surface the error if writing actually fails.
|
||||
__PROXMENUX_RESOLVED_SNIPPETS_STORAGE="local"
|
||||
echo "local"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local count
|
||||
count=$(echo "$candidates" | wc -l)
|
||||
|
||||
if [[ "$count" -eq 1 ]]; then
|
||||
__PROXMENUX_RESOLVED_SNIPPETS_STORAGE="$candidates"
|
||||
echo "$candidates"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -f "$PROXMENUX_CONFIG_JSON" ]] && command -v jq >/dev/null 2>&1; then
|
||||
local pref
|
||||
pref=$(jq -r '.snippets_storage // empty' "$PROXMENUX_CONFIG_JSON" 2>/dev/null)
|
||||
if [[ -n "$pref" ]] && echo "$candidates" | grep -qFx "$pref"; then
|
||||
__PROXMENUX_RESOLVED_SNIPPETS_STORAGE="$pref"
|
||||
echo "$pref"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$interactive" == "interactive" ]] && command -v whiptail >/dev/null 2>&1; then
|
||||
local options=()
|
||||
local first_pick=1
|
||||
while IFS= read -r s; do
|
||||
[[ -z "$s" ]] && continue
|
||||
if [[ $first_pick -eq 1 ]]; then
|
||||
options+=("$s" "" "ON")
|
||||
first_pick=0
|
||||
else
|
||||
options+=("$s" "" "OFF")
|
||||
fi
|
||||
done <<< "$candidates"
|
||||
|
||||
local choice
|
||||
choice=$(whiptail --backtitle "ProxMenux" \
|
||||
--title "Snippets storage (used by hookscripts)" \
|
||||
--radiolist \
|
||||
"Pick the storage where ProxMenux installs snippets/hookscripts.\n\nFor cluster setups, choose a shared NFS/CIFS storage so VMs and LXCs migrate cleanly between nodes — \`local\` is node-specific and breaks migration." \
|
||||
20 78 8 \
|
||||
"${options[@]}" 3>&1 1>&2 2>&3) || choice=""
|
||||
|
||||
if [[ -n "$choice" ]] && echo "$candidates" | grep -qFx "$choice"; then
|
||||
_save_snippets_storage_preference "$choice"
|
||||
__PROXMENUX_RESOLVED_SNIPPETS_STORAGE="$choice"
|
||||
echo "$choice"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
local first
|
||||
first=$(echo "$candidates" | head -n 1)
|
||||
__PROXMENUX_RESOLVED_SNIPPETS_STORAGE="$first"
|
||||
echo "$first"
|
||||
}
|
||||
|
||||
# Populate the two PROXMENUX_GPU_HOOK_* variables from whichever storage
|
||||
# `_resolve_snippets_storage` returns. Idempotent — safe to call multiple
|
||||
# times, the resolver is cached per-process.
|
||||
_compute_snippets_paths() {
|
||||
local interactive="${1:-}"
|
||||
local storage
|
||||
storage=$(_resolve_snippets_storage "$interactive")
|
||||
|
||||
PROXMENUX_GPU_HOOK_STORAGE_REF="${storage}:snippets/${PROXMENUX_GPU_HOOK_FILENAME}"
|
||||
|
||||
# `pvesm path` understands the storage:content/file syntax for any
|
||||
# registered storage and returns the absolute filesystem path — works
|
||||
# for `local`, NFS, CIFS, dir, etc. Falls back to the conventional
|
||||
# mount point if pvesm doesn't resolve (very old PVE / mid-mount
|
||||
# transitions).
|
||||
local abs
|
||||
abs=$(pvesm path "$PROXMENUX_GPU_HOOK_STORAGE_REF" 2>/dev/null)
|
||||
if [[ -n "$abs" ]]; then
|
||||
PROXMENUX_GPU_HOOK_ABS_PATH="$abs"
|
||||
elif [[ "$storage" == "local" ]]; then
|
||||
PROXMENUX_GPU_HOOK_ABS_PATH="/var/lib/vz/snippets/${PROXMENUX_GPU_HOOK_FILENAME}"
|
||||
else
|
||||
PROXMENUX_GPU_HOOK_ABS_PATH="/mnt/pve/${storage}/snippets/${PROXMENUX_GPU_HOOK_FILENAME}"
|
||||
fi
|
||||
}
|
||||
|
||||
_gpu_guard_has_vm_gpu() {
|
||||
local vmid="$1"
|
||||
qm config "$vmid" 2>/dev/null | grep -qE '^hostpci[0-9]+:'
|
||||
@@ -37,7 +205,13 @@ _gpu_guard_has_lxc_gpu() {
|
||||
}
|
||||
|
||||
ensure_proxmenux_gpu_guard_hookscript() {
|
||||
mkdir -p /var/lib/vz/snippets 2>/dev/null || true
|
||||
# Issue #195: resolve which snippets storage to write to (interactive
|
||||
# — this function is called from the GPU passthrough flow which is
|
||||
# always run from a tty). The resolver caches its answer for the rest
|
||||
# of the bash session, so subsequent attach_* calls reuse it.
|
||||
_compute_snippets_paths "interactive"
|
||||
|
||||
mkdir -p "$(dirname "$PROXMENUX_GPU_HOOK_ABS_PATH")" 2>/dev/null || true
|
||||
|
||||
cat >"$PROXMENUX_GPU_HOOK_ABS_PATH" <<'HOOKEOF'
|
||||
#!/usr/bin/env bash
|
||||
@@ -229,6 +403,12 @@ attach_proxmenux_gpu_guard_to_vm() {
|
||||
local vmid="$1"
|
||||
_gpu_guard_has_vm_gpu "$vmid" || return 0
|
||||
|
||||
# Resolver cache populated by ensure_* (or the first call here).
|
||||
# Pass "interactive" so a sync done in isolation can still prompt;
|
||||
# sync_proxmenux_gpu_guard_hooks pre-seeds the cache to suppress the
|
||||
# dialog when running non-interactively.
|
||||
_compute_snippets_paths "interactive"
|
||||
|
||||
local current
|
||||
current=$(qm config "$vmid" 2>/dev/null | awk '/^hookscript:/ {print $2}')
|
||||
if [[ "$current" == "$PROXMENUX_GPU_HOOK_STORAGE_REF" ]]; then
|
||||
@@ -236,9 +416,9 @@ attach_proxmenux_gpu_guard_to_vm() {
|
||||
fi
|
||||
|
||||
if qm set "$vmid" --hookscript "$PROXMENUX_GPU_HOOK_STORAGE_REF" >/dev/null 2>&1; then
|
||||
_gpu_guard_msg_ok "PCIe passthrough guard attached to VM ${vmid}"
|
||||
_gpu_guard_msg_ok "PCIe passthrough guard attached to VM ${vmid} (${PROXMENUX_GPU_HOOK_STORAGE_REF})"
|
||||
else
|
||||
_gpu_guard_msg_warn "Could not attach PCIe passthrough guard to VM ${vmid}. Ensure 'local' storage supports snippets."
|
||||
_gpu_guard_msg_warn "Could not attach PCIe passthrough guard to VM ${vmid}. Verify ${__PROXMENUX_RESOLVED_SNIPPETS_STORAGE} storage supports snippets."
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -246,6 +426,8 @@ attach_proxmenux_gpu_guard_to_lxc() {
|
||||
local ctid="$1"
|
||||
_gpu_guard_has_lxc_gpu "$ctid" || return 0
|
||||
|
||||
_compute_snippets_paths "interactive"
|
||||
|
||||
local current
|
||||
current=$(pct config "$ctid" 2>/dev/null | awk '/^hookscript:/ {print $2}')
|
||||
if [[ "$current" == "$PROXMENUX_GPU_HOOK_STORAGE_REF" ]]; then
|
||||
@@ -253,13 +435,22 @@ attach_proxmenux_gpu_guard_to_lxc() {
|
||||
fi
|
||||
|
||||
if pct set "$ctid" -hookscript "$PROXMENUX_GPU_HOOK_STORAGE_REF" >/dev/null 2>&1; then
|
||||
_gpu_guard_msg_ok "PCIe passthrough guard attached to LXC ${ctid}"
|
||||
_gpu_guard_msg_ok "PCIe passthrough guard attached to LXC ${ctid} (${PROXMENUX_GPU_HOOK_STORAGE_REF})"
|
||||
else
|
||||
_gpu_guard_msg_warn "Could not attach PCIe passthrough guard to LXC ${ctid}. Ensure 'local' storage supports snippets."
|
||||
_gpu_guard_msg_warn "Could not attach PCIe passthrough guard to LXC ${ctid}. Verify ${__PROXMENUX_RESOLVED_SNIPPETS_STORAGE} storage supports snippets."
|
||||
fi
|
||||
}
|
||||
|
||||
# Iterate every VM/LXC and reattach the guard if it has GPU passthrough
|
||||
# but no current hookscript reference. Used for cluster-wide sync /
|
||||
# upgrades. Runs non-interactively: pre-seeds the resolver cache so the
|
||||
# inner attach_* calls don't pop a dialog from a possibly headless
|
||||
# context.
|
||||
sync_proxmenux_gpu_guard_hooks() {
|
||||
if [[ -z "${__PROXMENUX_RESOLVED_SNIPPETS_STORAGE:-}" ]]; then
|
||||
__PROXMENUX_RESOLVED_SNIPPETS_STORAGE=$(_resolve_snippets_storage "")
|
||||
fi
|
||||
|
||||
ensure_proxmenux_gpu_guard_hookscript
|
||||
|
||||
local vmid ctid
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# ProxMenux - Shared Common Functions
|
||||
# ============================================
|
||||
# Author : MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# Version : 1.0
|
||||
# Last Updated: 29/01/2026
|
||||
# ============================================
|
||||
|
||||
@@ -1,11 +1,33 @@
|
||||
#!/bin/bash
|
||||
# ProxMenux - Universal GPU/iGPU Passthrough to LXC
|
||||
# ==================================================
|
||||
# ==========================================================
|
||||
# ProxMenux - GPU / iGPU Passthrough to LXC
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# License : MIT
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : GPL-3.0
|
||||
# Version : 1.0
|
||||
# Last Updated: 01/04/2026
|
||||
# ==================================================
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Shares a physical GPU (Intel iGPU, AMD or NVIDIA) with an
|
||||
# LXC container on Proxmox VE. Unlike VM passthrough, the
|
||||
# host keeps using the GPU — containers access it through
|
||||
# device nodes, not via VFIO binding.
|
||||
#
|
||||
# Features:
|
||||
# - Multi-vendor detection (Intel / AMD / NVIDIA)
|
||||
# - Multi-GPU selection via checklist
|
||||
# - Switch Mode: detects GPU bound to vfio-pci (VM) and
|
||||
# offers to free it before LXC passthrough
|
||||
# - SR-IOV check (blocks unsupported configurations)
|
||||
# - Automatic dev-node enumeration (DRI, KFD, NVIDIA)
|
||||
# - GID alignment (video / render) between host and CT
|
||||
# - Distro-aware driver install inside the container
|
||||
# (Alpine / Arch / Debian-Ubuntu / NVIDIA .run fallback)
|
||||
# - NVIDIA userspace version matched to host driver
|
||||
# - Container memory bump during NVIDIA install (restored)
|
||||
# - Optional GPU guard hookscript integration
|
||||
# ==========================================================
|
||||
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
@@ -814,7 +836,7 @@ _get_iommu_group_ids() {
|
||||
local dev dev_class
|
||||
dev=$(basename "$dev_path")
|
||||
dev_class=$(cat "/sys/bus/pci/devices/${dev}/class" 2>/dev/null)
|
||||
[[ "$dev_class" == "0x0604" || "$dev_class" == "0x0600" ]] && continue
|
||||
[[ "$dev_class" == 0x0604* || "$dev_class" == 0x0600* ]] && continue
|
||||
local vid did
|
||||
vid=$(cat "/sys/bus/pci/devices/${dev}/vendor" 2>/dev/null | sed 's/0x//')
|
||||
did=$(cat "/sys/bus/pci/devices/${dev}/device" 2>/dev/null | sed 's/0x//')
|
||||
|
||||
@@ -1112,7 +1112,7 @@ analyze_iommu_group() {
|
||||
# Skip PCI bridges and host bridges (class 0x0604 / 0x0600)
|
||||
local dev_class
|
||||
dev_class=$(cat "/sys/bus/pci/devices/${dev}/class" 2>/dev/null)
|
||||
if [[ "$dev_class" == "0x0604" || "$dev_class" == "0x0600" ]]; then
|
||||
if [[ "$dev_class" == 0x0604* || "$dev_class" == 0x0600* ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# ProxMenux - AMD GPU Tools Installer
|
||||
# ============================================
|
||||
# Author : MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# Version : 1.0
|
||||
# Last Updated: 29/01/2026
|
||||
# ============================================
|
||||
|
||||
@@ -1,34 +1,35 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux - Coral TPU Installer (unified: PCIe/M.2 + USB)
|
||||
# =========================================================
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# License : MIT
|
||||
# Version : 2.0 (unified PCIe+USB; auto-detect; feranick fork; libedgetpu runtime)
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : GPL-3.0
|
||||
# Version : 2.0
|
||||
# Last Updated: 17/04/2026
|
||||
# =========================================================
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Single entry point for every Coral variant. At startup the
|
||||
# script detects what Coral hardware is present on the host
|
||||
# and installs only what is actually needed.
|
||||
#
|
||||
# One entry point for every Coral variant. At startup the script detects
|
||||
# what Coral hardware is present on the host and installs only what is
|
||||
# actually needed:
|
||||
#
|
||||
# • Coral M.2 / Mini-PCIe (vendor 1ac1 on PCIe)
|
||||
# → build and install `gasket` + `apex` kernel modules via DKMS
|
||||
# (feranick/gasket-driver fork; google as fallback with patches)
|
||||
# → create apex group + udev rules
|
||||
# → reboot required to load the fresh kernel module
|
||||
#
|
||||
# • Coral USB Accelerator (USB IDs 1a6e:089a / 18d1:9302)
|
||||
# → add the Google Coral APT repository (signed-by keyring)
|
||||
# → install libedgetpu1-std (Edge TPU runtime)
|
||||
# → udev rules come with the package
|
||||
# → no reboot required
|
||||
#
|
||||
# • Both present → both paths are run in sequence
|
||||
# • Neither present → informative dialog and clean exit
|
||||
#
|
||||
# The script is idempotent: reruns on already-configured hosts skip work
|
||||
# that is already done and recover from broken gasket-dkms package state
|
||||
# (typical after a kernel upgrade on PVE 9).
|
||||
# Features:
|
||||
# - Auto-detection of M.2 / Mini-PCIe (vendor 1ac1) and
|
||||
# USB (1a6e:089a / 18d1:9302) Accelerators in one pass
|
||||
# - PCIe path: builds gasket + apex kernel modules via DKMS
|
||||
# using feranick/gasket-driver fork (actively maintained),
|
||||
# google/gasket-driver as fallback with kernel patches
|
||||
# - Kernel-aware patches applied only when needed
|
||||
# (no_llseek → noop_llseek on 6.5+, MODULE_IMPORT_NS
|
||||
# string form on 6.13+)
|
||||
# - apex system group + udev rules for /dev/apex_* nodes
|
||||
# - USB path: Google Coral APT repo (signed-by keyring) +
|
||||
# libedgetpu1-std runtime (udev rules ship with package)
|
||||
# - Both variants present → both paths run in sequence
|
||||
# - Idempotent: reruns skip work already done, recovers
|
||||
# from broken gasket-dkms state after PVE 9 kernel upgrades
|
||||
# - Reboot prompted only when the PCIe path ran
|
||||
# ==========================================================
|
||||
|
||||
# Guarantee a valid working directory before anything else. When the user
|
||||
# re-runs the installer from a previous /tmp/gasket-driver/... path that our
|
||||
|
||||
@@ -1,39 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ProxMenux - Coral TPU Passthrough to LXC
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Revision : @Blaspt (USB passthrough via udev rule with persistent /dev/coral)
|
||||
# Revision : @Blaspt (USB passthrough via udev rule)
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# Version : 1.4 (unprivileged container support, PVE dev API for apex/iGPU)
|
||||
# License : GPL-3.0
|
||||
# Version : 1.4
|
||||
# Last Updated: 01/04/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script automates the configuration and installation of
|
||||
# Coral TPU and iGPU support in Proxmox VE containers. It:
|
||||
# - Configures a selected LXC container for hardware acceleration
|
||||
# - Installs and sets up Coral TPU drivers on the Proxmox host
|
||||
# - Installs necessary drivers inside the container
|
||||
# - Manages required system and container restarts
|
||||
# Configures and installs Coral TPU passthrough (USB and
|
||||
# M.2 / PCIe) in a Proxmox LXC container. Writes the needed
|
||||
# dev / cgroup / mount entries into the LXC config, then
|
||||
# boots the container and installs the Edge TPU runtime
|
||||
# inside it so apps like Frigate can actually use the TPU.
|
||||
# iGPU (DRI) device nodes are added alongside when present,
|
||||
# which is the typical Frigate + Quick Sync combo.
|
||||
#
|
||||
# Supports Coral USB and Coral M.2 (PCIe) devices.
|
||||
# Includes USB passthrough enhancement using persistent udev alias (/dev/coral).
|
||||
#
|
||||
# Changelog v1.3:
|
||||
# - Fixed Coral USB passthrough: mount /dev/bus/usb instead of /dev/coral symlink
|
||||
# The udev symlink /dev/coral is not passthrough-safe in LXC; mounting the full
|
||||
# USB bus tree ensures the real device node is accessible inside the container
|
||||
# regardless of which port the Coral USB is connected to.
|
||||
#
|
||||
# Changelog v1.2:
|
||||
# - Fixed symlink detection for /dev/coral (create=dir for symlinks)
|
||||
# - Fixed /dev/apex_0 not being mounted in PVE 9 (device existence not required)
|
||||
# - Fixed grep patterns to avoid matching commented lines
|
||||
# - Improved device type inference for non-existent devices
|
||||
# - Added duplicate entry cleanup
|
||||
# - Better error handling and logging
|
||||
# Features:
|
||||
# - Supports Coral USB Accelerator and Coral M.2 / PCIe
|
||||
# - Auto-detects M.2 via lspci (Global Unichip), USB via
|
||||
# a persistent udev rule that creates /dev/coral
|
||||
# - USB passthrough mounts /dev/bus/usb (not /dev/coral)
|
||||
# so the container sees the real node even if the user
|
||||
# replugs the device to a different port
|
||||
# - PCIe/M.2 uses the PVE dev API (dev<N>: ... ,gid=apex)
|
||||
# which handles cgroup2 permissions automatically
|
||||
# in both privileged and unprivileged containers
|
||||
# - Fallback cgroup2 + mount if /dev/apex_0 not yet present
|
||||
# (module not loaded on host — reboot still pending)
|
||||
# - Inside container: adds Google Coral APT repo and
|
||||
# installs libedgetpu1-std (default) or -max (optional)
|
||||
# - Also installs iGPU user-space drivers when DRI nodes
|
||||
# are passed, so Quick Sync works out of the box
|
||||
# - Idempotent: duplicate entries in the LXC config are
|
||||
# cleaned up on every run
|
||||
# ==========================================================
|
||||
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
@@ -99,10 +101,16 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="9302", MODE="0666"
|
||||
# Coral Dev Board / Mini PCIe
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="1a6e", ATTRS{idProduct}=="089a", MODE="0666", TAG+="uaccess", SYMLINK+="coral"'
|
||||
|
||||
if [[ ! -f "$RULE_FILE" ]] || ! grep -q "18d1.*9302\|1a6e.*089a" "$RULE_FILE"; then
|
||||
if [[ ! -f "$RULE_FILE" ]]; then
|
||||
echo "$RULE_CONTENT" > "$RULE_FILE"
|
||||
udevadm control --reload-rules && udevadm trigger
|
||||
msg_ok "$(translate 'Udev rules for Coral USB devices added and rules reloaded.')"
|
||||
elif ! grep -q "18d1.*9302\|1a6e.*089a" "$RULE_FILE"; then
|
||||
# Append (>>) instead of overwriting (>) so any user-authored
|
||||
# rules in this file survive. Audit Tier 7 — udev rule sobreescribe.
|
||||
printf '\n%s\n' "$RULE_CONTENT" >> "$RULE_FILE"
|
||||
udevadm control --reload-rules && udevadm trigger
|
||||
msg_ok "$(translate 'Udev rules for Coral USB devices appended and rules reloaded.')"
|
||||
else
|
||||
msg_ok "$(translate 'Udev rules for Coral USB devices already exist.')"
|
||||
fi
|
||||
@@ -276,6 +284,15 @@ configure_lxc_hardware() {
|
||||
if lspci | grep -iq "Global Unichip"; then
|
||||
msg_info "$(translate 'Coral M.2 Apex detected, configuring...')"
|
||||
|
||||
# Pre-flight: warn if the host driver isn't loaded. Without `apex`
|
||||
# the container will see the device file but the TPU won't actually
|
||||
# be usable, and Frigate / coral-libs error out at runtime — much
|
||||
# later than expected. Audit Tier 6 — `install_coral_lxc.sh` no
|
||||
# verifica apex driver cargado.
|
||||
if ! lsmod 2>/dev/null | grep -q '^apex'; then
|
||||
msg_warn "$(translate 'apex kernel module not loaded on host. Run "Install Coral on Host" first or the container will not see /dev/apex_0.')"
|
||||
fi
|
||||
|
||||
local APEX_GID apex_dev_idx
|
||||
APEX_GID=$(getent group apex 2>/dev/null | cut -d: -f3 || echo "0")
|
||||
apex_dev_idx=$(get_next_dev_index "$CONFIG_FILE")
|
||||
@@ -293,9 +310,18 @@ configure_lxc_hardware() {
|
||||
# dynamically from /proc/devices to avoid hardcoding it.
|
||||
local APEX_MAJOR
|
||||
APEX_MAJOR=$(awk '/\bapex\b/{print $1}' /proc/devices 2>/dev/null | head -1)
|
||||
[[ -z "$APEX_MAJOR" ]] && APEX_MAJOR="245"
|
||||
if ! grep -q "lxc.cgroup2.devices.allow: c ${APEX_MAJOR}:0 rwm" "$CONFIG_FILE"; then
|
||||
echo "lxc.cgroup2.devices.allow: c ${APEX_MAJOR}:0 rwm # Coral M2 Apex" >> "$CONFIG_FILE"
|
||||
if [[ -z "$APEX_MAJOR" ]]; then
|
||||
# Hardcoded `245` was wrong on kernels that load drivers in
|
||||
# different order — dynamic majors vary. Surface the failure
|
||||
# so the user knows the cgroup rule won't match and they need
|
||||
# to load the apex module first. Audit Tier 6.
|
||||
msg_warn "$(translate 'Could not detect apex major number from /proc/devices. Load the apex module first: modprobe apex')"
|
||||
APEX_MAJOR=""
|
||||
fi
|
||||
if [[ -n "$APEX_MAJOR" ]]; then
|
||||
if ! grep -q "lxc.cgroup2.devices.allow: c ${APEX_MAJOR}:0 rwm" "$CONFIG_FILE"; then
|
||||
echo "lxc.cgroup2.devices.allow: c ${APEX_MAJOR}:0 rwm # Coral M2 Apex" >> "$CONFIG_FILE"
|
||||
fi
|
||||
fi
|
||||
add_mount_if_needed "/dev/apex_0" "dev/apex_0" "$CONFIG_FILE"
|
||||
msg_ok "$(translate 'Coral M.2 Apex configuration added - device will be available after reboot')"
|
||||
@@ -332,6 +358,15 @@ install_coral_in_container() {
|
||||
|
||||
stop_spinner
|
||||
|
||||
# Pre-flight: refuse to run on non-Debian-family containers. The
|
||||
# apt-get block below would crash with cryptic errors and leave the
|
||||
# container half-configured. Audit Tier 6 — `install_coral_lxc.sh`
|
||||
# asume Debian/Ubuntu sin distro detection.
|
||||
if ! pct exec "$CONTAINER_ID" -- bash -c 'command -v apt-get' &>/dev/null; then
|
||||
msg_error "$(translate 'Container does not have apt-get available. Coral driver installation only supports Debian/Ubuntu containers.')"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Determine driver package for Coral M.2
|
||||
CORAL_M2=$(lspci | grep -i "Global Unichip")
|
||||
if [[ -n "$CORAL_M2" ]]; then
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# ProxMenux - Intel GPU Tools Installer
|
||||
# ============================================
|
||||
# Author : MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# Version : 1.0
|
||||
# Last Updated: 29/01/2026
|
||||
# ============================================
|
||||
|
||||
@@ -1,12 +1,29 @@
|
||||
#!/bin/bash
|
||||
# ProxMenux - NVIDIA Driver Installer (PVE 9.x)
|
||||
# ============================================
|
||||
# ==========================================================
|
||||
# ProxMenux - NVIDIA GPU Driver Installer
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# Version : 1.2 (PVE9, fixed download issues)
|
||||
# License : GPL-3.0
|
||||
# Version : 1.2
|
||||
# Last Updated: 26/03/2026
|
||||
# ============================================
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Installs and manages the NVIDIA proprietary driver on a
|
||||
# Proxmox VE host. Detects hardware, picks a kernel-compatible
|
||||
# driver version and handles the full lifecycle
|
||||
# (install / update / remove).
|
||||
#
|
||||
# Features:
|
||||
# - GPU detection + VFIO passthrough safety check
|
||||
# - Kernel-aware driver version filter (5.15 → 6.17+)
|
||||
# - Nouveau blacklist + module unload
|
||||
# - DKMS-backed install (survives kernel upgrades)
|
||||
# - udev rules + nvidia-persistenced service
|
||||
# - Optional keylase/nvidia-patch (NVENC session limit)
|
||||
# - LXC container driver propagation (Alpine/Arch/Debian)
|
||||
# - Complete uninstall path
|
||||
# ==========================================================
|
||||
|
||||
SCRIPT_TITLE="NVIDIA GPU Driver Installer for Proxmox VE"
|
||||
|
||||
@@ -246,13 +263,6 @@ update_lxc_nvidia() {
|
||||
local install_rc=0
|
||||
|
||||
case "$distro" in
|
||||
alpine)
|
||||
msg_info2 "$(translate 'Upgrading NVIDIA utils (Alpine)...')"
|
||||
pct exec "$ctid" -- sh -c \
|
||||
"apk update && apk add --no-cache --upgrade nvidia-utils" \
|
||||
2>&1 | tee -a "$LOG_FILE"
|
||||
install_rc=${PIPESTATUS[0]}
|
||||
;;
|
||||
arch|manjaro|endeavouros)
|
||||
msg_info2 "$(translate 'Upgrading NVIDIA utils (Arch)...')"
|
||||
pct exec "$ctid" -- bash -c \
|
||||
@@ -270,7 +280,8 @@ update_lxc_nvidia() {
|
||||
install_rc=1
|
||||
else
|
||||
local free_mb
|
||||
free_mb=$(pct exec "$ctid" -- df -m / 2>/dev/null | awk 'NR==2{print $4}' || echo 0)
|
||||
free_mb=$(pct exec "$ctid" -- df -P -m / 2>/dev/null | awk 'END{print $4}')
|
||||
free_mb=${free_mb:-0}
|
||||
if [[ "$free_mb" -lt 1500 ]]; then
|
||||
_restore_container_memory "$ctid"
|
||||
whiptail --backtitle "ProxMenux" \
|
||||
@@ -314,21 +325,51 @@ update_lxc_nvidia() {
|
||||
|
||||
msg_info2 "$(translate 'Running NVIDIA installer in container. This may take several minutes...')"
|
||||
echo "" >>"$LOG_FILE"
|
||||
pct exec "$ctid" -- bash -c "
|
||||
mkdir -p /tmp/nvidia_lxc_install
|
||||
tar -xzf /tmp/nvidia_lxc.tar.gz -C /tmp/nvidia_lxc_install 2>&1
|
||||
/tmp/nvidia_lxc_install/nvidia-installer \
|
||||
--no-kernel-modules \
|
||||
--no-questions \
|
||||
--ui=none \
|
||||
--no-nouveau-check \
|
||||
--no-dkms \
|
||||
--no-install-compat32-libs
|
||||
EXIT=\$?
|
||||
rm -rf /tmp/nvidia_lxc_install /tmp/nvidia_lxc.tar.gz
|
||||
exit \$EXIT
|
||||
" 2>&1 | tee -a "$LOG_FILE"
|
||||
install_rc=${PIPESTATUS[0]}
|
||||
if [[ "$distro" == "alpine" ]]; then
|
||||
# Alpine uses musl libc and does not ship a glibc dynamic
|
||||
# loader, so the nvidia-installer binary (glibc) cannot
|
||||
# execute. We pull `gcompat` to provide the glibc loader
|
||||
# and a libc shim, then copy the userspace libs and the
|
||||
# standard NVIDIA binaries by hand. SONAME symlinks are
|
||||
# built from `readelf` (binutils) instead of trusting a
|
||||
# hard-coded list — the .run ships ~50 .so files and the
|
||||
# set varies between branches.
|
||||
pct exec "$ctid" -- sh -c '
|
||||
set -e
|
||||
mkdir -p /tmp/nvidia_lxc_install
|
||||
tar -xzf /tmp/nvidia_lxc.tar.gz -C /tmp/nvidia_lxc_install
|
||||
apk add --no-cache gcompat binutils >/dev/null
|
||||
cd /tmp/nvidia_lxc_install
|
||||
mkdir -p /usr/lib /usr/bin
|
||||
cp -P *.so* /usr/lib/ 2>/dev/null || true
|
||||
for lib in /usr/lib/lib*.so.*; do
|
||||
[ -f "$lib" ] || continue
|
||||
soname=$(readelf -d "$lib" 2>/dev/null | grep SONAME | head -n1 | sed -e "s/.*\[//" -e "s/\].*//")
|
||||
[ -n "$soname" ] && [ "$(basename "$lib")" != "$soname" ] && ln -sf "$(basename "$lib")" "/usr/lib/$soname"
|
||||
done
|
||||
for bin in nvidia-smi nvidia-debugdump nvidia-cuda-mps-control nvidia-cuda-mps-server nvidia-persistenced nvidia-modprobe; do
|
||||
[ -f "$bin" ] && cp -P "$bin" /usr/bin/ && chmod 755 "/usr/bin/$bin"
|
||||
done
|
||||
rm -rf /tmp/nvidia_lxc_install /tmp/nvidia_lxc.tar.gz
|
||||
' 2>&1 | tee -a "$LOG_FILE"
|
||||
install_rc=${PIPESTATUS[0]}
|
||||
else
|
||||
pct exec "$ctid" -- bash -c "
|
||||
mkdir -p /tmp/nvidia_lxc_install
|
||||
tar -xzf /tmp/nvidia_lxc.tar.gz -C /tmp/nvidia_lxc_install 2>&1
|
||||
/tmp/nvidia_lxc_install/nvidia-installer \
|
||||
--no-kernel-modules \
|
||||
--no-questions \
|
||||
--ui=none \
|
||||
--no-nouveau-check \
|
||||
--no-dkms \
|
||||
--no-install-compat32-libs
|
||||
EXIT=\$?
|
||||
rm -rf /tmp/nvidia_lxc_install /tmp/nvidia_lxc.tar.gz
|
||||
exit \$EXIT
|
||||
" 2>&1 | tee -a "$LOG_FILE"
|
||||
install_rc=${PIPESTATUS[0]}
|
||||
fi
|
||||
|
||||
rm -rf "$extract_dir"
|
||||
_restore_container_memory "$ctid"
|
||||
@@ -596,13 +637,20 @@ get_kernel_compatibility_info() {
|
||||
KERNEL_MAJOR=$(echo "$kernel_version" | cut -d. -f1)
|
||||
KERNEL_MINOR=$(echo "$kernel_version" | cut -d. -f2)
|
||||
|
||||
# Define minimum compatible versions based on kernel
|
||||
# Based on https://docs.nvidia.com/datacenter/tesla/drivers/index.html
|
||||
if [[ "$KERNEL_MAJOR" -ge 6 ]] && [[ "$KERNEL_MINOR" -ge 17 ]]; then
|
||||
# Kernel 6.17+ (Proxmox 9.x) - Requires 580.82.07 or higher
|
||||
MIN_DRIVER_VERSION="580.82.07"
|
||||
# Define minimum compatible versions based on kernel.
|
||||
# Floor bumped from 580.82.07 → 580.105.08 for kernel 6.17+ after a
|
||||
# user report (issue tracked as Sprint 11.4) that 580.82-580.95 builds
|
||||
# fail on kernel 6.17.13 (DKMS module compile errors with the newer
|
||||
# toolchain shipped with PVE 9.1). 580.105.08 is verified working on
|
||||
# the test host. Future kernel 7.x falls into the same bucket — the
|
||||
# `KERNEL_MAJOR -ge 7` branch was previously missing and routed 7.x
|
||||
# kernels to MIN=535 incorrectly.
|
||||
if { [[ "$KERNEL_MAJOR" -ge 7 ]]; } || \
|
||||
{ [[ "$KERNEL_MAJOR" -eq 6 ]] && [[ "$KERNEL_MINOR" -ge 17 ]]; }; then
|
||||
# Kernel 6.17+ / 7.x (Proxmox 9.x +) - Requires 580.105.08 or higher
|
||||
MIN_DRIVER_VERSION="580.105.08"
|
||||
RECOMMENDED_BRANCH="580"
|
||||
COMPATIBILITY_NOTE="Kernel $kernel_version requires NVIDIA driver 580.82.07 or newer"
|
||||
COMPATIBILITY_NOTE="Kernel $kernel_version requires NVIDIA driver 580.105.08 or newer (older 580.x builds fail to compile)"
|
||||
elif [[ "$KERNEL_MAJOR" -ge 6 ]] && [[ "$KERNEL_MINOR" -ge 8 ]]; then
|
||||
# Kernel 6.8-6.16 (Proxmox 8.2+) - Works with 550.x or higher
|
||||
MIN_DRIVER_VERSION="550"
|
||||
@@ -635,31 +683,131 @@ is_version_compatible() {
|
||||
ver_minor=$(echo "$version" | cut -d. -f2)
|
||||
ver_patch=$(echo "$version" | cut -d. -f3)
|
||||
|
||||
if [[ "$MIN_DRIVER_VERSION" == "580.82.07" ]]; then
|
||||
# Compare full version: must be >= 580.82.07
|
||||
if [[ ${ver_major} -gt 580 ]]; then
|
||||
return 0
|
||||
elif [[ ${ver_major} -eq 580 ]]; then
|
||||
if [[ $((10#${ver_minor})) -gt 82 ]]; then
|
||||
# Full-version comparison when MIN is dotted (e.g. "580.105.08").
|
||||
# Strips the dotted threshold from MIN_DRIVER_VERSION and reuses the
|
||||
# existing `version_le` helper. The previous code had a hardcoded
|
||||
# branch only for "580.82.07" — bumping the floor required editing two
|
||||
# places. Sprint 11.4.
|
||||
case "$MIN_DRIVER_VERSION" in
|
||||
*.*.*)
|
||||
# Dotted threshold: compare full triple.
|
||||
local _min_major _min_minor _min_patch
|
||||
IFS='.' read -r _min_major _min_minor _min_patch <<<"$MIN_DRIVER_VERSION"
|
||||
_min_major=${_min_major:-0}
|
||||
_min_minor=${_min_minor:-0}
|
||||
_min_patch=${_min_patch:-0}
|
||||
ver_minor=${ver_minor:-0}
|
||||
ver_patch=${ver_patch:-0}
|
||||
if (( 10#$ver_major > 10#$_min_major )); then
|
||||
return 0
|
||||
elif [[ $((10#${ver_minor})) -eq 82 ]]; then
|
||||
if [[ $((10#${ver_patch:-0})) -ge 7 ]]; then
|
||||
elif (( 10#$ver_major == 10#$_min_major )); then
|
||||
if (( 10#$ver_minor > 10#$_min_minor )); then
|
||||
return 0
|
||||
elif (( 10#$ver_minor == 10#$_min_minor )); then
|
||||
if (( 10#${ver_patch:-0} >= 10#$_min_patch )); then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
if [[ ${ver_major} -ge ${MIN_DRIVER_VERSION} ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
# Single-major threshold (e.g. "550", "535"): compare major only.
|
||||
if [[ ${ver_major} -ge ${MIN_DRIVER_VERSION} ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
is_current_nvidia_patched() {
|
||||
local status_file="/usr/local/share/proxmenux/components_status.json"
|
||||
[[ -f "$status_file" ]] || return 1
|
||||
command -v jq >/dev/null 2>&1 || return 1
|
||||
local patched
|
||||
patched=$(jq -r '.nvidia_driver.patched // false' "$status_file" 2>/dev/null)
|
||||
[[ "$patched" == "true" ]]
|
||||
}
|
||||
|
||||
KEYLASE_PATCH_CACHE="/var/cache/proxmenux/keylase_patch_versions.txt"
|
||||
KEYLASE_PATCH_TTL_SECONDS=$((7 * 86400))
|
||||
KEYLASE_PATCH_URL="https://raw.githubusercontent.com/keylase/nvidia-patch/master/patch.sh"
|
||||
|
||||
refresh_keylase_patch_cache() {
|
||||
local now ts age
|
||||
now=$(date +%s)
|
||||
if [[ -f "$KEYLASE_PATCH_CACHE" ]]; then
|
||||
ts=$(stat -c '%Y' "$KEYLASE_PATCH_CACHE" 2>/dev/null || echo 0)
|
||||
age=$(( now - ts ))
|
||||
if (( age < KEYLASE_PATCH_TTL_SECONDS )) && [[ -s "$KEYLASE_PATCH_CACHE" ]]; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
mkdir -p "$(dirname "$KEYLASE_PATCH_CACHE")" 2>/dev/null || return 1
|
||||
local tmp
|
||||
tmp=$(mktemp)
|
||||
if curl -fsSL --max-time 15 "$KEYLASE_PATCH_URL" 2>/dev/null \
|
||||
| grep -oE '\["[0-9]+\.[0-9]+(\.[0-9]+)?"\]' \
|
||||
| sed -E 's/\["([0-9.]+)"\]/\1/' \
|
||||
| sort -u > "$tmp" && [[ -s "$tmp" ]]; then
|
||||
mv "$tmp" "$KEYLASE_PATCH_CACHE"
|
||||
return 0
|
||||
fi
|
||||
rm -f "$tmp"
|
||||
return 1
|
||||
}
|
||||
|
||||
is_keylase_patch_supported() {
|
||||
local ver="$1"
|
||||
[[ -z "$ver" ]] && return 1
|
||||
[[ -f "$KEYLASE_PATCH_CACHE" && -s "$KEYLASE_PATCH_CACHE" ]] || return 1
|
||||
grep -qFx "$ver" "$KEYLASE_PATCH_CACHE"
|
||||
}
|
||||
|
||||
filter_keylase_supported() {
|
||||
local versions_in="$1"
|
||||
while IFS= read -r ver; do
|
||||
[[ -z "$ver" ]] && continue
|
||||
if is_keylase_patch_supported "$ver"; then
|
||||
printf '%s\n' "$ver"
|
||||
fi
|
||||
done <<< "$versions_in"
|
||||
}
|
||||
|
||||
filter_option_c_branch() {
|
||||
local versions_in="$1"
|
||||
local current="$2"
|
||||
local recommended_branch="$3"
|
||||
local target_branch=""
|
||||
|
||||
if [[ -n "$current" && "$current" =~ ^([0-9]+)\. ]]; then
|
||||
local current_branch="${BASH_REMATCH[1]}"
|
||||
if is_version_compatible "$current"; then
|
||||
target_branch="$current_branch"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "$target_branch" ]]; then
|
||||
target_branch="$recommended_branch"
|
||||
fi
|
||||
|
||||
if [[ -z "$target_branch" ]]; then
|
||||
printf '%s\n' "$versions_in"
|
||||
return 0
|
||||
fi
|
||||
|
||||
while IFS= read -r ver; do
|
||||
[[ -z "$ver" ]] && continue
|
||||
local ver_major="${ver%%.*}"
|
||||
if [[ "$ver_major" == "$target_branch" ]]; then
|
||||
printf '%s\n' "$ver"
|
||||
fi
|
||||
done <<< "$versions_in"
|
||||
}
|
||||
|
||||
version_le() {
|
||||
local v1="$1"
|
||||
local v2="$2"
|
||||
@@ -981,8 +1129,16 @@ EOF
|
||||
|
||||
ensure_workdir
|
||||
cd "$NVIDIA_WORKDIR" || return 1
|
||||
# Pin to the last release tag so a hostile push to upstream `master`
|
||||
# can't slip arbitrary code into the install. Bump as needed; the
|
||||
# `--depth 1` keeps the clone fast. Audit Tier 6 — `nvidia-persistenced`
|
||||
# git clone sin pinning de versión.
|
||||
local NVIDIA_PERSISTENCED_TAG="${NVIDIA_PERSISTENCED_TAG:-575.64.05}"
|
||||
if [[ ! -d nvidia-persistenced ]]; then
|
||||
git clone https://github.com/NVIDIA/nvidia-persistenced.git >>"$LOG_FILE" 2>&1 || true
|
||||
git clone --depth 1 --branch "$NVIDIA_PERSISTENCED_TAG" \
|
||||
https://github.com/NVIDIA/nvidia-persistenced.git >>"$LOG_FILE" 2>&1 \
|
||||
|| git clone --depth 1 https://github.com/NVIDIA/nvidia-persistenced.git >>"$LOG_FILE" 2>&1 \
|
||||
|| true
|
||||
fi
|
||||
|
||||
if [[ -d nvidia-persistenced/init ]]; then
|
||||
@@ -1004,8 +1160,25 @@ apply_nvidia_patch_if_needed() {
|
||||
msg_info "$(translate 'Cloning and applying NVIDIA patch (keylase/nvidia-patch)...')"
|
||||
ensure_workdir
|
||||
cd "$NVIDIA_WORKDIR" || return 1
|
||||
# Pin keylase/nvidia-patch to a known-good commit. Override via env var
|
||||
# for forward-compat as new driver versions land. patch.sh ships a list
|
||||
# of supported drivers in the repo; if our running driver isn't covered
|
||||
# the patch silently no-ops, so we surface a warning before running.
|
||||
# Audit Tier 6 — `keylase/nvidia-patch` sin pinning + sin compat check.
|
||||
local NVIDIA_PATCH_REF="${NVIDIA_PATCH_REF:-master}"
|
||||
if [[ ! -d nvidia-patch ]]; then
|
||||
git clone https://github.com/keylase/nvidia-patch.git >>"$LOG_FILE" 2>&1 || true
|
||||
git clone --depth 1 --branch "$NVIDIA_PATCH_REF" \
|
||||
https://github.com/keylase/nvidia-patch.git >>"$LOG_FILE" 2>&1 \
|
||||
|| git clone --depth 1 https://github.com/keylase/nvidia-patch.git >>"$LOG_FILE" 2>&1 \
|
||||
|| true
|
||||
fi
|
||||
|
||||
# Best-effort compatibility check: peek the supported-driver list in
|
||||
# patch.sh and warn if our driver isn't on it.
|
||||
if [[ -n "$CURRENT_DRIVER_VERSION" && -f nvidia-patch/patch.sh ]]; then
|
||||
if ! grep -qF "$CURRENT_DRIVER_VERSION" nvidia-patch/patch.sh 2>/dev/null; then
|
||||
msg_warn "$(translate 'NVIDIA driver') $CURRENT_DRIVER_VERSION $(translate 'is not in the patch.sh supported list. The patch may no-op or fail; review keylase/nvidia-patch README before continuing.')"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -x nvidia-patch/patch.sh ]]; then
|
||||
@@ -1132,6 +1305,15 @@ show_version_menu() {
|
||||
current_list="$filtered_list"
|
||||
fi
|
||||
|
||||
# Option C: kernel-compat alone is too permissive (e.g. kernel 6.14
|
||||
# accepts ≥ 550 so 595.x shows up — but 595.x has historically broken
|
||||
# builds on this kernel). Restrict the offered list to the user's
|
||||
# current branch when their installed driver still works, otherwise
|
||||
# fall back to the recommended branch for the kernel.
|
||||
if [[ -n "$current_list" ]]; then
|
||||
current_list=$(filter_option_c_branch "$current_list" "$CURRENT_DRIVER_VERSION" "$RECOMMENDED_BRANCH")
|
||||
fi
|
||||
|
||||
if [[ -n "$latest" ]]; then
|
||||
local filtered_max_list=""
|
||||
while IFS= read -r ver; do
|
||||
@@ -1143,8 +1325,42 @@ show_version_menu() {
|
||||
current_list="$filtered_max_list"
|
||||
fi
|
||||
|
||||
# If the user has the keylase NVENC patch applied, only offer versions
|
||||
# that the patch supports — picking an unsupported version reinstalls
|
||||
# the driver fine but the patch silently no-ops afterwards, so the
|
||||
# user loses NVENC limit removal without warning.
|
||||
local patch_filtered=false
|
||||
local patch_filter_note=""
|
||||
if is_current_nvidia_patched && [[ -n "$current_list" ]]; then
|
||||
if refresh_keylase_patch_cache; then
|
||||
local trimmed
|
||||
trimmed=$(filter_keylase_supported "$current_list")
|
||||
if [[ -n "$trimmed" ]]; then
|
||||
current_list="$trimmed"
|
||||
patch_filtered=true
|
||||
else
|
||||
patch_filter_note="$(translate 'No version in this branch is currently supported by keylase/nvidia-patch — the NVENC patch will not reapply after reinstall.')"
|
||||
fi
|
||||
else
|
||||
patch_filter_note="$(translate 'Could not fetch keylase/nvidia-patch supported list — patch reapply compatibility is not verified.')"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Recompute "latest" as the highest version still in the filtered list
|
||||
# so the menu's "Latest available" label matches what we actually offer
|
||||
# rather than the global upstream latest (which may have been filtered
|
||||
# out by Option C / kernel-compat / patch awareness).
|
||||
if [[ -n "$current_list" ]]; then
|
||||
latest=$(printf '%s\n' "$current_list" | head -n1 | tr -d '[:space:]')
|
||||
fi
|
||||
|
||||
local menu_text="$(translate 'Select the NVIDIA driver version to install:')\n\n"
|
||||
menu_text+="$(translate 'Versions shown are compatible with your kernel. Latest available is recommended in most cases.')"
|
||||
if $patch_filtered; then
|
||||
menu_text+="\n\n$(translate 'NVENC patch detected — list narrowed to versions supported by keylase/nvidia-patch.')"
|
||||
elif [[ -n "$patch_filter_note" ]]; then
|
||||
menu_text+="\n\n${patch_filter_note}"
|
||||
fi
|
||||
|
||||
local choices=()
|
||||
choices+=("latest" "$(translate 'Latest available') (${latest:-unknown})")
|
||||
@@ -1186,6 +1402,12 @@ show_version_menu() {
|
||||
# Main flow
|
||||
# ==========================================================
|
||||
main() {
|
||||
# Rotate the previous run's log instead of truncating — when the
|
||||
# current install fails, the user can compare against the previous
|
||||
# attempt to see what changed. Audit Tier 7 — log truncation.
|
||||
if [[ -f "$LOG_FILE" && -s "$LOG_FILE" ]]; then
|
||||
cp -p "$LOG_FILE" "${LOG_FILE}.prev" 2>/dev/null || true
|
||||
fi
|
||||
: >"$LOG_FILE"
|
||||
: >"$screen_capture"
|
||||
|
||||
|
||||
@@ -8,6 +8,35 @@
|
||||
# Version : 1.0
|
||||
# Last Updated: 05/04/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Moves an already-assigned GPU between the two modes it can
|
||||
# live in on a Proxmox host:
|
||||
# - VM mode (bound to vfio-pci, exclusive to one VM)
|
||||
# - LXC mode (bound to the native driver, shared with CTs)
|
||||
#
|
||||
# Detects the current mode of each selected GPU and applies
|
||||
# the host-side changes needed to switch (vfio.conf,
|
||||
# blacklist.conf, /etc/modules, initramfs). Also handles the
|
||||
# VM/LXC side so the switch doesn't leave dangling config
|
||||
# pointing at a GPU the workload can no longer access.
|
||||
#
|
||||
# Features:
|
||||
# - Multi-GPU selection (uniform current mode enforced)
|
||||
# - SR-IOV guard (blocks VF / active-PF passthrough)
|
||||
# - Blocked-ID policy list (e.g. Intel Arc A770)
|
||||
# - IOMMU-group aware ID collection (sweeps siblings)
|
||||
# - Conflict policy per affected VM/LXC
|
||||
# (keep + disable onboot OR remove from config)
|
||||
# - Orphan audio cascade: when a GPU leaves a VM, offer
|
||||
# to remove companion audio hostpci entries and clean
|
||||
# vfio.conf if no other VM still uses those IDs
|
||||
# - Precise BDF regex for hostpci removal
|
||||
# (no substring collision between unrelated GPUs)
|
||||
# - NVIDIA stack sanitize/restore (udev, module-load,
|
||||
# hard-blacklist) depending on target mode
|
||||
# - Rebuilds initramfs only if host config actually changed
|
||||
# - Reboot prompt at the end
|
||||
# ==========================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LOCAL_SCRIPTS_LOCAL="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
@@ -28,15 +57,24 @@ screen_capture="/tmp/proxmenux_gpu_switch_mode_screen_$$.txt"
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
# Both helper libraries are required for the SR-IOV guard and the audio
|
||||
# orphan cascade to work. Surface a loud warning if neither path resolves
|
||||
# — the previous behaviour evaluated `declare -F` later and silently
|
||||
# disabled the validations, leaving the user thinking they were
|
||||
# protected. Audit Tier 6 — `switch_gpu_mode.sh` silent helper loss.
|
||||
if [[ -f "$LOCAL_SCRIPTS_LOCAL/global/pci_passthrough_helpers.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS_LOCAL/global/pci_passthrough_helpers.sh"
|
||||
elif [[ -f "$LOCAL_SCRIPTS_DEFAULT/global/pci_passthrough_helpers.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS_DEFAULT/global/pci_passthrough_helpers.sh"
|
||||
else
|
||||
msg_warn "$(translate 'pci_passthrough_helpers.sh missing — SR-IOV / orphan-audio guards will be skipped')"
|
||||
fi
|
||||
if [[ -f "$LOCAL_SCRIPTS_LOCAL/global/gpu_hook_guard_helpers.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS_LOCAL/global/gpu_hook_guard_helpers.sh"
|
||||
elif [[ -f "$LOCAL_SCRIPTS_DEFAULT/global/gpu_hook_guard_helpers.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS_DEFAULT/global/gpu_hook_guard_helpers.sh"
|
||||
else
|
||||
msg_warn "$(translate 'gpu_hook_guard_helpers.sh missing — VM hookscript guard will be skipped')"
|
||||
fi
|
||||
|
||||
load_language
|
||||
@@ -130,7 +168,7 @@ _get_iommu_group_ids() {
|
||||
local dev dev_class vid did
|
||||
dev=$(basename "$dev_path")
|
||||
dev_class=$(cat "/sys/bus/pci/devices/${dev}/class" 2>/dev/null)
|
||||
[[ "$dev_class" == "0x0604" || "$dev_class" == "0x0600" ]] && continue
|
||||
[[ "$dev_class" == 0x0604* || "$dev_class" == 0x0600* ]] && continue
|
||||
vid=$(cat "/sys/bus/pci/devices/${dev}/vendor" 2>/dev/null | sed 's/0x//')
|
||||
did=$(cat "/sys/bus/pci/devices/${dev}/device" 2>/dev/null | sed 's/0x//')
|
||||
[[ -n "$vid" && -n "$did" ]] && echo "${vid}:${did}"
|
||||
@@ -978,8 +1016,21 @@ apply_vm_action_for_lxc_mode() {
|
||||
# switch-back) or it steals host audio unnecessarily. Enumerate
|
||||
# orphan audio hostpci entries and ask the user what to do.
|
||||
if declare -F _vm_list_orphan_audio_hostpci >/dev/null 2>&1; then
|
||||
local _orphan_audio
|
||||
_orphan_audio=$(_vm_list_orphan_audio_hostpci "$vmid" "${SELECTED_PCI_SLOTS[0]}")
|
||||
# Concatenate orphan-audio entries across ALL selected GPUs.
|
||||
# The previous code only checked `SELECTED_PCI_SLOTS[0]`, so when
|
||||
# the user switched 2 dGPUs at once and each had its own audio
|
||||
# companion, the second GPU's audio was left dangling in the VM
|
||||
# config. Audit Tier 6 — orphan audio solo del primer slot.
|
||||
local _orphan_audio=""
|
||||
local _slot
|
||||
for _slot in "${SELECTED_PCI_SLOTS[@]}"; do
|
||||
local _piece
|
||||
_piece=$(_vm_list_orphan_audio_hostpci "$vmid" "$_slot")
|
||||
if [[ -n "$_piece" ]]; then
|
||||
[[ -n "$_orphan_audio" ]] && _orphan_audio+=$'\n'
|
||||
_orphan_audio+="$_piece"
|
||||
fi
|
||||
done
|
||||
if [[ -n "$_orphan_audio" ]]; then
|
||||
local -a _orph_items=()
|
||||
local _line _o_idx _o_bdf _o_name
|
||||
@@ -1111,6 +1162,15 @@ switch_to_vm_mode() {
|
||||
msg_ok "$(translate 'IOMMU is already active on this system')" | tee -a "$screen_capture"
|
||||
elif grep -qE 'intel_iommu=on|amd_iommu=on' /etc/kernel/cmdline 2>/dev/null || \
|
||||
grep -qE 'intel_iommu=on|amd_iommu=on' /etc/default/grub 2>/dev/null; then
|
||||
# Cross-check that IOMMU is *actually* active in the running kernel.
|
||||
# The kernel parameter alone doesn't guarantee functional IOMMU —
|
||||
# if the BIOS toggle is off, /sys/kernel/iommu_groups/ is empty even
|
||||
# though intel_iommu=on is in cmdline. Without this gate we'd write
|
||||
# vfio.conf and after reboot the GPU never gets claimed by VFIO.
|
||||
# Audit Tier 6 — IOMMU check optimista.
|
||||
if ! find /sys/kernel/iommu_groups -mindepth 1 -maxdepth 1 -name '[0-9]*' 2>/dev/null | grep -q .; then
|
||||
msg_warn "$(translate 'intel_iommu/amd_iommu is set in cmdline but no IOMMU groups exist — IOMMU appears disabled in BIOS. Enable VT-d / AMD-Vi in firmware before continuing.')"
|
||||
fi
|
||||
_register_iommu_tool
|
||||
HOST_CONFIG_CHANGED=true
|
||||
msg_ok "$(translate 'IOMMU already configured in kernel parameters')" | tee -a "$screen_capture"
|
||||
|
||||
@@ -144,7 +144,7 @@ _get_iommu_group_ids() {
|
||||
local dev dev_class vid did
|
||||
dev=$(basename "$dev_path")
|
||||
dev_class=$(cat "/sys/bus/pci/devices/${dev}/class" 2>/dev/null)
|
||||
[[ "$dev_class" == "0x0604" || "$dev_class" == "0x0600" ]] && continue
|
||||
[[ "$dev_class" == 0x0604* || "$dev_class" == 0x0600* ]] && continue
|
||||
vid=$(cat "/sys/bus/pci/devices/${dev}/vendor" 2>/dev/null | sed 's/0x//')
|
||||
did=$(cat "/sys/bus/pci/devices/${dev}/device" 2>/dev/null | sed 's/0x//')
|
||||
[[ -n "$vid" && -n "$did" ]] && echo "${vid}:${did}"
|
||||
|
||||
+106
-12
@@ -1,21 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ProxMenux - Help and Info (Command Reference)
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 28/01/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script provides an interactive command reference menu
|
||||
# for Proxmox VE via dialog-based UI.
|
||||
# - Categorized and translated lists of common and advanced commands.
|
||||
# - Covers system, network, storage, VM/CT, updates, GPU passthrough,
|
||||
# ZFS, backup/restore, and essential CLI tools.
|
||||
# - Allows users to view or execute commands directly from the menu.
|
||||
# Interactive command-reference menu for Proxmox VE. Each
|
||||
# section lists numbered commands with translated descriptions;
|
||||
# the user can pick a number to execute the command directly,
|
||||
# paste a custom command, or press 0 / Esc to go back.
|
||||
#
|
||||
# Sections (9):
|
||||
# 1. Useful System Commands
|
||||
# 2. VM and CT Management
|
||||
# 3. Storage and Disks
|
||||
# 4. Network Commands
|
||||
# 5. Updates and Packages
|
||||
# 6. GPU / TPU Passthrough
|
||||
# 7. ZFS Management
|
||||
# 8. Backup and Restore
|
||||
# 9. System CLI Tools
|
||||
#
|
||||
# The menu also auto-installs 'dialog' if missing.
|
||||
# ==========================================================
|
||||
|
||||
# Configuration ============================================
|
||||
@@ -38,8 +48,16 @@ GREEN="\033[0;32m"
|
||||
NC="\033[0m"
|
||||
|
||||
if ! command -v dialog &>/dev/null; then
|
||||
# Surface apt failures so the user knows why the menu won't render.
|
||||
# The previous silent install made the next dialog call error with
|
||||
# "command not found" with no context. Audit Tier 6 — `help_info_menu.sh`
|
||||
# apt silent.
|
||||
apt update -qq >/dev/null 2>&1
|
||||
apt install -y dialog >/dev/null 2>&1
|
||||
if ! apt install -y dialog >/dev/null 2>&1; then
|
||||
echo "ERROR: failed to install 'dialog' (required for the help menu)." >&2
|
||||
echo "Run 'apt install dialog' manually and try again." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -170,6 +188,10 @@ show_vm_ct_commands() {
|
||||
echo -e "11) ${GN}[Only with menu] Show CT users for permission mapping${NC} - $(translate 'root and real users only')"
|
||||
echo -e "12) ${GREEN}pct exec <ctid> -- getent passwd | column -t -s :${NC} - $(translate 'Show CT users in table format')"
|
||||
echo -e "13) ${GREEN}pct exec <ctid> -- ps aux --sort=-%mem | head${NC} - $(translate 'Top memory processes in CT')"
|
||||
echo -e "14) ${GREEN}cat /etc/pve/qemu-server/<vmid>.conf${NC} - $(translate 'View raw VM configuration file')"
|
||||
echo -e "15) ${GREEN}cat /etc/pve/lxc/<ctid>.conf${NC} - $(translate 'View raw CT configuration file')"
|
||||
echo -e "16) ${GREEN}nano /etc/pve/qemu-server/<vmid>.conf${NC} - $(translate 'Edit raw VM configuration file')"
|
||||
echo -e "17) ${GREEN}nano /etc/pve/lxc/<ctid>.conf${NC} - $(translate 'Edit raw CT configuration file')"
|
||||
echo -e " ${DEF}0) $(translate ' Back to previous menu or Esc + Enter')"
|
||||
echo
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter a number, or write or paste a command: ') ${CL}"
|
||||
@@ -222,11 +244,31 @@ show_vm_ct_commands() {
|
||||
;;
|
||||
|
||||
13)
|
||||
|
||||
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter CT ID: ')${CL}"
|
||||
read -r id
|
||||
cmd="pct exec $id -- ps aux --sort=-%mem | head"
|
||||
;;
|
||||
14)
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter VM ID: ')${CL}"
|
||||
read -r id
|
||||
cmd="cat /etc/pve/qemu-server/$id.conf"
|
||||
;;
|
||||
15)
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter CT ID: ')${CL}"
|
||||
read -r id
|
||||
cmd="cat /etc/pve/lxc/$id.conf"
|
||||
;;
|
||||
16)
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter VM ID: ')${CL}"
|
||||
read -r id
|
||||
cmd="nano /etc/pve/qemu-server/$id.conf"
|
||||
;;
|
||||
17)
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter CT ID: ')${CL}"
|
||||
read -r id
|
||||
cmd="nano /etc/pve/lxc/$id.conf"
|
||||
;;
|
||||
0) break ;;
|
||||
*) cmd="$user_input" ;;
|
||||
esac
|
||||
@@ -271,6 +313,14 @@ show_storage_commands() {
|
||||
echo -e "20) ${GREEN}qm importdisk <vmid> <img> <storage>${NC} - $(translate 'Import disk image to VM')"
|
||||
echo -e "21) ${GREEN}qm set <vmid> -<bus><index> <disk>${NC} - $(translate 'Add physical disk to VM via') passthrough"
|
||||
echo -e "22) ${GREEN}qemu-img convert -O <format> <input> <output>${NC} - $(translate 'Convert disk image format')"
|
||||
echo -e "23) ${GREEN}smartctl --scan${NC} - $(translate 'List SMART-capable devices')"
|
||||
echo -e "24) ${GREEN}smartctl -H /dev/<disk>${NC} - $(translate 'Quick health check (PASSED / FAILED)')"
|
||||
echo -e "25) ${GREEN}smartctl -a /dev/<disk>${NC} - $(translate 'Full SMART info and attributes')"
|
||||
echo -e "26) ${GREEN}smartctl -t short /dev/<disk>${NC} - $(translate 'Start short self-test (~2 min)')"
|
||||
echo -e "27) ${GREEN}smartctl -t long /dev/<disk>${NC} - $(translate 'Start long self-test (hours)')"
|
||||
echo -e "28) ${GREEN}smartctl -l selftest /dev/<disk>${NC} - $(translate 'View self-test log')"
|
||||
echo -e "29) ${GREEN}nvme list${NC} - $(translate 'List NVMe devices')"
|
||||
echo -e "30) ${GREEN}nvme smart-log /dev/<nvme>${NC} - $(translate 'NVMe-specific SMART log')"
|
||||
echo -e " ${DEF}0) $(translate ' Back to previous menu or Esc + Enter')"
|
||||
echo
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter a number, or write or paste a command: ') ${CL}"
|
||||
@@ -453,6 +503,50 @@ show_storage_commands() {
|
||||
echo -e "\n${YELLOW}$(translate 'Converting image using command:')${NC}"
|
||||
cmd="qemu-img convert -O $output_format $input_image $output_image"
|
||||
;;
|
||||
23) cmd="smartctl --scan" ;;
|
||||
24)
|
||||
lsblk -dno NAME,SIZE,MODEL | grep -vE 'loop|dm-|zd' | sed 's/^/ /'
|
||||
echo
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter device (e.g., sda or nvme0): ')${CL}"
|
||||
read -r dev
|
||||
cmd="smartctl -H /dev/$dev"
|
||||
;;
|
||||
25)
|
||||
lsblk -dno NAME,SIZE,MODEL | grep -vE 'loop|dm-|zd' | sed 's/^/ /'
|
||||
echo
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter device (e.g., sda or nvme0): ')${CL}"
|
||||
read -r dev
|
||||
cmd="smartctl -a /dev/$dev"
|
||||
;;
|
||||
26)
|
||||
lsblk -dno NAME,SIZE,MODEL | grep -vE 'loop|dm-|zd' | sed 's/^/ /'
|
||||
echo
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter device (e.g., sda or nvme0): ')${CL}"
|
||||
read -r dev
|
||||
cmd="smartctl -t short /dev/$dev"
|
||||
;;
|
||||
27)
|
||||
lsblk -dno NAME,SIZE,MODEL | grep -vE 'loop|dm-|zd' | sed 's/^/ /'
|
||||
echo
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter device (e.g., sda or nvme0): ')${CL}"
|
||||
read -r dev
|
||||
cmd="smartctl -t long /dev/$dev"
|
||||
;;
|
||||
28)
|
||||
lsblk -dno NAME,SIZE,MODEL | grep -vE 'loop|dm-|zd' | sed 's/^/ /'
|
||||
echo
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter device (e.g., sda or nvme0): ')${CL}"
|
||||
read -r dev
|
||||
cmd="smartctl -l selftest /dev/$dev"
|
||||
;;
|
||||
29) cmd="nvme list" ;;
|
||||
30)
|
||||
ls /dev/nvme* 2>/dev/null | sed 's/^/ /'
|
||||
echo
|
||||
echo -en "${TAB}${BOLD}${YW}${HOLD}$(translate 'Enter NVMe device (e.g., nvme0): ')${CL}"
|
||||
read -r dev
|
||||
cmd="nvme smart-log /dev/$dev"
|
||||
;;
|
||||
0) break ;;
|
||||
*) cmd="$user_input" ;;
|
||||
esac
|
||||
|
||||
@@ -1,13 +1,39 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ProxMenux - Settings (Configuration Menu)
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# Author : MacRimi
|
||||
# Contributors : cod378
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# Version : 1.1
|
||||
# Last Updated: 04/07/2025
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.1
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# ProxMenux configuration / settings menu. Options are shown
|
||||
# conditionally based on the install type and current state:
|
||||
#
|
||||
# - ProxMenux Monitor (Activate / Deactivate + Show Status)
|
||||
# Only if proxmenux-monitor.service is registered with
|
||||
# systemd. Toggles between active / inactive states.
|
||||
#
|
||||
# - Deactivate Beta Program
|
||||
# Only if config.json has beta_program.status = "active".
|
||||
# Stops beta update prompts; stable updates continue.
|
||||
#
|
||||
# - Change Language
|
||||
# Only on the Translation install type (venv +
|
||||
# config.json.language present). Languages: en / es / fr /
|
||||
# de / it / pt.
|
||||
#
|
||||
# - Show Version Information
|
||||
# Always shown. Reports installed components, files,
|
||||
# virtual environment state and current language.
|
||||
#
|
||||
# - Uninstall ProxMenux
|
||||
# Always shown. Interactive uninstall with optional
|
||||
# dependency removal (jq, dialog, python3-*, ...) and
|
||||
# restoration of /root/.bashrc + /etc/motd backups.
|
||||
# ==========================================================
|
||||
|
||||
# Configuration ============================================
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenuX - Virtual Machine Creator Script
|
||||
# ProxMenux - Virtual Machine Creator Menu
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 07/05/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script is part of the central ProxMenux VM creation module. It allows users
|
||||
# to create virtual machines (VMs) in Proxmox VE using either default or advanced
|
||||
# configurations, streamlining the deployment of Linux, Windows, and other systems.
|
||||
# Central VM creation dispatcher for ProxMenux. Presents the user
|
||||
# with OS-family options (NAS, Windows, Linux, macOS, Others) and
|
||||
# routes to the matching ISO selector and configuration wizard.
|
||||
#
|
||||
# Key features:
|
||||
# - Supports virtual disks, import disks, and Controller + NVMe passthrough.
|
||||
# - Automates CPU, RAM, BIOS, network and storage configuration.
|
||||
# - Provides a user-friendly menu to select OS type, ISO image and disk interface.
|
||||
# - Automatically generates a detailed and styled HTML description for each VM.
|
||||
#
|
||||
# All operations are designed to simplify and accelerate VM creation in a
|
||||
# consistent and maintainable way, using ProxMenux standards.
|
||||
# Features:
|
||||
# - Dispatches to ISO selectors: NAS / Windows / Linux / Others.
|
||||
# - Default vs Advanced flows: CPU, RAM, BIOS, network, storage.
|
||||
# - Virtual disks, disk import, and Controller+NVMe passthrough.
|
||||
# - Optional GPU passthrough wizard post-creation.
|
||||
# - Auto-generates a styled HTML description for each VM.
|
||||
# - macOS path is external: launches the OSX-PROXMOX installer.
|
||||
# ==========================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
@@ -144,7 +143,7 @@ while true; do
|
||||
2 "$(translate "Create") VM System Windows" \
|
||||
3 "$(translate "Create") VM System Linux" \
|
||||
"" "" \
|
||||
"" "\Z4──────────────────────────────────────────────────\Zn" \
|
||||
"" "\Z4───────────────── Community Scripts ─────────────────\Zn" \
|
||||
"" "" \
|
||||
4 "$(translate "Create") VM System macOS (OSX-PROXMOX)" \
|
||||
5 "$(translate "Create") VM System Others (based Linux)" \
|
||||
@@ -152,7 +151,6 @@ while true; do
|
||||
6 "$(translate "Return to Main Menu")" \
|
||||
3>&1 1>&2 2>&3)
|
||||
|
||||
|
||||
[[ $? -ne 0 || "$OS_TYPE" == "6" ]] && exec bash "$MENU_REPO/main_menu.sh"
|
||||
|
||||
case "$OS_TYPE" in
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# Version : 2.0
|
||||
# Last Updated: 01/04/2026
|
||||
# ==========================================================
|
||||
|
||||
@@ -1,21 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ProxMenux - Proxmox VE Helper Scripts Browser
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.3
|
||||
# Last Updated: 14/03/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script provides a simple and efficient way to access and execute Proxmox VE scripts
|
||||
# from the Community Scripts project (https://community-scripts.github.io/ProxmoxVE/).
|
||||
# Front-end for the community-scripts/ProxmoxVE catalog
|
||||
# (https://community-scripts.github.io/ProxmoxVE/) —
|
||||
# the spiritual continuation of tteck's helper scripts.
|
||||
#
|
||||
# It serves as a convenient tool to run key automation scripts that simplify system management,
|
||||
# continuing the great work and legacy of tteck in making Proxmox VE more accessible.
|
||||
# A streamlined solution for executing must-have tools in Proxmox VE.
|
||||
# Loads a curated JSON cache (helpers_cache.json) maintained
|
||||
# by ProxMenux on GitHub, lists categories + scripts with
|
||||
# search and type filters, and executes the chosen script
|
||||
# via "bash <(curl -s <url>)".
|
||||
#
|
||||
# Features:
|
||||
# - Browse scripts by category (Container, OS, Network, …).
|
||||
# - Free-text search across name and description.
|
||||
# - Per-script details: description, notes, default credentials,
|
||||
# default port, website.
|
||||
# - Choice of source (GitHub or Mirror) per script.
|
||||
# - Type labels: LXC / VM / PVE / ADDON / TK / GEN.
|
||||
#
|
||||
# Requires: curl, jq, dialog. Internet access mandatory.
|
||||
# ==========================================================
|
||||
|
||||
|
||||
@@ -44,7 +56,11 @@ for cmd in curl jq dialog; do
|
||||
fi
|
||||
done
|
||||
|
||||
CACHE_JSON=$(curl -s "$HELPERS_JSON_URL")
|
||||
# `--connect-timeout` caps DNS+TCP setup; `--max-time` caps total fetch.
|
||||
# Without these the menu would hang silently for minutes when the network
|
||||
# is down or the upstream is slow, with no signal to the user. Audit
|
||||
# Tier 6 — `menu_Helper_Scripts.sh` curl sin --max-time.
|
||||
CACHE_JSON=$(curl -s --connect-timeout 5 --max-time 15 "$HELPERS_JSON_URL")
|
||||
|
||||
# Validate that the JSON loaded correctly
|
||||
if ! echo "$CACHE_JSON" | jq -e 'if type == "array" and length > 0 then true else false end' >/dev/null 2>&1; then
|
||||
@@ -93,8 +109,10 @@ get_type_label() {
|
||||
download_script() {
|
||||
local url="$1"
|
||||
|
||||
if curl --silent --head --fail "$url" >/dev/null; then
|
||||
bash <(curl -s "$url")
|
||||
# Same timeouts as the cache fetch above so a stalled mirror can't hang
|
||||
# the menu indefinitely. The HEAD probe and the GET both get bounded.
|
||||
if curl --silent --connect-timeout 5 --max-time 10 --head --fail "$url" >/dev/null; then
|
||||
bash <(curl -s --connect-timeout 5 --max-time 60 "$url")
|
||||
else
|
||||
dialog --title "Helper Scripts" --msgbox "$(translate "Error: Failed to download the script.")" 8 70
|
||||
fi
|
||||
@@ -152,28 +170,45 @@ run_script_by_slug() {
|
||||
decode() { echo "$1" | base64 --decode | jq -r "$2"; }
|
||||
|
||||
local first="${script_infos[0]}"
|
||||
local name desc notes port website
|
||||
local name desc notes warnings port website
|
||||
name=$(decode "$first" ".name")
|
||||
desc=$(decode "$first" ".desc")
|
||||
notes=$(decode "$first" '.notes | join("\n")')
|
||||
notes=$(decode "$first" '.notes // [] | join("\n")')
|
||||
# Sprint 11.7: PocketBase upstream tags certain notes with type=="warning".
|
||||
# The cache generator splits them into a separate `warnings` array so the
|
||||
# menu can render them in red with a dedicated WARNINGS header instead of
|
||||
# burying them inside the regular notes block.
|
||||
warnings=$(decode "$first" '.warnings // [] | join("\n")')
|
||||
port=$(decode "$first" ".port // 0")
|
||||
website=$(decode "$first" ".website // empty")
|
||||
|
||||
# Build notes block
|
||||
local notes_dialog=""
|
||||
if [[ -n "$notes" ]]; then
|
||||
while IFS= read -r line; do
|
||||
[[ -z "$line" ]] && continue
|
||||
notes_dialog+="• $line\n"
|
||||
done <<< "$notes"
|
||||
notes_dialog="${notes_dialog%\\n}"
|
||||
fi
|
||||
|
||||
local credentials
|
||||
credentials=$(format_credentials "$first")
|
||||
|
||||
# Build info message
|
||||
local msg="\Zb\Z4$(translate "Description"):\Zn\n$desc"
|
||||
# Build info message — warnings first, in red, so the user sees them
|
||||
# before deciding to launch the script. Sections are separated by a
|
||||
# single \n (one blank line) instead of \n\n; the bullet builders below
|
||||
# also strip their trailing \n so we don't double up. Helper Scripts
|
||||
# like "PVE LXC Apps Update" carry a lot of text and a fixed-height
|
||||
# dialog clips the bottom menu when each section eats two extra rows.
|
||||
local msg="\Zb\Z4$(translate "Description"):\Zn\n$desc"
|
||||
if [[ -n "$warnings" ]]; then
|
||||
local warn_short=""
|
||||
local char_count=0
|
||||
local max_chars=400
|
||||
while IFS= read -r line; do
|
||||
[[ -z "$line" ]] && continue
|
||||
char_count=$(( char_count + ${#line} ))
|
||||
if [[ $char_count -lt $max_chars ]]; then
|
||||
warn_short+="• $line\n"
|
||||
else
|
||||
warn_short+="...\n"
|
||||
break
|
||||
fi
|
||||
done <<< "$warnings"
|
||||
warn_short="${warn_short%\\n}"
|
||||
msg+="\n\Zb\Z1⚠ $(translate "Warnings"):\Zn\n\Z1${warn_short}\Zn"
|
||||
fi
|
||||
if [[ -n "$notes" ]]; then
|
||||
local notes_short=""
|
||||
local char_count=0
|
||||
@@ -188,13 +223,14 @@ local msg="\Zb\Z4$(translate "Description"):\Zn\n$desc"
|
||||
break
|
||||
fi
|
||||
done <<< "$notes"
|
||||
msg+="\n\n\Zb\Z4$(translate "Notes"):\Zn\n$notes_short"
|
||||
notes_short="${notes_short%\\n}"
|
||||
msg+="\n\Zb\Z4$(translate "Notes"):\Zn\n$notes_short"
|
||||
fi
|
||||
[[ -n "$credentials" ]] && msg+="\n\n\Zb\Z4$(translate "Default Credentials"):\Zn\n$credentials"
|
||||
[[ "$port" -gt 0 ]] && msg+="\n\n\Zb\Z4$(translate "Default Port"):\Zn $port"
|
||||
[[ -n "$credentials" ]] && msg+="\n\Zb\Z4$(translate "Default Credentials"):\Zn\n$credentials"
|
||||
[[ "$port" -gt 0 ]] && msg+="\n\Zb\Z4$(translate "Default Port"):\Zn $port"
|
||||
[[ -n "$website" ]] && msg+="\n\Zb\Z4$(translate "Website"):\Zn $website"
|
||||
|
||||
msg+="\n\n$(translate "Choose how to run the script:")"
|
||||
msg+="\n$(translate "Choose how to run the script:")"
|
||||
|
||||
# Build menu: one or two entries per script_info (GH + optional Mirror)
|
||||
declare -a MENU_OPTS=()
|
||||
@@ -251,9 +287,18 @@ local msg="\Zb\Z4$(translate "Description"):\Zn\n$desc"
|
||||
echo
|
||||
echo
|
||||
|
||||
if [[ -n "$desc" || -n "$notes" || -n "$credentials" ]]; then
|
||||
if [[ -n "$desc" || -n "$notes" || -n "$warnings" || -n "$credentials" ]]; then
|
||||
echo -e "$TAB\e[1;36m$(translate "Script Information"):\e[0m"
|
||||
|
||||
if [[ -n "$warnings" ]]; then
|
||||
echo -e "$TAB\e[1;31m⚠ $(translate "Warnings"):\e[0m"
|
||||
while IFS= read -r line; do
|
||||
[[ -z "$line" ]] && continue
|
||||
echo -e "$TAB\e[31m• $line\e[0m"
|
||||
done <<< "$warnings"
|
||||
echo
|
||||
fi
|
||||
|
||||
if [[ -n "$notes" ]]; then
|
||||
echo -e "$TAB\e[1;33m$(translate "Notes"):\e[0m"
|
||||
while IFS= read -r line; do
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ProxMenux - Post-Install Menu Dispatcher
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.2
|
||||
# Last Updated: 06/07/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Dispatcher for the post-installation options: Automated
|
||||
# (zero-prompt baseline), Customizable (checklist per category)
|
||||
# and Uninstall Optimizations (reverse any previously applied
|
||||
# change). Also exposes two community post-install scripts
|
||||
# (Proxmox VE Post Install and Microcode) via wget | bash.
|
||||
# ==========================================================
|
||||
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
@@ -85,6 +92,137 @@ declare -a PROXMENUX_SCRIPTS=(
|
||||
"Uninstall optimizations|ProxMenux|bash \"$LOCAL_SCRIPTS/post_install/uninstall-tools.sh\""
|
||||
)
|
||||
|
||||
# ==========================================================
|
||||
# Sprint 12C: post-install function update detection.
|
||||
#
|
||||
# The Monitor's startup hook writes updates_available.json. We read it
|
||||
# here so the bash menu can show a conditional "Apply available updates"
|
||||
# entry above Uninstall when bumped versions are detected on disk vs the
|
||||
# user's installed_tools.json.
|
||||
# ==========================================================
|
||||
UPDATES_FILE="/usr/local/share/proxmenux/updates_available.json"
|
||||
UPDATE_WRAPPER="$LOCAL_SCRIPTS/post_install/update_post_install_function.sh"
|
||||
|
||||
count_post_install_updates() {
|
||||
[[ ! -f "$UPDATES_FILE" ]] && { echo 0; return; }
|
||||
command -v jq >/dev/null 2>&1 || { echo 0; return; }
|
||||
jq '.updates | length' "$UPDATES_FILE" 2>/dev/null || echo 0
|
||||
}
|
||||
|
||||
# Build a dialog checklist with the available updates and run the
|
||||
# wrapper script for whichever the user picks. Entries flagged
|
||||
# `source_certain=false` (legacy bool entries) are listed but not
|
||||
# pre-checked; they need a source pick first via the Monitor or a
|
||||
# fresh re-run of the customizable post-install.
|
||||
run_updates_dialog() {
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
msg_error "$(translate "jq is required to apply updates from this menu.")"
|
||||
sleep 2
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ ! -f "$UPDATES_FILE" ]]; then
|
||||
msg_warn "$(translate "No updates available — run a scan first or wait for the Monitor to refresh.")"
|
||||
sleep 2
|
||||
return
|
||||
fi
|
||||
|
||||
local count
|
||||
count=$(count_post_install_updates)
|
||||
if [[ "$count" -eq 0 ]]; then
|
||||
msg_ok "$(translate "All ProxMenux optimizations are up to date.")"
|
||||
sleep 2
|
||||
return
|
||||
fi
|
||||
|
||||
# Build the dialog --checklist arguments. Format per row:
|
||||
# <tag> <description> <on|off>
|
||||
# We use the tool key as the tag so the selection callback can map
|
||||
# back to source/function via jq.
|
||||
local checklist=()
|
||||
while IFS=$'\t' read -r key current available; do
|
||||
# Sprint 12C v2: every row is checked by default. Legacy bool
|
||||
# entries default to the auto flow on the wrapper side so the
|
||||
# user no longer needs to do a "source pick" first.
|
||||
local label="${key} (v${current} → v${available})"
|
||||
checklist+=("$key" "$label" "on")
|
||||
done < <(jq -r '.updates[] | [.key, .current_version, .available_version] | @tsv' "$UPDATES_FILE" 2>/dev/null)
|
||||
|
||||
if [[ ${#checklist[@]} -eq 0 ]]; then
|
||||
msg_warn "$(translate "Updates file is empty or unreadable.")"
|
||||
sleep 2
|
||||
return
|
||||
fi
|
||||
|
||||
local selected
|
||||
selected=$(dialog --clear --colors --separate-output \
|
||||
--backtitle "ProxMenux" \
|
||||
--title "$(translate "Apply Available Updates")" \
|
||||
--checklist "\n$(translate "Select the optimizations to update. Each one re-runs its post-install function and registers the new version."):\n" \
|
||||
22 78 12 \
|
||||
"${checklist[@]}" 3>&1 1>&2 2>&3)
|
||||
|
||||
local rc=$?
|
||||
clear
|
||||
[[ $rc -ne 0 ]] && return # cancelled
|
||||
[[ -z "$selected" ]] && return
|
||||
|
||||
# Build FUNCTIONS_BATCH (newline-separated source:function:key) by
|
||||
# looking up each picked key in the JSON. The detector already
|
||||
# populates `.source` (defaulting to "auto" for legacy bool entries
|
||||
# that didn't record one) and `.function`, so this is a straight
|
||||
# passthrough. Sprint 12C v2 dropped the source-pick gate.
|
||||
local batch=""
|
||||
while IFS= read -r key; do
|
||||
[[ -z "$key" ]] && continue
|
||||
local entry
|
||||
entry=$(jq -r --arg k "$key" '
|
||||
.updates[] | select(.key == $k) |
|
||||
select(.function != "") |
|
||||
"\((.source // "auto")):\(.function):\(.key)"
|
||||
' "$UPDATES_FILE")
|
||||
[[ -n "$entry" ]] && batch+="${entry}"$'\n'
|
||||
done <<< "$selected"
|
||||
|
||||
if [[ -z "$batch" ]]; then
|
||||
msg_warn "$(translate "Nothing to apply — none of the selected updates have a runnable function on disk.")"
|
||||
sleep 3
|
||||
return
|
||||
fi
|
||||
|
||||
# Hand off to the same wrapper the Monitor uses. Running it directly
|
||||
# (not through a dialog menu) so the user sees the post-install
|
||||
# function output verbatim.
|
||||
EXECUTION_MODE="cli" FUNCTIONS_BATCH="$batch" bash "$UPDATE_WRAPPER"
|
||||
|
||||
# Sprint 12C v2: force the Monitor to rewrite updates_available.json
|
||||
# so the next loop iteration of show_menu sees the post-update state
|
||||
# and the "Apply available updates (N)" entry hides/decrements
|
||||
# correctly. The endpoint is exposed on localhost without auth (POST
|
||||
# is idempotent — just re-runs the parser), so a plain curl works
|
||||
# whether HTTPS is on or off. Falls back to direct file write via
|
||||
# the Python module if the service isn't reachable (host where the
|
||||
# Monitor isn't running yet).
|
||||
local scheme="http"
|
||||
[[ -f /etc/proxmenux/ssl_config.json ]] && \
|
||||
jq -e '.enabled' /etc/proxmenux/ssl_config.json >/dev/null 2>&1 && \
|
||||
scheme="https"
|
||||
if ! curl -k -s --max-time 5 -X POST "${scheme}://127.0.0.1:8008/api/updates/post-install/scan" >/dev/null 2>&1; then
|
||||
# Fallback: regenerate the JSON via the module directly. We
|
||||
# can't import it from system Python because dependencies live
|
||||
# inside the AppImage, so just rewrite the file by re-running
|
||||
# the detector logic in-process via jq + the on-disk scripts.
|
||||
# Simpler: leave the file stale — the next AppImage restart will
|
||||
# rewrite it. The Monitor's _ensure_fresh_cache also auto-
|
||||
# refreshes when installed_tools.json changes, so the API view
|
||||
# is correct even if the bash menu sees a one-cycle-stale list.
|
||||
:
|
||||
fi
|
||||
|
||||
msg_success "$(translate 'Press ENTER to continue...')"
|
||||
read -r _
|
||||
}
|
||||
|
||||
|
||||
declare -a COMMUNITY_SCRIPTS=(
|
||||
"Proxmox VE Post Install|Helper-Scripts|bash -c \"\$(wget -qLO - https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/post-pve-install.sh); msg_success \\\"\$(translate 'Press ENTER to continue...')\\\"; read -r _\""
|
||||
@@ -119,14 +257,35 @@ format_menu_item() {
|
||||
show_menu() {
|
||||
while true; do
|
||||
local menu_items=()
|
||||
|
||||
|
||||
|
||||
declare -A script_commands
|
||||
local counter=1
|
||||
|
||||
|
||||
# Sprint 12C: re-evaluate available updates on every loop so the
|
||||
# entry vanishes after the user has applied everything (and the
|
||||
# Monitor has rewritten updates_available.json on its next scan).
|
||||
local update_count
|
||||
update_count=$(count_post_install_updates)
|
||||
|
||||
for script in "${PROXMENUX_SCRIPTS[@]}"; do
|
||||
IFS='|' read -r name source command <<< "$script"
|
||||
|
||||
# Insert the conditional "Apply available updates" item right
|
||||
# above "Uninstall optimizations" so it sits next to the
|
||||
# related rollback action and not buried in the middle.
|
||||
if [[ "$name" == "Uninstall optimizations" && "$update_count" -gt 0 ]]; then
|
||||
local update_label
|
||||
update_label="Apply available updates ($update_count)"
|
||||
local translated_update
|
||||
translated_update="$(translate "$update_label")"
|
||||
local formatted_update
|
||||
formatted_update=$(format_menu_item "$translated_update" "ProxMenux")
|
||||
menu_items+=("$counter" "$formatted_update")
|
||||
script_commands["$counter"]="run_updates_dialog"
|
||||
((counter++))
|
||||
fi
|
||||
|
||||
local translated_name="$(translate "$name")"
|
||||
local formatted_item
|
||||
formatted_item=$(format_menu_item "$translated_name" "$source")
|
||||
|
||||
+181
-27
@@ -4,17 +4,32 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.1
|
||||
# Last Updated: 08/07/2025
|
||||
# ==========================================================
|
||||
|
||||
# Description:
|
||||
# Advanced network management and troubleshooting tool for Proxmox VE.
|
||||
# Features include interface detection, bridge management, connectivity testing,
|
||||
# network diagnostics, configuration backup/restore, and automated repairs.
|
||||
# Special thanks to @Andres_Eduardo_Rojas_Moya for contributing the persistent
|
||||
# network naming function and for the original idea.
|
||||
# Network management and troubleshooting tool for Proxmox VE.
|
||||
# Operates exclusively on the classic Debian/Proxmox network stack
|
||||
# (/etc/network/interfaces). Aborts safely on netplan / systemd-networkd
|
||||
# / NetworkManager hosts to avoid corrupting unsupported configurations.
|
||||
#
|
||||
# Features:
|
||||
# - Read-only diagnostics: routing table, connectivity tests, advanced
|
||||
# network statistics, bridge and interface configuration analysis.
|
||||
# - Real-time monitoring launchers (iftop, iptraf-ng).
|
||||
# - Guided repair flows for invalid bridge ports and orphaned interface
|
||||
# configurations, with mandatory backup and step-by-step preview.
|
||||
# - Persistent network interface naming via systemd .link files
|
||||
# (MAC-based, survives hardware changes and PCI re-enumeration).
|
||||
# - Manual backup / restore of /etc/network/interfaces under
|
||||
# /var/backups/proxmenux/.
|
||||
# - Network service restart with confirmation.
|
||||
# - Curated community scripts (e.g., NIC offloading fix for Intel e1000e).
|
||||
#
|
||||
# Acknowledgements:
|
||||
# Persistent network naming function originally contributed by
|
||||
# @Andres_Eduardo_Rojas_Moya.
|
||||
# Configuration ============================================
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
@@ -112,17 +127,9 @@ get_interface_info() {
|
||||
|
||||
# ==========================================================
|
||||
|
||||
show_routing_table_() {
|
||||
local route_info=""
|
||||
route_info+="$(translate "Routing Table")\n"
|
||||
route_info+="$(printf '=%.0s' {1..30})\n\n"
|
||||
route_info+="$(ip route show)\n\n"
|
||||
route_info+="$(translate "Default Gateway"): $(ip route | grep default | awk '{print $3}' | head -1)\n"
|
||||
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Routing Information")" \
|
||||
--msgbox "$route_info" 20 80
|
||||
}
|
||||
|
||||
# Note: previous `show_routing_table_` (with trailing underscore) was
|
||||
# dead code — never referenced anywhere. Removed in Sprint 10T.7.
|
||||
# `show_routing_table` below is the active implementation.
|
||||
|
||||
show_routing_table() {
|
||||
local route_info=""
|
||||
@@ -929,9 +936,21 @@ restore_network_backup() {
|
||||
|
||||
if dialog --backtitle "ProxMenux" --title "$(translate "Restart Network")" \
|
||||
--yesno "\n$(translate "Do you want to restart the network service now to apply changes?")" 8 60; then
|
||||
if systemctl restart networking; then
|
||||
# Capture stdout+stderr and check the exit code directly
|
||||
# via the assignment's success — `$?` after a command-
|
||||
# substitution assignment is the substitution's exit code,
|
||||
# which is fragile (non-zero shell options affect it).
|
||||
local _restart_err
|
||||
if _restart_err=$(systemctl restart networking 2>&1); then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Network Restarted")" \
|
||||
--msgbox "\n$(translate "Network service restarted successfully.")" 8 50
|
||||
else
|
||||
# Surface the failure — silent failure left the user
|
||||
# thinking the restart worked while they're actually
|
||||
# locked out of network. Audit Tier 7 — restore_network_backup
|
||||
# no reporta fallo del restart de networking.
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Network Restart Failed")" \
|
||||
--msgbox "\n$(translate "systemctl restart networking failed:")\n\n${_restart_err:-unknown error}\n\n$(translate "Restored config is on disk; reboot the host to apply.")" 14 70
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -939,26 +958,160 @@ restore_network_backup() {
|
||||
}
|
||||
|
||||
|
||||
launch_iftop() {
|
||||
if ! command -v iftop &>/dev/null; then
|
||||
apt-get update -qq && apt-get install -y iftop &>/dev/null
|
||||
# ---------------------------------------------------------------
|
||||
# Shared helper for the monitoring tool launchers.
|
||||
# Ensures a given network tool is installed using the canonical
|
||||
# repo + install pattern from global/utils-install-functions.sh.
|
||||
# Args: package_name verify_command description
|
||||
# Returns: 0 on success, 1 on failure (with the user already
|
||||
# acknowledged via "Press Enter to return to menu").
|
||||
# ---------------------------------------------------------------
|
||||
_ensure_network_tool() {
|
||||
local pkg="$1"
|
||||
local cmd="${2:-$pkg}"
|
||||
local desc="${3:-$pkg}"
|
||||
|
||||
if command -v "$cmd" &>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/utils-install-functions.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/utils-install-functions.sh"
|
||||
fi
|
||||
|
||||
if ! type ensure_repositories &>/dev/null || ! type install_single_package &>/dev/null; then
|
||||
clear
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Installing") $pkg"
|
||||
msg_error "$(translate "Required install helpers not available.")"
|
||||
msg_warn "$(translate "Cannot find") global/utils-install-functions.sh"
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
|
||||
clear
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Installing") $pkg"
|
||||
|
||||
if ! ensure_repositories; then
|
||||
msg_error "$(translate "Failed to configure repositories. Installation aborted.")"
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
|
||||
install_single_package "$pkg" "$cmd" "$desc"
|
||||
local rc=$?
|
||||
|
||||
if [[ $rc -eq 1 ]]; then
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
|
||||
# rc=0 (installed and available) or rc=2 (installed, hash refresh pending —
|
||||
# invoking the binary by name through PATH lookup still works).
|
||||
return 0
|
||||
}
|
||||
|
||||
launch_iftop() {
|
||||
_ensure_network_tool "iftop" "iftop" "Real-time network usage" || return
|
||||
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "iftop usage")" --msgbox "\n$(translate "To exit iftop, press q")" 8 50
|
||||
clear
|
||||
iftop
|
||||
}
|
||||
|
||||
launch_iptraf() {
|
||||
if ! command -v iptraf-ng &>/dev/null; then
|
||||
apt-get update -qq && apt-get install -y iptraf-ng &>/dev/null
|
||||
fi
|
||||
_ensure_network_tool "iptraf-ng" "iptraf-ng" "Network monitoring tool" || return
|
||||
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "iptraf-ng usage")" --msgbox "\n$(translate "To exit iptraf-ng, press x")" 8 50
|
||||
clear
|
||||
iptraf-ng
|
||||
}
|
||||
|
||||
launch_iperf3() {
|
||||
_ensure_network_tool "iperf3" "iperf3" "Network bandwidth testing" || return
|
||||
|
||||
# Mode selection
|
||||
local mode
|
||||
mode=$(dialog --backtitle "ProxMenux" \
|
||||
--title "$(translate "iperf3 - Bandwidth test")" \
|
||||
--menu "\n$(translate "Choose iperf3 mode:")" 12 70 2 \
|
||||
"1" "$(translate "Server (listen for incoming tests on TCP 5201)")" \
|
||||
"2" "$(translate "Client (run a bandwidth test to a server)")" \
|
||||
3>&1 1>&2 2>&3) || return
|
||||
|
||||
case "$mode" in
|
||||
1)
|
||||
# Server mode
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "iperf3 server")" \
|
||||
--msgbox "\n$(translate "Server will listen on TCP port 5201.")\n\n$(translate "Press Ctrl+C to stop the server and return to menu.")" 11 65
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "iperf3 - Bandwidth test (Server mode)")"
|
||||
|
||||
echo -e "${TAB}${BGN}$(translate "Listening on:")${CL} ${BL}TCP 0.0.0.0:5201${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "To stop:")${CL} ${BL}Ctrl+C${CL}"
|
||||
echo -e ""
|
||||
echo -e "${BOLD}─────────── $(translate "iperf3 server output") ───────────${CL}"
|
||||
echo -e ""
|
||||
|
||||
iperf3 -s
|
||||
|
||||
echo -e ""
|
||||
msg_success "$(translate "Server stopped. Press Enter to return to menu...")"
|
||||
read -r
|
||||
;;
|
||||
2)
|
||||
# Client mode
|
||||
local target
|
||||
target=$(dialog --backtitle "ProxMenux" --title "$(translate "iperf3 client")" \
|
||||
--inputbox "\n$(translate "Enter the iperf3 server IP or hostname:")" 10 60 \
|
||||
3>&1 1>&2 2>&3) || return
|
||||
|
||||
# Trim whitespace from input
|
||||
target=$(echo "$target" | tr -d '[:space:]')
|
||||
|
||||
if [[ -z "$target" ]]; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Invalid input")" \
|
||||
--msgbox "\n$(translate "No server IP or hostname provided.")" 8 55
|
||||
return 1
|
||||
fi
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "iperf3 - Bandwidth test (Client mode)")"
|
||||
|
||||
echo -e "${TAB}${BGN}$(translate "Target server:")${CL} ${BL}$target${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Port:")${CL} ${BL}TCP 5201${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Duration:")${CL} ${BL}10 $(translate "seconds (default)")${CL}"
|
||||
echo -e ""
|
||||
echo -e "${BOLD}─────────── $(translate "iperf3 client output") ───────────${CL}"
|
||||
echo -e ""
|
||||
|
||||
if iperf3 -c "$target"; then
|
||||
echo -e ""
|
||||
msg_ok "$(translate "Bandwidth test completed successfully")"
|
||||
else
|
||||
echo -e ""
|
||||
msg_error "$(translate "iperf3 test failed")"
|
||||
msg_warn "$(translate "Check that:")"
|
||||
echo -e "${TAB}• $(translate "iperf3 server is running on") ${BL}$target${CL}"
|
||||
echo -e "${TAB}• $(translate "TCP port 5201 is reachable (firewall on server)")"
|
||||
echo -e "${TAB}• $(translate "Network connectivity to") ${BL}$target${CL}"
|
||||
fi
|
||||
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
# ==========================================================
|
||||
|
||||
@@ -989,6 +1142,7 @@ confirm_and_run() {
|
||||
declare -a PROXMENUX_SCRIPTS=(
|
||||
"Real-time network usage (iftop)||launch_iftop"
|
||||
"Network monitoring tool (iptraf-ng)||launch_iptraf"
|
||||
"Bandwidth test (iperf3)||launch_iperf3"
|
||||
"Show Routing Table||show_routing_table"
|
||||
"Test Connectivity||test_connectivity"
|
||||
"Advanced Diagnostics||advanced_network_diagnostics"
|
||||
@@ -1075,7 +1229,7 @@ show_menu() {
|
||||
--backtitle "ProxMenux" \
|
||||
--title "$(translate "Network Management")" \
|
||||
--menu "\n$(translate "Select a network management option:"):\n" \
|
||||
26 78 19 \
|
||||
28 78 19 \
|
||||
"${menu_items[@]}" 2>&1 1>&3)
|
||||
exit_status=$?
|
||||
exec 3>&-
|
||||
|
||||
@@ -1,11 +1,25 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux - Security Menu
|
||||
# ============================================
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# ============================================
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Dispatcher for security tools shipped with ProxMenux. Loads the
|
||||
# selected installer/manager script and returns to the main menu
|
||||
# on cancel.
|
||||
#
|
||||
# Features:
|
||||
# - Fail2Ban — intrusion prevention for SSH and the Proxmox /
|
||||
# ProxMenux Monitor web interfaces, with auto-detected firewall
|
||||
# backend (nftables / iptables).
|
||||
# - Lynis — security auditing tool installed from upstream
|
||||
# GitHub (always latest), with run-audit and update actions.
|
||||
# ==========================================================
|
||||
|
||||
SCRIPT_TITLE="Security Tools"
|
||||
|
||||
|
||||
+23
-15
@@ -1,12 +1,18 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux - Network Storage Manager Menu
|
||||
# ProxMenux - Storage & Share Manager Menu
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.2
|
||||
# Last Updated: $(date +%d/%m/%Y)
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Dispatcher for the Storage & Share Manager menu. Two blocks:
|
||||
# HOST (register external or local storage as Proxmox storage,
|
||||
# plus the local shared directory helper) and LXC (bind mount
|
||||
# manager, NFS / Samba client and server for privileged CTs).
|
||||
# ==========================================================
|
||||
|
||||
# Configuration
|
||||
@@ -27,21 +33,23 @@ initialize_cache
|
||||
while true; do
|
||||
OPTION=$(dialog --colors --backtitle "ProxMenux" \
|
||||
--title "$(translate "Storage & Share Manager")" \
|
||||
--menu "\n$(translate "Select an option:")" 26 78 17 \
|
||||
--menu "\n$(translate "Select an option:")" 28 78 17 \
|
||||
"" "\Z4──────────────────────── HOST ─────────────────────────\Zn" \
|
||||
"1" "$(translate "Configure NFS shared on Host")" \
|
||||
"2" "$(translate "Configure Samba shared on Host")" \
|
||||
"3" "$(translate "Configure Local Shared on Host")" \
|
||||
"1" "$(translate "Add NFS share as Proxmox Storage")" \
|
||||
"2" "$(translate "Add Samba share as Proxmox Storage")" \
|
||||
"3" "$(translate "Add iSCSI Target as Proxmox Storage")" \
|
||||
"4" "$(translate "Add Local Disk as Proxmox Storage")" \
|
||||
"5" "$(translate "Add iSCSI Target as Proxmox Storage")" \
|
||||
"" "" \
|
||||
"" "\Z4─────────────── Host-only resources ──────────────────\Zn" \
|
||||
"5" "$(translate "Add Shared Directory on Host")" \
|
||||
"" "" \
|
||||
"" "\Z4──────────────────────── LXC ─────────────────────────\Zn" \
|
||||
"6" "$(translate "Configure LXC Mount Points (Host ↔ Container)")" \
|
||||
"" "" \
|
||||
"7" "$(translate "Configure NFS Client in LXC (only privileged)")" \
|
||||
"7" "$(translate "Configure NFS Client in LXC (only privileged)")" \
|
||||
"8" "$(translate "Configure Samba Client in LXC (only privileged)")" \
|
||||
"9" "$(translate "Configure NFS Server in LXC (only privileged)")" \
|
||||
"10" "$(translate "configure Samba Server in LXC (only privileged)")" \
|
||||
"9" "$(translate "Configure NFS Server in LXC (only privileged)")" \
|
||||
"10" "$(translate "Configure Samba Server in LXC (only privileged)")" \
|
||||
"" "" \
|
||||
"h" "$(translate "Help & Info (commands)")" \
|
||||
"0" "$(translate "Return to Main Menu")" \
|
||||
@@ -61,21 +69,21 @@ while true; do
|
||||
bash "$LOCAL_SCRIPTS/share/samba_host.sh"
|
||||
;;
|
||||
3)
|
||||
bash "$LOCAL_SCRIPTS/share/local-shared-manager.sh"
|
||||
bash "$LOCAL_SCRIPTS/share/iscsi_host.sh"
|
||||
;;
|
||||
4)
|
||||
bash "$LOCAL_SCRIPTS/share/disk_host.sh"
|
||||
;;
|
||||
5)
|
||||
bash "$LOCAL_SCRIPTS/share/iscsi_host.sh"
|
||||
bash "$LOCAL_SCRIPTS/share/local-shared-manager.sh"
|
||||
;;
|
||||
6)
|
||||
bash "$LOCAL_SCRIPTS/share/lxc-mount-manager_minimal.sh"
|
||||
;;
|
||||
7)
|
||||
bash "$LOCAL_SCRIPTS/share/nfs_client.sh"
|
||||
;;
|
||||
8)
|
||||
;;
|
||||
8)
|
||||
bash "$LOCAL_SCRIPTS/share/samba_client.sh"
|
||||
;;
|
||||
9)
|
||||
|
||||
@@ -1,13 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ProxMenux - Utilities Menu
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 02/07/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Dispatcher for the Utilities & Tools section. Six options that
|
||||
# cover ISO creation, system utility installation, Proxmox updates,
|
||||
# major-version upgrade (PVE 8 → 9) and VM portability (OVA / OVF).
|
||||
#
|
||||
# Features:
|
||||
# - UUP Dump ISO creator: build official Windows ISOs from UUP
|
||||
# Dump using a shared link.
|
||||
# - System Utilities Installer: 26 curated CLI tools (htop, btop,
|
||||
# iperf3, jq, tmux, ...) in custom-pick or predefined groups.
|
||||
# - Proxmox System Update: repos hygiene + apt update + apt
|
||||
# dist-upgrade with reboot prompt (delegates to per-version
|
||||
# worker scripts in global/).
|
||||
# - Upgrade PVE 8 to PVE 9: automated or interactive major-version
|
||||
# upgrade with pre-checks, repo migration and post-upgrade
|
||||
# validation. Manual guide alternative also exposed.
|
||||
# - Export VM to OVA / OVF: convert a Proxmox VM to a portable
|
||||
# OVA archive or OVF directory (VMware / VirtualBox / etc).
|
||||
# - Import VM from OVA / OVF: import a VMware / VirtualBox /
|
||||
# ProxMenux export back into Proxmox.
|
||||
# ==========================================================
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# ProxMenux - OCI Application Manager
|
||||
# ============================================
|
||||
# Author : MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# Version : 1.0
|
||||
# ============================================
|
||||
# Manages OCI container applications through dialog menus or direct CLI.
|
||||
|
||||
@@ -1,37 +1,30 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux - Complete Post-Installation Script with Registration
|
||||
# ProxMenux - Automated Post-Install Script
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 06/07/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Applies a curated set of 13 safe optimizations to a fresh
|
||||
# Proxmox VE host without prompts. Every change is registered
|
||||
# in installed_tools.json so it can be reversed later from the
|
||||
# Uninstall Optimizations menu.
|
||||
#
|
||||
# The script performs system optimizations including:
|
||||
# - Repository configuration and system upgrades
|
||||
# - Subscription banner removal and UI enhancements
|
||||
# - Advanced memory management and kernel optimizations
|
||||
# - Network stack tuning and security hardening
|
||||
# - Storage optimizations including log2ram for SSD protection
|
||||
# - System limits increases and entropy generation improvements
|
||||
# - Journald and logrotate optimizations for better log management
|
||||
# - Security enhancements including RPC disabling and time synchronization
|
||||
# - Bash environment customization and system monitoring setup
|
||||
# Features:
|
||||
# - Zero-interaction baseline: repos, upgrade, banner, APT
|
||||
# IPv4, skip translations, kernel limits, memory tuning,
|
||||
# kernel-panic behaviour, network stack tuning, bashrc,
|
||||
# Log2RAM (SSD-aware), journald, logrotate, persistent NIC names.
|
||||
# - Hardware-aware: auto-detects SSD/NVMe for Log2RAM and sizes
|
||||
# its ramdisk according to host RAM (128M/256M/512M).
|
||||
# - Registration: tracks each tool in installed_tools.json.
|
||||
# - Rollback: every tool has a reverse function in uninstall-tools.sh.
|
||||
#
|
||||
# Key Features:
|
||||
# - Zero-interaction automation: Runs completely unattended
|
||||
# - Intelligent hardware detection: Automatically detects SSD/NVMe for log2ram
|
||||
# - RAM-aware configurations: Adjusts settings based on available system memory
|
||||
# - Comprehensive error handling: Robust installation with fallback mechanisms
|
||||
# - Registration system: Tracks installed optimizations for easy management
|
||||
# - Reboot management: Intelligently handles reboot requirements
|
||||
# - Translation support: Multi-language compatible through ProxMenux framework
|
||||
# - Rollback compatibility: All optimizations can be reversed using the uninstall script
|
||||
#
|
||||
# This script is based on the post-install script cutotomizable
|
||||
# Shares the function library with customizable_post_install.sh.
|
||||
# ==========================================================
|
||||
|
||||
|
||||
@@ -55,17 +48,49 @@ RAM_SIZE_GB=$(( $(vmstat -s | grep -i "total memory" | xargs | cut -d" " -f 1) /
|
||||
NECESSARY_REBOOT=0
|
||||
export SCRIPT_TITLE="ProxMenux Optimization Post-Installation"
|
||||
|
||||
# Sprint 12A: identify which post-install flow is calling register_tool.
|
||||
# auto_post_install.sh always emits source=auto; customizable sets "custom".
|
||||
# The detector uses this to know which function to compare against and
|
||||
# which one to re-run when applying an update (preserves user's choice
|
||||
# between the auto and the custom flow of the same tool).
|
||||
SCRIPT_SOURCE="auto"
|
||||
|
||||
# ==========================================================
|
||||
# Tool registration system
|
||||
ensure_tools_json() {
|
||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
||||
}
|
||||
|
||||
# Sprint 12A: register_tool accepts (key, state, version, source).
|
||||
# key — tool identifier (existing)
|
||||
# state — true/false (existing)
|
||||
# version — defaults to "1.0"; each function declares its own version as
|
||||
# `local FUNC_VERSION="X.Y"` on the first line and passes
|
||||
# "$FUNC_VERSION" here. We use a `local` variable rather than a
|
||||
# `# version:` comment because bash's `declare -f` strips
|
||||
# comments — so a comment-based version was lost when the
|
||||
# update wrapper sourced the script and re-ran the function.
|
||||
# source — defaults to $SCRIPT_SOURCE (auto/custom) so the detector
|
||||
# knows which flow to compare against and which to re-run on
|
||||
# update.
|
||||
# On install (state=true) the entry becomes a structured object
|
||||
# {installed: true, version: "X.Y", source: "auto"|"custom"}
|
||||
# On uninstall (state=false) we keep the legacy boolean false so the rest
|
||||
# of the pipeline (uninstall-tools.sh, frontend) keeps working.
|
||||
register_tool() {
|
||||
local tool="$1"
|
||||
local state="$2"
|
||||
local version="${3:-1.0}"
|
||||
local source="${4:-${SCRIPT_SOURCE:-unknown}}"
|
||||
ensure_tools_json
|
||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
||||
if [[ "$state" == "true" ]]; then
|
||||
jq --arg t "$tool" --arg ver "$version" --arg src "$source" \
|
||||
'.[$t]={"installed": true, "version": $ver, "source": $src}' \
|
||||
"$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
||||
else
|
||||
jq --arg t "$tool" '.[$t]=false' \
|
||||
"$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -166,6 +191,8 @@ remove_subscription_banner() {
|
||||
|
||||
|
||||
configure_time_sync() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Detect timezone from public IP and enable systemd time sync (NTP).
|
||||
msg_info2 "$(translate "Configuring system time settings...")"
|
||||
|
||||
this_ip=$(dig +short myip.opendns.com @resolver1.opendns.com 2>/dev/null)
|
||||
@@ -174,20 +201,30 @@ configure_time_sync() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
timezone=$(curl -s --connect-timeout 10 "https://ipapi.co/${this_ip}/timezone" 2>/dev/null)
|
||||
timezone=$(curl -s --connect-timeout 10 "https://ipapi.co/${this_ip}/timezone" 2>/dev/null | tr -d '[:space:]')
|
||||
if [ -z "$timezone" ] || [ "$timezone" = "undefined" ]; then
|
||||
msg_warn "$(translate "Failed to determine timezone from IP address - keeping current timezone settings")"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Validate against the system's IANA timezone database before applying.
|
||||
# ipapi.co can return rate-limit JSON, an error string, or stale data; the
|
||||
# previous code accepted anything that wasn't literally "undefined" and
|
||||
# passed it straight to `timedatectl set-timezone`, which silently kept
|
||||
# the old TZ on a bad value.
|
||||
if ! timedatectl list-timezones 2>/dev/null | grep -Fxq "$timezone"; then
|
||||
msg_warn "$(translate "API returned an invalid timezone") ($timezone) - $(translate "keeping current settings")"
|
||||
return 0
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Found timezone $timezone for IP $this_ip")"
|
||||
|
||||
|
||||
if timedatectl set-timezone "$timezone"; then
|
||||
msg_ok "$(translate "Timezone set to $timezone")"
|
||||
|
||||
if timedatectl set-ntp true; then
|
||||
msg_ok "$(translate "Time settings configured - Timezone:") $timezone"
|
||||
register_tool "time_sync" true
|
||||
register_tool "time_sync" true "$FUNC_VERSION"
|
||||
|
||||
systemctl restart postfix 2>/dev/null || true
|
||||
else
|
||||
@@ -204,17 +241,20 @@ configure_time_sync() {
|
||||
# ==========================================================
|
||||
|
||||
skip_apt_languages() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Stop APT from downloading translation files to speed up updates.
|
||||
msg_info "$(translate "Configuring APT to skip downloading additional languages...")"
|
||||
cat > /etc/apt/apt.conf.d/99-disable-translations <<'EOF'
|
||||
Acquire::Languages "none";
|
||||
EOF
|
||||
msg_ok "$(translate "APT configured to skip additional languages")"
|
||||
register_tool "apt_languages" true
|
||||
register_tool "apt_languages" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
optimize_journald() {
|
||||
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Cap journald size, raise rate limit and force info-level logging so the log viewer and Fail2Ban work.
|
||||
if [ -f /etc/log2ram.conf ] || [ -d /var/log.hdd ]; then
|
||||
return 0
|
||||
fi
|
||||
@@ -254,18 +294,20 @@ EOF
|
||||
journalctl --rotate > /dev/null 2>&1
|
||||
|
||||
msg_ok "$(translate "Journald optimized - Max size: 64M")"
|
||||
register_tool "journald" true
|
||||
register_tool "journald" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
optimize_logrotate() {
|
||||
local FUNC_VERSION="1.1"
|
||||
# description: Replace logrotate.conf with a Log2RAM-friendly profile (daily rotation, copytruncate).
|
||||
msg_info "$(translate "Optimizing logrotate configuration...")"
|
||||
local logrotate_conf="/etc/logrotate.conf"
|
||||
local backup_conf="${logrotate_conf}.bak"
|
||||
|
||||
if ! grep -q "# ProxMenux optimized configuration" "$logrotate_conf"; then
|
||||
cp "$logrotate_conf" "$backup_conf"
|
||||
cat <<EOF > "$logrotate_conf"
|
||||
|
||||
cp -n "$logrotate_conf" "$backup_conf" 2>/dev/null || true
|
||||
|
||||
cat <<EOF > "$logrotate_conf"
|
||||
# ProxMenux optimized configuration (Log2RAM-friendly)
|
||||
daily
|
||||
su root adm
|
||||
@@ -279,15 +321,16 @@ create 0640 root adm
|
||||
copytruncate
|
||||
include /etc/logrotate.d
|
||||
EOF
|
||||
systemctl restart logrotate > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
systemctl restart logrotate > /dev/null 2>&1
|
||||
|
||||
msg_ok "$(translate "Logrotate optimization completed")"
|
||||
register_tool "logrotate" true
|
||||
register_tool "logrotate" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
increase_system_limits() {
|
||||
local FUNC_VERSION="1.1"
|
||||
# description: Raise inotify watches, file descriptors, process keys and PID limits to enterprise levels.
|
||||
msg_info "$(translate "Increasing various system limits...")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -355,11 +398,13 @@ fs.aio-max-nr = 1048576
|
||||
EOF
|
||||
|
||||
msg_ok "$(translate "System limits increase completed.")"
|
||||
register_tool "system_limits" true
|
||||
register_tool "system_limits" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
optimize_memory_settings() {
|
||||
local FUNC_VERSION="1.1"
|
||||
# description: Tune swappiness, dirty page ratios, overcommit and compaction proactiveness for VM hosts.
|
||||
msg_info "$(translate "Optimizing memory settings...")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -377,11 +422,13 @@ EOF
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Memory optimization completed.")"
|
||||
register_tool "memory_settings" true
|
||||
register_tool "memory_settings" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
configure_kernel_panic() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Auto-reboot on kernel panic / oops / hardlockup; write crash dumps to /var/crash.
|
||||
msg_info "$(translate "Configuring kernel panic behavior")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -394,22 +441,26 @@ kernel.hardlockup_panic = 1
|
||||
EOF
|
||||
|
||||
msg_ok "$(translate "Kernel panic behavior configuration completed")"
|
||||
register_tool "kernel_panic" true
|
||||
register_tool "kernel_panic" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
force_apt_ipv4() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Force APT to use IPv4 to avoid stalls on hosts with broken IPv6 connectivity.
|
||||
msg_info "$(translate "Configuring APT to use IPv4...")"
|
||||
|
||||
|
||||
echo 'Acquire::ForceIPv4 "true";' > /etc/apt/apt.conf.d/99-force-ipv4
|
||||
|
||||
|
||||
msg_ok "$(translate "APT IPv4 configuration completed")"
|
||||
register_tool "apt_ipv4" true
|
||||
register_tool "apt_ipv4" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
|
||||
apply_network_optimizations() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Tune TCP buffers, somaxconn, IPv4 hardening and disable rp_filter on fw bridges (PVE 9 compatible).
|
||||
msg_info "$(translate "Optimizing network settings...")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -484,7 +535,7 @@ EOF
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Network optimization completed")"
|
||||
register_tool "network_optimization" true
|
||||
register_tool "network_optimization" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -495,6 +546,8 @@ EOF
|
||||
|
||||
# ==========================================================
|
||||
customize_bashrc() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Inject the ProxMenux core bashrc block (aliases, prompt, history) into root's .bashrc, idempotent via begin/end markers.
|
||||
msg_info "$(translate "Customizing bashrc for root user...")"
|
||||
local bashrc="/root/.bashrc"
|
||||
local bash_profile="/root/.bash_profile"
|
||||
@@ -532,7 +585,7 @@ EOF
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Bashrc customization completed")"
|
||||
register_tool "bashrc_custom" true
|
||||
register_tool "bashrc_custom" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -547,11 +600,14 @@ EOF
|
||||
|
||||
|
||||
install_log2ram_auto() {
|
||||
|
||||
local FUNC_VERSION="1.1"
|
||||
# description: Install Log2RAM with size auto-tuned to host RAM (128M/256M/512M); SSD/M.2 detection skips on rotational disks.
|
||||
# ── Reinstall detection ─────────────────────────────────────────────────
|
||||
# If log2ram was previously installed by ProxMenux (register_tool "log2ram" true),
|
||||
# skip hardware detection and reinstall directly — no prompts, transparent to user.
|
||||
if [[ -f "$TOOLS_JSON" ]] && jq -e '.log2ram == true' "$TOOLS_JSON" >/dev/null 2>&1; then
|
||||
# If log2ram was previously installed by ProxMenux, skip hardware detection
|
||||
# and reinstall directly — no prompts, transparent to user. Sprint 12A:
|
||||
# also matches the new structured form `{"installed": true, ...}` written by
|
||||
# the updated register_tool, in addition to the legacy boolean true entry.
|
||||
if [[ -f "$TOOLS_JSON" ]] && jq -e '.log2ram == true or .log2ram.installed == true' "$TOOLS_JSON" >/dev/null 2>&1; then
|
||||
msg_ok "$(translate "Log2RAM already registered — updating to latest configuration")"
|
||||
else
|
||||
# ── First-time install: detect SSD/M.2 ─────────────────────────────────
|
||||
@@ -769,7 +825,7 @@ EOF
|
||||
msg_ok "$(translate "Journald configuration adjusted to") ${USE_MB}M (Log2RAM ${LOG2RAM_SIZE})"
|
||||
|
||||
|
||||
register_tool "log2ram" true
|
||||
register_tool "log2ram" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -783,6 +839,8 @@ EOF
|
||||
|
||||
|
||||
setup_persistent_network() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Pin NIC names to MAC addresses via systemd .link files so kernel updates don't shuffle interface names.
|
||||
local LINK_DIR="/etc/systemd/network"
|
||||
local BACKUP_DIR="/etc/systemd/network/backup-$(date +%Y%m%d-%H%M%S)"
|
||||
local pve_version
|
||||
@@ -791,6 +849,13 @@ setup_persistent_network() {
|
||||
msg_info "$(translate "Setting up persistent network interfaces")"
|
||||
sleep 2
|
||||
|
||||
# Same legacy-conflict warning as in customizable_post_install.sh.
|
||||
if [[ -f /etc/network/interfaces ]]; then
|
||||
if grep -qE '^[[:space:]]*allow-hotplug[[:space:]]' /etc/network/interfaces 2>/dev/null; then
|
||||
msg_warn "$(translate '/etc/network/interfaces uses allow-hotplug. Renaming interfaces via systemd .link can break that flow — review the file after reboot.')"
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p "$LINK_DIR"
|
||||
|
||||
if ls "$LINK_DIR"/*.link >/dev/null 2>&1; then
|
||||
@@ -833,7 +898,7 @@ EOF
|
||||
else
|
||||
msg_warn "$(translate "No physical interfaces found")"
|
||||
fi
|
||||
register_tool "persistent_network" true
|
||||
register_tool "persistent_network" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,50 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - Customizable script settings for Proxmox post-installation
|
||||
# ProxMenux - Customizable Post-Install Script
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.3
|
||||
# Last Updated: 30/06/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script automates post-installation configurations and optimizations
|
||||
# for Proxmox Virtual Environment (VE). It allows for a variety of system
|
||||
# customizations, including kernel optimizations, memory management, network
|
||||
# tweaks, and virtualization environment adjustments. The script facilitates
|
||||
# easy installation of useful tools and security enhancements, including
|
||||
# fail2ban, ZFS auto-snapshot, and more.
|
||||
# Interactive post-installation configurator for Proxmox VE.
|
||||
# Groups ~30 optimizations into 10 categories (Basic Settings,
|
||||
# System, Virtualization, Network, Storage, Security,
|
||||
# Customization, Monitoring, Performance, Optional) and presents
|
||||
# a checklist per category so the user picks exactly what to
|
||||
# apply. Every change is registered in installed_tools.json for
|
||||
# later reversal from Uninstall Optimizations.
|
||||
#
|
||||
# This script is based on the work of Adrian Jon Kriel from eXtremeSHOK.com,
|
||||
# and it was originally published as a post-installation script for Proxmox under the
|
||||
# BSD License.
|
||||
#
|
||||
# Copyright (c) Adrian Jon Kriel :: admin@extremeshok.com
|
||||
# Script updates can be found at: https://github.com/extremeshok/xshok-proxmox
|
||||
#
|
||||
# License: BSD (Berkeley Software Distribution)
|
||||
#
|
||||
# Additionally, this script incorporates elements from the
|
||||
# Proxmox VE Post Install script from Proxmox VE Helper-Scripts.
|
||||
#
|
||||
# Copyright (c) Proxmox VE Helper-Scripts Community
|
||||
# Script updates can be found at: https://github.com/community-scripts/ProxmoxVE
|
||||
#
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
#
|
||||
# Key features:
|
||||
# - Configures system memory and kernel settings for better performance.
|
||||
# - Enables IOMMU and VFIO for PCI passthrough and virtualization optimizations.
|
||||
# - Installs essential tools such as kernel headers, system utilities, and networking tools.
|
||||
# - Optimizes journald, achievement, and other system services for better efficiency.
|
||||
# - Enables guest agents for virtualization platforms such as KVM, VMware, and VirtualBox.
|
||||
# - Updates the system, adds correct repositories, and optimizes system features such as memory, network settings, and more.
|
||||
# - Provides a wide range of additional options for customization and optimization.
|
||||
# - Offers interactive selection of features using an easy-to-use menu-driven interface.
|
||||
# - And many more...
|
||||
# Features:
|
||||
# - Checklist UI per category (10 categories, ~30 tools total).
|
||||
# - Superset of the Automated script: includes the 13 baseline
|
||||
# optimizations plus opt-in items (IOMMU/VFIO, Fastfetch,
|
||||
# Figurine, Ceph repo, HA, AMD fixes, pigz, ZFS ARC, …).
|
||||
# - Idempotent: safe to run repeatedly.
|
||||
# - Registration + rollback: every tool has a reverse function
|
||||
# in uninstall-tools.sh.
|
||||
#
|
||||
# Credits:
|
||||
# Incorporates ideas and snippets originally published under BSD
|
||||
# by Adrian Jon Kriel (eXtremeSHOK) in xshok-proxmox, and elements
|
||||
# of the Proxmox VE Post Install script from the Proxmox VE
|
||||
# Helper-Scripts Community (MIT).
|
||||
# https://github.com/extremeshok/xshok-proxmox
|
||||
# https://github.com/community-scripts/ProxmoxVE
|
||||
# ==========================================================
|
||||
|
||||
|
||||
@@ -78,15 +67,36 @@ SCRIPT_TITLE="Customizable post-installation optimization script"
|
||||
|
||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
||||
|
||||
# Sprint 12A: customizable_post_install.sh always emits source=custom so
|
||||
# the update detector knows to re-run the customizable flow (which asks
|
||||
# the user for parameters again) instead of the silent auto flow.
|
||||
SCRIPT_SOURCE="custom"
|
||||
|
||||
ensure_tools_json() {
|
||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
||||
}
|
||||
|
||||
# Sprint 12A: register_tool accepts (key, state, version, source).
|
||||
# Each function declares `local FUNC_VERSION="X.Y"` on its first line and
|
||||
# passes "$FUNC_VERSION" here. We use `local` rather than a `# version:`
|
||||
# comment because bash's `declare -f` strips comments — comments would be
|
||||
# silently lost when the update wrapper sourced the script and re-ran a
|
||||
# function, leaving the registered version stuck at the default. See
|
||||
# auto_post_install.sh for the full contract.
|
||||
register_tool() {
|
||||
local tool="$1"
|
||||
local state="$2"
|
||||
local state="$2"
|
||||
local version="${3:-1.0}"
|
||||
local source="${4:-${SCRIPT_SOURCE:-unknown}}"
|
||||
ensure_tools_json
|
||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
||||
if [[ "$state" == "true" ]]; then
|
||||
jq --arg t "$tool" --arg ver "$version" --arg src "$source" \
|
||||
'.[$t]={"installed": true, "version": $ver, "source": $src}' \
|
||||
"$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
||||
else
|
||||
jq --arg t "$tool" '.[$t]=false' \
|
||||
"$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -119,6 +129,8 @@ $(translate "Do you want to continue anyway?")" 13 70
|
||||
|
||||
|
||||
enable_kexec() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Install kexec-tools and add a Ctrl+Alt+K hotkey + systemd unit for fast reboots that skip BIOS/POST.
|
||||
msg_info2 "$(translate "Configuring kexec for quick reboots...")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -179,7 +191,7 @@ EOF
|
||||
fi
|
||||
|
||||
msg_success "$(translate "kexec configured successfully. Use the command: reboot-quick")"
|
||||
register_tool "kexec" true
|
||||
register_tool "kexec" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -221,8 +233,10 @@ apt_upgrade() {
|
||||
|
||||
|
||||
optimize_journald() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Cap journald size, raise rate limit and force info-level logging so the log viewer and Fail2Ban work.
|
||||
msg_info2 "$(translate "Limiting size and optimizing journald")"
|
||||
NECESSARY_REBOOT=1
|
||||
NECESSARY_REBOOT=1
|
||||
local journald_conf="/etc/systemd/journald.conf"
|
||||
local config_changed=false
|
||||
|
||||
@@ -280,7 +294,7 @@ EOF
|
||||
journalctl --rotate > /dev/null 2>&1
|
||||
|
||||
msg_success "$(translate "Journald optimization completed")"
|
||||
register_tool "journald" true
|
||||
register_tool "journald" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -299,6 +313,8 @@ EOF
|
||||
|
||||
|
||||
configure_kernel_panic() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Auto-reboot on kernel panic / oops / hardlockup; write crash dumps to /var/crash.
|
||||
msg_info2 "$(translate "Configuring kernel panic behavior")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -320,7 +336,7 @@ EOF
|
||||
|
||||
|
||||
msg_ok "$(translate "Kernel panic configuration updated and applied")"
|
||||
register_tool "kernel_panic" true
|
||||
register_tool "kernel_panic" true "$FUNC_VERSION"
|
||||
msg_success "$(translate "Kernel panic behavior configuration completed")"
|
||||
}
|
||||
|
||||
@@ -333,6 +349,8 @@ EOF
|
||||
|
||||
|
||||
increase_system_limits() {
|
||||
local FUNC_VERSION="1.1"
|
||||
# description: Raise inotify watches, file descriptors, process keys and PID limits to enterprise levels.
|
||||
msg_info2 "$(translate "Increasing various system limits...")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -418,7 +436,7 @@ fs.file-max = 2097152
|
||||
fs.aio-max-nr = 1048576"
|
||||
|
||||
msg_ok "$(translate "Max FS open files configuration created successfully")"
|
||||
register_tool "system_limits" true
|
||||
register_tool "system_limits" true "$FUNC_VERSION"
|
||||
msg_success "$(translate "System limits increase completed.")"
|
||||
}
|
||||
|
||||
@@ -431,6 +449,8 @@ fs.aio-max-nr = 1048576"
|
||||
|
||||
|
||||
skip_apt_languages() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Stop APT from downloading translation files to speed up updates.
|
||||
msg_info2 "$(translate "Configuring APT to skip downloading additional languages")"
|
||||
|
||||
# 1. Detect locale
|
||||
@@ -471,7 +491,7 @@ skip_apt_languages() {
|
||||
msg_ok "$(translate "APT language configuration updated")"
|
||||
fi
|
||||
|
||||
register_tool "apt_languages" true
|
||||
register_tool "apt_languages" true "$FUNC_VERSION"
|
||||
msg_success "$(translate "APT configured to skip downloading additional languages")"
|
||||
}
|
||||
|
||||
@@ -489,6 +509,8 @@ skip_apt_languages() {
|
||||
|
||||
|
||||
configure_time_sync() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Detect timezone from public IP and enable systemd time sync (NTP).
|
||||
msg_info2 "$(translate "Configuring system time settings...")"
|
||||
|
||||
this_ip=$(dig +short myip.opendns.com @resolver1.opendns.com 2>/dev/null)
|
||||
@@ -497,20 +519,30 @@ configure_time_sync() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
timezone=$(curl -s --connect-timeout 10 "https://ipapi.co/${this_ip}/timezone" 2>/dev/null)
|
||||
timezone=$(curl -s --connect-timeout 10 "https://ipapi.co/${this_ip}/timezone" 2>/dev/null | tr -d '[:space:]')
|
||||
if [ -z "$timezone" ] || [ "$timezone" = "undefined" ]; then
|
||||
msg_warn "$(translate "Failed to determine timezone from IP address - keeping current timezone settings")"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Validate against the system's IANA timezone database before applying.
|
||||
# ipapi.co can return rate-limit JSON, an error string, or stale data; the
|
||||
# previous code accepted anything that wasn't literally "undefined" and
|
||||
# passed it straight to `timedatectl set-timezone`, which silently kept
|
||||
# the old TZ on a bad value.
|
||||
if ! timedatectl list-timezones 2>/dev/null | grep -Fxq "$timezone"; then
|
||||
msg_warn "$(translate "API returned an invalid timezone") ($timezone) - $(translate "keeping current settings")"
|
||||
return 0
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Found timezone $timezone for IP $this_ip")"
|
||||
|
||||
|
||||
if timedatectl set-timezone "$timezone"; then
|
||||
msg_ok "$(translate "Timezone set to $timezone")"
|
||||
|
||||
if timedatectl set-ntp true; then
|
||||
msg_ok "$(translate "Time settings configured - Timezone:") $timezone"
|
||||
register_tool "time_sync" true
|
||||
register_tool "time_sync" true "$FUNC_VERSION"
|
||||
|
||||
systemctl restart postfix 2>/dev/null || true
|
||||
else
|
||||
@@ -583,6 +615,8 @@ configure_time_sync() {
|
||||
|
||||
|
||||
apply_amd_fixes() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Detect AMD EPYC/Ryzen CPUs and apply microcode + IOMMU + KVM-specific kernel boot params.
|
||||
msg_info2 "$(translate "Detecting AMD CPU and applying fixes if necessary...")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -672,7 +706,7 @@ apply_amd_fixes() {
|
||||
fi
|
||||
|
||||
msg_success "$(translate "AMD CPU fixes applied successfully")"
|
||||
register_tool "amd_fixes" true
|
||||
register_tool "amd_fixes" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -687,6 +721,8 @@ apply_amd_fixes() {
|
||||
|
||||
|
||||
force_apt_ipv4() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Force APT to use IPv4 to avoid stalls on hosts with broken IPv6 connectivity.
|
||||
msg_info2 "$(translate "Configuring APT to use IPv4...")"
|
||||
|
||||
local config_file="/etc/apt/apt.conf.d/99-force-ipv4"
|
||||
@@ -701,7 +737,7 @@ force_apt_ipv4() {
|
||||
fi
|
||||
fi
|
||||
|
||||
register_tool "apt_ipv4" true
|
||||
register_tool "apt_ipv4" true "$FUNC_VERSION"
|
||||
msg_success "$(translate "APT IPv4 configuration completed")"
|
||||
}
|
||||
|
||||
@@ -716,6 +752,8 @@ force_apt_ipv4() {
|
||||
|
||||
|
||||
apply_network_optimizations() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Tune TCP buffers, somaxconn, IPv4 hardening and disable rp_filter on fw bridges (PVE 9 compatible).
|
||||
msg_info "$(translate "Optimizing network settings...")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -742,6 +780,12 @@ net.ipv4.conf.default.secure_redirects = 0
|
||||
net.ipv4.conf.default.send_redirects = 0
|
||||
net.ipv4.conf.default.log_martians = 0
|
||||
|
||||
# rp_filter=2 (loose) instead of the kernel default 1 (strict). Loose
|
||||
# allows asymmetric routing typical of a Proxmox host with VMs on
|
||||
# multiple bridges — strict mode would drop legitimate VM traffic when
|
||||
# the reverse path differs. Trade-off: slightly weaker spoofing
|
||||
# protection from local LAN. Document this choice rather than the
|
||||
# default.
|
||||
net.ipv4.conf.all.rp_filter = 2
|
||||
net.ipv4.conf.default.rp_filter = 2
|
||||
|
||||
@@ -750,6 +794,11 @@ net.ipv4.icmp_echo_ignore_broadcasts = 1
|
||||
net.ipv4.icmp_ignore_bogus_error_responses = 1
|
||||
|
||||
# TCP/IP
|
||||
# Wider ephemeral port range than Debian's default 32768-60999 so
|
||||
# Proxmox hosts handing out NAT/forward ports for many VMs/CTs don't
|
||||
# run out under load. Privileged-port range (1-1023) is still protected
|
||||
# by capabilities — the kernel won't actually pick one for an
|
||||
# unprivileged ephemeral allocation.
|
||||
net.ipv4.ip_local_port_range = 1024 65535
|
||||
net.ipv4.tcp_mtu_probing = 1
|
||||
net.ipv4.tcp_rfc1337 = 1
|
||||
@@ -771,7 +820,7 @@ EOF
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Network optimization completed")"
|
||||
register_tool "network_optimization" true
|
||||
register_tool "network_optimization" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -786,6 +835,8 @@ EOF
|
||||
|
||||
|
||||
install_openvswitch() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Install OpenVSwitch for software-defined networking inside VMs and containers.
|
||||
msg_info2 "$(translate "Installing OpenVSwitch for virtual internal network...")"
|
||||
|
||||
|
||||
@@ -813,6 +864,7 @@ install_openvswitch() {
|
||||
# Verify installation
|
||||
if command -v ovs-vsctl >/dev/null 2>&1; then
|
||||
msg_success "$(translate "OpenVSwitch is ready to use")"
|
||||
register_tool "openvswitch" true "$FUNC_VERSION"
|
||||
else
|
||||
msg_warn "$(translate "OpenVSwitch installation could not be verified")"
|
||||
fi
|
||||
@@ -829,6 +881,8 @@ install_openvswitch() {
|
||||
|
||||
|
||||
enable_tcp_fast_open() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Enable TCP Fast Open (clients + server) and BBR congestion control for better latency under load.
|
||||
msg_info2 "$(translate "Configuring TCP optimizations...")"
|
||||
|
||||
local bbr_conf="/etc/sysctl.d/99-kernel-bbr.conf"
|
||||
@@ -869,6 +923,7 @@ EOF
|
||||
fi
|
||||
|
||||
msg_success "$(translate "TCP optimizations configuration completed")"
|
||||
register_tool "tcp_optimizations" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -883,6 +938,8 @@ EOF
|
||||
|
||||
|
||||
install_ceph() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Install Ceph (client + server packages) for distributed RBD/CephFS storage; PVE 8/9 aware repo selection.
|
||||
msg_info2 "$(translate "Installing Ceph support...")"
|
||||
|
||||
|
||||
@@ -1043,8 +1100,11 @@ EOF
|
||||
msg_info2 "$(translate "You may need to run 'pveceph install' manually")"
|
||||
msg_success "$(translate "Ceph installation process finished with warnings")"
|
||||
fi
|
||||
|
||||
|
||||
# Track install in the registry so the Uninstall menu can offer
|
||||
# `apt purge ceph-*` + repo removal. Audit Tier 6 — `install_ceph` /
|
||||
# `enable_ha` sin `register_tool` ni uninstall.
|
||||
register_tool "ceph" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -1060,6 +1120,8 @@ EOF
|
||||
|
||||
|
||||
optimize_zfs_arc() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Cap ZFS ARC to a sensible fraction of host RAM so VMs don't fight the kernel for memory.
|
||||
msg_info2 "$(translate "Optimizing ZFS ARC size according to available memory...")"
|
||||
|
||||
# Check if ZFS is installed
|
||||
@@ -1139,6 +1201,7 @@ EOF
|
||||
fi
|
||||
|
||||
msg_success "$(translate "ZFS ARC optimization completed")"
|
||||
register_tool "zfs_arc" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -1151,6 +1214,8 @@ EOF
|
||||
|
||||
|
||||
install_zfs_auto_snapshot() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Install zfs-auto-snapshot with cron schedules for hourly/daily/weekly/monthly snapshots.
|
||||
msg_info2 "$(translate "Installing and configuring ZFS auto-snapshot...")"
|
||||
|
||||
# Check if zfs-auto-snapshot is already installed
|
||||
@@ -1171,6 +1236,7 @@ install_zfs_auto_snapshot() {
|
||||
config_zfs_auto_snapshot
|
||||
|
||||
msg_success "$(translate "ZFS auto-snapshot installation and configuration completed")"
|
||||
register_tool "zfs_auto_snapshot" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
config_zfs_auto_snapshot() {
|
||||
@@ -1238,6 +1304,8 @@ disable_rpc() {
|
||||
|
||||
|
||||
configure_pigz() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Replace gzip with pigz (parallel implementation) for faster vzdump backup compression.
|
||||
msg_info2 "$(translate "Configuring pigz as a faster replacement for gzip...")"
|
||||
|
||||
# Enable pigz in vzdump configuration
|
||||
@@ -1295,6 +1363,7 @@ EOF
|
||||
fi
|
||||
|
||||
msg_success "$(translate "pigz configuration completed")"
|
||||
register_tool "pigz" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -1339,6 +1408,8 @@ EOF
|
||||
|
||||
|
||||
install_guest_agent() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Detect the host's hypervisor (qemu/vmware/hyperv/virtualbox) and install the matching guest agent.
|
||||
msg_info2 "$(translate "Detecting virtualization and installing guest agent...")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -1366,6 +1437,11 @@ install_guest_agent() {
|
||||
msg_info "$(translate "Installing $guest_agent for $virt_env...")"
|
||||
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' install $guest_agent > /dev/null 2>&1; then
|
||||
msg_ok "$(translate "$guest_agent installed successfully")"
|
||||
# Persist which package was installed so the uninstaller knows
|
||||
# what to apt purge later (different per hypervisor).
|
||||
mkdir -p /usr/local/share/proxmenux 2>/dev/null
|
||||
echo "$guest_agent" > /usr/local/share/proxmenux/guest_agent.pkg
|
||||
register_tool "guest_agent" true "$FUNC_VERSION"
|
||||
else
|
||||
msg_error "$(translate "Failed to install $guest_agent")"
|
||||
fi
|
||||
@@ -1398,6 +1474,8 @@ install_guest_agent() {
|
||||
|
||||
|
||||
enable_vfio_iommu() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Enable IOMMU and load VFIO modules to allow GPU/PCI passthrough into VMs.
|
||||
msg_info2 "$(translate "Enabling IOMMU and configuring VFIO for PCI passthrough...")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -1553,7 +1631,7 @@ enable_vfio_iommu() {
|
||||
fi
|
||||
|
||||
msg_success "$(translate "IOMMU and VFIO setup completed")"
|
||||
register_tool "vfio_iommu" true
|
||||
register_tool "vfio_iommu" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -1570,6 +1648,8 @@ enable_vfio_iommu() {
|
||||
|
||||
|
||||
customize_bashrc() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Inject the ProxMenux core bashrc block (aliases, prompt, history) into root's .bashrc, idempotent via begin/end markers.
|
||||
msg_info2 "$(translate "Customizing bashrc for root user...")"
|
||||
|
||||
msg_info "$(translate "Customizing bashrc for root user...")"
|
||||
@@ -1609,7 +1689,7 @@ EOF
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Bashrc customization completed")"
|
||||
register_tool "bashrc_custom" true
|
||||
register_tool "bashrc_custom" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -1667,36 +1747,34 @@ setup_motd() {
|
||||
|
||||
|
||||
optimize_logrotate() {
|
||||
msg_info2 "$(translate "Optimizing logrotate configuration...")"
|
||||
local FUNC_VERSION="1.1"
|
||||
# description: Replace logrotate.conf with a Log2RAM-friendly profile (daily rotation, copytruncate).
|
||||
msg_info2 "$(translate "Optimizing logrotate configuration...")"
|
||||
|
||||
local logrotate_conf="/etc/logrotate.conf"
|
||||
local backup_conf="${logrotate_conf}.bak"
|
||||
|
||||
cp -n "$logrotate_conf" "$backup_conf" 2>/dev/null || true
|
||||
|
||||
if grep -q "# ProxMenux optimized configuration" "$logrotate_conf"; then
|
||||
msg_ok "$(translate "Logrotate configuration already optimized.")"
|
||||
else
|
||||
cp "$logrotate_conf" "$backup_conf"
|
||||
|
||||
msg_info "$(translate "Applying optimized logrotate configuration...")"
|
||||
cat <<EOF > "$logrotate_conf"
|
||||
# ProxMenux optimized configuration
|
||||
msg_info "$(translate "Applying optimized logrotate configuration...")"
|
||||
cat <<EOF > "$logrotate_conf"
|
||||
# ProxMenux optimized configuration (Log2RAM-friendly)
|
||||
daily
|
||||
su root adm
|
||||
rotate 7
|
||||
create
|
||||
compress
|
||||
size 10M
|
||||
compress
|
||||
delaycompress
|
||||
missingok
|
||||
notifempty
|
||||
create 0640 root adm
|
||||
copytruncate
|
||||
|
||||
include /etc/logrotate.d
|
||||
EOF
|
||||
|
||||
systemctl restart logrotate > /dev/null 2>&1
|
||||
msg_ok "$(translate "Logrotate service restarted successfully")"
|
||||
fi
|
||||
register_tool "logrotate" true
|
||||
register_tool "logrotate" true "$FUNC_VERSION"
|
||||
msg_success "$(translate "Logrotate optimization completed")"
|
||||
}
|
||||
|
||||
@@ -1711,6 +1789,8 @@ EOF
|
||||
|
||||
|
||||
remove_subscription_banner() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Patch the Proxmox web UI to suppress the "no valid subscription" dialog (PVE 8 + 9 variants supported).
|
||||
local pve_version
|
||||
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
|
||||
|
||||
@@ -1726,7 +1806,7 @@ remove_subscription_banner() {
|
||||
|
||||
bash "$LOCAL_SCRIPTS/global/remove-banner-pve8.sh"
|
||||
fi
|
||||
register_tool "subscription_banner" true
|
||||
register_tool "subscription_banner" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -1740,6 +1820,8 @@ remove_subscription_banner() {
|
||||
|
||||
|
||||
optimize_memory_settings() {
|
||||
local FUNC_VERSION="1.1"
|
||||
# description: Tune swappiness, dirty page ratios, overcommit and compaction proactiveness for VM hosts.
|
||||
msg_info2 "$(translate "Optimizing memory settings...")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -1777,7 +1859,7 @@ EOF
|
||||
|
||||
msg_ok "$(translate "Memory settings optimized successfully")"
|
||||
msg_success "$(translate "Memory optimization completed.")"
|
||||
register_tool "memory_settings" true
|
||||
register_tool "memory_settings" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -1791,10 +1873,19 @@ EOF
|
||||
|
||||
|
||||
optimize_vzdump() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Lift vzdump bandwidth/IO limits so backups run at the storage's real throughput.
|
||||
msg_info2 "$(translate "Optimizing vzdump backup speed...")"
|
||||
|
||||
local vzdump_conf="/etc/vzdump.conf"
|
||||
|
||||
# Backup the current config so the uninstall path can restore the
|
||||
# user's original values. The previous code edited in-place with no
|
||||
# backup; users with custom bwlimit/ionice lost them silently.
|
||||
if [[ -f "$vzdump_conf" && ! -f "${vzdump_conf}.bak" ]]; then
|
||||
cp -p "$vzdump_conf" "${vzdump_conf}.bak"
|
||||
fi
|
||||
|
||||
# Configure bandwidth limit
|
||||
msg_info "$(translate "Configuring bandwidth limit for vzdump...")"
|
||||
if ! grep -q "^bwlimit: 0" "$vzdump_conf"; then
|
||||
@@ -1812,6 +1903,7 @@ optimize_vzdump() {
|
||||
msg_ok "$(translate "I/O priority configured")"
|
||||
|
||||
msg_success "$(translate "vzdump backup speed optimization completed")"
|
||||
register_tool "vzdump_speed" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -1825,12 +1917,17 @@ optimize_vzdump() {
|
||||
|
||||
|
||||
install_ovh_rtm() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Detect OVH-rented hardware via whois lookup and install OVH Real-Time Monitoring (no-op on non-OVH).
|
||||
msg_info2 "$(translate "Detecting if this is an OVH server and installing OVH RTM if necessary...")"
|
||||
|
||||
# Get the public IP and check if it belongs to OVH
|
||||
msg_info "$(translate "Checking if the server belongs to OVH...")"
|
||||
public_ip=$(curl -s ipinfo.io/ip)
|
||||
is_ovh=$(whois -h v4.whois.cymru.com " -t $public_ip" | tail -n 1 | cut -d'|' -f3 | grep -i "ovh")
|
||||
# `--` ends whois client option parsing so "-t IP" reaches the cymru server
|
||||
# as the query string. Previous form had a leading space inside the quotes
|
||||
# ("\" -t IP\"") that mangled the query and caused detection to never match.
|
||||
is_ovh=$(whois -h v4.whois.cymru.com -- "-t $public_ip" | tail -n 1 | cut -d'|' -f3 | grep -i "ovh")
|
||||
|
||||
if [ -n "$is_ovh" ]; then
|
||||
msg_ok "$(translate "OVH server detected")"
|
||||
@@ -1838,11 +1935,13 @@ install_ovh_rtm() {
|
||||
msg_info "$(translate "Installing OVH RTM (Real Time Monitoring)...")"
|
||||
if wget -qO - https://last-public-ovh-infra-yak.snap.mirrors.ovh.net/yak/archives/apply.sh | OVH_PUPPET_MANIFEST=distribyak/catalog/master/puppet/manifests/common/rtmv2.pp bash > /dev/null 2>&1; then
|
||||
msg_ok "$(translate "OVH RTM installed successfully")"
|
||||
register_tool "ovh_rtm" true "$FUNC_VERSION"
|
||||
else
|
||||
msg_error "$(translate "Failed to install OVH RTM")"
|
||||
fi
|
||||
else
|
||||
msg_ok "$(translate "Not an OVH server, skipping RTM installation")"
|
||||
fi
|
||||
msg_ok "$(translate "Server belongs to OVH")"
|
||||
msg_success "$(translate "OVH server detection and RTM installation process completed")"
|
||||
}
|
||||
|
||||
@@ -1854,6 +1953,8 @@ install_ovh_rtm() {
|
||||
|
||||
|
||||
enable_ha() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Enable the Proxmox HA stack (pve-ha-lrm, pve-ha-crm, corosync) for cluster failover.
|
||||
msg_info2 "$(translate "Enabling High Availability (HA) services...")"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
@@ -1865,7 +1966,7 @@ enable_ha() {
|
||||
msg_ok "$(translate "High Availability services have been enabled successfully")"
|
||||
msg_success "$(translate "High Availability setup completed")"
|
||||
|
||||
|
||||
register_tool "ha" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -1879,6 +1980,8 @@ enable_ha() {
|
||||
|
||||
|
||||
configure_fastfetch() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Install Fastfetch system summary tool with the ProxMenux logo + status block as the SSH login banner.
|
||||
msg_info2 "$(translate "Installing and configuring Fastfetch...")"
|
||||
|
||||
|
||||
@@ -1900,8 +2003,17 @@ configure_fastfetch() {
|
||||
|
||||
|
||||
msg_info "$(translate "Downloading the latest Fastfetch release...")"
|
||||
local fastfetch_deb_url=$(curl -s https://api.github.com/repos/fastfetch-cli/fastfetch/releases/latest |
|
||||
jq -r '.assets[] | select(.name | test("fastfetch-linux-amd64.deb")) | .browser_download_url')
|
||||
# `--connect-timeout`/`--max-time` so a slow GitHub API call doesn't
|
||||
# hang the menu indefinitely. `FASTFETCH_PIN_TAG` env var lets the
|
||||
# caller pin to a known release if upstream introduces a breaking
|
||||
# change. Audit Tier 6 — recursos remotos sin pinning de versión.
|
||||
local fastfetch_deb_url=""
|
||||
if [[ -n "${FASTFETCH_PIN_TAG:-}" ]]; then
|
||||
fastfetch_deb_url="https://github.com/fastfetch-cli/fastfetch/releases/download/${FASTFETCH_PIN_TAG}/fastfetch-linux-amd64.deb"
|
||||
else
|
||||
fastfetch_deb_url=$(curl -s --connect-timeout 5 --max-time 15 https://api.github.com/repos/fastfetch-cli/fastfetch/releases/latest |
|
||||
jq -r '.assets[] | select(.name | test("fastfetch-linux-amd64.deb")) | .browser_download_url')
|
||||
fi
|
||||
|
||||
if [[ -z "$fastfetch_deb_url" ]]; then
|
||||
msg_error "$(translate "Failed to retrieve Fastfetch download URL.")"
|
||||
@@ -2070,7 +2182,7 @@ fi
|
||||
|
||||
msg_ok "$(translate "Fastfetch will start automatically in the console")"
|
||||
msg_success "$(translate "Fastfetch installation and configuration completed")"
|
||||
register_tool "fastfetch" true
|
||||
register_tool "fastfetch" true "$FUNC_VERSION"
|
||||
|
||||
}
|
||||
|
||||
@@ -2102,8 +2214,13 @@ register_tool "fastfetch" true
|
||||
|
||||
|
||||
configure_figurine() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Install Figurine (ASCII-art hostname banner) and wire it into the SSH login flow.
|
||||
msg_info2 "$(translate "Installing and configuring Figurine...")"
|
||||
local version="1.3.0"
|
||||
# `FIGURINE_VERSION` env var allows pinning to a specific release;
|
||||
# default tracks the last tested upstream tag. Audit Tier 6 —
|
||||
# recursos remotos sin pinning de versión.
|
||||
local version="${FIGURINE_VERSION:-1.3.0}"
|
||||
local file="figurine_linux_amd64_v${version}.tar.gz"
|
||||
local url="https://github.com/arsham/figurine/releases/download/v${version}/${file}"
|
||||
local temp_dir; temp_dir=$(mktemp -d)
|
||||
@@ -2190,7 +2307,7 @@ EOF
|
||||
msg_ok "$(translate "Aliases added to .bashrc")"
|
||||
|
||||
msg_success "$(translate "Figurine installation and configuration completed successfully.")"
|
||||
register_tool "figurine" true
|
||||
register_tool "figurine" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -2233,6 +2350,8 @@ update_pve_appliance_manager() {
|
||||
|
||||
|
||||
configure_log2ram() {
|
||||
local FUNC_VERSION="1.1"
|
||||
# description: Install Log2RAM with user-chosen RAM size; prompts for size and SSD/M.2 awareness before applying.
|
||||
msg_info2 "$(translate "Preparing Log2RAM configuration")"
|
||||
sleep 1
|
||||
|
||||
@@ -2311,7 +2430,14 @@ configure_log2ram() {
|
||||
fi
|
||||
|
||||
rm -rf /tmp/log2ram 2>/dev/null || true
|
||||
if ! git clone https://github.com/azlux/log2ram.git /tmp/log2ram >/dev/null 2>>/tmp/log2ram_install.log; then
|
||||
# Pin to a tested release — `master` could ship breaking changes
|
||||
# without notice. `LOG2RAM_TAG` env var lets the caller upgrade.
|
||||
local LOG2RAM_TAG="${LOG2RAM_TAG:-1.7.0}"
|
||||
if ! git clone --depth 1 --branch "$LOG2RAM_TAG" \
|
||||
https://github.com/azlux/log2ram.git /tmp/log2ram \
|
||||
>/dev/null 2>>/tmp/log2ram_install.log \
|
||||
&& ! git clone --depth 1 https://github.com/azlux/log2ram.git /tmp/log2ram \
|
||||
>/dev/null 2>>/tmp/log2ram_install.log; then
|
||||
msg_error "$(translate "Failed to clone log2ram repository. Check /tmp/log2ram_install.log")"
|
||||
return 1
|
||||
fi
|
||||
@@ -2452,7 +2578,7 @@ EOF
|
||||
systemctl restart rsyslog >/dev/null 2>&1 || true
|
||||
|
||||
msg_success "$(translate "Log2RAM installation and configuration completed successfully.")"
|
||||
register_tool "log2ram" true
|
||||
register_tool "log2ram" true "$FUNC_VERSION"
|
||||
}
|
||||
|
||||
|
||||
@@ -2470,6 +2596,8 @@ EOF
|
||||
|
||||
|
||||
setup_persistent_network() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Pin NIC names to MAC addresses via systemd .link files so kernel updates don't shuffle interface names.
|
||||
local LINK_DIR="/etc/systemd/network"
|
||||
local BACKUP_DIR="/etc/systemd/network/backup-$(date +%Y%m%d-%H%M%S)"
|
||||
local pve_version
|
||||
@@ -2478,8 +2606,20 @@ setup_persistent_network() {
|
||||
msg_info "$(translate "Setting up persistent network interfaces")"
|
||||
sleep 2
|
||||
|
||||
# Detect legacy `/etc/network/interfaces` setups that depend on the
|
||||
# default udev naming. If the file references `allow-hotplug` rules
|
||||
# or uses physical interface names directly, the .link rules below
|
||||
# could rename interfaces and break network on reboot. Warn loudly so
|
||||
# the user can review before continuing. Audit Tier 6 —
|
||||
# `setup_persistent_network` no detecta conflicto con legacy.
|
||||
if [[ -f /etc/network/interfaces ]]; then
|
||||
if grep -qE '^[[:space:]]*allow-hotplug[[:space:]]' /etc/network/interfaces 2>/dev/null; then
|
||||
msg_warn "$(translate '/etc/network/interfaces uses allow-hotplug. Renaming interfaces via systemd .link can break that flow — review the file after reboot.')"
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p "$LINK_DIR"
|
||||
|
||||
|
||||
|
||||
if ls "$LINK_DIR"/*.link >/dev/null 2>&1; then
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
@@ -2523,7 +2663,7 @@ EOF
|
||||
msg_warn "$(translate "No physical interfaces found")"
|
||||
fi
|
||||
msg_success "$(translate "Setting up persistent network interfaces successfully.")"
|
||||
register_tool "persistent_network" true
|
||||
register_tool "persistent_network" true "$FUNC_VERSION"
|
||||
NECESSARY_REBOOT=1
|
||||
}
|
||||
|
||||
@@ -2866,5 +3006,11 @@ done
|
||||
|
||||
|
||||
|
||||
check_extremeshok_warning
|
||||
main_menu
|
||||
# Sprint 12B: only run the interactive menu when this script is invoked
|
||||
# directly. When sourced from another script (e.g. the post-install
|
||||
# update wrapper that re-runs a single function), don't trigger the
|
||||
# extremeshok warning or the main menu.
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
check_extremeshok_warning
|
||||
main_menu
|
||||
fi
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux - Complete Uninstall Optimizations Script
|
||||
# ProxMenux - Uninstall Optimizations
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 06/07/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script provides a complete uninstallation and rollback system
|
||||
# for all post-installation optimizations applied by ProxMenux.
|
||||
# Reverses post-install optimizations previously applied by
|
||||
# ProxMenux. Reads the installed_tools.json registry to detect
|
||||
# which tools were applied, exposes them in a checklist, and
|
||||
# runs their dedicated uninstall function — restoring original
|
||||
# configs from their .bak backups where applicable.
|
||||
#
|
||||
# It allows administrators to safely revert any changes made during the
|
||||
# optimization process, restoring the system to its original state.
|
||||
#
|
||||
# This ensures full control over system configurations and gives users
|
||||
# the confidence to apply, test, and undo ProxMenux enhancements as needed.
|
||||
# Features:
|
||||
# - Registry-driven: only shows tools currently applied.
|
||||
# - Per-tool reverse functions (one for each entry in the
|
||||
# auto / customizable scripts).
|
||||
# - Restores /etc configs from .bak backups when they exist.
|
||||
# - Reboot prompt for changes that require it (VFIO, kernel
|
||||
# cmdline, persistent NIC names, …).
|
||||
# ==========================================================
|
||||
|
||||
|
||||
@@ -633,6 +638,8 @@ uninstall_vfio_iommu() {
|
||||
msg_ok "$(translate "IOMMU parameters removed from GRUB")"
|
||||
fi
|
||||
fi
|
||||
|
||||
msg_info "$(translate 'Updating initramfs (this may take a minute)...')"
|
||||
|
||||
update-initramfs -u -k all >/dev/null 2>&1 || true
|
||||
|
||||
@@ -804,6 +811,122 @@ migrate_installed_tools() {
|
||||
fi
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Sprint 10P — Uninstallers for items previously missing coverage.
|
||||
# Each `uninstall_*` mirrors its install function in
|
||||
# `customizable_post_install.sh` and flips `register_tool "X" false`
|
||||
# at the end so the entry is removed from the active set.
|
||||
################################################################
|
||||
|
||||
uninstall_ceph() {
|
||||
msg_info2 "$(translate 'Uninstalling Ceph...')"
|
||||
if dpkg -l 2>/dev/null | grep -qE '^ii\s+ceph'; then
|
||||
apt-get purge -y 'ceph-*' 'librados*' 'librbd*' 'libcephfs*' 'python3-ceph*' >/dev/null 2>&1 || true
|
||||
apt-get autoremove -y >/dev/null 2>&1 || true
|
||||
fi
|
||||
rm -f /etc/apt/sources.list.d/ceph.list /etc/apt/sources.list.d/ceph.sources 2>/dev/null
|
||||
rm -f /etc/apt/trusted.gpg.d/ceph.asc /etc/apt/trusted.gpg.d/ceph-release.gpg 2>/dev/null
|
||||
apt-get update -qq >/dev/null 2>&1 || true
|
||||
msg_ok "$(translate 'Ceph packages and repository removed')"
|
||||
register_tool "ceph" false
|
||||
}
|
||||
|
||||
uninstall_ha() {
|
||||
msg_info2 "$(translate 'Disabling High Availability services...')"
|
||||
systemctl disable --now pve-ha-lrm pve-ha-crm corosync >/dev/null 2>&1 || true
|
||||
msg_ok "$(translate 'HA services disabled (configs preserved)')"
|
||||
register_tool "ha" false
|
||||
}
|
||||
|
||||
uninstall_openvswitch() {
|
||||
msg_info2 "$(translate 'Removing OpenVSwitch...')"
|
||||
apt-get purge -y openvswitch-switch openvswitch-common >/dev/null 2>&1 || true
|
||||
apt-get autoremove -y >/dev/null 2>&1 || true
|
||||
msg_ok "$(translate 'OpenVSwitch removed')"
|
||||
register_tool "openvswitch" false
|
||||
}
|
||||
|
||||
uninstall_tcp_optimizations() {
|
||||
msg_info2 "$(translate 'Reverting TCP BBR + Fast Open...')"
|
||||
rm -f /etc/sysctl.d/99-kernel-bbr.conf /etc/sysctl.d/99-tcp-fastopen.conf
|
||||
sysctl --system >/dev/null 2>&1 || true
|
||||
msg_ok "$(translate 'TCP optimizations reverted (defaults restored on next reboot)')"
|
||||
register_tool "tcp_optimizations" false
|
||||
}
|
||||
|
||||
uninstall_guest_agent() {
|
||||
msg_info2 "$(translate 'Removing guest agent...')"
|
||||
local pkg=""
|
||||
if [[ -f /usr/local/share/proxmenux/guest_agent.pkg ]]; then
|
||||
pkg=$(cat /usr/local/share/proxmenux/guest_agent.pkg 2>/dev/null)
|
||||
fi
|
||||
if [[ -n "$pkg" ]]; then
|
||||
apt-get purge -y "$pkg" >/dev/null 2>&1 || true
|
||||
rm -f /usr/local/share/proxmenux/guest_agent.pkg
|
||||
msg_ok "$(translate 'Removed:') $pkg"
|
||||
else
|
||||
# Fallback: try the typical packages
|
||||
for p in qemu-guest-agent open-vm-tools virtualbox-guest-utils; do
|
||||
dpkg -s "$p" >/dev/null 2>&1 && apt-get purge -y "$p" >/dev/null 2>&1
|
||||
done
|
||||
msg_ok "$(translate 'Guest agent packages removed')"
|
||||
fi
|
||||
register_tool "guest_agent" false
|
||||
}
|
||||
|
||||
uninstall_ovh_rtm() {
|
||||
msg_info2 "$(translate 'Removing OVH RTM...')"
|
||||
# OVH RTM installs `rtm` packages and a puppet config.
|
||||
apt-get purge -y 'ovh-rtm*' 'rtm' 'rtm-*' >/dev/null 2>&1 || true
|
||||
rm -rf /etc/rtm 2>/dev/null
|
||||
msg_ok "$(translate 'OVH RTM removed (Puppet artefacts may need manual cleanup)')"
|
||||
register_tool "ovh_rtm" false
|
||||
}
|
||||
|
||||
uninstall_pigz() {
|
||||
msg_info2 "$(translate 'Reverting pigz wrapper...')"
|
||||
if [[ -f /bin/gzip.original ]]; then
|
||||
mv -f /bin/gzip.original /bin/gzip
|
||||
msg_ok "$(translate 'Restored original /bin/gzip')"
|
||||
fi
|
||||
rm -f /bin/pigzwrapper
|
||||
sed -i 's/^pigz: 1/#pigz: 1/' /etc/vzdump.conf 2>/dev/null || true
|
||||
apt-get purge -y pigz >/dev/null 2>&1 || true
|
||||
msg_ok "$(translate 'pigz removed')"
|
||||
register_tool "pigz" false
|
||||
}
|
||||
|
||||
uninstall_zfs_arc() {
|
||||
msg_info2 "$(translate 'Reverting ZFS ARC tuning...')"
|
||||
if [[ -f /etc/modprobe.d/99-zfsarc.conf.bak ]]; then
|
||||
mv -f /etc/modprobe.d/99-zfsarc.conf.bak /etc/modprobe.d/99-zfsarc.conf
|
||||
msg_ok "$(translate 'Original ZFS ARC config restored from .bak')"
|
||||
else
|
||||
rm -f /etc/modprobe.d/99-zfsarc.conf
|
||||
msg_ok "$(translate 'ZFS ARC config removed (kernel defaults will apply on reboot)')"
|
||||
fi
|
||||
register_tool "zfs_arc" false
|
||||
}
|
||||
|
||||
uninstall_zfs_auto_snapshot() {
|
||||
msg_info2 "$(translate 'Removing zfs-auto-snapshot...')"
|
||||
apt-get purge -y zfs-auto-snapshot >/dev/null 2>&1 || true
|
||||
msg_ok "$(translate 'zfs-auto-snapshot removed (existing snapshots preserved on the pool)')"
|
||||
register_tool "zfs_auto_snapshot" false
|
||||
}
|
||||
|
||||
uninstall_vzdump_speed() {
|
||||
msg_info2 "$(translate 'Reverting vzdump speed tuning...')"
|
||||
if [[ -f /etc/vzdump.conf.bak ]]; then
|
||||
mv -f /etc/vzdump.conf.bak /etc/vzdump.conf
|
||||
msg_ok "$(translate 'Restored original /etc/vzdump.conf from .bak')"
|
||||
else
|
||||
sed -i '/^bwlimit: 0$/d;/^ionice: 5$/d' /etc/vzdump.conf 2>/dev/null
|
||||
msg_ok "$(translate 'Removed bwlimit/ionice tuning (no .bak found)')"
|
||||
fi
|
||||
register_tool "vzdump_speed" false
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
||||
show_uninstall_menu() {
|
||||
@@ -843,6 +966,16 @@ show_uninstall_menu() {
|
||||
amd_fixes) desc="AMD CPU (Ryzen/EPYC) fixes";;
|
||||
vfio_iommu) desc="IOMMU/VFIO PCI Passthrough";;
|
||||
persistent_network) desc="Setting persistent network interfaces";;
|
||||
ceph) desc="Ceph (squid) packages + repo";;
|
||||
ha) desc="High Availability services (corosync/HA)";;
|
||||
openvswitch) desc="OpenVSwitch";;
|
||||
tcp_optimizations) desc="TCP BBR + Fast Open";;
|
||||
guest_agent) desc="Guest agent (qemu/vmware/virtualbox)";;
|
||||
ovh_rtm) desc="OVH Real-Time Monitoring";;
|
||||
pigz) desc="pigz (parallel gzip wrapper)";;
|
||||
zfs_arc) desc="ZFS ARC size tuning";;
|
||||
zfs_auto_snapshot) desc="zfs-auto-snapshot package";;
|
||||
vzdump_speed) desc="vzdump bwlimit/ionice tuning";;
|
||||
*) desc="$tool";;
|
||||
esac
|
||||
menu_options+=("$tool" "$desc" "off")
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux - Sprint 12B: re-run a single post-install function
|
||||
# ==========================================================
|
||||
# Invoked by the Monitor's "Update" buttons (Settings → ProxMenux
|
||||
# Optimizations) and by the bash menu's update flow. Sources the
|
||||
# appropriate post_install script and invokes one specific function so
|
||||
# the user can update a single tool without re-running the whole flow.
|
||||
#
|
||||
# Two invocation modes:
|
||||
#
|
||||
# SINGLE — set SOURCE_TYPE + FUNCTION_NAME (+ optionally TOOL_KEY):
|
||||
# SOURCE_TYPE=auto FUNCTION_NAME=install_log2ram_auto
|
||||
#
|
||||
# BATCH — set FUNCTIONS_BATCH to a newline-separated list of
|
||||
# "source:function:tool_key" triples (tool_key optional):
|
||||
# FUNCTIONS_BATCH="auto:install_log2ram_auto:log2ram
|
||||
# custom:install_ceph:ceph"
|
||||
#
|
||||
# In batch mode the wrapper iterates the list, sourcing each flow once
|
||||
# and re-using its function definitions. Tools coming from the same
|
||||
# flow share a single source step so the terminal output stays clean.
|
||||
# ==========================================================
|
||||
|
||||
set -e
|
||||
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
if command -v load_language >/dev/null 2>&1; then
|
||||
load_language
|
||||
fi
|
||||
if command -v initialize_cache >/dev/null 2>&1; then
|
||||
initialize_cache
|
||||
fi
|
||||
|
||||
if command -v show_proxmenux_logo >/dev/null 2>&1; then
|
||||
show_proxmenux_logo
|
||||
fi
|
||||
|
||||
SOURCE_TYPE="${SOURCE_TYPE:-}"
|
||||
FUNCTION_NAME="${FUNCTION_NAME:-}"
|
||||
TOOL_KEY="${TOOL_KEY:-${FUNCTION_NAME}}"
|
||||
FUNCTIONS_BATCH="${FUNCTIONS_BATCH:-}"
|
||||
|
||||
# Build the list of (source, function, tool_key) tuples from either the
|
||||
# single-mode env vars or the batch payload.
|
||||
declare -a BATCH=()
|
||||
if [[ -n "$FUNCTIONS_BATCH" ]]; then
|
||||
while IFS= read -r line; do
|
||||
[[ -z "$line" ]] && continue
|
||||
BATCH+=("$line")
|
||||
done <<< "$FUNCTIONS_BATCH"
|
||||
elif [[ -n "$SOURCE_TYPE" && -n "$FUNCTION_NAME" ]]; then
|
||||
BATCH+=("${SOURCE_TYPE}:${FUNCTION_NAME}:${TOOL_KEY}")
|
||||
else
|
||||
echo "ERROR: provide either SOURCE_TYPE+FUNCTION_NAME (single mode) or FUNCTIONS_BATCH (batch mode)."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Source the flow scripts on first use. Both auto and customizable
|
||||
# guard their entry point with `if [[ "${BASH_SOURCE[0]}" == "${0}" ]]`,
|
||||
# so sourcing loads function definitions without triggering the
|
||||
# interactive menu or the extremeshok dialog.
|
||||
# ----------------------------------------------------------------------
|
||||
SOURCED_AUTO=0
|
||||
SOURCED_CUSTOM=0
|
||||
ensure_flow_loaded() {
|
||||
local source_type="$1"
|
||||
case "$source_type" in
|
||||
auto)
|
||||
if [[ $SOURCED_AUTO -eq 0 ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source "$LOCAL_SCRIPTS/post_install/auto_post_install.sh"
|
||||
SOURCED_AUTO=1
|
||||
fi
|
||||
;;
|
||||
custom)
|
||||
if [[ $SOURCED_CUSTOM -eq 0 ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source "$LOCAL_SCRIPTS/post_install/customizable_post_install.sh"
|
||||
SOURCED_CUSTOM=1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: invalid source '$source_type' (must be 'auto' or 'custom')"
|
||||
return 2
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Run each tool. We don't bail on the first failure — the user marked a
|
||||
# multi-select, they expect every chosen tool to be attempted. RCs are
|
||||
# collected and the wrapper exits non-zero if any failed.
|
||||
# ----------------------------------------------------------------------
|
||||
TOTAL=${#BATCH[@]}
|
||||
FAILED=0
|
||||
INDEX=0
|
||||
for entry in "${BATCH[@]}"; do
|
||||
INDEX=$((INDEX + 1))
|
||||
IFS=':' read -r src fn tkey <<< "$entry"
|
||||
[[ -z "$tkey" ]] && tkey="$fn"
|
||||
|
||||
if command -v msg_info2 >/dev/null 2>&1; then
|
||||
msg_info2 "[$INDEX/$TOTAL] Updating ${tkey} (running ${fn} from ${src} flow)..."
|
||||
else
|
||||
echo "[ProxMenux] [$INDEX/$TOTAL] Updating ${tkey} (running ${fn} from ${src} flow)..."
|
||||
fi
|
||||
|
||||
if ! ensure_flow_loaded "$src"; then
|
||||
FAILED=$((FAILED + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! declare -F "$fn" >/dev/null 2>&1; then
|
||||
if command -v msg_error >/dev/null 2>&1; then
|
||||
msg_error "Function '$fn' is not defined in the ${src} flow."
|
||||
else
|
||||
echo "ERROR: function '$fn' is not defined in the ${src} flow."
|
||||
fi
|
||||
FAILED=$((FAILED + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
set +e
|
||||
"$fn"
|
||||
RC=$?
|
||||
set -e
|
||||
|
||||
if [[ $RC -eq 0 ]]; then
|
||||
if command -v msg_ok >/dev/null 2>&1; then
|
||||
msg_ok "Update for ${tkey} completed."
|
||||
else
|
||||
echo "[ProxMenux] Update for ${tkey} completed."
|
||||
fi
|
||||
else
|
||||
if command -v msg_error >/dev/null 2>&1; then
|
||||
msg_error "Update for ${tkey} exited with status $RC."
|
||||
else
|
||||
echo "ERROR: update for ${tkey} exited with status $RC."
|
||||
fi
|
||||
FAILED=$((FAILED + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $FAILED -eq 0 ]]; then
|
||||
if command -v msg_success >/dev/null 2>&1; then
|
||||
msg_success "All $TOTAL update(s) completed successfully."
|
||||
else
|
||||
echo "[ProxMenux] All $TOTAL update(s) completed successfully."
|
||||
fi
|
||||
else
|
||||
if command -v msg_warn >/dev/null 2>&1; then
|
||||
msg_warn "$FAILED of $TOTAL updates failed — see the messages above."
|
||||
else
|
||||
echo "WARNING: $FAILED of $TOTAL updates failed."
|
||||
fi
|
||||
fi
|
||||
|
||||
if command -v msg_success >/dev/null 2>&1; then
|
||||
msg_success "Press Enter to close this terminal..."
|
||||
else
|
||||
echo "Press Enter to close this terminal..."
|
||||
fi
|
||||
read -r 2>/dev/null || true
|
||||
|
||||
[[ $FAILED -eq 0 ]] && exit 0 || exit 1
|
||||
@@ -1,214 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# Version : 1.0
|
||||
# Last Updated: 28/01/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows users to assign physical disks for passthrough to existing
|
||||
# Proxmox virtual machines (VMs) through an interactive menu.
|
||||
# - Detects and lists physical and network interfaces.
|
||||
# - Verifies and repairs bridge configurations.
|
||||
# - Ensures network connectivity by checking IP assignments.
|
||||
# - Provides options to manually repair or verify network settings.
|
||||
# - Offers interactive menus for user-friendly operation.
|
||||
#
|
||||
# The script aims to simplify network troubleshooting and ensure
|
||||
# that Proxmox systems maintain stable connectivity.
|
||||
# ==========================================================
|
||||
|
||||
# Configuration ============================================
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
VENV_PATH="/opt/googletrans-env"
|
||||
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
load_language
|
||||
initialize_cache
|
||||
# ==========================================================
|
||||
|
||||
# Function to detect physical network interfaces
|
||||
detect_physical_interfaces() {
|
||||
|
||||
physical_interfaces=$(ip -o link show | awk -F': ' '$2 !~ /^(lo|veth|dummy|bond)/ {print $2}')
|
||||
whiptail --title "$(translate 'Network Interfaces')" --msgbox "$physical_interfaces" 10 78
|
||||
}
|
||||
|
||||
|
||||
# Function to get all relevant network interfaces (physical and bridges)
|
||||
get_relevant_interfaces() {
|
||||
echo $(ip -o link show | awk -F': ' '$2 !~ /^(lo|veth|dummy)/ {print $2}')
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Function to check and fix bridge configuration
|
||||
check_and_fix_bridges() {
|
||||
|
||||
local output=""
|
||||
output+="$(translate 'Checking bridges')\\n\\n"
|
||||
bridges=$(grep "^auto vmbr" /etc/network/interfaces | awk '{print $2}')
|
||||
for bridge in $bridges; do
|
||||
old_port=$(grep -A1 "iface $bridge" /etc/network/interfaces | grep "bridge-ports" | awk '{print $2}')
|
||||
if ! ip link show "$old_port" &>/dev/null; then
|
||||
output+="$(translate 'Bridge port missing'): $bridge - $old_port\\n"
|
||||
new_port=$(echo "$physical_interfaces" | tr ' ' '\n' | grep -v "vmbr" | head -n1)
|
||||
if [ -n "$new_port" ]; then
|
||||
sed -i "/iface $bridge/,/bridge-ports/ s/bridge-ports.*/bridge-ports $new_port/" /etc/network/interfaces
|
||||
output+="$(translate 'Bridge port updated'): $bridge - $old_port -> $new_port\\n"
|
||||
else
|
||||
output+="$(translate 'No physical interface available')\\n"
|
||||
fi
|
||||
else
|
||||
output+="$(translate 'Bridge port OK'): $bridge - $old_port\\n"
|
||||
fi
|
||||
done
|
||||
whiptail --title "$(translate 'Checking Bridges')" --msgbox "$output" 20 78
|
||||
}
|
||||
|
||||
|
||||
clean_nonexistent_interfaces() {
|
||||
|
||||
local output=""
|
||||
output+="$(translate 'Cleaning interfaces')\\n\\n"
|
||||
configured_interfaces=$(grep "^iface" /etc/network/interfaces | awk '{print $2}' | grep -v "lo")
|
||||
for iface in $configured_interfaces; do
|
||||
if [[ ! $iface =~ ^(vmbr|bond) ]] && ! ip link show "$iface" &>/dev/null; then
|
||||
sed -i "/iface $iface/,/^$/d" /etc/network/interfaces
|
||||
output+="$(translate 'Interface removed'): $iface\\n"
|
||||
fi
|
||||
done
|
||||
whiptail --title "$(translate 'Cleaning Interfaces')" --msgbox "$output" 15 78
|
||||
}
|
||||
|
||||
|
||||
# Update other functions to use physical_interfaces or get_relevant_interfaces as appropriate
|
||||
configure_physical_interfaces() {
|
||||
|
||||
local output=""
|
||||
output+="$(translate 'Configuring interfaces')\\n\\n"
|
||||
for iface in $physical_interfaces; do
|
||||
if ! grep -q "iface $iface" /etc/network/interfaces; then
|
||||
echo -e "\niface $iface inet manual" >> /etc/network/interfaces
|
||||
output+="$(translate 'Interface added'): $iface\\n"
|
||||
fi
|
||||
done
|
||||
whiptail --title "$(translate 'Configuring Interfaces')" --msgbox "$output" 15 78
|
||||
}
|
||||
|
||||
# Function to restart networking service
|
||||
restart_networking() {
|
||||
if (whiptail --title "$(translate 'Restarting Network')" --yesno "$(translate 'Do you want to restart the network service?')" 10 60); then
|
||||
clear
|
||||
msg_info "$(translate 'The network service is about to restart. You may experience a brief disconnection.')"
|
||||
systemctl restart networking
|
||||
if [ $? -eq 0 ]; then
|
||||
msg_ok "$(translate 'Network service restarted successfully')"
|
||||
else
|
||||
msg_error "$(translate 'Failed to restart network service')"
|
||||
fi
|
||||
else
|
||||
msg_ok "$(translate 'Network restart canceled')"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check network connectivity
|
||||
check_network_connectivity() {
|
||||
if ping -c 4 8.8.8.8 &> /dev/null; then
|
||||
msg_ok "$(translate 'Network connectivity OK')"
|
||||
return 0
|
||||
else
|
||||
msg_error "$(translate 'Network connectivity failed')"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Update the show_ip_info function to use the new get_relevant_interfaces function
|
||||
show_ip_info() {
|
||||
whiptail --title "$(translate 'IP Information')" --infobox "$(translate 'Gathering IP information...')" 8 78
|
||||
local ip_info=""
|
||||
ip_info+="$(translate 'IP Information')\\n\\n"
|
||||
|
||||
local interfaces=$(get_relevant_interfaces)
|
||||
|
||||
for interface in $interfaces; do
|
||||
local interface_ip=$(ip -4 addr show $interface 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
|
||||
if [ -n "$interface_ip" ]; then
|
||||
ip_info+="$interface: $interface_ip\\n"
|
||||
else
|
||||
ip_info+="$interface: $(translate 'No IP assigned')\\n"
|
||||
fi
|
||||
done
|
||||
|
||||
whiptail --title "$(translate 'Result')" --msgbox "${ip_info}\\n\\n$(translate 'IP information gathering completed')\\n\\n$(translate 'Press Enter to continue')" 20 78
|
||||
}
|
||||
|
||||
|
||||
# Function to repair network
|
||||
repair_network() {
|
||||
whiptail --title "$(translate 'Network Repair Started')" --infobox "$(translate 'Repairing network...')" 8 78
|
||||
echo -ne "${TAB}${YW}-$(translate 'Repairing network...') ${CL}"
|
||||
sleep 3
|
||||
detect_physical_interfaces
|
||||
clean_nonexistent_interfaces
|
||||
check_and_fix_bridges
|
||||
configure_physical_interfaces
|
||||
restart_networking
|
||||
if check_network_connectivity; then
|
||||
show_ip_info
|
||||
msg_ok "$(translate 'Network repair completed successfully')"
|
||||
else
|
||||
msg_error "$(translate 'Network repair failed')"
|
||||
fi
|
||||
whiptail --title "$(translate 'Result')" --msgbox "$(translate 'Repair process completed')\\n\\n$(translate 'Press Enter to continue')" 10 78
|
||||
}
|
||||
|
||||
# Function to verify network configuration
|
||||
verify_network() {
|
||||
whiptail --title "$(translate 'Network Verification Started')" --infobox "$(translate 'Verifying network...')" 8 78
|
||||
echo -ne "${TAB}${YW}-$(translate 'Verifying network...') ${CL}"
|
||||
detect_physical_interfaces
|
||||
show_ip_info
|
||||
if check_network_connectivity; then
|
||||
msg_ok "$(translate 'Network verification completed successfully')"
|
||||
else
|
||||
msg_error "$(translate 'Network verification failed')"
|
||||
fi
|
||||
whiptail --title "$(translate 'Result')" --msgbox "$(translate 'Verification process completed')\\n\\n$(translate 'Press Enter to continue')" 10 78
|
||||
}
|
||||
|
||||
# Function to show main menu
|
||||
show_main_menu() {
|
||||
while true; do
|
||||
OPTION=$(whiptail --title "$(translate 'Network Repair Menu')" --menu "$(translate 'Choose an option:')" 15 60 4 \
|
||||
"1" "$(translate 'Verify Network')" \
|
||||
"2" "$(translate 'Show IP Information')" \
|
||||
"3" "$(translate "Return to Main Menu")" 3>&1 1>&2 2>&3)
|
||||
|
||||
case $OPTION in
|
||||
1)
|
||||
verify_network
|
||||
;;
|
||||
2)
|
||||
show_ip_info
|
||||
;;
|
||||
3) exec bash "$LOCAL_SCRIPTS/menus/main_menu.sh" ;;
|
||||
*) exec bash "$LOCAL_SCRIPTS/menus/main_menu.sh" ;;
|
||||
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
clear
|
||||
#show_proxmenux_logo
|
||||
show_main_menu
|
||||
@@ -1,10 +1,37 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux - Fail2Ban Installer & Configurator
|
||||
# ============================================
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# License : MIT
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# ============================================
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Installs and configures Fail2Ban to protect SSH, the Proxmox VE
|
||||
# web UI (port 8006) and the ProxMenux Monitor (port 8008 + reverse
|
||||
# proxy) against brute-force attacks. Hybrid runtime: works from
|
||||
# terminal dialogs and from the ProxMenux web panel.
|
||||
#
|
||||
# Features:
|
||||
# - Adjusts journald MaxLevelStore if Proxmox default ('warning')
|
||||
# would silently drop SSH/PAM auth events.
|
||||
# - Creates two journal-to-file logger services so Fail2Ban can use
|
||||
# the reliable file backend instead of systemd journal (avoids
|
||||
# known issues with pvedaemon worker / sshd journal reads).
|
||||
# - Three jails: [sshd] (aggressive, 2 retries / 9h ban),
|
||||
# [proxmox] (8006, 3 retries / 1h ban), [proxmenux] (8008 +
|
||||
# http/https, 3 retries / 1h ban).
|
||||
# - Auto-detects firewall backend (nftables preferred, iptables
|
||||
# fallback) and sets the matching ban actions.
|
||||
# - SSH hardening: sets MaxAuthTries=3 (Lynis SSH-7408 recommendation),
|
||||
# backing up the original value for clean restore on uninstall.
|
||||
# - Reinstall flow rewrites all jails with current defaults.
|
||||
# - Clean uninstall: removes jails, logger services, journald drop-in
|
||||
# and restores the original SSH MaxAuthTries.
|
||||
# - Component status tracked in components_status.json.
|
||||
# ==========================================================
|
||||
# Hybrid script: works from terminal (dialog) and web panel (ScriptTerminalModal)
|
||||
|
||||
SCRIPT_TITLE="Fail2Ban Installer for Proxmox VE"
|
||||
|
||||
@@ -1,10 +1,35 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux - Lynis Security Audit Tool Installer
|
||||
# ============================================
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# License : MIT
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# ============================================
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Installs Lynis (CISOfy) from the official upstream GitHub
|
||||
# repository so the host always gets the latest scanner, not the
|
||||
# older Debian-packaged version. Provides install / update / run /
|
||||
# uninstall actions through a unified menu. Hybrid runtime: works
|
||||
# from terminal dialogs and from the ProxMenux web panel.
|
||||
#
|
||||
# Features:
|
||||
# - Clones https://github.com/CISOfy/lynis.git into /opt/lynis.
|
||||
# - Wrapper script at /usr/local/bin/lynis that cd's into /opt/lynis
|
||||
# before invoking ./lynis (Lynis requires being run from its own
|
||||
# directory).
|
||||
# - Detection looks at /usr/local/bin/lynis, /opt/lynis/lynis and
|
||||
# /usr/bin/lynis (apt install path) before showing the menu.
|
||||
# - Update action: 'git pull' inside /opt/lynis. Falls back to a
|
||||
# full reinstall if .git is missing.
|
||||
# - Run-audit action: launches 'lynis audit system --no-colors'
|
||||
# directly from the menu.
|
||||
# - Clean uninstall: removes /opt/lynis and /usr/local/bin/lynis
|
||||
# (does NOT touch an apt-installed Lynis at /usr/bin/lynis).
|
||||
# - Component status tracked in components_status.json.
|
||||
# ==========================================================
|
||||
# Hybrid script: works from terminal (dialog) and web panel (ScriptTerminalModal)
|
||||
|
||||
SCRIPT_TITLE="Lynis Security Audit Tool Installer"
|
||||
@@ -59,12 +84,19 @@ install_lynis() {
|
||||
msg_title "$(translate "$SCRIPT_TITLE")"
|
||||
msg_info2 "$(translate "Installing latest Lynis security scan tool...")"
|
||||
|
||||
# Install git if needed
|
||||
# Install git if needed. Verify the install actually succeeded —
|
||||
# `apt-get install -y git >/dev/null 2>&1` followed by `msg_ok` would
|
||||
# otherwise lie about success and the next `git clone` would fail with
|
||||
# an opaque error. Audit Tier 6 — `lynis_installer.sh` apt silent.
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
msg_info "$(translate "Installing Git as a prerequisite...")"
|
||||
apt-get update -qq >/dev/null 2>&1
|
||||
apt-get install -y git >/dev/null 2>&1
|
||||
msg_ok "$(translate "Git installed")"
|
||||
if apt-get install -y git >/dev/null 2>&1 && command -v git >/dev/null 2>&1; then
|
||||
msg_ok "$(translate "Git installed")"
|
||||
else
|
||||
msg_error "$(translate "Could not install Git — Lynis cannot be cloned. Run 'apt-get install git' manually.")"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove old installation if present
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ProxMenux - Storage & Share CLI Reference
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.6
|
||||
# Last Updated: 07/04/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Reference of the manual CLI commands behind the Storage &
|
||||
# Share Manager flows (NFS / Samba / iSCSI client and server,
|
||||
# bind mounts, Proxmox storage registration). Used as the
|
||||
# Help & Info entry of the Storage & Share menu.
|
||||
# ==========================================================
|
||||
|
||||
# Configuration ============================================
|
||||
|
||||
@@ -4,12 +4,24 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Adds local SCSI/SATA/NVMe disks as Proxmox directory storage
|
||||
# (pvesm add dir) or ZFS pool storage (pvesm add zfspool).
|
||||
# The disk can be formatted (ext4/xfs/zfs) and registered in Proxmox.
|
||||
# Prepares a local SCSI / SATA / NVMe disk on the Proxmox host
|
||||
# and registers it as Proxmox storage — either as a directory
|
||||
# (pvesm add dir) or as a ZFS pool (pvesm add zfspool).
|
||||
#
|
||||
# Features:
|
||||
# - Safety filter hides root / swap / mounted / in-use disks
|
||||
# and disks already referenced by any VM/CT config.
|
||||
# - Format path: wipe + GPT + mkfs (ext4 / xfs / btrfs / zfs).
|
||||
# - Reuse path: mount an existing filesystem without touching
|
||||
# the data.
|
||||
# - UUID-based /etc/fstab entries with defaults,nofail.
|
||||
# - Content-type presets (VM Storage / Standard NAS / All / Custom).
|
||||
# - View, remove (with fstab cleanup) and list-disks helpers.
|
||||
# ==========================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
@@ -1,271 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# ==========================================================
|
||||
# ProxMenux - Shared Groups Manager
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Description : Manage host groups for shared directories
|
||||
# ==========================================================
|
||||
|
||||
# Configuration
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
|
||||
pmx_list_groups() {
|
||||
local groups
|
||||
groups=$(getent group | awk -F: '$3 >= 1000 && $1 != "nogroup" && $1 !~ /^pve/ {print $1 ":" $3}')
|
||||
if [[ -z "$groups" ]]; then
|
||||
whiptail --title "$(translate "Groups")" --msgbox "$(translate "No user groups found.")" 8 60
|
||||
return
|
||||
fi
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Existing Groups")"
|
||||
echo "$groups" | column -t -s: | while read -r name gid; do
|
||||
members=$(getent group "$name" | awk -F: '{print $4}')
|
||||
echo -e " • ${BL}$name${CL} (GID: $gid) -> ${YW}${members:-no members}${CL}"
|
||||
done
|
||||
echo ""
|
||||
msg_success "$(translate "Press Enter to continue...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
pmx_create_group() {
|
||||
group_name=$(dialog --inputbox "$(translate "Enter new group name:")" 10 60 "sharedfiles-new" \
|
||||
--title "$(translate "New Group")" 3>&1 1>&2 2>&3) || return
|
||||
[[ -z "$group_name" ]] && return
|
||||
|
||||
if getent group "$group_name" >/dev/null; then
|
||||
dialog --title "$(translate "Error")" --msgbox "$(translate "Group already exists.")" 8 50
|
||||
return
|
||||
fi
|
||||
|
||||
if groupadd "$group_name"; then
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Create Group")"
|
||||
msg_ok "$(translate "Group created successfully:") $group_name"
|
||||
else
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Create Group")"
|
||||
msg_error "$(translate "Failed to create group.")"
|
||||
fi
|
||||
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to continue...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
pmx_edit_group() {
|
||||
local groups group_name action
|
||||
|
||||
|
||||
groups=$(getent group | awk -F: '$3 >= 1000 && $1 != "nogroup" && $1 !~ /^pve/ {print $1}')
|
||||
|
||||
if [[ -z "$groups" ]]; then
|
||||
dialog --title "$(translate "Error")" --msgbox "$(translate "No groups available to edit.")" 8 50
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
local menu_options=""
|
||||
while read -r group; do
|
||||
if [[ -n "$group" ]]; then
|
||||
local gid=$(getent group "$group" | cut -d: -f3)
|
||||
menu_options="$menu_options $group \"GID:$gid\""
|
||||
fi
|
||||
done <<< "$groups"
|
||||
|
||||
|
||||
group_name=$(eval "dialog --title \"$(translate "Edit Group")\" --menu \
|
||||
\"$(translate "Select a group:")\" 20 60 10 \
|
||||
$menu_options 3>&1 1>&2 2>&3")
|
||||
|
||||
if [[ -z "$group_name" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
action=$(dialog --title "$(translate "Edit Group")" --menu \
|
||||
"$(translate "What do you want to edit in group:") $group_name" 15 60 3 \
|
||||
"rename" "$(translate "Rename group")" \
|
||||
"gid" "$(translate "Change GID")" \
|
||||
"users" "$(translate "Add/Remove users")" 3>&1 1>&2 2>&3)
|
||||
|
||||
if [[ -z "$action" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
case "$action" in
|
||||
rename)
|
||||
new_name=$(dialog --inputbox "$(translate "Enter new group name:")" 10 60 \
|
||||
"$group_name" --title "$(translate "Rename Group")" 3>&1 1>&2 2>&3)
|
||||
if [[ -n "$new_name" && "$new_name" != "$group_name" ]]; then
|
||||
if groupmod -n "$new_name" "$group_name" 2>/dev/null; then
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Rename Group")"
|
||||
msg_ok "$(translate "Group renamed to:") $new_name"
|
||||
else
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Rename Group")"
|
||||
msg_error "$(translate "Failed to rename group")"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
gid)
|
||||
current_gid=$(getent group "$group_name" | cut -d: -f3)
|
||||
new_gid=$(dialog --inputbox "$(translate "Enter new GID:")" 10 60 \
|
||||
"$current_gid" --title "$(translate "Change GID")" 3>&1 1>&2 2>&3)
|
||||
if [[ -n "$new_gid" && "$new_gid" != "$current_gid" ]]; then
|
||||
if groupmod -g "$new_gid" "$group_name" 2>/dev/null; then
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Change GID")"
|
||||
msg_ok "$(translate "GID changed to:") $new_gid"
|
||||
else
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Change GID")"
|
||||
msg_error "$(translate "Failed to change GID")"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
users)
|
||||
user_action=$(dialog --title "$(translate "User Management")" --menu \
|
||||
"$(translate "Choose an action for group:") $group_name" 15 60 2 \
|
||||
"add" "$(translate "Add user to group")" \
|
||||
"remove" "$(translate "Remove user from group")" 3>&1 1>&2 2>&3)
|
||||
|
||||
case "$user_action" in
|
||||
add)
|
||||
username=$(dialog --inputbox "$(translate "Enter username to add:")" 10 60 \
|
||||
--title "$(translate "Add User")" 3>&1 1>&2 2>&3)
|
||||
if [[ -n "$username" ]]; then
|
||||
if id "$username" >/dev/null 2>&1; then
|
||||
if usermod -aG "$group_name" "$username" 2>/dev/null; then
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Add User")"
|
||||
msg_ok "$(translate "User added:") $username"
|
||||
else
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Add User")"
|
||||
msg_error "$(translate "Failed to add user")"
|
||||
fi
|
||||
else
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Add User")"
|
||||
msg_error "$(translate "User does not exist:") $username"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
remove)
|
||||
members=$(getent group "$group_name" | awk -F: '{print $4}' | tr ',' ' ')
|
||||
if [[ -z "$members" ]]; then
|
||||
dialog --title "$(translate "Info")" --msgbox "$(translate "No users in this group.")" 8 50
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
local user_options=""
|
||||
for user in $members; do
|
||||
user_options="$user_options $user \"\""
|
||||
done
|
||||
|
||||
username=$(eval "dialog --title \"$(translate "Remove User")\" --menu \
|
||||
\"$(translate "Select user to remove:")\" 15 60 5 \
|
||||
$user_options 3>&1 1>&2 2>&3")
|
||||
|
||||
if [[ -n "$username" ]]; then
|
||||
if gpasswd -d "$username" "$group_name" 2>/dev/null; then
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Remove User")"
|
||||
msg_ok "$(translate "User removed:") $username"
|
||||
else
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Remove User")"
|
||||
msg_error "$(translate "Failed to remove user")"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to continue...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
pmx_delete_group() {
|
||||
local groups group_name menu_options
|
||||
groups=$(getent group | awk -F: '$3 >= 1000 && $1 != "nogroup" && $1 !~ /^pve/ {print $1}')
|
||||
|
||||
if [[ -z "$groups" ]]; then
|
||||
dialog --title "$(translate "Error")" --msgbox "$(translate "No groups available to delete.")" 8 50
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
menu_options=""
|
||||
while read -r group; do
|
||||
if [[ -n "$group" ]]; then
|
||||
menu_options="$menu_options $group \"\""
|
||||
fi
|
||||
done <<< "$groups"
|
||||
|
||||
group_name=$(eval "dialog --title \"$(translate "Delete Group")\" --menu \
|
||||
\"$(translate "Select a group to delete:")\" 20 60 10 \
|
||||
$menu_options 3>&1 1>&2 2>&3") || return
|
||||
|
||||
if dialog --yesno "$(translate "Are you sure you want to delete group:") $group_name ?" 10 60; then
|
||||
if groupdel "$group_name" 2>/dev/null; then
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Deleting Groups")"
|
||||
msg_ok "$(translate "Group deleted:") $group_name"
|
||||
else
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Deleting Groups")"
|
||||
msg_ok "$(translate "Group deleted:") $group_name"
|
||||
msg_error "$(translate "Failed to delete group")"
|
||||
fi
|
||||
fi
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to continue...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
pmx_manage_groups() {
|
||||
while true; do
|
||||
CHOICE=$(dialog --title "$(translate "Shared Groups Manager")" \
|
||||
--menu "$(translate "Select an option:")" 20 70 10 \
|
||||
"list" "$(translate "View existing groups")" \
|
||||
"create" "$(translate "Create new group")" \
|
||||
"edit" "$(translate "Edit existing group")" \
|
||||
"delete" "$(translate "Delete a group")" \
|
||||
"exit" "$(translate "Exit")" \
|
||||
3>&1 1>&2 2>&3) || return 0
|
||||
|
||||
case "$CHOICE" in
|
||||
list) pmx_list_groups ;;
|
||||
create) pmx_create_group ;;
|
||||
edit) pmx_edit_group ;;
|
||||
delete) pmx_delete_group ;;
|
||||
exit) return 0 ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
pmx_manage_groups
|
||||
@@ -4,12 +4,22 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Adds iSCSI targets as Proxmox storage (pvesm add iscsi).
|
||||
# Proxmox manages the connection natively via open-iscsi.
|
||||
# iSCSI storage provides block devices for VM disk images.
|
||||
# Registers iSCSI targets as Proxmox storage via
|
||||
# pvesm add iscsi. Proxmox manages the session natively via
|
||||
# open-iscsi; LUNs appear as raw block devices for VM disks.
|
||||
#
|
||||
# Features:
|
||||
# - Auto-installs open-iscsi + enables iscsid service.
|
||||
# - sendtargets discovery against a portal (IP:port).
|
||||
# - Auto-selects a single target; menu when several.
|
||||
# - Storage ID derived from the IQN suffix.
|
||||
# - Content type fixed to 'images' (block storage only).
|
||||
# - View, remove and connectivity-test for existing storages.
|
||||
# ==========================================================
|
||||
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
|
||||
@@ -4,9 +4,24 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 08/04/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Creates a host directory pre-configured for LXC bind mounts.
|
||||
# Applies a permission profile (1777 + ACLs) that works for
|
||||
# both privileged and unprivileged containers without UID/GID
|
||||
# alignment.
|
||||
#
|
||||
# Features:
|
||||
# - Auto-suggests a free name in /mnt (shared, shared2, …).
|
||||
# - Accepts custom absolute paths outside /mnt.
|
||||
# - chown root:root + chmod 1777 (sticky + world-rwx).
|
||||
# - setfacl with default-inheritance ACLs so new files keep
|
||||
# the permissive profile.
|
||||
# - Registers the directory in the ProxMenux share map for
|
||||
# later use by the LXC Mount Manager.
|
||||
# ==========================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
@@ -4,15 +4,27 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Adds bind mounts from Proxmox host directories into LXC
|
||||
# containers using pct set -mpX (Proxmox native).
|
||||
# Bind-mounts a host directory into an LXC container using
|
||||
# Proxmox's native pct set -mpN syntax. Handles the permission
|
||||
# quirks of unprivileged containers on the host side — never
|
||||
# modifies anything inside the container.
|
||||
#
|
||||
# SAFE DESIGN: This script NEVER modifies permissions, ownership,
|
||||
# or ACLs on the host or inside the container. All existing
|
||||
# configurations are preserved as-is.
|
||||
# Features:
|
||||
# - Unified host-directory picker (mounted CIFS/NFS shares,
|
||||
# fstab-inactive entries, /mnt/* local dirs, /mnt/pve/*
|
||||
# Proxmox storages, manual entry).
|
||||
# - Active fix per source type:
|
||||
# - CIFS → offer remount with uid=0,gid=0,file_mode=0777
|
||||
# - NFS → offer chmod 1777 + setfacl on the share
|
||||
# - Local → offer chmod o+rwx + ACL (unprivileged only)
|
||||
# - Auto-detects privileged vs unprivileged containers.
|
||||
# - View / remove existing mp* entries.
|
||||
# - Optional CT restart at end with mount-point smoke test.
|
||||
# ==========================================================
|
||||
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux CT - NFS Client Manager for Proxmox LXC
|
||||
# ProxMenux - NFS Client Manager for LXC
|
||||
# ==========================================================
|
||||
# Based on ProxMenux by MacRimi
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows you to manage NFS client mounts inside Proxmox CTs:
|
||||
# - Mount NFS shares (temporary and permanent)
|
||||
# - View current mounts
|
||||
# - Unmount and remove NFS shares
|
||||
# - Auto-discover NFS servers
|
||||
# Manages NFS client mounts from inside a Proxmox LXC container.
|
||||
# Requires a privileged container (kernel NFS client needs
|
||||
# capabilities that unprivileged CTs do not expose).
|
||||
#
|
||||
# Features:
|
||||
# - Mount NFS shares (temporary and permanent via /etc/fstab).
|
||||
# - List current NFS mounts inside the CT.
|
||||
# - Unmount and remove NFS shares cleanly.
|
||||
# - Auto-discover NFS servers on the local network.
|
||||
# ==========================================================
|
||||
|
||||
# Configuration
|
||||
@@ -45,6 +53,17 @@ install_nfs_client() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Installing NFS Client in LXC")"
|
||||
|
||||
# Pre-flight: refuse non-Debian-family CTs. The script targets
|
||||
# `apt-get` only — Alpine / Rocky / AlmaLinux fail with cryptic
|
||||
# errors mid-flow. Audit Tier 6 — `nfs_client.sh`/`samba_client.sh`
|
||||
# asume distro Debian-family sin detección.
|
||||
if ! pct exec "$CTID" -- bash -c 'command -v apt-get' &>/dev/null; then
|
||||
msg_error "$(translate "This container does not have apt-get. NFS client installation only supports Debian/Ubuntu containers.")"
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
|
||||
msg_info "$(translate "Installing NFS client packages...")"
|
||||
if ! pct exec "$CTID" -- apt-get update >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Failed to update package list.")"
|
||||
@@ -551,9 +570,23 @@ unmount_nfs_share() {
|
||||
# Remove from fstab
|
||||
pct exec "$CTID" -- sed -i "\|[[:space:]]$SELECTED_MOUNT[[:space:]]|d" /etc/fstab
|
||||
msg_ok "$(translate "Removed from /etc/fstab.")"
|
||||
|
||||
|
||||
# Actually unmount it now (the previous version only edited fstab,
|
||||
# so the share remained mounted until the CT rebooted). Try a
|
||||
# graceful umount first, fall back to lazy umount if busy. Audit
|
||||
# Tier 7 — `unmount_nfs_share` only borra fstab.
|
||||
if pct exec "$CTID" -- mountpoint -q "$SELECTED_MOUNT" 2>/dev/null; then
|
||||
if pct exec "$CTID" -- umount "$SELECTED_MOUNT" 2>/dev/null; then
|
||||
msg_ok "$(translate "Unmounted") $SELECTED_MOUNT"
|
||||
elif pct exec "$CTID" -- umount -l "$SELECTED_MOUNT" 2>/dev/null; then
|
||||
msg_warn "$(translate "Mount was busy — performed lazy unmount") $SELECTED_MOUNT"
|
||||
else
|
||||
msg_warn "$(translate "Could not unmount") $SELECTED_MOUNT $(translate "automatically. Reboot LXC to fully release.")"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e ""
|
||||
msg_ok "$(translate "NFS share unmount successfully. Reboot LXC required to take effect.")"
|
||||
msg_ok "$(translate "NFS share unmount completed.")"
|
||||
fi
|
||||
|
||||
echo -e ""
|
||||
|
||||
@@ -4,11 +4,21 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Adds external NFS shares as Proxmox storage (pvesm).
|
||||
# Proxmox manages the mount natively — no fstab entries needed.
|
||||
# Registers external NFS exports as Proxmox storage via
|
||||
# pvesm add nfs. Proxmox manages the mount natively — no
|
||||
# fstab entries needed on the host.
|
||||
#
|
||||
# Features:
|
||||
# - Auto-discover NFS servers on the local subnet (nmap).
|
||||
# - Reachability validation chain (ping + nc + showmount).
|
||||
# - Content-type checklist (import/backup/iso/vztmpl/images/
|
||||
# rootdir/snippets).
|
||||
# - View, remove and connectivity-test for existing storages.
|
||||
# ==========================================================
|
||||
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux CT - NFS Manager for Proxmox LXC (Simple + Universal)
|
||||
# ProxMenux - NFS Server Manager for LXC
|
||||
# ==========================================================
|
||||
# Based on ProxMenux by MacRimi
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows you to manage NFS shares inside Proxmox CTs:
|
||||
# - Create NFS exports with universal sharedfiles group
|
||||
# - View configured exports
|
||||
# - Delete existing exports
|
||||
# - Check NFS service status
|
||||
# Manages NFS exports from inside a Proxmox LXC container.
|
||||
# Requires a privileged container (the kernel NFS server module
|
||||
# needs capabilities that unprivileged CTs do not expose).
|
||||
#
|
||||
# Features:
|
||||
# - Install and configure nfs-kernel-server inside the CT.
|
||||
# - Create NFS exports for folders under /mnt.
|
||||
# - Set up a universal "sharedfiles" group (GID 101000) on the
|
||||
# CT as a convention for cross-CT file sharing.
|
||||
# - List configured exports and check service status.
|
||||
# - Remove exports cleanly.
|
||||
# ==========================================================
|
||||
|
||||
# Configuration
|
||||
@@ -70,42 +80,55 @@ setup_universal_sharedfiles_group() {
|
||||
fi
|
||||
|
||||
|
||||
msg_info "$(translate "Creating UID remapping for unprivileged container compatibility...")"
|
||||
local remapped_count=0
|
||||
|
||||
if [[ -n "$lxc_users" ]]; then
|
||||
while IFS=: read -r username uid; do
|
||||
if [[ -n "$uid" ]]; then
|
||||
local remapped_uid=$((uid + 100000))
|
||||
local remapped_username="remap_${uid}"
|
||||
|
||||
|
||||
if ! pct exec "$ctid" -- id "$remapped_username" >/dev/null 2>&1; then
|
||||
pct exec "$ctid" -- useradd -u "$remapped_uid" -g sharedfiles -s /bin/false -M "$remapped_username" 2>/dev/null || true
|
||||
msg_ok "$(translate "Created remapped user") $remapped_username (UID: $remapped_uid)"
|
||||
((remapped_count++))
|
||||
else
|
||||
|
||||
pct exec "$ctid" -- usermod -g sharedfiles "$remapped_username" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
done <<< "$lxc_users"
|
||||
# `+ 100000` UID-shift only makes sense in unprivileged containers
|
||||
# (UID 0 in CT == UID 100000 on host). `select_privileged_lxc` already
|
||||
# gated the flow to privileged CTs above, so the shift is meaningless
|
||||
# here and creates phantom `remap_NNNN` accounts that don't map to
|
||||
# any real UID. Skip the loop in privileged context. Audit Tier 6 —
|
||||
# UID-shift remapping en CTs privilegiados donde no aplica.
|
||||
local _is_unpriv=0
|
||||
if pct config "$ctid" 2>/dev/null | grep -qE '^unprivileged:\s*1'; then
|
||||
_is_unpriv=1
|
||||
fi
|
||||
|
||||
local remapped_count=0
|
||||
|
||||
local common_uids=(33 1000 1001 1002)
|
||||
for base_uid in "${common_uids[@]}"; do
|
||||
local remapped_uid=$((base_uid + 100000))
|
||||
local remapped_username="remap_${base_uid}"
|
||||
|
||||
if ! pct exec "$ctid" -- id "$remapped_username" >/dev/null 2>&1; then
|
||||
pct exec "$ctid" -- useradd -u "$remapped_uid" -g sharedfiles -s /bin/false -M "$remapped_username" 2>/dev/null || true
|
||||
msg_ok "$(translate "Created common remapped user") $remapped_username (UID: $remapped_uid)"
|
||||
((remapped_count++))
|
||||
if (( _is_unpriv == 1 )); then
|
||||
msg_info "$(translate "Creating UID remapping for unprivileged container compatibility...")"
|
||||
|
||||
if [[ -n "$lxc_users" ]]; then
|
||||
while IFS=: read -r username uid; do
|
||||
if [[ -n "$uid" ]]; then
|
||||
local remapped_uid=$((uid + 100000))
|
||||
local remapped_username="remap_${uid}"
|
||||
|
||||
if ! pct exec "$ctid" -- id "$remapped_username" >/dev/null 2>&1; then
|
||||
pct exec "$ctid" -- useradd -u "$remapped_uid" -g sharedfiles -s /bin/false -M "$remapped_username" 2>/dev/null || true
|
||||
msg_ok "$(translate "Created remapped user") $remapped_username (UID: $remapped_uid)"
|
||||
((remapped_count++))
|
||||
else
|
||||
pct exec "$ctid" -- usermod -g sharedfiles "$remapped_username" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
done <<< "$lxc_users"
|
||||
fi
|
||||
done
|
||||
|
||||
msg_ok "$(translate "Universal sharedfiles group configured with") $remapped_count $(translate "remapped users")"
|
||||
|
||||
|
||||
local common_uids=(33 1000 1001 1002)
|
||||
for base_uid in "${common_uids[@]}"; do
|
||||
local remapped_uid=$((base_uid + 100000))
|
||||
local remapped_username="remap_${base_uid}"
|
||||
|
||||
if ! pct exec "$ctid" -- id "$remapped_username" >/dev/null 2>&1; then
|
||||
pct exec "$ctid" -- useradd -u "$remapped_uid" -g sharedfiles -s /bin/false -M "$remapped_username" 2>/dev/null || true
|
||||
msg_ok "$(translate "Created common remapped user") $remapped_username (UID: $remapped_uid)"
|
||||
((remapped_count++))
|
||||
fi
|
||||
done
|
||||
|
||||
msg_ok "$(translate "Universal sharedfiles group configured with") $remapped_count $(translate "remapped users")"
|
||||
else
|
||||
msg_ok "$(translate "Privileged container — UID-shift remapping skipped (not applicable)")"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux CT - Samba Client Manager for Proxmox LXC
|
||||
# ProxMenux - Samba / CIFS Client Manager for LXC
|
||||
# ==========================================================
|
||||
# Based on ProxMenux by MacRimi
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows you to manage Samba/CIFS client mounts inside Proxmox CTs:
|
||||
# - Mount Samba/CIFS shares (temporary and permanent)
|
||||
# - View current mounts
|
||||
# - Unmount and remove Samba shares
|
||||
# - Auto-discover Samba servers
|
||||
# - Manage credentials securely
|
||||
# Manages Samba / CIFS client mounts from inside a Proxmox LXC
|
||||
# container. Requires a privileged container (mount.cifs needs
|
||||
# capabilities that unprivileged CTs do not expose).
|
||||
#
|
||||
# Features:
|
||||
# - Mount CIFS shares (temporary and permanent via /etc/fstab).
|
||||
# - List current CIFS mounts inside the CT.
|
||||
# - Unmount and remove shares cleanly.
|
||||
# - Auto-discover Samba servers on the local network.
|
||||
# - Credentials stored in /etc/samba/credentials (root:0600).
|
||||
# ==========================================================
|
||||
|
||||
|
||||
@@ -52,6 +60,12 @@ install_samba_client() {
|
||||
msg_title "$(translate "Installing Samba Client")"
|
||||
msg_info "$(translate "Installing Samba/CIFS client packages...")"
|
||||
|
||||
# Mirror of nfs_client.sh: refuse non-Debian-family CTs early.
|
||||
if ! pct exec "$CTID" -- bash -c 'command -v apt-get' &>/dev/null; then
|
||||
msg_error "$(translate "This container does not have apt-get. Samba client installation only supports Debian/Ubuntu containers.")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! pct exec "$CTID" -- apt-get update &>/dev/null; then
|
||||
msg_error "$(translate "Failed to update package list.")"
|
||||
return 1
|
||||
|
||||
@@ -4,11 +4,23 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Adds external Samba/CIFS shares as Proxmox storage (pvesm).
|
||||
# Proxmox manages the mount natively — no fstab entries needed.
|
||||
# Registers external Samba (SMB / CIFS) shares as Proxmox
|
||||
# storage via pvesm add cifs. Credentials are stored encrypted
|
||||
# in /etc/pve/priv/storage/<id>.pw — no fstab entries needed.
|
||||
#
|
||||
# Features:
|
||||
# - Auto-discover Samba servers on the local subnet
|
||||
# (nmap on ports 139/445 + nmblookup for NetBIOS names).
|
||||
# - Guest or username/password authentication.
|
||||
# - Share listing via smbclient -L (filtered to Disk shares).
|
||||
# - Content-type checklist (no rootdir — Proxmox does not
|
||||
# support LXC rootfs on CIFS).
|
||||
# - View, remove and connectivity-test for existing storages.
|
||||
# ==========================================================
|
||||
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux CT - Samba Manager for Proxmox LXC
|
||||
# ProxMenux - Samba Server Manager for LXC
|
||||
# ==========================================================
|
||||
# Based on ProxMenux by MacRimi
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows you to manage Samba shares inside Proxmox CTs:
|
||||
# - Create shared folders
|
||||
# - View configured shares
|
||||
# - Delete existing shares
|
||||
# - Check Samba service status
|
||||
# Manages Samba (SMB / CIFS) shares from inside a Proxmox LXC
|
||||
# container. Requires a privileged container.
|
||||
#
|
||||
# Features:
|
||||
# - Install and configure samba inside the CT.
|
||||
# - Expose folders under /mnt as Samba shares.
|
||||
# - Set up a universal "sharedfiles" group (GID 101000) on the
|
||||
# CT as a convention for cross-CT file sharing.
|
||||
# - List configured shares and check service status.
|
||||
# - Remove shares cleanly.
|
||||
# ==========================================================
|
||||
|
||||
# Configuration
|
||||
@@ -146,7 +155,11 @@ create_share() {
|
||||
if ! pct exec "$CTID" -- id "$USERNAME" &>/dev/null; then
|
||||
pct exec "$CTID" -- adduser --disabled-password --gecos "" "$USERNAME"
|
||||
fi
|
||||
pct exec "$CTID" -- bash -c "echo -e '$PASSWORD\n$PASSWORD' | smbpasswd -a '$USERNAME'"
|
||||
# Pipe the password via stdin instead of interpolating into a `bash -c`
|
||||
# shell string. The previous form broke (and was injectable) when the
|
||||
# password contained a single quote. `-s` makes smbpasswd read silently
|
||||
# from stdin and `printf` keeps the bytes literal — no shell expansion.
|
||||
printf '%s\n%s\n' "$PASSWORD" "$PASSWORD" | pct exec "$CTID" -- smbpasswd -s -a "$USERNAME"
|
||||
|
||||
msg_ok "$(translate "Samba server installed successfully.")"
|
||||
else
|
||||
@@ -160,7 +173,12 @@ create_share() {
|
||||
if [[ -n "$IS_MOUNTED" ]]; then
|
||||
msg_info "$(translate "Detected a mounted directory from host. Setting up shared group...")"
|
||||
|
||||
SHARE_GID=999
|
||||
# Match the GID `nfs_lxc_server.sh` uses (101000) so the same
|
||||
# `sharedfiles` group bridges Samba- and NFS-served paths. The
|
||||
# previous `999` was inconsistent — files written via Samba were
|
||||
# owned by GID 999 and not visible to NFS clients accessing the
|
||||
# same dataset. Audit Tier 6 — GID inconsistente.
|
||||
SHARE_GID=101000
|
||||
GROUP_EXISTS=$(pct exec "$CTID" -- getent group sharedfiles || true)
|
||||
GID_IN_USE=$(pct exec "$CTID" -- getent group "$SHARE_GID" | cut -d: -f1 || true)
|
||||
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ProxMenux - Import Disk to VM (Passthrough)
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.2
|
||||
# Last Updated: 12/04/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows users to assign physical disks to existing
|
||||
# Proxmox virtual machines (VMs) through an interactive menu.
|
||||
# - Detects the system disk and excludes it from selection.
|
||||
# - Lists all available VMs for the user to choose from.
|
||||
# - Identifies and displays unassigned physical disks.
|
||||
# - Allows the user to select multiple disks and attach them to a VM.
|
||||
# - Supports interface types: SATA, SCSI, VirtIO, and IDE.
|
||||
# - Ensures that disks are not already assigned to active VMs.
|
||||
# - Warns about disk sharing between multiple VMs to avoid data corruption.
|
||||
# - Configures the selected disks for the VM and verifies the assignment.
|
||||
# - Prefers persistent /dev/disk/by-id paths for assignment when available.
|
||||
# Assigns physical disks to existing Proxmox VMs via an
|
||||
# interactive menu. Uses persistent /dev/disk/by-id paths
|
||||
# whenever available and blocks system / already-assigned disks.
|
||||
#
|
||||
# The goal of this script is to simplify the process of assigning
|
||||
# physical disks to Proxmox VMs, reducing manual configurations
|
||||
# and preventing potential errors.
|
||||
# Features:
|
||||
# - Detects and excludes the system disk.
|
||||
# - Lists all VMs for selection.
|
||||
# - Identifies unassigned physical disks.
|
||||
# - Supports SATA, SCSI, VirtIO and IDE interfaces.
|
||||
# - Warns about disk sharing between VMs to avoid corruption.
|
||||
# - Verifies the assignment after attaching.
|
||||
# ==========================================================
|
||||
|
||||
|
||||
@@ -426,7 +422,11 @@ for i in "${!DISK_LIST[@]}"; do
|
||||
IFS=$'\t' read -r _model _size <<< "${DISK_DESCRIPTIONS[$i]}"
|
||||
|
||||
INDEX=0
|
||||
while qm config "$VMID" | grep -q "${INTERFACE}${INDEX}"; do
|
||||
# Anchor the match: `^scsi1:` vs `^scsi1\d:`. The previous `grep -q
|
||||
# "scsi1"` matched scsi10/scsi11/... and skipped over a genuinely-free
|
||||
# scsi1 slot — the disk still got attached but a hole was left mid-
|
||||
# range. Audit Tier 6 — `disk-passthrough.sh` slot search no anchored.
|
||||
while qm config "$VMID" | grep -Eq "^${INTERFACE}${INDEX}:"; do
|
||||
((INDEX++))
|
||||
done
|
||||
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ProxMenux - Import Disk to LXC (Passthrough)
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.3
|
||||
# Last Updated: 07/04/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows users to assign physical disks to existing
|
||||
# Proxmox containers (CTs) through an interactive menu.
|
||||
# - Detects the system disk and excludes it from selection.
|
||||
# - Lists all available CTs for the user to choose from.
|
||||
# - Identifies and displays unassigned physical disks.
|
||||
# - Allows the user to select multiple disks and attach them to a CT.
|
||||
# - Configures the selected disks for the CT and verifies the assignment.
|
||||
# - Uses persistent device paths to avoid issues with device order changes.
|
||||
# Assigns physical disks to existing Proxmox LXC containers
|
||||
# via an interactive menu, using persistent device paths to
|
||||
# avoid issues with device order changes.
|
||||
#
|
||||
# Features:
|
||||
# - Detects and excludes the system disk.
|
||||
# - Lists all containers for selection.
|
||||
# - Identifies unassigned physical disks.
|
||||
# - Configures the selected disks for the CT and verifies
|
||||
# the assignment.
|
||||
# ==========================================================
|
||||
|
||||
# Configuration ============================================
|
||||
|
||||
@@ -714,14 +714,33 @@ main() {
|
||||
|
||||
if [[ "$OPERATION_MODE" == "clean_sigs" ]]; then
|
||||
msg_info "$(translate "Removing filesystem signatures...")"
|
||||
wipefs -af "$SELECTED_DISK" >/dev/null 2>&1 || true
|
||||
# `|| true` swallowed real failures (busy device, ENOSPC writing
|
||||
# the magic bytes) and the user got a green "Signatures removed"
|
||||
# even when nothing was actually wiped. Capture the failure and
|
||||
# continue but report it. Audit Tier 6 — `format-disk.sh` wipefs
|
||||
# `|| true` silencia fallos.
|
||||
local _wipefs_errs=0
|
||||
local _wipefs_err_out
|
||||
if ! _wipefs_err_out=$(wipefs -af "$SELECTED_DISK" 2>&1); then
|
||||
_wipefs_errs=$((_wipefs_errs + 1))
|
||||
msg_warn "$(translate "wipefs failed on") $SELECTED_DISK: $_wipefs_err_out"
|
||||
fi
|
||||
local pname
|
||||
while read -r pname; do
|
||||
[[ -z "$pname" ]] && continue
|
||||
[[ "/dev/$pname" == "$SELECTED_DISK" ]] && continue
|
||||
[[ -b "/dev/$pname" ]] && wipefs -af "/dev/$pname" >/dev/null 2>&1 || true
|
||||
if [[ -b "/dev/$pname" ]]; then
|
||||
if ! _wipefs_err_out=$(wipefs -af "/dev/$pname" 2>&1); then
|
||||
_wipefs_errs=$((_wipefs_errs + 1))
|
||||
msg_warn "$(translate "wipefs failed on") /dev/$pname: $_wipefs_err_out"
|
||||
fi
|
||||
fi
|
||||
done < <(lsblk -ln -o NAME "$SELECTED_DISK" 2>/dev/null | tail -n +2)
|
||||
msg_ok "$(translate "Signatures removed. Partition table preserved.")"
|
||||
if (( _wipefs_errs == 0 )); then
|
||||
msg_ok "$(translate "Signatures removed. Partition table preserved.")"
|
||||
else
|
||||
msg_warn "$(translate "Some signatures could not be removed (see warnings above).")"
|
||||
fi
|
||||
echo
|
||||
msg_success "$(translate "Disk is ready for VM passthrough.")"
|
||||
echo
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ProxMenux - Import Disk Image to VM
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.3
|
||||
# Last Updated: 12/04/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Imports disk images (.img, .qcow2, .vmdk, .raw) into Proxmox VE VMs.
|
||||
# Supports the default system ISO directory and custom paths.
|
||||
# All user decisions are collected in Phase 1 (dialogs) before
|
||||
# any operation is executed in Phase 2 (terminal output).
|
||||
# Imports disk images (.img, .qcow2, .vmdk, .raw) into
|
||||
# existing Proxmox VE VMs. Supports the default ISO directory
|
||||
# and custom paths; all user decisions are collected up-front
|
||||
# (Phase 1 dialogs) before any operation runs (Phase 2).
|
||||
# ==========================================================
|
||||
|
||||
# Configuration ============================================
|
||||
@@ -163,7 +163,13 @@ while IFS= read -r img; do
|
||||
IMAGE_OPTIONS+=("$img" "" "OFF")
|
||||
done <<< "$IMAGES"
|
||||
|
||||
# `--separate-output` prints each selected tag on its own line with no
|
||||
# quoting, so we never need `eval` to split the output. The previous form
|
||||
# `eval "declare -a A=($SELECTED)"` would execute backticks / $(...) baked
|
||||
# into a filename — perfectly legal on ext4 — as shell commands. Audit
|
||||
# Tier 6 — `import-disk-image.sh` `eval` sobre salida del dialog.
|
||||
SELECTED_IMAGES_STR=$(dialog --backtitle "$BACKTITLE" \
|
||||
--separate-output \
|
||||
--title "$(translate 'Select Disk Images')" \
|
||||
--checklist "$(translate 'Select one or more disk images to import:')" \
|
||||
$UI_MENU_H $UI_MENU_W $UI_MENU_LIST_H \
|
||||
@@ -171,7 +177,10 @@ SELECTED_IMAGES_STR=$(dialog --backtitle "$BACKTITLE" \
|
||||
2>&1 >/dev/tty)
|
||||
[[ -z "$SELECTED_IMAGES_STR" ]] && exit 0
|
||||
|
||||
eval "declare -a SELECTED_ARRAY=($SELECTED_IMAGES_STR)"
|
||||
declare -a SELECTED_ARRAY=()
|
||||
while IFS= read -r _img; do
|
||||
[[ -n "$_img" ]] && SELECTED_ARRAY+=("$_img")
|
||||
done <<< "$SELECTED_IMAGES_STR"
|
||||
|
||||
|
||||
# ── Step 5: Per-image options ─────────────────────────────
|
||||
|
||||
@@ -416,8 +416,10 @@ while true; do
|
||||
|
||||
# ── Auto-export JSON (except long — handled by background monitor)
|
||||
if [[ "$ACTION" != "long" && "$ACTION" != "report" ]]; then
|
||||
# Determine test type from ACTION (short test or status check)
|
||||
local json_test_type="short"
|
||||
# Determine test type from ACTION (short test or status check).
|
||||
# NOTE: no 'local' here — this block runs inside the top-level while loop,
|
||||
# not inside a function, so 'local' would print a bash warning at runtime.
|
||||
json_test_type="short"
|
||||
[[ "$ACTION" == "status" ]] && json_test_type="status"
|
||||
|
||||
JSON_PATH=$(_smart_json_path "$SELECTED_DISK" "$json_test_type")
|
||||
|
||||
@@ -4,9 +4,33 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 07/04/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Exports a Proxmox VM to OVA (single TAR archive) or OVF
|
||||
# (descriptor + VMDK files) using the standard DMTF OVF schema.
|
||||
# The exported package is portable and importable on VMware
|
||||
# (ESXi / Workstation / Fusion), VirtualBox and Proxmox itself
|
||||
# (via the matching import_vm_ova_ovf.sh).
|
||||
#
|
||||
# Features:
|
||||
# - Dependency check (dialog, qm, pvesm, qemu-img, tar, sha1sum).
|
||||
# - VM picker from 'qm list'; offers graceful shutdown (qm
|
||||
# shutdown --timeout 120) or force-stop (qm stop) for running
|
||||
# VMs.
|
||||
# - Format selector: OVA (single portable file) or OVF
|
||||
# (descriptor + external VMDK files).
|
||||
# - Destination directory selector (presets + manual path), with
|
||||
# write-access and free-space pre-flight (~120% of virtual disk
|
||||
# for OVF, ~220% for OVA).
|
||||
# - Disk inventory excludes CD-ROMs and cloud-init drives.
|
||||
# - Conversion via 'qemu-img convert -O vmdk -o subformat=
|
||||
# streamOptimized' (single-pass VMware-friendly format).
|
||||
# - OVF descriptor with vCPU / memory / SCSI controller / disks /
|
||||
# NIC count, plus SHA1 manifest (.mf) of all files.
|
||||
# - Temporary working directory cleaned on EXIT via trap.
|
||||
# ==========================================================
|
||||
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
@@ -533,8 +557,20 @@ run_export() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Validate the produced VMDK. `qemu-img check` reports leaks /
|
||||
# corrupted clusters that the convert exit code might not have
|
||||
# surfaced (silent partial-write under disk pressure, qemu-img
|
||||
# bug, etc.). Audit Tier 7 — `export_vm_ova_ovf.sh` no valida
|
||||
# integridad del VMDK convertido.
|
||||
if command -v qemu-img >/dev/null 2>&1; then
|
||||
if ! qemu-img check -q "$dst" 2>/dev/null; then
|
||||
msg_error "$(translate "Integrity check failed on") $disk_name"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
EXPORT_DISK_FILES+=("$disk_name")
|
||||
msg_ok "$(translate "Converted:") $disk_name"
|
||||
msg_ok "$(translate "Converted + verified:") $disk_name"
|
||||
done
|
||||
|
||||
local ovf_file mf_file
|
||||
|
||||
@@ -4,33 +4,51 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 10/04/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Imports a virtual machine from an OVA or OVF package into Proxmox VE.
|
||||
# Compatible with exports from VMware ESXi, VMware Workstation/Fusion,
|
||||
# VirtualBox, and Proxmox itself (via export_vm_ova_ovf).
|
||||
# Imports a virtual machine from an OVA or OVF package into
|
||||
# Proxmox VE. Compatible with exports from VMware (ESXi /
|
||||
# Workstation / Fusion), VirtualBox and Proxmox itself (via the
|
||||
# matching export_vm_ova_ovf.sh).
|
||||
#
|
||||
# What is imported:
|
||||
# - Disk images (VMDK converted to the target storage format)
|
||||
# - CPU and memory settings
|
||||
# - Number of network interfaces
|
||||
# - VM name and OS type hint
|
||||
# Features:
|
||||
# - File picker: scans /var/lib/vz/dump and /var/lib/vz/template/iso
|
||||
# by default, manual path also supported. Lists every .ova / .ovf.
|
||||
# - OVA auto-extracted to /tmp/.proxmenux-import-* with cleanup
|
||||
# trap; OVF used in place.
|
||||
# - OVF parsed via AWK to extract VM name, vCPU count, memory
|
||||
# (RASD ResourceType 4), NIC count (type 10) and disk file
|
||||
# references (.vmdk / .qcow2 / .img / .raw).
|
||||
# - OS-type heuristic: maps Linux -> l26, Windows -> win10,
|
||||
# anything else -> other.
|
||||
# - Dialog flow for VMID (suggests pvesh nextid), name, target
|
||||
# storage (pvesm status -content images), bridge (auto-picks
|
||||
# when only one exists).
|
||||
# - VM created with --scsihw lsi --net0 e1000,bridge=...; extra
|
||||
# NICs added per OVF NIC count.
|
||||
# - Disks imported with 'qm importdisk' (storage-native format),
|
||||
# then attached as scsiN and unusedN markers cleared.
|
||||
# - Boot config set to scsi0.
|
||||
#
|
||||
# What requires manual review after import:
|
||||
# - Network bridge assignment (vmbr0 assigned by default)
|
||||
# - NIC model (e1000 by default — change to VirtIO if guest supports it)
|
||||
# - Firmware (BIOS/UEFI — must match what the original VM used)
|
||||
# - Network bridge assignment (vmbr0 assigned by default).
|
||||
# - NIC model (e1000 by default -- change to VirtIO if guest
|
||||
# supports it).
|
||||
# - Firmware (BIOS / UEFI -- must match the original VM).
|
||||
# - VirtIO/qemu-guest-agent installation inside the guest (especially from ESXi)
|
||||
# - PCI passthrough, TPM, cloud-init, snapshots — not portable in OVF/OVA
|
||||
# ==========================================================
|
||||
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
LOCAL_SCRIPTS="$BASE_DIR/scripts"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
INSTALL_HELPERS="$LOCAL_SCRIPTS/global/utils-install-functions.sh"
|
||||
|
||||
[[ -f "$UTILS_FILE" ]] && source "$UTILS_FILE"
|
||||
[[ -f "$INSTALL_HELPERS" ]] && source "$INSTALL_HELPERS"
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
@@ -63,6 +81,46 @@ BRIDGE="vmbr0"
|
||||
# HELPERS
|
||||
# -------------------------------------------------------
|
||||
|
||||
# Ensure GNU awk (gawk) is installed before parsing OVF.
|
||||
# The OVF parser uses match($0, /regex/, array) — the 3-argument form
|
||||
# is a gawk extension; mawk (the Debian/Proxmox default 'awk') errors
|
||||
# with "syntax error at or near ,". Returns 0 on success, 1 if install
|
||||
# fails (caller is expected to abort with a clear error).
|
||||
ensure_gawk() {
|
||||
if command -v gawk >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
if type ensure_repositories &>/dev/null && type install_single_package &>/dev/null; then
|
||||
# Canonical path: install_single_package handles its own
|
||||
# msg_info / msg_ok / msg_error pair, so we don't open one here
|
||||
# (would leave an orphan spinner overlapping with theirs).
|
||||
if ! ensure_repositories; then
|
||||
msg_error "$(translate "Failed to configure repositories.")"
|
||||
return 1
|
||||
fi
|
||||
install_single_package "gawk" "gawk" "GNU awk (required for OVF parsing)"
|
||||
case $? in
|
||||
0|2) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Fallback when utils-install-functions.sh was not sourced.
|
||||
# Here we own the spinner: msg_info opens it, msg_ok / msg_error closes it.
|
||||
msg_info "$(translate "Installing gawk (required for OVF parsing)...")"
|
||||
if apt-get update -qq >/dev/null 2>&1 && apt-get install -y gawk >/dev/null 2>&1; then
|
||||
msg_ok "$(translate "gawk installed")"
|
||||
return 0
|
||||
fi
|
||||
|
||||
msg_error "$(translate "Failed to install gawk")"
|
||||
msg_warn "$(translate "Install manually with:") apt-get install gawk"
|
||||
return 1
|
||||
}
|
||||
|
||||
human_bytes() {
|
||||
local bytes="$1"
|
||||
local units=("B" "KB" "MB" "GB" "TB")
|
||||
@@ -194,8 +252,13 @@ prepare_ovf() {
|
||||
parse_ovf() {
|
||||
local ovf_file="$1"
|
||||
|
||||
# The parser below uses gawk's 3-argument match() form, which is
|
||||
# NOT supported by mawk (the default 'awk' on Debian/Proxmox).
|
||||
# ensure_gawk installs gawk on first use if missing.
|
||||
ensure_gawk || return 1
|
||||
|
||||
local result
|
||||
result=$(awk '
|
||||
result=$(gawk '
|
||||
BEGIN {
|
||||
in_item=0; rt=""; qty=""
|
||||
file_count=0; cap_count=0; net_count=0
|
||||
@@ -224,11 +287,29 @@ parse_ovf() {
|
||||
if (a[1]+0 > 0) caps[cap_count++] = a[1]
|
||||
}
|
||||
|
||||
/<Item>|<Item / { in_item=1; rt=""; qty="" }
|
||||
/<Item>|<Item / { in_item=1; rt=""; qty=""; au="" }
|
||||
/<\/Item>/ {
|
||||
if (in_item) {
|
||||
if (rt=="3" && qty ~ /^[0-9]+$/) vcpu=qty
|
||||
if (rt=="4" && qty ~ /^[0-9]+$/) mem=qty
|
||||
# ResourceType=4 is Memory. Normalise `qty` to MiB based
|
||||
# on AllocationUnits: VMware sometimes emits `byte`,
|
||||
# `byte * 2^10` (KiB), `byte * 2^30` (GiB) or textual
|
||||
# `MegaBytes`/`GigaBytes`. Defaulting to MiB blindly
|
||||
# (the previous behaviour) imported 8 GB VMs as 8 MiB
|
||||
# or vice-versa. Audit Tier 6 — OVF memory units.
|
||||
if (rt=="4" && qty ~ /^[0-9]+$/) {
|
||||
if (au ~ /byte \* 2\^30/ || au ~ /[Gg]iga[Bb]yte/) {
|
||||
mem = qty * 1024
|
||||
} else if (au ~ /byte \* 2\^10/ || au ~ /[Kk]ilo[Bb]yte/) {
|
||||
mem = int((qty + 1023) / 1024)
|
||||
} else if (au ~ /byte \* 2\^20/ || au ~ /[Mm]ega[Bb]yte/ || au == "") {
|
||||
mem = qty
|
||||
} else if (au == "byte" || au ~ /^bytes?$/) {
|
||||
mem = int((qty + 1048575) / 1048576)
|
||||
} else {
|
||||
mem = qty
|
||||
}
|
||||
}
|
||||
if (rt=="10") net_count++
|
||||
}
|
||||
in_item=0
|
||||
@@ -239,6 +320,9 @@ parse_ovf() {
|
||||
/VirtualQuantity>/ {
|
||||
match($0, /VirtualQuantity>([0-9]+)</, a); qty=a[1]
|
||||
}
|
||||
/AllocationUnits>/ {
|
||||
match($0, /AllocationUnits>([^<]+)</, a); au=a[1]
|
||||
}
|
||||
|
||||
END {
|
||||
gsub(/^[[:space:]]+|[[:space:]]+$/, "", name)
|
||||
@@ -601,7 +685,23 @@ main() {
|
||||
else
|
||||
echo ""
|
||||
msg_error "$(translate "Import failed. VM $NEW_VMID may be in partial state.")"
|
||||
msg_info2 "$(translate "To remove partial VM:") qm destroy $NEW_VMID --destroy-unreferenced-disks 1"
|
||||
# Offer to clean up the orphan VM. Most users want this — it
|
||||
# otherwise sits in the PVE UI as a half-broken entry that the
|
||||
# user has to clean up manually with the command we hint at. Audit
|
||||
# Tier 6 — `import_vm_ova_ovf.sh` VM huérfana tras fallo.
|
||||
if dialog --backtitle "$BACKTITLE" \
|
||||
--title "$(translate "Cleanup partial VM?")" \
|
||||
--yesno "$(translate "Remove the partial VM ($NEW_VMID) and its imported disks?")" 8 60; then
|
||||
clear
|
||||
msg_info "$(translate "Removing partial VM") $NEW_VMID..."
|
||||
if qm destroy "$NEW_VMID" --destroy-unreferenced-disks 1 &>/dev/null; then
|
||||
msg_ok "$(translate "Partial VM removed")"
|
||||
else
|
||||
msg_warn "$(translate "Could not remove VM automatically. Run manually:") qm destroy $NEW_VMID --destroy-unreferenced-disks 1"
|
||||
fi
|
||||
else
|
||||
msg_info2 "$(translate "To remove partial VM:") qm destroy $NEW_VMID --destroy-unreferenced-disks 1"
|
||||
fi
|
||||
echo ""
|
||||
msg_success "$(translate "Press Enter to return...")"
|
||||
read -r
|
||||
|
||||
@@ -1,13 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - Manual Proxmox VE 8 to 9 Upgrade Guide
|
||||
# ProxMenux - Manual PVE 8 to 9 Upgrade Guide
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 13/08/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Read-only display of a 17-step manual upgrade procedure from
|
||||
# Proxmox VE 8 to 9. Modifies nothing on the host -- exposes the
|
||||
# exact commands the automated upgrade runs so an operator can
|
||||
# perform the upgrade by hand for full visibility, or use it as a
|
||||
# reference / runbook.
|
||||
#
|
||||
# Features:
|
||||
# - Numbered steps with description + command + recommended
|
||||
# answers for the dpkg prompts encountered during dist-upgrade.
|
||||
# - Prerequisite checklist (PVE 8.4+, console access, backups,
|
||||
# free disk space, ...).
|
||||
# - Covers Debian bookworm -> trixie sed migration, repository
|
||||
# deb822 conversion, Ceph 19.x (Squid) requirement and
|
||||
# cluster-upgrade caveats.
|
||||
# - Recommends running the upgrade inside tmux / screen.
|
||||
# ==========================================================
|
||||
|
||||
# Configuration ============================================
|
||||
|
||||
@@ -1,28 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ProxMenux - Proxmox System Update
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 04/07/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script safely updates your Proxmox VE system and underlying Debian packages
|
||||
# through an interactive and automated process.
|
||||
# Wrapper that detects the running Proxmox major version and
|
||||
# delegates to the matching worker script:
|
||||
# - PVE 8 -> scripts/global/update-pve8.sh
|
||||
# - PVE 9 -> scripts/global/update-pve9_2.sh
|
||||
# After the worker finishes, runs the post-update cleanup
|
||||
# (apt-get autoremove + autoclean) and prompts for an immediate
|
||||
# reboot if the kernel was updated or /var/run/reboot-required
|
||||
# was created.
|
||||
#
|
||||
# Main features:
|
||||
# - Repairs and optimizes APT repositories (Proxmox & Debian)
|
||||
# - Removes duplicate or conflicting sources
|
||||
# - Switches to the recommended 'no-subscription' Proxmox repository
|
||||
# - Updates all Proxmox and Debian system packages
|
||||
# - Installs essential packages if missing (e.g., zfsutils, chrony)
|
||||
# - Checks for LVM and storage issues and repairs headers if needed
|
||||
# - Removes conflicting time sync packages automatically
|
||||
# - Performs a system cleanup after updating (autoremove, autoclean)
|
||||
# - Provides a summary and prompts for reboot if necessary
|
||||
# Features (delegated to worker scripts):
|
||||
# - APT repository hygiene (Proxmox + Debian)
|
||||
# - Removal of duplicate / conflicting sources
|
||||
# - Switch to the no-subscription Proxmox repository
|
||||
# - Full apt update + dist-upgrade
|
||||
# - Installs essential packages if missing (zfsutils, chrony, ...)
|
||||
# - LVM / storage sanity checks and header repair
|
||||
# - Removes conflicting time-sync packages
|
||||
# - Post-update system cleanup
|
||||
# - Reboot prompt when kernel changed
|
||||
# ==========================================================
|
||||
#
|
||||
# The goal of this script is to simplify and secure the update process for Proxmox,
|
||||
# reduce manual intervention, and prevent common repository and package errors.
|
||||
@@ -46,11 +52,21 @@ export SCRIPT_TITLE="Proxmox system update"
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
apt_upgrade() {
|
||||
local pve_version
|
||||
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
|
||||
local pve_version pve_raw
|
||||
# Capture both stdout and the rc so a failure is visible in the
|
||||
# error message — silent `2>/dev/null` previously hid the real cause
|
||||
# (binary missing / output malformed). Audit Tier 6 — `proxmox_update.sh`
|
||||
# detección de versión silenciosa.
|
||||
pve_raw=$(pveversion 2>&1)
|
||||
local pve_rc=$?
|
||||
pve_version=$(echo "$pve_raw" | grep -oP 'pve-manager/\K[0-9]+' | head -1)
|
||||
|
||||
if [[ -z "$pve_version" ]]; then
|
||||
msg_error "Unable to detect Proxmox version."
|
||||
if (( pve_rc != 0 )); then
|
||||
msg_error "Unable to detect Proxmox version (pveversion exit $pve_rc): ${pve_raw:0:200}"
|
||||
else
|
||||
msg_error "Unable to parse Proxmox version from output: ${pve_raw:0:200}"
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenuX - Upgrade PVE 8 → 9 (Simplified, per official guide)
|
||||
# ProxMenux - PVE 8 to 9 Pre-upgrade Check
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 14/08/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Runs Proxmox's official 'pve8to9 --full' pre-upgrade check and
|
||||
# offers guided remediation for the common blocking issues. Stops
|
||||
# before the actual upgrade -- invoke upgrade_pve8_to_pve9.sh to
|
||||
# proceed once the check passes cleanly.
|
||||
#
|
||||
# Features:
|
||||
# - Captures full pve8to9 output to /var/log/pve8-a-pve9-<timestamp>.log
|
||||
# - Counts FAIL / WARN entries and surfaces a summary banner.
|
||||
# - Detects common failure patterns (systemd-boot meta-package,
|
||||
# Ceph version, repository conflicts, missing packages, low
|
||||
# disk space, network restart needed) and proposes the matching
|
||||
# repair command.
|
||||
# - Three-way prompt: auto-repair, show manual commands, abort.
|
||||
# - Re-runs the check after auto-repair to confirm resolution.
|
||||
# ==========================================================
|
||||
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
@@ -21,6 +37,15 @@ fi
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
# Load shared global functions: cleanup_duplicate_repos and ensure_repositories
|
||||
# are referenced by the auto-repair flow below and live in these files.
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/common-functions.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/common-functions.sh"
|
||||
fi
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/utils-install-functions.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/utils-install-functions.sh"
|
||||
fi
|
||||
|
||||
|
||||
# ==========================================================
|
||||
|
||||
@@ -39,6 +64,19 @@ fi
|
||||
|
||||
|
||||
run_pve8to9_check2() {
|
||||
# Bound the auto-repair → re-check recursion. If repairs keep producing
|
||||
# FAILs (e.g. a missing repo can't be auto-fixed by `ensure_repositories`)
|
||||
# the user could keep picking "auto-repair" indefinitely and we'd grow
|
||||
# the bash call stack until it overflows. Cap at 3 attempts. Audit
|
||||
# Tier 6 — `pve8to9_check.sh` recursión sin guard.
|
||||
: "${_PVE8TO9_DEPTH:=0}"
|
||||
_PVE8TO9_DEPTH=$((_PVE8TO9_DEPTH + 1))
|
||||
if (( _PVE8TO9_DEPTH > 3 )); then
|
||||
msg_error "$(translate "Maximum auto-repair attempts reached (3). Please review the log and run any remaining commands manually.")"
|
||||
_PVE8TO9_DEPTH=0
|
||||
return 1
|
||||
fi
|
||||
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
echo -e
|
||||
@@ -76,9 +114,9 @@ run_pve8to9_check2() {
|
||||
|
||||
# Error 3: Repository configuration issues
|
||||
if grep -q -E '(repository.*issue|repo.*problem|sources.*error)' "$tmp"; then
|
||||
repair_commands+=("cleanup_duplicate_repos && configure_repositories")
|
||||
repair_commands+=("cleanup_duplicate_repos && ensure_repositories")
|
||||
repair_descriptions+=("$(translate "Fix repository configuration")")
|
||||
echo -e "${YW}$(translate "Fix repositories:") ${CL}cleanup_duplicate_repos && configure_repositories"
|
||||
echo -e "${YW}$(translate "Fix repositories:") ${CL}cleanup_duplicate_repos && ensure_repositories"
|
||||
fi
|
||||
|
||||
# Error 4: Package conflicts
|
||||
|
||||
@@ -1,36 +1,32 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ProxMenux - System Utilities Installer
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.2
|
||||
# Last Updated: 03/04/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script provides an interactive system utilities installer with a
|
||||
# comprehensive dialog-based interface for Proxmox VE and Linux systems.
|
||||
# It simplifies the installation and management of essential command-line
|
||||
# tools and utilities commonly used in server environments.
|
||||
#
|
||||
# The script offers both individual utility selection and predefined groups
|
||||
# for different use cases, ensuring administrators can quickly set up their
|
||||
# preferred toolset without manual package management.
|
||||
#
|
||||
# Supported utility categories:
|
||||
# - Basic utilities: grc, htop, tree, curl, wget
|
||||
# - Development tools: git, vim, nano, dos2unix
|
||||
# - Compression tools: zip, unzip, rsync, cabextract
|
||||
# - Network tools: iperf3, nmap, tcpdump, nethogs, iptraf-ng, sshpass
|
||||
# - Analysis tools: jq, ncdu, iotop, btop, iftop
|
||||
# - System tools: plocate, net-tools, ipset, msr-tools
|
||||
# - Virtualization tools: libguestfs-tools, wimtools, genisoimage, chntpw
|
||||
# - Download tools: axel, aria2
|
||||
#
|
||||
# The script automatically handles package name differences across distributions
|
||||
# and provides detailed feedback on installation success, warnings, and failures.
|
||||
# Interactive installer for 26 curated CLI utilities packaged in
|
||||
# the canonical PROXMENUX_UTILS list (defined in
|
||||
# global/utils-install-functions.sh). Uses the shared
|
||||
# ensure_repositories() + install_single_package() pair to keep the
|
||||
# repo configuration and feedback consistent with the rest of the
|
||||
# project.
|
||||
#
|
||||
# Features:
|
||||
# - Custom selection: dialog checklist of all 26 packages.
|
||||
# - Install ALL utilities: one-click for all of PROXMENUX_UTILS.
|
||||
# - Predefined groups (basic / dev / compression / multiplexers /
|
||||
# analysis / network) for quick targeted installs.
|
||||
# - Verify installations: checks every PROXMENUX_UTILS command for
|
||||
# availability and shows an Available / Missing summary.
|
||||
# - Per-package feedback (install_single_package returns 0 ok / 1
|
||||
# failed / 2 installed-but-command-not-found-yet).
|
||||
# - Hash refresh after each install to surface new commands.
|
||||
# ==========================================================
|
||||
|
||||
# Configuration ============================================
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
|
||||
@@ -1,12 +1,45 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenuX - Upgrade PVE 8 → 9 (Simplified, per official guide)
|
||||
# ProxMenux - Upgrade PVE 8 to PVE 9
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 14/08/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Automated or interactive Proxmox VE 8 -> 9 major-version upgrade.
|
||||
# Follows the official Proxmox upgrade procedure (Debian Bookworm ->
|
||||
# Trixie + PVE 8 -> 9) with comprehensive safeguards, repository
|
||||
# migration, Ceph version validation and post-upgrade verification.
|
||||
#
|
||||
# A major-version upgrade is destructive and not reversible -- the
|
||||
# script enforces multiple safety gates and refuses to run from the
|
||||
# Proxmox web terminal.
|
||||
#
|
||||
# Features:
|
||||
# - Mode menu: Automatic (unattended), Interactive, Pre-check,
|
||||
# Manual guide.
|
||||
# - Blocks execution from the web terminal (termproxy / vncshell);
|
||||
# requires SSH or physical / IPMI / iKVM console.
|
||||
# - Pre-flight: pve8to9 --full, disk-space check
|
||||
# (/var/cache/apt/archives >= 1024 MB), connectivity to
|
||||
# download.proxmox.com, Ceph 19.x Squid validation when present.
|
||||
# - Brings PVE 8 to the latest 8.4.x patch level first via the
|
||||
# PVE 8 update worker.
|
||||
# - Repository migration: sed bookworm -> trixie, deb822 .sources
|
||||
# files for proxmox + debian + ceph, automatic fallback from
|
||||
# Enterprise to no-subscription on 401 Unauthorized.
|
||||
# - Validates 'proxmox-ve' candidate is 9.x and that the dry-run
|
||||
# dist-upgrade does not propose removing it (would indicate
|
||||
# broken repo config).
|
||||
# - dist-upgrade with --force-confdef --force-confold in
|
||||
# unattended mode; user-driven dpkg prompts in interactive mode.
|
||||
# - Post-upgrade: installs grub-efi-amd64 on EFI hosts, restarts
|
||||
# pve-manager, re-runs pve8to9 to surface residual issues.
|
||||
# - Reboot prompt at the end.
|
||||
# - Full log written to /var/log/pve8-a-pve9-<timestamp>.log.
|
||||
# ==========================================================
|
||||
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
@@ -21,6 +54,15 @@ fi
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
# Load shared global functions: cleanup_duplicate_repos and ensure_repositories
|
||||
# are referenced by the auto-repair flow below and live in these files.
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/common-functions.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/common-functions.sh"
|
||||
fi
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/utils-install-functions.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/utils-install-functions.sh"
|
||||
fi
|
||||
|
||||
# ==========================================================
|
||||
|
||||
LOG="/var/log/pve8-a-pve9-$(date +%Y%m%d-%H%M%S).log"
|
||||
@@ -594,6 +636,17 @@ regenerate_pve_cache
|
||||
# ---------------------------
|
||||
|
||||
run_pve8to9_check() {
|
||||
# Same recursion guard as in pve8to9_check.sh — auto-repair followed by
|
||||
# re-check could otherwise loop indefinitely if repairs don't actually
|
||||
# resolve the FAIL. Cap at 3 attempts. Audit Tier 6.
|
||||
: "${_PVE8TO9_DEPTH:=0}"
|
||||
_PVE8TO9_DEPTH=$((_PVE8TO9_DEPTH + 1))
|
||||
if (( _PVE8TO9_DEPTH > 3 )); then
|
||||
msg_error "$(translate "Maximum auto-repair attempts reached (3). Please review the log and run any remaining commands manually.")"
|
||||
_PVE8TO9_DEPTH=0
|
||||
return 1
|
||||
fi
|
||||
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
echo -e
|
||||
@@ -637,9 +690,9 @@ run_pve8to9_check() {
|
||||
|
||||
# Error 4: Repository configuration issues
|
||||
if grep -q -E '(repository.*issue|repo.*problem|sources.*error)' "$tmp"; then
|
||||
repair_commands+=("cleanup_duplicate_repos && configure_repositories")
|
||||
repair_commands+=("cleanup_duplicate_repos && ensure_repositories")
|
||||
repair_descriptions+=("$(translate "Fix repository configuration")")
|
||||
echo -e "${YW}$(translate "Fix repositories:") ${CL}cleanup_duplicate_repos && configure_repositories"
|
||||
echo -e "${YW}$(translate "Fix repositories:") ${CL}cleanup_duplicate_repos && ensure_repositories"
|
||||
fi
|
||||
|
||||
# Error 5: Package conflicts
|
||||
@@ -1003,9 +1056,9 @@ run_pve8to9_check2() {
|
||||
|
||||
# Error 4: Repository configuration issues
|
||||
if grep -q -E '(repository.*issue|repo.*problem|sources.*error)' "$tmp"; then
|
||||
repair_commands+=("cleanup_duplicate_repos && configure_repositories")
|
||||
repair_commands+=("cleanup_duplicate_repos && ensure_repositories")
|
||||
repair_descriptions+=("$(translate "Fix repository configuration")")
|
||||
echo -e "${YW}$(translate "Fix repositories:") ${CL}cleanup_duplicate_repos && configure_repositories"
|
||||
echo -e "${YW}$(translate "Fix repositories:") ${CL}cleanup_duplicate_repos && ensure_repositories"
|
||||
fi
|
||||
|
||||
# Error 5: Package conflicts
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - UUP Dump ISO Creator Custom
|
||||
# ProxMenux - UUP Dump ISO Creator
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 30/06/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script is part of the ProxMenux tools for Proxmox VE.
|
||||
# It allows downloading and converting official Windows ISO images
|
||||
# from UUP Dump using a shared link (with ID, pack, and edition).
|
||||
# Downloads and converts official Windows ISO images from UUP Dump
|
||||
# using a shared link (ID + pack + edition). Produces an up-to-date
|
||||
# bootable ISO ready for VM creation in Proxmox VE.
|
||||
#
|
||||
# Key features:
|
||||
# - Automatically installs and verifies required dependencies (aria2c, cabextract, wimlib-imagex…)
|
||||
# - Downloads the selected Windows edition from UUP Dump using aria2
|
||||
# - Converts the downloaded files into a bootable ISO
|
||||
# - Stores the resulting ISO in the default template path (/var/lib/vz/template/iso)
|
||||
# - Provides a graphical prompt via whiptail for user-friendly usage
|
||||
#
|
||||
# This tool simplifies the creation of official Windows ISOs
|
||||
# for use in virtual machines within Proxmox VE.
|
||||
# Features:
|
||||
# - Automatically installs and verifies required dependencies
|
||||
# (aria2c, cabextract, wimlib-imagex, ...).
|
||||
# - Downloads the selected Windows edition from UUP Dump using
|
||||
# aria2 (multi-connection accelerator).
|
||||
# - Converts the downloaded files into a bootable ISO.
|
||||
# - Stores the resulting ISO in the default template path
|
||||
# (/var/lib/vz/template/iso) so it shows up in the Proxmox UI.
|
||||
# - Whiptail-driven UX (URL prompt, edition / pack confirmation,
|
||||
# progress reporting).
|
||||
# ==========================================================
|
||||
# ==========================================================
|
||||
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenuX - Virtual Machine Creator Script
|
||||
# ProxMenux - Linux ISO Selector
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 07/05/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script is part of the central ProxMenux VM creation module. It allows users
|
||||
# to create virtual machines (VMs) in Proxmox VE using either default or advanced
|
||||
# configurations, streamlining the deployment of Linux, Windows, and other systems.
|
||||
# Linux installation source selector for the ProxMenux VM creator.
|
||||
# Offers three paths to obtain the Linux installation media and
|
||||
# also exposes the "Others" prebuilt VM menu used by the main
|
||||
# dispatcher for community-maintained installers.
|
||||
#
|
||||
# Key features:
|
||||
# - Supports both virtual disk creation and physical disk passthrough.
|
||||
# - Automates CPU, RAM, BIOS, network and storage configuration.
|
||||
# - Provides a user-friendly menu to select OS type, ISO image and disk interface.
|
||||
# - Automatically generates a detailed and styled HTML description for each VM.
|
||||
#
|
||||
# All operations are designed to simplify and accelerate VM creation in a
|
||||
# consistent and maintainable way, using ProxMenux standards.
|
||||
# Features:
|
||||
# - Curated list of official Linux ISOs (Ubuntu, Debian, Fedora,
|
||||
# Arch, Rocky, Mint, openSUSE, Alpine, Kali, Manjaro) with
|
||||
# direct download URLs.
|
||||
# - Cloud-Init automated installers (community scripts).
|
||||
# - Pick an existing ISO from /var/lib/vz/template/iso.
|
||||
# - Separate "Others Prebuilt VMs" selector (HAOS, Docker, Nextcloud)
|
||||
# used by the main menu's Community Scripts path.
|
||||
# ==========================================================
|
||||
|
||||
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenuX - Virtual Machine Creator Script
|
||||
# ProxMenux - NAS ISO Selector
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 04/04/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script is part of the central ProxMenux VM creation module. It allows users
|
||||
# to create virtual machines (VMs) in Proxmox VE using either default or advanced
|
||||
# configurations, streamlining the deployment of Linux, Windows, and other systems.
|
||||
# NAS appliance selector for the ProxMenux VM creator. Lists the
|
||||
# supported NAS operating systems, auto-detects their latest stable
|
||||
# release (where possible), and prepares the ISO / image metadata
|
||||
# for the generic VM wizard. Synology DSM and ZimaOS have their own
|
||||
# dedicated flows; Umbrel OS runs an external community script.
|
||||
#
|
||||
# Key features:
|
||||
# - Supports both virtual disk creation and physical disk passthrough.
|
||||
# - Automates CPU, RAM, BIOS, network and storage configuration.
|
||||
# - Provides a user-friendly menu to select OS type, ISO image and disk interface.
|
||||
# - Automatically generates a detailed and styled HTML description for each VM.
|
||||
#
|
||||
# All operations are designed to simplify and accelerate VM creation in a
|
||||
# consistent and maintainable way, using ProxMenux standards.
|
||||
# Features:
|
||||
# - Auto-detects latest versions for TrueNAS SCALE/CORE, OMV,
|
||||
# XigmaNAS and Rockstor, with safe fallbacks.
|
||||
# - Dispatches Synology DSM to the dedicated loader-based flow.
|
||||
# - Dispatches ZimaOS to its own installer script.
|
||||
# - Runs the Umbrel OS community installer (external script).
|
||||
# ==========================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
@@ -188,6 +188,8 @@ function select_nas_iso() {
|
||||
"5" "XigmaNAS VM (FreeBSD based)"
|
||||
"6" "Rockstor VM (openSUSE based)"
|
||||
"7" "ZimaOS VM (Proxmox-zimaos)"
|
||||
"" ""
|
||||
"" "\Z4───────────────── Community Scripts ─────────────────\Zn"
|
||||
"8" "Umbrel OS VM (Helper Scripts)"
|
||||
"9" "$(translate "Return to Main Menu")"
|
||||
)
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenuX - Virtual Machine Creator Script
|
||||
# ProxMenux - Windows ISO Selector
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 07/05/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script is part of the central ProxMenux VM creation module. It allows users
|
||||
# to create virtual machines (VMs) in Proxmox VE using either default or advanced
|
||||
# configurations, streamlining the deployment of Linux, Windows, and other systems.
|
||||
# Windows installation source selector for the ProxMenux VM
|
||||
# creator. Offers two paths to obtain the Windows ISO and then
|
||||
# hands over to the generic VM wizard for CPU, RAM, storage and
|
||||
# optional GPU passthrough.
|
||||
#
|
||||
# Key features:
|
||||
# - Supports both virtual disk creation and physical disk passthrough.
|
||||
# - Automates CPU, RAM, BIOS, network and storage configuration.
|
||||
# - Provides a user-friendly menu to select OS type, ISO image and disk interface.
|
||||
# - Automatically generates a detailed and styled HTML description for each VM.
|
||||
#
|
||||
# All operations are designed to simplify and accelerate VM creation in a
|
||||
# consistent and maintainable way, using ProxMenux standards.
|
||||
# Features:
|
||||
# - Build an up-to-date Windows ISO via the UUP Dump creator.
|
||||
# - Pick a Windows ISO already present in /var/lib/vz/template/iso.
|
||||
# - Auto-detects the latest ISO created by UUP Dump.
|
||||
# - Exports ISO metadata (name, path, OS_TYPE) for the wizard.
|
||||
# ==========================================================
|
||||
|
||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
||||
|
||||
+19
-16
@@ -1,30 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenuX - Synology DSM VM Creator Script
|
||||
# ProxMenux - Synology DSM VM Creator
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 13/03/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script automates the creation and configuration of a Synology DSM
|
||||
# (DiskStation Manager) virtual machine (VM) in Proxmox VE. It simplifies the
|
||||
# setup process by allowing both default and advanced configuration options.
|
||||
# Creates and configures a Synology DSM (DiskStation Manager)
|
||||
# virtual machine on Proxmox VE. Downloads one of the supported
|
||||
# loaders (Arc, RR, TinyCore M-shell, or a custom one), imports
|
||||
# it as the VM boot disk, and prepares CPU/RAM/network/storage
|
||||
# through the ProxMenux default or advanced wizard.
|
||||
#
|
||||
# The script automates the complete VM creation process, including loader
|
||||
# download, disk configuration, and VM boot setup.
|
||||
#
|
||||
# **Credits**
|
||||
# This script is an original idea but incorporates ideas and elements from
|
||||
# a similar script by user **tim104979** from the ProxmoxVE branch:
|
||||
# (https://raw.githubusercontent.com/tim104979/ProxmoxVE/refs/heads/main/vm/synology-vm.sh)
|
||||
#
|
||||
# Copyright (c) Proxmox VE Helper-Scripts Community
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Features:
|
||||
# - Supports Arc, RR, TinyCore M-shell and Custom loaders.
|
||||
# - Default and Advanced configuration modes.
|
||||
# - Virtual disks (SATA, up to 6) or physical disk passthrough.
|
||||
# - Imports the loader as IDE for maximum compatibility.
|
||||
# - Generates a styled HTML description attached to the VM.
|
||||
#
|
||||
# Credits:
|
||||
# Original work by MacRimi. Incorporates ideas and snippets from
|
||||
# tim104979's synology-vm.sh in the ProxmoxVE Helper-Scripts
|
||||
# Community project (MIT):
|
||||
# https://raw.githubusercontent.com/tim104979/ProxmoxVE/refs/heads/main/vm/synology-vm.sh
|
||||
# ==========================================================
|
||||
|
||||
|
||||
|
||||
@@ -5,24 +5,26 @@
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 07/05/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script is part of the ProxMenux tools for Proxmox VE.
|
||||
# It allows downloading and converting official Windows ISO images
|
||||
# from UUP Dump using a shared link (with ID, pack, and edition).
|
||||
# Downloads and converts an official Windows ISO from UUP Dump
|
||||
# using a shared link that carries the build parameters (id,
|
||||
# pack, edition). The resulting ISO is placed in the Proxmox
|
||||
# ISO storage and becomes immediately available to the VM
|
||||
# creator.
|
||||
#
|
||||
# Key features:
|
||||
# - Automatically installs and verifies required dependencies (aria2c, cabextract, wimlib-imagex…)
|
||||
# - Downloads the selected Windows edition from UUP Dump using aria2
|
||||
# - Converts the downloaded files into a bootable ISO
|
||||
# - Stores the resulting ISO in the default template path (/var/lib/vz/template/iso)
|
||||
# - Provides a graphical prompt via whiptail for user-friendly usage
|
||||
#
|
||||
# This tool simplifies the creation of official Windows ISOs
|
||||
# for use in virtual machines within Proxmox VE.
|
||||
# Features:
|
||||
# - Auto-installs dependencies (aria2, cabextract, wimtools,
|
||||
# genisoimage, chntpw, curl).
|
||||
# - Downloads the UUP Dump converter and all UUP payload files
|
||||
# in parallel with aria2.
|
||||
# - Builds a bootable ISO via the upstream convert.sh.
|
||||
# - Auto-detects the Proxmox ISO storage directory and falls
|
||||
# back to /var/lib/vz/template/iso.
|
||||
# - Interactive prompts via whiptail / dialog.
|
||||
# ==========================================================
|
||||
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenuX - Virtual Machine Creator Script
|
||||
# ProxMenux - VM Configurator (CPU / RAM / BIOS / Network)
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 07/05/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script is part of the central ProxMenux VM creation module. It allows users
|
||||
# to create virtual machines (VMs) in Proxmox VE using either default or advanced
|
||||
# configurations, streamlining the deployment of Linux, Windows, and other systems.
|
||||
# Shared VM configurator used by the ProxMenux VM creation
|
||||
# flows (NAS, Windows, Linux, Synology, ZimaOS). Exposes two
|
||||
# helpers: the default-profile applier (per OS family) and the
|
||||
# advanced wizard that walks the user through every parameter.
|
||||
#
|
||||
# Key features:
|
||||
# - Supports both virtual disk creation and physical disk passthrough.
|
||||
# - Automates CPU, RAM, BIOS, network and storage configuration.
|
||||
# - Provides a user-friendly menu to select OS type, ISO image and disk interface.
|
||||
# - Automatically generates a detailed and styled HTML description for each VM.
|
||||
#
|
||||
# All operations are designed to simplify and accelerate VM creation in a
|
||||
# consistent and maintainable way, using ProxMenux standards.
|
||||
# Features:
|
||||
# - VMID auto-assignment and collision check.
|
||||
# - Hostname, machine type (q35 / i440fx), BIOS (OVMF / SeaBIOS).
|
||||
# - CPU type (host / kvm64), core count, RAM.
|
||||
# - Network: bridge, MAC, VLAN, MTU.
|
||||
# - Per-OS defaults (NAS, Windows, Linux) and OMV BIOS override.
|
||||
# ==========================================================
|
||||
|
||||
|
||||
|
||||
+13
-10
@@ -1,23 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenuX - ZimaOS VM Creator Script
|
||||
# ProxMenux - ZimaOS VM Creator
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# License : GPL-3.0
|
||||
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
||||
# Version : 1.0
|
||||
# Last Updated: 21/08/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script automates the creation and configuration of a ZimaOS
|
||||
# Virtual machine (VM) in Proxmox VE. It simplifies the
|
||||
# setup process by allowing both default and advanced configuration options.
|
||||
#
|
||||
# The script automates the complete VM creation process, including loader
|
||||
# download, disk configuration, and VM boot setup.
|
||||
#
|
||||
# Creates and configures a ZimaOS virtual machine on Proxmox VE.
|
||||
# Downloads the ZimaOS pre-built image, wires it into a new VM
|
||||
# using either the ProxMenux default profile or the advanced
|
||||
# wizard, and hands storage and optional GPU passthrough to the
|
||||
# shared helpers.
|
||||
#
|
||||
# Features:
|
||||
# - Default and Advanced configuration modes.
|
||||
# - Unified storage plan (virtual / import / PCI passthrough).
|
||||
# - Optional GPU passthrough via the shared VM wizard.
|
||||
# - Auto-generates a styled HTML description attached to the VM.
|
||||
# ==========================================================
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user