Compare commits

..

5 Commits

Author SHA1 Message Date
MickLesk 5113c2fe58 Work around nextcloudpi's broken ssh.socket restart on Debian 13
Debian 13's openssh-server ships socket-activated by default. NCP's
own bin/ncp/NETWORKING/SSH.sh detects that (systemctl is-active
ssh.socket) but then runs "systemctl restart ssh" in that branch
instead of reloading, which collides with the port ssh.socket already
holds and fails with "Job for ssh.service failed" (#15944). Switch the
container to classic ssh.service before handing off to their
installer so it takes the safe "systemctl reload ssh" branch instead.
2026-07-21 23:23:25 +02:00
MickLesk 7c42e757c3 Revert installer pin, track master again
master now targets trixie itself (matches the Debian 13 bump), and
the only tagged trixie ref was an RC explicitly marked "expect bugs".
Tracking master gets upstream trixie fixes as they land instead of
being stuck on a stale test release.
2026-07-21 23:16:02 +02:00
MickLesk 73666ef855 Bump NextCloudPi to Debian 13, matching upstream's trixie move
Upstream's master ncp.cfg now targets release "trixie" (Debian 13);
bookworm (Debian 12) is no longer in the supported check_distro list
at all. Move our own default to Debian 13 and pin the installer ref
to v1.58.0-rc1, the only tagged ref with release=trixie so far (no
stable trixie release exists yet upstream).
2026-07-21 23:14:52 +02:00
MickLesk c780fd7dfa Actually pin the branch nextcloudpi's install.sh clones internally
install.sh is only a thin bootstrapper: it clones BRANCH (default
"master") of the nextcloudpi repo itself and runs the real installer
from that fresh checkout, including the distro-support check. Fetching
install.sh from a pinned tag alone left BRANCH defaulting to "master",
so the internally-cloned code was unaffected and still failed with
"distro not supported" - confirmed by testing the previous fix. Pass
BRANCH explicitly so the internal clone also targets the pinned tag.
2026-07-21 23:08:01 +02:00
MickLesk 99f9949251 Pin NextCloudPi installer to last known-good stable release
The floating "master" branch of nextcloud/nextcloudpi's install.sh
started rejecting our default Debian 12 base with "distro not
supported" (#15944) after a regression landed upstream; the script
is third-party code we don't audit or control. Pin to v1.57.1, the
latest stable (non-prerelease) release, which explicitly targets
Debian bookworm and predates the regression.
2026-07-21 22:57:50 +02:00
63 changed files with 126 additions and 1166 deletions
-52
View File
@@ -505,58 +505,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details> </details>
## 2026-07-24
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Termix: migrate database to new db/data layout [@MickLesk](https://github.com/MickLesk) ([#15996](https://github.com/community-scripts/ProxmoxVE/pull/15996))
- Sync-in: create admin user with admin role instead of default user [@MickLesk](https://github.com/MickLesk) ([#15983](https://github.com/community-scripts/ProxmoxVE/pull/15983))
- VM: fix machine type selection being ignored, VM always created as q35 [@MickLesk](https://github.com/MickLesk) ([#15995](https://github.com/community-scripts/ProxmoxVE/pull/15995))
- #### ✨ New Features
- Bump all Alpine scripts to 3.24 [@asylumexp](https://github.com/asylumexp) ([#15994](https://github.com/community-scripts/ProxmoxVE/pull/15994))
## 2026-07-23
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- IronClaw: pin to v0.29.1, 1.0 Reborn CLI/config is incompatible [@MickLesk](https://github.com/MickLesk) ([#15982](https://github.com/community-scripts/ProxmoxVE/pull/15982))
- update authentik to 2026.5.6 [@thieneret](https://github.com/thieneret) ([#15973](https://github.com/community-scripts/ProxmoxVE/pull/15973))
- #### ✨ New Features
- Cockpit: default to Debian 13, 45Drives now ships Trixie packages | little refactor [@MickLesk](https://github.com/MickLesk) ([#15984](https://github.com/community-scripts/ProxmoxVE/pull/15984))
- Paperless-ngx: Support v3 [@tomfrenzel](https://github.com/tomfrenzel) ([#15221](https://github.com/community-scripts/ProxmoxVE/pull/15221))
## 2026-07-22
### 🆕 New Scripts
- pve-tool: storage share helper script for Proxmox [@MickLesk](https://github.com/MickLesk) ([#15869](https://github.com/community-scripts/ProxmoxVE/pull/15869))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- InvoiceNinja: preserve and Re-download snappdf Chromium [@MickLesk](https://github.com/MickLesk) ([#15956](https://github.com/community-scripts/ProxmoxVE/pull/15956))
- Anytype: preserve default mongod.conf when configuring Anytype replica set [@MickLesk](https://github.com/MickLesk) ([#15954](https://github.com/community-scripts/ProxmoxVE/pull/15954))
- Nametag: fix missing tailwindcss module [@MickLesk](https://github.com/MickLesk) ([#15955](https://github.com/community-scripts/ProxmoxVE/pull/15955))
- #### ✨ New Features
- OPNSense: Bump FreeBSD to 15 and OPNSense to 26.7 [@MickLesk](https://github.com/MickLesk) ([#15943](https://github.com/community-scripts/ProxmoxVE/pull/15943))
### 💾 Core
- #### ✨ New Features
- core: add OS mismatch guard for container updates [@MickLesk](https://github.com/MickLesk) ([#15948](https://github.com/community-scripts/ProxmoxVE/pull/15948))
## 2026-07-21 ## 2026-07-21
### 🚀 Updated Scripts ### 🚀 Updated Scripts
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}" var_ram="${var_ram:-2048}"
var_disk="${var_disk:-3}" var_disk="${var_disk:-3}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -12,7 +12,7 @@ var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-1024}" var_ram="${var_ram:-1024}"
var_disk="${var_disk:-20}" var_disk="${var_disk:-20}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-3}" var_disk="${var_disk:-3}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
var_nesting="${var_nesting:-0}" var_nesting="${var_nesting:-0}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-1024}" var_ram="${var_ram:-1024}"
var_disk="${var_disk:-2}" var_disk="${var_disk:-2}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-512}"
var_disk="${var_disk:-5}" var_disk="${var_disk:-5}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-512}"
var_disk="${var_disk:-3}" var_disk="${var_disk:-3}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-512}"
var_disk="${var_disk:-2}" var_disk="${var_disk:-2}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+3 -4
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-1024}" var_ram="${var_ram:-1024}"
var_disk="${var_disk:-8}" var_disk="${var_disk:-8}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
@@ -28,8 +28,7 @@ function update_script() {
exit exit
fi fi
RELEASE="ironclaw-v0.29.1" if check_for_gh_release "ironclaw-bin" "nearai/ironclaw"; then
if check_for_gh_release "ironclaw-bin" "nearai/ironclaw" "${RELEASE}" "IronClaw 1.0 (Reborn) is a ground-up rearchitecture with an incompatible CLI/config format; pinned until this script supports it"; then
msg_info "Stopping Service" msg_info "Stopping Service"
rc-service ironclaw stop 2>/dev/null || true rc-service ironclaw stop 2>/dev/null || true
msg_ok "Stopped Service" msg_ok "Stopped Service"
@@ -38,7 +37,7 @@ function update_script() {
cp /root/.ironclaw/.env /root/ironclaw.env.bak cp /root/.ironclaw/.env /root/ironclaw.env.bak
msg_ok "Backed up Configuration" msg_ok "Backed up Configuration"
fetch_and_deploy_gh_release "ironclaw-bin" "nearai/ironclaw" "prebuild" "${RELEASE}" "/usr/local/bin" \ fetch_and_deploy_gh_release "ironclaw-bin" "nearai/ironclaw" "prebuild" "latest" "/usr/local/bin" \
"ironclaw-$(uname -m)-unknown-linux-musl.tar.gz" "ironclaw-$(uname -m)-unknown-linux-musl.tar.gz"
chmod +x /usr/local/bin/ironclaw chmod +x /usr/local/bin/ironclaw
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-1024}" var_ram="${var_ram:-1024}"
var_disk="${var_disk:-10}" var_disk="${var_disk:-10}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-1024}" var_ram="${var_ram:-1024}"
var_disk="${var_disk:-2}" var_disk="${var_disk:-2}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -12,7 +12,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-2}" var_disk="${var_disk:-2}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
var_fuse="${var_fuse:-yes}" var_fuse="${var_fuse:-yes}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-512}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-512}"
var_disk="${var_disk:-3}" var_disk="${var_disk:-3}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-4}" var_disk="${var_disk:-4}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-2}" var_disk="${var_disk:-2}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-no}" var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-2}" var_disk="${var_disk:-2}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-512}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -12,7 +12,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-512}"
var_disk="${var_disk:-4}" var_disk="${var_disk:-4}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
var_tun="${var_tun:-1}" var_tun="${var_tun:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_disk="${var_disk:-1}"
var_cpu="${var_cpu:-1}" var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}" var_ram="${var_ram:-256}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-0}" var_unprivileged="${var_unprivileged:-0}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-512}"
var_disk="${var_disk:-1}" var_disk="${var_disk:-1}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+2 -2
View File
@@ -43,7 +43,7 @@ function update_script() {
RUST_PROFILE="minimal" RUST_TOOLCHAIN="stable" setup_rust RUST_PROFILE="minimal" RUST_TOOLCHAIN="stable" setup_rust
setup_yq setup_yq
AUTHENTIK_VERSION="version/2026.5.6" AUTHENTIK_VERSION="version/2026.5.5"
# Source: https://github.com/goauthentik/fips/blob/main/Makefile#L26 # Source: https://github.com/goauthentik/fips/blob/main/Makefile#L26
XMLSEC_VERSION="1.3.12" XMLSEC_VERSION="1.3.12"
@@ -105,7 +105,7 @@ function update_script() {
$STD go build -o /opt/authentik/radius ./cmd/radius $STD go build -o /opt/authentik/radius ./cmd/radius
msg_ok "Updated go proxy" msg_ok "Updated go proxy"
msg_info "Building worker. It may take more than 10 minutes, please be patient." msg_info "Building worker"
export AWS_LC_FIPS_SYS_CC="clang" export AWS_LC_FIPS_SYS_CC="clang"
cd /opt/authentik cd /opt/authentik
$STD cargo build --package authentik --no-default-features --features core --locked --release --jobs 1 $STD cargo build --package authentik --no-default-features --features core --locked --release --jobs 1
+1 -17
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-1024}" var_ram="${var_ram:-1024}"
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:-12}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
@@ -33,22 +33,6 @@ function update_script() {
$STD apt update $STD apt update
$STD apt -y upgrade $STD apt -y upgrade
msg_ok "Updated ${APP} LXC" msg_ok "Updated ${APP} LXC"
if [[ ! -f /etc/apt/sources.list.d/45drives.sources ]]; then
[[ "$(arch_resolve)" == "arm64" ]] || read -r -p "Would you like to install 45Drives' cockpit-file-sharing, cockpit-identities, and cockpit-navigator now? <y/N> " prompt
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
msg_info "Installing 45Drives' cockpit extensions"
setup_deb822_repo "45drives" \
"https://repo.45drives.com/key/gpg.asc" \
"https://repo.45drives.com/enterprise/debian" \
"$(get_os_info codename)" \
"main" \
"amd64"
$STD apt install -y cockpit-file-sharing cockpit-identities cockpit-navigator
msg_ok "Installed 45Drives' cockpit extensions"
fi
fi
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
exit exit
} }
+1 -7
View File
@@ -35,18 +35,12 @@ function update_script() {
systemctl stop supervisor nginx php8.4-fpm systemctl stop supervisor nginx php8.4-fpm
msg_ok "Stopped Services" msg_ok "Stopped Services"
create_backup /opt/invoiceninja/.env /opt/invoiceninja/storage /opt/invoiceninja/public/storage /opt/invoiceninja/vendor/beganovich/snappdf/versions create_backup /opt/invoiceninja/.env /opt/invoiceninja/storage /opt/invoiceninja/public/storage
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "invoiceninja" "invoiceninja/invoiceninja" "prebuild" "latest" "/opt/invoiceninja" "invoiceninja.tar.gz" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "invoiceninja" "invoiceninja/invoiceninja" "prebuild" "latest" "/opt/invoiceninja" "invoiceninja.tar.gz"
restore_backup restore_backup
msg_info "Verifying Chromium for PDF Generation"
cd /opt/invoiceninja
$STD ./vendor/bin/snappdf download
chown -R www-data:www-data /opt/invoiceninja/vendor/beganovich/snappdf/versions
msg_ok "Verified Chromium for PDF Generation"
msg_info "Running Migrations" msg_info "Running Migrations"
cd /opt/invoiceninja cd /opt/invoiceninja
$STD php artisan migrate --force $STD php artisan migrate --force
+2 -3
View File
@@ -30,8 +30,7 @@ function update_script() {
exit exit
fi fi
RELEASE="ironclaw-v0.29.1" if check_for_gh_release "ironclaw-bin" "nearai/ironclaw"; then
if check_for_gh_release "ironclaw-bin" "nearai/ironclaw" "${RELEASE}" "IronClaw 1.0 (Reborn) is a ground-up rearchitecture with an incompatible CLI/config format; pinned until this script supports it"; then
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop ironclaw systemctl stop ironclaw
msg_ok "Stopped Service" msg_ok "Stopped Service"
@@ -40,7 +39,7 @@ function update_script() {
cp /root/.ironclaw/.env /root/ironclaw.env.bak cp /root/.ironclaw/.env /root/ironclaw.env.bak
msg_ok "Backed up Configuration" msg_ok "Backed up Configuration"
fetch_and_deploy_gh_release "ironclaw-bin" "nearai/ironclaw" "prebuild" "${RELEASE}" "/usr/local/bin" \ fetch_and_deploy_gh_release "ironclaw-bin" "nearai/ironclaw" "prebuild" "latest" "/usr/local/bin" \
"ironclaw-$(uname -m)-unknown-linux-gnu.tar.gz" "ironclaw-$(uname -m)-unknown-linux-gnu.tar.gz"
chmod +x /usr/local/bin/ironclaw chmod +x /usr/local/bin/ironclaw
+1 -1
View File
@@ -43,7 +43,7 @@ function update_script() {
msg_info "Rebuilding Application" msg_info "Rebuilding Application"
cd /opt/nametag cd /opt/nametag
$STD npm ci --include=dev $STD npm ci
set -a set -a
source /opt/nametag/.env source /opt/nametag/.env
set +a set +a
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}" var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}" var_disk="${var_disk:-8}"
var_os="${var_os:-debian}" var_os="${var_os:-debian}"
var_version="${var_version:-12}" var_version="${var_version:-13}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+1 -1
View File
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-512}"
var_disk="${var_disk:-3}" var_disk="${var_disk:-3}"
var_os="${var_os:-alpine}" var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}" var_version="${var_version:-3.23}"
var_arm64="${var_arm64:-yes}" var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
+9 -112
View File
@@ -49,44 +49,22 @@ function update_script() {
fi fi
fi fi
local PAPERLESS_INSTALLED_VERSION="" BRIDGE_UPDATE=0 RELEASE="v2.20.15"
[[ -f ~/.paperless ]] && PAPERLESS_INSTALLED_VERSION="$(<~/.paperless)" if check_for_gh_release "paperless" "paperless-ngx/paperless-ngx" "${RELEASE}" "v3 needs further testing"; then
PAPERLESS_INSTALLED_VERSION="${PAPERLESS_INSTALLED_VERSION#v}"
if [[ "$PAPERLESS_INSTALLED_VERSION" == 2.* && "$PAPERLESS_INSTALLED_VERSION" != "2.20.15" ]]; then
BRIDGE_UPDATE=1
fi
if check_for_gh_release "paperless" "paperless-ngx/paperless-ngx"; then
if [[ "$PAPERLESS_INSTALLED_VERSION" == "2.20.15" ]]; then
msg_warn "Paperless-ngx v3 does not support encrypted documents anymore."
echo -e "${GATEWAY}${BGN}https://docs.paperless-ngx.com/migration-v3/#encryption-support${CL}"
msg_warn "Before continuing make sure that you do not use encryption or have decrypted all documents."
echo ""
read -rp "Do you want to continue with the update? (y/N): " MIGRATE
echo
if [[ ! "$MIGRATE" =~ ^[Yy]$ ]]; then
msg_info "Update aborted. Decrypt all documents before upgrading to v3."
exit 0
fi
fi
msg_info "Stopping all Paperless-ngx Services" msg_info "Stopping all Paperless-ngx Services"
systemctl stop paperless-consumer paperless-webserver paperless-scheduler paperless-task-queue systemctl stop paperless-consumer paperless-webserver paperless-scheduler paperless-task-queue
msg_ok "Stopped all Paperless-ngx Services" msg_ok "Stopped all Paperless-ngx Services"
if grep -q "uv run" /etc/systemd/system/paperless-webserver.service; then if grep -q "uv run" /etc/systemd/system/paperless-webserver.service; then
msg_info "Backing up configuration" msg_info "Backing up configuration"
local BACKUP_DIR="/opt/paperless_backup_$$" local BACKUP_DIR="/opt/paperless_backup_$$"
mkdir -p "$BACKUP_DIR" mkdir -p "$BACKUP_DIR"
[[ -f /opt/paperless/paperless.conf ]] && cp /opt/paperless/paperless.conf "$BACKUP_DIR/" [[ -f /opt/paperless/paperless.conf ]] && cp /opt/paperless/paperless.conf "$BACKUP_DIR/"
msg_ok "Backup completed to $BACKUP_DIR" msg_ok "Backup completed to $BACKUP_DIR"
PYTHON_VERSION="3.13" setup_uv PYTHON_VERSION="3.13" setup_uv
if ((BRIDGE_UPDATE)); then CLEAN_INSTALL=1 fetch_and_deploy_gh_release "paperless" "paperless-ngx/paperless-ngx" "prebuild" "${RELEASE}" "/opt/paperless" "paperless*tar.xz"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "paperless" "paperless-ngx/paperless-ngx" "prebuild" "v2.20.15" "/opt/paperless" "paperless*tar.xz"
else
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "paperless" "paperless-ngx/paperless-ngx" "prebuild" "latest" "/opt/paperless" "paperless*tar.xz"
fi
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "jbig2enc" "ie13/jbig2enc" "tarball" "latest" "/opt/jbig2enc" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "jbig2enc" "ie13/jbig2enc" "tarball" "latest" "/opt/jbig2enc"
. /etc/os-release . /etc/os-release
@@ -95,94 +73,18 @@ function update_script() {
else else
ensure_dependencies ghostscript ensure_dependencies ghostscript
fi fi
ensure_dependencies gnupg
cp -r "$BACKUP_DIR"/* /opt/paperless/
if ((BRIDGE_UPDATE == 0)) && [[ "$PAPERLESS_INSTALLED_VERSION" == 2.* ]]; then
msg_info "Migrating Paperless-ngx v2 configuration to v3"
PAPERLESS_CONF="/opt/paperless/paperless.conf"
SECRET_KEY_CURRENT="$(sed -n 's|^PAPERLESS_SECRET_KEY=||p' "$PAPERLESS_CONF" | tail -n1)"
DBENGINE="$(sed -n 's|^PAPERLESS_DBENGINE=||p' "$PAPERLESS_CONF" | tail -n1)"
DB_OPTIONS_DEPRECATED="$(sed -n '/^PAPERLESS_DBSSLMODE=/p;/^PAPERLESS_DBSSLROOTCERT=/p;/^PAPERLESS_DBSSLCERT=/p;/^PAPERLESS_DBSSLKEY=/p;/^PAPERLESS_DB_POOLSIZE=/p;/^PAPERLESS_DB_TIMEOUT=/p' "$PAPERLESS_CONF")"
CONSUMER_POLLING="$(sed -n 's|^PAPERLESS_CONSUMER_POLLING=||p' "$PAPERLESS_CONF" | tail -n1)"
CONSUMER_POLLING_INTERVAL="$(sed -n 's|^PAPERLESS_CONSUMER_POLLING_INTERVAL=||p' "$PAPERLESS_CONF" | tail -n1)"
CONSUMER_INOTIFY_DELAY="$(sed -n 's|^PAPERLESS_CONSUMER_INOTIFY_DELAY=||p' "$PAPERLESS_CONF" | tail -n1)"
CONSUMER_STABILITY_DELAY="$(sed -n 's|^PAPERLESS_CONSUMER_STABILITY_DELAY=||p' "$PAPERLESS_CONF" | tail -n1)"
OCR_MODE="$(sed -n 's|^PAPERLESS_OCR_MODE=||p' "$PAPERLESS_CONF" | tail -n1)"
OCR_SKIP_ARCHIVE="$(sed -n 's|^PAPERLESS_OCR_SKIP_ARCHIVE_FILE=||p' "$PAPERLESS_CONF" | tail -n1)"
ARCHIVE_FILE_GENERATION="$(sed -n 's|^PAPERLESS_ARCHIVE_FILE_GENERATION=||p' "$PAPERLESS_CONF" | tail -n1)"
CONSUMER_DELETE_DUPLICATES="$(sed -n 's|^PAPERLESS_CONSUMER_DELETE_DUPLICATES=||p' "$PAPERLESS_CONF" | tail -n1)"
sed -i \
-e '/^PAPERLESS_CONSUMER_POLLING=/d' \
-e '/^PAPERLESS_CONSUMER_INOTIFY_DELAY=/d' \
-e '/^PAPERLESS_CONSUMER_POLLING_DELAY=/d' \
-e '/^PAPERLESS_CONSUMER_POLLING_RETRY_COUNT=/d' \
-e '/^PAPERLESS_CONSUMER_BARCODE_SCANNER=/d' \
-e '/^PAPERLESS_PASSPHRASE=/d' \
-e '/^PAPERLESS_OCR_SKIP_ARCHIVE_FILE=/d' \
-e 's|^PAPERLESS_OCR_MODE="\?skip"\?$|PAPERLESS_OCR_MODE=auto|' \
-e 's|^PAPERLESS_OCR_MODE="\?skip_noarchive"\?$|PAPERLESS_OCR_MODE=auto|' \
"$PAPERLESS_CONF"
if [[ -n "$DB_OPTIONS_DEPRECATED" ]]; then
msg_warn "Deprecated Paperless DB options detected; migrate them manually to PAPERLESS_DB_OPTIONS."
echo -e "${GATEWAY}${BGN}https://docs.paperless-ngx.com/migration-v3/#database-advanced-options${CL}"
fi
if [[ -z "$SECRET_KEY_CURRENT" || "$SECRET_KEY_CURRENT" == "change-me" ]]; then
SECRET_KEY="$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | od -An -tx1 | tr -d ' \n')"
sed -i \
-e '/^#\?PAPERLESS_SECRET_KEY=/d' \
-e "\$a\\PAPERLESS_SECRET_KEY=$SECRET_KEY" \
"$PAPERLESS_CONF"
printf "Paperless-ngx Secret Key: %s\n" "$SECRET_KEY" >>~/paperless-ngx.creds
fi
[[ -z "$DBENGINE" ]] && sed -i '$a\PAPERLESS_DBENGINE=postgresql' "$PAPERLESS_CONF"
[[ -n "$CONSUMER_POLLING" && -z "$CONSUMER_POLLING_INTERVAL" ]] &&
sed -i "\$a\\PAPERLESS_CONSUMER_POLLING_INTERVAL=$CONSUMER_POLLING" "$PAPERLESS_CONF"
[[ -n "$CONSUMER_INOTIFY_DELAY" && -z "$CONSUMER_STABILITY_DELAY" ]] &&
sed -i "\$a\\PAPERLESS_CONSUMER_STABILITY_DELAY=$CONSUMER_INOTIFY_DELAY" "$PAPERLESS_CONF"
[[ -z "$CONSUMER_DELETE_DUPLICATES" ]] &&
sed -i '$a\PAPERLESS_CONSUMER_DELETE_DUPLICATES=true' "$PAPERLESS_CONF"
if [[ -z "$ARCHIVE_FILE_GENERATION" ]]; then
if [[ "$OCR_MODE" == "skip_noarchive" || "$OCR_MODE" == "\"skip_noarchive\"" ]]; then
sed -i '$a\PAPERLESS_ARCHIVE_FILE_GENERATION=never' "$PAPERLESS_CONF"
elif [[ "$OCR_SKIP_ARCHIVE" == "never" || "$OCR_SKIP_ARCHIVE" == "\"never\"" ]]; then
sed -i '$a\PAPERLESS_ARCHIVE_FILE_GENERATION=always' "$PAPERLESS_CONF"
elif [[ "$OCR_SKIP_ARCHIVE" == "with_text" || "$OCR_SKIP_ARCHIVE" == "\"with_text\"" ]]; then
sed -i '$a\PAPERLESS_ARCHIVE_FILE_GENERATION=auto' "$PAPERLESS_CONF"
elif [[ "$OCR_SKIP_ARCHIVE" == "always" || "$OCR_SKIP_ARCHIVE" == "\"always\"" ]]; then
sed -i '$a\PAPERLESS_ARCHIVE_FILE_GENERATION=never' "$PAPERLESS_CONF"
fi
fi
[[ -n "$(sed -n '/^PAPERLESS_CONSUMER_IGNORE_PATTERNS=/p' "$PAPERLESS_CONF")" ]] &&
msg_warn "PAPERLESS_CONSUMER_IGNORE_PATTERNS now uses regex patterns; please verify custom values."
[[ -n "$(sed -n '/^PAPERLESS_PRE_CONSUME_SCRIPT=/p;/^PAPERLESS_POST_CONSUME_SCRIPT=/p' "$PAPERLESS_CONF")" ]] &&
msg_warn "Pre/post consume scripts no longer receive positional arguments in v3; please verify custom scripts."
msg_ok "Migrated Paperless-ngx configuration"
fi
msg_info "Updating Paperless-ngx" msg_info "Updating Paperless-ngx"
if ((BRIDGE_UPDATE == 0)); then cp -r "$BACKUP_DIR"/* /opt/paperless/
sed -i 's|^ExecStart=.*|ExecStart=uv run -- granian --interface asginl --ws --loop uvloop "paperless.asgi:application"|' /etc/systemd/system/paperless-webserver.service
$STD systemctl daemon-reload
fi
cd /opt/paperless cd /opt/paperless
$STD uv sync --all-extras $STD uv sync --all-extras
cd /opt/paperless/src cd /opt/paperless/src
$STD uv run -- python manage.py migrate $STD uv run -- python manage.py migrate
msg_ok "Updated Paperless-ngx" msg_ok "Updated Paperless-ngx"
if ((BRIDGE_UPDATE == 0)) && [[ "$PAPERLESS_INSTALLED_VERSION" == "2.20.15" ]]; then
$STD apt -y purge libzbar0t64 libzbar0 2>/dev/null || true
$STD apt -y autoremove 2>/dev/null || true
fi
rm -rf "$BACKUP_DIR" rm -rf "$BACKUP_DIR"
else else
BRIDGE_UPDATE=1
msg_warn "You are about to migrate your Paperless-ngx installation to uv!" msg_warn "You are about to migrate your Paperless-ngx installation to uv!"
msg_custom "🔒" "It is strongly recommended to take a Proxmox snapshot first:" msg_custom "🔒" "It is strongly recommended to take a Proxmox snapshot first:"
echo -e " 1. Stop the container: pct stop <CTID>" echo -e " 1. Stop the container: pct stop <CTID>"
@@ -237,7 +139,7 @@ function update_script() {
msg_ok "Backup completed to $BACKUP_DIR" msg_ok "Backup completed to $BACKUP_DIR"
PYTHON_VERSION="3.13" setup_uv PYTHON_VERSION="3.13" setup_uv
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "paperless" "paperless-ngx/paperless-ngx" "prebuild" "v2.20.15" "/opt/paperless" "paperless*tar.xz" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "paperless" "paperless-ngx/paperless-ngx" "prebuild" "${RELEASE}" "/opt/paperless" "paperless*tar.xz"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "jbig2enc" "ie13/jbig2enc" "tarball" "latest" "/opt/jbig2enc" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "jbig2enc" "ie13/jbig2enc" "tarball" "latest" "/opt/jbig2enc"
. /etc/os-release . /etc/os-release
@@ -248,15 +150,14 @@ function update_script() {
ensure_dependencies ghostscript ensure_dependencies ghostscript
msg_ok "Installed Ghostscript" msg_ok "Installed Ghostscript"
fi fi
ensure_dependencies gnupg
msg_info "Updating Paperless-ngx to v2.20.15" msg_info "Updating Paperless-ngx"
cp -r "$BACKUP_DIR"/* /opt/paperless/ cp -r "$BACKUP_DIR"/* /opt/paperless/
cd /opt/paperless cd /opt/paperless
$STD uv sync --all-extras $STD uv sync --all-extras
cd /opt/paperless/src cd /opt/paperless/src
$STD uv run -- python manage.py migrate $STD uv run -- python manage.py migrate
msg_ok "Migrated to uv and updated to v2.20.15 (required before v3)" msg_ok "Paperless-ngx migration and update completed"
rm -rf "$BACKUP_DIR" rm -rf "$BACKUP_DIR"
if [[ -d /opt/paperless/backup ]]; then if [[ -d /opt/paperless/backup ]]; then
@@ -271,10 +172,6 @@ function update_script() {
systemctl start paperless-consumer paperless-webserver paperless-scheduler paperless-task-queue systemctl start paperless-consumer paperless-webserver paperless-scheduler paperless-task-queue
sleep 1 sleep 1
msg_ok "Started all Paperless-ngx Services" msg_ok "Started all Paperless-ngx Services"
if ((BRIDGE_UPDATE)); then
msg_custom "️" "${YW}" "Paperless-ngx is now on v2.20.15. Run the update again to upgrade to v3."
exit
fi
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit
+1 -12
View File
@@ -154,16 +154,9 @@ EOF
/opt/termix/nginx \ /opt/termix/nginx \
/opt/termix/nginx/logs \ /opt/termix/nginx/logs \
/opt/termix/nginx/cache \ /opt/termix/nginx/cache \
/opt/termix/nginx/client_body \ /opt/termix/nginx/client_body
/opt/termix/db/data
msg_ok "Recreated Directories" msg_ok "Recreated Directories"
if [[ -f /opt/termix/data/db.sqlite.encrypted && ! -f /opt/termix/db/data/db.sqlite.encrypted ]]; then
msg_info "Migrating Database to new layout"
cp -a /opt/termix/data/db.sqlite.encrypted /opt/termix/db/data/db.sqlite.encrypted
msg_ok "Migrated Database to new layout"
fi
msg_info "Building Frontend" msg_info "Building Frontend"
cd /opt/termix cd /opt/termix
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
@@ -175,10 +168,6 @@ EOF
msg_info "Building Backend" msg_info "Building Backend"
$STD npm rebuild better-sqlite3 --force $STD npm rebuild better-sqlite3 --force
$STD npm run build:backend $STD npm run build:backend
if [[ ! -f /opt/termix/dist/backend/backend/starter.js ]]; then
msg_error "Backend build failed: /opt/termix/dist/backend/backend/starter.js was not created"
exit 1
fi
msg_ok "Built Backend" msg_ok "Built Backend"
msg_info "Setting up Production Dependencies" msg_info "Setting up Production Dependencies"
+1 -1
View File
@@ -31,7 +31,7 @@ $STD su -s /bin/sh postgres -c "psql -c \"CREATE DATABASE ironclaw WITH OWNER ir
$STD su -s /bin/sh postgres -c "psql -d ironclaw -c \"CREATE EXTENSION IF NOT EXISTS vector;\"" $STD su -s /bin/sh postgres -c "psql -d ironclaw -c \"CREATE EXTENSION IF NOT EXISTS vector;\""
msg_ok "Set up Database" msg_ok "Set up Database"
fetch_and_deploy_gh_release "ironclaw-bin" "nearai/ironclaw" "prebuild" "ironclaw-v0.29.1" "/usr/local/bin" \ fetch_and_deploy_gh_release "ironclaw-bin" "nearai/ironclaw" "prebuild" "latest" "/usr/local/bin" \
"ironclaw-$(uname -m)-unknown-linux-musl.tar.gz" "ironclaw-$(uname -m)-unknown-linux-musl.tar.gz"
chmod +x /usr/local/bin/ironclaw chmod +x /usr/local/bin/ironclaw
+1 -1
View File
@@ -16,7 +16,7 @@ update_os
setup_mongodb setup_mongodb
msg_info "Configuring MongoDB Replica Set" msg_info "Configuring MongoDB Replica Set"
cat <<EOF >>/etc/mongod.conf cat <<EOF >/etc/mongod.conf
replication: replication:
replSetName: "rs0" replSetName: "rs0"
+2 -2
View File
@@ -59,7 +59,7 @@ PG_VERSION="17" setup_postgresql
PG_DB_NAME="authentik" PG_DB_USER="authentik" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db PG_DB_NAME="authentik" PG_DB_USER="authentik" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db
XMLSEC_VERSION="1.3.12" XMLSEC_VERSION="1.3.12"
AUTHENTIK_VERSION="version/2026.5.6" AUTHENTIK_VERSION="version/2026.5.5"
fetch_and_deploy_gh_release "xmlsec" "lsh123/xmlsec" "tarball" "${XMLSEC_VERSION}" "/opt/xmlsec" fetch_and_deploy_gh_release "xmlsec" "lsh123/xmlsec" "tarball" "${XMLSEC_VERSION}" "/opt/xmlsec"
fetch_and_deploy_gh_release "authentik" "goauthentik/authentik" "tarball" "${AUTHENTIK_VERSION}" "/opt/authentik" fetch_and_deploy_gh_release "authentik" "goauthentik/authentik" "tarball" "${AUTHENTIK_VERSION}" "/opt/authentik"
fetch_and_deploy_gh_release "geoipupdate" "maxmind/geoipupdate" "binary" fetch_and_deploy_gh_release "geoipupdate" "maxmind/geoipupdate" "binary"
@@ -109,7 +109,7 @@ EOF
echo "#39 19 * * 6,4 /usr/bin/geoipupdate -f /usr/local/etc/GeoIP.conf" | crontab - echo "#39 19 * * 6,4 /usr/bin/geoipupdate -f /usr/local/etc/GeoIP.conf" | crontab -
msg_info "Building worker. It may take more than 10 minutes, please be patient." msg_info "Building worker"
export AWS_LC_FIPS_SYS_CC="clang" export AWS_LC_FIPS_SYS_CC="clang"
cd /opt/authentik cd /opt/authentik
$STD cargo build --package authentik --no-default-features --features core --locked --release --jobs 1 $STD cargo build --package authentik --no-default-features --features core --locked --release --jobs 1
+21 -12
View File
@@ -15,33 +15,42 @@ network_check
update_os update_os
msg_info "Installing Cockpit" msg_info "Installing Cockpit"
CODENAME=$(get_os_info codename) source /etc/os-release
cat <<EOF >/etc/apt/sources.list.d/debian-backports.sources cat <<EOF >/etc/apt/sources.list.d/debian-backports.sources
Types: deb deb-src Types: deb deb-src
URIs: http://deb.debian.org/debian URIs: http://deb.debian.org/debian
Suites: ${CODENAME}-backports Suites: ${VERSION_CODENAME}-backports
Components: main Components: main
Enabled: yes Enabled: yes
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
EOF EOF
$STD apt update $STD apt update
$STD apt install -t ${CODENAME}-backports cockpit cracklib-runtime --no-install-recommends -y $STD apt install -t ${VERSION_CODENAME}-backports cockpit cracklib-runtime --no-install-recommends -y
sed -i "s/root//g" /etc/cockpit/disallowed-users sed -i "s/root//g" /etc/cockpit/disallowed-users
msg_ok "Installed Cockpit" msg_ok "Installed Cockpit"
# 45Drives only publishes amd64 packages # 45Drives only publishes amd64 packages
[[ "$(arch_resolve)" == "arm64" ]] || read -r -p "Would you like to install 45Drives' cockpit-file-sharing, cockpit-identities, and cockpit-navigator <y/N> " prompt [[ "$(arch_resolve)" == "arm64" ]] || read -r -p "Would you like to install 45Drives' cockpit-file-sharing, cockpit-identities, and cockpit-navigator <y/N> " prompt
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
msg_info "Installing 45Drives' cockpit extensions" install_45drives=true
setup_deb822_repo "45drives" \ if [[ "${VERSION_ID}" -ge 13 ]]; then
"https://repo.45drives.com/key/gpg.asc" \ read -r -p "Debian ${VERSION_ID} is not officially supported by 45Drives yet, would you like to continue anyway? <y/N> " prompt
"https://repo.45drives.com/enterprise/debian" \ if [[ ! "${prompt,,}" =~ ^(y|yes)$ ]]; then
"${CODENAME}" \ install_45drives=false
"main" \ fi
"amd64" fi
$STD apt install -y cockpit-file-sharing cockpit-identities cockpit-navigator if [[ "$install_45drives" == "true" ]]; then
msg_ok "Installed 45Drives' cockpit extensions" msg_info "Installing 45Drives' cockpit extensions"
setup_deb822_repo "45drives" \
"https://repo.45drives.com/key/gpg.asc" \
"https://repo.45drives.com/enterprise/debian" \
"bookworm" \
"main" \
"amd64"
$STD apt install -y cockpit-file-sharing cockpit-identities cockpit-navigator
msg_ok "Installed 45Drives' cockpit extensions"
fi
fi fi
motd_ssh motd_ssh
+1 -1
View File
@@ -23,7 +23,7 @@ msg_ok "Installed Dependencies"
PG_VERSION="17" PG_MODULES="pgvector" setup_postgresql PG_VERSION="17" PG_MODULES="pgvector" setup_postgresql
PG_DB_NAME="ironclaw" PG_DB_USER="ironclaw" PG_DB_EXTENSIONS="vector" setup_postgresql_db PG_DB_NAME="ironclaw" PG_DB_USER="ironclaw" PG_DB_EXTENSIONS="vector" setup_postgresql_db
fetch_and_deploy_gh_release "ironclaw-bin" "nearai/ironclaw" "prebuild" "ironclaw-v0.29.1" "/usr/local/bin" \ fetch_and_deploy_gh_release "ironclaw-bin" "nearai/ironclaw" "prebuild" "latest" "/usr/local/bin" \
"ironclaw-$(uname -m)-unknown-linux-gnu.tar.gz" "ironclaw-$(uname -m)-unknown-linux-gnu.tar.gz"
chmod +x /usr/local/bin/ironclaw chmod +x /usr/local/bin/ironclaw
+1 -1
View File
@@ -20,7 +20,7 @@ fetch_and_deploy_gh_release "nametag" "mattogodoy/nametag" "tarball" "latest" "/
msg_info "Setting up Application" msg_info "Setting up Application"
cd /opt/nametag cd /opt/nametag
$STD npm ci --include=dev $STD npm ci
DATABASE_URL="postgresql://${PG_DB_USER}:${PG_DB_PASS}@127.0.0.1:5432/${PG_DB_NAME}" $STD npx prisma generate DATABASE_URL="postgresql://${PG_DB_USER}:${PG_DB_PASS}@127.0.0.1:5432/${PG_DB_NAME}" $STD npx prisma generate
DATABASE_URL="postgresql://${PG_DB_USER}:${PG_DB_PASS}@127.0.0.1:5432/${PG_DB_NAME}" $STD npx prisma migrate deploy DATABASE_URL="postgresql://${PG_DB_USER}:${PG_DB_PASS}@127.0.0.1:5432/${PG_DB_NAME}" $STD npx prisma migrate deploy
msg_ok "Set up Application" msg_ok "Set up Application"
+5
View File
@@ -24,6 +24,11 @@ if [[ ! "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then
exit 10 exit 10
fi fi
msg_info "Switching SSH to classic (non-socket-activated) mode"
systemctl disable --now ssh.socket &>/dev/null || true
systemctl enable --now ssh &>/dev/null || true
msg_ok "Switched SSH to classic mode"
msg_info "Installing NextCloudPi (Patience)" msg_info "Installing NextCloudPi (Patience)"
$STD bash <(curl -fsSL https://raw.githubusercontent.com/nextcloud/nextcloudpi/master/install.sh) $STD bash <(curl -fsSL https://raw.githubusercontent.com/nextcloud/nextcloudpi/master/install.sh)
msg_ok "Installed NextCloudPi" msg_ok "Installed NextCloudPi"
+7 -6
View File
@@ -19,10 +19,10 @@ $STD apt install -y \
build-essential \ build-essential \
imagemagick \ imagemagick \
fonts-liberation \ fonts-liberation \
gnupg \
optipng \ optipng \
libpq-dev \ libpq-dev \
libmagic-dev \ libmagic-dev \
libzbar0t64 \
poppler-utils \ poppler-utils \
default-libmysqlclient-dev \ default-libmysqlclient-dev \
automake \ automake \
@@ -43,15 +43,16 @@ $STD apt install -y \
ghostscript ghostscript
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
PG_VERSION="18" setup_postgresql PG_VERSION="16" setup_postgresql
PG_DB_NAME="paperlessdb" PG_DB_USER="paperless" setup_postgresql_db PG_DB_NAME="paperlessdb" PG_DB_USER="paperless" setup_postgresql_db
PYTHON_VERSION="3.13" setup_uv PYTHON_VERSION="3.13" setup_uv
fetch_and_deploy_gh_release "paperless" "paperless-ngx/paperless-ngx" "prebuild" "latest" "/opt/paperless" "paperless*tar.xz" fetch_and_deploy_gh_release "paperless" "paperless-ngx/paperless-ngx" "prebuild" "v2.20.15" "/opt/paperless" "paperless*tar.xz"
msg_info "Setup Paperless-ngx" msg_info "Setup Paperless-ngx"
cd /opt/paperless cd /opt/paperless
rm -rf /opt/paperless/docker rm -rf /opt/paperless/docker
$STD uv sync --all-extras $STD uv sync --all-extras
curl -fsSL "https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/paperless.conf.example" -o /opt/paperless/paperless.conf
mkdir -p /opt/paperless_data/{consume,data,media,trash} mkdir -p /opt/paperless_data/{consume,data,media,trash}
mkdir -p /opt/paperless/static mkdir -p /opt/paperless/static
SECRET_KEY="$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32)" SECRET_KEY="$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32)"
@@ -68,12 +69,12 @@ sed -i \
-e "s|#PAPERLESS_MEDIA_ROOT=../media|PAPERLESS_MEDIA_ROOT=/opt/paperless_data/media|" \ -e "s|#PAPERLESS_MEDIA_ROOT=../media|PAPERLESS_MEDIA_ROOT=/opt/paperless_data/media|" \
-e "s|#PAPERLESS_EMPTY_TRASH_DIR=|PAPERLESS_EMPTY_TRASH_DIR=/opt/paperless_data/trash|" \ -e "s|#PAPERLESS_EMPTY_TRASH_DIR=|PAPERLESS_EMPTY_TRASH_DIR=/opt/paperless_data/trash|" \
-e "s|#PAPERLESS_STATICDIR=../static|PAPERLESS_STATICDIR=/opt/paperless/static|" \ -e "s|#PAPERLESS_STATICDIR=../static|PAPERLESS_STATICDIR=/opt/paperless/static|" \
-e 's|#PAPERLESS_DBHOST=localhost|PAPERLESS_DBENGINE=postgresql\nPAPERLESS_DBHOST=localhost|' \ -e 's|#PAPERLESS_DBHOST=localhost|PAPERLESS_DBHOST=localhost|' \
-e 's|#PAPERLESS_DBPORT=5432|PAPERLESS_DBPORT=5432|' \ -e 's|#PAPERLESS_DBPORT=5432|PAPERLESS_DBPORT=5432|' \
-e "s|#PAPERLESS_DBNAME=paperless|PAPERLESS_DBNAME=$PG_DB_NAME|" \ -e "s|#PAPERLESS_DBNAME=paperless|PAPERLESS_DBNAME=$PG_DB_NAME|" \
-e "s|#PAPERLESS_DBUSER=paperless|PAPERLESS_DBUSER=$PG_DB_USER|" \ -e "s|#PAPERLESS_DBUSER=paperless|PAPERLESS_DBUSER=$PG_DB_USER|" \
-e "s|#PAPERLESS_DBPASS=paperless|PAPERLESS_DBPASS=$PG_DB_PASS|" \ -e "s|#PAPERLESS_DBPASS=paperless|PAPERLESS_DBPASS=$PG_DB_PASS|" \
-e "s|PAPERLESS_SECRET_KEY=change-me|PAPERLESS_SECRET_KEY=$SECRET_KEY|" \ -e "s|#PAPERLESS_SECRET_KEY=change-me|PAPERLESS_SECRET_KEY=$SECRET_KEY|" \
/opt/paperless/paperless.conf /opt/paperless/paperless.conf
cd /opt/paperless/src cd /opt/paperless/src
set -a set -a
@@ -151,7 +152,7 @@ Requires=redis.service
[Service] [Service]
WorkingDirectory=/opt/paperless/src WorkingDirectory=/opt/paperless/src
ExecStart=uv run -- granian --interface asginl --ws --loop uvloop "paperless.asgi:application" ExecStart=uv run -- granian --interface asgi --ws "paperless.asgi:application"
Environment=GRANIAN_HOST=:: Environment=GRANIAN_HOST=::
Environment=GRANIAN_PORT=8000 Environment=GRANIAN_PORT=8000
Environment=GRANIAN_WORKERS=1 Environment=GRANIAN_WORKERS=1
+1 -8
View File
@@ -51,14 +51,7 @@ msg_ok "Ran Database Migrations"
msg_info "Creating Admin User" msg_info "Creating Admin User"
cd /opt/sync-in cd /opt/sync-in
ADMIN_PASS=$(openssl rand -base64 18) $STD npx sync-in-server create-user
$STD npx sync-in-server create-user --role admin --login admin --password "${ADMIN_PASS}"
cat <<EOF >~/sync-in.creds
Sync-in Credentials
====================
Login: admin
Password: ${ADMIN_PASS}
EOF
msg_ok "Created Admin User" msg_ok "Created Admin User"
VERSION=$(node -pe "require('/opt/sync-in/node_modules/@sync-in/server/package.json').version" 2>/dev/null || echo "") VERSION=$(node -pe "require('/opt/sync-in/node_modules/@sync-in/server/package.json').version" 2>/dev/null || echo "")
+1 -2
View File
@@ -85,8 +85,7 @@ mkdir -p /opt/termix/data \
/opt/termix/nginx \ /opt/termix/nginx \
/opt/termix/nginx/logs \ /opt/termix/nginx/logs \
/opt/termix/nginx/cache \ /opt/termix/nginx/cache \
/opt/termix/nginx/client_body \ /opt/termix/nginx/client_body
/opt/termix/db/data
cp -r /opt/termix/dist/* /opt/termix/html/ 2>/dev/null || true cp -r /opt/termix/dist/* /opt/termix/html/ 2>/dev/null || true
cp -r /opt/termix/src/locales /opt/termix/html/locales 2>/dev/null || true cp -r /opt/termix/src/locales /opt/termix/html/locales 2>/dev/null || true
+2 -87
View File
@@ -3831,78 +3831,6 @@ runtime_script_status_guard() {
return 0 return 0
} }
# ------------------------------------------------------------------------------
# check_container_os_guard()
#
# - Compares the container OS (/etc/os-release) with the script's recommended
# var_os/var_version before running update_script
# - On mismatch: interactive runs ask whether to continue (default: no);
# headless runs (PHS_SILENT=1 / no tty) abort instead of updating on an
# unsupported base and leaving the app broken mid-update
# - Bypass via var_ignore_os_mismatch=1|yes|true|on (still warns, but continues)
# ------------------------------------------------------------------------------
check_container_os_guard() {
local rec_os="${var_os:-}" rec_ver="${var_version:-}"
rec_os="${rec_os,,}"
[[ -z "$rec_os" || -z "$rec_ver" ]] && return 0
[[ -r /etc/os-release ]] || return 0
local cur_os cur_ver
cur_os="$(. /etc/os-release 2>/dev/null; echo "${ID:-}")"
cur_ver="$(. /etc/os-release 2>/dev/null; echo "${VERSION_ID:-}")"
cur_os="${cur_os,,}"
[[ -z "$cur_os" || -z "$cur_ver" ]] && return 0
# Exact version or prefix on a dot boundary (e.g. alpine 3.22 matches 3.22.1)
if [[ "$cur_os" == "$rec_os" ]] && [[ "$cur_ver" == "$rec_ver" || "$cur_ver" == "$rec_ver".* ]]; then
return 0
fi
case "${var_ignore_os_mismatch:-}" in
1 | yes | true | on)
msg_warn "Container OS is ${cur_os} ${cur_ver} but the script recommends ${rec_os} ${rec_ver} — continuing via var_ignore_os_mismatch (may break, no support)."
return 0
;;
esac
# Persistent opt-out: stores the ignored target version, so the question
# comes back once the script targets a newer OS again
local ignore_file="/usr/local/community-scripts/ignore-os-mismatch"
if [[ -f "$ignore_file" && "$(cat "$ignore_file" 2>/dev/null)" == "${rec_os} ${rec_ver}" ]]; then
msg_warn "Container OS is ${cur_os} ${cur_ver} but the script recommends ${rec_os} ${rec_ver} — continuing (previously ignored via ${ignore_file}, may break, no support)."
return 0
fi
if [[ "${PHS_SILENT:-0}" != "1" ]] && command -v whiptail &>/dev/null && [ -t 0 ] && [[ "$TERM" != "dumb" ]]; then
local choice
choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "OS VERSION MISMATCH" --menu \
"This container runs ${cur_os} ${cur_ver}, but this script now targets ${rec_os} ${rec_ver}.\n\nUpdating on the older base OS may fail or leave ${APP:-the application} broken (e.g. required runtime versions are not available).\n\nRecommended: upgrade the container OS to ${rec_os} ${rec_ver} first, then run this update again.\n\nIf you continue anyway, it may break — no support is provided in that case.\n\nContinue anyway?" \
20 70 3 \
"1" "No (cancel update)" \
"2" "Yes (continue this time)" \
"3" "Yes (continue and don't ask again)" \
--nocancel --default-item "1" 3>&1 1>&2 2>&3)
case "$choice" in
2)
msg_warn "Continuing update on ${cur_os} ${cur_ver} despite recommended ${rec_os} ${rec_ver} — may break, no support."
return 0
;;
3)
mkdir -p "${ignore_file%/*}"
echo "${rec_os} ${rec_ver}" >"$ignore_file"
msg_warn "Continuing update on ${cur_os} ${cur_ver}; OS check for ${rec_os} ${rec_ver} disabled via ${ignore_file} — may break, no support."
return 0
;;
esac
msg_error "Update cancelled: container OS ${cur_os} ${cur_ver} does not match the recommended ${rec_os} ${rec_ver}."
return 1
fi
msg_error "Container OS ${cur_os} ${cur_ver} does not match the recommended ${rec_os} ${rec_ver} — skipping update."
msg_error "Upgrade the container OS to ${rec_os} ${rec_ver} first, then run this update again — or bypass this check (may break, no support) with: echo \"${rec_os} ${rec_ver}\" > ${ignore_file}"
return 1
}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# start() # start()
# #
@@ -3924,7 +3852,6 @@ start() {
ensure_profile_loaded ensure_profile_loaded
get_lxc_ip get_lxc_ip
runtime_script_status_guard update || return 0 runtime_script_status_guard update || return 0
check_container_os_guard || return 0
update_script update_script
run_addon_updates run_addon_updates
update_motd_ip update_motd_ip
@@ -3936,7 +3863,6 @@ start() {
ensure_profile_loaded ensure_profile_loaded
get_lxc_ip get_lxc_ip
runtime_script_status_guard update || return 0 runtime_script_status_guard update || return 0
check_container_os_guard || return 0
update_script update_script
run_addon_updates run_addon_updates
update_motd_ip update_motd_ip
@@ -3967,7 +3893,6 @@ start() {
ensure_profile_loaded ensure_profile_loaded
get_lxc_ip get_lxc_ip
runtime_script_status_guard update || return 0 runtime_script_status_guard update || return 0
check_container_os_guard || return 0
update_script update_script
run_addon_updates run_addon_updates
update_motd_ip update_motd_ip
@@ -5215,10 +5140,7 @@ EOF
echo -en "${YW}Select option [1-${max_option}] (default: 1, auto-remove in 60s): ${CL}" echo -en "${YW}Select option [1-${max_option}] (default: 1, auto-remove in 60s): ${CL}"
local response="" local response=""
local read_rc if read -t 60 -r response; then
read -t 60 -r response
read_rc=$?
if [[ $read_rc -eq 0 ]]; then
case "${response:-1}" in case "${response:-1}" in
1) 1)
# Remove container # Remove container
@@ -5437,20 +5359,13 @@ EOF
fi fi
;; ;;
esac esac
elif [[ $read_rc -gt 128 ]]; then else
# Timeout - auto-remove # Timeout - auto-remove
echo "" echo ""
msg_info "No response - removing container ${CTID}" msg_info "No response - removing container ${CTID}"
pct stop "$CTID" &>/dev/null || true pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true pct destroy "$CTID" &>/dev/null || true
msg_ok "Container ${CTID} removed" msg_ok "Container ${CTID} removed"
else
# read itself failed (e.g. broken/closed stdin, I/O error) rather than
# timing out - don't guess and destroy the container on a read we
# couldn't actually capture; keep it since that's the reversible choice.
echo ""
msg_error "Could not read your response (stdin error) - keeping container ${CTID} for safety."
msg_error "Remove it manually if not needed: pct destroy ${CTID}"
fi fi
# Force one final status update attempt after cleanup # Force one final status update attempt after cleanup
+2 -17
View File
@@ -497,10 +497,7 @@ error_handler() {
fi fi
local response="" local response=""
local read_rc if read -t 60 -r response; then
read -t 60 -r response
read_rc=$?
if [[ $read_rc -eq 0 ]]; then
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
echo "" echo ""
if declare -f msg_info >/dev/null 2>&1; then if declare -f msg_info >/dev/null 2>&1; then
@@ -523,7 +520,7 @@ error_handler() {
echo -e "${YW}Container ${CTID} kept for debugging${CL}" echo -e "${YW}Container ${CTID} kept for debugging${CL}"
fi fi
fi fi
elif [[ $read_rc -gt 128 ]]; then else
# Timeout - auto-remove # Timeout - auto-remove
echo "" echo ""
if declare -f msg_info >/dev/null 2>&1; then if declare -f msg_info >/dev/null 2>&1; then
@@ -538,18 +535,6 @@ error_handler() {
else else
echo -e "${GN}${CL} Container ${CTID} removed" echo -e "${GN}${CL} Container ${CTID} removed"
fi fi
else
# read itself failed (e.g. broken/closed stdin, I/O error) rather than
# timing out - don't guess and destroy the container on a read we
# couldn't actually capture; keep it since that's the reversible choice.
echo ""
if declare -f msg_error >/dev/null 2>&1; then
msg_error "Could not read your response (stdin error) - keeping container ${CTID} for safety."
msg_error "Remove it manually if not needed: pct destroy ${CTID}"
else
echo -e "${YW}Could not read your response (stdin error) - keeping container ${CTID} for safety.${CL}"
echo -e "${YW}Remove it manually if not needed: pct destroy ${CTID}${CL}"
fi
fi fi
fi fi
fi fi
-693
View File
@@ -1,693 +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 "storage-share-helper" "pve"
set -eEuo pipefail
function header_info() {
clear
cat <<"EOF"
_____ __ ___ _________
/ ___// /_____ _________ _____ ____ / | / _/ __ \
\__ \/ __/ __ \/ ___/ __ `/ __ `/ _ \ / /| | / // / / /
___/ / /_/ /_/ / / / /_/ / /_/ / __/ / ___ |_/ // /_/ /
/____/\__/\____/_/ \__,_/\__, /\___/ /_/ |_/___/_____/
/____/
Proxmox Storage Allrounder
SMB | NFS | iSCSI | LVM-on-iSCSI | LXC Mountpoints | Host Shares
EOF
}
pause() {
read -r -p "Press Enter to continue..." _
}
require_pve() {
if ! command -v pct >/dev/null 2>&1 || ! command -v pvesm >/dev/null 2>&1; then
msg_error "This script must run on a Proxmox VE host (pct/pvesm missing)."
exit 1
fi
}
ensure_packages() {
local packages=()
command -v whiptail >/dev/null 2>&1 || packages+=("whiptail")
command -v mount.cifs >/dev/null 2>&1 || packages+=("cifs-utils")
command -v showmount >/dev/null 2>&1 || packages+=("nfs-common")
command -v iscsiadm >/dev/null 2>&1 || packages+=("open-iscsi")
if [[ ${#packages[@]} -gt 0 ]]; then
msg_info "Installing required packages: ${packages[*]}"
apt update >/dev/null 2>&1
apt install -y "${packages[@]}" >/dev/null 2>&1
msg_ok "Dependencies installed"
fi
}
confirm_start() {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Share Allrounder" \
--yesno "This AIO wizard can test and configure SMB/NFS/iSCSI, create/remove Proxmox storages, manage LXC mountpoints and optionally create host shares. Proceed?" 13 100
}
read_input() {
local title="$1"
local prompt="$2"
local default_value="${3:-}"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--inputbox "$prompt" 11 100 "$default_value" 3>&1 1>&2 2>&3
}
read_password() {
local title="$1"
local prompt="$2"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--passwordbox "$prompt" 11 100 3>&1 1>&2 2>&3
}
confirm_yes_no() {
local title="$1"
local prompt="$2"
local height="${3:-11}"
local width="${4:-100}"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--yesno "$prompt" "$height" "$width"
}
# Destructive confirmation: defaults to "No" so a stray Enter never removes anything.
confirm_danger() {
local title="$1"
local prompt="$2"
local height="${3:-15}"
local width="${4:-100}"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--defaultno --yesno "$prompt" "$height" "$width"
}
# Shown before slow data gathering. Goes to stderr: inside $(...) captures, stdout is
# swallowed — stderr is the real terminal.
show_loading() {
echo -e "${YW}Loading... gathering data, this can take a moment (CTRL+C to abort)${CL}" >&2
}
# Info popup that stays visible inside $(...) captures: whiptail draws its UI on
# stdout, so without 1>&2 the dialog would be captured and the script appears hung.
notice_box() {
local title="$1"
local text="$2"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--msgbox "$text" 10 80 1>&2
}
# Interactive container picker (read-only): returns the chosen CTID on stdout.
pick_container() {
local title="$1"
local -a rows=()
local ctid status name label
show_loading
while IFS=$'\t' read -r ctid status name; do
[[ -z "$ctid" ]] && continue
label=$(printf '%-58s' "${name:-<no-name>} [${status}]")
rows+=("$ctid" "$label")
done < <(pct list 2>/dev/null | awk 'NR>1 {print $1"\t"$2"\t"$NF}')
if [[ ${#rows[@]} -eq 0 ]]; then
notice_box "$title" "No LXC containers found on this host."
return 1
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--menu "Select a container:" 24 80 16 "${rows[@]}" 3>&1 1>&2 2>&3
}
# Interactive multi-select picker over ALL mountpoints across ALL containers (read-only).
# Returns chosen entries as "<ctid>:<mpX>" tokens on stdout.
# Reads /etc/pve/lxc/*.conf directly (one 'pct config' per CT is far too slow);
# awk stops at the first '[section]' so snapshot mp entries are not listed.
pick_all_mountpoints_multi() {
local title="$1"
local -a rows=()
local conf ctid name line key def label
show_loading
for conf in /etc/pve/lxc/*.conf; do
[[ -e "$conf" ]] || continue
ctid="$(basename "$conf" .conf)"
name=$(awk '/^\[/{exit} $1=="hostname:"{print $2; exit}' "$conf")
while IFS= read -r line; do
[[ -z "$line" ]] && continue
key="${line%%:*}"
def="${line#*: }"
label=$(printf '%-86s' "CT ${ctid} ${name:-<no-name>} | ${key}: ${def}")
rows+=("${ctid}:${key}" "$label" "OFF")
done < <(awk '/^\[/{exit} /^mp[0-9]+:/{print}' "$conf")
done
if [[ ${#rows[@]} -eq 0 ]]; then
notice_box "$title" "No LXC mountpoints found on any container."
return 1
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--checklist "Select mountpoint(s) to remove across all containers (Space to toggle, Enter to confirm):" \
24 112 16 "${rows[@]}" 3>&1 1>&2 2>&3
}
# Interactive multi-select storage picker (read-only): returns chosen storage IDs on stdout.
pick_storages_multi() {
local title="$1"
local -a rows=()
local stype sid label
show_loading
while read -r stype sid; do
[[ -z "$sid" ]] && continue
label=$(printf '%-58s' "[${stype}]")
rows+=("$sid" "$label" "OFF")
done < <(awk -F': ' '/^[a-z]+: /{print $1, $2}' /etc/pve/storage.cfg 2>/dev/null)
if [[ ${#rows[@]} -eq 0 ]]; then
notice_box "$title" "No storages found in /etc/pve/storage.cfg."
return 1
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--checklist "Select storage(s) to remove (Space to toggle, Enter to confirm):" \
24 80 16 "${rows[@]}" 3>&1 1>&2 2>&3
}
# Interactive multi-select container picker (read-only): returns chosen CTIDs on stdout.
pick_containers_multi() {
local title="$1"
local -a rows=()
local ctid status name label
show_loading
while IFS=$'\t' read -r ctid status name; do
[[ -z "$ctid" ]] && continue
label=$(printf '%-58s' "${name:-<no-name>} [${status}]")
rows+=("$ctid" "$label" "OFF")
done < <(pct list 2>/dev/null | awk 'NR>1 {print $1"\t"$2"\t"$NF}')
if [[ ${#rows[@]} -eq 0 ]]; then
notice_box "$title" "No LXC containers found on this host."
return 1
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--checklist "Select one or more containers (Space to toggle, Enter to confirm):" \
24 80 16 "${rows[@]}" 3>&1 1>&2 2>&3
}
manual_smb_test() {
header_info
local server share username password domain vers mount_dir mount_opts
server=$(read_input "SMB Test" "SMB server/IP (e.g. 10.0.1.9)") || return
share=$(read_input "SMB Test" "Share name (without leading //)" "Proxmox") || return
username=$(read_input "SMB Test" "Username" "proxmox") || return
password=$(read_password "SMB Test" "Password for ${username}") || return
domain=$(read_input "SMB Test" "Domain/Workgroup (optional, leave empty if not needed)") || return
vers=$(read_input "SMB Test" "SMB version (e.g. 3.0, 3.1.1)" "3.1.1") || return
mount_dir="/mnt/test-smb"
mkdir -p "$mount_dir"
mount_opts="username=${username},password=${password},vers=${vers},sec=ntlmssp"
if [[ -n "$domain" ]]; then
mount_opts+=";domain=${domain}"
fi
msg_info "Testing SMB mount on ${mount_dir}"
if mount -t cifs "//${server}/${share}" "$mount_dir" -o "${mount_opts//;/,}" >/dev/null 2>&1; then
touch "${mount_dir}/smb-test-$(date +%s)" >/dev/null 2>&1 || true
umount "$mount_dir" >/dev/null 2>&1 || true
msg_ok "SMB test successful"
else
msg_error "SMB test failed. Check network/firewall/credentials/share permissions."
fi
pause
}
manual_nfs_test() {
header_info
local server export_path mount_dir
server=$(read_input "NFS Test" "NFS server/IP (e.g. 10.0.6.159)") || return
export_path=$(read_input "NFS Test" "NFS export path (e.g. /srv/proxmox-nfs)") || return
mount_dir="/mnt/test-nfs"
mkdir -p "$mount_dir"
msg_info "Testing NFS mount on ${mount_dir}"
if mount -t nfs "${server}:${export_path}" "$mount_dir" >/dev/null 2>&1; then
touch "${mount_dir}/nfs-test-$(date +%s)" >/dev/null 2>&1 || true
umount "$mount_dir" >/dev/null 2>&1 || true
msg_ok "NFS test successful"
else
msg_error "NFS test failed. Check export/firewall/network permissions."
fi
pause
}
manual_iscsi_discovery() {
header_info
local portal
portal=$(read_input "iSCSI Discovery" "iSCSI portal IP/FQDN (e.g. 10.0.1.20)") || return
msg_info "Running iSCSI target discovery on ${portal}"
if iscsiadm -m discovery -t sendtargets -p "$portal"; then
msg_ok "iSCSI discovery completed"
else
msg_error "iSCSI discovery failed"
fi
pause
}
add_smb_storage() {
header_info
local storage_id server share username password content nodes options
storage_id=$(read_input "Add SMB/CIFS Storage" "Storage ID (unique, e.g. smb-media)") || return
server=$(read_input "Add SMB/CIFS Storage" "SMB server/IP") || return
share=$(read_input "Add SMB/CIFS Storage" "Share name (without //)") || return
username=$(read_input "Add SMB/CIFS Storage" "Username") || return
password=$(read_password "Add SMB/CIFS Storage" "Password for ${username}") || return
content=$(read_input "Add SMB/CIFS Storage" "Content types (comma separated)" "backup,iso,vztmpl,snippets") || return
nodes=$(read_input "Add SMB/CIFS Storage" "Nodes (optional, comma separated)") || return
options=$(read_input "Add SMB/CIFS Storage" "Mount options (optional, e.g. vers=3.1.1,domain=WORKGROUP)") || return
local cmd=(pvesm add cifs "$storage_id" --server "$server" --share "$share" --username "$username" --password "$password" --content "$content")
[[ -n "$nodes" ]] && cmd+=(--nodes "$nodes")
[[ -n "$options" ]] && cmd+=(--options "$options")
if "${cmd[@]}" >/dev/null 2>&1; then
msg_ok "SMB storage '${storage_id}' added"
else
msg_error "Failed to add SMB storage '${storage_id}'"
fi
pause
}
add_nfs_storage() {
header_info
local storage_id server export_path content nodes options
storage_id=$(read_input "Add NFS Storage" "Storage ID (unique, e.g. nfs-vmdata)") || return
server=$(read_input "Add NFS Storage" "NFS server/IP") || return
export_path=$(read_input "Add NFS Storage" "Export path") || return
content=$(read_input "Add NFS Storage" "Content types (comma separated)" "images,rootdir") || return
nodes=$(read_input "Add NFS Storage" "Nodes (optional, comma separated)") || return
options=$(read_input "Add NFS Storage" "Mount options (optional)") || return
local cmd=(pvesm add nfs "$storage_id" --server "$server" --export "$export_path" --content "$content")
[[ -n "$nodes" ]] && cmd+=(--nodes "$nodes")
[[ -n "$options" ]] && cmd+=(--options "$options")
if "${cmd[@]}" >/dev/null 2>&1; then
msg_ok "NFS storage '${storage_id}' added"
else
msg_error "Failed to add NFS storage '${storage_id}'"
fi
pause
}
add_iscsi_storage() {
header_info
local storage_id portal target nodes
storage_id=$(read_input "Add iSCSI Storage" "Storage ID (unique, e.g. iscsi-synology)") || return
portal=$(read_input "Add iSCSI Storage" "Portal IP/FQDN") || return
target=$(read_input "Add iSCSI Storage" "Target IQN (e.g. iqn.2000-01.com.synology:...)") || return
nodes=$(read_input "Add iSCSI Storage" "Nodes (optional, comma separated)") || return
local cmd=(pvesm add iscsi "$storage_id" --portal "$portal" --target "$target")
[[ -n "$nodes" ]] && cmd+=(--nodes "$nodes")
if "${cmd[@]}" >/dev/null 2>&1; then
msg_ok "iSCSI storage '${storage_id}' added"
else
msg_error "Failed to add iSCSI storage '${storage_id}'"
fi
pause
}
add_lvm_on_base_storage() {
header_info
local storage_id base_storage vgname content shared
storage_id=$(read_input "Add LVM Storage" "LVM Storage ID (unique, e.g. lvm-iscsi01)") || return
base_storage=$(read_input "Add LVM Storage" "Base storage ID (usually iSCSI storage ID)") || return
vgname=$(read_input "Add LVM Storage" "Volume Group name on target") || return
content=$(read_input "Add LVM Storage" "Content types (comma separated)" "images,rootdir") || return
shared=$(read_input "Add LVM Storage" "Shared across nodes? 1=yes, 0=no" "1") || return
local cmd=(pvesm add lvm "$storage_id" --base "$base_storage" --vgname "$vgname" --content "$content" --shared "$shared")
if "${cmd[@]}" >/dev/null 2>&1; then
msg_ok "LVM storage '${storage_id}' added"
else
msg_error "Failed to add LVM storage '${storage_id}'"
fi
pause
}
remove_storage() {
header_info
local selection storage_id
local -a results=()
selection=$(pick_storages_multi "Remove Storage") || return
if [[ -z "$selection" ]]; then
msg_warn "No storage selected."
pause
return
fi
# Confirm each selected storage separately (defaults to No).
for storage_id in $selection; do
storage_id="${storage_id//\"/}"
[[ -z "$storage_id" ]] && continue
if confirm_danger "Remove Storage" \
"Really remove storage '${storage_id}' from the Proxmox config?
This removes the storage definition only.
Data on the underlying share/target is NOT deleted."; then
if pvesm remove "$storage_id" >/dev/null 2>&1; then
results+=("removed ${storage_id}")
else
results+=("FAILED ${storage_id}")
fi
else
results+=("skipped ${storage_id}")
fi
done
header_info
echo -e "${BL}Remove storage — result${CL}\n"
printf ' %s\n' "${results[@]}"
echo
pause
}
find_next_mp_slot() {
local ctid="$1"
local used
used=$(pct config "$ctid" | awk -F: '/^mp[0-9]+:/ {gsub("mp", "", $1); print $1}')
for i in $(seq 0 255); do
if ! grep -qx "$i" <<<"$used"; then
echo "$i"
return
fi
done
echo ""
}
add_lxc_mountpoint() {
header_info
local ctid host_path ct_path mp_slot
ctid=$(pick_container "LXC: add mountpoint") || return
host_path=$(read_input "LXC Mountpoint" "Host path (must exist, e.g. /mnt/pve/smb-media)") || return
ct_path=$(read_input "LXC Mountpoint" "Container path (e.g. /mnt/media)") || return
if [[ ! -d "$host_path" ]]; then
msg_error "Host path does not exist: ${host_path}"
pause
return
fi
mp_slot=$(find_next_mp_slot "$ctid")
if [[ -z "$mp_slot" ]]; then
msg_error "No free mp slot available for container ${ctid}"
pause
return
fi
confirm_yes_no "LXC: add mountpoint" \
"Add mp${mp_slot} to CT ${ctid}?
${host_path} -> ${ct_path}" 13 100 || return
if pct set "$ctid" -mp"$mp_slot" "$host_path",mp="$ct_path" >/dev/null 2>&1; then
msg_ok "Added mp${mp_slot}: ${host_path} -> ${ct_path} on CT ${ctid}"
msg_warn "If CT is unprivileged, ensure UID/GID mapping and filesystem permissions fit your workload."
else
msg_error "Failed to add mountpoint to CT ${ctid}"
fi
pause
}
remove_lxc_mountpoint() {
header_info
local selection entry ctid mp_key mp_def
local -a results=()
selection=$(pick_all_mountpoints_multi "LXC: remove mountpoint") || return
if [[ -z "$selection" ]]; then
msg_warn "No mountpoint selected."
pause
return
fi
# Confirm each selected mountpoint separately (defaults to No).
for entry in $selection; do
entry="${entry//\"/}"
[[ -z "$entry" ]] && continue
ctid="${entry%%:*}"
mp_key="${entry#*:}"
mp_def=$(pct config "$ctid" | awk -F': ' -v k="$mp_key" '$1==k{print $2}')
if confirm_danger "LXC: remove mountpoint" \
"Remove ${mp_key} from CT ${ctid}?
${mp_key}: ${mp_def}
This only detaches the mountpoint from the container.
Data on the host is NOT deleted."; then
if pct set "$ctid" -delete "$mp_key" >/dev/null 2>&1; then
results+=("removed CT ${ctid} ${mp_key}")
else
results+=("FAILED CT ${ctid} ${mp_key}")
fi
else
results+=("skipped CT ${ctid} ${mp_key}")
fi
done
header_info
echo -e "${BL}Remove mountpoint — result${CL}\n"
printf ' %s\n' "${results[@]}"
echo
pause
}
list_lxc_mountpoints() {
header_info
local selection ctid mps
selection=$(pick_containers_multi "LXC: list mountpoints") || return
if [[ -z "$selection" ]]; then
msg_warn "No container selected."
pause
return
fi
for ctid in $selection; do
ctid="${ctid//\"/}"
[[ -z "$ctid" ]] && continue
echo -e "${BL}Mountpoints for CT ${ctid}${CL}"
mps=$(pct config "$ctid" | awk '/^mp[0-9]+:/{print}')
if [[ -n "$mps" ]]; then
echo "$mps"
else
echo " (no mountpoints configured)"
fi
echo
done
pause
}
host_create_samba_share() {
header_info
local share_name share_path user_name user_pass
share_name=$(read_input "Host Samba Share" "Share name (e.g. data)") || return
share_path=$(read_input "Host Samba Share" "Share path on host (e.g. /srv/samba/data)" "/srv/samba/${share_name}") || return
user_name=$(read_input "Host Samba Share" "Linux/Samba username") || return
user_pass=$(read_password "Host Samba Share" "Password for ${user_name}") || return
msg_info "Installing Samba on host if needed"
apt update >/dev/null 2>&1
apt install -y samba >/dev/null 2>&1
mkdir -p "$share_path"
getent group sambashare >/dev/null 2>&1 || groupadd sambashare
id "$user_name" >/dev/null 2>&1 || useradd -M -s /usr/sbin/nologin -G sambashare "$user_name"
usermod -aG sambashare "$user_name"
chown -R root:sambashare "$share_path"
chmod 2775 "$share_path"
if ! (
echo "$user_pass"
echo "$user_pass"
) | smbpasswd -s -a "$user_name" >/dev/null 2>&1; then
msg_error "Failed to set Samba password for ${user_name}"
pause
return
fi
if ! grep -q "^\[${share_name}\]" /etc/samba/smb.conf; then
cat <<EOF >>/etc/samba/smb.conf
[${share_name}]
comment = Proxmox Host Share (${share_name})
path = ${share_path}
browseable = yes
read only = no
guest ok = no
create mask = 0664
directory mask = 2775
valid users = @sambashare
EOF
fi
testparm -s >/dev/null 2>&1 || {
msg_error "Samba config validation failed (testparm). Check /etc/samba/smb.conf"
pause
return
}
systemctl enable --now smbd nmbd >/dev/null 2>&1
systemctl restart smbd nmbd >/dev/null 2>&1
msg_ok "Host SMB share created: //$(hostname -I | awk '{print $1}')/${share_name}"
msg_warn "Best practice: prefer running Samba in a dedicated LXC/VM for cleaner host separation."
pause
}
host_create_nfs_export() {
header_info
local export_path subnet options
export_path=$(read_input "Host NFS Export" "Export path on host (e.g. /srv/proxmox-nfs)" "/srv/proxmox-nfs") || return
subnet=$(read_input "Host NFS Export" "Allowed subnet/CIDR (e.g. 10.0.0.0/16)") || return
options=$(read_input "Host NFS Export" "Export options" "rw,sync,no_subtree_check,no_root_squash") || return
msg_info "Installing NFS server on host if needed"
apt update >/dev/null 2>&1
apt install -y nfs-kernel-server >/dev/null 2>&1
mkdir -p "$export_path"
chmod 0770 "$export_path"
if ! grep -qE "^${export_path//\//\/}[[:space:]]+${subnet//\//\/}\(" /etc/exports; then
echo "${export_path} ${subnet}(${options})" >>/etc/exports
fi
exportfs -ra >/dev/null 2>&1
systemctl enable --now nfs-kernel-server >/dev/null 2>&1
msg_ok "Host NFS export created: ${export_path} ${subnet}(${options})"
msg_warn "Best practice: use host exports carefully; dedicated storage VM/LXC is often cleaner."
pause
}
show_status() {
header_info
echo -e "${BL}pvesm status${CL}"
pvesm status || true
echo
echo -e "${BL}Mounted /mnt/pve paths${CL}"
mount | grep /mnt/pve || true
echo
echo -e "${BL}Mounted CIFS/NFS/iSCSI related paths${CL}"
mount | grep -E ' type (cifs|nfs|nfs4)' || true
echo
echo -e "${BL}iSCSI sessions${CL}"
iscsiadm -m session 2>/dev/null || true
echo
pause
}
main_menu() {
while true; do
local choice
choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Share Allrounder" \
--menu "Select action (read-only actions are safe; write/remove actions ask for confirmation):" 30 116 22 \
" " "────────── READ-ONLY (safe, no changes) ──────────" \
"1" "Test | SMB: manual mount test" \
"2" "Test | NFS: manual mount test" \
"3" "Test | iSCSI: discovery test" \
"4" "Read | LXC: list mountpoints" \
"5" "Read | Show storage/mount/iSCSI status" \
" " "────────── WRITE (modifies config / host) ──────────" \
"6" "Write | Proxmox: add SMB/CIFS storage" \
"7" "Write | Proxmox: add NFS storage" \
"8" "Write | Proxmox: add iSCSI storage" \
"9" "Write | Proxmox: add LVM on base storage (e.g. iSCSI)" \
"10" "Write | LXC: add bind mountpoint (pct set -mpX)" \
"11" "Write | Host: install Samba + create SMB share" \
"12" "Write | Host: install NFS server + create export" \
" " "────────── REMOVE (destructive, defaults to No) ──────────" \
"13" "Remove | Proxmox: remove storage definition" \
"14" "Remove | LXC: remove mountpoint (pct set -delete mpX)" \
"0" "Exit" 3>&1 1>&2 2>&3) || break
# '|| true' so a cancelled sub-dialog (whiptail returns non-zero) returns to the
# menu instead of tripping 'set -e' and exiting the whole script.
case "$choice" in
1) manual_smb_test || true ;;
2) manual_nfs_test || true ;;
3) manual_iscsi_discovery || true ;;
4) list_lxc_mountpoints || true ;;
5) show_status || true ;;
6) add_smb_storage || true ;;
7) add_nfs_storage || true ;;
8) add_iscsi_storage || true ;;
9) add_lvm_on_base_storage || true ;;
10) add_lxc_mountpoint || true ;;
11) host_create_samba_share || true ;;
12) host_create_nfs_export || true ;;
13) remove_storage || true ;;
14) remove_lxc_mountpoint || true ;;
0) break ;;
*) ;;
esac
done
}
header_info
root_check
pve_check
require_pve
ensure_packages
confirm_start || exit 0
main_menu
header_info
msg_ok "Finished."
+2 -2
View File
@@ -280,7 +280,7 @@ function extract_xz_with_pv() {
function default_settings() { function default_settings() {
BRANCH="$stable" BRANCH="$stable"
VMID=$(get_valid_nextid) VMID=$(get_valid_nextid)
MACHINE=" -machine q35" MACHINE="q35"
FORMAT="" FORMAT=""
DISK_SIZE="32G" DISK_SIZE="32G"
HN="haos-${BRANCH}" HN="haos-${BRANCH}"
@@ -598,7 +598,7 @@ msg_ok "${CL}${BL}${URL}${CL}"
download_and_validate_xz "$URL" "$CACHE_FILE" download_and_validate_xz "$URL" "$CACHE_FILE"
msg_info "Creating Home Assistant OS VM shell" msg_info "Creating Home Assistant OS VM shell"
qm create $VMID${MACHINE} -bios ovmf -agent 1 -tablet 0 -localtime 1 ${CPU_TYPE} \ qm create $VMID -machine q35 -bios ovmf -agent 1 -tablet 0 -localtime 1 ${CPU_TYPE} \
-cores "$CORE_COUNT" -memory "$RAM_SIZE" -name "$HN" -tags community-script \ -cores "$CORE_COUNT" -memory "$RAM_SIZE" -name "$HN" -tags community-script \
-net0 "virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU" -onboot 1 -ostype l26 -scsihw virtio-scsi-pci >/dev/null -net0 "virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU" -onboot 1 -ostype l26 -scsihw virtio-scsi-pci >/dev/null
msg_ok "Created VM shell" msg_ok "Created VM shell"
+19 -83
View File
@@ -25,7 +25,6 @@ METHOD=""
NSAPP="opnsense-vm" NSAPP="opnsense-vm"
var_os="opnsense" var_os="opnsense"
var_version="26.7" var_version="26.7"
FREEBSD_MAJOR="15"
# #
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//') GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
GEN_MAC_LAN=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//') GEN_MAC_LAN=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
@@ -491,7 +490,7 @@ function advanced_settings() {
fi fi
echo -e "${DGN}Using LAN GATEWAY ADDRESS: ${BGN}$LAN_GW${CL}" echo -e "${DGN}Using LAN GATEWAY ADDRESS: ${BGN}$LAN_GW${CL}"
fi fi
if NETMASK=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN netmask (24 for example)" 8 58 $NETMASK --title "LAN NETMASK" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then if NETMASK=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN netmmask (24 for example)" 8 58 $NETMASK --title "LAN NETMASK" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $NETMASK ]; then if [ -z $NETMASK ]; then
echo -e "${DGN}Netmask needs to be set if ip is not dhcp${CL}" echo -e "${DGN}Netmask needs to be set if ip is not dhcp${CL}"
fi fi
@@ -559,7 +558,7 @@ function advanced_settings() {
else else
exit-script exit-script
fi fi
if WAN_NETMASK=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN netmask (24 for example)" 8 58 $WAN_NETMASK --title "WAN NETMASK" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then if WAN_NETMASK=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN netmmask (24 for example)" 8 58 $WAN_NETMASK --title "WAN NETMASK" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $WAN_NETMASK ]; then if [ -z $WAN_NETMASK ]; then
echo -e "${DGN}WAN Netmask needs to be set if ip is not dhcp${CL}" echo -e "${DGN}WAN Netmask needs to be set if ip is not dhcp${CL}"
fi fi
@@ -575,7 +574,7 @@ function advanced_settings() {
else else
exit-script exit-script
fi fi
if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN MAC Address" 8 58 $GEN_MAC --title "LAN MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN MAC Address" 8 58 $GEN_MAC --title "WAN MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $MAC1 ]; then if [ -z $MAC1 ]; then
MAC="$GEN_MAC" MAC="$GEN_MAC"
else else
@@ -586,7 +585,7 @@ function advanced_settings() {
exit-script exit-script
fi fi
if MAC2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a WAN MAC Address" 8 58 $GEN_MAC_LAN --title "WAN MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then if MAC2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a LAN MAC Address" 8 58 $GEN_MAC_LAN --title "LAN MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z $MAC2 ]; then if [ -z $MAC2 ]; then
WAN_MAC="$GEN_MAC_LAN" WAN_MAC="$GEN_MAC_LAN"
else else
@@ -653,26 +652,23 @@ fi
msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location." msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location."
msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}." msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}."
msg_info "Retrieving the URL for the OPNsense Qcow2 Disk Image" msg_info "Retrieving the URL for the OPNsense Qcow2 Disk Image"
# Use latest stable FreeBSD amd64 qcow2 VM image matching FREEBSD_MAJOR # Use latest stable FreeBSD amd64 qcow2 VM image (generic, not UFS/ZFS)
RELEASE_LIST="$(curl -s https://download.freebsd.org/releases/VM-IMAGES/ | RELEASE_LIST="$(curl -s https://download.freebsd.org/releases/VM-IMAGES/ |
grep -Eo "${FREEBSD_MAJOR}\.[0-9]+-RELEASE" | grep -Eo '[0-9]+\.[0-9]+-RELEASE' |
sort -Vr | sort -Vr |
uniq)" uniq)"
URL="" URL=""
FREEBSD_VER="" FREEBSD_VER=""
for ver in $RELEASE_LIST; do for ver in $RELEASE_LIST; do
# FreeBSD 15+ publishes separate -ufs/-zfs images instead of a generic one candidate="https://download.freebsd.org/releases/VM-IMAGES/${ver}/amd64/Latest/FreeBSD-${ver}-amd64.qcow2.xz"
for variant in "" "-ufs" "-zfs"; do if curl -fsI "$candidate" >/dev/null 2>&1; then
candidate="https://download.freebsd.org/releases/VM-IMAGES/${ver}/amd64/Latest/FreeBSD-${ver}-amd64${variant}.qcow2.xz" FREEBSD_VER="$ver"
if curl -fsI "$candidate" >/dev/null 2>&1; then URL="$candidate"
FREEBSD_VER="$ver" break
URL="$candidate" fi
break 2
fi
done
done done
if [ -z "$URL" ]; then if [ -z "$URL" ]; then
msg_error "Could not find a FreeBSD ${FREEBSD_MAJOR}.x amd64 qcow2 image." msg_error "Could not find generic FreeBSD amd64 qcow2 image (non-UFS/ZFS)."
exit 115 exit 115
fi fi
msg_ok "Download URL: ${CL}${BL}${URL}${CL}" msg_ok "Download URL: ${CL}${BL}${URL}${CL}"
@@ -772,7 +768,7 @@ DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'> <a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/> <img src='https://raw.githubusercontent.com/michelroegl-brunner/ProxmoxVE/refs/heads/develop/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>
<h2 style='font-size: 24px; margin: 20px 0;'>OPNsense VM</h2> <h2 style='font-size: 24px; margin: 20px 0;'>OPNsense VM</h2>
@@ -818,70 +814,10 @@ if [ -n "$WAN_BRG" ]; then
msg_ok "WAN interface added" msg_ok "WAN interface added"
sleep 5 # Brief pause after adding network interface sleep 5 # Brief pause after adding network interface
fi fi
# FreeBSD 15+ VM images ship the base system as pkgbase packages; the bootstrap's send_line_to_vm "sh ./opnsense-bootstrap.sh.in -y -f -r 26.7"
# "delete all packages" step would remove the running base system (/bin/rm etc.)
# and brick the VM. Deregister them from the pkg db first - the files stay in
# place and OPNsense replaces base and kernel with its own sets afterwards.
send_line_to_vm "echo \"PRAGMA foreign_keys=ON; DELETE FROM packages WHERE name LIKE 'FreeBSD-%';\" | pkg shell"
sleep 5
send_line_to_vm "sh ./opnsense-bootstrap.sh.in -y -f -r ${var_version}"
msg_ok "OPNsense VM is being installed, do not close the terminal, or the installation will fail." msg_ok "OPNsense VM is being installed, do not close the terminal, or the installation will fail."
# The bootstrap ends with an automatic reboot into OPNsense. While it runs the #We need to wait for the OPNsense build proccess to finish, this takes a few minutes
# console keeps changing (download progress, package installs); once the VM has sleep 1000
# settled at the login prompt the screen stays static. Poll a screendump hash
# and continue after 3 minutes without change, bounded by a floor (the build
# never finishes faster) and a ceiling for slow machines. If no screendump can
# be captured at all, fall back to a fixed wait.
SCREEN_PPM="${TEMP_DIR}/screen-${VMID}.ppm"
function screen_hash() {
# Remove the previous dump first: a stale file from an earlier successful
# dump must not simulate a static screen when later dumps start failing.
# Note: "qm monitor" is unusable here - its readline attaches to /dev/tty
# even with piped stdin and captures the terminal, so use the API instead.
rm -f "$SCREEN_PPM"
timeout 10 pvesh create /nodes/$(hostname -s)/qemu/$VMID/monitor --command "screendump ${SCREEN_PPM}" >/dev/null 2>&1 || true
md5sum "$SCREEN_PPM" 2>/dev/null | cut -d' ' -f1 || true
}
build_elapsed=300
build_stable=0
screen_ok=0
hash_a=""
hash_b=""
sleep 300
while [ $build_stable -lt 6 ] && [ $build_elapsed -lt 2400 ]; do
sleep 30
build_elapsed=$((build_elapsed + 30))
new_hash=$(screen_hash)
if [ -n "$new_hash" ]; then
screen_ok=1
# The login prompt cursor may blink: a screen alternating between the same
# two frames (A/B/A/B) counts as stable, anything new resets the counter
if [ "$new_hash" = "$hash_a" ] || [ "$new_hash" = "$hash_b" ]; then
build_stable=$((build_stable + 1))
else
build_stable=0
fi
else
build_stable=0
fi
hash_b="$hash_a"
hash_a="$new_hash"
if [ -n "$new_hash" ]; then
echo -e "${DGN}Waiting for OPNsense build: ${YW}$((build_elapsed / 60))min elapsed, screen ${new_hash:0:8}, stable ${build_stable}/6${CL}"
else
echo -e "${DGN}Waiting for OPNsense build: ${YW}$((build_elapsed / 60))min elapsed, screendump failed${CL}"
fi
# No working screendump after several attempts: fixed wait instead
if [ $screen_ok -eq 0 ] && [ $build_elapsed -ge 480 ]; then
msg_error "Console screendump not available on this system - falling back to a fixed wait (12 minutes)."
sleep 720
build_elapsed=$((build_elapsed + 720))
break
fi
done
msg_ok "OPNsense build finished after $((build_elapsed / 60)) minutes"
send_line_to_vm "root" send_line_to_vm "root"
send_line_to_vm "opnsense" send_line_to_vm "opnsense"
send_line_to_vm "2" send_line_to_vm "2"
@@ -919,8 +855,8 @@ if [ -n "$WAN_BRG" ] && [ "$WAN_IP_ADDR" != "" ]; then
send_line_to_vm "2" send_line_to_vm "2"
send_line_to_vm "n" send_line_to_vm "n"
send_line_to_vm "${WAN_IP_ADDR}" send_line_to_vm "${WAN_IP_ADDR}"
send_line_to_vm "${WAN_NETMASK}" send_line_to_vm "${NETMASK}"
send_line_to_vm "${WAN_GW}" send_line_to_vm "${LAN_GW}"
send_line_to_vm "n" send_line_to_vm "n"
send_line_to_vm " " send_line_to_vm " "
send_line_to_vm "n" send_line_to_vm "n"
+2 -2
View File
@@ -273,7 +273,7 @@ function extract_xz_with_pv() {
function default_settings() { function default_settings() {
VMID=$(get_valid_nextid) VMID=$(get_valid_nextid)
MACHINE=" -machine q35" MACHINE="q35"
FORMAT="" FORMAT=""
DISK_SIZE="32G" DISK_SIZE="32G"
HN="umbrelos" HN="umbrelos"
@@ -564,7 +564,7 @@ mkdir -p "$CACHE_DIR" "$(dirname "$FILE_IMG")"
download_and_validate_xz "$URL" "$CACHE_FILE" download_and_validate_xz "$URL" "$CACHE_FILE"
qm create $VMID${MACHINE} -bios ovmf -agent 1 -tablet 0 -localtime 1 ${CPU_TYPE} \ qm create $VMID -machine q35 -bios ovmf -agent 1 -tablet 0 -localtime 1 ${CPU_TYPE} \
-cores "$CORE_COUNT" -memory "$RAM_SIZE" -name "$HN" -tags community-script \ -cores "$CORE_COUNT" -memory "$RAM_SIZE" -name "$HN" -tags community-script \
-net0 "virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU" -onboot 1 -ostype l26 -scsihw virtio-scsi-pci >/dev/null -net0 "virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU" -onboot 1 -ostype l26 -scsihw virtio-scsi-pci >/dev/null