JSON構造の概要
設定ファイルが記述するのは、コアが接続をどう処理するかであり、クライアント画面のすべての設定を保存したものではありません。データの流れに沿って読むと理解しやすくなります。アプリからinboundに接続が入り、ルーティングが宛先や接続元に応じてoutboundを選び、outboundが宛先へ直接接続するか、リモートサーバーへ接続します。DNSは名前解決が必要な場面で結果を提供し、policyは接続のタイムアウトや統計を管理します。各オブジェクトはタグやユーザーレベルなどの値で関連付けられているため、一部分だけでは全体の動作を判断できないことがあります。
クライアントの設定と実行時の設定を区別する
v2rayNが保存するサブスクリプションのグループ、画面の設定、更新設定などは、必ずしもコアのJSON設定に含まれるわけではありません。クライアントは通常、選択中のサーバーやルーティングテンプレート、各種設定から実行用の設定を生成し、再接続時に再生成することがあります。生成ファイルを直接編集すると、次にサーバーを切り替えた際に変更が上書きされる可能性があります。まず設定の変更元を確認してください。一般的なポートやルーティングの設定は画面から変更し、独自の設定が必要な場合は、クライアントが提供するインポート機能やカスタム設定の入口を使いましょう。
このページでは、一般的なオブジェクト形式のV2Ray JSONを基準に説明し、異なるコアの拡張項目を同一の仕様として扱いません。v2rayNGはXrayコア、v2flyNGはV2Flyコアを使用します。v2rayNで利用できる機能は、選択中のコアによって異なります。同じ項目名でも指定できる値が異なる場合があり、新しいトランスポートが別のコアでは使えないこともあります。未知の項目が見つかった場合は、エラー箇所の近くを手当たり次第に削除するのではなく、まず実行中のコアと設定形式を確認してください。
起動できるローカル直結の基本設定
以下の設定例では、ローカル端末からのみ接続できる2つの入口を作り、デフォルトでは宛先へ直接接続し、拒否用outboundも用意します。構造の理解とローカル経路の確認を目的としており、リモートのプロキシサーバーは含まず、システムプロキシも自動では変更しません。一般的なUTF-8テキストとして保存し、対応するコアのカスタム設定機能から実行してください。クライアントがすでに同じポートを使用している場合は、既存のプロセスを停止するか、この例とテストするアプリのポートを両方変更してください。
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
}
},
{
"tag": "http-in",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": []
}
}
JSONではオブジェクトに波括弧、配列に角括弧を使い、キー名と文字列は二重引用符で囲みます。ポート番号などの数値は引用符で囲まず、真偽値は小文字のtrueまたはfalseで記述します。このページの例にはコメントや末尾のカンマがなく、厳密なJSONパーサーでも読み込めます。特定の読み込み方法でコメントが許可されていても、すべてのクライアントのインポート機能が同じ構文を受け付けるとは限りません。
空のオブジェクトとオブジェクトの省略は、常に同じ意味になるとは限りません。プロトコルによってはsettingsを空にできますが、サーバーやユーザーの一覧が必要なものもあります。項目名の大文字・小文字も正確に記述してください。たとえばoutboundTagは、自由に付けられる説明用の名前ではありません。一方、directやsocks-inはこの例で定義したタグなので変更できますが、参照している箇所もすべて同時に変更し、重複を避けてください。
任意のオブジェクトをすべて埋める必要はありません。設定が完全であることは、項目が多いことを意味しません。記述した項目それぞれに明確な目的があることが大切です。確認を始める前に、現在の入口プロトコル、ポート、デフォルトoutbound、想定するルーティング動作をメモしておきましょう。以降の設定をこの4点に沿って確認すると、別の場所から設定を丸ごとコピーした結果、どのルールが有効なのか分からなくなる事態を減らせます。
inbounds(受信):アプリからの接続入口
inboundsは接続を受け付ける入口の配列です。各入口では、待ち受けアドレス、ポート、プロトコルを指定し、プロトコルに応じた設定を用意する必要があります。アプリが実際にこの入口へ接続して初めて、コアが通信を処理できます。クライアントが起動中でも、ブラウザーやターミナルなどのアプリがすべて接続済みとは限りません。トラブル対処では、ルーティングルールを変更する前に「アプリはどこへ接続しているか」を確認しましょう。
listen、port、プロトコルをまとめて確認する
listenに127.0.0.1を指定すると、ローカルのループバック接続だけを受け付けます。0.0.0.0はすべてのIPv4インターフェースで待ち受けるため、接続可能な範囲が大きく広がります。ポートは入口がローカルで実際に使用する番号であり、リモートサーバーのポートではありません。このページではSOCKSを10808、HTTPを10809で別々に待ち受ける例を使います。クライアントによっては、混合型の入口や別のポートを使うこともあります。実際の設定を確認し、よく使われる番号だけでプロトコルを判断しないでください。
HTTPプロキシの設定はHTTPの入口に、SOCKSの設定はSOCKSの入口に向けます。ブラウザーのHTTPプロキシにSOCKS専用ポートを指定しても、通常は正しいセッションを確立できません。HTTPSサイトへはHTTPプロキシのCONNECTトンネルを使って接続できますが、ローカルプロキシのアドレスをHTTPSに変更する必要はありません。アプリ設定の「セキュアプロキシ」という表記は、ローカル入口でTLSを有効にしているという意味ではなく、宛先への通信方式を示している場合があります。
| 項目 | 役割 | 確認ポイント |
|---|---|---|
tag | 入口を識別する名前 | ルーティングのinboundTagと一致するか |
listen | 待ち受けるローカルアドレス | ローカル端末だけに限定されているか |
port | 待ち受けポート | 使用中でないか、アプリの指定が正しいか |
protocol | 入口のプロトコル | SOCKSとHTTPを混同しない |
settings | プロトコル固有のパラメーター | 認証やUDPなどのオプション |
UDPとトラフィックのスニッフィング
SOCKS入口のudp: trueは、対応するUDP転送を有効にしますが、全体に適用されるUDPスイッチではありません。アプリが互換性のあるSOCKS UDP方式を使い、リモートプロトコル、サーバー、ネットワーク経路も対応している必要があります。TCPのリクエストが正常でも、UDPが使えるとは限りません。従来型のHTTPプロキシ入口は、あらゆるUDPアプリの代替にはなりません。ゲームやリアルタイム通信アプリでは、接続方法を個別に確認してください。
sniffingを使うと、一部のアプリケーション層のハンドシェイク情報から宛先ドメインを識別し、IPアドレスしかない接続をドメインルーティングの対象にできる場合があります。これは復号機能ではなく、暗号化された通信すべてからドメインを取得できるわけでもありません。以下の設定では、識別した情報をルーティングの判定だけに使います。routeOnlyが使えるかどうかは、実際のコアで確認してください。この項目に対応していない場合、単純に削除して同じ動作になると考えず、宛先の書き換えが許可されるかを改めて確認しましょう。
{
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"],
"routeOnly": true
}
}
この設定は、いずれかのinboundオブジェクト内でprotocolと同じ階層に追加します。プロトコルのsettingsの中ではありません。設定ツリーの階層を誤ると、読み込み時に起動を拒否されたり、認識できない内容が無視されたりすることがあります。JSONとして解析できるだけでは不十分です。コアが構造を受け入れたことと、対象ドメインのルールが実際に適用されたことも確認してください。
LANで共有する場合はアクセス制御が必要
別の端末からプロキシを利用する場合、クライアントの「LANからの接続を許可」設定によって待ち受け範囲が変わることがあります。また、OSのファイアウォールも影響します。接続先にはプロキシを動かしている端末のLANアドレスを指定してください。接続する側の端末自身のループバックアドレスではありません。アクセス元を制限し、必要に応じて認証を設定しましょう。待ち受けアドレスをすべてのインターフェースに変更しただけで、不特定のネットワークに入口を公開しないでください。
Android版のv2rayNGとv2flyNGでは、OSのVPNインターフェースやアプリごとの接続設定も関係します。アプリがこのインターフェースを通るかどうかは、JSONにSOCKS入口があるかどうかとは別の問題です。デスクトップのシステムプロキシ、アプリごとのプロキシ、Androidのアプリ別ルールは分けて確認してください。権限やバックグラウンド動作については、AndroidのVpnServiceとアプリ別プロキシ設定もご覧ください。
outbounds(送信):プロトコルとデフォルト経路
outboundsは接続を処理する出口の一覧です。outboundには、宛先へ直接接続するもの、リモートプロキシサーバーへ接続するもの、通信を拒否するものがあります。protocolはその出口でコアが使用するプロトコルを示し、アプリが最初に使った入口のプロトコルを示すものではありません。同じSOCKS inboundからの接続でも、ルーティング結果に応じて異なるoutboundへ渡せます。入口と出口は一対一で対応する必要はありません。
デフォルトoutboundとタグの参照
一般的なオブジェクト形式の設定では、ルーティングルールに一致しない接続は、先頭のoutboundを使用します。そのため、配列の順序も実際の動作に影響します。冒頭の設定例ではdirectを先頭に置いているため、ルールに一致しない接続はすべて直接接続されます。リモートプロキシを使う設定で、一致しない通信もプロキシ経由にしたい場合は、デフォルトの出口を明示的に設定してください。タグがproxyという名前だから自動的にデフォルトになるわけではありません。タグ名自体に特別な意味はありません。
tagはルーティングからoutboundを参照するための名前です。ルール内のoutboundTagは、定義済みのタグと大文字・小文字も含めて正確に一致させてください。見分けやすい短い名前を使い、重複を避けるのがおすすめです。ノード名、サブスクリプションのグループ名、outboundのタグは別のものです。クライアント画面の名前は変換されることがあり、実行設定にそのまま反映されるとは限りません。トラブル対処では実際に生成された設定を確認してください。
{
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {
"response": {
"type": "none"
}
}
}
]
}
freedomはローカル端末のネットワークから宛先へ直接接続します。コアを経由せずに接続するという意味ではありません。接続はコアのDNS設定、outboundの設定、OSのネットワーク状態の影響を受けることがあります。blackholeは指定された通信を破棄または拒否するために使い、明示的な遮断先として設定できます。拒否後、アプリがすぐにエラーを表示する場合もあれば、再試行を続けてタイムアウトする場合もあります。読み込み画面が続くからといって、ただちにリモート接続の障害とは限りません。
リモートプロトコルごとに異なるsettings
プロキシプロトコルによってサーバー情報や認証情報の構造は異なります。VMessやVLESSのユーザー情報は、Trojanのパスワード項目とは異なります。Shadowsocksでは、双方で同じ暗号化方式を使う必要があります。共有リンクには通常、リモートアドレス、ポート、認証、トランスポートの情報が含まれているため、インポート後は一式を確認してください。アドレスだけを差し替えて別の接続のトランスポートや認証設定を流用すると、構文上は正しくても接続できないことがあります。
リモートサーバーのアドレスは「どのサーバーへ接続するか」を示し、リクエストの宛先アドレスは「最終的にどこへアクセスするか」を示します。両者は異なる階層です。ローカルの待ち受けポート、リモートサーバーのポート、接続先サイトのポートも分けて記録しましょう。アプリからローカルポートに接続できても、確認できたのは最初の区間だけです。リモートポートへの接続不可、認証情報の不一致、TLSの失敗などがあれば、最終的なアクセスは失敗します。ログに表示されたアドレスが、どの区間のものかを先に見極めてください。
| オブジェクトまたは項目 | 担当する内容 | これだけでは判断できないこと |
|---|---|---|
protocol | outboundのプロキシプロトコル | トランスポートや証明書が正しいか |
settings | サーバーやユーザーなどのプロトコル設定 | ローカルアプリがプロキシに接続しているか |
streamSettings | トランスポートと接続のセキュリティ | ルーティングでこのoutboundが選択されたか |
tag | ルールから参照する識別子 | デフォルトの出口や動作状態 |
まずoutboundを一つ検証してから選択ロジックを追加する
outboundを複数追加する前に、同じテストリクエストで一つの出口を検証してください。直接接続できる経路を一つ残しておくと、宛先自体に接続できないのか、プロキシ経路に問題があるのかを区別しやすくなります。完全なカスタム設定では、クライアント画面で「現在のサーバー」を選んでもoutbound一覧が書き換わらない場合があります。画面上の選択を変更した後は、設定の生成元を確認してください。すべてのカスタム設定でクライアントの自動選択機能が働くとは限りません。
多重化、チェーン接続、負荷分散は、接続失敗時にまず試す対処法ではなく、動作をさらに制御するための機能です。同時接続や依存関係が増え、診断も難しくなります。入口、ルーティング、単一のリモート接続が動作することを確認してから、必要に応じて追加してください。プロトコルの違いが分かりにくい場合は、先に4種類のプロキシプロトコルの違いを読み、該当するプロトコルの設定項目を確認しましょう。
トランスポートとセキュリティ:streamSettingsの階層
プロキシプロトコルとトランスポート方式は、別の階層で設定します。プロトコルはセッションと認証を扱い、トランスポートはデータをネットワーク上でどう伝送するかを定めます。さらに接続セキュリティで、TLSなどを使うかどうか、その方法を指定します。同じプロトコルでも異なるトランスポートを組み合わせられますが、サーバーと使用中のコアの両方が対応している組み合わせでなければ動作しません。共有リンクをインポートしたら、プロトコル、トランスポート、セキュリティ方式をまとめて確認してください。プロトコル名が同じというだけで互換性があるとは限りません。
networkとsecurityの役割
streamSettingsは通常、outboundのsettingsと同じ階層に置きます。networkでは基盤となるトランスポートの種類を指定し、securityではその層で使う接続セキュリティ方式を指定します。トランスポート固有のオブジェクトには、パス、リクエストヘッダー、サービス名などを設定します。項目名や使用できる値はコアの機能によって異なります。あるコアで使える新しいトランスポートの項目を、別のコアでも使える共通の書き方だと考えないでください。
以下はTLS設定の構造例です。オブジェクトの配置と証明書名の項目を示していますが、リモートoutbound全体の設定ではありません。例にはドキュメント用に予約されたドメインを使っています。実際にはサーバー側から指定された名前を使用してください。この例でサブスクリプション内のトランスポート設定全体を置き換えたり、TLSを有効にすれば任意のリモートポートとハンドシェイクできると考えたりしないでください。
{
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "example.com",
"allowInsecure": false
}
}
}
serverNameは、TLSのサーバー名表示と関連する証明書名の検証に使います。基盤となる接続先のサーバーアドレスと同じとは限りません。接続先をIPアドレスにし、証明書とはドメイン名で照合する構成も可能です。逆に、サーバーアドレスをドメイン名に変えただけでは、アプリケーション層のリクエストヘッダー、トランスポートのパス、TLS名がすべて正しくなるとは限りません。各項目をサーバー側の指定と個別に照合し、一つの項目で複数の名前を代用しないでください。
パス、リクエストヘッダー、証明書の確認
WebSocketを使う場合、パスはトランスポートの取り決めに含まれるため、サーバーまたは前段の転送設定と一致させる必要があります。スラッシュ、大文字・小文字、追加パラメーターも一致判定に影響することがあります。リクエストヘッダーのHostとTLS名は同じ場合も、特定の構成では異なる場合もあります。推測で入力しないでください。TLS接続の成功で確認できるのはセキュア接続の段階までです。その後のWebSocketアップグレードやプロキシプロトコルの認証まで成功したとは限りません。
gRPCのサービス名も、サーバー側で定められた設定の一部です。画面に表示されるメモではありません。トランスポート名が正しく見えても、サービス名、パスの転送、中間ネットワーク機器の制限などが原因で失敗することがあります。TCP接続、TLSハンドシェイク、トランスポートのハンドシェイク、プロトコル認証のどの段階で失敗しているかを特定しましょう。各段階は前の段階に依存します。順序を飛ばして複数項目を同時に変更すると、原因を特定できていた問題も再現しにくくなります。
| レイヤー | 主な確認項目 | よくある症状 |
|---|---|---|
| ネットワーク接続 | リモートアドレス、ポート、ネットワーク到達性 | 接続拒否またはタイムアウト |
| TLS | 名前、証明書チェーン、システム時刻 | 証明書またはハンドシェイクのエラー |
| トランスポート | パス、Host、サービス名 | アップグレード失敗または接続切断 |
| プロキシプロトコル | ユーザー、パスワード、プロトコル設定 | 認証失敗またはリクエスト中断 |
互換性は実際に動作しているコアで確認する
REALITYやXTLS Visionなどの機能は、いくつかの項目をコピーするだけで使えるものではありません。クライアント画面が対応していても、実行中のコアがその設定を受け付けるとは限りません。該当する接続では、まずサーバーから提供された情報と実際のコアを確認し、次に関連する設定一式を照合してください。V2FlyとXrayには共通の背景がありますが、独自拡張が完全に互換というわけではありません。詳しくはコアの違いと設定の互換性をご覧ください。
コアを切り替えた後に「未知のトランスポート」や「セキュリティ設定を解析できない」といったエラーが出た場合は、起動するまで項目を一つずつ削除するのではなく、互換性が確認できた設定に戻してください。起動できても、双方で同じ接続方式が使われているとは限りません。元の接続情報と変更内容を記録しておくと、設定を復元する際に推測でやり直すことを避け、互換性の問題とネットワークの問題を切り分けられます。
routing(ルーティング):条件、順序、タグ
ルーティングルールは、接続をどのoutboundへ渡すかを決めます。一般的な項目ベースのルールは配列の順に確認され、最初に一致したルールで行き先が決まります。一致するルールがなければ、デフォルトoutboundが使われます。ルールを設定してもinboundへの接続は代替できず、接続できないoutboundも修復できません。分割ルーティングを設定する前に、まずデフォルト経路を検証しましょう。その後、目的が明確なルールを少数ずつ追加してください。最初から条件の意味を把握できないほど多くのルールを読み込まないようにしましょう。
ルール内の条件の組み合わせを理解する
同じルール内で異なる種類の条件を指定した場合、通常はすべてを満たす必要があります。たとえば接続元のinboundと宛先ドメインの両方が一致するとルールが適用されます。同じ項目の配列には、複数の一致条件を並べます。そのため、ドメイン一覧とIP一覧を一つのルールに置いても、「ドメインまたはIP」を意味するとは限りません。両方の宛先を対象にする場合は、通常はルールを分け、同じoutboundタグを指定します。
{
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": ["full:example.com"],
"outboundTag": "block"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"ip": ["geoip:cn"],
"outboundTag": "direct"
}
]
}
}
この例を使うには、directとblockのoutbound、および対応するドメインとIPのデータファイルが必要です。最初のルールでは、動作確認用のドメインを完全一致でブロックし、ルールの優先順位を確認します。後続の3ルールは、よく使われる直結の分類例です。すべてのネットワークに適した完全な分割ルーティング設定ではありません。一致しない通信は先頭のoutboundで処理されます。デフォルトoutboundが直結なら、後続のルールが他の通信を自動的にプロキシ経由にするわけではありません。
ドメインの書式とデータファイル
full:はドメインとの完全一致、domain:はドメインとそのサブドメインへの一致に使います。regexp:は正規表現、geosite:はドメイン分類の参照に使います。通常の文字列は想定より広い範囲に一致する場合があるため、完全一致が必要なら適切な接頭辞を指定してください。正規表現中のバックスラッシュはJSON文字列としてエスケープする必要があります。確認が難しい場合は、複雑な表現を避け、明確なドメイン条件をいくつか指定しましょう。
geosite:cnとgeoip:cnは、それぞれドメイン分類とIP分類を参照します。リアルタイムの位置情報ではなく、対応するデータセットが一対一で揃っているわけでもありません。データファイルの欠落、分類の不存在、ファイル形式の非互換などが読み込みに影響することがあります。クライアントやデータの更新後に、一部の宛先でルールの一致結果が変わる場合もあります。長期的に維持したい業務上の例外には、意図が明確なカスタムドメインルールを使うのが適しています。
domainStrategyとDNSサーバーの選択は別の設定
AsIsでは通常、元の宛先形式を維持し、ルーティング判定のためにドメインをIPへ変換しません。IPIfNonMatchは、ドメインの段階で一致しなかった場合に名前解決を試み、その後に再判定します。IPOnDemandは、ルーティング判定にIPが必要になった時点で名前解決を行います。具体的な動作はコアの実装にも左右されます。これらの設定が決めるのは「ルーティングでいつIPが必要になるか」です。DNSオブジェクトが決める「名前解決リクエストをどう処理するか」と混同しないでください。
アプリがIPアドレスを直接指定した場合、ドメインルールに使える情報がないことがあります。宛先がドメイン名のままでも、IPルールが適用されるかどうかは名前解決の方針に左右されます。トラフィックのスニッフィングで情報を補える場合もありますが、すべての接続でドメインを取得できるとは限りません。ルールが効かない場合は、まずコアが受け取った宛先がドメインかIPかを確認し、次にルールの順序とデータ分類を確認してください。すべての通信を同じoutboundに変更するのは避けましょう。
分割ルーティングを検証する際は、特定のドメイン、直結させたい宛先、デフォルト経路の宛先を一つずつ選び、それぞれ新しい接続を確立してください。ブラウザーが接続プール内の既存セッションを再利用する場合があるため、設定変更後は接続を作り直してログを確認します。システムプロキシのバイパスリストによって、リクエストがコアに届く前に直接接続されることもあります。これはコアのルーティングとは別の仕組みです。よくある現象についてはFAQの接続に関するトラブル対処もご覧ください。
dns設定:名前解決が行われる場所
DNS設定では、まず名前解決がどこで行われるかを確認します。ブラウザー、OS、アプリ内蔵のリゾルバー、コア内蔵のリゾルバー、リモートサービスなどが関係する場合があります。dnsオブジェクトを記述するのは、コア内蔵リゾルバーの動作を設定するだけです。システム上のすべてのDNSリクエストが自動的にそこへ送られるわけではありません。アプリが先に名前を解決してIPアドレスをプロキシへ渡す場合、コアが最初に受け取る宛先にはドメイン名が残っていないことがあります。
servers、hosts、名前解決の方針
serversには名前解決サーバーを指定します。単純なアドレスを指定する方法と、条件を含むオブジェクトを指定する方法があります。以下はドメインごとに名前解決先を分ける一般的な構造例です。各項目に対応したコアであることを前提としています。IPアドレスは公開リゾルバーの例であり、どのネットワークからも利用できるとは限らず、固定の推奨先でもありません。実環境で使う前に、現在のネットワークと想定する経路から接続できるかを確認してください。
{
"dns": {
"hosts": {
"example.com": "192.0.2.10"
},
"servers": [
{
"address": "223.5.5.5",
"domains": ["geosite:cn"],
"expectIPs": ["geoip:cn"]
},
"1.1.1.1"
],
"queryStrategy": "UseIPv4"
}
}
hostsはコアのリゾルバー内で静的な対応付けを行う項目であり、OSのhostsファイルを書き換えるものではありません。例の192.0.2.10はドキュメント用に予約されたアドレスで、構造を示すためだけに使っています。実際のサービスへの接続には使えません。静的な対応付けは、明確で変化しにくい要件に適しています。頻繁に変わるサイトを長期間一つのIPに固定すると、通常の接続先選択が行われなくなり、証明書、到達性、サービス提供地域に想定外の影響が出ることがあります。
domainsを含むサーバー項目は、特定のドメインに対する一致条件を指定します。expectIPsは、解決結果が想定する分類に合うかを確認するための項目ですが、「特定の地域からのアクセスだけを許可する」ファイアウォールではありません。候補となるリゾルバー、フォールバック、結果を受け入れる条件は、コアや他の設定にも左右されます。サーバーの配列が常に先頭から順に試され、失敗した場合だけ次へ進むとは限りません。配列の順番だけから、すべてのクエリの行き先を判断しないでください。
名前解決の経路と接続の経路を別々に確認する
DNSサーバーに名前解決リクエストが届くかどうかと、最終的なWebサイトへの接続がプロキシ経由になるかどうかは別の問題です。コアのルーティングに関わる名前解決方式もあれば、ローカル経路を直接使う方式もあります。詳細は実際の実装を確認してください。プロキシ向けのドメインルールを一つ追加しても、すべての名前解決リクエストの出口が変わるとは限りません。DNSアドレスを変更しただけで、リモート認証やトランスポート設定の誤りが直るわけでもありません。
HTTPSベースの名前解決サービスを使う場合は、リゾルバー自身のドメインを最初に解決する方法も考慮する必要があります。DNSサーバーのアドレスがドメイン名で、その名前解決にも同じ経路が必要だと、依存関係が循環することがあります。起動時にリゾルバーとプロキシサーバーをどうやって見つけるかを整理し、接続可能な初期経路を確保してください。プロキシサーバー名の名前解決が、まだ確立していない同じプロキシ接続に依存しないようにしましょう。
| 設定箇所 | 主な影響範囲 | 別途確認が必要な点 |
|---|---|---|
| システムDNS | システムの名前解決を使うアプリ | アプリが独自のリゾルバーを使っているか |
| コアのdnsオブジェクト | コアが行う関連クエリ | 内蔵リゾルバーが実際に使われているか |
| ルーティングのdomainStrategy | ルーティング時に名前解決を試みるか | outboundが宛先へどう接続するか |
| outboundの名前解決方針 | 宛先へ接続するための準備 | 現在のプロトコルが項目に対応しているか |
IPv4、IPv6、キャッシュ
UseIPv4は該当するクエリの方針を制限するもので、端末全体のIPv6を無効にする設定ではありません。アプリが独自のリゾルバーを使う場合、IPv6アドレスを取得して接続を試みることがあります。反対に、AAAAレコードを解決できても、ネットワークに利用可能なIPv6経路があるとは限りません。名前解決の結果と接続の成否を別々に確認し、特定の経路の問題を調べずにアドレスファミリー全体を無効にしないようにしましょう。
DNS設定の変更後も、アプリやシステムのキャッシュ、既存の接続が確認結果に影響する場合があります。まず新しいリクエストを作成し、ログに記録された宛先の形式とルーティング結果を照らし合わせてください。コマンドラインのシステム名前解決ツールで通常確認できるのはシステム側の名前解決経路であり、コア内蔵リゾルバーの動作と同じとは限りません。コアのDNSを確認するには、実際の入口を通るテストリクエストを送り、実行ログもあわせて確認してください。システムのクエリを一度確認しただけで、設定が有効になったと判断しないでください。
policy(ポリシー):接続時間と統計
policyは主に、ユーザーレベルごとの接続動作とシステム全体の統計設定を管理します。ここでいうポリシーは、ドメインの分割ルーティングルールでもシステムプロキシのモードでもありません。ルーティングは接続先の出口を選び、ポリシーは接続の待ち時間や終了条件、一部の統計を管理します。両者を分けて理解すれば、ルーティングの誤りをタイムアウトの短縮で直そうとするなど、関係のない設定変更を避けられます。
levelsとユーザーレベルの関係
levelsのキーには、"0"のようなレベル番号を文字列で指定します。ユーザーレベルを扱うプロトコルでは、ユーザー設定からレベルを参照できます。明示的な指定がない場合は通常、デフォルトのレベルが使われますが、動作はプロトコルとコアによって異なります。レベルは優先順位ではなく、ユーザーの通信を自動的に高速化するものでもありません。設定を変更する前に、対象となるユーザーオブジェクトが実際にそのレベルを使っていることを確認してください。
{
"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は該当するハンドシェイクに許される時間を、connIdleはアイドル状態の接続時間を制御します。uplinkOnlyとdownlinkOnlyは、接続の片側が終了した後、もう片側が処理を続ける際の待ち時間に関係します。一般的な実装では秒単位ですが、これらが制御するのはコアの接続処理であり、ブラウザーに表示されるページ読み込み時間と同じではありません。
制限時間を短くしすぎると、遅延の大きいネットワークではハンドシェイクが終わる前に中断されたり、ロングポーリング、メッセージ配信、短時間データが流れない接続に影響したりすることがあります。長く設定しすぎると、アイドル状態の接続が多く残る可能性があります。断続的な切断が起きたら、まずタイムアウト、リモート側の切断、アプリによる終了のどれなのかを確認してください。切断したからといって、すべての値を同時に増やさないようにしましょう。過剰な変更は回線品質の問題を見えにくくし、再現も難しくします。
統計のスイッチは完全な監視インターフェースではない
ユーザー通信量、inbound統計、outbound統計では集計対象が異なります。設定を有効にしても、クライアント画面に該当する数値が必ず表示されるとは限りません。統計モジュール、取得用インターフェース、クライアント側のデータ収集方法も連携する必要があります。ユーザー別の統計には、識別可能なユーザー情報が必要になる場合もあります。これらの数値をネットワークカードの通信量と同一視しないでください。プロトコルのオーバーヘッド、再送、他のプロセスの通信により、集計値の基準が異なることがあります。
統計を必要とする完全なカスタム設定では、通常、コアの要件に応じて統計オブジェクトや取得機能も設定します。APIの入口は管理用なので、ローカルまたは管理されたネットワークに制限してください。通信量を見るために、信頼できないインターフェースへ公開してはいけません。このページでは、管理ポートを公開する設定例は掲載しません。GUIクライアントを使う場合は、クライアントに備わっている統計機能を優先し、競合する管理用の入口を重複して有効にしないようにしましょう。
ポリシー、ログ、同時接続数は分けて調整する
ログレベルはlogオブジェクトで制御し、policyの統計スイッチでは設定しません。ポリシーの統計はバイト数を記録し、ログは動作中のイベントを記録します。互いに代用できません。多重化も別の場所で設定する機能であり、ユーザー統計を有効にしても自動的には有効になりません。リソース使用量を調べるときは、接続数、通信の同時実行、ログ出力、統計の要件をそれぞれ確認してから、変更する項目を決めてください。
デスクトップやモバイル端末でバックグラウンド接続が制限される原因は、OS側にある場合もあります。Androidのバッテリー最適化でクライアントが停止したり、ネットワークの切り替えで既存の接続が使えなくなったりすることがあります。こうした問題はconnIdleを延ばすだけでは解決できません。まずプロセスが動作中で、OSのネットワークインターフェースが有効であることを確認してから、コアのポリシーを確認してください。そうしないと、システム側の中断を設定のアイドルタイムアウトと誤認することがあります。
変更の効果を確かめるには、同じネットワーク、同じアプリ、似た使い方で再テストしてください。短いリクエストが成功しても、長時間の接続が正常とは限りません。接続を長時間維持できても、リソースを効率よく使えているとは限りません。よくある最適化設定を繰り返し試すより、失敗した段階とログを記録する方が役立ちます。明確な必要性がない項目は変更を控えることが、保守や将来のアップデートとの互換性にもつながります。
検証とトラブル対処:設定ファイルから実際のリクエストまで
設定の検証は、テキストを解析できるか、コアが読み込めるか、アプリが接続しているか、実際の通信経路が想定どおりか、の4段階で行います。前の段階に成功しても、次の段階の成功を意味するわけではありません。正しいJSONでも未定義のoutboundを参照していることがあり、コアが起動してもアプリから接続が届いていないことがあります。アクセスに成功しても、システムがプロキシを迂回して直接接続しただけかもしれません。各段階で確認できる証拠を残すことで、変更が実際にどこへ影響したのか判断できます。
まず構文と読み込みエラーを確認する
二重引用符、カンマ、括弧の対応、項目の型を確認してください。コードをコピーする際に、説明文やコードフェンスまで設定ファイルに含めないようにしましょう。JSONを解析できたら、コアの起動ログに未知のプロトコル、データファイルの不足、無効なタグ、ポートの使用中などが記録されていないか確認します。エラーの行や列は解析が停止した位置を示すことが多く、実際に欠けているカンマは一つ前の行にある場合もあります。前後のオブジェクト境界もあわせて確認してください。
編集したファイルではなく、クライアントが再生成した別の設定を実行していないか確認してください。GUIクライアントでは、ログや実行情報を確認できますが、画面や入口の名前はバージョンによって異なることがあります。最初からクライアントを変更する必要はありません。元のファイルを保存し、競合するプロセスを終了して一度再起動し、最初に表示されたエラーを記録しましょう。その後に繰り返し表示されるエラーは、同じ原因で再試行されているだけの場合があります。
入口を明示してテストする
以下の2つのコマンドは、冒頭の例で別々に設定したSOCKS入口とHTTP入口を対象にしています。SOCKSアドレスで使うsocks5hは、ドメイン名の処理をプロキシ側に任せる指定です。これにより、ローカルの名前解決経路と区別してテストできます。Windowsのコマンド環境ではcurl.exeを明示できます。その他のOSでは使用可能なcurlコマンドを使ってください。テスト先はドキュメント用の例示サイトであり、速度測定ではありません。また、すべてのアプリがプロキシ経由になったことを確認するものでもありません。
curl --noproxy "" --proxy socks5h://127.0.0.1:10808 --head https://example.com/
curl --noproxy "" --proxy http://127.0.0.1:10809 --head https://example.com/
既存のプロキシ環境変数がテストに影響するのを抑えるため、バイパスリストを明示的に空にしています。ローカルポートへの接続がすぐに拒否された場合は、プロセス、待ち受けアドレス、ポートを確認してください。ローカル入口には接続できてもリモート側がタイムアウトする場合は、outboundとネットワークを確認します。冒頭の直結設定を使ったテストに成功しても、「アプリからコアを経由して宛先に接続する」という基本経路を確認できたにすぎません。利用可能なリモートプロキシサーバーが存在する証明にはなりません。
ログから失敗した段階を特定する
warningは通常の運用に適したログレベルです。原因の特定に情報が足りない場合は、短時間だけログの詳細度を上げてください。変更後、識別しやすいリクエストを一つ送信し、時刻、宛先、入口、選択された出口を記録したら、通常のログレベルに戻します。詳細ログにはドメイン、アドレス、接続情報が含まれることがあります。共有する前に、サブスクリプションのURL、認証情報などの機密データを削除し、実行設定全体をそのまま送らないでください。
| 症状 | まず確認する項目 | 次に行うこと |
|---|---|---|
| 起動できない | 構文、コアとの互換性、ポートの使用状況 | 動作する基本設定に戻す |
| ローカル接続が拒否される | プロセス、アドレス、待ち受けポート | アプリに設定したプロキシプロトコルを確認する |
| リモートのハンドシェイクに失敗する | サーバー名、時刻、トランスポート、認証 | サーバー側の指定と段階ごとに照合する |
| 一部の宛先が誤ったoutboundを通る | ルールの順序、宛先の形式、デフォルトoutbound | 条件を具体的にして範囲を絞る |
| ブラウザーは正常だがターミナルは動作しない | それぞれのプロキシ設定とバイパスリスト | 入口を明示して再テストする |
「タイムアウト」は結果であり、原因は一つとは限りません。宛先に到達できない、名前解決に失敗した、出口が誤っている、リモート側のハンドシェイクが止まっているなど、複数の問題が似た症状を引き起こします。まず失敗した段階を特定してから、確認する項目を選んでください。ログのよくある内容については実行ログとよくあるエラーをご覧ください。ターミナルだけ動作しない場合は、ルーティング全体を変更する前にシステムプロキシとターミナルの経路確認を確認しましょう。
変更を元に戻せるよう記録する
変更するたびに、対象のオブジェクト、期待する変化、検証に使うリクエストの3点を記録してください。サブスクリプションの更新やサーバーの切り替え後は、クライアントがカスタム設定を保持しているか確認します。元に戻す場合は、パッチを重ねるのではなく、直近の動作する設定に復元してください。問題を特定できない場合は、チュートリアルの手順に沿ってインポート、モード、接続を再確認し、このページに記載したオブジェクトの順でカスタム設定を一つずつ戻しましょう。