JSON構造と設定の範囲
設定ファイルは、コアが接続を受け付け、経路を選び、outbound接続を確立する方法を定義するもので、クライアントの全設定をまとめたものではありません。ウィンドウ位置、サブスクリプショングループ、更新間隔、システムプロキシの切り替えなどは通常、GUIクライアント側に保存されます。一方、待ち受けポート、プロトコルのパラメーター、ルーティングルールは実行時設定に含まれます。まずこの2つを分けて考えると、GUIの設定、自分で管理するテンプレート、独立したJSONファイルのどれを変更すべきか判断しやすくなります。
トップレベルオブジェクトとデータ型
JSONの最上位はオブジェクトです。キー名と文字列は半角の二重引用符で囲みます。オブジェクトは波括弧、配列は角括弧で表し、ポート番号は通常数値、真偽値は小文字のtrueまたはfalseで記述します。最後の要素の後ろにカンマは付けません。全角の引用符、コメント、ページからコピーした際に混入する不可視文字をファイルに入れないでください。あるツールで読み込めても、すべてのコアで使えるとは限りません。
inboundsとoutboundsは配列です。1つのプロセスで複数の入口を提供したり、複数の出口を定義したりできるためです。一方、routing、dns、policyはオブジェクトで、それぞれルール、名前解決、接続ポリシーを管理します。キー名は大文字と小文字を区別し、タグも完全一致が必要です。outboundTagの大文字・小文字を変えても、自動修正されるわけではありません。
{
"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",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
]
}
最小構成を確認する
上の例は、ローカルのSOCKS inboundから直接接続する、基本的な設定ファイルです。アプリからローカルの指定ポートにリクエストを渡すと、コアはfreedomを使って現在のネットワークから接続します。リモートプロキシサーバーは含まれておらず、ブラウザーやOSのプロキシ設定も自動では変更されません。設定を読み込めるか、ポートを待ち受けているか、アプリからコアへ接続できるかを確認するための例であり、リモートノードへの接続例ではありません。
この例にはルーティングがないため、ルールで選択されない接続には通常、最初のoutboundが使われます。そのため、outbounds配列の順序には実際の意味があり、表示順にすぎないと考えてはいけません。リモートoutboundを追加する場合は、デフォルトの経路を明確に設計してください。何も考えずノードを1つ追加しただけでも、ルールに一致しないすべてのリクエストの行き先が変わることがあります。まず「デフォルトでどこへ接続するか」を決めてから、配列とフォールバックルールを設定しましょう。
完全な設定ファイル、断片、クライアントテンプレート
設定断片は、routingオブジェクトやoutboundの項目など、特定のフィールド周辺の構造だけを示します。組み込む際は、2つの完全なオブジェクトをそのまま連結せず、同じ名前のトップレベルフィールド内に配置してください。トップレベルのキーを重複させるのも避けましょう。重複キーの扱いはパーサーによって異なり、起動できても両方のルールが適用されるとは限りません。配列またはオブジェクトを1つにまとめる方法が確実です。
GUIクライアントは、選択中のサーバー、ルーティングのプリセット、ローカルポートなどに基づいて実行用ファイルを生成することがあります。そのファイルを直接編集しても、次にサーバーを切り替えたりコアを再起動したりすると、変更が上書きされる可能性があります。まず、クライアントにカスタム設定、ルーティング編集、インポートなどの機能があるか確認してください。ファイルを自分で継続管理できると確認できた場合に限り、長期的な設定元として使いましょう。GUIと手動編集の両方で同じ項目を管理しないでください。
| 内容 | 主な設定場所 | 確認するポイント |
|---|---|---|
| サブスクリプショングループ、自動更新 | クライアント設定 | 更新時にサーバー項目が再生成されるか |
| inbounds、outbounds、ルーティング | コアの実行設定 | 項目とタグの対応関係 |
| システムプロキシ、バックグラウンド権限 | OSとクライアントの連携 | アプリの通信がinboundに届いているか |
省略した項目にはコアのデフォルト値が適用されますが、デフォルト値を理解の妨げにする必要はありません。セキュリティ境界、デフォルトoutbound、ルーティング時の名前解決方針は明示するのがおすすめです。まだ使わない複雑な機能は、まず省略してください。例を参照するときは、コアの系統も確認しましょう。V2FlyとXrayは基本構造が似ていますが、拡張項目がすべて共通とは限りません。不明な項目や起動エラーが出た場合は、ネットワークの問題を疑う前に対応範囲を確認してください。
保存時には、正常に動作する基準設定を別に保管し、変更の目的はファイルとは別の通常のメモに記録してください。厳密なJSONに説明文を挿入してはいけません。1回につき関連する項目だけを変更し、読み込みに成功してから該当する動作をテストします。こうすれば「構文エラー」「階層の誤り」「接続パラメーターの不一致」を切り分けやすくなります。設定を一度に大量に貼り付けて、元に戻せなくなる事態も避けられます。
inbounds(受信)とローカル待ち受け
inboundは、アプリからコアへ接続を渡す入口です。設定で最初に確認すべきなのはリモートサーバーではなく、アプリが接続しているローカルアドレス、ポート、プロキシプロトコルです。リモートノードの設定が正しくても、ブラウザーが古いポートを参照していれば、この設定には接続されません。トラブル時は、アプリのプロキシ設定とinboundの待ち受け設定を並べて確認しましょう。クライアントの画面に「実行中」と表示されているかだけでは判断できません。
待ち受けアドレスと公開範囲
listenはバインドするローカルアドレス、portは待ち受けポートを指定します。端末内だけで使う場合は、IPv4ループバックアドレスの127.0.0.1を優先してください。アプリでlocalhostを指定すると、OSによってはIPv6ループバックアドレスに解決されます。コアがIPv4だけで待ち受け、アプリがIPv6だけを試すと接続できない場合があります。切り分け中は、同じループバックアドレスを明示するのがおすすめです。
すべてのネットワークインターフェースで待ち受けることと、LAN内の端末から接続を許可することは同じではありません。バインド範囲を広げる場合は、ファイアウォール、端末のネットワーク環境、inboundの認証も考慮してください。認証のないプロキシ入口を信頼できないネットワークに公開してはいけません。共有する場合は、利用者とネットワーク境界を明確にしたうえで、認証と接続元を制限するファイアウォールを設定します。リモートサーバーの認証情報は、ローカルinboundのアクセス制御の代わりにはなりません。
{
"inbounds": [
{
"tag": "local-socks",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
}
},
{
"tag": "local-http",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {}
}
]
}
SOCKSとHTTPの入口の違い
上の断片では、2つのinboundがそれぞれSOCKSプロキシとHTTPプロキシを提供します。アプリでSOCKS5を選んだ場合は前者に、HTTPプロキシを選んだ場合は後者に接続します。HTTPプロキシはCONNECTを使ってHTTPS宛ての接続を中継できます。接続先URLがHTTPSで始まるからといって、プロキシ入口にもTLSが必要だと誤解しないでください。入口のプロキシプロトコルと接続先サイトのプロトコルは、別のレイヤーです。
SOCKS inboundのudpは、SOCKS UDP転送を処理できることを示しますが、経路全体でUDPが使える保証ではありません。アプリが対応していることに加え、リモートoutboundとサーバーもUDPを処理でき、ネットワーク経路で該当パケットが許可されている必要があります。HTTP inboundは汎用のUDP入口の代わりにはなりません。Webページは見られるのに特定のリアルタイムアプリが動かない場合は、Web用ポートを繰り返し変更するのではなく、そのアプリの通信方式を個別に確認してください。
inboundタグとスニッフィングの範囲
tagは、ルーティングから参照できる入口名を設定します。たとえば、ブラウザーとテストツールで異なるinboundを使えば、inboundTagで2種類の通信を区別できます。タグを付けても待ち受けが始まるわけではなく、アプリの接続が制限されるわけでもありません。接続可否を決めるのはアドレス、ポート、プロトコルです。タグは短く、変更しにくい名前にしましょう。名前を変更したら参照元のルーティングも更新してください。
{
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
}
}
このsniffingオブジェクトは、個々のinboundの内部でsettingsと同じ階層に置きます。対応するプロトコルのハンドシェイクからドメイン名を識別し、ドメインベースのルーティングに利用します。暗号化された内容をすべて読み取れるわけではなく、すべての接続でドメイン名を取得できる保証もありません。IPアドレスを直接指定したリクエストでは、識別結果が宛先の処理に影響する場合があります。ルーティング用途などの拡張オプションは、実際のコアがサポートしているか確認してください。
ポート競合とシステムプロキシ
待ち受けに失敗した場合は、まずログに記録されたアドレスとポートを確認してください。別のクライアントプロセスが使用中の場合もあれば、システムサービスや他のローカルプロキシが待ち受けている場合もあります。ポートの数字を変えるだけで終わりにしないでください。inboundを変更したら、手動設定のブラウザー、ターミナルツール、その他のアプリも更新が必要です。クライアント管理のシステムプロキシは設定に応じて更新されますが、実際の値をOSのプロキシ設定画面で確認しましょう。
システムプロキシは、その設定に従うアプリに特定の入口への接続を指示するもので、端末の全通信を取り込む機能ではありません。独自のプロキシ設定を持つアプリや、システムプロキシを無視するアプリもあります。これはinboundの起動可否とは別の問題です。クライアントにTUNモードがある場合、通信の取り込み、ルーティング、権限にはOS側の仕組みも関わります。SOCKS inboundを追加するだけでは実現できません。検証では、まずプロキシ対応が明確なアプリを使って範囲を絞りましょう。
有効なinboundテストでは、コアが正常に起動したこと、対象ポートで待ち受けていること、アプリのリクエストが対応するログに記録されることをすべて確認します。プロセスが存在するだけでは不十分です。設定の読み込みに失敗していても、クライアントの画面に情報が残っていることがあります。この3点を確認してからoutboundを調べれば、ローカル入口の問題をリモート経路の障害と取り違えずに済みます。入口ごとの振り分けに進むための基準にもなります。
outbounds(送信)とタグの関係
outboundは、コアが受け取った接続をどの方法で宛先まで届けるかを決めます。直接接続する、リモートプロキシサーバーに中継する、ルールに一致した通信を破棄する、といった方法があります。outbounds内の各オブジェクトでは、まずプロトコルを確認し、次にそのプロトコルに対応するsettingsを確認してください。プロトコルごとに設定構造は異なります。protocol名を変更しただけで、既存の設定を別プロトコル用に変換することはできません。
直接接続、プロキシ、遮断
freedomは現在の端末が接続しているネットワークから直接接続するプロトコルで、blackholeは一致した通信を破棄します。direct、proxy、blockはよく使われるタグ名にすぎず、組み込みプロトコルではありません。たとえばdirectというタグが実際にはリモートプロトコルを指していれば、接続はリモート経由になります。設定を読む際はタグとプロトコルの両方を確認し、英語のタグ名だけで動作を判断しないでください。
{
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
]
}
この断片は、基本テスト設定のoutbound部分として使えます。ルールで別のoutboundが選ばれない場合、通常は最初のoutboundがデフォルト経路になります。クライアントが設定を生成する際、デフォルトoutboundやフォールバックルールを独自に配置することがあるため、手動で確認するときは画面に表示されたサーバー名だけでなく、最終的な実行用ファイルを見てください。outboundを追加しただけでは通信は流れません。デフォルトの順序またはルーティングから参照する必要があります。
リモートoutboundのパラメーター構造
リモートプロキシの設定には通常、サーバーアドレス、ポート、ユーザー認証、トランスポート、セキュリティの設定が含まれます。アドレスは接続先サーバー、ポートはサービスの待ち受け位置、ユーザー情報は選択したプロトコルに合わせます。トランスポート経路、サービス名、TLSサーバー名はそれぞれ別の階層です。これらの値をすべて1つのアドレス欄に入れたり、リンク内のエンコード文字列をそのまま認証項目に貼り付けたりすると、設定構造が崩れます。
サブスクリプションや共有リンクは、サーバー設定をやり取りするための情報であり、完全な実行設定ではありません。クライアントはインポート後、ローカルポート、DNS、ルーティングなどを組み合わせて実行ファイルを生成します。共有リンクを読み込めても、形式を認識できたことを示すだけです。認証の有効性、証明書の一致、トランスポートの接続先が存在することまでは保証されません。リモート設定には利用権限のあるサービスの情報を使い、別の例から認証情報やパスを継ぎ合わせないでください。
| 階層 | 主な項目 | 不一致時の症状 |
|---|---|---|
| 接続先 | サーバーアドレス、ポート | 名前解決失敗、接続拒否、タイムアウト |
| プロトコル認証 | ユーザーID、パスワード、暗号化パラメーター | 接続後に認証失敗または切断 |
| トランスポートとセキュリティ | パス、サービス名、TLSパラメーター | ハンドシェイク失敗、接続先の応答不一致 |
複数のoutboundと切り替え条件
1つの設定に複数のリモートoutboundを含め、ルールごとに参照できます。タグにはそれぞれ一意で分かりやすい名前を付け、同じ名前を重複させないでください。タグを手動で変更する場合はルーティングだけでなく、outboundを参照する他の機能も確認しましょう。outbound一覧の並び替えだけで、ヘルスチェックや自動切り替えが有効になるわけではありません。関連する仕組みを設定していなければ、経路が遅くてもコアが自動で別の経路に切り替えることはありません。
プロトコルによっては、ドメイン名の名前解決方針、コネクション再利用、低レベルのソケット設定などもあります。こうした項目は基本の接続が成功してから調整してください。たとえば名前解決方針は直接接続outboundでのドメイン処理に影響しますが、routingオブジェクトのドメインルールを置き換えるものではありません。コネクション再利用は接続の扱いを変えますが、サーバー認証の誤りを修正する機能ではありません。最適化と接続性を分けて考えると、トラブル時の記録も整理しやすくなります。
リモートoutboundの接続先にドメイン名を使う場合、起動時にその名前を解決する必要があります。プロキシ接続が確立する前にも名前解決できる経路が必要です。そうでないと「プロキシに接続するために、同じプロキシを経由する」という循環が発生することがあります。ローカルでの名前解決、明確なブートストラップDNS、またはサービス提供元の有効なアドレスを利用して循環を解消してください。システムプロキシの切り替えだけを繰り返しても解決しません。
クライアントと設定の役割分担
デスクトップではv2rayNがサーバーやルーティングテンプレートの管理に適しています。AndroidではXray系のv2rayNG、V2Fly系の選択肢としてv2flyNGを利用できます。基本的なoutboundの考え方は共通していても、独自のプロトコル拡張、トランスポート項目、インポート時の動作は個別に確認してください。クライアントは端末のプラットフォームと設定要件から選び、インストール先はダウンロードページで確認できます。クライアント名をコアの設定項目として入力しないでください。
リモート設定を保存する前に、接続先アドレス、ポート、認証、トランスポート、セキュリティを1つのサービス設定と照らし合わせてください。接続後はリクエストが想定したoutboundを通っているか確認しましょう。接続テストの成功だけでは、すべての宛先がそのルールに一致するとは限りません。ローカルの直接接続は成功し、リモートoutboundだけが失敗する場合は、inboundを変更せず、サーバーの名前解決、ハンドシェイク、認証に確認範囲を絞ってください。
routingの照合順と振り分けルール
ルーティングはinboundとoutboundをつなぎます。接続先のドメイン、IPアドレス、ポート、inboundタグなどを確認し、使用するoutboundを選びます。ルールは通常上から順に評価され、最初に一致したルールで行き先が決まります。特定の例外を先に、対象範囲の広いルールを後に置くのが、特定のプリセットを暗記するより確実な方法です。どのルールにも一致しない接続はデフォルトoutboundへ進み、ドメインの地域をもとに自動で経路が決まるわけではありません。
宛先を決めてから条件を書く
outboundTagは、outboundのtagと完全に一致させる必要があります。存在しない名前を参照しても、outboundが自動生成されることはありません。設定チェックで失敗したり、転送時にエラーになったりする可能性があります。ルールのtypeがfieldの場合、条件項目で照合対象を指定します。まず使用できるoutboundを確認してからルールを追加しましょう。そうすれば、条件が一致しないのか、一致後に送信先が見つからないのかを切り分けやすくなります。
{
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": ["full:blocked.example"],
"outboundTag": "block"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
}
]
}
}
このルーティング断片は、前述の直接接続outboundや遮断outboundと組み合わせて使用できます。blocked.exampleは一致構文を示すための予約済みサンプルドメインです。実際にテストする場合は、自分が管理する権限を持つドメインに置き換えてください。geositeとgeoipは外部のルールデータを参照するため、実行環境に対応するデータファイルが必要です。必要なデータセットがない場合、読み込みエラーをネットワーク経路の問題と判断しないでください。
同じフィールド内と異なるフィールド間の論理
同じドメイン配列に複数の項目を指定した場合、通常はいずれか1つに一致すればルールに合致します。一方、1つのルールにドメイン、ポート、ネットワーク種別を併記すると、異なる条件をすべて満たす必要があります。「特定のドメインまたは特定のIP」を同じoutboundに送るには、通常はルールを2つに分けます。ドメインとIPを1つのルールに並べて、論理和として扱われることを期待しないでください。条件の関係を先に整理してからJSONにすると、見た目は整っていても一度も一致しないルールを減らせます。
full:は完全一致、domain:は指定ドメインとそのサブドメイン、regexp:は正規表現で照合します。接頭辞のない文字列は想定より広い範囲に一致する場合があるため、厳密な例外指定には向きません。ルールの対象はホスト名であり、URL全体ではありません。通常、ドメイン条件にhttps://、パス、クエリパラメーターを含めないでください。ルーティングはブラウザーのアドレス欄の全文を照合するものではありません。
ドメイン戦略とIPルール
AsIsは、ルーティングのIP条件に合わせるためだけにドメインを積極的に名前解決しません。アプリからコアにドメイン名が渡された場合、IPルールだけでは期待どおりに一致しないことがあります。IPIfNonMatchはドメイン条件に一致しなかったときに名前解決を試してから再照合し、IPOnDemandはIPが必要なルールとの照合時に名前解決します。どちらも名前解決が行われる機会を増やし、ルール順序の実際の影響も変化させます。
名前解決で複数のIPアドレスが返ることがあり、サービスのアドレスも変わります。IPルールに一致しても、そのIPが常に特定のドメインに対応するとは限りません。共有インフラでは、複数のサービスが同じアドレス範囲を使う場合もあります。意図を安定したドメイン名で表せる場合は、ドメイン条件を優先してください。ローカルネットワークや固定のサービスアドレスを制御する必要がある場合にIP条件を使います。データセットの分類も、証明書やサービスの所有者を確定する証拠ではありません。
{
"type": "field",
"inboundTag": ["local-socks"],
"network": "tcp",
"port": "443",
"outboundTag": "direct"
}
この単独ルールは、指定したSOCKS inboundから入り、宛先ポートが443で、TCPを使う接続を直接接続outboundに送ります。3つの条件がすべて成立した場合に一致するため、そのポートを全体的に許可するルールではありません。ポートが示すのは接続先のポートであり、ローカルの待ち受けポートではありません。配列の前方に置く場合は、後続のドメイン遮断ルールを先回りして上書きしないか確認してください。対象範囲の広いルールほど、順序に注意が必要です。
デフォルトoutboundと検証方法
明示的なフォールバックが必要な場合は、ルールの末尾にTCPとUDPを対象とし、定義済みのデフォルトoutboundを参照するルールを追加できます。その後に同種のルールを置いても通常は使われないため、フォールバックは最後に確認してください。最初のoutboundをデフォルトにする場合も、後から並べ替えて動作が変わらないよう、設定メモに明記しておきましょう。クライアントの「グローバルプロキシ」モードと、OSが全アプリの通信を取り込むかどうかは別の話です。前者は主に経路選択の設定を表します。
ルールが適用されない場合は、アプリから渡される宛先がドメイン名かIPか、先行するルールに一致していないか、タグが一致しているか、データファイルを読み込めるかを順に確認します。変更後はコアに該当する設定を再読み込みさせてください。既存の長時間接続には、変更前の経路が使われ続ける場合があります。テスト時は古い接続を閉じて新しいリクエストを送り、接続の再利用による動作をルール未反映と取り違えないようにしましょう。
DNSとルーティングの連携
DNSはドメイン名をIPアドレスに変換しますが、プロキシ経路では名前解決を行う主体が1つとは限りません。アプリがプロキシに渡す前に解決する場合、コアがルーティングや直接接続outboundのために解決する場合、リモートサーバーが最終的な宛先を解決する場合があります。dnsオブジェクトを設定しても、コア用のリゾルバーが定義されたことを示すだけで、端末上のすべてのDNS問い合わせがそこを通るとは限りません。まずどのレイヤーで名前解決が発生しているか確認してから設定を変更してください。
コアDNSの基本構造
serversではコアが利用できるDNSサーバーを指定し、hostsでは特定ドメインの静的な対応付けを設定できます。以下では、ループバック用ドメインの割り当てとサンプルDNSサーバーのアドレスで構造を示します。OSのDNSを横取りするinboundは含まれておらず、アプリ側の名前解決設定も変更しません。DNSサーバーを置き換える場合は、現在のネットワークから接続できるか、利用環境の管理方針に沿っているかを確認してください。一般的に見えるアドレスだからという理由だけで使わないようにしましょう。
{
"dns": {
"hosts": {
"loopback.example": "127.0.0.1"
},
"servers": [
"1.1.1.1"
]
}
}
ここでの静的な割り当ては、コアの名前解決処理を確認するためのもので、OSのhostsファイルを変更するものではありません。コアDNSを使うリクエストだけが影響を受けます。別の方法でブラウザーが取得したIPアドレスを、後からこの設定で置き換えることはできません。運用環境で静的な割り当てを使う場合も、継続的な管理が必要です。サービス移行後には古いアドレスが使えなくなる可能性があります。サービス提供元が明示的に指定していない限り、変化するサービスのドメイン名を固定IPで長期的に置き換えないでください。
ドメイン別の名前解決とフォールバック
対応フィールドがあるコアでは、サーバーオブジェクトのdomainsで優先的に照合するドメイン範囲を指定し、expectIPsで応答IPアドレスの範囲を判定できます。前者は問い合わせの対象を絞り、後者は応答を検査します。どちらもroutingルールではありません。DNSでリゾルバーを選んだ後、実際の通信経路はoutboundとルーティングで決まります。DNSサーバーの振り分けを、接続の振り分けと混同しないでください。
{
"dns": {
"servers": [
{
"address": "223.5.5.5",
"domains": ["geosite:cn"],
"expectIPs": ["geoip:cn"]
},
"1.1.1.1"
]
}
}
この例は利用可能なルールデータセットを必要とし、優先して照合するリゾルバーと通常のリゾルバーを併用する構成を示します。実際のフォールバック動作は、コアがサポートするフォールバック設定にも左右されます。配列の順序を常に直列のプライマリー/セカンダリーキューとして解釈しないでください。特定の問い合わせが他のサーバーに送られないようにしたい場合は、該当バージョンのフォールバック設定を確認しましょう。設定後は、一致するドメインと一致しないドメインを個別にテストしてください。
DNS問い合わせ自体の経路
通常のUDPによる名前解決、HTTPS経由の名前解決、ローカルネットワークスタックを使う方式では、実際のoutboundが異なる場合があります。コア内で転送されるアドレス形式がある一方、ローカルモードでは通常のルーティング処理を通らない場合もあります。DNSサーバーURLの形式は実際に使うコアのドキュメントに従ってください。一般的なアドレスに接頭辞を付けただけでプロキシ経由になると考えてはいけません。特に、暗号化されたDNS接続を確立する際、DNSサーバーのホスト名を先にどう解決するか確認が必要です。
リモートoutboundのドメイン名とリモートDNSサーバーのドメイン名が互いに依存すると、起動時のループが発生しやすくなります。初回接続だけ失敗する、ネットワーク切り替え後に長時間待たされる、キャッシュがある間は動くのに再起動後は失敗するといった症状が出ます。プロキシ接続前に使えるブートストラップの名前解決経路を用意し、どの基本ドメインに使うかを明確にしてください。一度のタイムアウトを避けるために、すべてのDNSサーバーとoutboundを、まだ確立していない同じ経路に結び付けないようにしましょう。
IPv4・IPv6とキャッシュの違い
DNSでIPv6アドレスが取得できても、端末から宛先までIPv6で接続できるとは限りません。同様に、IPv6を無効にすることがあらゆるタイムアウトの解決策でもありません。ローカルネットワーク、リモートサービス、outboundが対応するアドレスファミリーを確認してから、DNS応答を制限するか決めてください。コアの問い合わせ方針を指定する項目は、コアの系統によって差があります。対応範囲を確認し、認識されない項目でネットワーク方針を記述しないようにしましょう。
アプリ、OS、コア、再帰リゾルバーのキャッシュが同時に存在する場合があります。DNS変更後にページを再読み込みしても動作が変わらないからといって、設定が反映されていないとは限りません。まずアプリの接続を作り直し、必要に応じて該当するレイヤーのキャッシュを消して、新しい問い合わせを確認してください。検証には管理可能なドメインを使うか、問い合わせ時刻を記録しましょう。大規模サイトのIPアドレスが変わったかどうかだけで、DNSサーバーの切り替えを判断しないでください。
Webページの表示が遅いのにログに明確な名前解決エラーがない場合は、初回アクセスと連続アクセスを分けて比較してください。初回だけ遅い場合は名前解決やハンドシェイクが原因かもしれません。継続的にダウンロードが遅い場合は、回線、負荷、ローカル処理が関係している可能性があります。さらに調べるには通信速度が遅いときの段階的な切り分け方法を参照してください。DNS、ノード、ルーティングを同時に変更すると、どれが影響したか判断できなくなります。
policy(接続ポリシー)、ログ、統計
policyは接続の動作や統計機能を管理する設定で、ドメイン振り分け用の別ルール表ではありません。ユーザーレベルごとのハンドシェイク待機時間やアイドルタイムアウトを設定したり、システム全体の通信統計を制御したりできます。ルーティングは経路を決め、policyは接続の管理方法を決めます。両者を混同すると、経路の問題に対してタイムアウトを何度も変更しても、原因にたどり着けないことがあります。
ユーザーレベルとタイムアウトの関係
levelsのキーにはレベル番号を文字列で指定します。このレベルは、対応プロトコルで設定したユーザーに関連付けられます。inboundにユーザーが明示されていない場合や、プロトコルがレベルに対応していない場合は、任意のレベル設定が影響すると考えてはいけません。まずデフォルトレベルを確認し、接続の動作を観察してください。レベル番号は優先順位や帯域幅のランクではなく、通信を自動的に高速なoutboundへ振り分けるものでもありません。
{
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300,
"uplinkOnly": 2,
"downlinkOnly": 5
}
},
"system": {
"statsInboundUplink": true,
"statsInboundDownlink": true,
"statsOutboundUplink": true,
"statsOutboundDownlink": true
}
},
"stats": {}
}
ここに示す時間項目の単位は秒です。構造を説明する例であり、すべてのネットワークに適した最適値ではありません。handshakeはハンドシェイクの待ち時間、connIdleは通信がない状態のタイムアウトを制御します。残り2項目は、一方向の通信終了後に反対方向を待つ時間に関係します。通信が長時間ない接続がタイムアウトするのは、想定どおりの場合もあります。値を際限なく大きくしても接続できなくなった経路が復旧するわけではなく、切断処理が遅れるだけです。
長時間維持する必要がある接続では、まずアプリにハートビート機能があるか、サーバーが接続を維持できるか、ネットワーク機器がアイドル接続を切断しないか確認してください。コアのアイドル時間を調整しても、中継機器の制限は変わりません。反対に、時間を短くしすぎると、正常な低頻度リクエストでも頻繁に再接続することがあります。切断までの時間とログを記録し、どのレイヤーが切断したか判断してください。すべての切断をクライアントの電池消費やバックグラウンド動作の問題と決めつけないようにしましょう。
統計の有効化と統計画面は別
この例には統計オブジェクトとシステム統計の有効化設定が含まれていますが、アクセス可能なグラフや管理画面が自動で作られるわけではありません。統計の取得には対応するAPIとクライアントが必要で、カウンターによってはinbound、outboundのタグやユーザーIDも必要です。画面の数値が更新されない場合は、ルーティング項目を増やす前に、クライアントが実際にそのコアの統計を読み取っているか確認してください。統計は処理量を示すもので、リモート側のリクエストが失敗する理由を直接説明するものではありません。
管理用APIを独自に設定する場合は、待ち受けを信頼できるローカル範囲に限定し、APIルーティングと権限の境界を理解してください。ツールから読み取りやすくするためだけに、管理用の入口をすべてのネットワークインターフェースにバインドしてはいけません。一般的なデスクトップユーザーは、まずクライアントに備わっている統計機能を使いましょう。独立した設定には、本当に必要な項目だけを残すことで、不要な待ち受けや保守の手間を減らせます。
ログレベルとトラブルシューティング
{
"log": {
"loglevel": "info"
}
}
これは接続を一時的に観察するためのログ設定例です。普段は必要最低限のログレベルにし、調査中だけ情報量を増やして、再現後は元に戻してください。アクセスログ、エラーログ、ログの詳細度はそれぞれ別の設定です。ファイルパスを指定していない場合は、クライアントがコアの出力をどう取得するかも確認しましょう。ファイルに書き込む場合は書き込み可能なディレクトリを選び、ファイルサイズも管理してください。どのプラットフォームでもアプリのインストール先に書き込めるとは限りません。
ログは時刻順に追い、設定の読み込み、inboundの待ち受け、リクエストの受信、outboundの選択、接続が終了した段階をつなげて確認します。「タイムアウト」という1行だけでは原因を特定できず、その前の名前解決失敗やハンドシェイクエラーが根本原因の場合もあります。ログを共有する前に、サーバーの認証情報、サブスクリプションURL、個人的なアクセス先を削除してください。エラーの種類、発生段階、必要最低限の匿名化したタグを残せば十分です。
policy変更の検証範囲
コネクション再利用、キャッシュ、既存接続があると、policy変更の効果がすぐ現れない場合があります。タイムアウトを変更しても、アプリがすでに確立した接続には反映されないことがあるため、対象の接続を作り直してからテストしてください。同じ宛先と操作で検証し、アイドル時間と再接続の状況を記録します。サーバー負荷の変化をpolicyの効果と混同しないようにしましょう。再現可能な差がある変更だけを長期設定として残してください。
Androidのバックグラウンド動作やバッテリー最適化はOSのスケジューリングにも左右されるため、connIdleを大きくしても解決しません。v2rayNGがシステムに停止されると、コアの設定だけでは動作を続けられません。まずアプリのバッテリー権限と動作モードを確認してください。詳しくはv2rayNGのバッテリー消費とバックグラウンド動作のトラブル対処をご覧ください。OS側とコア側を分けて検証すれば、実際の改善がないままタイムアウトを延ばし、電池消費だけ増やす事態を避けられます。
トランスポート設定とTLSのセキュリティ層
同じプロキシプロトコルでも異なるトランスポート上で動作し、同じトランスポートで複数のプロトコルを扱うこともできます。設定は内側から、プロキシプロトコル、トランスポート方式、セキュリティ層に分けて考えると理解しやすくなります。プロトコルはユーザー認証とリクエストの意味を扱い、トランスポートはサーバーへのデータの届け方、セキュリティ層は対象接続の暗号化と認証を担います。ある層が正しくても、他の層の設定が自動で補われるわけではありません。
streamSettingsの配置
streamSettingsは通常、個々のoutboundオブジェクト内でprotocol、settingsと同じ階層に置きます。プロトコルのユーザーオブジェクト内や、任意のトップレベルに配置するものではありません。以下はWebSocketとTLSのトランスポート断片のみを示しており、実際のサービスから提供されたoutbound設定と組み合わせる必要があります。ドメイン名は予約済みのサンプルを使い、パスは構文を説明するためのもので、接続できるリモートサービスを示すものではありません。
{
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "gateway.example",
"allowInsecure": false
},
"wsSettings": {
"path": "/transport",
"headers": {
"Host": "gateway.example"
}
}
}
}
サーバーへの接続アドレスはこの断片には含まれず、outboundプロトコルのサーバー設定で指定します。serverNameはTLSのサーバー名や証明書検証に関する処理に使い、WebSocketのHostはアプリケーション層で接続先ホストを選択するために使います。環境によっては同じ値ですが、異なる役割を持つ構成もあります。どちらもドメイン名に見えるからといって、サーバー側の説明なしに入れ替えないでください。
パス、ホスト名、証明書
WebSocketのパスはサーバー側の受け付け先と一致させる必要があります。先頭のスラッシュ、大文字・小文字、追加の文字列も照合結果に影響する場合があります。パスが誤っていても、サーバーが通常のWebページや別のHTTP応答を返すことはありますが、プロキシのハンドシェイクは成立していません。サーバーのトップページを開けても、トランスポートの接続先が正しいとは限りません。ブラウザーからドメインにアクセスできるかだけでなく、アップグレードハンドシェイクとコアのエラーを確認してください。
証明書の検証に失敗した場合は、端末の時刻、証明書に含まれるドメイン名、信頼チェーン、実際に接続したサービスを確認してください。allowInsecureで検証を無効にするとセキュリティ境界が変わるため、証明書エラーの恒久的な対処として使ってはいけません。IPアドレスで接続し、サービスの証明書がドメイン名に対して発行されている場合は、サービス設定に従って正しいサーバー名を指定します。証明書検証とプロキシのユーザー認証は別の仕組みです。ユーザーIDを変えてもドメイン名の不一致は解消しません。
トランスポート項目を別の種類に流用しない
トランスポートを切り替える際、networkだけを変更すればよいわけではありません。WebSocketのパス、gRPCのサービス名、その他のトランスポートのパラメーターは、それぞれ異なる設定オブジェクトに属し、サーバー側の設定と一致させる必要があります。無関係な項目を残すと、無視される場合もあれば、読み込みやハンドシェイクに失敗する場合もあります。実際に使用するトランスポートの設定だけを残し、サーバーから提供された値を1つずつ対応させましょう。複数の共有リンクの内容を混ぜないでください。
基本的なTCP、WebSocket、gRPCなどは、リソース使用量、接続管理、導入条件がそれぞれ異なります。サーバー側の条件に関係なく最速になる方式はありません。クライアントで方式を選んでも、サーバーに対応する接続先がなければ接続できません。調整では、まず利用可能なトランスポートを変えずに、同じネットワークでの実際の動作を比較してください。方式名だけを速度の保証と考えないようにしましょう。
| 項目・概念 | 主な役割 | 確認する設定元 |
|---|---|---|
| サーバーアドレス | 実際の接続先を指定 | outboundのサーバー設定 |
| TLS serverName | サーバー名と証明書の照合 | セキュリティ層の設定 |
| WebSocketのHostとpath | アプリケーション層の接続先を選択 | サーバー側のトランスポート設定 |
| gRPC serviceName | 対応するサービスを選択 | クライアントとサーバーで合意したサービス名 |
コアの系統と拡張機能
V2FlyとXrayは関連するプロキシコアの系統ですが、設定できる機能はそれぞれ独自に進化しています。REALITYなど独自のセキュリティ機能は、実際に対応するコアを使い、その仕様に沿って設定してください。この節のTLS例で項目名だけを置き換えても動作しません。JSONの見た目が似ていても、パラメーターに互換性があるとは限りません。共有リンクをインポートした後も、クライアントがノードの要件に合ったコアを使っているか確認してください。
コネクション再利用も、プロトコルとサーバー側の条件を考慮する必要があります。有効にすると新規接続の一部コストを抑えられる場合がありますが、経路や用途によって動作が異なることもあります。特定の長時間接続に問題がある場合は、他の項目を変えず、まずコネクション再利用を追加しない基準設定に戻して比較してください。再利用、トランスポート、TLS、DNSを一度に変更すると、変更が多すぎて一度だけ成功した状態を再現できなくなります。
ローカルinboundが正常で、サーバーポートにも到達できるのに、ログがTLSまたはトランスポートのハンドシェイクで止まる場合は、ルーティングとpolicyの調整をいったん止めてください。システム時刻、サーバー名、パス、サービス名、認証情報が同じ設定に基づいているか確認し、中間のリバースプロキシの接続先マッピングも調べます。層ごとに確認すれば、サブスクリプションを何度もインポートするより有効な手がかりを保ちやすく、正常なルールまで上書きすることもありません。
設定の統合、テスト、問題発生時の復旧
設定管理で大切なのは、項目を一度に多く集めることではなく、変更の理由を説明し、検証して、元に戻せる状態にすることです。開始前に現在のクライアント、実際に動作するコア、設定の取得元、デフォルトoutboundを確認し、正常に動く基準設定を保存してください。基準にはJSONだけでなく、クライアントのモードやシステムプロキシの状態も含まれます。ファイルだけを残して外部の切り替え設定を忘れると、復旧後の結果が異なる場合があります。
依存関係に沿って設定断片を統合
まず起動できるinboundと直接接続outboundを用意し、次にリモートoutbound、宛先を1つだけ対象とするルーティング、最後にDNSとpolicyを追加します。この順序は機能上の制限ではなく、トラブルシューティングに必要な依存関係に基づいています。入口が動かなければ出口を検証できず、出口がなければルールを検証できません。基本接続が失敗している段階でタイムアウトを最適化しても意味がありません。各段階の成功を記録してから次へ進めば、問題発生時に戻る場所が明確になります。
配列を統合する場合は要素を追加し、オブジェクトを統合する場合はキーを1つずつ照合してください。設定断片をファイルの末尾にそのまま貼り付けないでください。特にrouting、dns、logフィールドの重複や、同じタグ名の複数定義に注意が必要です。テンプレートツールが一部のフィールドを自動生成する場合は、オブジェクト全体を置き換えるのか、配列に要素だけ追加するのか確認してください。見た目上すべての内容が残っていることより、統合方法を理解することが重要です。
起動前後の確認
まずローカルエディターでJSON構文を確認し、次に実際に動作するコアで設定構造を検証します。構文が正しくても項目がサポートされているとは限らず、コアが読み込めてもリモートサーバーに接続できるとは限りません。エラーはレイヤーごとに確認してください。解析エラーなら引用符やカンマ、不明なフィールドならコアの対応状況、待ち受け失敗ならローカルポート、ハンドシェイク失敗ならリモート設定を確認します。読み込みに成功していないファイルの問題をネットワークテストで覆い隠さないようにしましょう。
| 段階 | 検証方法 | 失敗時に最初に確認する項目 |
|---|---|---|
| 設定の読み込み | コアの起動ログを確認 | JSONの階層、項目の対応状況、データファイル |
| ローカル接続 | アプリでローカルプロキシを明示 | 待ち受けアドレス、ポート、inboundプロトコル |
| リモート接続 | 固定のテスト宛先を使用 | 名前解決、認証、トランスポート、セキュリティ層 |
| ルールによる経路選択 | リクエストに対応するoutboundを確認 | 照合条件、ルール順序、タグ |
テストツールではプロキシを明示して指定し、システムプロキシの状態による混乱を避けてください。以下のリクエストは、ローカルSOCKS入口でHTTPS宛ての接続を処理できるか確認するものです。socks5hはドメイン名の処理をSOCKS側に渡すことを示します。結果は選択したoutboundとネットワークに左右され、遅延の評価や、すべてのアプリがプロキシに接続されていることの証明にはなりません。Windowsでは実行ファイル名を明示すると、ターミナル環境で同名のエイリアスが使われることによる違いを避けられます。
curl.exe --proxy socks5h://127.0.0.1:10808 --head https://example.com
curl --proxy http://127.0.0.1:10809 --head https://example.com
クライアントによる設定再生成とサブスクリプション更新
v2rayNでは、サーバーやルーティングプリセットの切り替え、コアの再起動によって実行設定が再生成されることがあります。手動変更がすぐ消える場合は、一時的な出力ファイルを編集し続けるのではなく、変更を保持できる設定箇所を探してください。初回のインストール先、書き込み権限、起動設定はv2rayNの初回インストール設定チェックリストで確認できます。接続の基本手順はクイックスタートガイドに戻って見直してください。
サブスクリプションを更新すると、サーバー項目、ノード名、利用可能なパラメーターが変わる場合もあります。頻繁に変わる項目名を前提とするカスタムルールでは、クライアントが実行時のタグにどう対応付けるか確認してください。画面上の表示名が常にoutboundタグと同じとは限りません。複数のソースの管理方法はサブスクリプショングループとフィルターの設定方法をご覧ください。更新前後の構造の差分を残すと、「更新後に動かなくなった」と記録するだけより原因を特定しやすくなります。
よくある質問と復旧手順
設定は起動するのに、アプリが直接接続するのはなぜ?
まずアプリがシステムプロキシに従っているか、現在のinboundを明示的に使っているか確認してください。次にデフォルトoutboundとルールの照合結果を確認します。コアのプロセスが動作していることは、プログラムの起動を示すだけで、アプリのリクエストがコアを通った証明にはなりません。
ルール変更後も、既存の接続が以前の経路を使うのはなぜ?
すでに確立している接続は、ルールが変わっても通常は自動で移行しません。対象アプリの既存接続を閉じて新しいリクエストを送り、ログを確認してください。必要に応じてコアの設定を再読み込みし、クライアントが変更内容を上書きしていないかも確認しましょう。
接続が突然失敗したとき、どの設定から戻す?
直近に正常動作していたコア設定とクライアントのモードに戻し、inboundを1つ、宛先を1つに絞って検証してください。失敗時のログを残し、変更を1つずつ再適用します。基準設定でも失敗する場合は、ネットワーク、サーバーの状態、サブスクリプションの設定に変更がないか確認してください。
最終的な検証記録では、リクエストがどのinboundから入り、宛先がドメイン名かIPアドレスのどちらで表され、どのルールに一致し、どのoutboundで接続したかを確認できるようにします。「使える」だけでは振り分けの正しさを証明できず、「タイムアウト」だけでは障害の段階も判断できません。成功時と失敗時の接続経路を記録して比較すると、設定ファイル全体を書き直さなくても、問題のある項目を絞り込めます。
メンテナンス後は適切なログレベルに戻し、不要になったテストinboundや一時的な静的割り当てを削除して、長期的に使う設定をクライアントが認識する場所に保存してください。プリセットを積み重ねるより、簡潔で意味の分かるルールを保つほうが管理しやすくなります。接続手順だけを確認したい場合はガイドを参照してください。項目の意味、依存関係、設定の統合方法を確認したい場合は、このページの目次から該当する節に戻れます。