JSON構造の概要と読み取り順
まずコア設定とクライアント設定を区別する
V2Ray設定ファイルはJSONオブジェクトです。コアは起動後にトップレベルのフィールドを読み込み、受信待受、送信接続、ルーティング、名前解決、接続ポリシーを一連の処理として組み立てます。ファイル内の記述順に沿って1行ずつ実行するわけではないため、routingをinboundsより前に書いても動作結果は変わりません。通信の行き先を決めるのはフィールド間の参照関係で、特にtag、inboundTag、outboundTag、balancerTagが重要です。
v2rayN、v2rayNG、v2flyNGには、それぞれ独自の画面設定とデータ保存方式があります。クライアントに表示されるサブスクリプションのグループ、システムプロキシの切り替え、アプリごとの設定が、コアのJSONにそのまま存在するとは限りません。デスクトップで調査するときは、まず今回の起動で実際に読み込まれた設定を見ているか、古いバックアップやサブスクリプション原文ではないかを確認します。クライアントが設定を再生成すると、実行ファイルへ直接書き込んだ内容が置き換えられる場合があります。長期的に保持したいルールは、クライアントが提供するカスタムルーティング、DNS、詳細設定の項目に登録するのが安全です。
よく使うトップレベルフィールド
| フィールド | 型 | 役割 | 主な関連項目 |
|---|---|---|---|
log |
オブジェクト | アクセスログ、エラーログ、ログレベルを定義 | 障害の切り分け |
inbounds |
配列 | ローカルアプリやネットワークインターフェースからの接続を受け付ける | routing.inboundTag |
outbounds |
配列 | 通信で最終的に使用する接続方式を定義 | routing.outboundTag |
routing |
オブジェクト | ドメイン、アドレス、ポート、プロトコル、送信元に応じてoutboundを選択 | inboundとoutboundのタグ |
dns |
オブジェクト | コア内部のドメイン名前解決の動作を定義 | routing.domainStrategy |
policy |
オブジェクト | 接続タイムアウト、統計機能、システムレベルのポリシーを定義 | ユーザーのlevel、stats |
stats |
オブジェクト | コアの統計モジュールを有効化 | policy内の統計設定 |
最小構成はサーバーオブジェクトが1つだけという意味ではありません。完全な処理には、少なくとも1つのinboundと1つのoutboundが必要です。inboundはアプリがリクエストをコアへ渡す方法を、outboundはコアがリクエストを処理する方法を決めます。routing、DNS、policyは一時的に省略でき、その場合はコアのデフォルト動作が使われます。ただしルーティングルールを追加したら、参照されるすべてのタグが実在しなければなりません。タグは大文字と小文字を区別するため、proxyとProxyは別の値として扱われます。
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "local-socks",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
}
]
}
この例ではローカルのループバックアドレスだけでSOCKSを待ち受け、受信した通信をすべてfreedom outboundへ渡します。JSONをコアが読み込めるか、ポートを待ち受けられるか、アプリが正しいプロキシポートを向いているかを確認するのに適していますが、リモートプロキシサーバーは含みません。listenが127.0.0.1の場合、同一LAN上の他の端末はそのポートへ接続できません。すべてのネットワークインターフェースで待ち受ける前に、公開範囲とシステムのファイアウォール設定を確認してください。
JSON構文の基本ルール
JSONのオブジェクトキーと文字列には必ずダブルクォートを使います。配列やオブジェクトの最後の要素の後にカンマは置けません。真偽値はtrueまたはfalseのみで、ポート番号をクォートしてはいけません。標準JSONはコメントを受け付けないため、説明文は外部ドキュメントやクライアントのメモ欄に置き、実行用設定へ挿入しないでください。例をコピーするときは、全角記号、スマートクォート、不可視スペースにも注意しましょう。これらはリッチテキストエディターから混入しやすい文字です。
設定の読みやすさは、インデント、タグ、セクション分けで保ちます。インデントは2スペースに統一し、local-socks、proxy、direct、blockのように、短く用途が伝わる英単語をタグに使うのがおすすめです。用途を配列の位置だけで表現しないでください。後からoutboundを追加したりルーティングを変更したりするときも、安定したタグが誤参照を防ぎます。目的がサブスクリプションをインポートして接続することだけなら、ファイル全体を手書きする必要はありません。V2Ray使用ガイドに沿って操作してください。クライアントを選ぶ場合はダウンロードセンターへ進みます。
inbounds(受信):待受、プロトコル、通信の入口
inboundオブジェクトの役割
inboundsは配列で、各要素が独立した入口を表します。デスクトップクライアントでは、ローカルのSOCKSポートとHTTPプロキシポートがよく使われます。透過的に通信を取り込む構成では、dokodemo-doorを使う場合もあります。リクエストがコアへ入ると、inboundタグ、宛先アドレス、宛先ポート、ネットワーク種別などの属性を伴い、これらがルーティングモジュールの判定に渡されます。inboundは最終的にプロキシ、直接接続、ブロックのどれを使うかは決めず、リクエストを受け取り、解析して処理チェーンへ送る役割だけを担います。
共通フィールドにはtag、listen、port、protocol、settings、sniffing、streamSettingsがあります。settingsの構造はプロトコルごとに異なります。SOCKSでは認証方式とUDP、HTTPではアカウント、dokodemo-doorでは転送先を設定できます。異なるプロトコルのフィールドは混在させないでください。SOCKSのudpをHTTP inboundに置いても、期待した動作にはなりません。
ローカルSOCKS・HTTPの2つの入口
{
"inbounds": [
{
"tag": "local-socks",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
],
"routeOnly": true
}
},
{
"tag": "local-http",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {}
}
]
}
2つのinboundは異なるポートを使います。SOCKS対応アプリは127.0.0.1:10808へ、HTTPプロキシにのみ対応するアプリは127.0.0.1:10809へ接続します。同じアドレスとポートを2つのプロセスが同時に待ち受けることはできません。クライアント起動時にポート使用中と表示されたら、別のクライアント、古いコアプロセス、他のプロキシツールが動作していないか確認してから、プロセスを終了するかポートを変更します。
auth: "noauth"は、ループバックアドレスだけにバインドするローカル入口に適しています。待受範囲をLANへ広げる場合、アクセス制御をアプリ層の認証だけに頼らず、システムのファイアウォールで送信元も制限してください。設定のudp: trueは、SOCKS inboundがUDP転送リクエストを受け付けることを示すだけで、すべてのoutboundプロトコル、転送方式、上流ネットワークがUDP通信に対応することを意味しません。Webページは開くのに音声、ゲーム、名前解決で問題が出る場合は、inbound、routing、outbound、上流対応の4層に分けて確認します。
sniffingと宛先の復元
一部のアプリはドメインを先にアドレスへ解決し、そのアドレスをプロキシポートへ渡します。この場合、ルーティングモジュールから見える宛先はアドレスだけになり、ドメインルールを直接適用できません。sniffingは、条件に合う接続からHTTPのホスト名やTLSハンドシェイク内のサーバー名を識別し、ルーティングモジュールにドメイン情報を提供します。ただし、すべての通信を識別可能なドメインへ変換する機能でも、汎用的なパケットキャプチャ機能でもありません。
destOverrideは識別を許可する種類を指定します。例ではhttpとtlsを有効にしています。routeOnly: trueは、識別結果を主にルーティング判定へ使い、元の接続先を直接置き換えないことを示します。これにより宛先書き換えによる互換性の差を抑えられます。宛先識別を有効にして特定アプリの接続に問題が出たら、まずSOCKS inboundだけで試し、アプリごとに確認してください。原因を特定しないままrouting、DNS、outboundの設定を同時に変更しないでください。
| フィールド | 推奨チェックポイント | よくある症状 |
|---|---|---|
listen |
ローカル利用ではまずループバックアドレスにバインド | バインド設定の誤りで接続不能または公開範囲が拡大 |
port |
他のプロセスが使用していないことを確認 | コアの起動に失敗し、クライアントで接続未確立と表示 |
protocol |
アプリが実際に対応するプロキシ種別と一致 | HTTPリクエストをSOCKSポートへ送ると直ちに失敗 |
udp |
outboundと上流側の対応も確認 | TCPは正常だがUDP通信に問題 |
tag |
ルーティングのinboundTagと完全に一致 | inboundを限定したルールが常にマッチしない |
複数入口を使う際の境界
複数の入口は、アプリの送信元を分けたい場合に適しています。たとえばブラウザー用と開発ツール用に別々のinboundを用意し、ルーティングルールでinboundTagに応じて異なるoutboundへ振り分けます。全体ルールを何度も変更するより、構成が明確です。2つのinboundに同じポリシーを適用するなら、形式的な理由だけで分割する必要はありません。入口が増えるほど、ポート競合、システムプロキシの誤設定、ルール漏れが起きやすくなります。
Androidクライアントは通常、システムが提供するネットワークインターフェースを通じてアプリの通信を受け取ります。画面上のアプリ別プロキシやバイパス設定も、実行用設定の生成に反映されます。デスクトップ向けJSONのローカル待受方式を、そのままモバイル端末へ持ち込むことはできません。v2rayNGはXrayコア、v2flyNGはv2flyコアを使用するため、画面上の項目やコアが利用できる機能が異なる場合があります。手動で調整する前に、使用中のクライアント、コア、実際の設定生成先を確認してからフィールドを照合してください。
outbounds(送信):サーバー、プロトコル、転送層
outboundオブジェクトの3層構造
outboundsも配列です。各outboundは通常、3層の情報で構成されます。共通層ではtagとprotocolで用途を示し、プロトコル層ではsettingsにサーバーアドレス、ポート、ユーザーパラメータを記入します。転送層ではstreamSettingsにTCP、WebSocket、gRPC、TLSなどを設定します。調査時は3層を分けて確認し、「プロトコルが正しい」ことを接続全体が正しいことと同一視しないでください。
サーバーが提供するプロトコル、アドレス、ポート、ユーザー識別子、転送方式、セキュリティ層、サーバー名は、ひとまとまりの情報として確認する必要があります。プロトコル名だけを変更したり、VMessのユーザーパラメータをVLESSのものに置き換えたりするだけでは、設定の変換は完了しません。サブスクリプションインポートの利点は、これらの関連フィールドを完全なノードとしてクライアントへ渡せることです。手入力する場合は、古いノードのデフォルト値に頼らず、サーバー側の資料と1項目ずつ照合してください。
VLESS over TCP with TLSの例
{
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "server.example.com",
"port": 443,
"users": [
{
"id": "11111111-1111-4111-8111-111111111111",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "server.example.com",
"allowInsecure": false
}
}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
]
}
例のドメインとユーザー識別子は構造を示すためのものです。実際の接続にはサーバーが提供した情報を使用してください。addressは接続先で、ドメインにもアドレスにもできます。portは数値です。VLESSユーザー項目のidは識別に使われ、encryptionは通常サーバーの要件に合わせます。これは外側のTLSとは別の概念です。前者はプロトコルのユーザーパラメータ、後者は転送時のセキュリティ層であり、相互に置き換えることはできません。
network: "tcp"は、基盤となる転送方式がTCPであることを示します。security: "tls"でTLSを有効にし、tlsSettings.serverNameでハンドシェイクに使うサーバー名を指定します。通常はサーバー証明書と構成情報に一致させます。allowInsecure: falseにして、通常の証明書検証を維持してください。接続に失敗しても、問題を隠すために先にtrueへ変更せず、システム時刻、サーバー名、アドレス解決、証明書の対象範囲、経路上のネットワークを確認します。
VMessオブジェクトのフィールド位置
{
"tag": "proxy-vmess",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "vmess.example.com",
"port": 443,
"users": [
{
"id": "22222222-2222-4222-8222-222222222222",
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "vmess.example.com"
},
"wsSettings": {
"path": "/connection"
}
}
}
VMessとVLESSはいずれもvnextを使う場合がありますが、users内部のフィールドは異なります。VMessの例ではsecurity、VLESSの例ではencryptionを使います。WebSocket転送にはwsSettingsも必要で、そのパスはサーバー側と一致させます。特定のリクエストヘッダーを要求される場合は、対応するWebSocket設定に記入します。TCP、WebSocket、gRPCにはそれぞれ専用の設定オブジェクトがあるため、前の転送方式で残った無関係なフィールドを残さないでください。
directとblockは処理の出口
freedom outboundはコアが宛先へ直接接続するもので、通常directと名付けます。blackholeはマッチした通信を終了させるもので、通常blockと名付けます。これらはリモートノードではありませんが、ルーティング設定には重要な構成要素です。ルールはタグを選ぶだけなので、同名のoutboundがなければ処理を完了できません。プロキシ、直接接続、ブロックの3つのタグを明示し、ルールの意図をファイル上で分かるようにするのがおすすめです。
配列の先頭にあるoutboundには特別な意味があります。ルーティングルールにマッチしない場合、コアは通常、先頭のoutboundをデフォルトの出口として使います。そのため、outboundを単に名前順で並べないでください。未マッチの通信をデフォルトでプロキシへ送るならプロキシoutboundを先頭に、直接接続をデフォルトにするならdirectを先頭に置きます。重要なフォールバックルールも明示し、順序を変更した後は実際の経路を再確認すると安全です。
| 層 | 代表的なフィールド | 確認する情報源 |
|---|---|---|
| 共通層 | tag、protocol |
ローカル名とプロトコル種別 |
| プロトコル層 | address、port、users |
サーバー情報またはサブスクリプション情報 |
| 転送層 | network、security |
サーバー側の転送設定 |
| 転送の詳細 | tlsSettings、wsSettings |
サーバー名、パスなどのデプロイ情報 |
routing(ルーティング):条件、ルール順序、出口の選択
ルーティングルールは順番に処理される
routingは接続属性に基づいてoutboundを選択します。rulesは順序付き配列で、コアは先頭から確認し、最初に条件へ一致したルールが指定する出口を使います。その接続について後続ルールは判定されません。したがって具体的なルールを前に、広いルールを後ろに置きます。「全ポート」や「広範囲のアドレス」のルールを先頭に置くと、下にあるより精密なドメインルールが隠れてしまうことがあります。
1つのルール内にある複数の条件は、通常すべて同時に成立する必要があります。たとえばinboundTag、domain、portを同じルールに書くと、入口、ドメイン、ポートのすべてが一致したときにだけマッチします。いずれかのドメイン条件またはアドレス条件を表したい場合は、同じoutboundを指す2つのルールに分けると、構造が明確でログからも経路を追いやすくなります。
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"inboundTag": [
"local-socks"
],
"domain": [
"full:internal.example.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"protocol": [
"bittorrent"
],
"outboundTag": "block"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
1つ目はlocal-socksから入り、指定した完全なドメインを宛先とするリクエストだけを処理します。2つ目はプライベートアドレス範囲を直接接続にし、ローカル端末の通信がリモートへ送られるのを防ぎます。3つ目は識別可能なプロトコルに基づいて処理します。最後のルールは残りのTCP・UDP通信を対象にする明示的なフォールバックです。すべてのoutboundTagはoutbounds内に存在しなければなりません。タグ名を変更したら、ルーティング側の参照も同時に更新します。
domainStrategyは解析のタイミングを決める
domainStrategyは、ルーティングモジュールがドメイン宛ての接続に対して、さらにアドレス解決を行うかどうかに影響します。AsIsは主に元のドメインで判定し、アドレスルールのために積極的な解決は行いません。IPIfNonMatchはまずドメインルールを試し、マッチしなければアドレスを解決してアドレスルールを確認します。IPOnDemandは、ルール判定でアドレスが必要になった時点でより早く解決します。積極的な戦略ほどアドレスルールが使われやすくなりますが、DNSの動作もルーティング結果へ直接影響します。
設定が主にドメイン分類に依存し、宛先アドレスで判定する必要がないなら、AsIsから始めるとよいでしょう。geoipや独自のネットワーク範囲も使う場合は、IPIfNonMatchのほうが理解しやすいことが多く、まずドメインを確認して、マッチしなければ解決します。このフィールドを変更して経路が変わったら、ルーティング配列だけでなくDNSサーバーの選択、解決結果、キャッシュも確認してください。
ドメインのマッチ形式
| 形式 | 意味 | 適した場面 |
|---|---|---|
full:example.com |
完全一致のドメインだけを対象 | 単一の固定ホスト |
domain:example.com |
そのドメインと一般的なサブドメイン範囲に一致 | サイト単位でルールを整理 |
regexp:^.+\.example\.com$ |
正規表現で一致させる | 構造が複雑で、前2つの形式では表現できない場合 |
geosite:category-ads-all |
コアが利用できるドメイン分類データを参照 | クライアントとコアに対応データが用意されている場合 |
正規表現は柔軟ですが、保守の負担が大きくなります。ドットなどの文字は正規表現の規則に従ってエスケープし、JSON文字列内ではバックスラッシュもJSONのエスケープ規則に合わせる必要があります。full:やdomain:で表現できる場合は、より直感的な形式を優先してください。分類データのルールは、クライアントがコアとともに提供するデータファイルに依存します。同じルールの結果が端末ごとに異なる場合は、分類内容が完全に同じだと決めつけず、データファイルの入手元と更新日時を確認してください。
アドレス、ポート、送信元、ネットワーク種別
ipには単一アドレス、CIDRネットワーク、コアが対応するアドレス分類を指定できます。portには単一ポート、範囲、カンマ区切りの組み合わせを指定できます。例:53、80-443。sourceとsourcePortは送信元情報でルールを制限するために使い、networkはTCPとUDPを区別し、inboundTagは入口ごとにアプリの経路を分けます。必要な条件だけを組み合わせ、項目を埋めるためにすべて記入しないでください。
ポートだけで判定できるのは宛先ポートであり、アプリやプロトコルを確実に識別できるわけではありません。Webサービスが標準外ポートを使うこともあれば、別のサービスが一般的なポートを使うこともあります。宛先を安定して識別したい場合は、ドメイン、アドレス、入口の送信元を組み合わせてください。プロトコル判定は、コアが対象通信を識別できるかどうかに依存します。識別できなければルールはマッチしません。未識別の接続が意図しない出口へ流れないよう、明確なフォールバックを用意します。
複雑な振り分けは、プライベートアドレスを直接接続、明確に処理したい宛先を指定の出口、残りをデフォルト出口という3ルールから始めるとよいでしょう。基本経路が安定してから、ドメイン分類、ポート、送信元条件を段階的に追加します。大量のルールを一度に投入すると、競合箇所の特定が難しくなります。一般的な振り分け用語は用語マニュアルで確認できます。ルールがマッチしているのに接続できない場合は、順序を繰り返し変えるのではなく、outboundとDNSを確認してください。
dns設定:名前解決サーバー、ドメイングループ、ルーティング連携
コアDNSとシステムDNSの境界
dnsは、コア内部でドメインを解決するときに使うサーバーと判定方法を定義します。OS全体のDNS設定と同じものではありません。アプリがシステム層で先に解決してアドレスをプロキシへ渡す場合もあれば、ドメインをプロキシ経由で渡し、コアまたはリモート側で処理する場合もあります。DNSルールがリクエストに関与するか判断するには、まずどの層でドメインが解決されるか、inboundの宛先識別がドメイン情報を提供しているかを確認します。
ルーティングのdomainStrategyがコアの名前解決を発生させることがあります。また、outboundが接続するサーバーアドレスの解決も必要で、一部のDNSクエリが通常の通信として再びルーティングを通る場合もあります。設定を誤ると、コアがプロキシサーバーへ接続するためにそのドメインを解決しようとし、その解決リクエストがまだ確立していないプロキシoutboundへ送られるという循環依存が起きます。起動に必要な宛先へ明確で到達可能な解決経路を用意し、ルールをシンプルに保つことが解決の基本です。
{
"dns": {
"hosts": {
"router.example": "192.168.1.1"
},
"servers": [
{
"address": "223.5.5.5",
"domains": [
"domain:example.cn"
],
"expectIPs": [
"geoip:cn"
]
},
{
"address": "1.1.1.1",
"domains": [
"domain:example.com"
]
},
"localhost"
],
"queryStrategy": "UseIP"
}
}
hostsは静的な名前解決を提供し、固定されたローカルサービス名や、明確に上書きしたい少数のドメインに適しています。大規模なドメインリストの代わりにはなりません。静的マッピングを変更しても実際のサービス変更には自動追従しないため、保守できる宛先だけを設定してください。例では構造を示すため、router.exampleをプライベートアドレスへ割り当てています。実際の設定ではローカルネットワークの情報を使用します。
serversには名前解決サーバーを順番に記述します。オブジェクト形式ではdomainsを追加し、特定のドメインを優先してそのサーバーへ渡せます。文字列形式は汎用サーバーまたはフォールバックとして使えます。localhostは本機の名前解決機能を使うことを示します。クライアントがDNSを管理している場合、コア設定がクライアントによって書き換えられる可能性もあるため、最終的な動作は実行時設定とログを基準にしてください。
domainsとexpectIPs
domainsは、どのドメインを現在のサーバーで優先的に解決するかを決めます。ルーティングのドメインルールに近い形式を使い、特定ホストにはfull:、ドメイン範囲全体にはdomain:、分類データには対応する分類識別子を指定できます。サーバーオブジェクトにdomainsがない場合は、通常、汎用候補になります。複数サーバーが一致すると、コアの実装やクエリ戦略も実行結果に影響するため、範囲の重複は減らしてください。
expectIPsは、解決結果に対する期待値フィルターです。例では、最初のサーバーグループが指定したアドレス分類に合う結果を返すよう求めています。結果が条件に合わなければ、コアは他の候補を検討できます。「このドメイングループは特定種別のアドレスへ解決されるべき」という制約を表すのに適していますが、上流が到達不能、サーバーがタイムアウト、分類データが不足している問題は直せません。トラブル対処では、まずこの制限を一時的に外して基本クエリが成功するか確認し、その後で結果条件を戻します。
queryStrategyとアドレスファミリー
| 戦略 | 主な動作 | 使用前の確認事項 |
|---|---|---|
UseIP |
利用可能なアドレス種別を問い合わせる | システムとoutboundが返されたアドレスを処理できるか |
UseIPv4 |
IPv4の解決結果を優先 | 宛先がIPv4アドレスを提供しているか |
UseIPv6 |
IPv6の解決結果を優先 | ローカルネットワークとoutboundにIPv6接続性があるか |
アドレスファミリーの選択は、実際のネットワーク能力と一致させる必要があります。IPv6アドレスが解決されたからといって、端末、ルーター、プロキシサーバー、outboundチェーンのすべてが到達できるとは限りません。一部のドメインだけ長時間待たされ、ネットワークを変えると直る場合は、返されたアドレス種別とoutboundの接続性を確認してください。逆にIPv4を強制すると、IPv6アドレスしか提供しない宛先を解決できなくなることがあります。戦略は汎用的な高速化スイッチではなく、実際のネットワーク状況に基づいて選びます。
DNSリクエストがルーティングを通る仕組み
DNSサーバーにアドレスを指定した場合、クエリの宛先はそのままoutbound選択へ進めます。ドメインを指定した場合は、DNSサーバー自身のドメインを先に解決しなければなりません。特定のクエリ群をプロキシ経由にしたいなら、識別可能で循環を起こさないDNS宛てのルーティングルールを用意します。最も簡単な確認方法は、2つの経路を書き出すことです。業務ドメインを誰が解決するのか、DNSサーバー自身を誰が解決するのかを分けて考えます。どちらかがまだ確立していない自身の接続へ戻るなら、設計を見直してください。
ドメインルールが機能しない場合は、まずアプリがコアへ渡しているのがドメインかアドレスかを確認します。アドレスしかない場合は、SOCKSリクエスト方式、宛先識別、ルーティングのdomainStrategyを確認します。DNSが正しいのに接続先が誤る場合は、キャッシュ、静的マッピング、クライアントが生成した追加ルールを調べます。名前解決サーバーの変更、アドレスファミリーの変更、ルーティング順序の入れ替えを同時に行わないでください。復旧しても原因を特定できなくなります。
中国本土と海外のドメイングループ、リモート名前解決、アドレスルールの組み合わせをさらに理解したい場合は、ブログのV2Ray DNS設定詳解をご覧ください。記事は構成設計、本章はフィールドと実行範囲に重点を置いています。クライアントの画面項目と手書きフィールドが一致しない場合は、使用中のコアが対応する機能と、実際に生成された設定を基準にしてください。
policy(ポリシー):タイムアウト、ユーザーレベル、統計設定
policyはoutboundを選択しない
policyは接続のライフサイクルと統計設定を定義するもので、ドメインやアドレスによる振り分けは行いません。一般的な構造にはlevelsとsystemがあります。levelsはユーザーレベルをキーに、同じレベルを使うユーザーへハンドシェイク、アイドル、上り下りの保持時間、統計項目を設定します。systemはinboundとoutboundのシステムレベル統計を制御します。特定ドメインの出口を変えたい場合はroutingを変更し、policy内にルール項目を探さないでください。
レベルは速度プランでも優先順位でもありません。プロトコルのユーザーオブジェクトはlevelで同じ名前のポリシーグループを参照できます。明示しない場合は通常、デフォルトレベルが使われます。複数のレベルを用意する意味があるのは、接続ライフサイクルを実際に分ける必要がある場合だけです。一般的なクライアント設定では1つのレベルで十分で、ユーザーオブジェクトとポリシーオブジェクトの参照関係を減らせます。
{
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300,
"uplinkOnly": 2,
"downlinkOnly": 5,
"statsUserUplink": false,
"statsUserDownlink": false
}
},
"system": {
"statsInboundUplink": false,
"statsInboundDownlink": false,
"statsOutboundUplink": false,
"statsOutboundDownlink": false
}
}
}
handshakeは、接続確立段階で待機できる時間を制御します。値が小さすぎると、高遅延ネットワークや遅いハンドシェイクが早期に失敗し、値が大きすぎると、本当に到達不能な接続を長く待つことになります。Webページの読み込み全体のタイムアウトでも、アプリ自身のリクエスト期限でもありません。ハンドシェイクに失敗したら、まずアドレス、ポート、転送層、ネットワーク到達性を確認し、その後で値の調整を検討します。
connIdleは、データの動きがない接続を保持できる時間です。短すぎると長時間接続、プッシュ通知、断続的な転送に影響し、長すぎると使われていない接続がリソースを長く占有します。適切な値は用途によって異なり、すべてのネットワークに共通する数字はありません。モバイルネットワークが頻繁に切り替わる場合、コア内に古い接続が残っていても利用不能になっている可能性があるため、クライアントの再接続動作も合わせて判断します。
uplinkOnlyとdownlinkOnlyは、ハーフクローズ状態で接続を保持する時間を指定します。一方向のデータ送信が終わっても、もう一方では短時間の転送が必要な場合があります。早く終了すると末尾のデータが途切れ、長く保持するとリソース解放が遅れます。通常はまずこの2項目を調整せず、ログと業務上の挙動がハーフクローズ処理を示している場合だけ、個別にテストしてください。
統計機能は2つの層を同時に有効にする
statsUserUplinkとstatsUserDownlinkはユーザー単位の統計を制御し、system下のフィールドはinboundとoutboundの統計を制御します。統計データを実際に生成するには、通常、トップレベルにstatsオブジェクトも必要で、クライアントまたはAPIがデータを読み取ります。policyのスイッチを開くだけで表示用グラフが自動生成されたり、結果が特定のページへ自動保存されたりするわけではありません。
{
"stats": {},
"policy": {
"system": {
"statsInboundUplink": true,
"statsInboundDownlink": true,
"statsOutboundUplink": true,
"statsOutboundDownlink": true
}
}
}
統計機能を有効にすると、処理量とメモリ使用量が多少増えます。トラブル対処のため一時的にinbound・outboundの通信量を確認するだけなら、必要な範囲で有効にし、完了後は戻してください。ユーザー単位の統計には、プロトコルユーザーに対応するレベルと識別子があることも必要です。サーバー管理や明確なデータ収集が必要な場合に向いています。一般的なローカルクライアントでは、ユーザーごとの統計層を作るより、outboundに通信が流れているかを確認することのほうが重要です。
| フィールド | 単位または型 | 変更時のリスク |
|---|---|---|
handshake |
秒 | 短すぎると接続確立段階が早期終了 |
connIdle |
秒 | 短すぎると長時間接続に影響し、長すぎるとリソース解放が遅れる |
uplinkOnly |
秒 | 上り方向の終了後に接続を保持する時間へ影響 |
downlinkOnly |
秒 | 下り方向の終了後に接続を保持する時間へ影響 |
statsInboundUplink |
ブール値 | 有効にすると対応する統計データと追加負荷が発生 |
ポリシー変更のテスト方法
接続ポリシーを調整するときは、ノード、ルーティング、DNSを固定し、変更するポリシー値を1つだけにします。テスト対象も明確にしてください。ハンドシェイクの問題は新規接続で、アイドルの問題は接続後に待機して、ハーフクローズの問題は一方向の終了を再現できる通信で確認します。Webページを1回更新するだけでは、すべてのフィールドを検証できません。テスト後は元の値、変更値、現象を記録し、何度も調整した後も基準を失わないようにします。
クライアントは起動時にデフォルトのpolicyを生成する場合もあれば、省略してコアのデフォルト値を使う場合もあります。フィールドを省略したからといって値がゼロになるわけではありません。現在の接続が安定しており、統計やライフサイクルに明確な要件がないなら、出所不明のパラメータ一式をコピーするよりデフォルト動作を維持するほうが適切です。v2rayN、v2rayNG、v2flyNGのプラットフォーム上の位置付けを比較する場合は比較レビューへ進んでください。ポリシーフィールドの利用可否は各コアとクライアントの実装に従います。
完全な組み合わせ、読み込み確認、段階的なトラブル対処
各セクションを追跡可能な処理チェーンに組み立てる
完全な設定で重要なのはフィールド数ではなく、各接続が明確な経路をたどれることです。アプリがinboundへ接続し、inboundが宛先情報を生成し、必要に応じてDNSが解決結果を提供し、routingがoutboundを選択し、outboundがプロトコルと転送設定に従って接続を確立し、policyがライフサイクルを管理します。どの層でエラーが起きても、クライアントには「接続できない」としか見えない場合があります。調査では、この曖昧な症状を具体的な段階へ分解する必要があります。
{
"log": {
"loglevel": "warning"
},
"dns": {
"servers": [
"localhost"
],
"queryStrategy": "UseIP"
},
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
},
"inbounds": [
{
"tag": "local-socks",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "server.example.com",
"port": 443,
"users": [
{
"id": "11111111-1111-4111-8111-111111111111",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "server.example.com",
"allowInsecure": false
}
}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300
}
}
}
}
この例は構造上の関係を示すもので、サーバー情報は実際の資料に置き換えてください。プライベートアドレスはdirectへ、その他のTCP・UDP通信はproxyへ送ります。SOCKS inboundはローカルだけで待ち受け、DNSにはシステムの名前解決機能を使い、policyには基本的な接続ライフサイクルだけを設定しています。設定内ではblockも定義していますが、現在のルーティングルールからは参照していません。将来、明確なブロックルールを追加できるよう残しています。
第1層:ファイルを読み込めるか
まずファイルの文字コード、JSON構文、キー名のつづり、データ型を確認します。よくある誤りは、カンマの付け忘れ、最後の要素の後の余分なカンマ、シングルクォートの使用、ポートを文字列で記述すること、配列の外側に角括弧が1層足りないこと、コピー後に全角記号が混入することです。コアが起動時に直ちに終了する場合は、まずエラーログのフィールドパスと行・列位置を確認してください。構文が通っていない段階で、ルーティングがマッチするかを議論しないでください。
GUIクライアントを使う場合は、そのファイルが現在のプロセスによって実際に読み込まれているかも確認します。v2rayNは現在のサーバー、ルーティング、DNS設定に基づいてコア設定を再生成することがあります。v2rayNGとv2flyNGも、モバイル画面の状態に応じて実行パラメータを生成します。使われていないエクスポートファイルを編集しても、現在の接続は変わりません。クライアントログ、設定プレビュー、起動パラメータで実際の読み込み先を確認できます。
第2層:inboundが確立しているか
コア起動後、ローカルの待受アドレスとポートが存在するか確認します。アプリのプロキシ種別はinboundのプロトコルと一致させます。SOCKSはSOCKSポート、HTTPはHTTPポートを指定してください。システムプロキシを有効にしてもブラウザーが直接接続する場合は、システムプロキシの向き先、ブラウザー独自のプロキシ設定、現在のクライアントモードを確認します。アプリが直ちにプロキシサーバーへの接続拒否を示すなら、まずコアの稼働、ポートの一致、本機のファイアウォールを調べます。
特定のアプリだけに問題がある場合、すぐにノードの失敗と判断しないでください。そのアプリがシステムプロキシを参照しない、独自のDNSやHTTP/3、独立したネットワーク設定を持つ可能性があります。まずSOCKSまたはHTTPプロキシに確実に対応するテストアプリでinboundを確認し、その後で対象アプリのプロキシ対応を調べます。モバイル端末では、アプリ別の対象範囲とシステムネットワークインターフェースが確立しているかも確認します。
第3層:routingとDNSが期待する宛先を返すか
inboundが接続を受けたら、宛先がドメインかアドレスかを確認し、ルーティングで最初にマッチしたルールを調べます。ログで誤ったoutboundへ進んでいるなら、ルール順序、タグのつづり、条件の組み合わせを重点的に確認します。ドメインルールはマッチせずアドレスルールだけが有効なら、アプリが解決する場所、sniffing、domainStrategyを確認します。解決がタイムアウトする場合は、DNSサーバーと結果制限を一時的に減らし、基本的な問い合わせ経路を確認してください。
ルーティングの問題とDNSの問題は互いに影響します。次の2点を分けて確認してください。対象ドメインは何に解決されたのか、解決後にどのルールがマッチしたのか。この2段階を分けることで、解決結果が期待と違うのか、ルール順序が誤っているのかを判断できます。ノードを何度も交換しても、ローカルのルール競合は解決しません。
第4層:outboundが接続を完了できるか
outboundの段階では、サーバーアドレスの解決、ポート到達性、プロトコル種別、ユーザーパラメータ、転送種別、セキュリティ層、サーバー名、パスまたはサービス名の順に確認します。ログのタイムアウトはネットワーク到達性や経路を示すことが多く、即時切断はポート、プロトコル、ハンドシェイクパラメータの不一致で起きやすい症状です。システム時刻の大きなずれもTLS接続に影響します。一度に変更するフィールドは1つにし、復元できる元設定を残してください。
| 症状 | 優先して確認する項目 | 次の手順 |
|---|---|---|
| コア起動後すぐ終了する | JSON構文、フィールド型、ポートの使用状況 | エラーログのフィールドパスを確認 |
| アプリがローカルプロキシへ接続できない | inboundのアドレス、ポート、プロトコル種別 | アプリのプロキシ設定とコアプロセスを確認 |
| 一部のドメインだけ誤った出口へ進む | ルール順序、宛先種別、DNS結果 | 最初にマッチしたルールを記録 |
| すべてのリモート接続がタイムアウトする | サーバー解決、ポート、ネットワーク経路 | 次に転送方式とセキュリティ層を確認 |
| TCPは正常だがUDPに問題がある | inboundのUDP、ルーティングのネットワーク種別、outboundの対応 | 上流側とアプリの動作を確認 |
| 変更後に再起動しても変化しない | 実際に読み込まれたファイル、クライアントの自動生成 | 実行設定から設定元を逆引き |
ログレベルと最小再現
日常利用では、比較的簡潔なログレベルを維持できます。問題を切り分けるときだけ一時的に情報量を増やし、明確な操作を1回再現してから元に戻してください。ログが多いほど結論が早いわけではありません。時刻、inboundタグ、宛先、ルーティング結果、outboundエラーを軸に読み取ります。ログを共有する前に、サーバーアドレス、ユーザー識別子、サブスクリプション内容、ローカルパスなどの機密情報を処理してください。
最小再現設定には、inboundを1つ、プロキシoutboundを1つ、直接接続outboundを1つ、最小限のルールだけを残します。最小設定で接続できたら、DNSグループ、追加inbound、複雑なルーティング、policyを段階的に追加します。どの段階で問題が再発したかが、追加した内容の調査範囲です。最小設定でも失敗するなら、サーバーパラメータ、ネットワーク経路、コアの互換性に戻って確認します。完全な設定から無作為にフィールドを削るより、安定した方法です。
判断できない場合は、FAQトラブル対処で症状から引き続き確認できます。クライアントを再インストールしたり、プラットフォームとの対応関係を確認したりする場合は、ダウンロードセンターでv2rayN、v2rayNG、v2flyNGを選択してください。デスクトップではv2rayN、Androidでは必要なコアに応じてv2rayNGまたはv2flyNGを選びます。再インストール前に、現在のサブスクリプション、ルーティング、DNS設定を記録し、設定の問題とプログラムの問題を同じ操作で混同しないようにしてください。