Skip to content
github-actions[bot] edited this page Feb 17, 2026 · 4 revisions

Deployment

Muximux supports three deployment styles. Pick the one that matches your setup.

Style You provide Muximux does Ports to expose
Behind an external proxy Traefik / nginx / Caddy handles TLS and auth Serves the dashboard on a single port 8080 (internal only)
Standalone with built-in proxy Direct access, optional built-in auth Dashboard + per-app /proxy/{slug}/ for iframe embedding 8080
Full reverse proxy appliance DNS records TLS certificates, HTTP→HTTPS redirects, gateway for other services 80, 443

The built-in per-app reverse proxy (proxy: true) works in all three styles -- it runs inside the Go server and is independent of Caddy or any external proxy.


Docker

The recommended way to run Muximux in production.

Behind an external proxy (Traefik, nginx, etc.)

# docker-compose.yml
services:
  muximux:
    image: ghcr.io/mescon/muximux:latest
    ports:
      - "8080:8080"
    volumes:
      - ./data:/app/data
    restart: unless-stopped

Set auth.method: none or forward_auth in config.yaml and let your external proxy handle TLS and authentication.

As a full reverse proxy appliance

# docker-compose.yml
services:
  muximux:
    image: ghcr.io/mescon/muximux:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./data:/app/data
      - ./sites.Caddyfile:/app/data/sites.Caddyfile:ro
    restart: unless-stopped

Configure tls.domain and gateway in config.yaml. See TLS & HTTPS for a full walkthrough. Port 8080 does not need to be exposed -- Caddy handles all traffic on 80/443.

Volume

Mount a directory to /app/data. This stores:

  • config.yaml -- Configuration
  • themes/ -- Custom themes
  • icons/ -- Icon caches and custom uploads

Health Check

The Docker image includes a built-in health check (GET /api/health every 30s).

Updating

docker compose pull
docker compose up -d

Systemd Service

For running Muximux as a native binary on Linux.

Create /etc/systemd/system/muximux.service:

[Unit]
Description=Muximux - Web Application Portal
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=muximux
Group=muximux
WorkingDirectory=/opt/muximux
ExecStart=/opt/muximux/muximux --data /opt/muximux/data
Restart=on-failure
RestartSec=5

# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/muximux/data
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Setup

# Create user
sudo useradd -r -s /bin/false muximux

# Create directories
sudo mkdir -p /opt/muximux/data
sudo chown -R muximux:muximux /opt/muximux

# Copy binary
sudo cp muximux /opt/muximux/

# Create config
sudo cp config.example.yaml /opt/muximux/data/config.yaml
sudo chown muximux:muximux /opt/muximux/data/config.yaml

# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable muximux
sudo systemctl start muximux

# Check status
sudo systemctl status muximux
sudo journalctl -u muximux -f

Behind an External Reverse Proxy

If you run Muximux behind Nginx, Traefik, or Caddy (external), you do not need Muximux's built-in TLS or gateway. Your external proxy handles TLS termination and optionally authentication. Set auth.method: none (if your proxy handles auth) or forward_auth (for Authelia/Authentik) in config.yaml.

The per-app reverse proxy (proxy: true) still works in this setup -- it runs inside the Go server and is unrelated to the external proxy.

Nginx

server {
    listen 443 ssl;
    server_name muximux.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Traefik (Docker Labels)

services:
  muximux:
    image: ghcr.io/mescon/muximux:latest
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.muximux.rule=Host(`muximux.example.com`)"
      - "traefik.http.routers.muximux.tls.certresolver=letsencrypt"
      - "traefik.http.services.muximux.loadbalancer.server.port=8080"
    volumes:
      - ./data:/app/data

Subpath Deployment (Base Path)

If your reverse proxy serves Muximux at a subpath (e.g., https://example.com/muximux/ instead of a dedicated domain), configure the base path so Muximux generates correct URLs for assets, API calls, and WebSocket connections.

Configuration

Set the base path using any of these methods (in order of precedence):

# CLI flag
muximux --base-path /muximux

# Environment variable
MUXIMUX_BASE_PATH=/muximux muximux

# Or in config.yaml
server:
  base_path: /muximux

The path must start with / and have no trailing slash. If not set, Muximux serves from the root.

Nginx (subpath)

location /muximux/ {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # WebSocket support
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Traefik (subpath with StripPrefix)

services:
  muximux:
    image: ghcr.io/mescon/muximux:latest
    environment:
      - MUXIMUX_BASE_PATH=/muximux
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.muximux.rule=PathPrefix(`/muximux`)"
      - "traefik.http.routers.muximux.tls.certresolver=letsencrypt"
      - "traefik.http.services.muximux.loadbalancer.server.port=8080"
    volumes:
      - ./data:/app/data

Note: Muximux handles its own path stripping internally. Do not use Traefik's StripPrefix middleware — Muximux expects the full path including the base prefix and strips it itself.

Docker Compose (subpath)

services:
  muximux:
    image: ghcr.io/mescon/muximux:latest
    environment:
      - MUXIMUX_BASE_PATH=/muximux
    ports:
      - "8080:8080"
    volumes:
      - ./data:/app/data
    restart: unless-stopped

Network Considerations

  • Same network as apps: Muximux needs to reach your apps (for health checks and the built-in reverse proxy). In Docker, use the same Docker network or host networking.
  • WebSocket support: If running behind an external reverse proxy, make sure it supports WebSocket connections (needed for real-time health updates).
  • Ports:
    • Behind an external proxy: only 8080 (or your configured listen port), and it doesn't need to be publicly accessible.
    • Standalone: 8080 (or your configured listen port).
    • Full reverse proxy appliance: 80 and 443. Port 8080 is not needed externally.

Clone this wiki locally