vzdump and pct restore ran with their output thrown away, so a failed
backup only said "Backup failed for container N" (exit 235). That is the
second most common update-apps failure and none of them can be told
apart. Keep the output in the run log and put its error line in the
message, e.g. "CT is locked (backup)".
var_backup_storage was matched with grep -w, so "truenas" passed when
only "truenas-backup" exists and vzdump then failed on a storage that
does not exist. Match the whole name, and list the valid ones in the
error instead of a spinner line after it.
Name the app in "Update failed for container N", so a failed update
says which app's update failed. Declining the start dialog now exits 0
like the other tools instead of failing with whiptail's 1.
clear exits 1 for a TERM the host has no terminfo entry for, such as
xterm-ghostty or xterm-kitty over SSH, and when TERM is unset under cron.
The tools that run under errexit died on it in header_info within a
second, before showing anything, which telemetry counts as
"exit_code=1 | General error" with no step for update-lxcs, update-repo,
fstrim, clean-lxcs, execute and storage-share-helper.
Fall back to the escape sequence the engine's _cs_clear uses.
Both whiptail prompts ran bare under errexit, so No on the first question
or Cancel in the template list ended in the error handler and was reported
as a failed run (3 of 5 failures in three days).
Monitor-All is now stopped right before the download instead of at the
start, so leaving at a prompt no longer leaves it stopped.
The user was the first passwd entry with a UID from 1000 up. On a Proxmox
host with Ceph that is ceph (UID 64045, shell nologin), and su - ceph fails
with "This account is currently not available". Accounts without a login
shell are skipped now.
apt update on a host with the enterprise repository and no subscription exits
100 on the 401. apt_update_safe retries, says why and carries on, as the other
scripts already do since #17462.
The container menu lists stopped containers too, and pct exec on one exits
255: 12 of 41 failures in three days. Start it the way add-netbird-lxc does
and wait for its default route.
The install runs under bash, which an Alpine container from the template does
not have; lxc-attach then exits 127 before the Alpine branch is reached.
Install bash there first, and stop with a clear message on any OS other than
Debian, Ubuntu or Alpine instead of failing on apt-get.
Nothing checked that the host is a Backup Server. On a PVE host the
first step stopped only because tar found no /etc/proxmox-backup (exit
2); answering "no" to that backup would have gone on to delete
/etc/apt/sources.list.d/*.list, add the PBS repositories and
dist-upgrade. Stop with the same message post-pbs-install uses.
The add-on runs on the Proxmox host, where the enterprise repository without a
subscription answers 401 and apt update exits 100 (2 of 3 failures in three
days). apt_update_safe retries, points at the enterprise repository and
carries on; the netdata repository was fetched fine.
Cancel in the first menu was reported as a failed run.
pct fstrim exits 255 when the container is locked, for example while a
backup runs ("CT is locked (backup)"). Under errexit the command
substitution ended the whole run there, before the output check below it
and before the remaining containers, and telemetry filed it as
"DPKG: Fatal internal error". Print the result and go on instead.
The skip message printed $name, which is only set once a container has
run the command. When a non-Debian container (Alpine, for example) came
before any Debian one, set -u ended the run there with "name: unbound
variable" and exit 1; later it printed the previous container's name.
The target list came from storages with "images" content, but pct
restore puts the container's rootfs there and refuses a storage without
"rootdir" ("storage 'X' does not support container directories"). A
storage that holds VM disks only was offered, and picking it ended the
run after the backup with "Conversion failed" (exit 235).
On a PVE 9 host without deb822 .sources files the script asks whether to
disable the legacy .list sources, then read the answer from $? on the
next line. Under set -e a "No" ended the whole run with exit 1 right
there, so the "Kept legacy sources as-is" branch never ran and nothing
after it was offered. Test whiptail in the if instead.
* Drop the legacy engine copies from misc/
Nothing has loaded misc/*.func since ct/, install/, vm/ and tools/ moved to
community-scripts/core. misc/api.func stays until vm/owncloud-vm.sh gets its
DevScripts rewrite.
misc/images/ moves to .github/assets/. The tombstone stub for removed scripts
sourced misc/build.func and called variables(), which core's PVE engine does
not define; it now sources core.func.
* Drop misc/api.func
vm/owncloud-vm.sh was its last caller; DevScripts holds that script's rewrite
onto core/pve/vm-core.func. Merge this after the promotion.
* post-pmg-install: hide the subscription nag in the PMG 9 mobile quarantine
PMG 9 replaced pmgmanagerlib-mobile.js with the Yew/WASM app in
pmg-mobile-quarantine-ui, so the mobile hook no longer found its file.
The status check is compiled into the WASM, so the helper now injects a
fetch wrapper into the mobile index template that reports the
subscription as active to the app. The API response itself is unchanged.
All patches move into /usr/local/bin/pmg-remove-nag.sh behind a single
apt hook. "no" now also removes the mobile hook and the helper, and the
reinstall covers pmg-mobile-quarantine-ui so its template is restored.
Fixes#16217
* post-pmg-install: reinstall the mobile quarantine UI only where it exists
pmg-mobile-quarantine-ui is not in the PMG 8 (bookworm) repository, so
naming it in the reinstall made apt abort there and skip the widget
toolkit reinstall as well.
The mobile UI patch removed the dialog and card only when their text
contained "subscription", so translated UIs (de: "Subskription", fr:
"Abonnement", ...) kept the nag. It also deleted DOM nodes Yew still
owns and polled every 300 ms for good.
The helper now injects a fetch wrapper into the mobile index template
that fills the empty subscription level of each node in the /nodes
response, so the app never shows the alert or card. The API response
itself is unchanged; the node list shows "-" instead of "No
subscription". The mobile UI package is reinstalled alongside the widget
toolkit so old blocks are dropped, and "no" also removes the helper.
IPP 4.0 lets visitors upload through a second, optional app in the same
repository. The addon now builds the whole workspace, so upload-app is
always ready, and can run it as immich-proxy-upload on port 3001: asked
on install (var_ipp_uploads), offered in the menu of an existing
install, rebuilt and restarted on update with its config.json kept, and
removed on uninstall. It stays off unless chosen.
v2.0.0 reads the config strictly and stops at the v1 keys the addon
wrote (server.port, conditionals, indexingIntervalMinutes). It also only
imports the old BoltDB when server.database.migrateFrom names it and no
database.db is left in the working directory. The update now rewrites
the config, renames the database and points migrateFrom at it, keeping
a copy of the v1 config. New installs write the v2 layout.
The CT check resolved the IP by running ip inside the guest via pct
exec, which depends on the guest having it installed. If not, this
always comes back empty, so the container is restarted every cycle
despite answering ping. lxc-info reports the addresses from the
host without running anything inside the guest.
Fixes#17685
* Scripts: close every msg_info block with msg_ok
Past-tense msg_info calls that should have been msg_ok, notices that opened a block before a prompt, and blocks without a closing msg_ok. These already left a stale spinner; with core's block stack they would resume it after every later msg_ok.
* Generate passwords with random_password
openssl rand -base64 | tr -dc | head -c returned fewer characters than asked for, and the unfiltered | cut variants put / and + into passwords that end up in DSNs and sed expressions. Secrets an app decodes as base64 are unchanged. Requires community-scripts/core#61.
* Keep data directories through CLEAN_INSTALL instead of copying them
create_backup copied uploads, storage and similar directories twice per update and needed their size again in free space. CLEAN_INSTALL_KEEP moves them aside instead. Only directories the upstream release does not ship, in scripts that restored right after the fetch. Requires community-scripts/core#61.
* Drop the 300s uv timeout overrides
setup_uv exports UV_HTTP_TIMEOUT=600 now; the scripts' 300 only lowered it. Requires community-scripts/core#61.
One checklist now lists containers and VMs side by side, each tagged with its
type, with separate ALL CT / ALL VM entries. VMs stop via qm stop and are
removed with qm destroy --purge --destroy-unreferenced-disks.
Two fixes fall out of the rework: the destroy exit status is read from the
background job rather than from the spinner, so failures actually surface, and
a guest is only stopped once its deletion is confirmed.
A container keeps the slug it was built with, so a renamed ct/ script leaves
the updater looking for a name that no longer exists.
Reported for pbs, renamed to proxmox-backup-server in 0e5f663df. The Alpine
merge on 2026-08-18 retired 29 more names the same way, so every container
installed from an alpine-* script before that date hits this too.
Candidates are only accepted when the target script really exists, so an
unknown slug still errors rather than running some other app's updater.
Fixes#16989
* docker-vm, pve-privilege-converter: source from GitHub raw instead of gitea mirror
* docker-vm, pve-privilege-converter, vm-core.func: source from GitHub raw instead of gitea mirror
* Fix: Incorporate the new update functions to prevent a empty grep on the legacy link in /usr/bin/update
* Remove outdated comments from update-apps.sh
Removed comments regarding the new-style entrypoint and fallback logic for service extraction.
---------
Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com>
* Move the top 25 scripts onto the core engine
The engine work of the last few days reaches 30 of 561 ct scripts, about 5% of
ProxmoxVE traffic: retry on engine downloads, exit 227 instead of a misfiled
dpkg error, the umask fix that stops a hardened host producing containers apt
cannot resolve in, the TMPDIR guard, the toolchain restore. All of it has been
sitting where almost nobody runs it.
All eighteen at once rather than in waves. A slow rollout does not exercise the
paths only some scripts take, and broad exposure is what surfaces bugs -- a
deliberate call about release risk.
Checked before touching anything, because "migrate" meant far more than a line
swap last time:
- None of the eighteen has an alpine-* variant, so there is no merge to do.
- No script references misc/ outside its bootstrap line.
- Of the 61 functions that exist only in misc/, none is called by any of them.
So it is one line per script, and every head is now byte-identical to the ones
migrated earlier. With these, ProxmoxVE goes from 30 scripts on the core engine
to 48 -- and from roughly 5% of traffic to the majority, since these are the
ones people actually install.
Two to watch: immich sits at 44.7% success and vaultwarden at 42.1% before
this. If their numbers move, the engine is one of two changed variables rather
than the only one.
* Move update-apps onto the core engine
Entry 11 of the list and the only one that is not a ct script, so it was left
out of the previous commit. It is a host tool: it never used build.func at all,
it sources misc/core.func and misc/api.func directly.
The swap is therefore two lines rather than one, and worth checking rather than
assuming. It uses exactly five engine functions -- header_info,
init_tool_telemetry, msg_info, msg_ok, msg_error -- all present in the core, and
both files load standalone, which they had not had to do before: everywhere else
they arrive through build.func.
That completes the list. All 25 now run on the core engine.
Fixing this one matters beyond the migration: update-apps is what drives
unattended updates across every container on a host, and it is the path where
PHS_SILENT was being ignored (#16593). It now gets the engine that honours it.
msg_info starts a background spinner while loading the container list,
but the script never stops it before opening the interactive radiolist,
so the spinner keeps repainting over the UI.
Co-authored-by: Cursor <cursoragent@cursor.com>