Docker discovery becomes predictable: auto-import only touches containers
that carry a muximux.* label, it can never write an app without a URL or
leave a config that refuses to start, Swarm and Compose apps keep one
identity across redeploys, and labels you set (name, icon, group, order,
health check, group style) stay applied while an app is tracked. Settings
now merges onto the live config instead of overwriting it, every open
browser follows config changes, and every bundled theme meets WCAG AA
contrast, with focus kept inside dialogs and much better keyboard support.
Upgrade notes:
- Auto-import imports only labelled containers. An auto-imported app whose
container has no labels is detached from auto-import (the app is kept) on
the first refresh underupdate/sync. - Swarm and Compose apps get new tracking keys (
swarm:<service>,
compose:<project>:<service>), migrated in place on the first refresh. - Labels that are set now re-sync onto apps you imported by hand, so an
edit to those fields in Settings is reset while the label is set; remove
the label or detach the app to keep your edit. (#500) - Restore refuses legacy
server.gatewaybackups and explains how to
convert them; a saved theme cannot use a bundled theme's name;
lifecycle_allowed_groupsaccepts any group names. - API scripts that
PUT /api/configwithoutbasekeep the old two-way
behaviour; the gateway site PUT accepts an optionalbase_backend_url;
GET /api/discovery/docker/configis new.
Added
- Explicit opt-in for auto-import.
discovery.docker.require_explicit_enable
andMUXIMUX_DISCOVERY_REQUIRE_EXPLICIT_ENABLElimit auto-import to
containers labelledmuximux.app.enabled=true. The environment override
stays in memory and shows as locked in Settings. (#496) muximux.app.health_checklabel enables or disables health monitoring
for an imported app; it is re-synced like the other label fields and shown
locked in the app's settings. (#497)- Docker Swarm. Services are tracked as
swarm:<service>(and Compose
services ascompose:<project>:<service>), ingress-published ports and
deploy.labelsare read from the service,container_dnsuses the
service name, and one app is imported per service. Existingname:keys
are migrated on the first refresh. A socket proxy must allow/services
(SERVICES=1). (#499) - The Discover modal says why a container is not auto-imported, and
Settings -> Discovery lists invalid auto-imported entries that were not
loaded and tracked containers that are missing. (#499) GET /api/discovery/docker/configreturns the stored discovery
config, andPUTmerges onto it. (#494)baseonPUT /api/configenables a three-way merge, and apps and
groups acceptoriginal_name; the admin config response lists
env_overrides. A save that would create two apps or groups with the same
name is refused with 409 and Settings blocks Save until one is renamed.
(#494)base_backend_urlon the gateway site PUT keeps Docker tracking when
the backend address was refreshed while the site was being edited. (#494)- Docker group labels.
muximux.group.icon,muximux.group.colorand
muximux.group.orderset the look and order of a group Docker discovery
created; the container with the lowest tracking key wins a conflict, and
editing the group in Settings hands it back. (#500) - The Discover modal marks containers that are already tracked with a
"Tracked" chip naming the app, gateway site or quarantined entry, and warns
when an import name is already taken. (#500)
Changed
- Auto-import considers only labelled containers. A container needs at
least onemuximux.*label;muximux.app.enabled=falseopts out (under
syncthe app is removed). Upgrade note: an auto-imported app whose
container has no labels is detached from auto-import on the first refresh
underupdate/sync: it stays, its URL keeps refreshing, andsyncno
longer removes it. (#499) - Tracking keys for Swarm and Compose containers change to
swarm:<service>andcompose:<project>:<service>; existingname:keys
are migrated automatically on the first refresh. (#499) - Swarm apps take their name from the service. Under
update/syncan
auto-imported Swarm app without amuximux.app.namelabel is re-synced
from the task name to the service name on the first refresh, which can
change its slug and its/proxy/<slug>/path. (#499) - Images whose last path segment is generic (
server,app,web,api
and similar) no longer match a catalog entry by that segment. (#499) - Live updates. Every open browser receives a
config_updatedevent
after any config change and refetches the config (the page reloads only
when the language changed); an open Settings dialog keeps unsaved edits
and rebases them onto the new state. (#494) - Settings closes only after a successful save. On failure it stays open
with the server's message; every close path asks about unsaved changes and
is blocked while a save runs. Discard also reverts keybinding and theme
previews. (#494) - Docker tracking is server-owned on every endpoint.
POST /api/apps
andPOST /api/gateway/sitesignoredocker_*fields in the payload, as
the PUTs already do; only discovery's import attaches an app or site to a
container. (#494) lifecycle_allowed_groupsare user and identity-provider group names;
renaming or deleting a dashboard group no longer touches them. (#494)- Restore uses the startup load path.
${VAR}expansion, defaults and
validation apply, and users, auth, OIDC, discovery and proxy routes reload
at once. Listen address, TLS, base-path routing and session cookie
settings still need a restart. A backup with the legacyserver.gateway
setting is refused with 400. (#494) - Status colours come from theme tokens. Warnings, errors, success and
info notices, pills and the danger button read--success-*,
--warning-*,--danger-*,--info-*,--accent-text,
--accent-on-primaryand--danger-solidinstead of fixed Tailwind
shades, so themes can set them; omitted tokens fall back to the defaults.
The theme editor writes the text colour for accent fills when a custom
theme is saved (pure white or black, whichever reads better on the
accent). Visible shifts that come with this: status text, tints and
borders move to one shade per status; the Login and onboarding primary
buttons use the theme accent instead of a fixed brand shade; buttons
share the standard button style; accent-coloured text and links are one
shade off in some themes and links underline on hover; focus is a uniform
2px outline; the unknown health dot is a hollow ring and the tooltip's
uptime badge uses the status badge colours. - Theme colours adjusted for contrast. Every bundled theme now meets
WCAG 2.1 AA for text (4.5:1) and for control borders and focus outlines
(3:1), light and dark. Muted and secondary text moved a step towards the
foreground; the elevated and overlay surfaces of Catppuccin, Cineplex Dark,
Gruvbox, Nord and Solarized Dark are a step darker; buttons use dark text
on most accents; accent-coloured text moved a step away from the
background so accent badges reach 4.5:1 on their tint. Accent and status
base colours are unchanged. Custom themes that omit the new tokens get
values derived from their own colours, switched by@theme-is-dark. - Form controls have a visible boundary. Inputs, selects, textareas,
checkboxes and the locale picker use a new--border-inputtoken that
meets 3:1 on every surface; card and divider borders are unchanged. - Toasts follow the theme instead of always being dark.
- Primary buttons keep their colour on hover. The primary button and
the floating navigation button signal hover with their glow and shadow
instead of switching to the secondary accent, which fell below AA in
several light themes. A custom theme that omits--accent-on-primary
gets a readable text colour derived from its own accent. - Linux in the update instructions shows Tux in his own colours.
Fixed
- Label re-sync for tracked apps.
muximux.app.name,icon,groupand
orderare re-synced onto every tracked app that auto-import does not own
(apps imported by hand), in every mode includingoff, instead of only on
first import. Auto-imported apps followauto_importupdate/syncand
are left alone underoffandadd. (#500) - Auto-created groups appear in the sidebar. A group an import needs is
created in the same save, and an app whose group is missing is listed
under Ungrouped instead of disappearing. (#500) network_filteris applied consistently. The refresh tick lists
containers through the same filtered path as the scan, so a multi-network
container gets its URL from the filtered network, and Swarm services are
read once per tick. (#500)- Docker auto-import can no longer break the config. A container without
a usable port is skipped (and shown as not importable) instead of written
without a URL; an update never blanks an existing URL; the poller validates
before saving. An invalid auto-imported entry already inconfig.yamlis
quarantined at startup with a warning instead of stopping Muximux, is kept
in the file, and no longer blocks saving from Settings. Swarm redeploys and
scaled Compose services no longer duplicate or re-create apps. Names that
differ only by case or punctuation are deduplicated. "Tracked docker
container not found" is logged once per outage instead of every refresh.
syncremoves only auto-imported apps, and only after the container has
been absent for three consecutive scans. (#499) - Custom apps added in the onboarding wizard appear on the dashboard.
An app added through the wizard's custom app form was saved in an "Other"
group that was never created, so it stayed hidden until the group was
added by hand. Finishing the wizard now also creates any group an app
refers to. - Settings keeps what you changed and nothing else. Saving from Settings
merges your edits onto the current server config instead of replacing it,
so apps added by Docker auto-import or an import, URLs refreshed by the
poller, a cookie scope set in the Gateway tab, and edits from another tab
are no longer reverted or deleted. Renaming an app keeps its access rules,
Docker tracking and forwarded-headers setting. Imports no longer show a
false "Unsaved changes" or an empty Apps list. (#494) - Discovery tab shows and keeps its stored values. Host IP, network
filter, refresh interval, auto-import mode and badge placement are read
from the config and preserved on save, including fields the tab does not
show (auto_import, TLS paths);npipe://endpoints are accepted on
Windows and an enabled config with an empty endpoint gets the platform
default. (#494) - Environment overrides stay in the environment.
MUXIMUX_LOG_LEVEL,
MUXIMUX_LOG_FORMAT,--listen/MUXIMUX_LISTEN,
--base-path/MUXIMUX_BASE_PATHandMUXIMUX_DISCOVERY_AUTO_IMPORTare
no longer written intoconfig.yamlby a save; Settings shows them as
locked. (#494) - Forward-auth saves keep
forward_auth_admin_groups; a failed user change
no longer lingers in memory. (#494) - Gateway site saves are validated like startup, so a gated site without a
cookie scope can no longer break the next restart; the forward-headers
checkbox shows the real value; sites imported from the Gateway tab appear
at once. (#494) - The onboarding wizard opens only on a new install and never for a
non-admin; finishing it keeps existing groups, navigation, theme and
discovery settings; a retry after a failed save no longer hits 409. (#494) - Custom theme delete works again; a theme cannot shadow a bundled one;
theme editor previews are cleaned up. (#494) - Health settings reach the client with snake_case keys and polling follows
them right after a save; floating navigation position from the config is
honoured; Docker state loads under a base path; the http_action method no
longer flips to GET when the form opens;proxy_timeoutcan be cleared;
replacing a custom icon in another format shows at once. (#494) - Restoring a backup with the legacy
server.gatewaysetting (string or
map) explains how to convert it instead of reporting invalid YAML. (#494) - Accessibility groundwork. Every focusable element shows the same
visible focus outline, and a field with an error keeps its danger border
while focused. The health indicator has a name, a distinct shape per
status and a tooltip that opens with the keyboard ("Check now" in it is
still mouse-only). Errors are announced as alerts and confirmations as
status messages, the onboarding wizard announces step changes, the log
level filters report on or off, and form controls and icon-only buttons
have names, including per-row actions. Transitions, spinners and pulses
calm down when the operating system asks for reduced motion. - Focus stays inside dialogs. Settings and every other dialog trap Tab
and Shift+Tab, make the page behind them inert and return focus to the
control that opened them; pickers opened over a dialog keep their own
focus, and Escape closes each sub-dialog. Theme and onboarding cards no
longer nest controls inside each other, links in running text are
underlined, and the log view scrolls with the keyboard. - Status text is legible on light themes. "Unsaved changes", failed
saves (previously pink on pink), warnings, success notices, pills, the
Logs level colours and the keyboard-conflict notice use per-theme colours
with AA contrast; disabled-looking grey is no longer used for real
content or placeholders.
Security
golang.org/x/netv0.60.0 -- fixes GO-2026-6603, GO-2026-6610,
GO-2026-6611, GO-2026-6612 and GO-2026-6617 in the HTTP/2 code reached by
the reverse proxy.- Restore drops all sessions and refuses racing logins. Restoring a
backup reloads users and auth immediately, ends every session, and refuses
a login that was in progress during the restore, so credentials from before
the restore cannot survive it. An unreachable OIDC provider in a backup is
switched off instead of kept. (#494) - Admin auth endpoints wait for setup. Before setup completes, only auth
status, setup, login, logout,meand the OIDC sign-in routes answer
without the setup token; creating users or an API key, changing the auth
method and the OIDC settings return 503setup_requiredinstead of
running as the pre-setup admin. (#494) - Setup token no longer readable from the log viewer. Before setup, an
anonymous caller could read the setup token fromGET /api/logs/recent
and use it to claim the instance. The token is now printed only to the
console (container/console output) and is never written to the log
buffer ormuximux.log; the log viewer,/api/system/updatesand
/api/system/info, the/wslive stream and the/proxy/app routes
return 503setup_requireduntil setup completes -- only the theme list,
icon routes and static assets the wizard uses stay open. A setup
token found in a log file written by an earlier release is replaced with
a new one at startup, and newly created log files are mode 0600. (#494)