V2RayのJSON設定ファイルを解説:inbounds・outbounds・routingの構造と書き方

最小構成の設定例を使い、log、inbounds、outbounds、routing、dnsの各項目と、tagで入出力やルーティングルールをつなぐ仕組みを解説します。

この記事の概要

この記事は、v2rayNを使ったことがあり、コアの実行設定を理解したい方向けです。まずローカルのinbound、directとblockのoutboundだけを含むJSONを動かし、「アプリ → inbound → routing → outbound」の順に各項目を確認します。リモートノードなしで、待ち受けポート、タグ参照、ルールの順序を検証できます。VMessやVLESSを使う場合は、サーバーのパラメーターに合わせてoutboundを置き換えてください。

1. 設定の流れ:クライアント・コア・JSONの役割

inboundsはアプリからの通信を受け付け、outboundsは通信を宛先またはリモートサーバーへ送ります。routingはその間で使用するoutboundを選びます。JSONは設定形式であり、ノードのプロトコルではありません。拡張子が同じでも、異なるコア間で設定ファイル全体をそのまま使えるとは限りません。

v2rayNは、サブスクリプション管理、サーバー編集、ルーティング設定の画面を備えたデスクトップクライアントです。実際にポートを待ち受けて接続を処理するのは、選択したコアです。Android版のv2rayNGはXrayコア、v2flyNGはV2Flyコアを使用します。項目の互換性を調べる際は、クライアント名だけでなく、実際に起動しているコアを確認してください。

設定方法は2通り:画面から作成する方法と手動で管理する方法

クライアントで設定を生成
  • サブスクリプションまたはサーバー編集画面でノードのパラメーターを入力します。
  • クライアントがローカルポート、DNS、ルーティングルールを組み合わせてコアに渡します。
  • 生成されたファイルは、サーバーの切り替えやコアの再起動時に上書きされることがあります。
独立したJSON設定
  • inbound、outbound、タグ参照を含む設定全体を手動で管理します。
  • まず独立したディレクトリで、コマンドを使ってコアの設定を検証します。
  • クライアントに読み込む前に、カスタム設定がどのように扱われるか確認してください。

構造を学ぶときは独立したファイルを使い、普段使うサブスクリプションのノード設定はクライアントの該当画面から変更しましょう。一時生成ファイルの編集を避けられます。

以下では、V2Rayの従来型JSON設定で使われる基本項目を取り上げ、Xrayのコマンドで検証します。V2Flyはメジャーバージョンによって設定形式やコマンドが異なる場合があります。特にTLS、REALITY、トランスポート層の設定は、異なるコア間でそのまま流用しないでください。

2. 最小構成の設定例:2つのinboundと2つのoutbound

以下の内容をUTF-8でconfig.jsonとして保存します。ローカルでSOCKSとHTTPのプロキシポートを開き、通常の通信はdirectで接続します。HTTP inboundから入り、宛先ドメインがexample.comのリクエストだけを遮断します。ここでいう「プロキシポート」はローカルから接続するための入口であり、通信がリモートプロキシサーバーを経由するという意味ではありません。

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    },
    {
      "tag": "http-in",
      "listen": "127.0.0.1",
      "port": 10809,
      "protocol": "http",
      "settings": {}
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "inboundTag": ["http-in"],
        "domain": ["full:example.com"],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "ip": [
          "10.0.0.0/8",
          "172.16.0.0/12",
          "192.168.0.0/16"
        ],
        "outboundTag": "direct"
      }
    ]
  },
  "dns": {
    "servers": ["localhost"]
  }
}
10808
例のSOCKS inboundポート
10809
例のHTTP inboundポート
2件
配列の順に照合されるルーティングルール

ここで示すポートは記事内の設定値であり、すべてのクライアントバージョンのデフォルト値ではありません。実行前に、同じポートを使用しているプロキシプロセスを終了するか、JSONとテストコマンドの両方でポートを変更してください。この例ではシステムプロキシもTUNも有効にしません。指定したポートに接続するアプリの通信だけがコアに入ります。

3. inbounds:待ち受けアドレス・ポート・inboundタグ

inboundsは配列で、各オブジェクトが1つの接続入口を表します。listenは接続を受け付けるローカルアドレス、portは待ち受けポート、protocolはアプリとコア間で使うプロトコルを指定します。アプリ側のプロトコル設定が違うと、ポートに接続できてもリクエストを正常に転送できません。

SOCKSの入口

tag
socks-in
listen
127.0.0.1
port
10808
protocol
socks
udp
true

アプリでSOCKS5を選択します。UDPを使えるかどうかは、アプリ自体と後段のoutboundの対応状況にも左右されます。

HTTPの入口

tag
http-in
listen
127.0.0.1
port
10809
protocol
http
settings
{}

アプリでHTTPプロキシを選択します。HTTPSの宛先には通常、HTTP CONNECTでトンネルを確立します。

127.0.0.1はローカルマシンからの接続だけを許可します。0.0.0.0に変更すると、IPv4の待ち受け範囲が広がります。一般的な互換性対策として変更しないでください。特に例のSOCKS入口はnoauthを使用しているため、信頼できないネットワークに直接公開してはいけません。

4. outbounds:デフォルトの送信先とリモートノードの違い

outboundsには利用可能な出口を定義します。例のdirectはfreedomを使って宛先へ直接接続し、blockはblackholeを使って該当する接続を破棄します。どのルールにも一致しない場合、通常のルーティングではoutbounds配列の先頭が使われます。この例ではdirectがデフォルトです。

項目またはプロトコル役割設定のポイント
tagルーティングから参照するoutbound名重複を避け、用途が分かる名前にする
freedom宛先に直接接続リモートサーバーのアカウントは不要
blackhole接続を遮断テスト時にリクエストが失敗することを確認
vmessVMessサーバーに接続アドレス、ポート、ユーザーパラメーター、トランスポート設定を確認
vlessVLESSサーバーに接続ユーザーパラメーター、暗号化項目、安全性に関する設定を確認

リモートノードを使うには、protocolをvlessに変更するだけでは不十分です。プロトコルに応じたsettings、トランスポート層のstreamSettings、サーバー側の設定をそろえる必要があります。アドレス、ポート、UUID、トランスポート種別、TLSのサーバー名、必要に応じたflowは、それぞれ役割が異なります。

VMessとVLESSは「暗号化強度」を選ぶ項目でもありません。特にVLESSは、それ自体では通信を暗号化しないため、サーバーが要求するTLSなどのセキュリティ層と組み合わせる必要があります。REALITYはXray関連の機能です。対応する項目をV2Flyの設定にそのまま追加しても、正常に動くとは限りません。

まずはdirectの例を維持する

おすすめ

最初にローカルポート、JSON形式、ルーティングタグを検証してから、outboundのパラメーターを一度に1組ずつ置き換えます。これにより、ローカル設定の問題とリモート接続の問題を切り分けられます。

おすすめの用途:設定を初めて読むとき、起動失敗の原因を調べるとき、ルールの順序を検証するとき。

有効なノードのoutboundを使用

接続できることを確認済みのノード設定からoutboundオブジェクト全体を取得し、サーバーが要求するトランスポートとセキュリティの項目を残したうえで、ローカルのタグ参照を調整します。

おすすめの用途:利用可能なノードがあり、既存設定にルーティングを追加するとき。

5. routing:tagで接続全体をつなぐ

routing.rulesは上から順に照合され、最初に一致したルールが接続のルーティング先を決めます。例の1つ目のルールにはinboundTagとdomainがあり、両方の条件を満たす必要があります。同じdomain配列に複数のドメイン条件がある場合は、いずれか1つに一致すれば対象になります。

  1. アプリが127.0.0.1:10809に接続すると、コアはその接続にinboundタグhttp-inを付けます。
  2. リクエストの宛先はexample.comで、full:example.comの完全一致条件を満たします。
  3. 1つ目のルールに一致し、outboundTag: "block"から該当するoutboundを特定します。
  4. blackholeがその接続を処理します。後続のプライベートネットワーク向けルールは、今回の選択には適用されません。

full:example.comはドメイン名との完全一致を表し、サブドメインは含みません。ルートドメインとサブドメインの両方を対象にするには、domain:example.comを使います。ドメイン配列に通常の文字列を指定した場合も、単純な完全一致とは限りません。

2つ目のルールには3つのIPv4プライベートネットワーク範囲が指定されており、宛先がこれらのIPアドレスならdirectで接続します。この例はAsIsを使うため、IP条件に一致させる目的でルーティングがドメインを積極的に名前解決することはありません。したがって、ドメインの最終的な解決先がプライベートIPでも、このルールに必ず一致するとは限りません。例ではデフォルトもdirectのため、結果は同じになる場合がありますが、照合の過程は異なります。

デフォルトでリモートノードを使う場合は、有効なリモートoutboundを配列の先頭に置くか、最後に明示的なフォールバックルールを追加します。フォールバックルールを詳細な遮断ルールやプライベートネットワーク向けdirectルールより前に置くと、広い条件に先に一致して後続のルールが機能しなくなるため、避けてください。

6. dnsとlog:名前解決とログを個別に確認

dns.serversには、内蔵DNSが問い合わせる上位DNSサーバーを指定します。例のlocalhostは、システムのローカル名前解決機能を使う設定です。これによってOSのDNS設定が自動で変わったり、他のアプリのDNSリクエストが自動的に取り込まれたりするわけではありません。コア内の該当モジュールが名前解決を必要とする場合にのみ、実際の処理に使われます。

これらはルーティング層のポリシーであり、outbound接続時の名前解決ポリシーとは異なります。ルーティングにAsIsを使っていても、direct outboundがドメイン名の宛先に接続する際には名前解決が必要な場合があります。アプリが最初からドメインをIPアドレスに解決していると、コアが元のドメイン名を取得できないこともあります。この記事のテストでは、SOCKSリクエストでドメイン名を渡すためにsocks5hを使用します。

log.loglevelは、まず警告とエラーを確認するならwarningが適しています。調査中は一時的にinfoへ変更し、必要に応じてdebugを使います。アクセスログとエラーログにはそれぞれ個別の出力設定があり、ログレベルを上げてもアクセス記録が自動ですべて有効になるわけではありません。

"log": {
  "access": "access.log",
  "error": "error.log",
  "loglevel": "info"
}

上記の断片は、設定全体のlogオブジェクトと置き換えて使うものであり、単独で実行する設定ファイルではありません。相対パスで指定したログの保存先は、通常、プロセスの作業ディレクトリを基準に解釈されます。クライアントから起動した場合、作業ディレクトリとJSONファイルの保存先が異なることがあります。調査後は適切なログレベルに戻し、ログを共有する前にサーバーアドレス、サブスクリプションURL、アカウント情報を削除してください。

7. 保存・テスト・検証:一度に変更するのは1項目

まず現在のコアでJSONを読み込めることを確認し、次にポート、最後にルールの結果を検証します。設定テストに合格しても、実行時にポートを確保できるとは限らず、リモートサーバーに接続できることも保証されません。

  1. 設定を保存する

    Windows 11のエクスプローラーで「表示」→「表示」→「ファイル名拡張子」を選び、ファイル名がconfig.jsonであることを確認します。config.json.txtではありません。内容には半角の二重引用符を使い、コメントや末尾の余分なカンマは入れないでください。

  2. 設定項目を検証する

    設定ファイルをXrayの実行ファイルがある独立したテスト用ディレクトリに置き、そのディレクトリでPowerShellを開いて、下の検証コマンドを実行します。V2Flyを使う場合は、該当コアのコマンドヘルプを先に確認し、Xrayのオプションをそのまま使わないでください。

  3. コアを起動する

    10808と10809を使用している他のプロキシプロセスを終了してから、起動コマンドを実行します。ターミナルは閉じず、ポートのバインド失敗や項目の解析エラーが表示されないか確認してください。

  4. ルールを検証する

    SOCKSとHTTPをそれぞれテストします。まず通常のWebサイトに接続できることを確認し、次に両方のinboundでexample.comへの結果がどう異なるかを確認してください。テストが終わったら、コアを実行しているターミナルでCtrl+Cを押してプロセスを停止します。

.\xray.exe run -test -config .\config.json

.\xray.exe run -config .\config.json

コアを起動したまま、別のPowerShellウィンドウで以下のコマンドを実行します。環境によってcurlが別のコマンドとして解釈されるのを避けるため、curl.exeを明示的に指定しています。各コマンドのタイムアウトは15秒です。待ち時間を制限するための設定であり、性能測定ではありません。

curl.exe --max-time 15 --proxy socks5h://127.0.0.1:10808 https://example.org/

curl.exe --max-time 15 --proxy http://127.0.0.1:10809 https://example.com/

curl.exe --max-time 15 --proxy socks5h://127.0.0.1:10808 https://example.com/
テストリクエスト想定されるルーティング判定の根拠
SOCKS → example.orgdirectルールに一致しないため、先頭のoutboundを使用
HTTP → example.comblockinboundタグと完全一致するドメインの両方が一致
SOCKS → example.comdirectinboundタグが一致せず、遮断ルールに該当しない

direct接続でWebページを取得できるかどうかは、現在のネットワーク、システムの名前解決、宛先への到達性にも左右されます。HTTPで遮断対象へリクエストすると失敗しますが、エラーの内容や所要時間は接続段階によって異なります。1回タイムアウトしただけでルールが適用されたと判断せず、inbound、宛先ドメイン、ルールの順序、ログを合わせて確認してください。

8. よくある設定ミス:エラー箇所から項目を見直す

設定の問題は、構文、構造、実行環境、接続パラメーターの4段階に分けられます。エラーが出たらまず該当する段階を特定し、ローカルポートの競合をノードの障害と取り違えたり、未対応の項目をネットワーク障害と誤認したりしないようにしましょう。

JSON設定全体、単一のoutboundオブジェクト、ノードの共有リンク、サブスクリプションURLは、それぞれ異なる入力形式です。設定全体にはローカルのinboundとルーティングが含まれますが、サブスクリプションは通常、クライアントでノード情報を読み込むためのものです。JSON全体をサブスクリプション欄に貼り付けたり、サブスクリプションURLをoutboundのサーバーアドレスとして指定したりしても、自動で形式が変換されることはありません。

v2rayNのダウンロード