# Configuration ## Overview Muximux is configured via a single YAML file. By default, this is `data/config.yaml` (inside the data directory). The data directory defaults to `data/` relative to the binary's location and can be changed with `--data` or `MUXIMUX_DATA`. You can also override the config path directly: ```bash # Change the data directory (config will be at /opt/muximux/data/config.yaml) muximux --data /opt/muximux/data # Or override the config path explicitly muximux --config /path/to/config.yaml ``` ## Complete Configuration Reference ```yaml # ─── Server ───────────────────────────────────── server: listen: ":8080" # Listen address (default: ":8080") title: "Muximux" # Page title shown in browser tab log_level: info # Log verbosity: debug, info, warn, error log_format: text # Log output format: text or json proxy_timeout: 30s # Global timeout for proxied requests base_path: "" # Subpath for reverse proxy (e.g. "/muximux") # Optional: TLS / HTTPS tls: domain: "" # Auto-HTTPS domain (requires email) email: "" # Let's Encrypt registration email cert: "" # Path to TLS certificate PEM key: "" # Path to TLS private key PEM # Replaced by `gateway_sites:` below. If you're upgrading from # 3.0.x and still have this set, Muximux converts it to # `gateway_sites:` on first boot and saves backups of both the # original `config.yaml` and your Caddyfile alongside them. gateway: "" # legacy # Optional: Override the bind address for the embedded Caddy that # serves gateway sites. Useful when (a) you don't want to grant # CAP_NET_BIND_SERVICE / run as root, or (b) an upstream proxy # terminates TLS and you want Caddy on a high port behind it. # When set, gateway sites are emitted with http://: # and auto-https is disabled. Empty = legacy behaviour (:80/:443). gateway_listen: "" # e.g. ":8443" # Optional: cookie scope for cross-subdomain session sharing. # Required when any entry in gateway_sites has require_auth=true, # otherwise the session cookie won't reach the gated subdomain. # Leading dot is optional (browsers normalise). session_cookie_domain: "" # e.g. ".example.com" # Optional: declarative gateway sites served by the embedded Caddy. # See the Gateway Examples and Gateway Auth Gate wiki pages for the # full reference. Each entry can optionally gate access behind the # Muximux session via require_auth + min_role + allowed_groups. gateway_sites: - domain: sonarr.example.com # required backend_url: http://192.168.1.5:8989 # required tls: auto # auto | none | custom tls_cert: "" # required when tls=custom tls_key: "" # required when tls=custom streaming: false # disable Caddy response buffering for live data strip_frame_blockers: true # strip X-Frame-Options for iframe embedding forwarded_headers: true # forward X-Forwarded-Proto/Host/Real-IP backend_skip_tls_verify: false # skip verifying a self-signed HTTPS backend (Proxmox); https backends only proxy_headers: {} # extra headers injected on upstream requests # Optional: also surface this site in the dashboard menu app_name: "" # link to an existing app by name # Gateway auth gate (3.1.0+) -- gate this subdomain behind Muximux login require_auth: false # 302 anonymous visitors to /login first min_role: "" # "user" / "power-user" / "admin"; empty = any signed-in user allowed_groups: [] # case-insensitive; admins bypass # Auto-populated by Docker discovery on import; do not hand-edit. # Presence of docker_key locks backend_url to the refresh poller. docker_key: "" docker_endpoint: "" docker_strategy: "" # ─── Authentication ───────────────────────────── auth: method: none # none, builtin, forward_auth, oidc setup_complete: false # Set automatically after onboarding wizard completes session_max_age: 24h # Session duration (default: 24h) secure_cookies: false # Require HTTPS for session cookies api_key_hash: "" # Optional bcrypt hash of API key for X-Api-Key auth # Builtin auth users users: - username: "" password_hash: "" # bcrypt hash (see Authentication page) role: admin # admin, power-user, or user email: "" # Optional display_name: "" # Optional # Forward auth settings trusted_proxies: [] # CIDR ranges, e.g., ["192.168.0.0/16"] headers: user: Remote-User email: Remote-Email groups: Remote-Groups name: Remote-Name # Note: key is "name" not "display_name" logout_url: "" # Auth provider logout URL (e.g., https://auth.example.com/logout) # OIDC settings oidc: enabled: false issuer_url: "" client_id: "" client_secret: "" # Supports ${ENV_VAR} syntax redirect_url: "" # Must match provider callback URL scopes: [openid, profile, email] username_claim: preferred_username email_claim: email groups_claim: groups display_name_claim: name admin_groups: [] # Groups that grant admin role # ─── Theme ───────────────────────────────────── theme: family: default # Theme family: default, nord, dracula, etc. variant: system # dark, light, system (follow OS preference) # ─── Navigation ───────────────────────────────── navigation: position: top # top, left, right, bottom, floating width: 220px # Sidebar width auto_hide: false auto_hide_delay: 0.5s show_on_hover: true show_labels: true show_logo: true show_app_colors: true show_icon_background: false show_splash_on_startup: false show_shadow: true icon_scale: 1.0 # Icon zoom multiplier bar_style: grouped # grouped or flat (top/bottom bars only) floating_position: bottom-right # bottom-right, bottom-left, top-right, top-left hide_sidebar_footer: false # Hide the footer section in sidebars max_open_tabs: 0 # Max app tabs kept alive in memory (0 = unlimited) # ─── Icons ────────────────────────────────────── icons: dashboard_icons: cache_dir: icons/dashboard # Where fetched dashboard icons are cached cache_ttl: 7d # How long a cached icon is reused before refetch # ─── Health Monitoring ────────────────────────── health: enabled: true interval: 30s timeout: 5s # ─── Docker Discovery (optional, opt-in) ─────── # Connect to a Docker daemon to discover running # containers and keep their URLs current. See the # Docker Discovery wiki page for the full guide. discovery: docker: enabled: false # opt-in; requires socket access endpoint: unix:///var/run/docker.sock # or tcp://host:2376 network_strategy: container_ip # container_ip | container_dns | host_port | host_docker_internal network_filter: "" # scope scans to one docker network when set host_ip: "" # required by host_port strategy refresh_interval: 60s # poller cadence auto_import: off # off (default) | add | update | sync; auto-import muximux.*-labeled containers lifecycle_enabled: false # allow start/stop/restart of tracked containers (requires :rw socket mount) lifecycle_min_role: admin # min role for lifecycle controls lifecycle_allowed_groups: [] # additionally require group membership health_badge_placement: overview # overview | overview_and_nav | off tls: # only needed for tcp:// with mTLS enabled: false ca_cert: "" # CA bundle that signed the daemon cert client_cert: "" # client certificate (PEM) client_key: "" # client key (PEM, chmod 600) # ─── Keyboard Shortcuts ──────────────────────── keybindings: bindings: {} # Custom overrides only; defaults managed client-side # ─── Groups ───────────────────────────────────── groups: - name: Media icon: type: lucide name: play color: "#e5a00d" order: 1 expanded: true # ─── Apps ─────────────────────────────────────── apps: - name: Plex url: http://plex:32400 # health_url: http://plex:32400/web # Optional custom health endpoint icon: type: dashboard name: plex # variant: light # Icon variant (dashboard icons only) # file: healarr # Filename in data/icons/ (type: custom only) # url: https://example.com/icon.png # Remote image URL (type: url only) # color: "#ff0000" # Tint color (Lucide only) # background: "#1a1a2e" # Icon background override # invert: false # Invert icon colors (dark ↔ light) color: "#e5a00d" group: Media order: 1 enabled: true default: true open_mode: iframe # iframe, new_tab, new_window, redirect, http_action proxy: false proxy_skip_tls_verify: true # Skip TLS certificate verification (default: true) proxy_headers: # Custom headers sent to the backend X-Custom-Header: value scale: 1.0 health_check: true # Opt-in: set true to enable health monitoring for this app shortcut: null # Assign a number key (1-9) for quick switching min_role: "" # Minimum role to see this app (user, power-user, admin) force_icon_background: false # Show icon background even when global setting is off auth_bypass: [] access: roles: [] users: [] ``` ## Command Line Options ``` muximux [flags] --data PATH Base data directory (default: data/ beside binary, env: MUXIMUX_DATA) --config PATH Override config file path (default: /config.yaml, env: MUXIMUX_CONFIG) --listen ADDR Override listen address (env: MUXIMUX_LISTEN) --base-path PATH Subpath for reverse proxy (e.g. /muximux, env: MUXIMUX_BASE_PATH) --version Show version and exit ``` Precedence: CLI flag > environment variable > config file value > default. ## Environment Variable Expansion Use `${VARIABLE_NAME}` in any string value to reference environment variables. This is useful for keeping secrets out of config files: ```yaml auth: oidc: client_secret: ${OIDC_CLIENT_SECRET} api_key_hash: ${MUXIMUX_API_KEY_HASH} apps: - name: Plex url: ${PLEX_URL} ``` If the referenced environment variable is not set, the `${VAR}` reference is left as-is (the literal string is preserved). This avoids silently deleting values when an env var is missing. ### Direct Override Environment Variables These override the corresponding config file values without needing `${VAR}` syntax in config.yaml: | Variable | Description | Default | |----------|-------------|---------| | `MUXIMUX_DATA` | Base data directory | `data/` beside binary | | `MUXIMUX_CONFIG` | Override config file path | `/config.yaml` | | `MUXIMUX_LISTEN` | Listen address (e.g., `:9090`) | From config file | | `MUXIMUX_BASE_PATH` | Subpath for reverse proxy (e.g., `/muximux`) | Empty (root) | | `MUXIMUX_LOG_LEVEL` | Log verbosity (debug, info, warn, error) | From config file | | `MUXIMUX_LOG_FORMAT` | Log format (`text` or `json`) | `text` | ## Validation Rules Muximux validates the configuration on startup and will refuse to start if the configuration is invalid. The following rules are enforced: - If `tls.domain` is set, `tls.email` is required (for Let's Encrypt registration). - `tls.cert` and `tls.key` must both be set or both empty. You cannot provide only one. - `tls.domain` and `tls.cert` are mutually exclusive. Use either auto-HTTPS or manual certificates, not both. - Legacy `gateway:` (Caddyfile path) configs from 3.0.x are auto-migrated to `gateway_sites:` on first boot under 3.1.0 (clean conversions only; lossy ones surface a hard error pointing at `muximux migrate-gateway`). - If any `gateway_sites[]` entry has `require_auth: true`, `server.session_cookie_domain` is required and every gated site must be a subdomain of it (real host-suffix check: `evilexample.com` is not a subdomain of `example.com`). - `gateway_sites[].min_role` must be one of `user`, `power-user`, `admin` when set (empty means "any authenticated user"). - `server.gateway_listen` must be a valid bind address (e.g., `:8443` or `127.0.0.1:8443`). ## Live Configuration Most settings can be changed through the Settings panel while Muximux is running. Changes are saved to `data/config.yaml` immediately and take effect without restarting. The following settings **require a restart** to take effect: - `server.listen` (listen address/port) - `server.base_path` (subpath prefix) - `server.tls.*` (all TLS settings) - `server.gateway_listen` (overrides the bind port for the embedded Caddy) - `server.session_cookie_domain` (cookie scope; takes effect on next login) - `server.gateway_sites:` schema changes (the auth gate; backend swaps and TLS-mode flips reload Caddy in place) Everything else -- navigation, themes, apps, groups, icons, keybindings, health monitoring, log level, log format -- is applied immediately. ## Config Export and Import You can export your configuration as a downloadable YAML file and import it on another instance: - **Export** strips sensitive data (password hashes, OIDC secrets, API key hashes) before download. - **Import** parses the uploaded YAML, validates it, and shows a preview so you can review before applying. This is available in the Settings panel under the General tab, or via the API (see [API Reference](api.md)). ## Config API The configuration can also be read and updated via the API: - `GET /api/config` -- Retrieve the current configuration (any authenticated user). - `PUT /api/config` -- Update the full configuration (admin role required). - `GET /api/appearance` -- Read-only snapshot of language, theme id, and theme colors, for embedded apps that want to sync their own appearance (see [Apps > Appearance API](apps.md#appearance-api)). See the [API Reference](api.md) for details.