Compare commits

..

3 Commits

Author SHA1 Message Date
MickLesk 71ecb99c62 Source core.func for shared messaging in iommu-setup
Replace locally duplicated color variables and msg_* helpers with
core.func + load_functions, matching the pattern used by update-apps
and pve-privilege-converter. Telemetry remains via api.func only.
2026-06-26 22:02:49 +02:00
MickLesk a9cc6234e8 Fix bare-metal detection in iommu-setup
systemd-detect-virt prints "none" on bare metal but exits non-zero, so the
`|| echo "none"` fallback appended a second "none" and the check wrongly
treated a physical Proxmox host as virtualized. Capture the command output
directly and only block when a real virtualization type is reported.
2026-06-26 21:50:48 +02:00
MickLesk 9a4c8325cc Add iommu-setup tool for PCI(e) passthrough preparation
New PVE host tool that enables IOMMU for PCI(e) passthrough:

- Detects the CPU vendor and applies the matching kernel parameters
  (intel_iommu=on / amd_iommu=on plus iommu=pt).
- Supports both boot configurations: GRUB (/etc/default/grub + update-grub)
  and proxmox-boot-tool managed systemd-boot (/etc/kernel/cmdline +
  proxmox-boot-tool refresh).
- Idempotent: only missing parameters are appended and a timestamped backup
  of the boot config is created before editing.
- Loads the vfio modules at boot (vfio_virqfd omitted, merged into the core
  since kernel 6.2).
- Guards for root, supported PVE 8.x/9.x and bare metal; reports current
  IOMMU state and prints verification commands.
2026-06-26 21:43:56 +02:00
31 changed files with 458 additions and 707 deletions
-204
View File
@@ -1,207 +1,3 @@
## 2026-06-27
### 🆕 New Scripts
- tool: add disk-health tool (SMART + NVMe) [@MickLesk](https://github.com/MickLesk) ([#15417](https://github.com/community-scripts/ProxmoxVE/pull/15417))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Deluge openssl fix [@asylumexp](https://github.com/asylumexp) ([#15435](https://github.com/community-scripts/ProxmoxVE/pull/15435))
- fix command syntax in tunarr.sh [@asylumexp](https://github.com/asylumexp) ([#15434](https://github.com/community-scripts/ProxmoxVE/pull/15434))
- #### 🔧 Refactor
- Storyteller: bump Node.js version to Node 24 [@thinusn](https://github.com/thinusn) ([#15439](https://github.com/community-scripts/ProxmoxVE/pull/15439))
### ❔ Uncategorized
- fix(endurain): replace Poetry/uv-pip backend setup with uv sync --frozen --no-dev [@Copilot](https://github.com/Copilot) ([#15429](https://github.com/community-scripts/ProxmoxVE/pull/15429))
## 2026-06-26
### 🚀 Updated Scripts
- Termix: Update Nginx configuration file paths [@xyzulu](https://github.com/xyzulu) ([#15397](https://github.com/community-scripts/ProxmoxVE/pull/15397))
- #### 🐞 Bug Fixes
- Docuseal: use real SECRET_KEY_BASE for db:migrate on update [@MickLesk](https://github.com/MickLesk) ([#15411](https://github.com/community-scripts/ProxmoxVE/pull/15411))
- bun: correct install for degoog [@MickLesk](https://github.com/MickLesk) ([#15412](https://github.com/community-scripts/ProxmoxVE/pull/15412))
- fix databasus update/install errors [@asylumexp](https://github.com/asylumexp) ([#15403](https://github.com/community-scripts/ProxmoxVE/pull/15403))
### 💾 Core
- #### 🐞 Bug Fixes
- tools.func: fix setup_docker - don't abort update on docker pull failure [@MickLesk](https://github.com/MickLesk) ([#15410](https://github.com/community-scripts/ProxmoxVE/pull/15410))
- fix(build.func): set /dev/kfd GID in fix_gpu_gids for AMD ROCm [@jamiej](https://github.com/jamiej) ([#15401](https://github.com/community-scripts/ProxmoxVE/pull/15401))
- fix alpine mktmp error [@asylumexp](https://github.com/asylumexp) ([#15398](https://github.com/community-scripts/ProxmoxVE/pull/15398))
### 🧰 Tools
- #### 🔧 Refactor
- Refactor: reduce IP-Tag resource usage and clean up ShellCheck findings [@MickLesk](https://github.com/MickLesk) ([#15418](https://github.com/community-scripts/ProxmoxVE/pull/15418))
- QoL: kernel-clean: Validate kernel selection input [@MickLesk](https://github.com/MickLesk) ([#15414](https://github.com/community-scripts/ProxmoxVE/pull/15414))
- QoL: clean-lxcs exclude matching and set -e cancel handling [@MickLesk](https://github.com/MickLesk) ([#15413](https://github.com/community-scripts/ProxmoxVE/pull/15413))
- QoL: Harden microcode download/install in microcode and pbs-microcode [@MickLesk](https://github.com/MickLesk) ([#15415](https://github.com/community-scripts/ProxmoxVE/pull/15415))
- QoL: scaling-governor extend selection and guard missing cpufreq [@MickLesk](https://github.com/MickLesk) ([#15416](https://github.com/community-scripts/ProxmoxVE/pull/15416))
## 2026-06-25
### 🆕 New Scripts
- Pinchflat ([#15367](https://github.com/community-scripts/ProxmoxVE/pull/15367))
### 🚀 Updated Scripts
- #### ✨ New Features
- persist gramps-web configuration file after update [@operfesium](https://github.com/operfesium) ([#15394](https://github.com/community-scripts/ProxmoxVE/pull/15394))
### 💾 Core
- #### ✨ New Features
- VM-Core: Update some Functions [@MickLesk](https://github.com/MickLesk) ([#15113](https://github.com/community-scripts/ProxmoxVE/pull/15113))
## 2026-06-24
### 🆕 New Scripts
- SnapOtter ([#15368](https://github.com/community-scripts/ProxmoxVE/pull/15368))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- enabling rewirte module in apache [@d3v3lop3rDE](https://github.com/d3v3lop3rDE) ([#15360](https://github.com/community-scripts/ProxmoxVE/pull/15360))
- watcharr: Increase default RAM allocation from 1024 to 2048 [@MickLesk](https://github.com/MickLesk) ([#15370](https://github.com/community-scripts/ProxmoxVE/pull/15370))
- #### 🔧 Refactor
- Refactor LibreNMS: replace old install and update variant with tarball approach [@MickLesk](https://github.com/MickLesk) ([#15369](https://github.com/community-scripts/ProxmoxVE/pull/15369))
### 🗑️ Deleted Scripts
- delete wger [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15380](https://github.com/community-scripts/ProxmoxVE/pull/15380))
- Delete ghost [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15377](https://github.com/community-scripts/ProxmoxVE/pull/15377))
### 💾 Core
- #### ✨ New Features
- core: add SDN vnet selection in advanced install [@MickLesk](https://github.com/MickLesk) ([#15366](https://github.com/community-scripts/ProxmoxVE/pull/15366))
- core: add var_http_proxy and var_http_no_proxy support [@MickLesk](https://github.com/MickLesk) ([#15225](https://github.com/community-scripts/ProxmoxVE/pull/15225))
## 2026-06-23
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- update jdk when updating crafty-controller [@asylumexp](https://github.com/asylumexp) ([#15349](https://github.com/community-scripts/ProxmoxVE/pull/15349))
- fix docker update function [@asylumexp](https://github.com/asylumexp) ([#15353](https://github.com/community-scripts/ProxmoxVE/pull/15353))
- LibreNMS: run daily.sh as librenms user with git available [@MickLesk](https://github.com/MickLesk) ([#15314](https://github.com/community-scripts/ProxmoxVE/pull/15314))
- #### ✨ New Features
- termix - patch tmp nginx behaviour to match the install script [@xyzulu](https://github.com/xyzulu) ([#15283](https://github.com/community-scripts/ProxmoxVE/pull/15283))
### 💾 Core
- Fix syntax error in build function [@l0caldadmin](https://github.com/l0caldadmin) ([#15337](https://github.com/community-scripts/ProxmoxVE/pull/15337))
- #### 🐞 Bug Fixes
- fix: close lxc build function [@ServerBP](https://github.com/ServerBP) ([#15343](https://github.com/community-scripts/ProxmoxVE/pull/15343))
### 🧰 Tools
- #### ✨ New Features
- [arm64] port pve scripts to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15288](https://github.com/community-scripts/ProxmoxVE/pull/15288))
### ❔ Uncategorized
- fix(build.func): remove duplicate if statement causing syntax error on container creation [@Copilot](https://github.com/Copilot) ([#15338](https://github.com/community-scripts/ProxmoxVE/pull/15338))
## 2026-06-22
### 🆕 New Scripts
- Postiz ([#15048](https://github.com/community-scripts/ProxmoxVE/pull/15048))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- invoiceshelf: use pnpm instead of yarn for frontend build [@MickLesk](https://github.com/MickLesk) ([#15312](https://github.com/community-scripts/ProxmoxVE/pull/15312))
- VictoriaMetrics: resolve architecture before jq asset filter [@MickLesk](https://github.com/MickLesk) ([#15316](https://github.com/community-scripts/ProxmoxVE/pull/15316))
- Endurain: pin uv to the version required by the project [@MickLesk](https://github.com/MickLesk) ([#15313](https://github.com/community-scripts/ProxmoxVE/pull/15313))
- add proxy headers to dispatcharr from #15143 [@asylumexp](https://github.com/asylumexp) ([#15293](https://github.com/community-scripts/ProxmoxVE/pull/15293))
- Fix-15015: check correct path for certbot [@galz55](https://github.com/galz55) ([#15034](https://github.com/community-scripts/ProxmoxVE/pull/15034))
- fix(romm): resolve 403 Forbidden error on nginx mod_zip installation [@hug-efrei](https://github.com/hug-efrei) ([#15134](https://github.com/community-scripts/ProxmoxVE/pull/15134))
- Degoog: Fix valkey url in update; set mandatory settings password [@vhsdream](https://github.com/vhsdream) ([#15300](https://github.com/community-scripts/ProxmoxVE/pull/15300))
- [arm64] fix update functions to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15290](https://github.com/community-scripts/ProxmoxVE/pull/15290))
- Fix typo in victoriametrics [@asylumexp](https://github.com/asylumexp) ([#15289](https://github.com/community-scripts/ProxmoxVE/pull/15289))
- #### ✨ New Features
- update: esphome to install and run ESPHome Device Builder [@jesserockz](https://github.com/jesserockz) ([#15195](https://github.com/community-scripts/ProxmoxVE/pull/15195))
- [arm64] Port scripts between warracker-zwavejsui to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15291](https://github.com/community-scripts/ProxmoxVE/pull/15291))
- [arm64] Port scripts between thingsboard & wanderer to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15286](https://github.com/community-scripts/ProxmoxVE/pull/15286))
- [arm64] Port scripts between snowshare & thelounge to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15280](https://github.com/community-scripts/ProxmoxVE/pull/15280))
### 💾 Core
- #### 🐞 Bug Fixes
- tools.func: refresh ruby-build when requested version is missing [@MickLesk](https://github.com/MickLesk) ([#15315](https://github.com/community-scripts/ProxmoxVE/pull/15315))
- #### ✨ New Features
- core: add pre-install storage health checks [@MickLesk](https://github.com/MickLesk) ([#15226](https://github.com/community-scripts/ProxmoxVE/pull/15226))
- #### 🔧 Refactor
- core:: skip LXC stack upgrade prompt in unattended mode [@MickLesk](https://github.com/MickLesk) ([#15319](https://github.com/community-scripts/ProxmoxVE/pull/15319))
### 🧰 Tools
- #### 🔧 Refactor
- update-apps: sanitize service detection and fail on invalid names [@MickLesk](https://github.com/MickLesk) ([#15318](https://github.com/community-scripts/ProxmoxVE/pull/15318))
## 2026-06-21
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Matomo: flatten nested deploy layout after update [@MickLesk](https://github.com/MickLesk) ([#15267](https://github.com/community-scripts/ProxmoxVE/pull/15267))
- #### ✨ New Features
- [arm64] Port scripts between qdrant & snipeit to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15274](https://github.com/community-scripts/ProxmoxVE/pull/15274))
- [arm64] Port scripts between nodered & paperlessngx to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15255](https://github.com/community-scripts/ProxmoxVE/pull/15255))
- [arm64] port scripts titled between papra and qbittorrent to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15258](https://github.com/community-scripts/ProxmoxVE/pull/15258))
- [arm64] Port scripts between mediamtx-nocodb to support arm64 [@asylumexp](https://github.com/asylumexp) ([#15254](https://github.com/community-scripts/ProxmoxVE/pull/15254))
- #### 🔧 Refactor
- tools.func: centralize Node.js corepack and npm handling in `setup_nodejs()` [@MickLesk](https://github.com/MickLesk) ([#15268](https://github.com/community-scripts/ProxmoxVE/pull/15268))
### 💾 Core
- #### 🐞 Bug Fixes
- tools.func: APT install and deb822 repo reliability [@MickLesk](https://github.com/MickLesk) ([#15272](https://github.com/community-scripts/ProxmoxVE/pull/15272))
- tools.func: prevent MySQL data loss and fix repo version matching [@MickLesk](https://github.com/MickLesk) ([#15271](https://github.com/community-scripts/ProxmoxVE/pull/15271))
- tools.func: runtime hardening for API helpers and Docker/MeiliSearch [@MickLesk](https://github.com/MickLesk) ([#15273](https://github.com/community-scripts/ProxmoxVE/pull/15273))
## 2026-06-20 ## 2026-06-20
### 🆕 New Scripts ### 🆕 New Scripts
+161 -47
View File
@@ -68,9 +68,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
@@ -84,7 +81,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
<details> <details>
<summary><h4>June (27 entries)</h4></summary> <summary><h4>June (20 entries)</h4></summary>
[View June 2026 Changelog](.github/changelogs/2026/06.md) [View June 2026 Changelog](.github/changelogs/2026/06.md)
@@ -489,35 +486,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details> </details>
## 2026-06-28
### 🚀 Updated Scripts
- #### 💥 Breaking Changes
- remove: promtail as EOL and other fixes [@asylumexp](https://github.com/asylumexp) ([#15455](https://github.com/community-scripts/ProxmoxVE/pull/15455))
## 2026-06-27
### 🆕 New Scripts
- tool: add disk-health tool (SMART + NVMe) [@MickLesk](https://github.com/MickLesk) ([#15417](https://github.com/community-scripts/ProxmoxVE/pull/15417))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Deluge openssl fix [@asylumexp](https://github.com/asylumexp) ([#15435](https://github.com/community-scripts/ProxmoxVE/pull/15435))
- fix command syntax in tunarr.sh [@asylumexp](https://github.com/asylumexp) ([#15434](https://github.com/community-scripts/ProxmoxVE/pull/15434))
- #### 🔧 Refactor
- Storyteller: bump Node.js version to Node 24 [@thinusn](https://github.com/thinusn) ([#15439](https://github.com/community-scripts/ProxmoxVE/pull/15439))
### ❔ Uncategorized
- fix(endurain): replace Poetry/uv-pip backend setup with uv sync --frozen --no-dev [@Copilot](https://github.com/Copilot) ([#15429](https://github.com/community-scripts/ProxmoxVE/pull/15429))
## 2026-06-26 ## 2026-06-26
### 🚀 Updated Scripts ### 🚀 Updated Scripts
@@ -526,28 +494,15 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- #### 🐞 Bug Fixes - #### 🐞 Bug Fixes
- Docuseal: use real SECRET_KEY_BASE for db:migrate on update [@MickLesk](https://github.com/MickLesk) ([#15411](https://github.com/community-scripts/ProxmoxVE/pull/15411))
- bun: correct install for degoog [@MickLesk](https://github.com/MickLesk) ([#15412](https://github.com/community-scripts/ProxmoxVE/pull/15412))
- fix databasus update/install errors [@asylumexp](https://github.com/asylumexp) ([#15403](https://github.com/community-scripts/ProxmoxVE/pull/15403)) - fix databasus update/install errors [@asylumexp](https://github.com/asylumexp) ([#15403](https://github.com/community-scripts/ProxmoxVE/pull/15403))
### 💾 Core ### 💾 Core
- #### 🐞 Bug Fixes - #### 🐞 Bug Fixes
- tools.func: fix setup_docker - don't abort update on docker pull failure [@MickLesk](https://github.com/MickLesk) ([#15410](https://github.com/community-scripts/ProxmoxVE/pull/15410))
- fix(build.func): set /dev/kfd GID in fix_gpu_gids for AMD ROCm [@jamiej](https://github.com/jamiej) ([#15401](https://github.com/community-scripts/ProxmoxVE/pull/15401)) - fix(build.func): set /dev/kfd GID in fix_gpu_gids for AMD ROCm [@jamiej](https://github.com/jamiej) ([#15401](https://github.com/community-scripts/ProxmoxVE/pull/15401))
- fix alpine mktmp error [@asylumexp](https://github.com/asylumexp) ([#15398](https://github.com/community-scripts/ProxmoxVE/pull/15398)) - fix alpine mktmp error [@asylumexp](https://github.com/asylumexp) ([#15398](https://github.com/community-scripts/ProxmoxVE/pull/15398))
### 🧰 Tools
- #### 🔧 Refactor
- Refactor: reduce IP-Tag resource usage and clean up ShellCheck findings [@MickLesk](https://github.com/MickLesk) ([#15418](https://github.com/community-scripts/ProxmoxVE/pull/15418))
- QoL: kernel-clean: Validate kernel selection input [@MickLesk](https://github.com/MickLesk) ([#15414](https://github.com/community-scripts/ProxmoxVE/pull/15414))
- QoL: clean-lxcs exclude matching and set -e cancel handling [@MickLesk](https://github.com/MickLesk) ([#15413](https://github.com/community-scripts/ProxmoxVE/pull/15413))
- QoL: Harden microcode download/install in microcode and pbs-microcode [@MickLesk](https://github.com/MickLesk) ([#15415](https://github.com/community-scripts/ProxmoxVE/pull/15415))
- QoL: scaling-governor extend selection and guard missing cpufreq [@MickLesk](https://github.com/MickLesk) ([#15416](https://github.com/community-scripts/ProxmoxVE/pull/15416))
## 2026-06-25 ## 2026-06-25
### 🆕 New Scripts ### 🆕 New Scripts
@@ -1139,4 +1094,163 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- #### 🔧 Refactor - #### 🔧 Refactor
- Sure: Remove `$STD` for `systemctl enable -q` [@tremor021](https://github.com/tremor021) ([#14801](https://github.com/community-scripts/ProxmoxVE/pull/14801)) - Sure: Remove `$STD` for `systemctl enable -q` [@tremor021](https://github.com/tremor021) ([#14801](https://github.com/community-scripts/ProxmoxVE/pull/14801))
## 2026-05-28
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- RomM: remove nginx default.conf during installation [@MickLesk](https://github.com/MickLesk) ([#14766](https://github.com/community-scripts/ProxmoxVE/pull/14766))
- Open-Archiver: replace pnpm approve-builds --yes with --all [@MickLesk](https://github.com/MickLesk) ([#14765](https://github.com/community-scripts/ProxmoxVE/pull/14765))
- fix(hermesagent): set npm_config_yes=true to suppress interactive pro… [@steveonjava](https://github.com/steveonjava) ([#14763](https://github.com/community-scripts/ProxmoxVE/pull/14763))
- #### 🔧 Refactor
- Yamtrack: migrate to uv [@MickLesk](https://github.com/MickLesk) ([#14767](https://github.com/community-scripts/ProxmoxVE/pull/14767))
### ❔ Uncategorized
- chore(ct): sync adventurelog defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#14772](https://github.com/community-scripts/ProxmoxVE/pull/14772))
## 2026-05-27
### 🆕 New Scripts
- MusicSeerr ([#14746](https://github.com/community-scripts/ProxmoxVE/pull/14746))
- Hermes Agent ([#14751](https://github.com/community-scripts/ProxmoxVE/pull/14751))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- grist: restore install:ee step [@paulfitz](https://github.com/paulfitz) ([#14759](https://github.com/community-scripts/ProxmoxVE/pull/14759))
### 💾 Core
- #### 🐞 Bug Fixes
- [tools.func]: `setup_gs()` fix getting dotted release format [@tremor021](https://github.com/tremor021) ([#14745](https://github.com/community-scripts/ProxmoxVE/pull/14745))
## 2026-05-26
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Add directory creation to Profilarr update script [@ryansully](https://github.com/ryansully) ([#14740](https://github.com/community-scripts/ProxmoxVE/pull/14740))
- profilarr: Fix ARCH assignment in profilarr.sh to support Profilarr build usage [@mpeleshenko](https://github.com/mpeleshenko) ([#14709](https://github.com/community-scripts/ProxmoxVE/pull/14709))
- Jackett: Remove quotes in Service File [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14729](https://github.com/community-scripts/ProxmoxVE/pull/14729))
- Open-archiver: approve pnpm build scripts and run build:oss without subshell [@MickLesk](https://github.com/MickLesk) ([#14711](https://github.com/community-scripts/ProxmoxVE/pull/14711))
- Docuseal: read Ruby version from Gemfile, upgrade on update if needed [@MickLesk](https://github.com/MickLesk) ([#14715](https://github.com/community-scripts/ProxmoxVE/pull/14715))
- #### ✨ New Features
- Birdnet-GO: install libonnxruntime.so from release tarball [@MickLesk](https://github.com/MickLesk) ([#14716](https://github.com/community-scripts/ProxmoxVE/pull/14716))
### 💾 Core
- #### ✨ New Features
- tools.func: better error diagnostics, consistent OS detection, setup function ordering [@MickLesk](https://github.com/MickLesk) ([#14692](https://github.com/community-scripts/ProxmoxVE/pull/14692))
### 🧰 Tools
- #### 🐞 Bug Fixes
- IPTag-Tool: use qm set for VM tags to handle snapshot sections crrectly [@MickLesk](https://github.com/MickLesk) ([#14713](https://github.com/community-scripts/ProxmoxVE/pull/14713))
- #### ✨ New Features
- Netdata: extend PVE version support to 9.x [@MickLesk](https://github.com/MickLesk) ([#14714](https://github.com/community-scripts/ProxmoxVE/pull/14714))
## 2026-05-25
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- karakeep: fix: pip config [@CrazyWolf13](https://github.com/CrazyWolf13) ([#14703](https://github.com/community-scripts/ProxmoxVE/pull/14703))
### 💾 Core
- #### ✨ New Features
- tools.func: replace raw GitHub API curl calls with get_latest_github_release [@MickLesk](https://github.com/MickLesk) ([#14690](https://github.com/community-scripts/ProxmoxVE/pull/14690))
### 🧰 Tools
- #### 🔧 Refactor
- Kernel-Clean: detect meta-packages and fix silent removal failures [@MickLesk](https://github.com/MickLesk) ([#14674](https://github.com/community-scripts/ProxmoxVE/pull/14674))
## 2026-05-24
### 🚀 Updated Scripts
- #### ✨ New Features
- RomM: add installation steps for Nginx mod_zip module [@MickLesk](https://github.com/MickLesk) ([#14678](https://github.com/community-scripts/ProxmoxVE/pull/14678))
- ISponsorblockTV: detect CPU capabilities to select compatible binary [@MickLesk](https://github.com/MickLesk) ([#14677](https://github.com/community-scripts/ProxmoxVE/pull/14677))
- #### 🔧 Refactor
- Refactor: MQTT [@tremor021](https://github.com/tremor021) ([#14673](https://github.com/community-scripts/ProxmoxVE/pull/14673))
## 2026-05-23
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- IronClaw: Extra configuration during install to ensure Web Gateway can run [@SystemIdleProcess](https://github.com/SystemIdleProcess) ([#14635](https://github.com/community-scripts/ProxmoxVE/pull/14635))
- Tunarr: fix path to backup during update [@SystemIdleProcess](https://github.com/SystemIdleProcess) ([#14655](https://github.com/community-scripts/ProxmoxVE/pull/14655))
- #### ✨ New Features
- wealthfolio: add: prebuild [@CrazyWolf13](https://github.com/CrazyWolf13) ([#14658](https://github.com/community-scripts/ProxmoxVE/pull/14658))
### 🧰 Tools
- #### ✨ New Features
- kernel-clean: support range syntax in selection prompt [@djhojd](https://github.com/djhojd) ([#14656](https://github.com/community-scripts/ProxmoxVE/pull/14656))
## 2026-05-22
### 🆕 New Scripts
- bitfocus-companion ([#14603](https://github.com/community-scripts/ProxmoxVE/pull/14603))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix(the-lounge): install Node.js 22 before deb package [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14648](https://github.com/community-scripts/ProxmoxVE/pull/14648))
- Docmost: Fix duplicate STORAGE_DRIVER [@MickLesk](https://github.com/MickLesk) ([#14645](https://github.com/community-scripts/ProxmoxVE/pull/14645))
- Profilarr: pin Deno version to v2.7.5 [@MickLesk](https://github.com/MickLesk) ([#14632](https://github.com/community-scripts/ProxmoxVE/pull/14632))
- #### ✨ New Features
- add: karakeep cli wrapper [@CrazyWolf13](https://github.com/CrazyWolf13) ([#14618](https://github.com/community-scripts/ProxmoxVE/pull/14618))
- #### 💥 Breaking Changes
- OpenCloud: v7.0.0 changes [@vhsdream](https://github.com/vhsdream) ([#14650](https://github.com/community-scripts/ProxmoxVE/pull/14650))
- #### 🔧 Refactor
- workflows: update workflows, templates to support arm64. [@asylumexp](https://github.com/asylumexp) ([#14653](https://github.com/community-scripts/ProxmoxVE/pull/14653))
- SoulSync: setup Node v22 and build WebUI [@MickLesk](https://github.com/MickLesk) ([#14639](https://github.com/community-scripts/ProxmoxVE/pull/14639))
- Refactor: Dispatcharr [@MickLesk](https://github.com/MickLesk) ([#14313](https://github.com/community-scripts/ProxmoxVE/pull/14313))
### 💾 Core
- #### 🐞 Bug Fixes
- fix: make LXC banner OS detection dynamic via /etc/os-release [@atahan99](https://github.com/atahan99) ([#14269](https://github.com/community-scripts/ProxmoxVE/pull/14269))
- #### 🔧 Refactor
- core: suppress MOTD for non-interactive shells [@MickLesk](https://github.com/MickLesk) ([#14638](https://github.com/community-scripts/ProxmoxVE/pull/14638))
+2
View File
@@ -58,3 +58,5 @@ msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW}Access it using the following URL:${CL}" echo -e "${INFO}${YW}Access it using the following URL:${CL}"
echo -e "${GATEWAY}${BGN}http://${IP}:3100${CL}" echo -e "${GATEWAY}${BGN}http://${IP}:3100${CL}"
echo -e "${INFO}${YW}Access Promtail using the following URL:${CL}"
echo -e "${GATEWAY}${BGN}http://${IP}:9080${CL}"
+2 -2
View File
@@ -38,7 +38,7 @@ function update_script() {
create_backup /opt/degoog/.env \ create_backup /opt/degoog/.env \
/opt/degoog/data /opt/degoog/data
if [[ ! -x /root/.bun/bin/bun ]]; then if ! command -v bun >/dev/null 2>&1; then
msg_info "Installing Bun" msg_info "Installing Bun"
export BUN_INSTALL="/root/.bun" export BUN_INSTALL="/root/.bun"
curl -fsSL https://bun.sh/install | $STD bash curl -fsSL https://bun.sh/install | $STD bash
@@ -52,7 +52,7 @@ function update_script() {
msg_ok "Updated Valkey" msg_ok "Updated Valkey"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "degoog" "fccview/degoog" "prebuild" "latest" "/opt/degoog" "degoog_*_prebuild.tar.gz" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "degoog" "fccview/degoog" "prebuild" "latest" "/opt/degoog" "degoog_*_prebuild.tar.gz"
fetch_and_deploy_gh_release "curl-impersonate" "lexiforest/curl-impersonate" "prebuild" "latest" "/usr/local/bin" "curl-impersonate-v*.$(uname -m)-linux-gnu.tar.gz" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "curl-impersonate" "lexiforest/curl-impersonate" "prebuild" "latest" "/usr/local/bin" "curl-impersonate-v*.$(uname -m)-linux-gnu.tar.gz"
restore_backup restore_backup
+2 -2
View File
@@ -12,7 +12,7 @@ var_ram="${var_ram:-2048}"
var_disk="${var_disk:-4}" var_disk="${var_disk:-4}"
var_os="${var_os:-debian}" var_os="${var_os:-debian}"
var_version="${var_version:-13}" var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
header_info "$APP" header_info "$APP"
@@ -31,7 +31,7 @@ function update_script() {
msg_info "Updating Deluge" msg_info "Updating Deluge"
ensure_dependencies python3-setuptools ensure_dependencies python3-setuptools
$STD apt update $STD apt update
$STD pip3 install deluge[all] "pyopenssl<25" --upgrade $STD pip3 install deluge[all] --upgrade
msg_ok "Updated Deluge" msg_ok "Updated Deluge"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
exit exit
+1 -1
View File
@@ -55,7 +55,7 @@ function update_script() {
eval "$(rbenv init - bash)" 2>/dev/null || true eval "$(rbenv init - bash)" 2>/dev/null || true
export RAILS_ENV=production export RAILS_ENV=production
export NODE_ENV=production export NODE_ENV=production
mkdir -p /opt/docuseal/tmp export SECRET_KEY_BASE_DUMMY=1
set -a set -a
source /opt/docuseal/.env source /opt/docuseal/.env
set +a set +a
+4 -1
View File
@@ -63,7 +63,10 @@ function update_script() {
cd /opt/endurain/backend cd /opt/endurain/backend
UV_VERSION=$(grep -Po 'required-version\s*=\s*"\K[^"]+' pyproject.toml 2>/dev/null || echo "0.11.18") UV_VERSION=$(grep -Po 'required-version\s*=\s*"\K[^"]+' pyproject.toml 2>/dev/null || echo "0.11.18")
UV_VERSION="$UV_VERSION" setup_uv UV_VERSION="$UV_VERSION" setup_uv
$STD uv sync --frozen --no-dev $STD poetry export -f requirements.txt --output requirements.txt --without-hashes
$STD uv venv --clear
$STD uv pip install -r requirements.txt
$STD uv pip install pytz
msg_ok "Backend Updated" msg_ok "Backend Updated"
msg_info "Starting Service" msg_info "Starting Service"
-69
View File
@@ -1,69 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: CrazyWolf13
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/pawelmalak/flame
APP="Flame"
var_tags="${var_tags:-dashboard;startpage}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/flame ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "flame" "pawelmalak/flame"; then
msg_info "Stopping Service"
systemctl stop flame
msg_ok "Stopped Service"
create_backup /opt/flame/.env \
/opt/flame/data
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "flame" "pawelmalak/flame" "tarball"
restore_backup
msg_info "Rebuilding Application"
cd /opt/flame
mkdir -p data public
$STD npm install --production
cd /opt/flame/client
$STD npm install --production
$STD npm run build
cd /opt/flame
cp -r client/build/. public/
msg_ok "Rebuilt Application"
msg_info "Starting Service"
systemctl start flame
msg_ok "Started Service"
msg_ok "Updated successfully!"
fi
exit
}
start
build_container
description
msg_ok "Completed Successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5005${CL}"
-6
View File
@@ -1,6 +0,0 @@
________
/ ____/ /___ _____ ___ ___
/ /_ / / __ `/ __ `__ \/ _ \
/ __/ / / /_/ / / / / / / __/
/_/ /_/\__,_/_/ /_/ /_/\___/
+14 -1
View File
@@ -31,7 +31,7 @@ function update_script() {
fi fi
CHOICE=$(msg_menu "Loki Update Options" \ CHOICE=$(msg_menu "Loki Update Options" \
"1" "Update Loki" \ "1" "Update Loki & Promtail" \
"2" "Allow 0.0.0.0 for listening" \ "2" "Allow 0.0.0.0 for listening" \
"3" "Allow only ${LOCAL_IP} for listening") "3" "Allow only ${LOCAL_IP} for listening")
@@ -39,15 +39,24 @@ function update_script() {
1) 1)
msg_info "Stopping Loki" msg_info "Stopping Loki"
systemctl stop loki systemctl stop loki
if systemctl is-active --quiet promtail 2>/dev/null || dpkg -s promtail >/dev/null 2>&1; then
systemctl stop promtail
fi
msg_ok "Stopped Loki" msg_ok "Stopped Loki"
msg_info "Updating Loki" msg_info "Updating Loki"
$STD apt update $STD apt update
$STD apt install -y --only-upgrade loki $STD apt install -y --only-upgrade loki
if dpkg -s promtail >/dev/null 2>&1; then
$STD apt install -y --only-upgrade promtail
fi
msg_ok "Updated Loki" msg_ok "Updated Loki"
msg_info "Starting Loki" msg_info "Starting Loki"
systemctl start loki systemctl start loki
if dpkg -s promtail >/dev/null 2>&1; then
systemctl start promtail
fi
msg_ok "Started Loki" msg_ok "Started Loki"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
exit exit
@@ -80,3 +89,7 @@ msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access loki using the following URL:${CL}" echo -e "${INFO}${YW} Access loki using the following URL:${CL}"
echo -e "${GATEWAY}${BGN}http://${IP}:3100${CL}\n" echo -e "${GATEWAY}${BGN}http://${IP}:3100${CL}\n"
if dpkg -s promtail >/dev/null 2>&1; then
echo -e "${INFO}${YW} Access promtail using the following URL:${CL}"
echo -e "${GATEWAY}${BGN}http://${IP}:9080${CL}"
fi
-3
View File
@@ -235,9 +235,6 @@ EOF
fi fi
sed -i 's/user npm/user root/g; s/^pid/#pid/g' /usr/local/openresty/nginx/conf/nginx.conf sed -i 's/user npm/user root/g; s/^pid/#pid/g' /usr/local/openresty/nginx/conf/nginx.conf
sed -r -i 's/^([[:space:]]*)su npm npm/\1#su npm npm/g;' /etc/logrotate.d/nginx-proxy-manager sed -r -i 's/^([[:space:]]*)su npm npm/\1#su npm npm/g;' /etc/logrotate.d/nginx-proxy-manager
if [ -n "$(command -v node)" ]; then
sed -i -E "s|^ExecStart=.*/node index\.js|ExecStart=$(command -v node) index.js|" /lib/systemd/system/npm.service
fi
systemctl daemon-reload systemctl daemon-reload
systemctl enable -q --now openresty systemctl enable -q --now openresty
systemctl enable -q --now npm systemctl enable -q --now npm
+1 -1
View File
@@ -39,7 +39,7 @@ function update_script() {
JAVA_VERSION="21" setup_java JAVA_VERSION="21" setup_java
OMADA_URL=$(curl -fsSL -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.5 Safari/605.1.15" "https://support.omadanetworks.com/en/download/software/omada-controller/" | OMADA_URL=$(curl -fsSL "https://support.omadanetworks.com/en/download/software/omada-controller/" |
grep -o 'https://static\.tp-link\.com/upload/software/[^"]*linux_x64[^"]*\.deb' | grep -o 'https://static\.tp-link\.com/upload/software/[^"]*linux_x64[^"]*\.deb' |
head -n1) head -n1)
OMADA_PKG=$(basename "${OMADA_URL}") OMADA_PKG=$(basename "${OMADA_URL}")
-2
View File
@@ -30,8 +30,6 @@ function update_script() {
exit exit
fi fi
NODE_VERSION="24" NODE_MODULE="corepack,yarn" setup_nodejs
if check_for_gl_release "storyteller" "storyteller-platform/storyteller"; then if check_for_gl_release "storyteller" "storyteller-platform/storyteller"; then
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop storyteller systemctl stop storyteller
+7 -2
View File
@@ -33,12 +33,17 @@ function update_script() {
systemctl stop tunarr systemctl stop tunarr
msg_ok "Stopped Service" msg_ok "Stopped Service"
create_backup /root/.local/share/tunarr msg_info "Creating Backup"
if [ -d "/root/.local/share/tunarr" ]; then
tar -czf "/opt/${APP}_backup_$(date +%F).tar.gz" /root/.local/share/tunarr $STD
msg_ok "Backup Created"
else
msg_error "Backup failed: /root/.local/share/tunarr does not exist"
fi
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "tunarr" "chrisbenincasa/tunarr" "prebuild" "latest" "/opt/tunarr" "*linux-$(arch_resolve "x64" "arm64").tar.gz" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "tunarr" "chrisbenincasa/tunarr" "prebuild" "latest" "/opt/tunarr" "*linux-$(arch_resolve "x64" "arm64").tar.gz"
cd /opt/tunarr cd /opt/tunarr
mv tunarr* tunarr mv tunarr* tunarr
restore_backup
msg_info "Starting Service" msg_info "Starting Service"
systemctl start tunarr systemctl start tunarr
+1 -1
View File
@@ -29,7 +29,7 @@ function update_script() {
fi fi
if check_for_gh_release "wishlist" "cmintey/wishlist"; then if check_for_gh_release "wishlist" "cmintey/wishlist"; then
NODE_VERSION="24" NODE_MODULE="pnpm@11" setup_nodejs NODE_VERSION="24" NODE_MODULE="pnpm" setup_nodejs
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop wishlist systemctl stop wishlist
+10
View File
@@ -71,6 +71,16 @@ $STD rc-update add loki default
$STD rc-service loki start $STD rc-service loki start
msg_ok "Installed Loki" msg_ok "Installed Loki"
read -rp "Would you like to install Promtail? (y/N): " INSTALL_PROMTAIL
if [[ "${INSTALL_PROMTAIL,,}" =~ ^(y|yes)$ ]]; then
msg_info "Installing Promtail"
$STD apk add loki-promtail
$STD sed -i '/http_addr/s/127.0.0.1/0.0.0.0/g' /etc/conf.d/loki-promtail
$STD rc-update add loki-promtail default
$STD rc-service loki-promtail start
msg_ok "Installed Promtail"
fi
motd_ssh motd_ssh
customize customize
cleanup_lxc cleanup_lxc
+1 -1
View File
@@ -26,7 +26,7 @@ cat >~/.config/pip/pip.conf <<EOF
[global] [global]
break-system-packages = true break-system-packages = true
EOF EOF
$STD pip install deluge[all] "pyopenssl<25" $STD pip install deluge[all]
msg_ok "Installed Deluge" msg_ok "Installed Deluge"
msg_info "Creating Service" msg_info "Creating Service"
+8 -1
View File
@@ -83,7 +83,14 @@ msg_info "Setting up Backend"
cd /opt/endurain/backend cd /opt/endurain/backend
UV_VERSION=$(grep -Po 'required-version\s*=\s*"\K[^"]+' pyproject.toml 2>/dev/null || echo "0.11.18") UV_VERSION=$(grep -Po 'required-version\s*=\s*"\K[^"]+' pyproject.toml 2>/dev/null || echo "0.11.18")
UV_VERSION="$UV_VERSION" setup_uv UV_VERSION="$UV_VERSION" setup_uv
$STD uv sync --frozen --no-dev $STD uv tool install poetry
$STD uv tool update-shell
export PATH="/root/.local/bin:$PATH"
$STD poetry self add poetry-plugin-export
$STD poetry export -f requirements.txt --output requirements.txt --without-hashes
$STD uv venv --clear
$STD uv pip install -r requirements.txt
$STD uv pip install pytz
msg_ok "Setup Backend" msg_ok "Setup Backend"
msg_info "Creating Service" msg_info "Creating Service"
-62
View File
@@ -1,62 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: CrazyWolf13
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/pawelmalak/flame
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt install -y build-essential
msg_ok "Installed Dependencies"
NODE_VERSION="22" setup_nodejs
fetch_and_deploy_gh_release "flame" "pawelmalak/flame" "tarball"
msg_info "Setting up Flame"
cd /opt/flame
mkdir -p data public
$STD npm install --production
cd /opt/flame/client
$STD npm install --production
$STD npm run build
cd /opt/flame
cp -r client/build/. public/
FLAME_VERSION=$(cat ~/.flame)
cat <<EOF >/opt/flame/.env
NODE_ENV=production
VERSION=${FLAME_VERSION}
PASSWORD=
EOF
msg_ok "Set up Flame"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/flame.service
[Unit]
Description=Flame Startpage
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/flame
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now flame
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
+8
View File
@@ -70,6 +70,14 @@ chown loki /etc/loki/config.yml
systemctl enable -q --now loki systemctl enable -q --now loki
msg_ok "Installed Loki" msg_ok "Installed Loki"
read -rp "Would you like to install Promtail? (y/N): " INSTALL_PROMTAIL
if [[ "${INSTALL_PROMTAIL,,}" =~ ^(y|yes)$ ]]; then
msg_info "Installing Promtail"
$STD apt install -y promtail
systemctl enable -q --now promtail
msg_ok "Installed Promtail"
fi
motd_ssh motd_ssh
customize customize
cleanup_lxc cleanup_lxc
+1 -1
View File
@@ -35,7 +35,7 @@ if ! dpkg -l | grep -q 'libssl1.1'; then
fi fi
msg_info "Installing Omada Controller" msg_info "Installing Omada Controller"
OMADA_URL=$(curl -fsSL -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.5 Safari/605.1.15" "https://support.omadanetworks.com/en/download/software/omada-controller/" | OMADA_URL=$(curl -fsSL "https://support.omadanetworks.com/en/download/software/omada-controller/" |
grep -o 'https://static\.tp-link\.com/upload/software/[^"]*linux_x64[^"]*\.deb' | grep -o 'https://static\.tp-link\.com/upload/software/[^"]*linux_x64[^"]*\.deb' |
head -n1) head -n1)
OMADA_PKG=$(basename "${OMADA_URL}") OMADA_PKG=$(basename "${OMADA_URL}")
+1 -1
View File
@@ -24,7 +24,7 @@ $STD apt install -y \
ffmpeg ffmpeg
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
NODE_VERSION="24" NODE_MODULE="corepack,yarn" setup_nodejs NODE_VERSION="22" NODE_MODULE="corepack,yarn" setup_nodejs
fetch_and_deploy_gh_release "readium" "readium/cli" "prebuild" "latest" "/opt/readium" "readium_linux_$(arch_resolve "x86_64" "arm64").tar.gz" fetch_and_deploy_gh_release "readium" "readium/cli" "prebuild" "latest" "/opt/readium" "readium_linux_$(arch_resolve "x86_64" "arm64").tar.gz"
ln -sf /opt/readium/readium /usr/local/bin/readium ln -sf /opt/readium/readium /usr/local/bin/readium
+7 -7
View File
@@ -4614,11 +4614,11 @@ EOF
local image=$(echo "$container" | awk '{print $2}') local image=$(echo "$container" | awk '{print $2}')
local current_digest=$(docker inspect "$name" --format='{{.Image}}' 2>/dev/null | cut -d':' -f2 | cut -c1-12) local current_digest=$(docker inspect "$name" --format='{{.Image}}' 2>/dev/null | cut -d':' -f2 | cut -c1-12)
# Pull latest image digest (ignore failures, e.g. local-only images or registry/permission issues) # Pull latest image digest
docker pull "$image" >/dev/null 2>&1 || true docker pull "$image" >/dev/null 2>&1
local latest_digest=$(docker inspect "$image" --format='{{.Id}}' 2>/dev/null | cut -d':' -f2 | cut -c1-12) local latest_digest=$(docker inspect "$image" --format='{{.Id}}' 2>/dev/null | cut -d':' -f2 | cut -c1-12)
if [ -n "$latest_digest" ] && [ "$current_digest" != "$latest_digest" ]; then if [ "$current_digest" != "$latest_digest" ]; then
containers_with_updates+=("$name") containers_with_updates+=("$name")
container_info+=("${index}) ${name} (${image})") container_info+=("${index}) ${name} (${image})")
((index++)) ((index++))
@@ -7561,8 +7561,8 @@ setup_nodejs() {
} }
# Install global Node modules # Install global Node modules
if [[ -n "$NODE_MODULE" ]] || ((node_major >= 25)); then if [[ -n "$NODE_MODULE" ]] || (( node_major >= 25 )); then
if ((node_major >= 25)) && [[ ",${NODE_MODULE}," != *",corepack,"* ]] && [[ "$NODE_MODULE" != corepack* ]]; then if (( node_major >= 25 )) && [[ ",${NODE_MODULE}," != *",corepack,"* ]] && [[ "$NODE_MODULE" != corepack* ]]; then
NODE_MODULE="${NODE_MODULE:+$NODE_MODULE,}corepack" NODE_MODULE="${NODE_MODULE:+$NODE_MODULE,}corepack"
fi fi
@@ -7624,12 +7624,12 @@ setup_nodejs() {
fi fi
fi fi
done done
if ((failed_modules > 0)); then if (( failed_modules > 0 )); then
msg_warn "$failed_modules Node.js module(s) failed: $NODE_MODULE" msg_warn "$failed_modules Node.js module(s) failed: $NODE_MODULE"
fi fi
fi fi
if [[ "$NODE_COREPACK_ENABLE" == "1" ]] && ((wants_corepack)) && command -v corepack >/dev/null 2>&1; then if [[ "$NODE_COREPACK_ENABLE" == "1" ]] && (( wants_corepack )) && command -v corepack >/dev/null 2>&1; then
msg_info "Enabling corepack" msg_info "Enabling corepack"
if $STD corepack enable 2>/dev/null; then if $STD corepack enable 2>/dev/null; then
msg_ok "Enabled corepack" msg_ok "Enabled corepack"
+32 -72
View File
@@ -22,10 +22,10 @@ APP="IP-Tag"
hostname=$(hostname) hostname=$(hostname)
# Color variables # Color variables
YW="\033[33m" YW=$(echo "\033[33m")
GN="\033[1;92m" GN=$(echo "\033[1;92m")
RD="\033[01;31m" RD=$(echo "\033[01;31m")
CL="\033[m" CL=$(echo "\033[m")
BFR="\\r\\033[K" BFR="\\r\\033[K"
HOLD=" " HOLD=" "
CM="${GN}${CL} " CM="${GN}${CL} "
@@ -127,7 +127,7 @@ update_installation() {
echo -e "\n${YW}Configuration file already exists.${CL}" echo -e "\n${YW}Configuration file already exists.${CL}"
echo -e "${YW}Note: No critical changes were made in this version.${CL}" echo -e "${YW}Note: No critical changes were made in this version.${CL}"
while true; do while true; do
read -rp "Do you want to replace it with defaults? (y/n): " yn read -p "Do you want to replace it with defaults? (y/n): " yn
case $yn in case $yn in
[Yy]*) [Yy]*)
interactive_config_setup interactive_config_setup
@@ -176,7 +176,7 @@ export FORCE_SINGLE_RUN=true
exec "$SCRIPT_FILE" exec "$SCRIPT_FILE"
EOF EOF
chmod +x /usr/local/bin/iptag-run chmod +x /usr/local/bin/iptag-run
msg_ok "Created iptag-run executable - You can execute this manually by entering 'iptag-run' in the Proxmox host, so the script is executed by hand." msg_ok "Created iptag-run executable - You can execute this manually by entering iptag-run in the Proxmox host, so the script is executed by hand."
msg_info "Restarting service" msg_info "Restarting service"
systemctl daemon-reload &>/dev/null systemctl daemon-reload &>/dev/null
@@ -208,7 +208,7 @@ install_command_only() {
else else
stop_spinner stop_spinner
echo -e "\n${YW}Configuration file already exists.${CL}" echo -e "\n${YW}Configuration file already exists.${CL}"
read -rp "Do you want to reconfigure tag format? (y/n): " reconfigure read -p "Do you want to reconfigure tag format? (y/n): " reconfigure
case $reconfigure in case $reconfigure in
[Yy]*) [Yy]*)
interactive_config_setup_command interactive_config_setup_command
@@ -285,7 +285,7 @@ interactive_config_setup_command() {
echo -e "${GN}3)${CL} full - Show full IP address (e.g., 192.168.0.100)" echo -e "${GN}3)${CL} full - Show full IP address (e.g., 192.168.0.100)"
while true; do while true; do
read -rp "Enter your choice (1-3) [1]: " tag_choice read -p "Enter your choice (1-3) [1]: " tag_choice
case ${tag_choice:-1} in case ${tag_choice:-1} in
1) 1)
TAG_FORMAT="last_two_octets" TAG_FORMAT="last_two_octets"
@@ -323,7 +323,7 @@ interactive_config_setup() {
echo -e "${GN}3)${CL} full - Show full IP address (e.g., 192.168.0.100)" echo -e "${GN}3)${CL} full - Show full IP address (e.g., 192.168.0.100)"
while true; do while true; do
read -rp "Enter your choice (1-3) [1]: " tag_choice read -p "Enter your choice (1-3) [1]: " tag_choice
case ${tag_choice:-1} in case ${tag_choice:-1} in
1) 1)
TAG_FORMAT="last_two_octets" TAG_FORMAT="last_two_octets"
@@ -352,7 +352,7 @@ interactive_config_setup() {
echo -e "${YW}Recommended range: 300-3600 seconds${CL}" echo -e "${YW}Recommended range: 300-3600 seconds${CL}"
while true; do while true; do
read -rp "Enter interval in seconds [300]: " interval_input read -p "Enter interval in seconds [300]: " interval_input
interval_input=${interval_input:-300} interval_input=${interval_input:-300}
if [[ $interval_input =~ ^[0-9]+$ ]] && [ $interval_input -ge 300 ] && [ $interval_input -le 7200 ]; then if [[ $interval_input =~ ^[0-9]+$ ]] && [ $interval_input -ge 300 ] && [ $interval_input -le 7200 ]; then
@@ -563,10 +563,9 @@ get_vm_ips() {
debug_log "vm $vmid: starting IP detection" debug_log "vm $vmid: starting IP detection"
# Check if VM is running first (status comes from the cached `qm list`, # Check if VM is running first
# falling back to `qm status` only when called outside the normal cycle). local vm_status=""
local vm_status="${STATUS_CACHE[vm_${vmid}]:-}" if command -v qm >/dev/null 2>&1; then
if [[ -z "$vm_status" ]] && command -v qm >/dev/null 2>&1; then
vm_status=$(qm status "$vmid" 2>/dev/null | awk '{print $2}') vm_status=$(qm status "$vmid" 2>/dev/null | awk '{print $2}')
fi fi
@@ -579,43 +578,33 @@ get_vm_ips() {
local mac_addresses=$(grep -E "^net[0-9]+:" "$vm_config" | grep -oE "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}" | head -3) local mac_addresses=$(grep -E "^net[0-9]+:" "$vm_config" | grep -oE "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}" | head -3)
debug_log "vm $vmid: found MACs: $mac_addresses" debug_log "vm $vmid: found MACs: $mac_addresses"
# Method 1: QEMU guest agent (most reliable for current IP). Only query it # Method 1: QM guest agent (most reliable for current IP)
# when the agent is actually enabled in the VM config, otherwise the call if command -v qm >/dev/null 2>&1; then
# blocks until the timeout on every VM without an agent. debug_log "vm $vmid: trying qm guest agent first"
local agent_enabled=0 local qm_ips=$(timeout 8 qm guest cmd "$vmid" network-get-interfaces 2>/dev/null | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | grep -v "127.0.0.1" | head -3)
if [[ "$(grep -E '^agent:' "$vm_config" 2>/dev/null)" =~ (^agent:[[:space:]]*1|enabled=1) ]]; then
agent_enabled=1
fi
if [[ "$agent_enabled" == "1" ]] && command -v qm >/dev/null 2>&1; then
debug_log "vm $vmid: querying guest agent"
local qm_ips=$(timeout 5 qm guest cmd "$vmid" network-get-interfaces 2>/dev/null | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | grep -v "127.0.0.1" | head -3)
for qm_ip in $qm_ips; do for qm_ip in $qm_ips; do
if [[ "$qm_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then if [[ "$qm_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
debug_log "vm $vmid: found IP $qm_ip via qm guest cmd" debug_log "vm $vmid: found IP $qm_ip via qm guest cmd"
ips+="$qm_ip " ips+="$qm_ip "
fi fi
done done
else
debug_log "vm $vmid: guest agent not enabled, skipping qm guest cmd"
fi fi
# Method 2: ARP table lookup (only if the guest agent gave us nothing). # Method 2: Fresh ARP table lookup (force refresh)
if [[ -z "$ips" && -n "$mac_addresses" ]]; then if [[ -n "$mac_addresses" ]]; then
debug_log "vm $vmid: checking ARP table" debug_log "vm $vmid: refreshing ARP table and checking"
# Snapshot the neighbor table once instead of per MAC # Try to refresh ARP table by pinging network ranges
local neigh_table
neigh_table=$(ip neighbor show 2>/dev/null)
for mac in $mac_addresses; do for mac in $mac_addresses; do
local mac_lower=$(echo "$mac" | tr '[:upper:]' '[:lower:]') local mac_lower=$(echo "$mac" | tr '[:upper:]' '[:lower:]')
# Check current ARP table # First check current ARP table
local current_ip=$(echo "$neigh_table" | grep "$mac_lower" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) local current_ip=$(ip neighbor show | grep "$mac_lower" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1)
# If found in ARP, verify it's still valid by trying to ping # If found in ARP, verify it's still valid by trying to ping
if [[ -n "$current_ip" && "$current_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then if [[ -n "$current_ip" && "$current_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
debug_log "vm $vmid: found IP $current_ip in ARP table for MAC $mac_lower, verifying..." debug_log "vm $vmid: found IP $current_ip in ARP table for MAC $mac_lower, verifying..."
# Quick ping test to verify IP is still active # Quick ping test to verify IP is still active
if timeout 1 ping -c 1 -W 1 "$current_ip" >/dev/null 2>&1; then if timeout 2 ping -c 1 "$current_ip" >/dev/null 2>&1; then
debug_log "vm $vmid: verified IP $current_ip is active via ping" debug_log "vm $vmid: verified IP $current_ip is active via ping"
ips+="$current_ip " ips+="$current_ip "
else else
@@ -639,7 +628,7 @@ get_vm_ips() {
if [[ -n "$dhcp_ip" && "$dhcp_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then if [[ -n "$dhcp_ip" && "$dhcp_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
debug_log "vm $vmid: found IP $dhcp_ip via DHCP leases" debug_log "vm $vmid: found IP $dhcp_ip via DHCP leases"
# Verify this IP responds # Verify this IP responds
if timeout 1 ping -c 1 -W 1 "$dhcp_ip" >/dev/null 2>&1; then if timeout 2 ping -c 1 "$dhcp_ip" >/dev/null 2>&1; then
debug_log "vm $vmid: verified DHCP IP $dhcp_ip is active" debug_log "vm $vmid: verified DHCP IP $dhcp_ip is active"
ips+="$dhcp_ip " ips+="$dhcp_ip "
break 2 break 2
@@ -663,9 +652,6 @@ get_vm_ips() {
# Cache for configs to avoid repeated reads # Cache for configs to avoid repeated reads
declare -A CONFIG_CACHE declare -A CONFIG_CACHE
declare -A IP_CACHE declare -A IP_CACHE
# Status cache populated once per check from `pct list` / `qm list` to avoid
# spawning an expensive `pct status` / `qm status` (Perl) per guest each cycle.
declare -A STATUS_CACHE
# Update tags for container or VM # Update tags for container or VM
update_tags() { update_tags() {
@@ -850,16 +836,7 @@ update_all_tags() {
# Get list of all containers/VMs # Get list of all containers/VMs
if [[ "$type" == "lxc" ]]; then if [[ "$type" == "lxc" ]]; then
# A single `pct list` call yields both the VMID list and the running vmids=($(pct list 2>/dev/null | grep -v VMID | awk '{print $1}'))
# status, so we never need a per-container `pct status` afterwards.
local pct_list_output
pct_list_output=$(pct list 2>/dev/null)
vmids=($(echo "$pct_list_output" | awk 'NR>1 {print $1}'))
local _vmid _status _rest
while read -r _vmid _status _rest; do
[[ "$_vmid" == "VMID" || -z "$_vmid" ]] && continue
STATUS_CACHE["lxc_${_vmid}"]="$_status"
done <<<"$pct_list_output"
else else
# More efficient: direct file listing instead of ls+sed # More efficient: direct file listing instead of ls+sed
vmids=() vmids=()
@@ -868,15 +845,6 @@ update_all_tags() {
local basename="${conf##*/}" local basename="${conf##*/}"
vmids+=("${basename%.conf}") vmids+=("${basename%.conf}")
done done
# A single `qm list` call yields the status for all VMs, avoiding a
# per-VM `qm status`.
if command -v qm >/dev/null 2>&1; then
local _vmid _name _status _rest
while read -r _vmid _name _status _rest; do
[[ "$_vmid" == "VMID" || -z "$_vmid" ]] && continue
STATUS_CACHE["vm_${_vmid}"]="$_status"
done <<<"$(qm list 2>/dev/null)"
fi
fi fi
count=${#vmids[@]} count=${#vmids[@]}
@@ -913,7 +881,6 @@ check() {
# Clear caches before each run # Clear caches before each run
CONFIG_CACHE=() CONFIG_CACHE=()
IP_CACHE=() IP_CACHE=()
STATUS_CACHE=()
# Update LXC containers # Update LXC containers
update_all_tags "lxc" update_all_tags "lxc"
@@ -958,12 +925,8 @@ get_lxc_ips() {
debug_log "lxc $vmid: starting IP detection" debug_log "lxc $vmid: starting IP detection"
# Check if LXC is running (status comes from the cached `pct list`, # Check if LXC is running
# falling back to `pct status` only when called outside the normal cycle). local lxc_status=$(pct status "${vmid}" 2>/dev/null | awk '{print $2}')
local lxc_status="${STATUS_CACHE[lxc_${vmid}]:-}"
if [[ -z "$lxc_status" ]]; then
lxc_status=$(pct status "${vmid}" 2>/dev/null | awk '{print $2}')
fi
if [[ "$lxc_status" != "running" ]]; then if [[ "$lxc_status" != "running" ]]; then
debug_log "lxc $vmid: not running (status: $lxc_status)" debug_log "lxc $vmid: not running (status: $lxc_status)"
return return
@@ -989,12 +952,9 @@ get_lxc_ips() {
if [[ -z "$ips" && -f "$pve_lxc_config" ]]; then if [[ -z "$ips" && -f "$pve_lxc_config" ]]; then
local mac_addrs=$(grep -Eo 'hwaddr=([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}' "$pve_lxc_config" | cut -d'=' -f2) local mac_addrs=$(grep -Eo 'hwaddr=([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}' "$pve_lxc_config" | cut -d'=' -f2)
if [[ -n "$mac_addrs" ]]; then if [[ -n "$mac_addrs" ]]; then
# Snapshot the neighbor table once instead of per MAC
local neigh_table
neigh_table=$(ip neighbor show 2>/dev/null)
while IFS= read -r mac_addr; do while IFS= read -r mac_addr; do
[[ -z "$mac_addr" ]] && continue [[ -z "$mac_addr" ]] && continue
local arp_ip=$(echo "$neigh_table" | grep -i "$mac_addr" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) local arp_ip=$(ip neighbor show | grep -i "$mac_addr" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1)
if [[ -n "$arp_ip" && "$arp_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then if [[ -n "$arp_ip" && "$arp_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
debug_log "lxc $vmid: found IP $arp_ip via ARP table for MAC $mac_addr" debug_log "lxc $vmid: found IP $arp_ip via ARP table for MAC $mac_addr"
ips="${ips}${ips:+ }${arp_ip}" ips="${ips}${ips:+ }${arp_ip}"
@@ -1036,7 +996,7 @@ echo -e "${GN}3)${CL} Update existing installation"
echo -e "${RD}4)${CL} Cancel" echo -e "${RD}4)${CL} Cancel"
while true; do while true; do
read -rp "Enter your choice (1-4): " choice read -p "Enter your choice (1-4): " choice
case $choice in case $choice in
1) 1)
INSTALL_MODE="service" INSTALL_MODE="service"
@@ -1065,7 +1025,7 @@ done
echo -e "\n${YW}This will install ${APP} on ${hostname} in $INSTALL_MODE mode.${CL}" echo -e "\n${YW}This will install ${APP} on ${hostname} in $INSTALL_MODE mode.${CL}"
while true; do while true; do
read -rp "Proceed? (y/n): " yn read -p "Proceed? (y/n): " yn
case $yn in case $yn in
[Yy]*) [Yy]*)
break break
@@ -1112,7 +1072,7 @@ if [[ "$INSTALL_MODE" == "service" ]]; then
else else
stop_spinner stop_spinner
echo -e "\n${YW}Configuration file already exists.${CL}" echo -e "\n${YW}Configuration file already exists.${CL}"
read -rp "Do you want to reconfigure tag format and loop interval? (y/n): " reconfigure read -p "Do you want to reconfigure tag format and loop interval? (y/n): " reconfigure
case $reconfigure in case $reconfigure in
[Yy]*) [Yy]*)
interactive_config_setup interactive_config_setup
+8 -15
View File
@@ -30,7 +30,7 @@ declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "clean-lxcs" "
header_info header_info
echo "Loading..." echo "Loading..."
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Updater" --yesno "This will clean logs, cache and update package lists on selected LXC Containers. Proceed?" 10 58 || exit 0 whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Updater" --yesno "This will clean logs, cache and update package lists on selected LXC Containers. Proceed?" 10 58
NODE=$(hostname) NODE=$(hostname)
EXCLUDE_MENU=() EXCLUDE_MENU=()
@@ -42,17 +42,17 @@ while read -r TAG ITEM; do
EXCLUDE_MENU+=("$TAG" "$ITEM " "OFF") EXCLUDE_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1') done < <(pct list | awk 'NR>1')
# Capture the selection; abort cleanly if the user cancels the dialog excluded_containers=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Containers on $NODE" --checklist "\nSelect containers to skip from cleaning:\n" \
# (set -e would otherwise terminate on the failing command substitution). 16 $((MSG_MAX_LENGTH + 23)) 6 "${EXCLUDE_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
if ! excluded_containers=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Containers on $NODE" --checklist "\nSelect containers to skip from cleaning:\n" \
16 $((MSG_MAX_LENGTH + 23)) 6 "${EXCLUDE_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"'); then if [ $? -ne 0 ]; then
exit 0 exit
fi fi
function run_lxc_clean() { function run_lxc_clean() {
local container=$1 local container=$1
header_info header_info
name=$(pct exec "$container" -- hostname) name=$(pct exec "$container" hostname)
pct exec "$container" -- bash -c ' pct exec "$container" -- bash -c '
BL="\033[36m"; GN="\033[1;92m"; CL="\033[m" BL="\033[36m"; GN="\033[1;92m"; CL="\033[m"
@@ -84,14 +84,7 @@ function run_lxc_clean() {
} }
for container in $(pct list | awk '{if(NR>1) print $1}'); do for container in $(pct list | awk '{if(NR>1) print $1}'); do
excluded=0 if [[ " ${excluded_containers[@]} " =~ " $container " ]]; then
for ex in $excluded_containers; do
if [[ "$ex" == "$container" ]]; then
excluded=1
break
fi
done
if [[ "$excluded" -eq 1 ]]; then
header_info header_info
echo -e "${BL}[Info]${GN} Skipping ${BL}$container${CL}" echo -e "${BL}[Info]${GN} Skipping ${BL}$container${CL}"
sleep 1 sleep 1
-156
View File
@@ -1,156 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/core.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
load_functions
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "disk-health" "pve"
function header_info {
clear
cat <<"EOF"
____ _ __ __ __ ____ __
/ __ \(_)____/ /__ / / / /__ ____ _/ / /_/ /_
/ / / / / ___/ //_/ / /_/ / _ \/ __ `/ / __/ __ \
/ /_/ / (__ ) ,< / __ / __/ /_/ / / /_/ / / /
/_____/_/____/_/|_| /_/ /_/\___/\__,_/_/\__/_/ /_/
EOF
}
header_info
# Must run as root (SMART access requires it)
if [ "$(id -u)" -ne 0 ]; then
msg_error "This script must be run as root."
exit 1
fi
if ! command -v pveversion >/dev/null 2>&1; then
msg_error "No Proxmox VE detected!"
exit 1
fi
# Install required tooling on demand
if ! command -v smartctl >/dev/null 2>&1; then
msg_info "Installing smartmontools"
apt-get update &>/dev/null
if apt-get install -y smartmontools &>/dev/null; then
msg_ok "Installed smartmontools"
else
msg_error "Failed to install smartmontools"
exit 1
fi
fi
if ! command -v nvme >/dev/null 2>&1; then
msg_info "Installing nvme-cli"
if apt-get install -y nvme-cli &>/dev/null; then
msg_ok "Installed nvme-cli"
else
msg_error "nvme-cli not available (NVMe details limited)"
fi
fi
# Collect physical disks (exclude loop, zram and device-mapper devices)
mapfile -t DISKS < <(lsblk -dn -o NAME,TYPE | awk '$2=="disk"{print $1}' | grep -vE '^(loop|zram|dm-)' | sort)
if [ "${#DISKS[@]}" -eq 0 ]; then
msg_error "No physical disks found."
exit 0
fi
# Pull a single attribute value out of "smartctl -A" output by attribute name
sata_attr() {
local output="$1" name="$2"
echo "$output" | awk -v n="$name" '$2==n {print $10; exit}'
}
report_disk() {
local dev="$1"
local path="/dev/${dev}"
local model size health
model=$(lsblk -dn -o MODEL "$path" 2>/dev/null | sed 's/[[:space:]]*$//')
size=$(lsblk -dn -o SIZE "$path" 2>/dev/null | tr -d ' ')
echo -e "\n${BL}======================================================${CL}"
echo -e "${GN}${path}${CL} ${YW}${size:-?}${CL} ${model:-Unknown model}"
echo -e "${BL}======================================================${CL}"
# Overall SMART health verdict
health=$(smartctl -H "$path" 2>/dev/null | grep -iE "SMART overall-health|SMART Health Status" | sed 's/.*: *//')
if [ -z "$health" ]; then
echo -e " Health: ${YW}SMART not available for this device${CL}"
elif echo "$health" | grep -qiE "PASSED|OK"; then
echo -e " Health: ${GN}${health}${CL}"
else
echo -e " Health: ${RD}${health}${CL}"
fi
if [[ "$dev" == nvme* ]]; then
local a
a=$(smartctl -A "$path" 2>/dev/null)
echo "$a" | grep -iE "Temperature:|Available Spare:|Percentage Used:|Data Units Written:|Power On Hours:|Unsafe Shutdowns:|Media and Data Integrity Errors:" |
sed 's/^/ /'
else
local a poh temp realloc pending offline crc wear
a=$(smartctl -A "$path" 2>/dev/null)
poh=$(sata_attr "$a" "Power_On_Hours")
temp=$(sata_attr "$a" "Temperature_Celsius")
realloc=$(sata_attr "$a" "Reallocated_Sector_Ct")
pending=$(sata_attr "$a" "Current_Pending_Sector")
offline=$(sata_attr "$a" "Offline_Uncorrectable")
crc=$(sata_attr "$a" "UDMA_CRC_Error_Count")
wear=$(sata_attr "$a" "Wear_Leveling_Count")
[ -z "$wear" ] && wear=$(sata_attr "$a" "Media_Wearout_Indicator")
[ -n "$temp" ] && echo -e " Temperature: ${temp} C"
[ -n "$poh" ] && echo -e " Power On Hours: ${poh}"
[ -n "$wear" ] && echo -e " Wear Leveling/Wearout: ${wear}"
print_attr() {
local label="$1" val="$2"
[ -z "$val" ] && return
if [ "$val" -gt 0 ] 2>/dev/null; then
echo -e " ${label} ${RD}${val}${CL}"
else
echo -e " ${label} ${GN}${val}${CL}"
fi
}
print_attr "Reallocated Sectors: " "$realloc"
print_attr "Pending Sectors: " "$pending"
print_attr "Offline Uncorrectable:" "$offline"
print_attr "UDMA CRC Errors: " "$crc"
fi
}
header_info
echo -e "${YW}Scanning ${#DISKS[@]} disk(s) for SMART health...${CL}"
for d in "${DISKS[@]}"; do
report_disk "$d"
done
echo
# Offer an optional, non-destructive short self-test
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "SMART Self-Test" \
--yesno "Health report complete.\n\nDo you want to start a non-destructive SHORT SMART self-test on a disk?\n\n(The test runs in the background; check results later with: smartctl -a /dev/XXX)" 14 70; then
TEST_MENU=()
for d in "${DISKS[@]}"; do
TEST_MENU+=("$d" "/dev/$d" "OFF")
done
sel=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Select Disk for Short Self-Test" \
--radiolist "\nSelect a disk:\n" 16 60 6 "${TEST_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
if [ -n "$sel" ]; then
msg_info "Starting short self-test on /dev/$sel"
if smartctl -t short "/dev/$sel" &>/dev/null; then
msg_ok "Short self-test started on /dev/$sel"
echo -e "${YW}Check progress/result with: ${GN}smartctl -a /dev/$sel${CL}"
else
msg_error "Could not start self-test on /dev/$sel"
fi
fi
fi
echo -e "\n${GN}Disk health check complete.${CL}\n"
+158
View File
@@ -0,0 +1,158 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/core.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
load_functions
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "iommu-setup" "pve"
function header_info {
clear
cat <<"EOF"
____ ____ __ _____ __ ____ _____ __
/ _/ / __ \/ |/ / |/ / / / / / ___/___ / /___ ______
/ / / / / / /|_/ / /|_/ / / / / \__ \/ _ \/ __/ / / / __ \
_/ / / /_/ / / / / / / / /_/ / ___/ / __/ /_/ /_/ / /_/ /
/___/ \____/_/ /_/_/ /_/\____/ /____/\___/\__/\__,_/ .___/
/_/
EOF
}
header_info
# Guards
if [ "$(id -u)" -ne 0 ]; then
msg_error "This script must be run as root."
exit 1
fi
if ! command -v pveversion >/dev/null 2>&1; then
msg_error "No Proxmox VE detected!"
exit 1
fi
if ! pveversion | grep -Eq "pve-manager/(8\.[0-4]|9\.[0-9]+)(\.[0-9]+)*"; then
msg_error "This version of Proxmox Virtual Environment is not supported."
msg_error "Requires Proxmox Virtual Environment Version 8.0-8.4 or 9.x."
exit 1
fi
# systemd-detect-virt prints "none" but exits non-zero on bare metal, so a
# `|| echo none` fallback would duplicate the value; capture output as-is.
virt=$(systemd-detect-virt 2>/dev/null)
if [ -n "$virt" ] && [ "$virt" != "none" ]; then
msg_error "IOMMU/PCI passthrough must be configured on bare metal. Detected: $virt"
exit 1
fi
# Whether a kernel parameter is already present in a cmdline string
has_token() {
case " $1 " in
*" $2 "*) return 0 ;;
*) return 1 ;;
esac
}
# Detect CPU vendor and the matching kernel parameters
cpu_vendor=$(lscpu | grep -oP 'Vendor ID:\s*\K\S+' | head -n 1)
case "$cpu_vendor" in
GenuineIntel) IOMMU_PARAMS=("intel_iommu=on" "iommu=pt") ;;
AuthenticAMD) IOMMU_PARAMS=("amd_iommu=on" "iommu=pt") ;;
*)
msg_error "Unsupported CPU vendor: ${cpu_vendor:-unknown}"
exit 1
;;
esac
# Report current IOMMU state
iommu_active="no"
if [ -d /sys/kernel/iommu_groups ] && [ -n "$(ls -A /sys/kernel/iommu_groups 2>/dev/null)" ]; then
iommu_active="yes"
fi
echo -e "${BL}CPU vendor:${CL} ${cpu_vendor}"
echo -e "${BL}IOMMU active:${CL} $([ "$iommu_active" = "yes" ] && echo -e "${GN}yes${CL}" || echo -e "${RD}no${CL}")"
echo -e "${BL}Kernel params:${CL} ${IOMMU_PARAMS[*]}"
echo
if [ "$iommu_active" = "yes" ]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "IOMMU Already Active" \
--yesno "IOMMU already appears to be active on this host.\n\nDo you still want to (re)apply the kernel parameters and vfio modules?" 12 70 || {
echo -e "${GN}Nothing to do.${CL}"
exit 0
}
else
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Enable IOMMU / PCI(e) Passthrough" \
--yesno "This will enable IOMMU for PCI(e) passthrough by:\n\n - adding '${IOMMU_PARAMS[*]}' to the kernel command line\n - loading the vfio kernel modules\n\nA reboot is required afterwards. A backup of the modified boot config is created.\n\nProceed?" 16 74 || exit 0
fi
# Determine the boot configuration in use
# proxmox-boot-tool managed systems (ZFS / UEFI) use /etc/kernel/cmdline,
# everything else uses GRUB via /etc/default/grub.
if command -v proxmox-boot-tool >/dev/null 2>&1 && [ -f /etc/kernel/cmdline ]; then
BOOT_MODE="systemd-boot"
else
BOOT_MODE="grub"
fi
apply_grub() {
local file="/etc/default/grub" current merged
cp -a "$file" "${file}.bak.$(date +%Y%m%d%H%M%S)"
if grep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' "$file"; then
current=$(sed -n 's/^GRUB_CMDLINE_LINUX_DEFAULT=//p' "$file" | tail -1)
current="${current%\"}"
current="${current#\"}"
else
current=""
fi
merged="$current"
for tok in "${IOMMU_PARAMS[@]}"; do
has_token "$merged" "$tok" || merged="${merged:+$merged }$tok"
done
if grep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' "$file"; then
sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"${merged}\"|" "$file"
else
echo "GRUB_CMDLINE_LINUX_DEFAULT=\"${merged}\"" >>"$file"
fi
update-grub &>/dev/null
}
apply_systemd_boot() {
local file="/etc/kernel/cmdline" current merged
cp -a "$file" "${file}.bak.$(date +%Y%m%d%H%M%S)"
current=$(tr -d '\n' <"$file")
merged="$current"
for tok in "${IOMMU_PARAMS[@]}"; do
has_token "$merged" "$tok" || merged="${merged:+$merged }$tok"
done
echo "$merged" >"$file"
proxmox-boot-tool refresh &>/dev/null
}
msg_info "Applying kernel parameters via ${BOOT_MODE}"
if [ "$BOOT_MODE" = "systemd-boot" ]; then
apply_systemd_boot
else
apply_grub
fi
msg_ok "Applied kernel parameters (${BOOT_MODE})"
# Load vfio modules at boot (vfio_virqfd was merged into the core in
# kernel 6.2+, so it is intentionally not added here)
msg_info "Configuring vfio modules"
for m in vfio vfio_iommu_type1 vfio_pci; do
grep -qxF "$m" /etc/modules 2>/dev/null || echo "$m" >>/etc/modules
done
msg_ok "Configured vfio modules"
echo -e "\n${GN}IOMMU configuration written.${CL}"
echo -e "${YW}A reboot is required to activate IOMMU.${CL}"
echo -e "After rebooting, verify with: ${BL}dmesg | grep -e DMAR -e IOMMU${CL}"
echo -e "and list groups with: ${BL}find /sys/kernel/iommu_groups/ -type l${CL}\n"
+4 -14
View File
@@ -55,23 +55,12 @@ read -r selected
selected_indices=() selected_indices=()
IFS=',' read -r -a tokens <<<"$selected" IFS=',' read -r -a tokens <<<"$selected"
for token in "${tokens[@]}"; do for token in "${tokens[@]}"; do
# Strip surrounding whitespace and skip empty tokens
token="${token//[[:space:]]/}"
[ -z "$token" ] && continue
if [[ "$token" =~ ^([0-9]+)-([0-9]+)$ ]]; then if [[ "$token" =~ ^([0-9]+)-([0-9]+)$ ]]; then
start=${BASH_REMATCH[1]} for ((i = BASH_REMATCH[1]; i <= BASH_REMATCH[2]; i++)); do
end=${BASH_REMATCH[2]}
if ((start > end)); then
echo -e "${RD}Ignoring invalid range '${token}' (start greater than end).${CL}"
continue
fi
for ((i = start; i <= end; i++)); do
selected_indices+=("$i") selected_indices+=("$i")
done done
elif [[ "$token" =~ ^[0-9]+$ ]]; then
selected_indices+=("$token")
else else
echo -e "${RD}Ignoring invalid selection '${token}'.${CL}" selected_indices+=("$token")
fi fi
done done
@@ -112,7 +101,8 @@ for kernel in "${kernels_to_remove[@]}"; do
remaining=$(dpkg --list | remaining=$(dpkg --list |
awk '/^ii/ {print $2}' | awk '/^ii/ {print $2}' |
grep -E "^proxmox-kernel-${minor_version}\." | grep -E "^proxmox-kernel-${minor_version}\." |
grep -cv "^${kernel}$") grep -v "^${kernel}$" |
wc -l)
if [ "$remaining" -eq 0 ]; then if [ "$remaining" -eq 0 ]; then
pkgs_to_remove+=("$meta") pkgs_to_remove+=("$meta")
fi fi
+11 -11
View File
@@ -16,10 +16,10 @@ function header_info {
EOF EOF
} }
RD="\033[01;31m" RD=$(echo "\033[01;31m")
YW="\033[33m" YW=$(echo "\033[33m")
GN="\033[1;92m" GN=$(echo "\033[1;92m")
CL="\033[m" CL=$(echo "\033[m")
BFR="\\r\\033[K" BFR="\\r\\033[K"
HOLD="-" HOLD="-"
CM="${GN}${CL}" CM="${GN}${CL}"
@@ -47,7 +47,7 @@ intel() {
sleep 1 sleep 1
fi fi
intel_microcode=$(curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode/" | grep -o 'href="[^"]*amd64.deb"' | sed 's/href="//;s/"//') intel_microcode=$(curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode//" | grep -o 'href="[^"]*amd64.deb"' | sed 's/href="//;s/"//')
[ -z "$intel_microcode" ] && { [ -z "$intel_microcode" ] && {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Microcode Found" --msgbox "It appears there were no microcode packages found\n Try again later." 10 68 whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Microcode Found" --msgbox "It appears there were no microcode packages found\n Try again later." 10 68
msg_info "Exiting" msg_info "Exiting"
@@ -80,17 +80,17 @@ intel() {
msg_ok "Downloaded the Intel Processor Microcode Package $microcode" msg_ok "Downloaded the Intel Processor Microcode Package $microcode"
msg_info "Installing $microcode (Patience)" msg_info "Installing $microcode (Patience)"
dpkg -i "$microcode" &>/dev/null dpkg -i $microcode &>/dev/null
msg_ok "Installed $microcode" msg_ok "Installed $microcode"
msg_info "Cleaning up" msg_info "Cleaning up"
rm -f "$microcode" rm $microcode
msg_ok "Cleaned" msg_ok "Cleaned"
echo -e "\nIn order to apply the changes, a system reboot will be necessary.\n" echo -e "\nIn order to apply the changes, a system reboot will be necessary.\n"
} }
amd() { amd() {
amd_microcode=$(curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/" | grep -o 'href="[^"]*amd64.deb"' | sed 's/href="//;s/"//') amd_microcode=$(curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode///" | grep -o 'href="[^"]*amd64.deb"' | sed 's/href="//;s/"//')
[ -z "$amd_microcode" ] && { [ -z "$amd_microcode" ] && {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Microcode Found" --msgbox "It appears there were no microcode packages found\n Try again later." 10 68 whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Microcode Found" --msgbox "It appears there were no microcode packages found\n Try again later." 10 68
@@ -120,15 +120,15 @@ amd() {
} }
msg_info "Downloading the AMD Processor Microcode Package $microcode" msg_info "Downloading the AMD Processor Microcode Package $microcode"
curl -fsSL --proto '=https' "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode" -o "$microcode" curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode" -o $(basename "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode")
msg_ok "Downloaded the AMD Processor Microcode Package $microcode" msg_ok "Downloaded the AMD Processor Microcode Package $microcode"
msg_info "Installing $microcode (Patience)" msg_info "Installing $microcode (Patience)"
dpkg -i "$microcode" &>/dev/null dpkg -i $microcode &>/dev/null
msg_ok "Installed $microcode" msg_ok "Installed $microcode"
msg_info "Cleaning up" msg_info "Cleaning up"
rm -f "$microcode" rm $microcode
msg_ok "Cleaned" msg_ok "Cleaned"
echo -e "\nIn order to apply the changes, a system reboot will be necessary.\n" echo -e "\nIn order to apply the changes, a system reboot will be necessary.\n"
} }
+9 -9
View File
@@ -18,10 +18,10 @@ EOF
} }
# Color definitions # Color definitions
RD="\033[01;31m" RD=$(echo "\033[01;31m")
YW="\033[33m" YW=$(echo "\033[33m")
GN="\033[1;92m" GN=$(echo "\033[1;92m")
CL="\033[m" CL=$(echo "\033[m")
BFR="\\r\\033[K" BFR="\\r\\033[K"
HOLD="-" HOLD="-"
CM="${GN}${CL}" CM="${GN}${CL}"
@@ -94,11 +94,11 @@ intel() {
msg_ok "Downloaded Intel processor microcode package $microcode" msg_ok "Downloaded Intel processor microcode package $microcode"
msg_info "Installing $microcode (this might take a while)" msg_info "Installing $microcode (this might take a while)"
dpkg -i "$microcode" &>/dev/null dpkg -i $microcode &>/dev/null
msg_ok "Installed $microcode" msg_ok "Installed $microcode"
msg_info "Cleaning up" msg_info "Cleaning up"
rm -f "$microcode" rm $microcode
msg_ok "Clean up complete" msg_ok "Clean up complete"
echo -e "\nA system reboot is required to apply the changes.\n" echo -e "\nA system reboot is required to apply the changes.\n"
} }
@@ -137,15 +137,15 @@ amd() {
} }
msg_info "Downloading AMD processor microcode package $microcode" msg_info "Downloading AMD processor microcode package $microcode"
curl -fsSL --proto '=https' "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode" -o "$microcode" curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode" -o $(basename "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode")
msg_ok "Downloaded AMD processor microcode package $microcode" msg_ok "Downloaded AMD processor microcode package $microcode"
msg_info "Installing $microcode (this might take a while)" msg_info "Installing $microcode (this might take a while)"
dpkg -i "$microcode" &>/dev/null dpkg -i $microcode &>/dev/null
msg_ok "Installed $microcode" msg_ok "Installed $microcode"
msg_info "Cleaning up" msg_info "Cleaning up"
rm -f "$microcode" rm $microcode
msg_ok "Clean up complete" msg_ok "Clean up complete"
echo -e "\nA system reboot is required to apply the changes.\n" echo -e "\nA system reboot is required to apply the changes.\n"
} }
+5 -15
View File
@@ -20,26 +20,16 @@ header_info() {
EOF EOF
} }
header_info header_info
whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU Scaling Governors" --yesno "View/Change CPU Scaling Governors. Proceed?" 10 58 || exit 0 whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU Scaling Governors" --yesno "View/Change CPU Scaling Governors. Proceed?" 10 58
current_governor=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
GOV_BASE="/sys/devices/system/cpu/cpu0/cpufreq"
if [[ ! -r "$GOV_BASE/scaling_governor" || ! -r "$GOV_BASE/scaling_available_governors" ]]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU Scaling Not Available" \
--msgbox "CPU frequency scaling is not available on this system.\n\nThis is normal when no cpufreq driver is active (e.g. CPU power management handled by the BIOS, or certain virtualized hosts)." 12 70
clear
exit 0
fi
current_governor=$(cat "$GOV_BASE/scaling_governor")
GOVERNORS_MENU=() GOVERNORS_MENU=()
MSG_MAX_LENGTH=0 MSG_MAX_LENGTH=0
while read -r TAG ITEM; do while read -r TAG ITEM; do
OFFSET=2 OFFSET=2
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=${#ITEM}+OFFSET ((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=${#ITEM}+OFFSET
GOVERNORS_MENU+=("$TAG" "$ITEM " "OFF") GOVERNORS_MENU+=("$TAG" "$ITEM " "OFF")
done < <(tr ' ' '\n' <"$GOV_BASE/scaling_available_governors" | sed '/^$/d' | grep -vxF "$current_governor") done < <(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors | tr ' ' '\n' | grep -v "$current_governor")
# A radiolist is used on purpose: only a single governor can be active at a time. scaling_governor=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Current CPU Scaling Governor is set to $current_governor" --checklist "\nSelect the Scaling Governor to use:\n" 16 $((MSG_MAX_LENGTH + 58)) 6 "${GOVERNORS_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
scaling_governor=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Current CPU Scaling Governor is set to $current_governor" --radiolist "\nSelect the Scaling Governor to use:\n" 16 $((MSG_MAX_LENGTH + 58)) 6 "${GOVERNORS_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
[ -z "$scaling_governor" ] && { [ -z "$scaling_governor" ] && {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No CPU Scaling Governor Selected" --msgbox "It appears that no CPU Scaling Governor was selected" 10 68 whiptail --backtitle "Proxmox VE Helper Scripts" --title "No CPU Scaling Governor Selected" --msgbox "It appears that no CPU Scaling Governor was selected" 10 68
clear clear
@@ -59,7 +49,7 @@ yes)
EXISTING_CRONTAB=$(crontab -l 2>/dev/null) EXISTING_CRONTAB=$(crontab -l 2>/dev/null)
if [[ -n "$EXISTING_CRONTAB" ]]; then if [[ -n "$EXISTING_CRONTAB" ]]; then
TEMP_CRONTAB_FILE=$(mktemp) TEMP_CRONTAB_FILE=$(mktemp)
echo "$EXISTING_CRONTAB" | grep -vF "@reboot (sleep 60 && echo" >"$TEMP_CRONTAB_FILE" echo "$EXISTING_CRONTAB" | grep -v "@reboot (sleep 60 && echo*" >"$TEMP_CRONTAB_FILE"
crontab "$TEMP_CRONTAB_FILE" crontab "$TEMP_CRONTAB_FILE"
rm "$TEMP_CRONTAB_FILE" rm "$TEMP_CRONTAB_FILE"
fi fi