この記事の概要

「クライアントは起動しているのに、リクエストに失敗する」という方に向けた解説です。クライアントログ、コアのエラーログ、アクセスログを区別し、ローカルの待ち受け、DNS、リモート接続、TLS、プロトコル認証の順に確認します。エラーは原因を探る手掛かりであり、結論そのものではありません。最も内側の原因を読み取り、該当する設定項目を変更しましょう。何度も再インストールするより効果的です。

1. まずログの種類を見分け、リクエストを1回再現する

v2rayNはクライアントで、V2RayまたはXrayが接続を処理するコアです。サブスクリプションのダウンロード失敗や画面設定の保存失敗はクライアント側の問題です。一方、待ち受けポートの起動失敗やプロキシのハンドシェイク失敗は、通常コア側で発生します。Android版のv2rayNGはXrayコア、v2flyNGはV2Flyコアを使用します。コアやバージョンによってログの表現は異なるため、ログ全体をそのまま検索しても答えが見つかるとは限りません。

コアのログには、アクセスログとエラーログがあります。アクセスログでは、リクエストがインバウンドに到達したか、どの宛先にアクセスしたか、どのアウトバウンドが選ばれたかを確認できます。エラーログでは、起動時や接続中の異常を確認できます。acceptedと表示されても、通常はリクエストがインバウンドに受け付けられたことを示すだけです。リモート接続の成功や、Webページの内容が返されたことまでは意味しません。

ローカルのインバウンド ルールの照合 アウトバウンドの選択 リモート接続 セキュアハンドシェイク プロトコル認証

上記の流れは、調査する段階を切り分けるためのものです。すべての接続で、必ず同じ順番で名前解決が行われるわけではありません。DNSの解決はルーティング判定時に行われることも、リモート側に委ねられることもあります。まずはリクエストがどの段階で失敗したかを特定し、DNS、ルーティング、ノード設定を一度に変更するのは避けましょう。

  1. 現在の設定を保存し、システム時刻、選択中のノード、実際に使用しているコアを記録します。
  2. クライアントのログ画面を開き、サブスクリプション更新の通知だけでなく、コアの実行ログが表示されていることを確認します。
  3. ほかのアプリからのネットワークリクエストを一時的に止め、決まった宛先にアクセスして、失敗を1回だけ再現します。
  4. 失敗の前後を含む連続したログを保存し、時刻、宛先アドレス、接続IDを手掛かりに同じリクエストを特定します。

2. loglevelの選び方:普段はwarning、調査中だけdebug

log.loglevelはエラーログの詳細度を制御する設定です。接続速度の設定でも、アクセスログのオン・オフでもありません。普段はwarningにしてログのノイズを抑え、問題を再現するときだけ一時的にinfoまたはdebugへ切り替えます。原因を特定したら元のレベルに戻し、ログの増え続けや接続情報の露出を防ぎましょう。

レベル記録される内容用途
debugデバッグ情報と、それ以上の重大度のメッセージ複雑な接続問題を短時間で再現するとき
info通常の動作情報、警告、エラー起動、接続、処理の状況を確認するとき
warning警告とエラー通常運用で一般情報を減らしたいとき
errorエラー明確な失敗情報だけを記録
noneエラーログの出力を無効化トラブルの原因を調べているときには不向き

以下はV2Ray形式の設定におけるトップレベルのlogオブジェクトの例で、実行可能な設定ファイル全体ではありません。GUIクライアントでは、ログ設定画面から変更するのが基本です。クライアントが生成する設定ファイルは、次回起動時に上書きされる場合があります。ファイルとコンソールのどちらに出力されるかは、ログの出力先設定やクライアント側の出力取得方法にも左右されます。

{
  "log": {
    "loglevel": "debug"
  }
}

3. connection refusedとポート競合:まず接続先がどちら側か確認

connection refusedは接続が明示的に拒否されたことを示します。接続先ポートでサービスが待ち受けていない場合や、ファイアウォールが接続を拒否した場合によく発生します。まずエラーに記載されたIPアドレスとポートを確認してください。127.0.0.1ならローカルの入口を、ノードのサーバーを指しているならリモート側のサービスを調べます。この2つを混同すると、ノード設定を変更してもローカルプロキシに接続できないままになります。

エラー:connect: connection refused

原因:そのTCP接続が接続先から拒否されています。このメッセージだけでアカウントが無効だとは判断できません。

対処:同じ行にある接続先アドレスとポートを確認します。ローカルアドレスならコアが起動しているか、リモートアドレスならノードのポートとサービスの待ち受け状態を確認してください。

エラー:bind: address already in use

原因:コアが待ち受けアドレスをバインドできません。通常、そのアドレスとポートを別のプロセスがすでに使用しています。

対処:ポートを使用しているプロセスを特定し、重複して起動したプロセスを終了するか、ローカルの待ち受けポートを変更します。変更後はアプリのプロキシアドレスも合わせて更新してください。

以下の数値は一般的な設定例であり、現行バージョンの固定された初期値ではありません。HTTPとSOCKSを1つの混合ポートで受け付ける設定もあります。実際の待ち受け項目は、クライアントに表示される内容を確認してください。リモート側のポートが443でも、TLSを使うサービスだとは限りません。

10808
ローカルSOCKSポートの例
10809
ローカルHTTPポートの例
443
リモートTLSポートの例

Windowsでは、次のコマンドでこの2つのローカルポートを調べられます。出力の最終列はPIDです。TCPの行がLISTENING状態かどうかを確認してください。その後、タスクマネージャーの「詳細」タブでプロセス名を確認し、見覚えのないプロセスをポート番号だけで終了しないようにしましょう。

netstat -ano | findstr ":10808"
netstat -ano | findstr ":10809"

4. timeoutとDNSエラー:最も具体的な原因から判断

i/o timeoutは読み書きが待ち時間を超えたことを示し、context deadline exceededは処理が期限を超えたことを示します。どちらも「ノードが使えなくなった」と直接示すものではありません。DNS問い合わせ、TCP接続、TLSハンドシェイク、応答待ちなど、さまざまな段階でタイムアウトが起きる可能性があります。エラーの連鎖をたどって最も具体的な子エラーを確認し、どのアドレスへの、どの段階の処理でタイムアウトしたかを特定しましょう。

エラー:dial tcp ...: i/o timeout

原因:前後のログからTCP接続の段階だと分かる場合、期限内に接続が確立できなかったことを示します。ルーティング、パケットロス、フィルタリング、リモートへの到達不能などが考えられます。

対処:リモートのアドレスとポートを確認し、現在のネットワークと別の利用可能なネットワークでそれぞれテストします。待ち時間を延ばすだけで問題を隠さないようにしてください。

エラー:no such host

原因:ドメイン名を解決できず、有効な結果が得られていません。ドメイン名の誤記、レコードの欠落、名前解決経路の異常などが考えられます。

対処:エラーに表示されたドメイン名がノードのアドレスかアクセス先かを確認し、それぞれに対応するリゾルバーとDNSレコードを調べてください。

エラー:failed to find an available destination

原因:アウトバウンドの選択または接続に失敗したことを示す上位レベルのメッセージです。この一文だけでDNS障害だとは断定できません。

対処:続くログに記録された詳細な原因を確認します。名前解決エラーならDNS、接続タイムアウトならリモートへの到達性、接続拒否なら待ち受けサービスを調べてください。

たとえば、ブラウザーでアクセスに失敗し、ログにはノードのドメイン名の名前解決エラーだけが記録されている場合、ノードへの接続はまだ確立していません。アクセス先サイトのルーティングルールを先に変更する必要はありません。反対に、ノードには接続できていて特定の宛先ドメインだけ失敗する場合は、その宛先の名前解決とルーティング結果を確認します。

  1. ノードのaddressがドメイン名かIPアドレスか、またポートがサーバー側と一致しているかを確認します。
  2. システムの名前解決コマンドを実行し、ローカルで正常に解決できるかを確認します。Windowsではnslookupの後に実際のノードのドメイン名を指定します。
  3. システムの問い合わせが成功しても、コアのDNS解決が成功するとは限りません。dns.servers、リゾルバーへの到達性、関連するルーティングを確認してください。
  4. 変更する項目は一度に1つにし、変更前後のエラーを記録します。どの設定が効果をもたらしたのか判断できなくなるのを防げます。

5. TLSハンドシェイク失敗:時刻、証明書名、通信設定を確認

TCP接続が成功したことは、リモートのポートに接続できたという意味にすぎません。その後のTLS接続は、証明書、サーバー名、プロトコルのネゴシエーションが原因で失敗する場合があります。streamSettings.securityがサーバーの要件と一致しているか確認してください。通常のTLSを使用している場合は、tlsSettings.serverNameも確認します。サーバーアドレスと証明書名が異なる構成もありますが、サーバー側の設定に合っている必要があります。

エラー:x509: certificate has expired or is not yet valid

原因:システム時刻が正しくないか、サーバー証明書の有効期間外です。

対処:まずシステムの日付、時刻、タイムゾーンを合わせます。時刻に問題がなければ、サーバー管理者に証明書の更新状況と実際の設定を確認してもらってください。

エラー:x509: certificate signed by unknown authority

原因:クライアントが証明書チェーンを信頼されたルート証明書まで検証できていません。サーバー証明書チェーンの不足や、ローカルの証明書環境が原因の可能性があります。

対処:証明書チェーン全体とシステムの証明書環境を確認してください。検証を無効にする設定を、普段の解決策として使わないでください。

エラー:remote error: tls: handshake failure

原因:リモート側がTLSハンドシェイクを拒否しています。このメッセージだけでは原因を特定できません。

対処:サーバー側の設定と照らし合わせてSNI、TLS設定、ポートを確認します。必要に応じて、同じ時刻のサーバーログも確認してください。

TLS接続に成功しても、その後の通信や認証でエラーが発生することがあります。WebSocketのpathやリクエストのHost、gRPCのserviceNameは、サーバー側の設定と一致している必要があります。websocket: bad handshakeは、パス、Host、リバースプロキシの転送設定、通信方式の不一致などでよく発生し、証明書の問題とは限りません。

6. ログから設定項目を特定する:失敗した段階に合わせて変更

設定項目は、障害が発生した段階に合わせて確認します。起動時に待ち受けエラーが出るなら、まずインバウンドを確認します。リモート接続の失敗なら、アウトバウンドの接続先を確認します。リクエストが誤った経路に進むなら、ルーティングタグを確認してください。以下は一般的なV2Ray形式のJSONを例にした対応表です。実際の構造は使用するコアとクライアントの設定に従ってください。

ログで確認した現象優先して確認する項目確認するポイント
起動時にバインドに失敗するinbounds[].listen、inbounds[].portアドレスがローカルのものか、ポートが使用中か
アプリからローカルの入口に接続できないinbounds[].protocolアプリで使うHTTPまたはSOCKSの種類が一致しているか
リモート接続が拒否される、または接続がタイムアウトするoutbounds[].settingsのアドレスとポートノード情報、リモート側の待ち受け、ネットワーク経路
ドメイン名の名前解決に失敗するdns.serversと関連する名前解決ポリシーDNSレコード、リゾルバーへの到達性、名前解決トラフィックの経路
証明書名またはTLSハンドシェイクに問題があるstreamSettings、tlsSettings.serverNameセキュリティ方式、SNI、証明書、システム時刻
リクエストが誤ったアウトバウンドに入るrouting.rules[].outboundTag、outbounds[].tagルールの順序とタグの対応が正しいか

VMess、VLESS、Trojan、Shadowsocksでは認証に使う設定項目が異なります。プロトコル認証の段階まで進んでいることを確認してから、UUID、パスワード、暗号化方式を調べてください。すべてのエラーを「パスワードが違う」と決めつけるのは避けましょう。EOFが繰り返し発生しても、読み取り中に接続が終了したことを示すだけです。ハンドシェイクの前かデータ転送の後かを確認して判断してください。

7. ログ調査でよくある質問

ログが空白です。リクエストがプロキシに届いていないのでしょうか?

まずコアが実行中であること、エラーログのレベルがnoneではないこと、現在の画面にコアの出力が表示されていることを確認します。異常がなければ、エラーログに新しい内容が記録されない場合もあります。リクエストが入口に届いているか確認するには、一時的にアクセスログを表示し、アプリのプロキシアドレスと実際の待ち受けポートを照合してください。

ブラウザーでは開けるのに、ターミナルでは接続エラーが続くのはなぜですか?

ターミナルがシステムプロキシを使うとは限りません。ターミナルのプロキシ環境変数が、待ち受け中のアドレスを指しているか確認し、プロトコルも照合してください。たとえば、10809がHTTPの入口として実際に待ち受けている場合に限り、http://127.0.0.1:10809を指定します。対応するリクエストがログにない場合は、アプリからローカルの入口までの経路を先に調べてください。

v2rayNGが画面消灯後に通信できなくなり、ログにTLSエラーもありません。どうすればよいですか?

まずAndroidのVPN接続が維持されているか、クライアントのプロセスが停止していないかを確認し、アプリのバッテリー使用量とバックグラウンド実行の権限も調べてください。コアがシステムによって終了された場合、ログが途中で途切れることがあります。これはリモート側の証明書障害とは異なります。バックグラウンド制限を調整した後、画面をロックして再テストし、停止した時刻を記録してください。

debugログを共有する前に、何を削除すればよいですか?

サブスクリプションURL、UUID、パスワード、アクセストークンのほか、公開したくないサーバーアドレス、アクセス先ドメイン、個人用パスを削除してください。コアの種類、エラーのキーワード、ポートの用途、ログの前後関係は残します。アドレスは「ノードアドレス」や「宛先アドレス」に置き換え、末尾だけを切り取ったスクリーンショットにしないでください。