OCI manager Apps
- App tab: containers installed from an OCI image are identified from their
installation record; the application and image versions are shown and an
update is detected by image digest; repository link; Refresh data.
- Updates tab for OCI containers: Update and Recreate run the same flow as the
OCI menu in the Monitor terminal; the pre-update backup can be kept in a
backup storage; scheduled image updates with an optional minimum age.
- Logs tab: console output of the application, kept on the host
(lxc.console.logfile + logrotate) and followed live.
- The Proxmox console opens a shell (cmode: shell) when the image has one.
- A damaged image download is fetched again before failing.
- Multi-container applications open at their LAN address; volume mount
points on block storage report their usage.
Monitor
- Proxmox notifications are delivered to a loopback-only HTTP listener when
HTTPS is enabled, so they no longer fail certificate verification.
- Log persistence counts recurring patterns only; an ended burst is not
reported as persistent and its warning clears on its own (#386).
- Proxmox notification config backups are deduplicated and capped at three.
- The update icon on the Apps page opens the container on its Updates tab.
- Version 1.2.6.2-beta and its release notes in every Monitor language.
Docs
- OCI manager Apps and Audit & Report rebuilt as per-page message files,
with a new page for OCI containers in the Monitor.
- Seven pages fixed where rich-text tags were missing from t.rich.
Translations
- Spanish fixes across the OCI engine, the Monitor and the TUI menus.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The glossary only holds what someone listed, and what reaches the reader
as a broken command was never on it. Paths, long options and Proxmox
subcommands are now recognised by shape:
/dev/apex_0 came back as /dev/apex 0
--auto-uninstall desinstalación automática
pct config 110 configuration PCT 110 (fr)
pct enter 101 pct inserire 101 (it)
OCI joins the glossary as well. Read as a word it became "BEC" in French
across thirty-one strings — "Vérification du BEC" named nothing — and the
menu entry read "Gestionnaire du BEC Apps". The entry itself and "beta"
are protected too, so the name stays the same in every language.
A provider can also alter a token rather than carry it through: argos
returned MPXTERM000 for PMXTERM000, the restore found nothing, and the
token shipped. "MPXTERM000 configuré" is in the French catalogue today.
The restore now verifies its own tokens and fails the string instead,
which leaves the key absent for the next run to retry.
Spanish category labels: twenty-six were wrong. Seven collapsed two
categories into one — "Backup & Recovery" read only "Recuperación",
"Network & Firewall" read "Red de cortafuegos" — six were half
translated, and the connector alternated between "&", "y" and "e". They
now use "y" or "e" throughout. "IoT & Smart Home" and
"AI / Coding & Dev-Tools" stay in English by choice.
"Messaging & Queues" becomes "Messaging & Notifications": its only
application is Apprise, a notification gateway, not a queue. The
Helper-Scripts import still maps their name, so nothing breaks upstream.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two next steps in the backup area claimed more than the evidence behind
them supports, reported by @Vaso73 while reviewing the pattern.
A failed run is now treated as unsuccessful with a copy to confirm,
rather than asserted to have produced nothing usable — the task log does
not establish that. And a missing host-configuration record says no
backup is recorded here, leaving room for one this node cannot see.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both batches seed the same block for their English-only additions. One
read and one write now cover the PBS key guidance and the Borg SSH keys
together.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds the OCI manager: an engine that turns a Docker Compose file into an
LXC definition, a catalog of 365 applications drawn from LinuxServer.io
and other container image sources, and a per-instance registry recording
what each container was built from. Reachable from the main menu.
Catalog text is translated like every other string in the project: the
taglines go through translate() and land in lang/*.json, so the entries
read in all eight languages instead of only English.
Translation cache builder:
- a failed translation leaves the key absent rather than writing English,
which previously made the string count as translated forever
- a result identical to a 3+ word source is rejected, catching a provider
that silently returns the text it was given
- strings that are nothing but glossary terms keep their source spelling
instead of being discarded as failures
- no backoff between attempts when the provider is deterministic
- application names are protected so "HAOS One" survives translation
- argos joins the provider list, and the workflow reads the OCI sources
Audit & Report:
- findings that moved in the wrong direction between runs are reported
alongside the ones that improved
- an accepted risk can carry a review date and is flagged when it falls due
- backup checks explain in plain language what they looked at and what to
do next
Monitor:
- disks can be excluded from periodic reads, and an idle disk says so
instead of showing a stale temperature
- per-disk identity survives a controller or enclosure change
- scheduled Borg backups resolve their SSH key from the repository entry
- PVE upgrades log the package list and the resulting dpkg changes
The web build no longer copies scripts/ into public/: the documentation
links to GitHub, so nothing read that folder.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both message batches seeded locale copies at the same point of
test_command_descriptions.py. The two blocks are independent — one
seeds the backup messages, the other the storage ones — so they are
merged into a single block that reads and writes the fixture once.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The change journal exists so a sysadmin sees what ProxMenux changed on the host — its own configuration, packages and services — not how it uses the host or configures a guest. Several scripts recorded operations that are neither: disk passthrough to a VM, container conversions, VM import/export, mounting a share into an LXC. Those are restored to their original, uninstrumented form. Scripts that operate on the host while also installing a package now record only the package: format-disk keeps its exFAT-tools install, the UUP ISO builder its build dependencies, and the share/host scripts their packages, services and /etc/fstab writes, while the mount and unmount operations they used to log are dropped.
The page now reads in three sections: what ProxMenux optimized after install (each function under its menu name), what its other host scripts changed (by script), and what it installed (packages and utilities, each referencing the script that installed it). A file reads as created or modified with its diff, a service shows its state transition, and the undo line appears only when a revert is possible.
ProxMenux modifies the host: it rewrites configuration files, installs packages, enables services. Until now nobody could say afterwards what had changed, and showing the script does not answer that question — a four-hundred-line function may alter two values, and the reader has no way to know which two. This adds the two halves of an answer.
The change journal records what ProxMenux does as it does it. Eleven bash primitives capture the previous state, apply the change and record it in the same step, writing to a spool that the Monitor reads back. One hundred and thirteen functions across twenty-five scripts are instrumented, covering post-install, shared storage, security tooling, container conversions, disk operations and the PVE 8 to 9 upgrade path. The page shows the difference — rotate 7 becoming rotate 14 — and never the script. Restore and backup scripts are deliberately left out: a restore puts the host back to a state some other script already recorded.
The Audit and reports page answers the other half: what state is this host in, regardless of who put it there. Forty-three checks across seven areas read the host and classify each result as critical, warning, observation, conformant, unverified or not applicable, with the evidence they read attached to each one. A declared policy lets the reader say what this particular host is expected to do — which guests must have a backup, which storages are essential — so the report judges the host against its own intent rather than a generic template. An inventory records the hardware, network and guest topology behind those readings, a comparison shows what moved between two runs, and six report profiles produce a printable document scoped to what the reader needs. Everything is available in the eight supported languages.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An LXC running its workload in Docker could not answer two questions it
already had the data for: which application is in there, and whether a
newer version exists.
**Which version is available.** The Updates tab resolved that number only
for docker.io, and only when a version tag happened to share the digest of
the tag in use. On ghcr.io, lscr.io or quay.io the row said "New image
available" with no number at all. The image a pull would install carries
its own version label, so it is now read from the registry by digest —
over the same protocol and Bearer challenge the digest comparison already
uses, and through the same label lookup the installed version uses, now
shared as _docker_version_from_labels.
The question this answers is the one the tab asks: what do I get if I
re-pull this tag. Not "what is the newest upstream release", which is a
different number whenever a tag is pinned or the publisher tags releases
differently from images.
Docker Hub keeps priority on docker.io: its tag API is not a pull and does
not spend the anonymous pull-rate budget, and official images carry no
labels for the registry path to read. The digest still decides whether an
update exists; this only names it, and declines to name it when the answer
would be a guess — no build for this platform, no labels, an unreadable
manifest, a moving tag, a rebuild of the same version, or two sides whose
versions came from different label keys. Each refusal is recorded in
available_version_source.
Attestation manifests are skipped explicitly: they advertise
unknown/unknown and their config blob is a provenance document, not an
image. Every document is fetched by digest and verified against it, the
config read is bounded, and it is cached per digest, which never changes
content. The CDN redirect is followed by hand, dropping Authorization:
urllib re-sends it to the redirect target and signed-URL storage rejects a
second auth mechanism.
**Which application it is.** The probe already read "1.37.2" out of a
Vaultwarden container and get_suggestions discarded it, so the panel
answered "No new applications were detected" about an application whose
version it had just measured. Containerised applications are now offered
for registration like any other, with their name, logo, published ports
and installed version.
What they do not get is an update path of their own, because they do not
have one: updating Vaultwarden means pulling and recreating its image. A
new update_via=docker marker records that delegation, so one release stays
one badge, one notification and one button. The marker is validated rather
than inferred from installed_via, since docker_exec with an upstream is a
legitimate registration someone may already rely on; combining it with an
upstream is rejected instead of silently stripped, because registering an
app that checks GitHub behind a delegation promising it will not is worse
than an error message.
Three failure modes the delegation had to be defended against: detector
auto-healing would have migrated the app onto a leftover /root/.<app>
marker and quietly un-delegated it; saving replaces the whole record, so
the editor carries the marker explicitly rather than dropping it on the
first port edit; and the release-age hold gates on a publish date a
delegated app never has, which deferred the whole schedule forever.
Their version is resolved server-side through the container the detector
declares — not through the app's name or image, since Immich's compose
service and image are both immich-server while the application is immich.
The annotation happens on the way out of both endpoints rather than into
their caches: the App tab's cache is invalidated by events, not by time,
and the Docker inventory it reads is built asynchronously, so annotating
before storing froze a response taken before the first scan.
The rows carry that name too. display_name was already computed and
already used by the bulk-update section; the image row, the update
notification and the CT badge now use it as well. A delegated app's
pending update counts in the badge only while its image is not already
being counted, so registering just the application does not leave the
container looking up to date, and registering both does not count twice.
Catalog: four detectors verified on real containers, following the rules
in the file. vaultwarden and immich gain docker fallbacks for installs
where the native marker does not exist. netalertx is new — note its
repository is netalertx/NetAlertX; the Docker Hub namespace 404s.
technitiumdns is new and uses Technitium's own update endpoint rather than
GitHub releases: its marker reads 15.4 while the release tag is v15.4.0,
and _version_tuple compares (15,4,0) > (15,4) as an update that would
never clear.
Verified live against ghcr.io (Immich 3.1.0), docker.io (Vaultwarden
1.37.2) and lscr.io (Radarr 6.3.0.10514-ls314), plus postgres:16, which
correctly reports no version because official images carry no labels.
Exercised end to end on Proxmox VE 9.2.4 with NetAlertX reporting
26.6.3 -> 26.9.0. 31 new unit tests cover the resolution rules, every
refusal, the delegation contract and the container-to-image pairing.
Restores AI Assistant support for OpenAI-compatible endpoints on private IPs, loopback
and Docker networks (LiteLLM, LM Studio, LocalAI, vLLM, OmniRoute, self-hosted proxies)
and surfaces the server's error under the Load button (#325). Aligns the Secure Gateway
wizard's Alpine template selection and pct create with the host's real architecture on
x86_64 and arm64 (#324). Consolidates changes landing on develop: atomic notification
delivery, custom SSH port for Borg remote targets (#236), optional GitHub API token for
app version tracking (#306), and richer replication failure notifications.
feat(host-backup): custom SSH port for Borg remote targets
Add Borg destinations no longer assume port 22. The Monitor form and
the shell TUI both take an optional port (default 22, range 1-65535)
and embed it in the persisted ssh://user@host:port/path URL. BORG_RSH,
the sshpass key installer and the capacity probe all honour it.
Reported by @songochain in #236 — NAS-style Borg hosts on non-standard
SSH ports are now first-class targets.
Existing borg-targets.txt entries without a port keep working; the
port is only serialised into the URL when it differs from 22.
Stable release consolidating the v1.2.4 beta cycle (1.2.4.1-beta and 1.2.4.2-beta) into 1.2.5.
Highlights:
- Apps dashboard: single launcher for every LXC-registered app and user-defined Custom Web Link, with category badges, search, sort and one-click deep-links back to the guest modal.
- LXC Apps & Updates end-to-end: App tab inside every guest modal, upstream version tracking, and Easy Updates that cover OS packages, registered apps, Docker Engine and per-image updates on the same 24-hour cycle.
- Application detection catalog with 380+ tracked workloads generated live from community-scripts across seven detector methods.
- Monitor now speaks 8 languages: English, Spanish, German, French, Italian, Portuguese, Slovak and Swedish (i18n scaffolding by @vaso73).
- NVIDIA multi-GPU passthrough by exact BDF so one card can be assigned to a VM while another stays operational on the host or LXC.
- Navigation reorder, Memory & Swap real memory-pressure signal, native Pushover channel, Actions API, plus wide-reaching improvements across health, hardware, network, backup and post-install.
Full release notes: see CHANGELOG.md and https://github.com/MacRimi/ProxMenux/releases
- centralize the app version in a new `AppImage/lib/version.ts` — the dashboard footer, SMART report footer and release-notes modal all read from a single export, so a future bump only has to touch version.ts, package.json and beta_version.txt
- roll `package.json` and `package-lock.json` to `1.2.4.2-beta` (the lockfile was still stuck on the stale `1.2.2.2-beta` marker)
- move the previous `1.2.4.1-beta` feature list into the modal's historical CHANGELOG under its August 17, 2026 date so navigating "Anterior/Próximo" still walks through the complete history
- write the four new What's New entries for the ongoing 1.2.4.2 cycle: smarter LXC app detection (Docker promoted as parent workload during cold start, unregistered suggestions cached at startup, on-demand catalog scan), end-to-end Docker updates (Engine + per-image tracking on the 24h cycle with a "Check now" action), the 380+ workload detection catalog built from the live community-scripts source, and Pushover joining Telegram/Gotify/Discord/Email/Apprise as a native notification channel
- add the four new i18n keys (appDetection, dockerUpdates, appCatalog, pushover) to all eight bundled locales — en and es curated, the six remaining kept in English until the docs-i18n workflow retranslates them
- add an apt-listchanges notification event that surfaces package-maintainer NEWS forwarded through the PVE mail queue, with its own template, emoji and per-locale label
- emit a single post_install_update event when a tool exposes a newer version, and persist per-tool notified versions on disk so a Monitor restart no longer re-fires the same update announcement
- force AI enrichment to formatting-only on availability notices (update_available / pve_update / proxmenux_update / post_install_update / apt_listchanges / lxc_updates_available / secure_gateway_update_available / nvidia_driver_update_available / coral_driver_update_available / app_update_available / docker_stack_update_available / update_summary) so translations never turn factual inventories into advice
- add the apt_listchanges channel label to Monitor UI strings across the eight locales
- rewrite the 15 post-install pages and the 3 hardware GPU pages so they reflect the current scripts (reversibility, tracked-tool counts, kernel parameters, per-tool commands, Alpine LXC propagation flow)
- migrate the legacy step-badge helper on post-install/optional and create-vm/synology to the canonical pill component, with the stepLabel key added in each locale
- fix rich-text i18n calls missing helpers across network, automated, optional, security, customization and the post-install landing pages, and escape the `<iface>` placeholder in automated so intl no longer parses it as a tag
- remove the mouse-follow blue overlay from the docs landing layout
- reposition the App-tab Edit button and stack the Search and Register controls vertically on mobile
- move the Bulk update Configure/Edit control into the section header so it behaves the same on desktop and mobile
- show a spinner during the final autoremove/autoclean pass of update-pve-safe so the cleanup step reads as active instead of silent
- restyle the shell spinner and msg_info in a distinctive purple and drop the unused msg_lang duplicate
- add a web-docs i18n build script and its CI workflow, plus tests for the pushover notification channel