ノードをインポート済みで、コアの設定を理解したい方向けです。まずリクエストの流れに沿って4つのトップレベル項目を確認し、VMess + WebSocket + TLSの例を読み解きます。最後にタグ参照、ルールの順序、DNSを確認します。読み終えると、接続に失敗するたびにJSON全体を書き直すのではなく、inbounds、ノード設定、routingのどこを見直すべきか判断できます。
1. 設定ファイルとクライアント設定の違い
v2rayNとv2rayNGはクライアントで、ノード管理やサブスクリプション更新、コアが実行する設定の生成を担います。v2rayNGはXrayコア、v2flyNGはv2flyコアを使用します。v2rayNでは複数のコアを管理できますが、この記事で扱うのは従来のV2Ray/XrayのJSON設定形式です。すべてのコアに共通するフィールド一覧ではありません。
ここでいうconfig.jsonは、コアが実際に読み込む設定ファイルです。ウィンドウ位置やサブスクリプションのグループなどを保存するクライアント設定ファイルではありません。ファイル名も固定とは限りません。起動コマンドで指定されたファイルか、またinboundsやoutboundsなどの項目が含まれているかで判断します。クライアントがノードを更新したりコアを再起動したりすると、自動生成されたファイルが上書きされる場合があります。
inbounds:リクエストを受け付ける場所を定義します。たとえば、ローカルのSOCKSポートです。outbounds:リクエストの送信方法を定義します。プロキシノードへの転送、直接接続、ブロックなどを指定します。routing:接続先のドメインやIP、inboundのタグなどを条件に、使用するoutboundを選択します。dns:組み込みDNSリゾルバーを設定します。システムDNSを自動的に制御するスイッチではありません。
2. JSON全体の例:2つのinboundsと3つのoutbounds
以下は構造を読み解くための完全な例です。node.example.invalidは実在しないドメインで、UUIDもサンプル値のため、実際のノードには接続できません。従来のVMessで使われるvnext構造を使用しています。実際のアドレス、ポート、UUID、伝送パス、TLS名はサーバーの設定に合わせてください。
{
"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"],
"routeOnly": true
}
},
{
"tag": "http-in",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "node.example.invalid",
"port": 443,
"users": [
{
"id": "00000000-0000-4000-8000-000000000001",
"alterId": 0,
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "node.example.invalid"
},
"wsSettings": {
"path": "/ws",
"headers": {
"Host": "node.example.invalid"
}
}
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": ["full:blocked.example.invalid"],
"outboundTag": "block"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["full:localhost"],
"outboundTag": "direct"
}
]
},
"dns": {
"servers": ["223.5.5.5"]
}
}
ポート番号はこの記事の例で使用する値で、すべてのバージョンに共通する既定値ではありません。JSONのポート番号は数値、trueは真偽値です。どちらも引用符で囲んだ文字列にしてはいけません。最後の項目の後ろにカンマを付けることもできません。検証しやすいよう、例ではコメントを使っていません。
3. inbounds:待ち受けアドレス、プロトコル、スニッフィング
listenは接続を受け付けるローカルアドレス、portはポート番号、protocolはアプリが接続に使うプロキシプロトコルを指定します。SOCKSクライアントからHTTP inboundへ直接接続することはできません。ポートに接続できても、プロトコルが正しいとは限りません。アプリに手動設定する場合、この例ではSOCKS5なら127.0.0.1:10808、HTTPプロキシなら127.0.0.1:10809を指定します。
SOCKS inbound
- tag
- socks-in
- listen
- 127.0.0.1
- port
- 10808
- protocol
- socks
- settings.udp
- true
ローカルホストのみで待ち受けます。UDPを使うには、アプリ側でSOCKS5 UDP転送を利用する必要もあります。
HTTP inbound
- tag
- http-in
- listen
- 127.0.0.1
- port
- 10809
- protocol
- http
- settings
- 空のオブジェクト
HTTPプロキシ対応アプリ向けです。HTTPSリクエストでは通常CONNECTトンネルを使用します。
127.0.0.1を指定すると、ローカルホストからの接続だけを受け付けます。0.0.0.0に変更すると、すべてのIPv4ネットワークインターフェースで待ち受けます。サンプルのSOCKS inboundではauth: "noauth"も指定しているため、そのままネットワークに公開しないでください。プロキシを共有する場合は、認証、ファイアウォール、接続を許可する送信元をあわせて確認してください。
sniffingを使うと、HTTP HostやTLSハンドシェイクのサーバー名から接続先ドメインを特定し、ドメインルールの判定に利用できます。routeOnly: trueは、スニッフィングで取得した名前をルーティング判定だけに使い、元の接続先を置き換えない設定です。HTTPSを復号する機能ではなく、すべての通信でドメインを取得できるわけでもありません。この例ではSOCKS inboundだけでスニッフィングを有効にしています。
tagは設定内で参照する名前であり、サーバーに表示されるユーザー名ではありません。settings.udp: trueを設定しても、すべてのUDP通信が自動的にコアへ取り込まれるわけではなく、TUNが有効になるわけでもありません。- AndroidクライアントのVPN経由の通信を、この2つのローカル待ち受けポートだけで説明することはできません。この記事の例は、主に手動プロキシの入口を理解するためのものです。
4. outbounds:ノード認証と伝送方式を分けて確認
プロキシoutboundのprotocol: "vmess"はノードのプロトコルを表します。settings.vnextにサーバー一覧、usersに認証情報を設定します。idはユーザーUUIDです。alterId: 0は現在のVMessで一般的な設定です。古い解説にある0以外の値を試すのは避けてください。users[].security: "auto"はVMessの暗号化オプションで、TLSの有効・無効とは別の設定です。
| 項目 | 例の値 | 役割 |
|---|---|---|
vnext[].address | node.example.invalid | コアが接続するノードのアドレス |
vnext[].port | 443 | サーバーの待ち受けポート。ローカルのinboundポートではありません。 |
streamSettings.network | ws | WebSocketで通信 |
streamSettings.security | tls | 伝送レイヤーでTLSを有効化 |
tlsSettings.serverName | node.example.invalid | TLSのサーバー名。通常はSNIと証明書名の検証に使用 |
wsSettings.path | /ws | WebSocketリクエストのパス。サーバー側の設定と一致させる必要があります。 |
wsSettings.headers.Host | node.example.invalid | WebSocketハンドシェイクで使用するHTTP Host |
この例では変数を減らすため、アドレス、SNI、Hostに同じ値を使っています。実際の設定では、3つが異なる場合もあります。IPアドレスに接続するときも、TLSでドメイン名の指定が必要なことがあります。パスも完全に一致させてください。/wsと/proxyは、入れ替え可能な飾りの文字列ではありません。
freedomは直接接続するoutbound、blackholeは通信をブロックするoutboundです。direct、block、proxyはこの記事で付けたタグ名なので変更できますが、すべてのoutboundTag参照もあわせて変更してください。VLESSのユーザー項目はVMessと完全には同じではありません。protocolをvlessに変えるだけでは移行できません。
確認ポイント:接続できないときは2段階で確認
まずアドレス、ポート、UUIDを照合し、次にnetwork、TLS名、Host、pathを確認します。証明書検証を無効にしてserverNameの誤りを回避しないでください。設定を間違えたまま検証を省略しても、ノードが正しくなるわけではありません。
5. routing:ルールの順序と既定のoutbound
rulesは配列の先頭から順に評価され、最初に一致したルールでoutboundが決まります。この例では、まずサンプルのドメインをブロックし、次にプライベートアドレスとlocalhostを直接接続します。どのルールにも一致しない場合、従来のV2Ray/Xray設定ではoutbounds配列の先頭にあるoutboundが使われます。そのため、この例では既定でproxyを使用します。タグ名が「proxy」かどうかは関係ありません。
- タグを確認:
outboundTag: "direct"に対応するtag: "direct"のoutboundが必要です。 - 順序を確認:具体的な例外ルールは、通常、範囲の広いルールより前に置きます。末尾に置くフォールバックルールを先に置くと、後続のルールに到達できません。
- 条件を確認:1つのルール内にある異なるフィールドは、通常すべて満たす必要があります。同じフィールドの配列にある複数の候補は、通常いずれかに一致すれば対象になります。
- データを確認:
geoip:privateを使うにはGeoIPデータファイルが利用できる必要があります。geositeの項目を使う場合も、対応するドメインデータを確認してください。
ドメインのマッチ方法には違いがあります。full:example.comは完全一致、domain:example.comはそのドメインとサブドメインに一致します。接頭辞のない文字列は通常キーワードとして扱われ、想定以上に広い範囲に一致することがあります。対象を絞りたい場合は、マッチ範囲を明示してください。
| domainStrategy | 名前解決のタイミング | 確認ポイント |
|---|---|---|
AsIs | ルーティング判定では、ドメインを自動的にIPアドレスへ名前解決しません。 | ドメイン宛てのリクエストがIPルールに自動一致するとは限りません。 |
IPIfNonMatch | ドメインルールに一致しない場合、名前解決してからIPルールを試します。 | 名前解決の結果によって、最終的なoutboundが変わる場合があります。 |
IPOnDemand | 判定にIP条件が必要になった時点で名前解決します。 | 名前解決の負荷とDNSの応答内容を確認してください。 |
この例では、判定の流れをシンプルにするためAsIsを指定しています。接続先がもともとプライベートIPなら、プライベートアドレスのルールに一致します。一方、名前解決の結果がプライベートIPになるドメインが、そのルールに一致するとは限りません。LAN内のドメインには、明示的な直接接続ルールを追加するか、名前解決の挙動を理解したうえで方針を調整してください。
6. dns:組み込みリゾルバーとシステムDNSの違い
dns.serversでは、コアの組み込みリゾルバーが使用するサーバーを指定します。この例では構造を説明するため、上流サーバーを223.5.5.5だけにしています。DNSの振り分けを完全に設定した例ではありません。アプリがリクエスト前に独自に名前解決することもあります。システム、ブラウザー、コアそれぞれの名前解決経路を個別に確認してください。
- アプリからドメインが渡される場合:コアはドメインルールで判定できます。ルーティング方針でIPが必要なら、組み込みDNSでアドレスを取得します。
- アプリが先に名前解決し、IPを渡す場合:ルーティングからはIPしか見えないことがあります。スニッフィングで一部のドメイン情報を補える場合はありますが、すべてのリクエストを特定できるとは限りません。
- 直接接続outboundでの名前解決:
freedomのドメイン処理方針も名前解決の方法に影響します。この例では設定が空ですが、すべての名前解決が前述の組み込みDNSサーバーを経由するという意味ではありません。 - リモートプロキシでの名前解決:ドメインがプロキシプロトコル経由でサーバーに送信された場合、サーバー側で名前解決されることがあります。実際のリクエストと設定によって異なります。
したがって、dnsを設定しただけでは、すべての名前解決が想定どおりプロキシを経由するとは限りません。アプリが独自に名前解決していないか、routingのdomainStrategy、outboundの名前解決方針、DNSクエリ自体の到達性を確認してください。特に、ドメイン名で接続するノードを使う場合は、ノードへの接続がまだ確立していないのに、そのノードに依存してノードのドメイン名を解決する構成にならないよう注意してください。
7. エクスポートした設定からトラブルシューティングまで:変更は1つずつ
トラブルシューティングでは、まず動作する設定を1つ保存し、コアのバージョンと実際に読み込まれているファイルを確認します。v2rayNの「設定」→「パラメータ設定」では、ローカルの待ち受けに関する項目を確認・変更できます。画面のタブや項目名はバージョンによって異なります。クライアント画面のノード設定やルーティング設定と、実行時のJSONが対応しているか確認してください。クライアントが再生成したファイルだけを見ても不十分です。
- 構文を確認:ローカルのエディターで括弧、カンマ、値の型を確認します。UUID、サブスクリプションURL、ノード情報を公開オンラインフォーマッターに送信しないでください。
- コアとの互換性を確認:設定を読み込んでいるのがV2RayかXrayかを確認します。新しいフィールドや伝送方式は、使用中のコアが対応している範囲に合わせてください。
- 入口を確認:プロセスが実際に設定されたポートで待ち受けているか確認します。
address already in useが表示された場合は、まずポートの競合を解消してください。ノードのUUIDを先に変更する必要はありません。 - outboundを確認:ルールの条件を一時的に減らし、アドレス、認証情報、伝送方式を確認します。タイムアウト、認証失敗、TLSエラーは、それぞれ異なる観点から調べてください。
- 振り分けを確認:対象を絞ったテストルールを1つ追加し、リクエストが意図したoutboundを選ぶか確認してから、ルール一式を元に戻します。
- デバッグログを元に戻す:必要に応じて
loglevelを一時的にdebugへ変更します。確認後はwarningに戻し、接続情報が過剰に記録され続けないようにしてください。
コアを単独で実行する場合は、設定ファイルのテストコマンドを使用できます。以下はサブコマンド形式を採用しているV2Ray/Xray実行ファイル向けです。パスは実際のファイルの場所に置き換えてください。古いバージョンではコマンドライン引数が異なる場合があるため、まずローカルのhelp出力を確認してください。
v2ray test -c config.json
xray run -test -config config.json
テストに成功しても、現在のコアで設定を解析・読み込みできたことがわかるだけです。ノードの稼働状況、証明書の正しさ、すべてのルールが意図どおりかどうかまでは確認できません。最後に、プロキシ対応を明示しているアプリから実際にリクエストを送信してください。ログではinboundのタグ、接続先アドレス、選択されたoutboundを確認します。共有する前に認証情報や個人のアクセス履歴を削除してください。
確認のまとめ:入口、outbound、routing、DNSを個別に検証
まずリクエストが正しいポートに届くことを確認し、次にプロキシノードの接続を検証します。その後、振り分けと名前解決の方針を追加してください。各段階で元に戻せる設定を保存し、4つのレイヤーを同時に変更して「まだつながらない」だけが残る事態を避けましょう。