V2Ray config.jsonの構造を解説:inbounds・outbounds・routingを徹底解説

log、inbounds、outbounds、routing、dnsの順にconfig.jsonを解説。各項目の役割とよく使われる設定例を紹介します。

この記事の概要

サブスクリプションをインポートしたことがあり、コアの実行設定を理解したい方に向けた解説です。アプリの入口、接続先、ルーティングの選択を整理したうえで、ローカル待ち受け・直接接続・通信遮断だけを使った完全な設定例で項目間の関係を確認します。読み終えると、ポート競合、タグの入力ミス、ルール順序の不備、DNS設定が反映されない原因を特定しやすくなります。

まず押さえる基本:config.jsonはコアの設定ファイルで、サブスクリプション一覧ではない

v2rayNはデスクトップクライアント、V2RayとXrayは接続を処理するコアです。クライアントはサブスクリプション、ノード、画面設定を保存し、選択したコアに応じて実行設定を生成します。そのため、サブスクリプション内のVMessやVLESSの共有リンクは、完全なconfig.jsonではありません。通常はリモート接続の情報のみが記載され、ローカルの入口、ログ、DNS、ルーティングルールなどは含まれていません。

この記事では、V2Rayの従来型JSON設定を使い、V2RayとXrayでよく見られる項目間の関係を説明します。V2Ray v5には別形式の設定もあるため、拡張子だけで形式を判断したり、異なる形式の項目を混在させたりしないでください。プロトコルやトランスポートの項目は、実際に使用するコアのバージョンに合わせる必要があります。

アプリからのリクエスト ローカルのinbound ルーティング判定 outboundの選択 接続先サービス

問題を調べるときは、この流れに沿って確認します。Webリクエストは、まず何らかのinboundに入らなければルーティングの対象になりません。ルーティングで指定するのはoutboundのタグであり、サブスクリプションのグループ名ではありません。DNSは名前解決や一部のルーティング判定を支えますが、すべての通信が必ず通る「プロキシ出口」ではありません。

log:確認できる情報を把握してから接続設定を調整

logはトップレベルにあり、ログ出力を制御します。トラブルの調査中はまずinfoを使い、解決後は通常warningに戻します。最初からdebugを有効にすると詳細なログが大量に出力され、単純なポート競合の情報が埋もれるおそれがあります。

{
  "log": {
    "loglevel": "info"
  }
}

これは項目の抜粋であり、実行に必要な設定一式ではありません。一般的なログレベルはdebug、info、warning、error、noneです。ここではログファイルのパスを指定せず、まず端末やクライアントのログ画面で起動結果を確認できるようにしています。accessやerrorの出力先を設定する場合は、対象ディレクトリが存在し、実行ユーザーに書き込み権限があることを確認してください。

inbounds:アプリはどのアドレス・ポートから接続するか

inboundsは配列で、1つの設定でSOCKSとHTTPのプロキシリクエストを同時に受け付けられます。listenは待ち受けアドレス、portはローカルポート、protocolはアプリが接続に使うプロキシプロトコルを指定します。いずれもリモートノードのアドレスやポートではありません。

10808
この記事で使うSOCKSのinboundポート
10809
この記事で使うHTTPのinboundポート
127.0.0.1
ローカルからのみ接続できる待ち受けアドレス

ここで示すポートは、この記事で明示的に指定した値であり、すべてのクライアントバージョンのデフォルト値ではありません。v2rayNがすでにいずれかのポートを使用している場合、テスト用コアは同じポートを再度バインドできません。使用中のプロセスを停止するか、設定とテストコマンドのポートを両方変更してください。片方だけを変更しないようにします。

SOCKS inbound

tag
local-socks
listen
127.0.0.1
port
10808
protocol
socks
settings
authはnoauth、udpはfalse

この例ではTCPのみをテストします。UDP転送を無効にしても、通常のHTTPS接続には影響しません。

HTTP inbound

tag
local-http
listen
127.0.0.1
port
10809
protocol
http
settings
空のオブジェクト。inboundのデフォルト設定を使用

HTTPSサイトでは通常、HTTPプロキシのCONNECTメソッドを使ってトンネルを確立します。

ローカルアプリのHTTPプロキシには127.0.0.1:10809、SOCKS5プロキシには127.0.0.1:10808を設定します。ポート番号だけを見て、異なるプロトコルを入れ替えてはいけません。待ち受けアドレスを0.0.0.0にすると、接続可能な範囲が広がります。アクセス制御やファイアウォールの制限がない状態で、認証なしのプロキシを他の端末から到達可能なネットワークに公開しないでください。

outbounds:出口タグと接続プロトコルは別のもの

outboundsも配列です。tagは設定内で参照する名前で、実際の送信方式はprotocolで決まります。タグをproxyと名付けても、自動的にプロキシ機能が有効になるわけではありません。プロトコルがfreedomなら、接続は直接行われます。

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

この2つのoutboundにはリモートアカウントは不要です。freedomはローカルのネットワークを使って接続先に直接接続し、blackholeは該当する通信を破棄します。この記事の設定にはロードバランサーなどの追加設定がないため、どのルールにも一致しない通信には配列の先頭にあるoutboundが使われます。したがって、デフォルトの出口はdirectです。

結論:出口を変更する前に、タグが指すプロトコルを確認

「ルールに一致したのにローカル回線で接続される」場合は、まず該当するoutboundのprotocolを確認します。freedomなら出口の設定を修正してください。ドメインの一致条件を何度も変更しても解決しません。

routing:上から順に照合し、タグの参照先を確認

routing.rulesは上から順に評価され、最初に一致したルールで通信先が決まります。よく使われる条件は、ドメインのdomain、宛先IPのip、ポートのport、inboundタグのinboundTagです。1つのルールに異なる種類の条件を指定した場合、通常はすべてを満たす必要があります。同じドメイン一覧に含まれる複数の項目は、いずれかが一致すれば候補になります。

{
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "domain": ["full:blocked.example"],
        "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"
      }
    ]
  }
}

full:blocked.exampleはこの完全一致のドメインだけを対象にします。domain:example.orgは該当ドメインとそのサブドメインに一致します。この記事では予約済みのサンプルドメインを使って遮断をテストし、実在サイトへの依存を避けています。ルールのoutboundTagは、定義済みのblockまたはdirectに対応させ、英字の大文字・小文字も一致させてください。

domainStrategy照合の動作設定を読む際のポイント
AsIsリクエストに含まれる宛先情報を使って照合し、ルーティングのためにドメインを自動で名前解決しないドメイン宛てのリクエストが、名前解決後のIPルールに自動で一致するとは限らない
IPIfNonMatchドメインがルールに一致しない場合、名前解決後にIPルールとの照合を試みるDNSの結果と、名前解決によって追加される可能性がある待ち時間を確認
IPOnDemandルーティングの照合にIP情報が必要な場合に名前解決するIPルールの配置によって、早い段階で名前解決が行われる場合がある

この例ではAsIsを使うため、192.168.1.1への直接リクエストはプライベートIPルールに一致します。一方、プライベートアドレスに解決されるドメインへのアクセスは、このルールだけを理由にルーティングで名前解決されることはありません。直接接続の確立時にドメインの名前解決が必要になる場合はありますが、これはoutboundの接続処理であり、ルーティングの判定方式とは別のものです。

dns:組み込みリゾルバーがすべてのDNSリクエストを処理するわけではない

トップレベルのdnsで組み込みリゾルバーを設定します。ルーティングでドメインに対応するIPが必要な場合や、outboundの設定で組み込みの名前解決結果を使う場合に、該当する処理で利用されます。dns.serversを書くだけでは、ブラウザーの暗号化DNSやシステム全体の名前解決を自動で引き受けることはありません。また、ローカルのDNS待ち受けポートが新たに作られるわけでもありません。

{
  "dns": {
    "servers": ["localhost"]
  }
}

ここでのlocalhostは、システムの名前解決機能を呼び出す特殊な値です。127.0.0.1:53でDNSサーバーを稼働させる必要があるという意味ではありません。この記事では例を簡潔にするために使用していますが、DNSを分離する方法として使うものではありません。特定の出口経由で名前解決したい場合は、コアのDNS動作、関連するルーティング、outboundのドメイン解決方式をあわせて確認してください。

  1. まずアプリから何が渡されるか確認:HTTPプロキシのCONNECTリクエストには通常ドメイン名が含まれます。SOCKSリクエストにはドメイン名が含まれる場合と、アプリが解決済みのIPが含まれる場合があります。
  2. 次にルーティングで名前解決するか確認:routing.domainStrategyで、ルーティング時にドメインをIPに変換するタイミングを指定します。
  3. 最後にoutboundの接続方法を確認:freedomの名前解決方式はoutbound側の設定です。ルーティング側にある同名の項目とは別の階層に属します。項目を誤った階層にコピーしないでください。

たとえばcurlでsocks5://127.0.0.1:10808を使うと、通常はcurlがローカルで宛先を名前解決します。socks5h://127.0.0.1:10808では、ドメイン名がSOCKSプロキシ側に渡されます。ドメイン別ルーティングをテストするときは、後者を使うのがおすすめです。前者ではコアにIPアドレスしか渡らず、ドメインルールが照合されない場合があります。

完全な設定例:直接接続と遮断で5つのトップレベル項目を確認

以下は従来型JSON形式の完全な設定例です。ローカル向けのHTTP・SOCKS入口と、直接接続・遮断のoutboundのみを設定しています。リモートプロキシノードは含まれておらず、ローカル環境から直接接続できないWebサイトにアクセスできるようになるわけではありません。まず設定の構造、ポートの待ち受け、ルールの参照関係を確認し、その後で実際のノード情報を追加するための例です。

{
  "log": {
    "loglevel": "info"
  },
  "inbounds": [
    {
      "tag": "local-socks",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": false
      }
    },
    {
      "tag": "local-http",
      "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": [
      {
        "type": "field",
        "domain": ["full:blocked.example"],
        "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"
      }
    ]
  },
  "dns": {
    "servers": ["localhost"]
  }
}

JSONオブジェクトのトップレベル項目の記述順は、処理順には影響しません。この記事では読みやすさを考慮して並べています。動作を左右するのは、ルール配列の順序、デフォルトoutboundの位置、項目間の参照関係です。UTF-8で保存し、キー名と文字列には半角の二重引用符を使います。最後の項目の後にカンマを付けず、説明用のコメントをファイルにコピーしないでください。

検証の手順:構文・起動・inbound・ルーティングを分けて確認

完全な設定例を、現在のディレクトリにあるconfig.jsonとして保存します。以下ではLinuxの端末を例に、まずJSONの構文を確認し、次に実際のコアで設定を検証します。構文チェックに通っても、JSONを解析できることがわかるだけで、プロトコル項目、ファイル依存関係、ネットワーク接続が正しいとは限りません。

python3 -m json.tool config.json > /dev/null

# Xrayを使う場合に実行
xray run -test -config config.json

# このコマンド形式に対応したV2Ray v5を使う場合に実行
v2ray test -c config.json

2つのコア検証コマンドは、実際に使用しているコアに応じてどちらか一方を実行してください。テストのために両方のサービスを同時に起動しないでください。旧バージョンでは実行ファイルのサブコマンドが異なる場合があります。まずxray helpまたはv2ray helpで確認してください。検証に成功したら、そのバージョンに対応した実行コマンドで同じファイルを読み込みます。たとえばXrayではxray run -config config.jsonを使用します。

# 別の端末でTCPの待ち受けを確認
ss -lntp 'sport = :10808 or sport = :10809'

# HTTP inbound経由で直接接続のoutboundをテスト
curl --noproxy "" --proxy http://127.0.0.1:10809 --max-time 15 -I https://example.org/

# ドメイン名をSOCKS inboundに渡して遮断ルールをテスト
curl --noproxy "" --proxy socks5h://127.0.0.1:10808 --max-time 5 -I https://blocked.example/

1つ目のcurlが成功するかどうかは、ローカルネットワーク、システムの名前解決、接続先サイトに左右されます。プロキシノードの速度テストではありません。2つ目のリクエストは、宛先ドメインがblockに一致するため、接続先からHTTPレスポンスを取得できない想定です。具体的なエラー内容はコアや接続段階によって異なるため、ログも確認してください。一度タイムアウトしただけで、ルーティングが機能したと判断しないでください。

結論:一度に確認するのは1つの段階だけ

まず待ち受けが存在することを確認し、次に明示的なプロキシ指定でリクエストがコアに届くことを確かめ、最後にログで出口を確認します。これにより「アプリがプロキシを使っていない」問題と「プロキシに届いた後のルールが正しくない」問題を切り分けられます。ポート、DNS、ノードを同時に変更して、新たな混乱を招くことも避けられます。

  1. 接続が拒否される:プロセスが起動しているか、待ち受けアドレスとポートが一致しているか確認します。まずはリモートノードの設定を調べる必要はありません。
  2. inboundにリクエストが届くが、出口が違う:ルールの順序、リクエストに含まれるのがドメインかIPか、デフォルトoutboundの位置を確認します。
  3. ルールは正しいのに接続できない:次に名前解決の結果、宛先への到達性、リモート認証、トランスポートのセキュリティ設定を確認します。
  4. 再起動後に変更が消える:手動で管理している設定を変更したのか、クライアントが生成した一時的な実行ファイルを変更したのか確認します。クライアントを利用している場合は、使い方ガイドで該当する設定画面を確認してください。

この構造を理解すると、v2rayNが生成した設定も読み解きやすくなります。まずinboundのポート、次にデフォルトoutbound、続いてルール、最後にDNSが実際に使われる箇所を確認します。プラットフォームへのインストールやコアの準備手順を確認する場合は、総合ドキュメントもご覧ください。最初からすべての高度な項目を1つのファイルに詰め込む必要はありません。

v2rayN をダウンロード