V2RayのTLSハンドシェイク失敗・証明書エラー対策|時刻同期、SNI、allowInsecureの確認

証明書の期限切れやx509エラー、ハンドシェイクのタイムアウトは、端末の時刻ずれ、SNIと証明書名の不一致、指紋設定が原因のことがあります。原因別の確認方法と設定手順を解説します。

この記事の要点

v2rayN、v2rayNG、v2flyNGのTLS接続トラブルを対象に、ログから証明書検証エラーと接続タイムアウトを切り分け、端末の時刻、ノードのSNI、サーバー証明書チェーン、指紋設定を確認します。変更は一度に1項目だけにし、接続復旧後も証明書検証を有効にしてください。REALITYを使うノードでは専用の認証パラメーターを確認し、通常のTLS向け対処法をそのまま適用しないでください。

まず確認:TLSエラーはどの段階で発生するか

TLSハンドシェイクは、接続確立後、プロキシプロトコルの認証前に行われます。VMessとVLESSはプロキシプロトコル、TLSは通信を保護するレイヤーで、別々の仕組みです。ノードが選択済みでコアが正常に動作していても、ローカルアプリが起動していることを示すだけで、接続先の証明書検証に成功したとは限りません。選択中のノードで「トランスポートのセキュリティ」がTLSかREALITYかを確認してから、この記事の手順が当てはまるか判断してください。

サーバーを名前解決接続先ポートへ接続TLSネゴシエーション証明書を検証プロキシプロトコル認証

v2rayNのメイン画面にあるログ欄で、失敗したリクエストの時刻を探し、外側の「接続失敗」だけでなく、最も内側にある原因をコピーしてください。v2rayNGとv2flyNGでは、サイドメニューから「ログ」を開いて確認できます。バージョンによってメニュー名が多少異なることがあります。クライアントのバージョン、コアの種類、ノードのセキュリティ方式、エラーの全体を記録してください。ログを共有する前に、サブスクリプションURL、ユーザー識別情報、認証情報を隠してください。

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

原因と対処:端末の現在時刻が証明書の有効期間外です。まず端末の時刻を合わせてください。時刻が正しければ、サーバー管理者に証明書の期限切れがないか、更新後の証明書が読み込まれているか確認してもらいます。

エラー:x509: certificate signed by unknown authority

原因と対処:証明書チェーンを信頼されたルート証明書までたどれません。サーバーが中間証明書を送信しているか確認し、自己署名証明書、古い信頼ストア、ネットワーク上のTLS検査装置も確認してください。

エラー:context deadline exceeded

原因と対処:制限時間内に処理が完了しなかったことを示します。このログだけで証明書の問題とは断定できません。前後のログも確認し、名前解決、接続先ポート、ハンドシェイクの状況を調べてください。

時刻を同期して、端末側の有効期間判定を確認

証明書には有効期間の開始日時と終了日時が記録されています。端末の年、日付、または実際のシステム時刻が間違っていると、正常な証明書が「まだ有効ではない」または「期限切れ」と判定されます。画面上のタイムゾーンだけを変更しても、実際の時計のずれは直りません。タイムゾーンは時刻の表示方法を決めるもので、証明書検証では実際の時刻が使われます。

  1. 日付を確認

    Windowsでは「設定」→「時刻と言語」→「日付と時刻」を開き、年、月、日、タイムゾーンを確認します。明らかな誤りを直してから、インターネット経由で同期してください。

  2. 時計を同期

    「時刻を自動的に設定する」を有効にし、「その他の設定」または「時計を同期する」から「今すぐ同期」をクリックします。Androidではシステムの「設定」→「日付と時刻」を開き、「日時を自動的に設定」を有効にします。機種によっては「システム」内にあります。

  3. 同期結果を確認

    Windowsでは、最後に同期に成功した時刻を確認します。同期に失敗する場合は、管理者権限のターミナルで次のコマンドを実行し、時刻サービスを確認してください。ネットワークで時刻同期の通信が許可されていない場合は、先にネットワークまたはサービスの状態を確認する必要があります。

  4. 再接続

    現在の接続を切断し、同じノードで再接続して新しいリクエストを1回送信します。新しいログのタイムスタンプを確認し、ログ欄に残っている過去のエラーで変更結果を判断しないでください。

w32tm /query /status
w32tm /resync

上記のコマンドはWindowsの時刻サービス用で、プロキシコアのコマンドではありません。サービスが起動していないと表示された場合は、システムの「サービス」で「Windows Time」を確認してください。組織のポリシーで管理されているPCでは、管理者が指定した時刻ソースを使用します。再起動のたびに日付が戻る場合は、ノードを何度も変更するのではなく、デバイスの時計保持機能とシステムの時刻設定を確認してください。

SNIの設定:接続先アドレスと証明書のドメイン名は別

ノードの「アドレス」は接続先サーバーを決め、「ポート」は接続するサービスを決めます。SNIは通常、コアのserverNameフィールドで指定し、TLSの仮想ホスト選択と証明書名の検証に使われます。接続先がIPアドレスでも、SNIにドメイン名を指定できます。接続先のサービスがそのドメインに対応する証明書を提供していれば、問題のない組み合わせです。

  • アドレス:サブスクリプションまたはサーバー設定で指定されたホスト名やIPアドレスを入力します。SNIと安易に入れ替えないでください。
  • ポート:ノード設定に記載された値を入力します。443は一般的なTLSポートですが、必須ではありません。すべてのノードを443に変更しないでください。
  • SNI / serverName:サーバーが指定する証明書のドメイン名を入力します。たとえば説明にexample.comとあればその形式です。これは形式を示す例であり、実際の値はノード設定に従ってください。
  • 入力形式:ホスト名だけを入力します。https://、パス、クエリパラメーター、:443は付けません。
  • 証明書の適用範囲:現在の検証では通常、証明書のSANを確認します。ワイルドカード*.example.comは一般にa.example.comには一致しますが、ルートドメインのexample.comやa.b.example.comには一致しません。

v2rayNのメイン画面で対象ノードをダブルクリックして編集画面を開き、「トランスポートのセキュリティ」にあるTLS設定で「SNI」または「serverName」を確認します。v2rayNGとv2flyNGでは、ノード編集画面の同名フィールドを確認してください。バージョンによって、どちらか一方の名称だけが表示されることがあります。WebSocketの「Host」をSNIと混同しないでください。前者はHTTPリクエストヘッダー、後者はTLSハンドシェイクで使われます。

証明書チェーンとハンドシェイクのタイムアウト:名前、信頼性、ポートを個別に確認

名前の不一致と不明な認証局は別の問題です。前者ではSNIが証明書のSANに含まれているかを確認し、後者では証明書チェーンが完全か、認証局が現在の環境で信頼されているかを確認します。同じドメインのWebページをブラウザーで開けても、プロキシ接続が正常とは限りません。ブラウザーは異なるポートやアドレスに接続している場合があり、信頼ストアや証明書チェーンの補完方法も異なることがあります。

ログの手がかり優先して確認する項目確認・対処する場所
expired / not yet valid実際のシステム時刻、証明書の有効期間端末の時刻設定、サーバーの証明書配置
certificate is valid for…not…SNIと証明書のSANが一致しているかノードのTLS設定、サーバーの仮想ホスト
unknown authority中間証明書、ルート証明書への信頼、自己署名証明書サーバーが送信する完全な証明書チェーン、管理対象の信頼設定
handshake failureTLSパラメーター、クライアント指紋、サーバー側のポリシーノードのトランスポート設定、サーバーのハンドシェイクログ
timeout / deadline exceeded名前解決、ポートへの到達性、パケットロス、サービスの応答ネットワーク経路、接続先の待ち受け状態とファイアウォール

WindowsではPowerShellで接続先のTCPポートを確認できます。以下のドメイン名とポート番号はコマンド形式の例です。実際に使用するノードのアドレスとポートに置き換えてください。TcpTestSucceededがTrueでも、TCP接続の成功を示すだけで、証明書、SNI、プロキシ認証が正しいとは限りません。

Test-NetConnection -ComputerName example.com -Port 443

OpenSSLがインストールされた環境では、接続先から送信される証明書チェーンを確認できます。コマンドの接続先とSNIは異なっていても構いません。それぞれノードの「アドレス」と「serverName」に対応します。次の例では両方に説明用のドメイン名を設定し、名前の検証も明示的に有効にしています。

openssl s_client -connect example.com:443 -servername example.com -showcerts -verify_hostname example.com -verify_return_error
  • 返された証明書のSAN、有効期間、検証エラーを確認してください。証明書が出力されたというだけで成功と判断しないでください。
  • サーバー側で証明書を更新しても古い証明書が返る場合は、証明書ファイルのパスを確認し、TLSを終端するサービスで設定を再読み込みしてください。
  • OpenSSLとプロキシコアでは、異なるルート証明書ストアを使うことがあります。ツールの結果は原因の切り分けに利用し、最終的にはクライアントで再テストしてください。

指紋とREALITY:2つの対処法を混同しない

クライアント指紋はClientHelloの見え方に影響しますが、証明書名の誤り、証明書の期限切れ、中間証明書の不足は解決しません。Xrayの関連機能がV2Flyと完全に同じとは限りません。v2rayNGはXrayコア、v2flyNGはV2Flyコアを使用するため、画面にTLS設定があるというだけで、すべてのパラメーターが共通だと判断しないでください。

  • 通常のTLSノード:まずサブスクリプション本来の指紋設定に戻します。サーバー側から明確な指定がある場合のみ、その値を入力してください。複数の指紋を手当たり次第に切り替えないでください。
  • コアを変更した後:ログに未知のフィールド、未対応のオプション、設定の解析エラーがないか確認します。これらは設定の互換性に関する問題で、証明書検証の問題ではありません。
  • REALITYノード:サーバーが指定するserverName、公開鍵関連のパラメーター、shortId、指紋を確認します。バージョンによって画面上のフィールド名が異なる場合があるため、使用するコアのドキュメントとサーバー設定を基準にしてください。
  • 設定値の注意点:REALITYの接続先ドメインを推測で設定しないでください。また、通常のTLS向け「証明書検証をスキップ」をREALITYの認証失敗対策に使わないでください。

通常のTLSノードで特定の指紋を指定した場合だけハンドシェイクできるなら、サーバー側のアクセス制御とネットワーク上の中間装置も確認してください。変更前後のエラー全体を保存すると、ハンドシェイクが復旧したのか、テストリクエストが別の経路から送信されただけなのかを切り分けられます。調査中は同じノードと同じ宛先へのリクエストを使い、ルーティングルール、TUN、システムプロキシを同時に切り替えないでください。

allowInsecureの注意点:検証は有効にしたまま原因を解決

通常のTLS設定でallowInsecureは、一般的な証明書検証をスキップするかどうかを制御します。有効にしても通信が暗号化される場合はありますが、通常の証明書チェーンと名前の検証ではサーバーの身元を確認できなくなり、なりすましや中間者による傍受のリスクが生じます。「互換性を高める」または「速度を上げる」ための設定ではありません。

以下は通常のTLS設定におけるstreamSettings内のtlsSettingsオブジェクトの例です。ノード設定全体ではなく、REALITYにも適用できません。serverNameはサーバーが指定する実際のドメイン名に置き換えてください。例をすべてのノードにそのまま貼り付けないでください。

{
  "serverName": "example.com",
  "allowInsecure": false
}
  • 検証をスキップして接続が復旧しても、証明書検証を詳しく調べる必要があると分かるだけです。時刻、名前、信頼チェーンのどれが根本原因かは特定できません。
  • 有効にしてもタイムアウトする場合は、ポートとハンドシェイクの調査に戻ってください。この設定を繰り返し切り替えても、接続先サーバーに到達できない問題は解決しません。
  • 修正後、ノードの編集画面で「安全でない接続を許可」がオフになっていることを確認し、切断してから再接続してください。

よくある質問:問題の解決を確認する方法

時刻を同期したのに、証明書が期限切れと表示されるのはなぜですか?

まず、新しいログが今回の接続で記録されたものか確認し、次にサーバーが実際に返す証明書の有効期間を確認してください。端末の時刻が正しく、証明書が期限切れなら、サーバー側で証明書を更新して再読み込みする必要があります。クライアントを再起動するだけでは、接続先から送られる証明書は変わりません。

アドレスにIP、SNIにドメイン名を設定してもよいですか?

はい。ただし、そのIPアドレスとポートで指定したドメインのTLSサービスが提供され、証明書もそのドメインをカバーしている必要があります。ノードをダブルクリックし、「アドレス」「ポート」「SNI」の3項目を確認してください。項目をそろえて見せるためにSNIをIPアドレスへ変更しないでください。

Webページは開けるのに、クライアントでunknown authorityと表示されるのはなぜですか?

まず接続先のアドレス、ポート、SNIを比較し、次にサーバーが完全な中間証明書チェーンを送信しているか確認してください。ブラウザーとプロキシコアでは、異なる信頼ストアや証明書チェーンの処理方法を使うことがあります。ブラウザーで正常に表示できても、クライアントの検証に成功するとは限りません。

サブスクリプションを更新するとSNIが元に戻ります。どうすればよいですか?

ノードを複製して一時的にテストし、正常に動作するフィールドを記録したうえで、サブスクリプション提供元に元設定の誤りを報告してください。設定が正式に修正されたらサブスクリプションを更新し、SNI、指紋、検証設定を確認します。同じノードで新しいリクエストを送信して確認し、過去の接続結果で判断しないでください。

ログにTLSエラーが出なくなったのに、Webページが開けないのはなぜですか?

プロキシプロトコルの認証、ルーティング、DNS、システムプロキシの入口を続けて確認してください。証明書検証の成功はTLSレイヤーの処理が完了したことを示すだけです。VMessやVLESSの認証、接続先への通信、アプリのプロキシ設定がすべて正しいとは限りません。

最終確認は同じ順序で行います。システム時刻が正しいこと、ノードの設定がサーバー側と一致していること、証明書検証が有効なことを確認します。再接続後、新たなTLS検証エラーがログにないことを確認し、アプリのリクエストが想定した経路から送信されているかも確認してください。今回変更したフィールド名と結果を記録しておけば、次回のサブスクリプション更新やコア切り替え時に照合できます。

v2rayNのダウンロード