サブスクリプションをインポート済みで、config.jsonを詳しく読みたいMacユーザー向けです。まず、ローカルの受信設定、直接接続、ブロックだけを含む完全な設定例で全体像をつかみ、ポート、出力タグ、ルールの順序、DNSを確認します。ポート番号は説明用に指定した値で、すべてのクライアントの初期設定を示すものではありません。
config.jsonとv2rayNの設定の違い
config.jsonはコアが読み込む設定ファイルで、v2rayNはノード、サブスクリプション、実行状態を管理するデスクトップクライアントです。両者は役割の異なる階層にあります。クライアントは画面上の設定をコアの実行設定に変換したり、カスタム設定を管理したりできます。config.jsonという名前のファイルを見つけても、それだけで現在のプロセスが読み込んでいるファイルとは判断できません。
この記事では、V2Rayの従来型JSON設定を使用します。XrayとV2Rayには共通する項目がありますが、対応プロトコルや個々のパラメーターは完全には一致しません。設定を読む前に、クライアントの実行ログで使用中のコア、設定ファイルのパス、起動エラーを確認してください。一方のコア向けのプロトコル設定を、もう一方にそのまま貼り付けないでください。
この流れから、システムプロキシの役割も分かります。システムプロキシ設定に従うアプリのリクエストを、ローカルの受信設定へ送る仕組みです。コアを単独で起動しても、すべてのアプリが自動的にこの経路を使うわけではありません。システムプロキシを参照しないアプリでは、アプリ独自のプロキシ設定など、明示的な接続方法が必要です。
inbounds:リクエストを受け付け、待ち受けアドレス、ポート、ローカルプロキシプロトコルを指定します。outbounds:リクエストの処理方法として、直接接続、プロキシサーバー、ブロックを指定します。routing:ルーティング先を選び、条件に一致したリクエストを指定したタグの出力へ渡します。logとdnsは、それぞれログとコアのDNS動作を設定します。前述の3項目とは役割が異なります。
設定例:2つの受信設定と2つの出力設定
以下は、ローカル環境で設定構造を理解するための例です。SOCKSとHTTPの2つの受信口があり、デフォルトでは直接接続し、例として挙げたexample.comとそのサブドメインをブロックします。リモートプロキシサーバーは設定されていないため、サブスクリプションのノード設定としては使えません。テスト前に、2つのポートが起動中のクライアントに使用されていないことを確認してください。
{
"log": {
"loglevel": "warning"
},
"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": "blocked",
"protocol": "blackhole",
"settings": {}
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"domain:example.com"
],
"outboundTag": "blocked"
},
{
"type": "field",
"ip": [
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16"
],
"outboundTag": "direct"
}
]
}
}
最上位から見ると、受信設定、出力設定、ルールはいずれも配列です。角括弧内には複数のオブジェクトを記述でき、オブジェクト同士はカンマで区切ります。最後の項目の後にカンマは付けません。一般的なJSONツールとの互換性を保つため、保存時は二重引用符を使い、コメントを入れず、ポートを引用符付きの文字列にしないでください。
inbounds:待ち受けアドレス、ポート、受信タグ
listenは接続を受け付けるネットワークインターフェースを指定します。例では127.0.0.1を使い、ローカルマシンからのみ接続できるようにしています。0.0.0.0に変更すると、すべてのIPv4インターフェースで待ち受けます。ただし、それだけで他のデバイスからアクセスできるわけではなく、ファイアウォール、ネットワーク分離、認証も考慮が必要です。ローカルで使う場合は、ループバックアドレスで待ち受けるとアクセス範囲を管理しやすくなります。
SOCKS受信設定
- タグ
local-socks- 待ち受け
127.0.0.1:10808- プロトコル
socks- 認証
noauth、ローカルでのみ使用- UDP
false、この例では無効
アプリ側でSOCKSプロキシを選択してください。このポートをHTTPプロキシのポートとして入力することはできません。
HTTP受信設定
- タグ
local-http- 待ち受け
127.0.0.1:10809- プロトコル
http- パラメーター
settings: {}
HTTPプロキシリクエストとCONNECTトンネルリクエストを受け付けます。受信口自体がTLS暗号化で待ち受けるわけではありません。
macOSでは、「システム設定」→「ネットワーク」→現在のネットワーク接続→「詳細」→「プロキシ」でアドレスとポートを確認できます。この例のHTTP受信設定を使う場合は、必要に応じてWebプロキシとセキュアWebプロキシの接続先を127.0.0.1:10809にします。SOCKS受信設定を使う場合のポートは10808です。トラブルシューティング中は必要な方式だけを有効にし、複数の設定が影響し合わないようにしてください。
tagはコア設定内で使う識別子であり、サーバーアドレスでも、あらゆるアプリが認識する名前でもありません。ルーティングのinboundTagでリクエストの受信元を区別できます。たとえば、あるルールをlocal-httpだけに適用し、別のルールをlocal-socksに適用すれば、受信口ごとにポリシーを設定できます。
outbounds:プロトコルが動作を決め、tagでルーティングと連携
例で使うfreedomは直接接続用の出力で、現在のデバイスから接続先に直接アクセスします。blackholeはリクエストのブロックに使います。リモートプロキシへの接続には、対応するプロトコルのサーバーアドレス、ポート、認証情報のほか、必要に応じてトランスポート設定も必要です。tagをproxyに変えただけでは、直接接続がプロキシ接続に変わることはありません。
| 項目またはプロトコル | 意味 | 確認ポイント |
|---|---|---|
tag | 出力設定の内部名 | ルールのoutboundTagと完全に一致しているか |
protocol | 出力方式の選択 | 実行中のコアがそのプロトコルに対応しているか |
settings | そのプロトコル固有のパラメーター | 異なるプロトコルに同じ構造を流用しない |
streamSettings | トランスポートとトランスポートのセキュリティ設定 | サーバー側の要件と項目ごとに一致しているか |
freedom | 接続先へ直接接続 | ローカルマシンの実際のネットワーク出口を使用 |
blackhole | 条件に一致したリクエストをブロック | 通常の通信まで誤って一致していないか |
一般的な設定では、ルーティングルールに一致しないリクエストはoutbounds配列の先頭にある出力を使います。この例ではdirectが先頭にあるため、一致しないリクエストは直接接続します。クライアントが生成した設定を読むときは、この順序が特に重要です。プロキシ出力が設定に含まれていても、ルールに一致しない通信が必ずその出力を使うとは限りません。
要点:まずデフォルトの出力を確認し、次に個別ルールを確認する
「なぜまだ直接接続になるのか」を調べるときは、まずoutboundsの先頭項目を確認し、次に一致したルールのoutboundTagを確認してください。ノード名や画面上の色から、実際の接続先を推測しないでください。
routing:最初に一致したルール、条件の組み合わせ、ドメイン戦略
routing.rulesは上から順に評価され、ルールに一致すると指定された出力が使われ、以降のルールは確認されません。そのため、明確な例外は通常、範囲の広いルールより前に置きます。配列の順序も設定動作の一部です。順序を変えると、構文エラーがなくても接続先が変わることがあります。
- 接続先が
www.example.comの場合:最初のルールのdomain:example.comがメインドメインとそのサブドメインに一致し、blockedへ渡します。 - 接続先が
192.168.1.20の場合:最初のルールには一致せず、2番目のルールがプライベートアドレス範囲に一致して、directへ渡します。 - 接続先が上記の条件に一致しない場合:どのルールにも該当しないため、最初の出力である
directを使います。
同じルール内の異なる条件項目は、通常すべて満たす必要があります。同じ項目に複数の候補値がある場合は、いずれかに一致すれば条件を満たします。たとえば、次のルールはHTTP受信設定から入り、接続先ポートが25のTCPリクエストだけをブロックします。同じポートへのリクエストでも、SOCKS受信設定からのものはすべての条件を満たしません。
{
"type": "field",
"inboundTag": ["local-http"],
"network": "tcp",
"port": "25",
"outboundTag": "blocked"
}
このオブジェクトは既存のrouting.rules配列に追加し、必要に応じて順序を調整してください。完全な設定ではありません。フィールドの型にも注意が必要です。受信設定のportは数値ですが、ルーティングルールのportは、"80,443"のようにポート番号や範囲を文字列で指定します。
AsIs:ルーティング段階で、IPルールのためにドメイン名を積極的に解決しません。リクエストの接続先がもともとIPアドレスなら、IPルールに一致することがあります。IPIfNonMatch:ドメイン名を使ったリクエストが既存の条件に一致しない場合、アドレスを解決してからルーティングを再評価します。IPOnDemand:評価中にIPアドレスが必要なルールが現れた場合、その時点でドメイン名を解決します。
geosite:やgeoip:のような条件を使う場合は、コアが対応するデータファイルを読み込めることと、指定した項目名が存在することも確認してください。この記事では、ルールの動作を外部データへの依存と切り分けて確認しやすいよう、明示的なドメイン名とCIDR範囲を使っています。routing.domainStrategyと、直接接続の出力にある同名または類似したDNS戦略の設定を混同しないでください。
DNSとsniffing:ルールが参照できる接続先情報
ドメインルールに一致するかどうかは、受信設定が受け取る接続先情報によって変わります。HTTPプロキシリクエストとCONNECTでは通常、ドメイン名が渡されます。SOCKSリクエストでは、ドメイン名のほか、アプリがすでに名前解決したIPアドレスが渡されることもあります。アプリがローカルで先に名前解決した場合、コアに届くのはIPアドレスだけかもしれません。元のドメイン名を必ず特定できるとは限りません。
curl --proxy socks5h://127.0.0.1:10808 --connect-timeout 5 https://example.com/
curl --proxy http://127.0.0.1:10809 --connect-timeout 5 https://example.com/
最初のコマンドでは、socks5hを指定することで、curlがドメイン名の解決をSOCKSプロキシに任せます。socks5に変更すると、curlはローカルで接続先を解決します。この例では対象ドメインがブロックされる想定のため、コマンドが失敗してもルールどおりの結果です。具体的なエラー表示は接続に失敗した段階によって異なります。ここでの5は接続タイムアウトの秒数であり、性能測定の結果ではありません。
dnsオブジェクトはコアのDNS機能を設定するもので、macOSのシステムDNS設定を自動的に変更するわけではありません。sniffingを使うと、一部の通信からHTTP HostやTLSのサーバー名などを識別できます。ただし、すべての接続でドメイン名を復元できるわけではありません。- sniffingの有効・無効、接続先の上書き、アプリによる事前の名前解決の有無は、いずれも最終的なルール判定に影響します。
- トラブルシューティングでは、まずプロキシの種類とテストコマンドを固定し、ログを比較しやすいよう一度に変更する条件を1つに絞ってください。
設定を変更する手順とよくあるエラーの調べ方
まずバックアップを取り、現在有効なファイルを特定してから編集してください。v2rayNは、ノードの切り替え、サブスクリプションの更新、コアの再起動時に実行設定を再生成することがあります。生成されたファイルの一時的な編集は問題の検証には使えますが、ルールを長期保存する方法としては適していません。残したい変更は、クライアントの該当設定または管理対象のカスタム設定に反映してください。
- コアとファイルのパスを確認。起動ログでコア名、読み込んだファイル、エラー行を確認します。パスに空白が含まれる場合、ターミナルのコマンドではファイルパスを引用符で囲んでください。
- JSONの構造を確認。macOSのターミナルで次のコマンドを実行します。JSONを解析するだけで、各項目がコアに対応しているかどうかは検証しません。
- 待ち受けポートを確認。
10808と10809がほかのプロセスに使われていないことを確認し、アプリの設定と一致させます。 - タグの参照先を確認。
outboundTagが既存の出力を指しているか、inboundTagが受信タグと一致しているかを項目ごとに確認します。 - 再読み込みして検証。クライアントからコアを再起動または再読み込みし、正常に起動したことを確認してから、既知のルールに一致する接続先と一致しない接続先をそれぞれテストします。
plutil -lint -s -r -- config.json
lsof -nP -iTCP:10808 -sTCP:LISTEN
lsof -nP -iTCP:10809 -sTCP:LISTEN
plutilはここではJSON構文の確認に使います。構文に問題がなくても、プロトコル名の誤り、必須パラメーターの不足、コアとの互換性が原因で起動に失敗することがあります。待ち受け確認で何も表示されなくても、設定の構文エラーとは限りません。プロセスが起動しているか、別のファイルを読み込んでいないかも確認してください。
| 症状 | まず確認する項目 | 次に行うこと |
|---|---|---|
| コアが起動直後に終了する | JSON、項目の互換性、必須パラメーター | 起動ログで最初に表示される有効なエラーを確認する |
| アドレスが使用中と表示される | 受信ポートと重複して起動したプロセス | ポートを使用しているプロセスを特定し、停止するかポートを変更する |
| ルールに一致しない | ルールの順序、接続先の形式、受信タグ | プロキシを固定したコマンドで再現し、ログと照合する |
| 再起動後に変更が消える | 生成されたファイルを編集していないか | 設定をクライアントの管理画面に移す |
| ブラウザーは使えるが、ほかのアプリは失敗する | アプリがシステムプロキシに従っているか | アプリ独自のプロキシ方式とポートを確認する |
要点:一度に変更する階層は1つだけ
まず受信設定でリクエストを受け付けられることを確認し、次に出力が利用できることを確認してから、ルーティングを調整してください。短時間だけログの詳細度を上げると調査に役立ちます。終了後は元のレベルに戻し、ログや設定を共有する前にサブスクリプションURL、認証情報、個人の接続先情報を削除してください。