Changed
- Health checks are now opt-in — Apps no longer have health checks enabled by default. Enable per-app with
health_check: trueor in bulk from Settings. TLS certificate verification is skipped for health checks to support self-signed certs common in homelabs. - Build tag split — Go builds no longer require a
dist/placeholder directory. Dev builds compile withoutembed_webtag; production builds use-tags embed_webto embed frontend assets. - Docker PUID/PGID support — Container entrypoint now creates a runtime user matching
PUID/PGIDenvironment variables for bind-mount permission compatibility (linuxserver.io convention). - Docker security hardening —
docker-compose.ymladdsinit: true,no-new-privileges, andcap_drop: ALL. - Settings modal refactored — Extracted each tab (General, Apps, Theme, Security, About) into its own component, reducing Settings.svelte from ~3800 lines to ~1800.
- Button styles standardized — All buttons in Settings now use the design system classes (
.btn,.btn-primary,.btn-secondary,.btn-ghost) instead of hand-rolled Tailwind. - Open mode labels — Consistent display between Add and Edit flows; both now use shared
openModesconstant.
Added
- Iframe caching — Visited app iframes are kept alive in the DOM when switching between apps. Returning to a previously opened app is instant — no reload, no lost scroll position, no re-authentication. Frames are pruned when apps are deleted or disabled.
- Forward auth login page — When auth method is
forward_auth, the login page shows an "External Authentication" message instead of a username/password form that can't be used. The/api/auth/statusendpoint now includesauth_methodin its response. - Runtime URL interceptor for reverse proxy — Proxied SPAs (like Plex) that construct URLs dynamically in JavaScript now work correctly. The proxy injects a script that patches
fetch(),XMLHttpRequest,WebSocket,EventSource, and DOM property setters (img.src, etc.) so all requests route through the proxy automatically. - Content-type-aware rewriting — HTML and CSS get full path rewriting; JS, JSON, and XML use safe-only rewriting (SRI stripping, absolute URLs) to avoid corrupting API data that apps read programmatically.
- Dynamic proxy route rebuilds — Adding, editing, or removing a proxied app in Settings takes effect immediately without restarting Muximux.
- Hash-based app routing — Clicking an app updates the URL hash (e.g.,
#plex), allowing direct links to specific apps and browser back/forward navigation between them. - Debug logging — Add
?debug=trueto the URL to enable browser console logging across all major subsystems (config, websocket, auth, theme, health, icons, keybindings). Persists via localStorage; disable with?debug=false. - Flat bar style for top/bottom navigation — a streamlined layout that shows apps in a single row separated by group icon dividers, without group headers or collapsible sections.
- Per-app keyboard shortcut assignment — assign number keys (1–9) to specific apps instead of relying on position-based ordering. Configured via
shortcutfield on each app or in Settings > Keybindings. - Per-app health check toggle — disable health monitoring for individual apps with
health_check: false. Useful for apps that don't respond to HTTP checks or where you don't care about status. Includes bulk enable/disable in Settings. - Base path support — serve Muximux at a subpath behind a reverse proxy (e.g.,
https://example.com/muximux/). Configure withserver.base_pathin config,--base-pathCLI flag, orMUXIMUX_BASE_PATHenvironment variable. - Cancel button on Edit modals — Edit App and Edit Group modals now have a Cancel button that reverts changes. Previously only "Done" was available, which applied changes immediately.
- Validation on Edit modals — Edit App and Edit Group modals now validate with Zod schemas before accepting, matching the Add flows.
- Redirect open mode in UI — The
redirectopen mode is now available in the Settings dropdown (previously only configurable via YAML). - Dynamic themed favicons — All favicons (browser tab, apple-touch-icon, Android manifest icon, theme-color meta) now update to match the current theme's accent color instead of using static green PNGs.
- Screenshot gallery — README now includes a collapsible gallery with numbered screenshots covering onboarding, themes, dashboard, and log viewer. Wiki pages reference screenshots inline.
.btn-dangerdesign system class — For destructive action buttons (delete confirmations).--accent-on-primarytheme variable — Dedicated text color for accent-colored buttons, ensuring readable contrast in both dark and light themes.- Docstring coverage enforcement — CI checks that 80%+ of exported Go identifiers have doc comments (
scripts/check-docstrings.sh). - CHANGELOG-based release notes — Release workflow extracts notes from CHANGELOG.md instead of auto-generating from PR titles. Falls back to auto-generation if no entry found.
- CONTRIBUTING.md — Developer guide covering prerequisites, dev mode, building, testing, and PR process.
- systemd service file —
muximux.servicefor bare-metal deployments with security hardening. - Snyk Node scan — CI security workflow now scans frontend npm dependencies in addition to Go and Docker.
Fixed
- Health tooltip showing nanoseconds — Health check response times in tooltips now correctly display milliseconds instead of raw nanosecond values.
- Proxy 404 on double-prefixed URLs — XML/JSON API responses from proxied apps no longer have root-relative paths statically rewritten, preventing double-prefixing when the SPA embeds those paths in query parameters (e.g., Plex photo transcode URLs).
- Proxied app images invisible due to frozen iframe timeline — Chrome may freeze
document.timelineinside iframes, stalling CSS/Web Animations. The interceptor detects loaded images stuck at opacity 0 and forces them visible. - Config env var expansion corrupting bcrypt hashes — Replaced
os.ExpandEnvwith braced-only${VAR}expansion so bare$signs in bcrypt hashes and other values are not treated as variable references. - Unset
${VAR}silently replaced with empty string —${VAR}references to undefined environment variables are now preserved literally instead of being silently deleted. - Config export zeroing live password hashes — Exporting config (
GET /api/config/export) no longer corrupts in-memory auth state. The shallow struct copy now deep-copies the users slice before stripping sensitive fields. - Config save race between API and auth handlers — Both handlers now share a single
sync.RWMutexfor all config reads and writes, preventing concurrent saves from silently overwriting each other. - GetApps and GetGroups missing read lock — These endpoints now acquire the config read lock, preventing data races with concurrent config writes.
- Single-app update overwriting proxied app URL —
PUT /api/app/{name}now preserves the original backend URL for proxied apps instead of saving the frontend proxy path. - App rename via bulk save dropping auth rules — Renaming an app in Settings no longer loses its AuthBypass and Access rules; a positional fallback matches renamed apps to their original config.
- Theme delete failing when
@theme-iddiffers from filename — Theme ID is now always derived from the filename, ignoring@theme-idmetadata comments. - Cannot clear user email or display name —
PUT /api/auth/users/{name}now accepts empty strings to clear these fields instead of silently ignoring them. - Button text contrast on accent backgrounds — Primary buttons use
--accent-on-primary(white) instead of--bg-basewhich was near-black in dark themes. - Theme family cards — Now use semantic
<button>elements instead of<div role="button">with manual keyboard handlers. - Separated setup and add-user state — The "Create first user" form in Security no longer shares state with the "Add User" modal.
- Icon browser pre-population — Opening the icon browser for a new app/group now passes the current icon selection.
- Static assets blocked by auth middleware — Root-level static files (manifest.json, favicon.ico, apple-touch-icon.png, etc.) were incorrectly blocked by authentication, causing browser errors. Auth bypass rules now use explicit paths instead of non-functional glob patterns.