パネル専用ではなく一体型サーバーイメージを選ぶ

MetaCubeXDには、名前がよく似た2つのDockerイメージがあります。ghcr.io/metacubex/metacubexd:latestはコンテナの80番ポートでWebダッシュボードだけを配信するパネル専用イメージです。Mihomoを同梱せず、起動や監視もしないため、別に管理しているMihomoのExternal Controllerへ接続する場合に使います。

この記事で扱うのは一体型のghcr.io/metacubex/metacubexd-server:latestです。このサーバーイメージには、ダッシュボード、同一オリジンの制御エージェント、使用するCPUアーキテクチャに合ったMihomoコアが含まれます。プロファイルの管理と検証、Mihomoコアの起動・停止までを1つのサービスで扱えるのが、ここで使う公式Compose構成です。

イメージ名を置き換えないでください:metacubexd-serverをmetacubexdに変えると、画面は開いても同梱のMihomoコアと制御エージェントは利用できません。パネル専用コンテナが正常でも、Mihomoコアが動作している証明にはなりません。

公式Composeの初期構成はプロキシ専用です。明示的に設定したアプリがMixedポートを利用する構成であり、ホストをLAN向け透過ゲートウェイに変えたり、TUNを自動的に有効化したりはしません。

公式Composeを取得し、用途の異なる2つの認証情報を用意する

専用ディレクトリを作成し、MetaCubeXD公式リポジトリからComposeファイルを取得します。同じ場所にローカルの.envを置きます。この記事の公開後にリポジトリの内容やlatestの参照先が変わる可能性があるため、起動前に取得したYAMLを確認してください。

Shellmkdir metacubexd-server
cd metacubexd-server
curl -fLO https://raw.githubusercontent.com/MetaCubeX/metacubexd/main/docs/docker-compose.yml

公式ファイルではCONTROL_TOKENとCLASH_SECRETが必須です。互いに異なる、十分に強いランダム値を.envへ記録してください。サブスクリプションのトークンやアカウントのパスワード、Web上のサンプルに載っている値は流用しません。

.envCONTROL_TOKEN=replace-with-a-unique-control-token
CLASH_SECRET=replace-with-a-different-clash-secret
TZ=Asia/Shanghai
変数保護する対象注意点
CONTROL_TOKEN/api/control配下の制御エージェントAPI同一オリジンの画面へ渡されるため、ダッシュボード自体のログイン機能ではない
CLASH_SECRET9090番のMihomo Clash APIダッシュボードのEndpointにあるSecretへ入力する

.envを公開リポジトリ、スクリーンショット、問い合わせ資料、シェル履歴へ残さないでください。これらの値が漏れると、ホストへ接続できる第三者にプロファイルやMihomo APIを操作されるおそれがあります。

検証、取得、起動、状態確認を順番に実行する

docker-compose.ymlと.envがあるディレクトリで実行します。まずCompose設定と必須変数を検証します。認証情報を画面に表示させないよう--quietを付け、その後にイメージの取得、バックグラウンド起動、状態確認、ログ確認へ進みます。

Shelldocker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 metacubexd
  1. config --quietが成功し、必須変数の不足がないことを確認します。
  2. pullで現在のComposeが参照するイメージを取得します。
  3. up -dでサービスを作成または更新します。
  4. psでコンテナとヘルスチェックの推移を確認します。
  5. logsで制御エージェント、Mihomoコア、プロファイル、ポート競合に関する最初のエラーを読みます。

公式ファイルのサービス名はmetacubexdで、イメージ名のmetacubexd-serverとは異なります。docker compose logsにはサービス名を指定します。失敗時に何度も作り直す前に、最初の具体的なエラーを保存してください。

3つのポートと書き込み可能なデータボリュームを区別する

公式Composeは3つのTCPポートを公開し、名前付きボリュームを/dataへマウントします。8080はブラウザ画面とエージェント、9090は画面から直接接続するMihomo API、7890はアプリが利用するHTTP/SOCKS Mixedプロキシです。

ホスト側ポート役割確認方法
8080ダッシュボードUIと制御エージェントAPIhttp://<host>:8080を開く
9090Mihomo Clash APIとWebSocketUI Endpointにhttp://<host>:9090を指定
7890Mihomo Mixed HTTP/SOCKSプロキシ許可したクライアントに<host>:7890を設定

metacubexd-dataは/dataに接続され、プロファイル、有効な設定、Geoデータ、Mihomoコアのダウンロードデータ、実行時キャッシュを保持します。この場所には書き込み権限が必要です。読み取り専用にすると、同梱のMihomoコアがエラー終了することがあります。

Dockerのポート公開はMihomoの待受ポリシーを上書きしません。Mihomoのallow-lan既定値はfalseです。bridgeネットワークではMixedポートがコンテナのloopbackにのみ待受するため、7890:7890だけでホストやLANからプロキシへ接続できるようにはなりません。公開したプロキシポートを使う場合は、現在有効なプロファイルでallow-lan: trueを明示し、bind-addressとlan-allowed-ipsを必要な範囲に絞ります。さらにauthentication、Dockerのホスト側binding、ホストのfirewallを組み合わせ、プロファイル切り替え後に再確認します。

左側のホストポートだけを18080:8080に変更した場合、コンテナは8080番で待受しますが、ブラウザとホスト側のhealthリクエストは18080番を使います。9090と7890の左側を変更した場合も、Endpointまたはクライアントに新しいホストポートを設定します。コンテナ内のCONTROL_PORTを変更するなら、mappingの右側とhealthcheck URLも同時に変更してください。

コンテナとデータは別物です:サービスの再作成では名前付きボリュームを維持できますが、ボリュームを削除すれば永続状態も失われます。イメージやプロファイルを変更する前に、このボリュームをバックアップ対象へ含めます。

ダッシュボードを開き、同梱のMihomoコアへ接続する

ブラウザでhttp://<host>:8080を開きます。サーバーはCONTROL_TOKENを同一オリジンのページへ注入し、ダッシュボードが/api/controlを確認できるようにします。ユーザーがこのトークンを貼り付ける欄はありません。ただし、ページへ届く値なので、ダッシュボードへのアクセス制御そのものにはなりません。

MihomoのEndpointでは、URLにhttp://<host>:9090、Secretに.envで設定したCLASH_SECRETと同じ値を入力します。8080はUIとエージェントのポートでありClash APIではありません。Endpointを8080へ向けてもMihomoには接続できません。

8080と9090はポートが違うため、ブラウザ上では別オリジンです。有効なMihomoプロファイルのexternal-controller-corsに、例えばhttp://192.168.1.20:8080のような正確なUIオリジンを許可する必要があります。公開ページからプライベートネットワークのControllerへ接続する場合は、Private Network Access(PNA)も確認し、必要な構成でのみallow-private-network: trueを有効にします。画面だけ開いてバックエンド接続に失敗する場合は、Secretやコンテナを変更する前に開発者ツールでCORSまたはPNAエラーを確認します。

HTTPSのUIにはMixed Contentの制約もあります。HTTPSで読み込んだページから、安全でないhttp://<host>:9090のHTTP/WebSocketへ接続すると、CORSの評価より前にブラウザで拒否されるのが通常です。9090番をHTTPS/WSS対応のリバースプロキシの後ろに置くか、Mihomoのexternal-controller-tlsと有効な証明書を設定し、UI Endpointに対応するhttps:// URLを入力します。TLSとMixed Contentを解決した後に、CORSとPNAを確認します。

層ごとに確認:8080の画面、制御エージェント、9090のEndpointとCLASH_SECRET、最後に7890のMixedプロキシという順番なら、失敗箇所を混同しません。

MetaCubeXD 公式プロジェクトのデスクトップ概要画面
MetaCubeXD 公式リポジトリの概要画面です。表示中のデモ接続先と通信量は、自分の展開結果を示すものではありません。

HTTP 200をUIとエージェントの確認だけに使う

サーバーのヘルスエンドポイントは、CONTROL_PORT上のGET /api/control/healthです。公式Composeでは8080番なので、ホスト上から次のように確認できます。

Shellcurl -i http://127.0.0.1:8080/api/control/health

ホスト側のmappingを18080:8080に変更した場合、ホストからのリクエストは18080番を使います。コンテナ内のCONTROL_PORTを変更した場合は、mappingの右側とComposeのhealthcheck URLも同時に変更します。

HTTP 200はダッシュボードサーバーと制御エージェントが応答していることを示します。Mihomoコアの稼働、プロファイル検証の成功、Endpoint Secretの一致、外向きのプロキシ通信までは保証しません。公式Composeのhealthcheckも同じURLを見るため、healthy表示が確認している範囲も同じです。

  1. docker compose psでコンテナとhealthの状態を確認します。
  2. Mihomoコアの状態表示で、同梱コアがrunningになっているか確認します。
  3. docker compose logs --tail=100 metacubexdで設定や起動エラーを読みます。
  4. http://<host>:9090とCLASH_SECRETで接続できるか確認します。
  5. 許可した1台からMixedプロキシを使い、ConnectionまたはRuleログを確認します。

この順番なら、8080が200でも、読み取り専用の/data、不正なYAML、ポート競合などでMihomoコアだけが停止している状態を「デプロイ完了」と誤認せずに済みます。

信頼できるLANの外へ出す前に公開ポートを制限する

8080:8080、9090:9090、7890:7890という記述は、既定でホストの全インターフェースに公開されます。VPSや公開経路があるホストでは、ダッシュボード、Clash API、プロキシポートが意図しないネットワークから到達可能になることがあります。CONTROL_TOKENを強くしても、ページ自体の公開は解決しません。

ホストだけから管理するなら、例えば127.0.0.1:8080:8080のようにホスト側をloopbackへ限定します。信頼するLANで使う場合は、ホストファイアウォールまたはACLで接続元を絞ります。遠隔ブラウザからの管理が必要なら、UIを認証付きTLSリバースプロキシの背後へ置き、9090と7890も別々に保護してください。UIのリバースプロキシが他の2ポートまで自動的に保護するわけではありません。

CLASH_SECRETはExternal Controllerを保護し、MihomoのauthenticationはHTTP、SOCKS、Mixedプロキシの利用者認証に使えます。どちらもネットワーク制限の代わりではなく補完です。認証なしのMixedプロキシや広く許可したControllerをインターネットへ直接公開しません。

実際の到達範囲を確認:Composeのbinding、OSファイアウォール、クラウドのSecurity Group、リバースプロキシ設定を一緒に確認します。ホスト内からのテストだけでは外部公開の有無を判断できません。

ボリュームを残したまま更新し、元の状態へ戻せるようにする

公式例はghcr.io/metacubex/metacubexd-server:latestを使用します。latestは固定バージョンではなく、後日同じComposeから異なるイメージが取得されることがあります。更新前に現在動作中のイメージを記録し、metacubexd-dataをバックアップして、正常に動作していたイメージのdigestも控えておきます。

Shelldocker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 metacubexd

更新後は、UIと制御エージェントのhealth、Mihomoコアの稼働状態、Endpoint接続、プロファイル、1件のプロキシ通信を再確認します。新しいイメージで失敗した場合は、必要に応じてデータを復元し、Composeのimage:を記録済みのdigestへ戻してdocker compose up -dを再実行します。

通常の更新や切り分けにdocker compose down -vを使わないでください。-vは、この構成が永続データに使うmetacubexd-dataを含む名前付きボリュームを削除します。コンテナの再作成とデータ削除は別の操作です。

運用方針を明記:latestは追随しやすく、確認済みdigestは再現とロールバックに向きます。「latest」が永久に同じビルドを示すと考えず、採用した方針と確認日を記録します。

TUNはLinux向けの高度な設定。まず標準構成を確認する

公式Composeはプロキシ専用で起動し、TUNなしでダッシュボード、プロファイル管理、明示的に7890を指定するアプリを利用できます。最初にこの最小構成を検証してから、特権を伴うネットワーク機能を検討します。

公式のLinux向けTUN overrideには、network_mode: host、NET_ADMIN capability、/dev/net/tun:/dev/net/tunのdevice mappingが必要です。有効なMihomoプロファイルにも適切なtun:設定が必要です。host networkを使うとDockerはComposeのports: mappingを無視し、8080、9090、7890はホストのnetwork namespaceで直接bindされます。

標準のプロキシ構成LinuxでTUNを使う場合
ports:で公開host networkを使用し、ports mappingは無視される
NET_ADMINやTUN deviceは不要NET_ADMINと/dev/net/tunが必要
アプリが7890を明示的に使用有効なプロファイルがTUNのネットワーク動作を定義

これらの権限を追加すると、コンテナがホストのネットワークへ与える影響も大きくなります。ただし、他のLAN端末向けのforwarding、NAT、policy routing、DNS方針、firewall ruleまで自動で設定されるわけではありません。ここでは公式資料に記載されたTUNの必要条件だけを説明し、LAN全体で使うネットワークゲートウェイの構築手順には踏み込みません。

公式情報源とバージョン範囲

バージョン番号、ファイル名、画面表示は更新で変わる場合があります。作業前にリンク先の公式資料を確認してください。