V2Ray設定ファイルの構造を段階的に解説:inbounds、outbounds、routingの役割

最小構成のV2Ray JSON設定を分解し、inbounds、outbounds、routingの役割と、GUIクライアントとの対応関係を解説します。

この記事の要点

ノードはインポートできるものの、コア設定やログの項目が分かりにくい方に適した記事です。読み終えると、ローカル待受、リモート接続、ルールによる振り分けがどの区画にあるかを把握し、「リクエストがどこから入り、どのルールを通り、どの出口から送信されるか」をtagで追跡できるようになります。

まず全体像を確認:設定ファイルは1つのノードではない

V2Ray 5.xでは、JSONを使ってコアの動作を記述します。完全なクライアント設定には、通常サーバーアドレスやユーザーIDだけでなく、本機でトラフィックを受け取る入口、外部へ送る出口、DNSの動作、ログレベル、ルーティングルールも定義します。GUIクライアントに表示される「1つのノード」は、主にプロキシoutbound内のサーバーパラメータ群に対応するもので、実行設定全体と同じではありません。

設定を読むときは、まずプロトコルの細部を置いておき、データの流れを3段階で考えると分かりやすくなります。アプリがリクエストをローカル待受ポートへ渡し、inboundsが受信してリクエストを識別し、routingがドメイン、IP、ポート、プロトコルに応じて宛先を選び、最後にいずれかのoutbounds項目が送信します。inboundとoutboundはtagで名前を付け、ルーティングルールがその名前を参照します。

アプリのリクエストinboundで受信ドメインを検出ルール照合outboundを選択宛先へ送信

トップレベルの項目には固定された記述順序がなく、routingoutboundsより前に書いても、JSONパーサーが実行結果を変えることはありません。ただし、配列内の順序には意味がある場合があります。ルーティングルールは通常上から順に照合され、どのルールにも一致しないトラフィックは先頭のoutboundに渡されます。そのため、読む際はtagと配列内の位置の両方を確認します。

inbounds

方向
アプリからコアへ
一般的なプロトコル
SOCKS、HTTP
主な項目
listen、port、tag
代表的なポート
10808

本機のどのアドレスとポートからコアへトラフィックを渡せるかを決めます。

outbounds

方向
コアから宛先へ
プロキシプロトコル
VMess、VLESS
補助出口
freedom、blackhole
識別方法
tag

ノードのサーバー情報、トランスポート層、TLSパラメータは主にここに集約されます。

routing

ルールタイプ
field
照合対象
ドメイン、IP、ポート
実行結果
outboundTag
照合順序
上から下

出口を選択する機能であり、リモートプロトコル接続を確立する機能ではありません。

dns と log

dns
名前解決の方針
log
ログレベル
一般的なレベル
warning
トラブルシューティング用
info

すべての設定に明示されるとは限りませんが、名前解決と問題調査に直接影響します。

inbounds:トラフィックは本機のどこから入るか

inboundsは配列で、各オブジェクトが1つのローカル入口を表します。デスクトップクライアントでは、SOCKSとHTTPのinboundを同時に作成する方法が一般的です。たとえばSOCKSを127.0.0.1:10808、HTTPを127.0.0.1:10809で待ち受けます。ブラウザー、コマンドラインツール、システムプロキシが対応するポートへリクエストを送ると、コアがその接続の処理を開始します。

listenは待受アドレスを決めます。127.0.0.1なら本機からの接続だけを受け付け、0.0.0.0ならすべてのネットワークインターフェースで待ち受けるため、LAN内の端末からそのポートへアクセスできる可能性があります。LANプロキシが明確に必要でない限り、デスクトップ用途ではループバックアドレスが適しています。portは他のプログラムが使用していない必要があり、重複するとログにbindやaddress already in useが表示されることがあります。

10808
SOCKSのポート例
10809
HTTPのポート例
127.0.0.1
本機のみで待受
53
標準DNSポート

protocolは入口側のプロトコルを示すもので、リモートノードのプロトコルではありません。SOCKS inboundのリクエストをVLESSやVMess outboundへ渡すこともでき、両者のプロトコルを一致させる必要はありません。settingsには、そのinboundプロトコル固有のパラメータを保存します。SOCKS inboundでよく使われるudp: trueは、UDPリクエストの受信を許可する設定です。

sniffingは、接続内容から宛先ドメインを復元するために使います。アプリが先にドメインをIPへ解決し、その後ローカルプロキシへ接続する場合があります。コアにIPしか見えていなければ、ドメインで記述したルーティングルールに一致しません。嗅探を有効にしてdestOverrideを設定すると、コアは対応するHTTPやTLSトラフィックからドメインを識別し、routingの判定に渡せます。

{
  "tag": "socks-in",
  "listen": "127.0.0.1",
  "port": 10808,
  "protocol": "socks",
  "settings": {
    "auth": "noauth",
    "udp": true
  },
  "sniffing": {
    "enabled": true,
    "destOverride": ["http", "tls"]
  }
}

outbounds:ノード、直接接続、ブロック用の出口

outboundsも配列です。プロキシノードは通常そのうちの1項目にすぎず、実際のクライアントは直接接続用とブロック用の出口も生成します。プロキシ出口はVMessやVLESSなどのプロトコルでリモートサービスへ接続し、freedomはコアから宛先へ直接アクセスさせ、blackholeはルールで選ばれた接続を終了させます。

プロキシoutboundはさらに2層に分けて考えられます。settingsはプロトコルの認証情報やサーバーポートを記述します。たとえばVMessのアドレス、ポート、ユーザーID、セキュリティパラメータなどです。streamSettingsはTCP、WebSocket、TLS、Realityなど、下位のトランスポートとセキュリティ層を記述します。プロトコル項目が正しくても、トランスポート経路、SNI、セキュリティ層が一致しなければ接続は失敗します。

VMess + WebSocket + TLS

protocol
vmess
network
ws
security
tls
リモートポート
443
パス
/v2ray

ユーザー情報はsettings、トランスポート経路とTLSはstreamSettingsに記述します。

VLESS + TCP + Reality

protocol
vless
network
tcp
security
reality
flow
xtls-rprx-vision
フィンガープリント
chrome

Realityのパラメータはサーバー側と対応させる必要があり、security項目の名前を変えるだけでは動作しません。

直接接続用の出口

tag
direct
protocol
freedom
リモートノード
不要
用途
ローカルおよび直接接続ルール

directに一致すると、本機のネットワークから宛先へ直接接続します。

ブロック用の出口

tag
block
protocol
blackhole
リモート接続
確立しない
用途
指定トラフィックの遮断

ルーティングルールがblockを参照すると、リクエストは宛先へ送信されません。

outboundのtagは、設定を調査する際に最も重要な索引です。ルーティングルールに"outboundTag": "direct"とあれば、outboundsに戻ってtagがdirectのオブジェクトを探します。存在しないtagをルールが参照すると、コアは通常起動時に設定エラーを報告し、出口を自動的に推測することはありません。

サブスクリプションで提供されるのは通常ノードの接続パラメータであり、ローカルポート、ログレベル、すべての振り分けルールまで決めるものではありません。v2rayN、v2rayNG、v2flyNGはサブスクリプションをインポートすると、ノード項目とクライアント固有の設定を統合し、コアへ渡す実行設定を生成します。そのため、同じサブスクリプションでもクライアントによって生成される完全なJSONは異なる場合があります。

結論:出口の問題は層ごとに切り分ける

認証エラーならsettingsのアドレス、ポート、ユーザー情報を確認します。TLS、Reality、WebSocketのハンドシェイク失敗ならstreamSettingsを確認します。2つの層のパラメータを混在させて変更すると、項目が揃っているように見えても接続がタイムアウトしやすくなります。

routing:リクエストを順番に指定の出口へ渡す

routing.rulesはルールの配列です。よく使うタイプはfieldで、domainipportnetworkprotocolinboundTagなどの条件で照合できます。ルール自体はデータを転送せず、outboundTagによって処理を担当するoutboundを指定します。

ルールの順序によって結果が変わります。1つ目のルールが特定のドメインをプロキシへ送り、2つ目がより広いドメイン集合を直接接続へ送る場合、そのドメインは1つ目に一致した時点で照合を終了します。より具体的なブロックまたは強制プロキシのルールを前に置き、対象範囲の広い直接接続ルールや最終フォールバックルールを後ろに置きます。

照合項目 照合対象 代表的な用途 実行結果
domain 完全なドメイン、サフィックス、ドメイン集合 サイトの種類ごとの振り分け 指定したoutboundTagへ渡す
ip 単一IP、CIDR、IP集合 LANと対象ネットワークの振り分け 直接接続、プロキシ、ブロック
port 単一ポート、ポート範囲 特定サービスの通信制御 対応する出口を選択
network tcp、udp、または両方 最終フォールバックルール 残りの接続をカバー
inboundTag 1つ以上のinbound tag ローカル入口ごとに異なる出口を使用 入口単位の振り分け

domainStrategyは、ルーターがドメインのIPアドレスをいつ解決するかを決めます。AsIsは元のドメインを優先して照合し、IPルールのために自動で解決しません。IPIfNonMatchはまずドメインルールを確認し、一致しなければIPを解決してIPルールを試します。IPOnDemandはIPが必要になりそうなルールに遭遇した時点で、より早く解決を開始します。どれを選ぶかはルール設計によって決まり、積極的な設定ほどよいわけではありません。

どのルールにも一致しない場合、V2Rayは通常、先頭のoutboundを使用します。暗黙の順序に依存しないように、TCPとUDPをカバーするフォールバックルールを末尾に追加し、対象のoutboundTagを明示するとよいでしょう。こうすればoutboundsの順序を変更しても、デフォルトの通信方向が意図せず変わることはありません。

{
  "domainStrategy": "IPIfNonMatch",
  "rules": [
    {
      "type": "field",
      "protocol": ["bittorrent"],
      "outboundTag": "block"
    },
    {
      "type": "field",
      "ip": ["geoip:private"],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "domain": ["geosite:cn"],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "network": "tcp,udp",
      "outboundTag": "proxy"
    }
  ]
}

結論:ルーティングの問題は最初のルールから調べる

まず対象のドメインまたはIPが実際にどのルールへ一致したかを確認し、次にそのルールが参照するoutboundTagを確認します。ノードに接続できるのに通信方向が誤る場合、原因は通常、ルール順序、ドメイン検出、DNS結果であり、プロキシプロトコル自体の破損ではありません。

読みやすい最小クライアント設定

以下の例では、ログ、1つのSOCKS inbound、3つのoutbound、4つのルーティングルールを同じファイルにまとめています。例のアドレスとユーザーIDは構造を示すためだけのもので、実際のノードとしては使用できません。設定ファイルは標準JSONで記述し、キー名と文字列には二重引用符を使います。末尾に余分なカンマを残したり、コメントを直接挿入したりすることはできません。

データの流れとしては、アプリがまず127.0.0.1:10808へ接続します。コアがルーティングを確認し、BitTorrentの通信はblockへ、プライベートアドレスと指定されたドメイン集合はdirectへ、それ以外のTCPとUDPリクエストはproxyへ送ります。proxyはVMess、WebSocket、TLSを使い、例示サーバーの443ポートへ接続します。

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      },
      "sniffing": {
        "enabled": true,
        "destOverride": ["http", "tls"]
      }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "server.example.com",
            "port": 443,
            "users": [
              {
                "id": "00000000-0000-4000-8000-000000000000",
                "alterId": 0,
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "serverName": "server.example.com"
        },
        "wsSettings": {
          "path": "/v2ray"
        }
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "protocol": ["bittorrent"],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": ["geosite:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "proxy"
      }
    ]
  }
}
  1. まずJSONの構文を確認します。特に二重引用符、カンマ、角括弧が正しく対応しているかを見ます。
  2. すべてのtagが一意で、routingが参照するoutboundTagが実際に存在するか確認します。
  3. inboundポートが使用中でないことを確認し、システムプロキシまたはアプリを同じポートへ向けます。
  4. プロキシoutboundのプロトコル、サーバーポート、トランスポート方式、セキュリティ層が対応しているか確認します。
  5. 最後にルールの順序を確認し、フォールバックルールがより具体的なルールの後ろにあることを確認します。

GUIクライアントとコアJSONの対応関係

v2rayN、v2rayNG、v2flyNGはいずれも、よく使う項目をフォームに分けて表示します。ノード編集画面のアドレス、ポート、ユーザーID、トランスポート方式、セキュリティ設定は主にプロキシoutboundへ対応します。ローカルSOCKSポートやLAN接続の許可などはinboundsへ、ルーティングモード、ルールセット、カスタムルールはroutingへ対応します。

v2rayNを例にすると、ローカルポートや基本動作は通常「設定」→「パラメータ設定」から変更し、ノードのパラメータはサーバー編集画面で変更します。クライアントがコアを起動すると、ノード、全般設定、ルーティング設定を実行設定にまとめます。一時的に生成されたコアJSONを直接編集しても、次回のノード切り替え、サブスクリプション更新、コア再起動で再生成される場合があります。

Androidのv2rayNGとv2flyNGも似た層構造を採用していますが、使用するコアは異なります。v2rayNGはXrayコア、v2flyNGはv2flyコアを使用します。一部の高度な項目やデフォルト値には差があるため、あるクライアントが出力した完全な設定を、別のクライアントの画面設定ファイルとしてそのまま使うことはできません。

画面には1つのノードしかないのに、なぜ実行設定には3つのoutboundがあるのですか?

ノードはproxy outboundに対応します。クライアントは直接接続とブロックのルールから参照するdirectとblockも追加生成するため、outboundsの数は通常ノード数より多くなります。

生成されたJSONを変更したのに、再起動すると元に戻るのはなぜですか?

生成ファイルは実行時に作られる成果物です。「設定」→「パラメータ設定」、ノード編集、ルーティング設定で元のデータを変更してから、コアを再起動して確認してください。

サブスクリプションをインポートしても、ローカルポートが変わらないのはなぜですか?

サブスクリプションが主に提供するのはノード接続パラメータで、ローカル待受ポートはクライアント設定です。SOCKSポートが10808のままか確認し、システムプロキシも同期して変更します。

ルーティングルールにドメインを書いたのに、誤った出口を通るのはなぜですか?

まず適切なドメイン検出を有効にし、domainStrategy、DNSの結果、ルールの順序を確認します。ログレベルを一時的にinfoへ変更すると、実際の宛先とoutbound tagを確認できます。

ログの順序に沿って起動失敗と振り分けミスを調べる

設定の問題は、起動段階と実行段階に分けられます。起動段階の失敗は、JSON構文、項目の型、ポートの重複、無効なtagなどが原因であることが多く、コアがinboundの待受を開始する前に停止することもあります。実行段階で発生する問題は、ノードパラメータ、DNS、ルールの一致、対象ネットワークに関係することが多くなります。

問題調査では、一度に複数の区画を変更しないでください。まずloglevelwarningから一時的にinfoへ変更し、問題を1回再現して時刻を記録します。inboundが待ち受けていないのか、ルールが誤った出口を選んだのか、proxy outboundの接続に失敗したのかを確認してから、該当する区画を変更します。解決後はwarningに戻すと、通常のログ量を減らせます。

{
  "log": {
    "loglevel": "info"
  }
}

ログのinbound tag、宛先アドレス、outbound tagをつなげると、通信経路全体を追跡できます。たとえばリクエストがsocks-inから入り、宛先が特定のドメインとして表示され、最終的にdirectが選ばれた場合、その接続にはノード自体が関与していません。プロキシを通す想定なら、VMessやVLESSの認証パラメータを繰り返し変更するのではなく、routingを確認します。

反対に、ログですでにルールがproxyを選んだことが示され、その後にTLSハンドシェイクや接続タイムアウトが発生するなら、ルーティングの役割はほぼ完了しています。この場合は、プロキシoutboundのアドレス、ポート、SNI、トランスポート経路、システム時刻、リモート側への到達性を確認します。

結論:tagで経路全体を追跡する

問題調査の手順を「inbound tag → 宛先ドメインまたはIP → 一致したルール → outbound tag → トランスポート接続」に固定します。各段階が対応する設定区画を1つに絞れるため、ポート競合、振り分けミス、ノードのハンドシェイク失敗を同じ問題として扱わずに済みます。

v2rayN をダウンロード Windows、macOS、Android、Linuxクライアントを確認