Config Deep Dive · · Approx. 22 min read

Clash Meta External Controller and Secret: Secure Web Dashboard and LAN Access Guide (2026)

You finally have a humming mihomo core: subscriptions hydrate, latency tests look sane, DNS modes behave. The missing convenience layer is usually the browser dashboard—something like Yacd-meta whispering politely to JSON endpoints—but the searches that land here are painfully specific: what is external-controller, why does every guide mention a Secret, must the API listen beyond 127.0.0.1, and how do we avoid copying “paste from Reddit” snippets that inadvertently expose administrative control across the LAN or worse toward the wider internet? This article maps the REST control plane separately from SOCKS and HTTP listeners, spells out pragmatic bind-address choices, validates auth handshakes over curl, and frames partnership with LAN proxy sharing tutorials when you deliberately widen reach. Companion reading: route subscribers through our Windows-focused LAN allow-lan walkthrough, and skim routing rules if policy reload API calls confuse your mental model between “what I tweak in YAML” versus “what the UI toggles”.

1. Control Plane Versus Mixed-Port Data Plane

In Clash Meta derivatives, “proxying the internet” and “managing the proxy” are separate contracts. The familiar mixed-port (or discrete port / socks-port) handles user traffic: browsers, terminals, game launchers. The external-controller listener instead speaks the REST API dialect that dashboards, automation scripts, and some GUI shells use to read runtime state, flip policy groups, stream logs, and push configuration reloads. Treat that second listener like an administrative socket on a router: powerful, chatty, and catastrophic when strangers can reach it without credentials.

Confusion arises because both surfaces appear as “a port on localhost,” yet their exposure semantics diverge. Opening the mixed port to the LAN for family devices is a policy decision we already documented for Windows households. Extending the controller across the same subnet is a different conversation: any smartphone that can hit http://192.168.1.50:9090 might attempt to interrogate or mutate your stack unless you consistently enforce Secret headers, bind only to trusted interfaces, and monitor unexpected clients. When in doubt, keep the controller loopback-only and access dashboards through SSH port forwarding or an explicit reverse proxy you control.

Practitioners sometimes conflate the controller with built-in static file hosting for web UIs. Modern cores may bundle or reference external-ui paths that serve compiled SPAs from disk. Even when the static bundle is local, the dynamic JSON still flows through the API. Securing the API secures the interactive experience; beautifying the front-end does not replace authentication on the wire.

2. Threat Model Before You Punch Holes

Begin with the uncomfortable truth: an unauthenticated external-controller on a routable address is effectively remote code configuration for your proxy graph. Attackers who can issue HTTP requests may fetch secrets embedded in memory-adjacent structures, rewrite rules, or leverage debug endpoints depending on build flags. Your Secret is therefore not “nice to have”—it is the primary gate between casual network scanning and operator-grade control. Pair it with least-privilege binding: if only your laptop browser needs the dashboard, bind to 127.0.0.1 and stop there.

LAN trust is contextual. Roommates, IoT gadgets, and guest SSIDs all share the same broadcast domain in many apartments. Hotel and café networks should be considered hostile even with passwords. Document who may access the controller, rotate the Secret when someone leaves, and prefer wired management VLANs or VPN overlays if you truly need remote administration. None of these steps are Clash-specific; they simply keep your beautiful automation from becoming someone else’s outbound traffic laundering tool.

Edge case operators running mihomo on headless Linux boxes sometimes forward the API through SSH -L tunnels to avoid exposing TCP 9090 entirely. That pattern keeps hotel Ethernet workable without permanently widening bind-address. Document the tunnel in your runbook so future you is not debugging “works on my phone but not laptop” mysteries at midnight.

3. Secret: Non-Negotiable Randomness

The configuration key is literally secret. Assign a long, high-entropy string—think password-manager random or openssl rand -hex 32 output—not your birthday or airport subscription token. Every dashboard connection, scripted health check, and manual curl invocation should include the shared bearer token in the Authorization header unless your client documents an alternate query parameter (prefer headers to keep tokens out of server logs). If you rotate the value, update saved browser profiles and automation secrets atomically; half-rotated states produce maddening 401 loops that look like “Clash broke.”

# Example — replace values; do not reuse sample secrets in production.
external-controller: '127.0.0.1:9090'
secret: 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'

Some community templates still ship with empty secrets “for convenience.” Delete that habit. If a GUI wrote the file, open the generated YAML on disk and confirm the field exists before you forward ports. Tools that embed the controller URL in QR codes or deep links must be screened: they often persist historical tokens, so scrub old phone installs when personnel changes.

Where multiple operators share one machine, consider separate accounts with OS-level permissions instead of sharing the literal token in a group chat. The REST API cannot distinguish friendly roommates from compromised laptops if the secret leaks. Layer organization policy on top of technology.

4. Bind-Address Profiles: Loopback vs LAN-Wide Listening

The external-controller value accepts a host:port tuple. Binding to 127.0.0.1:9090 limits connections to the local stack—ideal for single-user laptops and for scenarios where you will forward ports explicitly when remote. Switching to 0.0.0.0:9090 or shorthand forms that listen on all IPv4 interfaces advertises the API on every address your OS owns, including Wi-Fi, Ethernet, and virtual adapters. That may be intentional if a tablet on the same subnet should load Yacd-meta without tunneling, but it broadens attack surface commensurately.

The global bind-address knob that governs inbound proxy listeners does not automatically solve controller isolation. You might bind proxies to a LAN interface for family sharing while keeping the controller loopback-only—an excellent pattern when only you should flip nodes. Conversely, binding the controller to a specific non-loopback IPv4 (for example 192.168.1.50:9090) documents intent more clearly than wildcards, at the cost of adjusting YAML when DHCP renumbers the host. Pick explicit addresses on static reservations; keep wildcards for lab machines you frequently rebuild.

IPv6 introduces parallel questions. If your network advertises global addresses and the core binds to [::], you may unintentionally expose management interfaces beyond the subnet you imagined. Unless you understand your router’s prefix policies, prefer IPv4 loopback for the controller and rely on proxy listeners for dual-stack traffic. Document each choice in your personal wiki so future edits do not “simplify” security away.

5. Interaction With allow-lan and Proxy Ports

allow-lan toggles whether non-loopback clients may use your HTTP or SOCKS listeners, not whether the external-controller becomes magically safe. You can run allow-lan: true for shared Netflix bandwidth while the API remains on 127.0.0.1; that is often the sweet spot for households with one power user and several casual devices. Re-read the dedicated allow-lan guide when debugging mixed-port reachability before you misattribute failures to the controller.

When you intentionally expose both surfaces, treat them as two firewall rules with two narratives: “who may relay traffic” versus “who may reconfigure the relay.” Windows Defender and macOS application firewalls should list both TCP ports explicitly. If only the proxy port appears, your controller may still be world-accessible through an overly permissive rule you added months ago—audit rather than assume.

Container users bridging Docker networks should remember published ports on the host may bypass intended loopback semantics. Map only what you need, pin to 127.0.0.1 in publish flags when possible, and avoid sharing the host network namespace unless you enjoy surprise listeners. Our Docker host gateway article explores adjacent networking foot-guns that pair well with this checklist.

6. Connecting Yacd-meta and Other Dashboards Securely

Yacd-meta and sibling panels are glorified browsers over the JSON REST API. In the hosted variant you load static assets from HTTPS, then configure the frontend with your controller endpoint—typically http://127.0.0.1:9090 for local setups. Paste the identical Secret the YAML defines; mismatched capitalization or trailing whitespace silently fails with opaque console errors beginners misread as CORS doom.

Cross-origin chatter matters when dashboards run on HTTPS while your API speaks plain HTTP on loopback—browsers gate mixed content aggressively. Serving everything locally via the core’s bundled static hosting (when available) or proxying via a localhost-only TLS terminator simplifies the drama. Avoid publishing the SPA to the public internet with an open backend even if Hugging Face or Vercel makes hosting effortless; attackers scan those endpoints within hours when URLs leak.

On LAN tablets, substitute the laptop’s reachable IP yet keep HTTPS termination on your router or a trusted PKI only if you can maintain certificates. plaintext HTTP internally is acceptable for many home labs when WPA3 credentials are sane and attacker risk is proportional; still pair with Secret-protected requests rather than pretending obscurity equals authentication.

7. Verifying With curl: Version, Proxies, and Reload Discipline

After editing YAML, confirm the listener with an authenticated probe before you touch GUI sliders. Replace host, port, and token with yours:

curl -s -H 'Authorization: Bearer YOUR_SECRET_HERE' \
     http://127.0.0.1:9090/version

A JSON payload naming the running core confirms the handshake. Unauthorized attempts should yield HTTP 401 bodies that clearly signal absent headers. Scripts can chain through /proxies queries to sanity-check latency results or ensure group names drifted after merges. Reload endpoints deserve extra caution—automate only with idempotent pipelines and snapshots of last-known-good configs.

Logging verbosity intersects API usage: dashboards polling aggressively may drown journals you otherwise rely on for DNS debugging. Tune polling intervals in the UI where possible, especially on battery-powered hardware. Respect rate limits inherent to single-threaded event loops; hammering endpoints during massive rule imports rarely speeds completion.

When integrating home automation stacks, segregate credentials per service—Home Assistant snippets need not reuse your personal bearer token if separate least-privilege tokens become available in upstream releases you track. Audit automation quarterly; forgotten cron jobs resurrect widened binds long after laptops sleep.

8. Operating-System Firewalls and Network Segmentation

Binding to 0.0.0.0 invites every interface; firewalls translate intent into enforced reality. Windows Defender inbound rules should reference the executable path of your GUI wrapper or daemon, not ephemeral copies in temp directories renamed after upgrades. macOS prompts may confuse users—“allow incoming connections?”—but accepting blindly for unnamed helpers widens surfaces; tie approvals to binaries you hashed.

Linux servers benefit from nftables or ufw profiles scoped to LAN CIDR ranges. Explicitly denying WAN_IF while permitting 192.168.0.0/16 → tcp/9090 expresses policy in firewall language rather than YAML hope. Raspberry Pi setups double as stealth admin panels; relocating SSH and the controller onto non-default ports buys little if UPnP or dynamic DNS accidentally forwards them globally—verify routers after firmware updates.

Corporate split tunnels sometimes mean “LAN” spans multiple routed segments. If your controller accidentally binds to a VPN interface shared with dozens of colleagues, treat the incident as credentials exposure: rotate secrets, review logs, and tighten binds before compliance teams notice unexpected traffic toward residential nodes.

9. Anti-Patterns: Blank Secrets, Cloudflared Tunnels, Hotel Wi-Fi

Three recurring mistakes deserve callouts. First, copying “quick start” snippets with empty secret fields “because it is local.” Local today includes browser extensions, malware-adjacent utilities, and compromised npm dependencies with arbitrary loopback access. Always wire a token. Second, tunneling the raw API through exposed SaaS ingress without authentication layers adds global reach to a service designed for adjacent trust. If you insist on remote admin, front it with mutual TLS or VPN, not a cosmetic Cloudflare Access toggle you forget to renew.

Third, enabling every experimental dashboard feature simultaneously—external UI, debug memory endpoints, packet capture hooks—amplifies leak paths. Turn features on when debugging, then revert to minimal surfaces. Document toggles in git-tracked overrides so teammates see intentional diffs rather than mystery GUI drift.

Travelers who temporarily widen bind-address for hotel debugging should script teardown: close listeners, restore loopback-only YAML, and restart services before reconnecting to airport lounge SSIDs. Mobile hotspot NAT does not imply safety; it simply shrinks the broadcast domain until the next guest joins the same SSID.

10. Closing Thoughts

Mature mihomo operations treat the external-controller like an infrastructure API: authenticate every call, bind only where policy demands, monitor who connects, and separate “family shares my proxy port” from “anyone can rewrite my rules.” Pair that discipline with trusted clients, routine log reviews, and hardware firewalls that echo your intent. The ergonomics of Yacd-meta are worth preserving—just ensure the story ends with you in control, not an anonymous scanner in another timezone.

Fresh builds and signed installers close security gaps faster than YAML cleverness alone. When you are ready to standardize on a distribution that tracks upstream hardening, prefer our curated channel so verification steps stay predictable—especially if teammates mirror configurations from this article verbatim. The experience difference between ad-hoc binaries and maintained releases shows up long before you need emergency incident response. → Download Clash for free and experience the difference

Hand-picked deep-dives on the same topic — practical Clash routing guides in the same category.