設定を読むときは、まず入口と出口、それらをつなぐタグを確認し、次にルーティングとDNSを見ていきます。この記事では、リモートサーバーの認証情報を含まないV2Rayの従来形式のJSON設定を例に、各項目や照合順序、確認方法を解説します。サブスクリプションを読み込み、v2rayNの出力ファイルを理解したい方向けです。例ではローカルのSOCKS接続、直接接続、通信の遮断のみを扱い、リモートプロキシ機能は提供しません。
1. クライアント設定とコアの実行設定を区別する
v2rayNは管理用のインターフェースで、V2RayとXrayは実際に通信を処理するコアです。サブスクリプションにはサーバー情報や設定元が保存され、インターフェースにはグループ、選択中の項目、ルーティングプリセットなどの状態も保存されます。一方、コアの起動時に読み込まれるJSONには、待ち受けポート、出力プロトコル、ルーティングルールが記述されています。拡張子が同じだからといって、これらのファイルを相互に置き換えることはできません。
この記事ではV2Rayの従来形式のJSON設定を扱い、すべてのコア固有の項目を網羅するものではありません。v2rayNGはXrayコア、v2flyNGはv2flyコアを使用します。どちらも inbounds と outbounds が含まれていても、すべてのプロトコル設定が互換とは限りません。特にREALITY、フロー制御、トランスポート関連の項目は、実際に使用するコアのドキュメントで確認してください。
設定ファイルを読むときは、この流れに沿って参照関係を確認します。log は処理の記録を確認するためのもので、dns は名前解決機能を提供します。どちらも、記述された順に実行されるネットワークノードではありません。JSONオブジェクト内の5つのモジュールの並び順は処理順を決めませんが、配列内のルーティングルールの順序は結果に影響します。
- オブジェクト:
{}にキーと値を格納します。たとえば、インバウンドの待ち受けアドレスやプロトコルを記述します。 - 配列:
[]に複数の項目を格納します。たとえば、複数のアウトバウンドやルーティングルールを記述します。 - 型:
10808は数値、"10808"は文字列、falseは真偽値です。これらを自由に置き換えることはできません。 - 構文:この記事では標準JSONを使用し、コメントや末尾のカンマは使いません。キー名と文字列は英語の二重引用符で囲みます。
2. 設定全体の例:ローカルSOCKSインバウンドと2種類のアウトバウンド
以下は設定の構造を理解するための一例です。ローカルループバックアドレスのみで待ち受け、SOCKSリクエストを受け付けます。宛先ポートが25のTCP接続は遮断し、それ以外のルールに該当しない通信はデフォルトで直接接続します。アプリが自動的にプロキシを使う設定にはならず、リモートプロキシサーバーへの接続も行いません。
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "local-socks",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": false
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"inboundTag": ["local-socks"],
"network": "tcp",
"port": "25",
"outboundTag": "block"
},
{
"type": "field",
"ip": [
"127.0.0.0/8",
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["full:localhost"],
"outboundTag": "direct"
}
]
},
"dns": {
"servers": ["localhost"],
"queryStrategy": "UseIP"
}
}
これらの数値はサンプル設定で指定した値であり、すべてのクライアントバージョンのデフォルト値ではありません。10808 を使用するプログラムがすでにある場合は、空いているポートに変更し、アプリ側のSOCKSアドレスも同じ値にしてください。例に含まれるプライベートネットワークへの直接接続ルールは、記述方法を示すものであり、ローカルネットワークのアドレスを網羅したものではありません。
3. logとinbounds:リクエストがコアに届くか確認する
log.loglevel はログの詳細度を指定します。例では、警告やエラーの確認に適した warning を使用しています。トラブルシューティング時は一時的に info に変更し、必要に応じて debug を使います。access や error のファイルパスを指定していなくても、ログが必ず出力されなくなるわけではありません。起動元のクライアントが受け取り、表示する場合があります。
inbounds はインバウンドの配列です。この例では 127.0.0.1:10808 宛てのSOCKS接続のみを受け付けるため、アプリでこのアドレスを明示的に指定する必要があります。ブラウザーでHTTPプロキシを設定し、SOCKS専用のポートを指定すると、プロトコルが一致せず接続できません。また、コアを起動しただけではシステムプロキシは変更されません。
ログの確認項目
- loglevel
- warning
- 一時的なトラブルシューティング
- infoまたはdebug
- 出力先
- パスの設定と起動方法による
問題の特定後は詳細度を下げ、接続情報が長期間記録されすぎないようにしてください。
ローカルインバウンドの項目
- listen
- 127.0.0.1
- port
- 10808
- protocol
- socks
- tag
- local-socks
tagはルーティングで参照する名前です。待ち受けアドレスでも、リモートノード名でもありません。
auth: "noauth" は、このSOCKSインバウンドで認証を要求しないことを示します。そのため、例では待ち受け範囲をローカルに限定しています。他のデバイスから接続できるようにするために、アクセス制御を無視して待ち受けアドレスをすべてのインターフェースに変更しないでください。udp: false は、このインバウンドでSOCKS UDP転送が有効になっていないことを示します。UDPを使うアプリの動作確認には使えません。
ポートの競合はインバウンドの起動時に起きる問題で、接続タイムアウトはその後の通信経路で起きる問題です。まずログで待ち受けに失敗していないか確認し、その後にルーティング、DNS、リモートサーバーを調べると、無駄な変更を減らせます。
4. outbounds:プロトコルが接続を処理し、tagで参照する
outbounds 配列では、通信をコアからどのように送り出すかを定義します。この例の freedom は宛先に直接接続し、blackhole は該当する通信を破棄します。direct と block は任意に付けたタグです。タグ名を変更してもプロトコルの動作は変わりませんが、そのタグを参照するルールもすべて変更する必要があります。
| 項目 | サンプル値 | 確認ポイント |
|---|---|---|
| outbounds[0].tag | direct | ルーティングで参照する名前。ここではデフォルトのアウトバウンドも兼ねる |
| outbounds[0].protocol | freedom | リモートプロキシを経由せず、宛先に直接接続 |
| outbounds[1].protocol | blackhole | ルーティングで選択された接続を遮断 |
| settings | 空のオブジェクト | この例ではデフォルトの動作を使用。プロキシプロトコルには通常、追加のパラメーターが必要 |
ここで扱う従来形式の設定モデルでは、どのルールにも一致しない接続は最初のアウトバウンドに渡されます。そのため、配列の順番を変えるとデフォルトの動作も変わる可能性があります。block を先頭にすると、デフォルトで直接接続されていたリクエストが遮断される場合があります。単なる表示順の整理と考えて並べ替えないでください。
実際にVMessまたはVLESSのアウトバウンドを使う場合は、サーバーアドレス、ポート、認証情報のほか、streamSettings が含まれることもあります。protocol でプロキシプロトコルを指定し、トランスポートやセキュリティ層のパラメーターは別の場所に設定します。freedom を vless に置き換えるだけで接続できるわけではありません。また、異なるプロトコルの settings をそのまま流用することもできません。
デフォルトの動作を確認するには、まず先頭の項目を見てからタグの参照先を調べる
設定を変更する前に、最初のアウトバウンドのtagを記録し、すべてのoutboundTagを検索してください。デフォルト経路と明示的な経路の両方を確認して初めて、接続が最終的に直接接続、プロキシ経由、遮断のどれになるか判断できます。
5. routing:ルールの順に照合し、条件の細かさで優先順位を推測しない
routing.rules は上から順に照合し、一致したルールに対応するアウトバウンドを使います。ドメイン名が長いルールや、IP範囲が狭いルールが自動的に優先されるわけではありません。1つのルール内の異なる条件は、通常すべて満たす必要があります。同じ条件の配列に複数の値がある場合は、通常そのうち1つに一致すれば該当します。設定前に「すべて一致」と「いずれかに一致」を区別してください。
- 1つ目のルール:インバウンドタグが
local-socksで、ネットワークがTCP、宛先ポートが25であることが条件です。3つすべてを満たした場合にblockに渡されます。 - 2つ目のルール:宛先IPが列挙されたネットワーク範囲のいずれかに含まれる場合、
directに渡されます。宛先がプライベートIPでも、先に1つ目のTCPポート25のルールに一致すれば、引き続き遮断されます。 - 3つ目のルール:
full:localhostはドメイン名との完全一致を意味し、localhostという文字列を含むすべての名前に一致するわけではありません。 - どのルールにも一致しない場合:最初のアウトバウンドを使います。この例では
directです。2つ目と3つ目のルールは、この例ではデフォルトのアウトバウンドと結果が同じですが、ルールの書き方を示すために残しています。
inboundTag にはインバウンドの tag を、outboundTag にはアウトバウンドの tag を指定します。大文字・小文字やスペルを一致させてください。これらはコアが自動認識する日本語のグループ名ではなく、クライアントに表示されるノード名を変更しても自動で追従しません。
domainStrategy: "AsIs" は、ルーティング時にIPルールとの照合を目的としてドメインを積極的にIPアドレスへ解決しない設定です。アプリからドメイン名が渡された場合、2つ目のIPルールでは照合できないことがあります。最初からIPアドレスが渡された場合は、ネットワーク範囲を直接確認できます。IPIfNonMatch に変更すると、ドメイン名で一致しなかった場合に解決を試してから照合しますが、すべてのDNSリクエストがリモート経由になるという意味ではありません。
full:example.com:ドメイン名が完全一致した場合のみ照合します。個別の確認に適しています。domain:example.com:そのドメインとサブドメインに一致します。ドメイン単位で通信を振り分ける場合に適しています。port: "25":ここで指定するのは宛先ポートです。ローカルの待ち受けポート10808ではありません。ip:宛先アドレスを対象とします。「特定のLAN内デバイスからの通信」という送信元条件には使えません。
6. dns:名前解決の設定と通信の出口を区別する
この例の dns.servers には "localhost" のみを指定しています。これはローカルシステムの名前解決機能を使う設定であり、ローカルのDNSポートで待ち受ける設定ではありません。queryStrategy: "UseIP" はIPv4とIPv6のアドレスを問い合わせます。実際に返される結果は、ドメインのレコード、リゾルバー、ネットワーク環境にも左右されます。
dns モジュールを設定しても、すべてのアプリのDNSリクエストがコアに入るとは限りません。アプリ側で名前解決してからIPアドレスをSOCKSに渡す場合もあれば、ドメイン名をコアに渡して処理させる場合もあります。前者では、ドメイン名による振り分けに必要な情報が失われる可能性があります。後者では宛先ドメイン名が保持されます。リクエストをインバウンドで受け取る方法と、DNSモジュールで名前解決する方法は別の問題です。
| 設定箇所 | 制御する内容 | 混同しないこと |
|---|---|---|
| dns.servers | 内蔵DNSモジュールが利用する名前解決先 | OS上のすべてのプログラムのDNS設定 |
| dns.queryStrategy | 問い合わせるアドレスファミリーの方針 | 直接接続かプロキシかを選ぶルーティングルール |
| routing.domainStrategy | ルーティングの照合時に名前解決結果を使うかどうか | すべての名前解決リクエストを同じ経路に固定すること |
| アウトバウンド側の名前解決方針 | そのアウトバウンドで宛先ドメイン名を処理する方法 | すべてのコアで共通の項目 |
ドメイン名に応じてリゾルバーを使い分ける場合は、DNSサーバーオブジェクトの domains などの項目も確認してください。その際は、問い合わせ通信がどのようにリゾルバーへ届くかも調べる必要があります。DNSアドレスを変更しただけでは、意図したプロキシ経路をDNSリクエストが通るとは限りません。トラブルシューティングでは、リクエストにドメイン名とIPアドレスのどちらが渡されるか、最終的にどのアウトバウンドが選ばれるかをあわせて確認してください。
7. 出力ファイルの確認方法:構文から実際の接続まで
編集前に設定ファイルをコピーし、クライアントが自動生成した実行用ファイルを直接上書きしないようにしてください。v2rayNは、ノードの切り替え、サブスクリプションの更新、コアの再起動時に設定を再生成することがあります。一時的な実行ファイルだけを変更すると、次回起動時に変更が失われる可能性があります。長期的に反映する変更は、クライアントのルーティング設定、DNS設定、またはカスタム設定画面に保存してください。具体的な場所は使用中のバージョンの画面で確認してください。
- JSON構文を確認する:二重引用符、括弧、カンマが正しく対応しているか確認します。Pythonがインストールされていれば、次のコマンドで基本的な構文を検査できます。検査に通っても、コアがすべての項目に対応しているとは限りません。
- 実際に使うコアを確認する:クライアントのコア選択画面と起動ログで、コア名、バージョン、読み込まれた設定ファイルのパスを確認してください。クライアント名だけで判断しないでください。
- 参照関係を確認する:
inboundTagとoutboundTagを1つずつ検索し、対応する定義が見つかることと、最初のアウトバウンドを確認してください。 - 待ち受けとリクエストを確認する:
127.0.0.1:10808で待ち受けが開始できること、アプリ側でSOCKSプロトコルと同じポートを使っていることを確認してください。 - 個別に検証する:一度に変更するのは1つのモジュールだけにします。まず通常のTCPリクエストを確認し、次にドメインルールと遮断ルールをテストして、複数の要因が混在しないようにしてください。
python -m json.tool config.json
構文に問題がなくてもコアが起動を拒否する場合は、ログで項目のパスとエラーの種類を確認してください。未対応の項目、プロトコル設定の非互換、ポート競合はそれぞれ別の問題であり、DNSを変更して一括で解決することはできません。ログや設定を共有する前に、サーバーの認証情報、サブスクリプションURL、不要な個人用パスを削除してください。
JSONの検査に通っても起動に失敗するのはなぜですか?
構文検査で確認できるのは、ファイルを解析できることだけです。クライアントの起動ログを開き、最初のエラーを特定して、プロトコル名、項目の型、実際に使うコアを確認してください。アドレスの競合が表示された場合は、10808を使用しているプログラムを停止するか、待ち受けポートも合わせて変更してください。
outboundTagを変更したら、元のノードが使われなくなったのはなぜですか?
新しいタグが、いずれかのアウトバウンドのtagと完全に一致しているか確認し、次にルールの順序を確認してください。ルーティング側の参照だけを変更し、アウトバウンドの定義を変更し忘れないようにしてください。また、リクエストが上位のルールに先に一致していないかも確認します。
この設定をコピーしても、サブスクリプションのサーバーに接続できないのはなぜですか?
この記事の例にあるアウトバウンドはfreedomとblackholeの2種類のみです。リモートプロキシを使うには、有効なサブスクリプションをもとにクライアントで対応するアウトバウンドを生成し、ルーティングから正しく参照されているか確認してください。このサンプルに認証情報を推測で書き加えないでください。
v2rayNを再起動すると、手動で変更した内容が消えるのはなぜですか?
通常は、クライアントが実行設定を再生成したことが原因です。変更前後のコピーを保存し、長期的に保持するルーティングやDNSの変更はクライアントの保存設定に反映してください。その後再起動し、新しく生成されたファイルを確認します。一時ファイルを繰り返し編集する方法は避けてください。