-
Notifications
You must be signed in to change notification settings - Fork 84
gateway examples
3.1.0 note: The recipes below are written as gateway Caddyfile blocks for reference. In 3.1.0+ the supported configuration form is
server.gateway_sites:declarative YAML; a 3.0.x Caddyfile is auto-migrated to the YAML form on first boot. Use the Configuration Reference for the YAML schema, and Settings -> Gateway in the dashboard to edit visually. The Caddyfile snippets here still describe what each gateway-site option does; map them to the YAML equivalents by hand or feed your existing Caddyfile throughmuximux migrate-gatewayto see the conversion side-by-side.
Practical recipes for using Muximux's embedded Caddy as a reverse proxy for your other services. See TLS & HTTPS for initial setup.
Your config.yaml needs one or more gateway_sites: entries. Server-level tls is not required -- each site's own tls: auto provisions its certificate, and the embedded Caddy binds :80/:443 as soon as any gateway site exists:
server:
listen: ":8080"
tls:
domain: "muximux.example.com" # or cert/key for manual TLS
email: "admin@example.com"
gateway_sites:
- domain: grafana.example.com
backend_url: http://grafana:3000
tls: auto # auto | none | customExpose ports 80 and 443 (Caddy needs both for ACME and HTTPS). Adding or removing gateway_sites: entries reloads Caddy in place -- no full restart required. Schema changes to existing sites (TLS-mode flip, auth gate toggle) also reload in place.
The recipe sections below show the Caddyfile shape for each scenario; translate each into the corresponding gateway_sites: entry fields (see Configuration Reference for the full schema).
Each gateway site proxies one backend_url per domain. The fields you can set are:
-
backend_url-- thehttp://orhttps://backend (no path, query, or transport flags) -
tls-- certificate mode (auto,none, orcustom) -
proxy_headers-- extra headers sent to the backend -
forwarded_headers-- emitX-Forwarded-*andX-Real-IP(default true) -
streaming-- disable response buffering for streaming backends -
strip_frame_blockers-- removeX-Frame-Options/CSP frame headers so the app can load in an iframe -
backend_skip_tls_verify-- skip verifying a self-signed / untrustedhttpsbackend certificate (e.g. Proxmox) -
require_auth/min_role/allowed_groups-- gate the site behind Muximux auth (see Gateway Auth)
Anything outside this list (basic auth, rate limiting, subpath routing, wildcard host matching, arbitrary transport tuning like read_buffer) is not a gateway-site option. Those recipes are marked below and need an external proxy in front of Muximux.
The simplest case: one domain, one backend.
grafana.example.com {
reverse_proxy localhost:3000
}
Caddy automatically obtains a Let's Encrypt certificate, redirects HTTP to HTTPS, and proxies all traffic. Nothing else needed.
Add as many site blocks as you need:
grafana.example.com {
reverse_proxy localhost:3000
}
sonarr.example.com {
reverse_proxy localhost:8989
}
radarr.example.com {
reverse_proxy localhost:7878
}
prowlarr.example.com {
reverse_proxy localhost:9696
}
jellyfin.example.com {
reverse_proxy localhost:8096
}
Each domain gets its own certificate. Caddy handles renewals automatically.
If those backends run as Docker containers, Apps tab → Discover from Docker (or Gateway tab → Discover from Docker) builds the same site list in one click. Pick "Gateway" routing per row and supply the public domain; the gateway site is created and Caddy reloads in the same transaction. URLs auto-refresh as container IPs shift. See Docker Discovery.
Or enable discovery.docker.auto_import so labeled containers appear automatically without opening the modal (see Docker Discovery). Note: in update/sync mode, gateway-only label changes (require_auth, min_role, allowed_groups, streaming, strip_frame_blockers, forwarded_headers, skip_tls_verify) propagate on their own on the next refresh tick -- an app field no longer has to change too.
Labels on your compose file pre-fill name, icon, port, and a stable tracking key:
# docker-compose.yml
services:
sonarr:
image: linuxserver/sonarr
labels:
- muximux.discovery.id=sonarr-stable # survives docker-compose --force-recreate
- muximux.app.name=Sonarr
- muximux.app.icon=sonarr
- muximux.app.group=Media
# port + scheme auto-detected from the catalog for known imagesCaddy proxies WebSocket connections automatically -- no extra configuration. This works out of the box for apps like Homeassistant, Code Server, Portainer, and Gotify.
homeassistant.example.com {
reverse_proxy localhost:8123
}
Some apps need specific headers to work behind a reverse proxy.
On a gateway site, forwarded headers are emitted for you and arbitrary backend headers go in proxy_headers:
gateway_sites:
- domain: app.example.com
backend_url: http://app:8080
proxy_headers: # extra headers sent to the backend
X-Api-Key: "secret"
forwarded_headers: true # X-Forwarded-* + X-Real-IP (default true; set false to suppress)Plex needs large header buffers and the real client IP:
plex.example.com {
reverse_proxy localhost:32400 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
transport http {
read_buffer 8192
}
}
}
Not available via
gateway_sites: this requires an external Caddy/nginx in front of Muximux. The embedded gateway only proxies onebackend_urlper domain. Forwarded headers (X-Real-IP,X-Forwarded-*) are emitted automatically; the customtransport/read_buffertuning is not configurable on a gateway site.
Proxmox serves its web UI on :8006 with a self-signed certificate. Set backend_skip_tls_verify: true so the gateway does not reject that certificate:
gateway_sites:
- domain: proxmox.example.com
backend_url: https://192.168.1.10:8006 # https + self-signed
tls: auto
backend_skip_tls_verify: true # skip verifying the backend certbackend_skip_tls_verify only applies to an https:// backend_url, and affects the gateway-to-backend hop only -- the public-facing certificate Caddy serves for proxmox.example.com is unaffected. (Label form: muximux.gateway.skip_tls_verify=true.)
Vaultwarden needs both the web vault and WebSocket notifications:
vault.example.com {
reverse_proxy localhost:8082
}
Vaultwarden v1.29+ handles WebSocket on the same port, so a simple reverse_proxy is sufficient.
Harden responses with security headers:
sonarr.example.com {
header {
X-Content-Type-Options nosniff
X-Frame-Options DENY
Referrer-Policy strict-origin-when-cross-origin
-Server
}
reverse_proxy localhost:8989
}
The -Server removes Caddy's Server header from responses.
Protect a service that has no built-in authentication:
filebrowser.example.com {
basicauth {
admin $2a$14$... # bcrypt hash
}
reverse_proxy localhost:8085
}
Generate a bcrypt hash with Caddy's own tool (caddy hash-password) or any bcrypt utility -- for example htpasswd -nbBC 12 "" 'your-password' | cut -d: -f2. Muximux's embedded Caddy is an internal runtime only and does not expose a CLI surface of its own.
Not available via
gateway_sites: this requires an external Caddy/nginx in front of Muximux. The embedded gateway only proxies onebackend_urlper domain. To gate a site behind Muximux's own login instead, setrequire_authon the gateway site (see Gateway Auth).
Protect public-facing services from abuse:
api.example.com {
rate_limit {
zone dynamic_zone {
key {remote_host}
events 10
window 1s
}
}
reverse_proxy localhost:9000
}
Note: Rate limiting requires the third-party
rate_limitCaddy module, which is not compiled into Muximux's embedded Caddy (only the standard module set is included: reverse proxying, headers, TLS, and basic auth). This directive will not work here. For rate limiting, put Muximux behind an external proxy that provides it.
Route different paths on the same domain to different backends:
services.example.com {
handle /grafana/* {
reverse_proxy localhost:3000
}
handle /prometheus/* {
reverse_proxy localhost:9090
}
handle {
respond "Not found" 404
}
}
Make sure each service is configured to serve from the correct subpath (e.g., Grafana's GF_SERVER_ROOT_URL=https://services.example.com/grafana/).
Not available via
gateway_sites: this requires an external Caddy/nginx in front of Muximux. The embedded gateway only proxies onebackend_urlper domain (no path orhandlerouting).
If you use a wildcard DNS record (*.example.com → your-server-ip), you can add new services by just appending site blocks to the Caddyfile. No DNS changes needed per service.
Not available via
gateway_sites: this requires an external Caddy/nginx in front of Muximux. The embedded gateway only proxies onebackend_urlper domain, with no wildcard host matching. Add each subdomain as its own gateway site instead.
For wildcard TLS certificates, you need a DNS provider plugin for the ACME DNS-01 challenge:
*.example.com {
tls {
dns cloudflare {env.CF_API_TOKEN}
}
@grafana host grafana.example.com
handle @grafana {
reverse_proxy localhost:3000
}
@sonarr host sonarr.example.com
handle @sonarr {
reverse_proxy localhost:8989
}
handle {
abort
}
}
Note: DNS provider plugins (like
cloudflare) must be compiled into the Caddy binary. Muximux's embedded Caddy includes the standard modules only. If you need DNS-01 challenges, consider using Muximux behind an external Caddy instance that includes the DNS plugin, or run certbot separately and usetls.cert/tls.keywith manual certificates.
When running Muximux in Docker, your gateway backends need to be reachable. There are two approaches:
Add your services to the same Docker network as Muximux and use container names:
# docker-compose.yml
services:
muximux:
image: ghcr.io/mescon/muximux:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./data:/app/data
networks:
- proxy
grafana:
image: grafana/grafana
networks:
- proxy
# No need to expose ports -- Caddy connects via the Docker network
networks:
proxy:
name: proxyThen in your gateway site, use the container name as the backend host:
gateway_sites:
- domain: grafana.example.com
backend_url: http://grafana:3000Alternatively, use network_mode: host or reference host.docker.internal:
gateway_sites:
- domain: grafana.example.com
backend_url: http://host.docker.internal:3000Note:
host.docker.internalworks on Docker Desktop and on Linux with Docker 20.10+ (addextra_hosts: ["host.docker.internal:host-gateway"]to your compose file).
A complete example for a typical homelab:
config.yaml:
server:
listen: ":8080"
tls:
domain: "home.example.com"
email: "admin@example.com"
gateway_sites:
- domain: grafana.example.com
backend_url: http://grafana:3000
tls: auto
- domain: sonarr.example.com
backend_url: http://sonarr:8989
tls: auto
apps:
- name: Grafana
url: https://grafana.example.com
icon: { type: dashboard, name: grafana }
open_mode: iframe
enabled: true
- name: Sonarr
url: https://sonarr.example.com
icon: { type: dashboard, name: sonarr }
open_mode: iframe
enabled: true
- name: Proxmox
url: https://proxmox.example.com
icon: { type: lucide, name: server }
open_mode: new_tab # Proxmox doesn't work in iframes
health_check: false # Proxmox health endpoint isn't standard
enabled: trueGateway sites only accept an http:// or https:// backend_url with no path, query, or subpath routing. Proxmox is shown here as a new_tab dashboard app because its UI does not embed in an iframe -- but it could equally be a gateway site, since its self-signed backend is handled by backend_skip_tls_verify (see the Proxmox recipe above).
docker-compose.yml:
services:
muximux:
image: ghcr.io/mescon/muximux:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./data:/app/data
networks:
- proxy
restart: unless-stopped
networks:
proxy:
external: trueEach gateway site you add automatically gets HTTPS. Add a corresponding app entry in config.yaml to see it on your dashboard.
-
In-place reload: Adding, editing, or removing
gateway_sitesreloads Caddy in place -- no full restart required. -
Validated before apply: Gateway sites are validated when the config loads or when you save in Settings → Gateway. An invalid entry (bad domain, backend with a path, unknown
tlsmode) is rejected with a specific error rather than silently breaking Caddy. -
Certificate storage: Caddy stores certificates in its default data directory. In Docker, this is inside the container -- certificates are re-obtained on container recreation. To persist them, mount a volume to
/data(Caddy's default storage path inside the Muximux container). -
Dashboard integration: Gateway sites are proxied by Caddy directly -- they don't go through Muximux's built-in reverse proxy. Add them as apps in
config.yamlusing theirhttps://domain URLs to see them on the dashboard. - Debug: If a gateway service isn't working, check Muximux's logs. Caddy logs through Muximux's logging system and will report certificate errors and unreachable backends.
Getting Started
Features
- Apps
- HTTP Actions
- Reverse Proxy
- Docker Discovery
- Navigation
- Split View
- Themes
- Keyboard Shortcuts
- Health Monitoring
- Icons
- Translations
Security
Identity provider guides
Operations