JSON / INBOUNDS / OUTBOUNDS / ROUTING / DNS / POLICY

V2Ray 設定ファイルリファレンス

項目の意味からルールの適用順まで、章ごとに設定を確認できます。

初めてのサブスクリプション追加、ノード選択、システムプロキシの有効化は、まずクイックスタートガイドに沿って進めてください。このページではクリック手順を繰り返すのではなく、クライアントが生成するJSONの各項目の役割や、併せて変更できる設定、問題発生時の確認箇所を解説します。接続できるようになってからルーティングやDNSを調整すると、原因を特定しやすくなります。

JSON構造の概要:まず通信の流れを確認

V2Rayの設定は、互いに無関係なスイッチの集まりではありません。アプリがinboundに接続すると、コアは接続先情報に基づいてルートを選び、outboundに処理を渡します。DNSは必要な場面で名前解決を行い、policyとログは接続の管理や状況の把握に使われます。まずこの流れに沿って設定を読むと、項目を個別に暗記するより実用的です。同じ接続エラーでも、アプリからinboundに届いていない場合と、outboundでハンドシェイクに失敗した場合では、対処法が異なります。

トップレベルオブジェクトと各項目の役割

トップレベルにはJSONオブジェクトが必要です。inboundsとoutboundsは配列で、複数の入口と出口を定義できます。routing、dns、policy、logは通常オブジェクトです。inboundのlistenをoutboundに入れたり、ルーティングルールをトップレベルに直接置いたりしないでください。エディターで括弧を認識できても、構文として読み込める可能性を示すだけで、項目が正しい位置にあるとは限りません。

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": []
  }
}

上の構造例は項目同士の関係を示すもので、ローカルの待ち受け口がないため、ブラウザーから直接接続することはできません。空配列は有効なJSONですが、実行時の意味はコアのデフォルト動作によって異なります。設定の一部を使うときは、まずどの項目を置き換えるものか確認し、配列全体を置き換えるのか、オブジェクトを1つ追加するのかを判断してください。2つの設定オブジェクトをそのまま連結すると、解析できない文書になります。

項目役割確認ポイント
inboundsローカルアプリからの接続を受け付けるアドレス、ポート、プロトコル
outbounds次の接続を確立するタグ、プロトコル、リモート接続情報
routing接続をoutboundに振り分けるルールの順序とタグの参照先
dnsコア側でドメインを名前解決するリゾルバーとクエリポリシー
policy接続管理と統計の設定レベル設定と統計機能の依存関係

構文が正しいことと、設定が有効なことは別

ツール間で使いやすいよう、このページでは厳格なJSONに統一しています。キー名と文字列は半角の二重引用符で囲み、配列の最後にカンマを付けず、説明文はコードブロックに含めません。読み込み側がコメントに対応していても、サブスクリプション処理機能や別のコアでも使えるとは限りません。真偽値はtrueまたはfalseと記述し、引用符で囲んだ文字列にしないでください。数値と文字列も見た目だけで置き換えず、対応するコアで求められる型を確認してください。

同じオブジェクト内でキーを重複させないでください。たとえばroutingを2回記述すると、処理系によっては前の設定が上書きされたり、読み込みを拒否されたりします。ルールが2組あるように見えても、実際に有効なのは片方だけということがあります。設定を統合するときは、ルールを同じrules配列にまとめてください。配列の順序にも意味があります。outbound配列の先頭項目がデフォルトの出口に影響し、ルーティングの先行ルールが接続を先に捕捉することもあるため、自動整列ツールで安易に並べ替えないでください。

タグは設定項目間をつなぐ参照先です。outboundにdirectを定義すれば、ルーティングからoutboundTagで参照できます。大文字・小文字や綴りを一致させてください。各inboundとoutboundには、安定した一意のタグを付けるのがおすすめです。ログやルーティングでもタグを手がかりに確認できます。タグは単なる名前で、proxyと名付けても自動的にプロキシ機能が有効になるわけではありません。実際の動作はオブジェクトのプロトコルと設定で決まります。

設定の読み込み元を確認してから編集

GUIクライアントでは、サブスクリプション情報、画面上の設定、実行時の設定が別々に管理されていることがあります。まず復元できるバックアップを作成し、今回の起動時に実際に生成された内容を確認してください。コアの実行中に一時ファイルを変更しても、次回起動後に変更が残るとは限りません。画面から設定できる項目は、該当する設定画面で保存するのが優先です。カスタム設定を使う場合は、クライアントが用意している読み込み方法に従ってください。

変更前に「このドメインは直結のoutboundを使う」のように、期待する結果を具体的に決めましょう。「ネットワークを最適化する」といった曖昧な目標は避けてください。目的に関係する設定だけを変更し、再読み込み後に同じ操作で結果を確認します。これにより、構文エラー、項目の非互換、ルール不一致を切り分けやすくなります。初回接続がまだ確立していない場合は、チュートリアルの手順に戻って基本の動作を確認してください。複雑なルールを同時に追加する必要はありません。

クライアントとコア:設定形式を確認する

V2Rayはエコシステム全体を指す名称として使われることがありますが、クライアントの画面と、実際に接続を処理するコアは別のものです。v2rayNはデスクトップ上でサブスクリプションや設定の選択、実行を管理し、コアは設定の読み込み、接続の確立、ルーティングを担当します。似たメニューがあっても、内部の対応機能が同じとは限りません。項目を確認する際は、まず実行中のコアを特定し、次にクライアントが画面上の設定を別形式に変換していないか確認してください。

V2FlyとXray:共通する構造と違い

Project Vエコシステムに属するV2FlyとXrayには共通の歴史があり、似たJSON構造も多くあります。一方で、プロトコルの実装、トランスポート設定、追加機能、項目の変更は必ずしも同期していません。このページの例は、一般的な従来型JSONの基本を説明するもので、すべての拡張項目がコア間でそのまま使えることを保証しません。特にVLESS、XTLS、REALITYなどを設定する場合は、使用するコアとプロトコルの組み合わせが各項目に対応しているか確認してください。

Androidでは、v2rayNGは主にXrayコアを使い、v2flyNGはV2Flyコアを利用する選択肢です。デスクトップではまずv2rayNを検討し、実際のコアは設定の要件に合わせて選んでください。リンクをクライアントにインポートできても、含まれるすべてのパラメーターが動作するとは限りません。リンクの解析、設定の生成、コアの起動は、それぞれ個別に確認が必要です。

クライアント主な用途設定の確認ポイント
v2rayNデスクトップでのサブスクリプションと実行管理実行中のコア、生成された設定、システムプロキシ
v2rayNGAndroidでの接続管理Xrayの設定、システム接続の許可、アプリの対象範囲
v2flyNGAndroid向けV2FlyクライアントV2Flyの項目、プロトコルの互換性

GUIの設定画面は元のJSONをそのまま表示しているわけではない

クライアントは、1つのプルダウン項目から複数の設定を組み立てたり、プログラムが管理するタグやポートを画面上で隠したりすることがあります。たとえば画面上のルーティングモードは、「モード」というトップレベルキーではなく、一連のルールに対応している場合があります。生成ファイルを編集した後でモードを切り替えると、変更が上書きされることもあります。設定を読むときは、現在のノード由来の値、全体設定由来の値、起動時にクライアントが自動補完する値を区別してください。

カスタム設定では、クライアントが管理するすべての機能を利用できるとは限りません。完全な設定として実行する読み込み方法もあれば、接続項目の1つとして扱う方法もあります。システムプロキシが指定するローカルポート、クライアントの状態確認用の入口、統計に必要なタグなど、独自の前提がある場合もあります。画面では起動済みなのにアプリから接続できない場合は、リモートサーバーの障害と判断する前に、実際の待ち受けポートを確認してください。

{
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    }
  ]
}

このoutboundは直接接続を定義しており、基本的な項目の説明には使えますが、リモート接続の完全な設定ではありません。設定の互換性を判断する方法も示しています。まずプロトコル名を確認し、そのプロトコルのsettingsを見てから、トランスポート関連のパラメーターを確認してください。プロトコル名だけを置き換え、元のプロトコル用の設定オブジェクトを残しても、通常は正しく動作しません。サーバー、認証、トランスポートの各項目はセットで確認してください。

コアの移行時は対応機能を項目ごとに確認

コアを切り替える前に、実際に使用中のプロトコル、トランスポート、ルーティングデータベース、DNSポリシー、inbound機能を洗い出してください。新しいコアが必要な機能に対応していることを確認してから、設定を1つ選んで小規模に検証しましょう。設定全体を一度に置き換え、画面上で起動したかどうかだけで移行の成否を判断しないでください。コアが起動しても、特定のルールやUDPを使うケース、追加のトランスポート動作が以前と異なることがあります。

ルーティングデータベースも互換性の確認が必要です。設定にgeosite:cnと記述しても、実行中のコアが対応するリソースを読み込み、そのファイルに該当カテゴリが含まれていなければ使えません。クライアントがルールデータを更新するディレクトリと、別のコアがデータを探すディレクトリは異なる場合があります。手動で移行する際はJSONだけでなく、リソースの読み込み先も確認してください。異なる形式のデータファイルを安易に改名して流用しないでください。

トラブル対処では、「クライアント名、実際のコア、設定の読み込み元、エラーが出た項目」を記録すると、ホーム画面のスクリーンショットより役立つことがあります。インストーラーを選ぶ場合はクライアント一覧へ進んでください。2つのコアの違いを詳しく知りたい場合は、XrayとV2Flyのコアの違いをご覧ください。クライアントを変更すれば必ず直ると考えず、具体的な互換性の問題が解消するかを先に確認しましょう。

inbounds:アプリの接続口を定義する

inboundは、アプリからコアへ接続を渡す方法を定義します。一般的なローカル接続口はSOCKSプロキシとHTTPプロキシで、アプリは対応するプロトコルとポートを指定して接続します。inboundのポートはリモートサーバーのポートではありません。また、ローカルで待ち受けていても、リモート接続が成功したとは限りません。トラブル対処では、まずアプリから接続がinboundに届いているか確認してください。リクエストがコアに入っていなければ、outboundの認証情報を変更しても結果は変わりません。

ローカルアドレス、ポート、プロトコルをまとめて確認

{
  "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": {}
    }
  ]
}

この設定では、ローカルループバックアドレスだけで待ち受ける接続口を2つ作成します。SOCKS対応アプリは10808、HTTPプロキシ対応アプリは10809を使用します。2つのポートは任意に入れ替えられる別名ではありません。ここで示す数値は例であり、使用中のクライアントが同じポートを使うとは限りません。画面に別の値が表示される場合は、実行中の設定を優先し、アプリ側のプロキシアドレスも合わせて変更してください。

listenが127.0.0.1の場合、ほかのデバイスからLANアドレス経由で接続することはできません。ワイルドカードアドレスで待ち受けると、接続可能な範囲が本機だけではなくなるため、認証、OSのファイアウォール、信頼できるネットワークの範囲を同時に検討する必要があります。上のSOCKS例は認証なしで使用する設定なので、本機だけにアクセスを限定した状況に適しています。そのまま外部公開の共有プロキシにしないでください。

UDPを有効にしても通信全体が保証されるわけではない

SOCKS設定のudpは、inboundで該当するUDPリクエストを処理できるようにします。ただし、実際に通信できるかは、アプリがSOCKSのUDP機能を使うか、outboundプロトコルが対応しているか、リモート側のネットワークで許可されているかによって異なります。HTTPプロキシは通常、HTTPリクエストやトンネル接続向けで、汎用UDP接続口ではありません。ブラウザーは動作するのにリアルタイムアプリだけ失敗する場合は、まずそれぞれが使う通信方式を確認してください。

システムプロキシも、OSの設定に従うアプリへ接続口を通知するだけで、すべての通信を自動的に処理するものではありません。独自のプロキシ設定を使うアプリもあれば、直接ネットワークに接続するアプリもあります。TUNは仮想ネットワークインターフェース、権限、ルーティング、DNSを組み合わせる別の方式で、SOCKS inboundを追加するだけでは代替できません。どの通信に設定が反映されているかを確認するには、トレイの状態だけでなく、対象アプリの通信がどこから入るかを調べてください。

スニッフィングはドメイン情報を補う機能で、すべてを識別できるわけではない

{
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      },
      "sniffing": {
        "enabled": true,
        "destOverride": ["http", "tls"]
      }
    }
  ]
}

スニッフィングは、受信した通信からプロトコルやドメイン情報を取得し、接続先のIPアドレスだけが渡された場合にコアが判断する手がかりを得る機能です。通信を復号する機能ではなく、すべての接続からドメインを特定できるわけでもありません。ハンドシェイク方式や暗号化されたメタデータ、HTTP・TLS以外の通信などによって識別できない場合があります。有効にした後は、使用中のコアで接続先の上書きがどう扱われるかも確認してください。「ルーティングに使えるドメイン情報」と「実際の接続先」は必ずしも同じではありません。

inboundに安定したタグを付けると、入口ごとのルーティングにも役立ちます。たとえばテスト用のinboundを用意し、ルーティングのinboundTagと組み合わせれば、その入口からの通信だけにルールを適用できます。ただし、ルールは順に評価されるため、先に広範な条件に一致すると、入口専用ルールまで到達しないことがあります。inboundを追加するときにタグを決め、後から名前を変更した際に参照ルールを見落とさないようにしてください。

inboundを検証するには、まず手動プロキシに対応したアプリでローカルアドレスと該当ポートを指定し、ログにリクエストが記録されるか確認します。記録がない場合は、アプリの設定、待ち受けアドレス、ファイアウォールを確認してください。記録はあるものの後続処理でエラーになる場合は、outboundと名前解決を調べます。LAN上の別デバイスからだけ接続できない場合は、待ち受けアドレスとアクセス範囲を確認してください。この3種類の問題を切り分ければ、関係のない設定変更を減らせます。

outbounds:接続方式とタグを区別する

outboundは、接続を受け取った後、次の接続先へどうアクセスするかを処理します。直接接続するほか、リモートプロトコルで接続したり、リクエストを明示的に遮断したりできます。inboundは「アプリからどう入るか」、outboundは「コアからどう出るか」を扱い、同じプロトコルを使う必要はありません。アプリからSOCKS inboundでコアに接続しても、ルーティング先のoutboundは別の方式にできます。ローカルのSOCKSポートだけを見て、リモート側もSOCKSだと判断しないでください。

直結と遮断の基本outboundを用意する

{
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ]
}

freedomはコアから接続先へ直接接続し、blackholeは振り分けられた通信を破棄します。directとblockはこの例で付けたタグなので、名前は変更できますが、ルーティング側の参照も合わせて変更してください。遮断用outboundは明示的な拒否ルールに使うもので、接続失敗時に自動で使われる予備のoutboundではありません。ルールを誤って日常的な通信に適用すると、アプリではタイムアウトや接続切断として見えることがあります。

従来の設定動作では、どのルールにも一致しない通信は通常、outbounds配列の先頭にある出口へ送られます。上の例では先頭が直結のため、デフォルトも直結です。リモートoutboundを配列の末尾に追加しても、すべてのリクエストが自動的にリモート経由になるわけではありません。デフォルトの出口を変更する前に、クライアントが別途フォールバックルールを生成しているか、負荷分散などの追加機能を使っているか確認してください。配列の順番だけですべてのケースを判断できるとは限りません。

リモート接続の設定は関連項目を一式で保持する

VMess、VLESS、Trojanなどでは、認証とトランスポートの設定項目が異なります。リモートアドレス、ポート、ユーザー情報、トランスポート方式、TLS関連の項目は、サーバー側の設定と一致させてください。あるプロトコルのリンクから認証情報だけを別プロトコルのオブジェクトに移したり、設定を読み込ませるために理解できない項目を削除したりしないでください。読み込みに成功したことは形式が受け付けられたという意味にすぎず、接続先と同じハンドシェイク設定になっているとは限りません。

リモート側でTLSを使う場合、接続先のアドレス、ハンドシェイク時のサーバー名、アプリケーション層のリクエストで使うホスト名が、それぞれ別の役割を持つことがあります。値が一致する場合もありますが、すべてドメイン名だからといって同一視しないでください。トランスポートの経路もサーバー側で指定されていることがあります。取得した完全な設定をもとに項目ごとに確認しましょう。名前やパスを適当に置き換えると、原因が分かりやすいエラーが複数の不一致に変わってしまいます。

確認する項目主な内容よくある間違い
オブジェクトの識別tag、protocolタグをプロトコルの機能だと思い込む
プロトコル設定settings内の接続パラメーター異なるプロトコルの認証形式を混在させる
トランスポート設定streamSettingsなど該当する項目トランスポート名だけを変更し、関連項目を変更しない
ルーティングからの参照outboundTagoutboundは存在するが一度も選択されない

エラーが発生した段階を特定する

接続がoutboundに割り当てられた後も、名前解決、下位層の接続、TLSハンドシェイク、プロトコル認証、データ転送といった段階があります。どこかで失敗しても、すぐに「ノードが使えない」と決めつけないでください。たとえばローカルの名前解決に失敗すれば、接続先のアドレスも取得できません。ポートに到達できても、プロトコル認証に成功するとは限りません。ログでは最後の要約だけでなく、最初に記録された具体的なエラーを探しましょう。

直結とリモートoutboundのテストには、それぞれ異なる確認対象を使います。まず同じローカルinboundから、直結できることが分かっているサイトへ接続し、アプリからコアまでの経路を確認します。次に既存のリモートoutboundを選び、ルーティングとハンドシェイクの結果を確認してください。両方のテストが失敗する場合は、共通するinboundやクライアントの動作から調べます。リモート経由だけ失敗するなら、リモート設定、ネットワーク環境、プロトコルの互換性を確認してください。

証明書検証の無効化を、トラブル対処の定番にしないでください。証明書名、システム時刻、信頼チェーン、サーバー設定はいずれもTLSに影響します。検証を無効にすると、本当の不一致が隠れることがあります。まず接続情報の取得元と端末の時刻を確認し、ログに示された原因に沿って対処してください。認証情報を含むJSON全体を公開の掲示板に投稿するのも避けましょう。通常、プロトコルの種類、項目名、必要に応じて加工したエラー情報があれば状況を説明できます。

クライアントによるサブスクリプション更新で、リモートoutboundが書き換えられる場合があります。長期的に使うローカルルーティングは、できるだけクライアントが対応する管理方法で設定してください。クライアントを新しくインストールする場合はダウンロードページへ。インポート後の確認手順はv2rayNの初回接続チェックリストをご覧ください。outboundは最小限にし、1つの経路で接続を確認してから複雑な構成を追加しましょう。

routing:ルールを順に評価して接続先を決める

ルーティングの優先順位はルール数ではなく、設定の順序で決まります。通常は上から順に評価し、一致したルールの出口が選ばれると、その後のルールはこの接続の選択には使われません。そのため、個別の例外は広い条件の分類より前に置きます。直結に指定したドメインがリモート経由になる場合は、クライアントを何度も再起動するより先に、上位の広範なルールが一致していないか確認してください。

ルールの順序とタグの参照先

{
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": ["domain:example.com"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": ["geosite:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "block"
      }
    ]
  }
}

この例では、directとblockのoutboundが既に存在し、GeoIPとGeoSiteのデータを読み込める必要があります。最後のルールは、残りのTCP・UDP接続を遮断用outboundに送ります。これは利用を制限するポリシーの一例であり、すべてのユーザーに推奨するデフォルト設定ではありません。残りの通信を既存のリモートoutboundへ送る場合は、実在するタグを指定してください。存在しない「proxy」タグを作り足さないでください。

同じルール内の異なる条件項目は、通常すべてを満たす必要があります。同じリスト内の候補は、どれか1つに一致すればよい条件として扱われます。たとえばinboundTagとdomainを同じルールに記述すると、指定したinboundから入り、指定ドメインにも一致する通信を表します。どちらか一方に一致すればよいという意味ではありません。関係のない条件を1つのルールに詰め込むと、一度も一致しない可能性があります。独立した2つの経路を表す場合は、ルールオブジェクトを分けてください。

ドメインマッチングでは条件の意味を使い分ける

domain:example.comはexample.comとそのサブドメインを対象とし、full:example.comはドメイン名全体の完全一致に使います。通常の文字列と正規表現では意味が異なります。一度マッチしただけで、意図した範囲を判定できているとは限りません。通常のドメイン振り分けには明示的なマッチ形式を使い、短すぎるキーワードによる別ドメインへの誤一致を防ぎましょう。正規表現が必要な場合は、境界条件とエスケープを個別に確認してください。

JSON文字列と正規表現はどちらもエスケープを扱うため、別のツールからルールをコピーする際は特に注意が必要です。まずJSON内の実際の文字列を確認し、次にコアがその文字列をどう解釈するかを確認してください。1つのドメインとサブドメインを対象にするだけなら、短さを優先して複雑な正規表現を使う必要はありません。ルールが読みやすいほど、誤マッチの原因を推測に頼らず見つけやすくなります。

domainStrategy:IPアドレスを使うタイミングを決める

AsIsはルーティングのためにドメインをIPアドレスへ積極的に解決しませんが、IPアドレスが分かっている接続はIPルールの対象になることがあります。IPIfNonMatchはドメイン段階で一致するルールがない場合に名前解決を試み、IP条件で判定します。IPOnDemandは、マッチングにIP情報が必要になった時点で名前解決を行います。これらはルーティング時の名前解決のタイミングを変えるもので、端末全体のDNS設定を切り替えたり、特定の出口を指定したりするものではありません。

特にフォールバックルールの影響に注意してください。ドメイン判定の段階で広い条件のルールに一致すると、IPIfNonMatchでも、名前解決後の判定に進まない場合があります。プライベートIPルールが特定のドメインを処理すると思っていても、実際には末尾のネットワーク向けルールが先に選択されているかもしれません。ルール設計では、ドメイン分類で判定する接続と、名前解決後にアドレスを調べる接続を明確にしてください。項目名だけから評価順を推測しないようにしましょう。

ルールは「ローカルアドレス、個別の例外、用途別分類、最後のフォールバック」のように読みやすい順序に分け、一度に追加・変更するのは1種類にしましょう。ルールデータを更新した後は、分類内容が変わることもあるため、代表的な接続先をいくつか再確認してください。リソース不足や分類が見つからない場合は、ルーティングルールをすべて削除して隠すのではなく、起動ログを確認します。データの更新方法はGeoIP・GeoSiteデータベースの更新方法をご覧ください。

最後にログで接続先のドメイン、inboundのタグ、選択されたoutboundを確認します。ブラウザーでページを開けただけでは、意図した出口が選ばれたとは限りません。直結でもリモート経由でも成功する場合があるからです。ルーティング結果が想定と違う場合は、まず実際に読み込まれた設定のルール順を確認し、次にアプリからドメイン情報が渡されているか、最後にデータベースを調べてください。この順序で確認すれば、ドメイン情報の不足を分類ミスと取り違えにくくなります。

dns:どの経路で名前解決されるかを確認

1回のアクセスでも、アプリ、OS、コア内蔵DNS、リモート接続の接続先など、複数の場所で名前解決されることがあります。設定にdnsがあるからといって、端末上のすべてのクエリがその設定を使うとは限りません。まずアプリからinboundにドメイン名とIPアドレスのどちらが渡されるかを確認し、そのうえで現在のリクエストにこの設定が関わるか判断してください。システムの名前解決結果を見ながらコアのDNSだけを変更すると、誤った結論になりがちです。

serversとqueryStrategyの基本

{
  "dns": {
    "servers": [
      "1.1.1.1",
      "localhost"
    ],
    "queryStrategy": "UseIPv4"
  }
}

ここでは、明示的なアドレスを持つリゾルバーと、ローカルシステムを使う名前解決経路を設定し、コアが対応する問い合わせのアドレスファミリーをIPv4に限定しています。localhostはローカルのシステム名前解決機能を使う指定であり、リモートホスト名ではありません。リストを「1つ目が失敗したら必ず2つ目を使う」という固定の主系・予備系と解釈しないでください。実際の選択、並行処理、フォールバックは、サーバーオブジェクト、対象ドメイン、コアの実装によって異なります。

UseIPv4は、性能を上げるための決まり文句ではなく、使用するアドレスファミリーの指定です。接続先がIPv6アドレスしか持たない場合、IPv4に限定すると到達できないことがあります。端末のIPv6経路に問題がある場合は、デュアルスタックを許可すると別の接続エラーが表面化することもあります。まずローカルネットワークとリモート経路で使えるアドレスファミリーを確認してから、問い合わせポリシーを設定してください。この項目でOSのIPv6機能が自動的に無効になるわけではないため、端末のネットワーク設定の代わりにはなりません。

ドメインに応じてリゾルバーを選択

{
  "dns": {
    "servers": [
      {
        "address": "1.1.1.1",
        "port": 53,
        "domains": ["domain:example.com"]
      },
      "localhost"
    ],
    "queryStrategy": "UseIP"
  }
}

サーバーオブジェクトを使うと、特定のドメインに応じた名前解決先を指定できます。この例では、example.comとそのサブドメインを指定サーバーの対象にしています。その他の問い合わせがどう処理されるかは、フォールバックを含む全体の設定で判断してください。domainsはルーティングのdomainとは別の項目です。値が似ていても、項目名を入れ替えてはいけません。サーバーオブジェクトには、希望するアドレスやフォールバック設定が関わることもあるため、正確な動作を使用中のコアがサポートしているか確認しましょう。

リゾルバーへのネットワーク到達性も確認が必要です。平文DNS、暗号化DNS、ローカルの名前解決経路では、通信経路が異なることがあります。通常のルーティングの影響を受けるものもあれば、ローカルで処理されるものもあります。「serversに書けば必ずプロキシ経由になる」とは一概に言えません。リゾルバーのアドレス自体がドメイン名の場合、起動時にそのアドレスをどう取得するかも検討してください。自分自身の名前解決に依存する循環状態になると、解決できなくなることがあります。

設定場所主な役割この設定だけでは判断できないこと
OSのネットワーク設定OSの名前解決機能を使うアプリに影響するコアのすべての問い合わせがこの設定を使う
トップレベルのdnsコア側に名前解決機能を提供する端末上のすべてのDNS通信を処理する
ルーティングの名前解決ポリシールールの判定にアドレスが必要か決める接続の出口を指定する
アプリ独自の名前解決設定そのアプリの名前解決経路に影響するほかのアプリも同じ結果を使う

キャッシュ、スニッフィング、FakeDNSの適用範囲

名前解決ポリシーを変更しても、アプリ、OS、コアに古いキャッシュが残っていたり、既存の接続が再利用されたりすることがあります。動作確認では新しい接続を作成し、必要に応じて対象アプリの方法でキャッシュを処理してください。同じページを1回更新するだけでは不十分な場合があります。ブラウザー独自の暗号化DNSが有効なら、OSとは異なる結果を使うこともあります。比較する前に、確認用ツールがどの名前解決経路を使うのかを明確にしてください。

FakeDNSは仮想アドレスにドメインとの対応を記録し、後続の通信からドメイン情報を復元しやすくする機能です。インターネット上に実際の接続先アドレスを割り当てるものではありません。通信の取り込み方法、マッピングの解放、スニッフィングと組み合わせて使う必要があり、項目を1つ有効にするだけですべてのアプリが正常になるわけではありません。想定した入口を通らないアプリが仮想アドレスを取得して直接接続すると、通信に失敗することがあります。通常のシステムプロキシが使えているなら、項目を増やすためだけに有効にする必要はありません。

DNSのトラブル対処は3段階で進めましょう。まず名前解決の結果が返るか、次にその結果が現在のネットワークで使えるか、最後にアクセスがどの結果を利用したかを確認します。ログにタイムアウトがあれば、まずリゾルバーへの到達性を調べてください。アドレスを取得できても接続できない場合は、アドレスファミリー、outbound、リモート経路を確認します。仕組みの詳細はFakeDNSの仕組みと利用場面をご覧ください。すべてのアクセス障害をDNSのせいにしないようにしましょう。

設定が安定したら、異なる名前解決経路を代表する接続先を少数選び、回帰テストに使いましょう。サーバー、問い合わせポリシー、通信の取り込み方法を変更するたび、同じ接続先で再確認します。名前解決結果はサーバーの振り分けに応じて変わるため、アドレスが常に同じである必要はありません。確認するのは、名前解決が完了すること、取得したアドレスに接続できること、接続が想定したルーティングの範囲内で処理されることです。

policyとログ:接続を制御し、記録を残す

policyは接続管理や統計に関するポリシーを扱い、ドメインの出口は決めません。ルーティングの問題はまずrouting、認証の問題はoutboundを確認してください。policyに「タイムアウト」の項目があるからといって、すべての接続失敗を待ち時間の不足と考えないでください。通常の用途ではまずデフォルト設定を使い、特定の接続のライフサイクルが要件に合わないことをログで確認できた場合に、必要な項目だけ調整しましょう。

レベル設定と接続の関連付け

{
  "policy": {
    "levels": {
      "0": {
        "handshake": 4,
        "connIdle": 300,
        "uplinkOnly": 2,
        "downlinkOnly": 5,
        "statsUserUplink": false,
        "statsUserDownlink": false
      }
    },
    "system": {
      "statsInboundUplink": false,
      "statsInboundDownlink": false,
      "statsOutboundUplink": false,
      "statsOutboundDownlink": false
    }
  }
}

ここでのレベルキー"0"はオブジェクトのキーなので、二重引用符が必要です。接続で使うレベルは、各プロトコルが対応するユーザーレベルの設定によって決まります。inboundのuserLevelで指定する場合もあれば、プロトコルのユーザーオブジェクト内にレベルを設定する場合もあります。レベルオブジェクトを追加しただけでは、すべての接続が自動的にそのレベルへ移るわけではありません。この例の数値は項目を説明するためのもので、あらゆるネットワーク環境に推奨する値ではありません。

handshakeは接続確立時のハンドシェイク待ち時間、connIdleは接続がアイドル状態でいられる時間、uplinkOnlyとdownlinkOnlyは一方向の通信状態で接続を維持する時間に関係します。時間は通常秒単位ですが、具体的な動作はプロトコルや接続段階によって異なります。すべての値を極端に大きくしても、無効な接続が長くリソースを占有するだけで、サーバーアドレスや認証情報の誤りは直りません。

統計の設定を有効にしても、統計機能全体が使えるとは限らない

policy内の統計用真偽値は、対象データの記録を許可する設定です。統計を取得するには、統計モジュール、ユーザー識別子、API設定、クライアント側の呼び出し方法などが必要になる場合があります。スイッチをいくつか有効にしても、画面にすぐすべての統計が表示されるわけではありません。GUIクライアントでは統計関連の設定をクライアントに管理させ、タグの手動変更やAPIの削除によって、画面とコアの通信を妨げないようにしましょう。

統計の確認を目的に、管理用APIを安易に公開しないでください。待ち受けの有無、バインド先アドレス、アクセスできるユーザーはそれぞれ別に検討する必要があり、通常のアプリ用プロキシ入口とは異なります。クライアントに通信量表示機能がある場合は、外部からアクセスできるAPIを別途作る必要は通常ありません。このページの基本設定に管理用APIを含めていないのは、接続経路を分かりやすくするためで、完全な監視環境の構築を目的としているわけではありません。

ログはwarningから始め、必要なときだけ一時的に詳細化する

{
  "log": {
    "loglevel": "warning"
  }
}

通常の利用ではwarningにしておくと、ログ出力を抑えられます。接続先を確認する必要がある場合は、ログレベルを一時的に上げてから問題を再現してください。詳細ログを長期間有効にすると、接続先や通信の情報が記録されたり、ストレージを圧迫したりすることがあります。原因の特定後は通常のレベルに戻し、不要になったログはクライアントの手順に従って処理してください。

{
  "log": {
    "access": "access.log",
    "error": "error.log",
    "loglevel": "info"
  }
}

この設定例ではアクセスログとエラーログを相対パスのファイルに出力します。相対パスは通常、プロセスの作業ディレクトリを基準にするため、JSONを開いているフォルダーに保存されるとは限りません。クライアントが出力先を別に管理している場合もあります。使用前にディレクトリへ書き込めること、ファイルの場所が分かること、ログが増え続けることを確認してください。ログのパスが原因で起動できない場合は、接続設定を根拠なく繰り返し変更せず、まずクライアントのデフォルト出力方法に戻してください。

ログは時系列に沿って、1回のアクセスの流れを確認します。コアが起動したか、inboundが接続を受けたか、ルーティングでどのoutboundが選ばれたか、名前解決が成功したか、ハンドシェイクのどこで失敗したかを追ってください。最初の明確なエラーが設定項目の認識失敗なら、その後の接続状態を調べても意味はありません。正常に起動しているのにアクセス記録がなければ、アプリ側の入口を確認します。最初に確実に異常が発生した箇所を見つけてから、変更する設定を決めましょう。

モバイル端末では、アプリのプロセスが動作し続けるかどうかと、接続ポリシーを分けて考えてください。OSによるアプリの終了、バックグラウンド実行の制限、ネットワークの切り替えは、connIdleを長くしても解決しません。画面消灯後に接続が切れる場合は、v2rayNGのバックグラウンド実行とバッテリー設定を参考に、OS側の条件を確認してください。policyの値を調整する意味があるのは、コアが動作していて、その接続を実際に管理している場合です。

検証とロールバック:最小構成で問題を特定する

設定の検証では、「コアが起動できること」と「接続先にアクセスできること」を分けて確認します。起動の確認ではJSON、項目の互換性、リソース、待ち受け条件を調べます。アクセスの確認には、アプリからの接続、名前解決、ルーティング、その後の通信も関係します。以下はローカル直結の基本設定です。もともと直結できる接続先へアプリからアクセスできるかを確認するためのもので、リモートプロキシ機能やGeoIP・GeoSiteのリソースは含みません。

ローカル直結の基本設定

{
  "log": {
    "loglevel": "info"
  },
  "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": {}
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "direct"
      }
    ]
  }
}

まずクライアントの既存設定をバックアップし、完全なカスタム設定に対応したクライアントの読み込み方法を使って、この基本設定を読み込んでください。ノード項目だけを受け付ける入力欄に貼り付けないでください。クライアントがポートや設定生成を管理している場合は、その方式に合わせて操作し、2つのコアを同時に実行してポートを競合させないようにしましょう。読み込み後、手動プロキシに対応したアプリで該当するローカル接続口を指定し、直結できることが分かっている接続先にアクセスしてください。

複数の条件を一度に変えず、段階ごとに確認する

基本設定を読み込めない場合は、最初に出たエラーを確認してください。構文エラーなら括弧、カンマ、二重引用符を確認し、ポートの競合なら別のプロセスを調べます。項目が認識されない場合は、コアの種類と設定形式を確認してください。この段階ではDNS、スニッフィング、outboundを追加しないでください。原因の候補が増えてしまいます。最小構成を使う利点は、絡み合った問題を個別に確認できる段階へ切り分けられることです。

起動は成功したのにアプリからアクセスできない場合は、まずログに今回のリクエストが記録されているか確認します。記録がなければ、アプリに設定したプロキシの方式、アドレス、ポートを調べてください。リクエストが記録されても名前解決に失敗する場合は、システムの名前解決と対象ドメインを確認します。アドレスを取得できても接続できない場合は、ローカルネットワークと接続先のサービスを調べましょう。この段階にはリモートoutboundがないため、リモート側の認証やトランスポート設定を検討する必要はありません。まず基本設定が機能することを確認してから、次の設定と比較してください。

基本設定で動作を確認できたら、既存のリモートoutboundを戻し、明示的なルールを1つ設定して接続先に割り当てます。まずリモート接続を1つだけ検証し、その後、ドメイン分類、DNSオブジェクト、その他のポリシーを順に追加しましょう。設定を1組追加するたびに、同じ操作で結果を確認して記録してください。追加した設定が原因で失敗した場合は、その部分を戻せば範囲を絞れます。検証済みのinboundを最初から設定し直す必要はありません。

確認できた現象まず確認する項目優先度の低い項目
コアがすぐに終了する構文、項目、リソース、ポートブラウザーのキャッシュ
起動するがリクエストが記録されないアプリの接続口とプロキシの適用範囲リモート側の認証情報
リクエストは届くが出口が想定と違う読み込まれた設定、ルール順、タグ接続タイムアウトを延長する
出口は正しいがハンドシェイクに失敗するプロトコル、トランスポート、時刻、リモート接続情報ドメイン分類のルールを並べ替える

設定の再読み込みと既存の接続

設定を変更した後は、クライアントが対応する方法で再読み込みするか、コアを再起動してください。確立済みの長時間接続、ブラウザーの接続プール、アプリのキャッシュには古い状態が残ることがあります。再生中のページだけを見て、新しいルールが効いていないと判断しないでください。確認には新しい接続を使い、必要に応じて対象アプリを終了して再試行します。項目を1つ変えるたびに端末全体を再起動する必要はありません。まず小さな操作で設定の切り替わりを確認すると効率的です。

システムプロキシとTUNの検証も、それぞれ分けて行います。まず一方の接続方式だけでテストを完了し、その後もう一方に切り替えてください。2種類の通信制御を重ねると、どこから通信が入ったか判断できなくなります。デスクトップとAndroidではOSとの連携方法が異なりますが、確認する順番は同じです。入口、名前解決、ルーティング、出口を調べてください。特定のアプリだけ影響を受けない場合は、コア全体の故障と結論づける前に、そのアプリのプロキシ適用範囲を確認しましょう。

ロールバックでは関連する項目をまとめて元に戻す

有効なバックアップにはJSONファイルだけでなく、設定の読み込み元、使用中のコア、必要なリソース、クライアント側の関連設定も含まれます。ルーティングを戻す場合はルール全体の順序を、outboundを戻す場合はプロトコルと関連するトランスポート項目を復元してください。DNSを戻す場合はアプリ独自の名前解決設定も確認します。最後に見つけた値だけを元に戻し、削除済みタグを参照するルールを残さないようにしましょう。関連項目が欠けると、新しいエラーの原因になります。

最後に、変更の目的、対象項目、検証方法、結果を簡潔に記録してください。アカウント情報を含める必要も、毎回のログ全体を保存する必要もありません。次に似た問題が起きたときは、検証済みの基本設定を使い、新しく追加した部分を比較しましょう。初めて利用する場合はチュートリアルへ、よくある接続の問題は接続トラブルのQ&Aをご覧ください。このページは項目と処理の関係を確認するためのリファレンスです。実際の問題に応じて該当する章を参照してください。