セキュリティとプライバシー · Clash 技術ブログ

Clash Dashboard へ安全にリモートアクセスする方法

Dashboard が実際に接続するのは、ノードの切り替え、設定の変更、接続の終了が可能な制御インターフェースです。リモートから使う場合は、まずリッスンアドレスを制限して secret を設定し、その後 LAN またはトンネル経由でアクセスしてください。

  • セキュリティ
  • Dashboard
  • secret
目次

Clash Dashboard へリモートアクセスする場合は、管理用の入口として保護する

Clash Dashboard は external-controller が提供する REST API を通じて、接続、トラフィック、プロキシグループ、ルールを読み取ります。このインターフェースではノードの切り替え、設定の再読み込み、一部の実行時設定の変更、接続の終了も行えるため、9090 ポートを公開インターネットへ直接さらすリスクは、読み取り専用のステータスページを公開する場合よりはるかに高くなります。

まず、誰がアクセスする必要があるかを明確にします。ローカルだけで使うなら、ループバックアドレスだけでリッスンします。同じローカルネットワークから時々確認する場合も、接続元を制限し、secret とファイアウォールを設定してください。リモート管理には SSH トンネルまたは管理された Tailscale ネットワーク経由の転送を使い、0.0.0.0:9090 を公開インターネットへ直接マッピングしないでください。

アクセス場面と推奨する入口

状況リッスン方法アクセス制限
ローカルクライアントに同梱されたパネル127.0.0.1:9090強力な secret を設定し、任意のウェブページからローカルインターフェースを呼び出せないようにする
家庭内 LAN からの管理明示した LAN アドレスまたは制限付きのリッスンファイアウォールで管理デバイスまたはプライベートサブネットだけを許可
別の場所から一時的に保守引き続きローカルホストだけでリッスンSSH ローカル転送または Tailscale 経由でアクセス
公開インターネット向けサービス直接公開は推奨しない少なくとも独立したリバースプロキシ、TLS、認証、接続元制限が必要

別のデバイスからアクセスする必要がなければ、リッスンアドレスをローカルホストへ限定する

最終的に有効となる Mihomo 設定で、external-controller を 127.0.0.1 にバインドします。GUI クライアントでは、「設定 → 外部コントローラー」またはオーバーライドファイルからこのフィールドを生成する場合があるため、元のサブスクリプションを編集しても反映されるとは限りません。再読み込み後に、最終設定と実際のリッスン状態を確認してください。

次の REPLACE_WITH_RANDOM_SECRET はプレースホルダーにすぎません。パスワードマネージャーで長いランダム値を生成し、設定と Dashboard の接続設定にある値を両方置き換えてから、Mihomo を再読み込みします。プレースホルダーをそのままパスワードとして使わないでください。

ローカルの Dashboard 専用の開始設定
external-controller: 127.0.0.1:9090
secret: "REPLACE_WITH_RANDOM_SECRET"
9090 で待ち受けているプロセスを確認する
# Windows PowerShell
Get-NetTCPConnection -LocalPort 9090 -State Listen

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

secret の設定後、未認証のリクエストが実際に拒否されることを検証する

secret は外部コントローラーの Bearer Token です。空の値、短いパスワード、複数デバイスでの長期的な使い回しは、ポートへ到達できる相手へ管理権限を渡すのと同じです。ランダム値を生成し、Mihomo の設定と Dashboard のバックエンドアドレス設定へそれぞれ入力してください。完全な token をスクリーンショット、フロントエンドリポジトリ、公開の障害ログへ記載しないでください。

認証情報なし、誤った認証情報、正しい認証情報を個別にテストする
# 无 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

認証が機能していることを示す結果

  • Authorization なしのリクエストでバージョン JSON ではなく 401 が返る
  • 正しい secret で /version を読み取れる
  • 誤った secret も拒否される
  • Dashboard を更新すると接続とプロキシグループが正常に表示される
  • ログとブラウザのアドレスバーに secret が露出していない

Dashboard を開けない場合も、CORS を任意のオリジンへいきなり許可しない

リモートでホストされた Dashboard は、ブラウザから external-controller へリクエストを送るウェブオリジンです。CORS はインターフェースを呼び出せるウェブオリジンを制限するだけで、ユーザー認証の代わりにはなりません。

allow-origins を * に設定し、さらにプライベートネットワークへのリクエストを許可すると、任意のウェブページからローカルまたは同一ネットワーク内のコントローラーポートへのアクセスを試みやすくなります。secret を設定していても、漏えいした場合の影響範囲は広がります。

まず Dashboard の実際の origin(例: https://dashboard.example.com)を確認し、その完全な origin だけを許可します。ドメイン、プロトコル、ポートのいずれかが変われば、別の origin になります。設定内の UI 静的ファイルのパスと API のリッスンアドレスも別物です。ページが開くからといって、コントロール API が安全に接続されているとは限りません。

サンプルドメインを実際の Dashboard origin に置き換える
external-controller-cors:
  allow-origins:
    - "https://dashboard.example.com"
  allow-private-network: false

一時的なリモート保守には SSH トンネルを使い、9090 をローカルへ転送する

Mihomo を自宅サーバーで動かす場合は、external-controller を 127.0.0.1:9090 のままにし、SSH ローカルポートフォワーディングでリモート側のループバックポートを現在のコンピューターへ転送できます。ブラウザは引き続き自身の 127.0.0.1 にアクセスし、公開インターネットから 9090 は見えません。

例: リモートコントローラーをローカルの 19090 に転送する
ssh -N -L 19090:127.0.0.1:9090 [email protected]

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

Tailscale を使用する場合も、tailnet 全体が管理者だと決めつけないでください。tailnet policy でホストとポートへアクセスできるユーザーやデバイスを制限し、secret も残します。家庭用ルーターで LAN アドレスのリッスンが避けられない場合は、ファイアウォールで管理用コンピューターだけを許可し、Guest Wi-Fi や WAN zone 全体は許可しないでください。

リモート管理パネルへ安全にアクセスする経路
  1. 使用中のブラウザ信頼できるデバイスからのみアクセスする
  2. SSH トンネルまたは VPNコントローラーポートを直接公開しない
  3. 127.0.0.1:9090external-controller はローカルホストだけでリッスン
  4. Mihomosecret でコントロールリクエストを検証

LAN アドレスでのリッスンが避けられない場合も、ファイアウォールで接続元を制限し、十分に長い secret を設定してください。

長期アクセスが必要になった場合だけ、9090 の前段にリバースプロキシを追加する

固定ドメインと長期的なリモートアクセスが必要な場合に限り、リバースプロキシの導入を検討します。Mihomo の external-controller は引き続き 127.0.0.1:9090 でリッスンし、同じホスト上の Nginx、Caddy、または別のゲートウェイが外部向けに HTTPS を提供します。公開インターネットにはリバースプロキシのポートだけを開放し、9090 は開放しません。

リバースプロキシには、少なくとも信頼できる TLS、独立したログインまたはクライアント認証、接続元の制限、アクセスログを用意し、Dashboard が使用する WebSocket も正しく転送する必要があります。Mihomo の secret も残してください。secret とリバースプロキシのログインは独立した二層の保護であり、互いの代わりにはなりません。secret は公開 URL に付加せず、Dashboard の接続設定に保存します。

Dashboard のウェブページと API が異なるドメインを使用する場合は、実際のページの origin を CORS に正確に追加します。設定後は、公開インターネットからのポートスキャンまたは別のデバイスでテストしてください。HTTPS ドメインではログインでき、サーバーの公開 IP:9090 へ直接アクセスすると接続に失敗する状態が正解です。

長期運用するリモート接続口が満たすべき条件

  • external-controller は引き続き 127.0.0.1 だけでリッスン
  • 公開側に 9090 のポートマッピングがない
  • リバースプロキシが HTTPS を必須とし、独立した認証を備えている
  • WebSocket のログとトラフィックページが正常に更新される
  • Mihomo の secret が引き続き正常に検証される
  • 許可されていない接続元からはアクセスできない

サーバー本体と別の一台のデバイスから、それぞれ一度テストする

総合検証

  1. ローカルでリッスン状態を確認

    ポートが想定したアドレスにバインドされ、プロセスが古いインスタンスではなく現在の Mihomo であることを確認します。

  2. 未認証アクセス

    curl で /version をリクエストし、token がない場合も誤っている場合も 401 が返ることを確認します。

  3. 認証済みアクセス

    Dashboard を開いてテスト用のポリシーグループを切り替え、Mihomo 側にも同じ結果が反映されることを確認します。

  4. 権限のないネットワークからテスト

    アクセス権を持たないはずの LAN、Guest Wi-Fi、または公開アドレスからテストし、接続がタイムアウトするか拒否されることを確認します。

  5. 再起動して再テスト

    Mihomo を再起動した後、リッスンアドレス、secret、ファイアウォールルールがクライアントによって上書きされていないことを確認します。

コントローラーが公開されていた可能性がある場合は、まずリッスン範囲とファイアウォールを絞り、その後 secret をローテーションします。続いて、ポートマッピング、クラウドのセキュリティグループ、リバースプロキシのアクセスログ、設定リポジトリの履歴を確認してください。Dashboard のパスワードだけを変更しても、漏えいした Bearer Token は無効になりません。

参考資料