Security & Privacy · Clash Technical Blog

How to Access the Clash Dashboard Remotely and Safely

Secure remote Clash Dashboard access by restricting the control interface listen address, setting a secret, and connecting only through a private network or tunnel.

  • Security
  • Dashboard
  • secret
On this page

Treat remote access to Clash Dashboard as access to an administrative interface

Clash Dashboard uses the REST API exposed by external-controller to read connections, traffic, proxy groups, and rules. This interface can also switch nodes, reload the configuration, change some runtime settings, and close connections, so exposing port 9090 directly to the public internet is far riskier than publishing a read-only status page.

First answer who needs access. For local use, listen only on a loopback address. For occasional viewing on the same LAN, still restrict sources, set a secret, and add firewall rules. For remote administration, use an SSH tunnel or forwarding over a controlled Tailscale network; do not map 0.0.0.0:9090 directly to the public internet.

Access scenarios and recommended entry points

ScenarioListening methodAccess restrictions
Panel bundled with a local client127.0.0.1:9090A strong secret, preventing arbitrary web pages from calling the local interface
Administration from the home LANAn explicit LAN address or restricted listenerThe firewall allows only management devices or private subnets
Temporary maintenance from another locationContinue listening only on the local machineAccess through SSH local forwarding or Tailscale
Public internet serviceDirect exposure is not recommendedAt minimum, use a separate reverse proxy, TLS, authentication, and source restrictions

If cross-device access is unnecessary, restrict the listening address to the local machine

In the final active Mihomo configuration, bind external-controller to 127.0.0.1. A graphical client may generate this field through “Settings → External Controller” or an override file, so editing the raw subscription may have no effect. After reloading, inspect both the final configuration and the actual listener.

REPLACE_WITH_RANDOM_SECRET below is only a placeholder. Use a password manager to generate a long random value, replace it in both the configuration and Dashboard connection settings, then reload Mihomo. Do not use the placeholder itself as the password.

A starting point for a local-only Dashboard
external-controller: 127.0.0.1:9090
secret: "REPLACE_WITH_RANDOM_SECRET"
Confirm what is listening on 9090
# Windows PowerShell
Get-NetTCPConnection -LocalPort 9090 -State Listen

# Linux / OpenWrt
ss -lntp | grep ':9090'

After setting a secret, verify that unauthenticated requests are actually rejected

The secret is the external controller's Bearer Token. An empty value, a short password, or long-term reuse across devices effectively grants administrative access to anyone who can reach the port. After generating a random value, enter it in both the Mihomo configuration and Dashboard backend-address settings. Do not include the full token in screenshots, a front-end repository, or public troubleshooting logs.

Test no credentials, incorrect credentials, and correct credentials separately
# 无 Authorization,应返回未授权,而不是接口数据
curl -i http://127.0.0.1:9090/version

# 错误 token 也必须被拒绝
curl -i -H "Authorization: Bearer WRONG_TOKEN" http://127.0.0.1:9090/version

# 只在自己的终端中替换 REAL_TOKEN
curl -i -H "Authorization: Bearer REAL_TOKEN" http://127.0.0.1:9090/version

Results that prove authentication works

  • A request without Authorization returns 401 rather than version JSON
  • The correct secret can read /version
  • An incorrect secret is also rejected
  • Dashboard shows connections and proxy groups correctly after a refresh
  • Neither the logs nor the browser address bar exposes the secret

If Dashboard will not open, do not immediately allow every CORS origin

A remotely hosted Dashboard is a web origin that sends requests to external-controller from the browser. CORS restricts which web origins can call the interface; it does not replace user authentication.

Setting allow-origins to * and also allowing private network requests makes it easier for any website to attempt access to local or LAN controller ports. Even with a secret configured, the blast radius is larger if it leaks.

First confirm the Dashboard's actual origin, such as https://dashboard.example.com, and allow only that complete origin. A change in the domain, scheme, or port creates a different origin. The UI static-file path in the configuration and the API listening address are also separate: a page that opens does not mean the control API is connected securely.

Replace the example domain with the actual Dashboard origin
external-controller-cors:
  allow-origins:
    - "https://dashboard.example.com"
  allow-private-network: false

For temporary remote maintenance, use an SSH tunnel to bring 9090 to the local machine

If Mihomo runs on a home server, keep external-controller on 127.0.0.1:9090 and use SSH local forwarding to map the remote loopback port to the current computer. The browser still connects to its own 127.0.0.1, while 9090 remains invisible to the public internet.

Example: map the remote controller to local port 19090
ssh -N -L 19090:127.0.0.1:9090 [email protected]

# Dashboard 后端填写
http://127.0.0.1:19090

When using Tailscale, do not assume that everyone on the tailnet is an administrator. Use tailnet policy to restrict which users or devices can access the host and port, and keep the secret. If a home router must listen on a LAN address, allow only the management computer through the firewall—not Guest Wi-Fi or the entire WAN zone.

Secure access path for a remote administration panel
  1. Your browserInitiate access only from a trusted device
  2. SSH tunnel or VPNDo not expose the controller port directly
  3. 127.0.0.1:9090external-controller listens only on the local machine
  4. MihomoValidate control requests with a secret

If listening on a LAN address is unavoidable, also restrict firewall sources and keep a sufficiently long secret.

Add a reverse proxy in front of 9090 only when long-term access is required

Deploy a reverse proxy only when you need a stable domain and long-term remote access. Mihomo's external-controller should still listen on 127.0.0.1:9090, while Nginx, Caddy, or another gateway on the same host serves HTTPS externally. Expose only the reverse-proxy port to the public internet, not 9090.

The reverse proxy should have at least valid TLS, a separate sign-in or client authentication, source restrictions, access logs, and correct forwarding for the WebSocket used by Dashboard. Keep Mihomo's secret as well; it and reverse-proxy authentication are two independent layers and cannot replace each other. Store the secret in Dashboard connection settings instead of appending it to a public URL.

If the Dashboard page and API use different domains, add the page's exact origin to CORS. After configuring it, test with an external port scan or from another device: the HTTPS domain should present a sign-in, while direct access to the server's public IP:9090 should fail to connect.

A persistent remote entry point should meet these requirements

  • external-controller still listens only on 127.0.0.1
  • No public port mapping exists for 9090
  • The reverse proxy enforces HTTPS and has independent authentication
  • WebSocket logs and the traffic page update normally
  • The Mihomo secret still validates successfully
  • Unauthorized sources cannot connect

Test once from the server itself and once from another device

Complete acceptance checks

  1. Inspect the listener locally

    Confirm that the port is bound to the intended address and that the process is the current Mihomo instance rather than an old one.

  2. Unauthenticated access

    Use curl to request /version and confirm that a missing or incorrect token returns 401.

  3. Authenticated access

    Open Dashboard, switch one test policy group, and confirm that Mihomo shows the same result.

  4. Test from a network without permission

    Test from a LAN, Guest Wi-Fi, or public address that should not have access; the connection should time out or be refused.

  5. Restart and retest

    After restarting Mihomo, confirm that the client did not overwrite the listening address, secret, or firewall rules.

If the controller may have been exposed, first tighten the listener and firewall, then rotate the secret. Next, inspect port mappings, cloud security groups, reverse-proxy access logs, and configuration-repository history. Changing only the Dashboard password cannot invalidate a leaked Bearer Token.

References