V2RayまたはXrayのコアが暗号化接続を確立するときは、まずTCPなどの下位トランスポートを確立し、その後TLSハンドシェイクを行います。証明書の有効期間、証明書ドメイン、システム時刻、SNI、TLSバージョン、クライアントフィンガープリントのいずれかが一致しないと、プロキシリクエストを送信する前に接続が終了することがあります。そのため、ブラウザーに接続失敗と表示されたり、v2rayNの速度テストが利用不可になったり、v2rayNGのログに証明書エラーが出たりしても、サーバーのポートが閉じているとは限りません。
この記事は、TLS handshake、x509、certificate、serverName、SNIのエラーが出るv2rayN、v2rayNG、v2flyNGユーザー向けです。「ログ確認、時刻確認、ドメイン照合、パラメータ確認、再テスト」の順に進めると、原因が端末、ノード設定、サーバーの証明書チェーンのどこにあるか判断できます。
まずログでTLSエラーの種類を見分ける
TLSトラブルでは、速度テストを何度も繰り返す前に完全なログを1回保存します。v2rayNではメイン画面のログ欄でコアの出力を確認でき、「設定」→「パラメータ設定」でログレベルも確認できます。v2rayNGとv2flyNGではサイドメニューのログ画面を開き、もう一度接続します。確認時は最初に現れたエラー行を記録してください。その後の接続終了や再試行失敗は、連鎖的に発生した結果であることが多いためです。
エラー: x509: certificate has expired or is not yet valid
原因と対処:端末の時刻が証明書の有効期間外になっているか、サーバー証明書が実際に期限切れです。まずシステムの日付、時刻、タイムゾーンを同期し、証明書の有効開始日時と終了日時を確認します。
エラー: x509: certificate is valid for example.com, not edge.example.net
原因と対処:クライアントが検証するserverNameと証明書のドメインが一致していません。SNIを証明書がカバーする完全なドメイン名に変更し、サーバーのIPアドレスをそのまま入力しないでください。
エラー: tls: failed to verify certificate
原因と対処:証明書チェーン、発行関係、または端末の信頼環境の検証に失敗しています。まず時刻の問題を除外し、サーバーが完全な証明書チェーンを送信しているか確認します。
エラー: remote error: tls: handshake failure
原因と対処:リモート側がハンドシェイク中に接続を意図的に終了しています。SNI、ALPN、TLSフィンガープリント、トランスポート設定を確認し、正しいポートへ接続していることも確認します。
エラー: context deadline exceeded
原因と対処:制限時間内にハンドシェイクが完了していません。まずネットワーク到達性とポートを確認し、直前のログと照らし合わせて証明書トラブルか判断します。
EOF、connection reset by peer、タイムアウトはTLSに特有のエラーではありません。サーバープロセスが待ち受けていない、トランスポート経路が一致していない、中間ネットワーク機器が先に切断した場合にも発生します。ログに x509、certificate、serverName、またはTLSハンドシェイクに関する明確な文言が同時に出ている場合に限り、まず証明書チェーンを確認してください。
- 最初に発生したエラーを確認し、ログの最後の1行だけをコピーしないでください。
- ノードのアドレス、ポート、トランスポート方式、TLSの有効・無効、SNIを記録します。ただし、サブスクリプションURLは公開しないでください。
- 同じノードは連続2回までテストすれば十分です。頻繁に再接続すると、ログが重複情報で埋まってしまいます。
- 同じ端末で複数のノードが同時に証明書の時刻エラーになる場合は、まず端末の時計を確認します。
システム時刻とタイムゾーンを最初に確認する
証明書には「有効開始」と「有効期限」の2つの時刻があります。端末はローカルのシステム時計を使い、現在時刻が有効期間内か判断します。日付が正しくてもタイムゾーンが間違っていたり、スリープ後に時計がずれたり、仮想マシンがホストの時刻と同期していなかったりすると、not yet validやexpiredが発生します。確認時はタスクバーの時分だけでなく、年、月、日、タイムゾーンも確認してください。
-
日付を確認
年、月、日がすべて正しいことを確認します。端末が長時間のスリープから復帰した直後なら、システムの時刻同期が完了するまで待ちます。
-
タイムゾーンを確認
Windowsでは「設定」→「時刻と言語」→「日付と時刻」を開き、タイムゾーンが現在地と一致していることを確認し、自動時刻設定を有効にします。
-
今すぐ同期
同じ画面で「今すぐ同期」をクリックします。Android端末ではシステムの「設定」→「システム」→「日付と時刻」を開き、自動日時設定と自動タイムゾーン設定を有効にします。
-
コアを再起動
現在の接続を停止し、クライアントのコアを終了してから再起動します。その後、元のノードで遅延テストと実際のWebページへのアクセスを1回ずつ行います。
Windowsでは管理者ターミナルから時刻サービスの状態を確認し、同期を開始することもできます。Linuxでは timedatectl を使ってローカル時刻、UTC時刻、タイムゾーン、NTPの状態を確認できます。コマンドが成功したら、古い接続が以前のハンドシェイク状態を使い続けないよう、V2RayまたはXrayのコアを再起動します。
w32tm /query /status
w32tm /resync
timedatectl status
sudo timedatectl set-ntp true
ノードのアドレス、SNI、証明書ドメインを確認する
ノードの「アドレス」とTLSの serverName は異なる役割を持ちます。アドレスはDNS解決とネットワーク接続の確立に使われ、serverNameはTLS ClientHelloのSNI拡張に含まれ、通常は証明書のドメイン検証対象にもなります。サーバーアドレスはIPまたは接続用ドメインにできますが、SNIはサーバー証明書がカバーするドメインと一致させます。
たとえば、クライアントの接続先が 203.0.113.20で、証明書が edge.example.netだけをカバーしている場合、アドレスはIPのままにして、SNIには edge.example.netを入力します。SNIを空欄にすると、コアがアドレスから検証名を推測することがあります。アドレスがIPなのに証明書がドメイン名しか含まない場合、「証明書は特定のドメインには有効だが、現在のアドレスには適用できない」というエラーが発生しやすくなります。
| 設定項目 | 役割 | 正しい確認方法 |
|---|---|---|
| アドレス Address | 実際に接続するホストを決める | ドメインが解決できること、またはIPがサーバーと一致することを確認 |
| ポート Port | 接続先の待ち受けポートを決める | サーバーがそのポートで対象のTLSインバウンドを提供していることを確認 |
| SNI / serverName | 仮想ホストを選択し、証明書検証にも使われる | 証明書がカバーする完全なドメイン名を入力し、プロトコルやパスは付けない |
| Host | HTTPやWebSocketなどのトランスポート層で使われる | サーバー側のリバースプロキシ規則に従って入力し、SNIと自動的に同じにしない |
| ALPN | アプリケーション層プロトコルをネゴシエートする | サーバーが要求する値を使い、明確な指定がない場合はむやみに上書きしない |
-
ノードを開く
v2rayNのメイン画面で対象ノードを選択し、編集画面を開きます。v2rayNGまたはv2flyNGでは、対象設定の編集画面を開きます。
-
パラメータを書き留める
アドレス、ポート、トランスポートプロトコル、TLSの有効・無効、SNI、Host、ALPN、フィンガープリントを記録します。変更前の値を残しておくと、元に戻せます。
-
ドメインを照合
SNIとエラーに表示された証明書ドメインを1文字ずつ比較します。余分なスペース、日本語の句読点、誤ったサフィックス、欠落したサブドメインを特に確認してください。
-
保存して再テスト
保存後にコアを再起動し、このノードだけをテストします。エラーがドメイン不一致から接続タイムアウトに変わった場合は、アドレス解決とポート到達性を個別に確認します。
結論:接続先に到達できても、証明書名が正しいとは限らない
TCP接続が確立していてもx509がドメイン不一致を明確に報告する場合は、まずSNIを修正します。ローカルのSOCKSまたはHTTPポートを変更しても、リモート証明書の検証結果は変わりません。
証明書の期限切れ、証明書チェーン欠落、サーバー設定ミスを見分ける
システム時刻が正確で、SNIもドメインと一致しているのに証明書検証に失敗する場合は、サーバー証明書そのものを確認します。よくある原因は、証明書の期限切れ、更新後にサービスが再読み込みされていない、誤った仮想ホストに新しい証明書を配備した、サイト証明書だけを送信して中間証明書が欠落している、といったものです。
エラー: x509: certificate signed by unknown authority
原因と対処:クライアントが信頼されたルート証明書までの完全なチェーンを構築できていません。サーバーには完全な証明書チェーンを配備し、端末の証明書ストアも正常に更新される状態に保ちます。
エラー: x509: certificate has expired
原因と対処:システム時刻が正確であるにもかかわらず、証明書の有効期限を過ぎています。更新後は、TLSを実際に待ち受けているサービスに証明書ファイルを再読み込みさせます。
エラー: tls: bad certificate
原因と対処:リモート側がクライアント証明書または相互認証パラメータを拒否しています。このインバウンドでクライアント証明書認証が有効か確認し、対応する設定を使用します。
同じドメインに通常のブラウザーでアクセスしても証明書異常が表示されるなら、問題はサーバー証明書の配備にある可能性が高いです。ブラウザーは正常なのにV2Ray/Xrayだけ失敗する場合は、接続ポート、SNI、ALPN、トランスポート層を引き続き比較します。ブラウザーで正常に接続できても、ブラウザーが接続したドメインとポートが利用可能だと分かるだけで、ノード設定の別ポートが同じ証明書を使っているとは限りません。
- 証明書の有効開始時刻と有効期限が現在時刻をカバーしていることを確認します。
- 証明書のサブジェクト代替名に、SNIで使用する完全なドメイン名が含まれていることを確認します。
- リバースプロキシまたはTLS終端サービスが完全な証明書チェーンを送信していることを確認します。
- 証明書更新後、実際に待ち受けているプロセスが設定を再読み込みしたことを確認します。
- ポート443またはカスタムポートが別のサービスに占有されていないことを確認します。
- サブスクリプション更新によって古いドメインや古いポートがクライアントに再書き込みされていないことを確認します。
allowInsecure、フィンガープリント、ALPNの設定方法
allowInsecureは、クライアントが証明書の有効性とドメイン検証をスキップするかどうかを制御します。v2rayN、v2rayNG、v2flyNGでは、「証明書検証をスキップ」などの名称で表示されることがあります。公開された信頼済み証明書を通常利用する場合は無効のままにし、コアに証明書チェーンとserverNameを検証させます。
この項目を一時的に有効にすると、問題の切り分けに役立ちます。有効にしてすぐ接続できた場合、ネットワークアドレス、ポート、主要なトランスポート経路はおおむね到達可能で、証明書の有効期間、ドメイン一致、信頼チェーンに問題が絞られます。ただし診断専用の結果なので、その後は厳格な検証に戻し、根本原因を修正してください。
- allowInsecure:証明書検証に影響しますが、誤ったSNIを修正するものでも、期限切れの証明書を更新するものでもありません。
- fingerprint:TLS ClientHelloの特徴を調整するために使います。たとえば設定で
chromeが要求される場合などです。証明書のフィンガープリントとは異なり、証明書チェーンの検証を代替するものではありません。 - ALPN:一般的な値には
h2とhttp/1.1があり、サーバー側の入口とトランスポート方式に対応させる必要があります。 - TLSバージョン:クライアントとサーバーの双方が対応する共通バージョンが必要です。古いシステム環境では、最新のTLSネゴシエーションを完了できないことがあります。
フィンガープリントを変更する前に、ノード提供元または自分で構築したサービスの設定で何が要求されているか確認します。フィンガープリント、ALPN、SNIを一度にすべて変更すると、テスト結果を比較できなくなります。元の設定を保存し、毎回1項目だけ変更して、コアを再起動し、対応するログを保存するのが正しい方法です。
テスト1:証明書の厳格な検証を維持し、システム時刻だけを修正
テスト2:他のパラメータは変更せず、SNIだけを修正
テスト3:厳格な検証に戻し、サーバーが要求するフィンガープリントだけを調整
テスト4:ALPNとトランスポート層を確認して再接続
結論:検証のスキップは原因範囲の絞り込みに限って使う
証明書検証を無効にして接続が回復した場合は、証明書の有効期間、完全なチェーン、SNIの3項目に戻って原因を特定します。一時的な診断用スイッチをノード設定に残したままにしないでください。
決まった順序で再テストし、複数パラメータの干渉を避ける
変更後は古い接続を停止してコアを再起動します。画面上で保存をクリックするだけでは、確立済みまたは再試行中の接続が中断されないことがあります。再テストでは、まずノードの遅延テスト、次に通常のHTTPSページへのアクセス、最後にログで同じ最初のエラーが残っていないかを確認します。
-
時刻を同期
システム時刻のずれを正常な範囲まで戻し、日付、タイムゾーン、自動時刻同期の状態が正しいことを確認します。
-
アドレスを確認
ノードのドメインが解決でき、サーバーアドレスとポートに入力ミスがなく、TLSサービスが対象ポートで待ち受けていることを確認します。
-
SNIを修正
serverNameを証明書がカバーするドメインと一致させます。入力するのはドメイン名だけにし、
https://、ポート、パスは含めません。 -
証明書チェーンを検証
有効期間、中間証明書、実際の読み込み状態を確認します。証明書更新後は、待ち受けサービスが新しい証明書を使用していることを確認します。
-
パラメータを1項目ずつ変更
必要に応じてフィンガープリントとALPNを確認し、各回で変更するのは1項目だけにします。変更前後のログ結果も保存してください。
-
厳格な検証に戻す
診断が終わったら証明書検証をスキップする設定を無効にし、コアを再起動して最終接続テストを行います。
デスクトップとAndroid端末が同じネットワーク、同じノードで同時に失敗し、両方の時刻が正確なら、まずサーバー証明書とSNIを確認します。1台だけ失敗する場合は、その端末のシステム時刻、クライアント設定、システムの証明書環境を優先的に比較します。すべてのTLSノードが失敗する一方で非TLSのテスト接続が正常なら、端末のセキュリティソフト、ネットワーク出口、システムTLS環境がハンドシェイク経路を書き換えていないかも確認します。