通常のTLSを使用するノードで、クライアントログにハンドシェイク失敗やx509証明書エラーが表示される場合が対象です。「ログの内容 → システム時刻 → 接続先とSNI → 証明書チェーン → クライアントの設定項目」の順に確認し、ネットワークのタイムアウトと証明書検証エラーを切り分けます。証明書検証は有効のままにし、項目を一つずつ変更してログで結果を確認してください。
証明書エラーと接続失敗を切り分ける
「TLSハンドシェイク失敗」は処理段階を示すもので、原因を特定するエラーではありません。クライアントはまずノードのアドレスとポートに接続し、TLSネゴシエーションと証明書検証を行ってから、プロキシプロトコルの通信に進みます。接続タイムアウト、サーバー側からの切断、証明書のドメイン不一致などが、まとめて「接続失敗」と表示されることがあります。調査時は速度測定の失敗表示だけで判断せず、詳細なコアログを開き、エラーの末尾を確認してください。
v2rayNではメイン画面のログ欄から今回の接続ログを確認できます。v2rayNGとv2flyNGでは、メインメニューのログ項目を開きます。リリースによって項目名や場所が異なる場合があります。クライアントのバージョン、コアの名称、トランスポート方式、エラー全文を記録したうえで、対象ノードだけに一度リクエストを送り、複数のバックグラウンド接続のログが混ざらないようにしてください。
エラー:x509: certificate has expired or is not yet valid
原因:検証時刻が証明書の有効期間外です。端末の時刻がずれている場合と、サーバー証明書そのものが期限切れの場合があります。対処:まず端末の時刻を同期し、ログに記録された現在時刻と証明書の有効期間を照合します。解消しない場合は、サーバー側で証明書を更新して再読み込みします。
エラー:x509: certificate signed by unknown authority
原因:証明書から信頼されたルート証明書までのチェーンを構築できません。中間証明書の不足、自己署名証明書、接続の差し替えなどが考えられます。対処:サーバーが証明書チェーンを正しく送信しているか、端末の信頼ストアに問題がないかを確認し、発行者も照合してください。検証を無効にして回避するのではなく、原因を修正します。
エラー:tls: first record does not look like a TLS handshake
原因:接続先ポートからTLSデータではなく、別の応答が返っています。平文のサービスに接続している可能性があります。対処:ノードのポート、トランスポートのセキュリティ設定、リバースプロキシの待ち受け設定を確認してください。
エラー:context deadline exceeded
原因:処理がタイムアウトしたことを示すエラーで、この表示だけでは証明書の問題と判断できません。対処:前後のログも確認し、名前解決、TCP接続、ハンドシェイクのどの段階で止まったかを調べます。まず証明書関連の設定を変更するのは避けてください。
システム時刻:同期してから証明書の期限を確認
証明書には有効開始時刻と有効期限があります。端末の時計が進んでいると「まだ有効ではない」、遅れていると「期限切れ」と判定されることがあります。タイムゾーンを変えるだけでは、実際のシステム時刻は通常変わりません。修正が必要なのは実際の日付と時刻です。デュアルブート、長期間の電源オフ後の起動、自動時刻同期の失敗があれば、優先して確認してください。
-
時刻を同期する
Windows 11:「設定」→「時刻と言語」→「日付と時刻」を開き、「時刻を自動的に設定する」をオンにします。「その他の設定」で「今すぐ同期」をクリックしてください。同期できない場合は、まず端末のネットワーク接続を確認します。
-
ほかの端末も確認する
macOS:「システム設定」→「一般」→「日付と時刻」を開き、日付と時刻の自動設定をオンにします。Android:「設定」→「システム」→「日付と時刻」を開き、自動設定をオンにします。メーカー独自のOSでは、「その他の設定」に項目がある場合があります。
-
接続をやり直す
時刻を同期したら、クライアントの接続をいったん停止して再起動し、新しいログを記録します。時刻を修正する前の古いログで、修正の効果を判断しないでください。
-
証明書の有効期間を確認する
端末の時刻が正しいのに期限切れと表示される場合は、実際に受信した証明書の有効期間を確認してください。証明書を更新した後は、TLS終端サービスの再読み込みも必要です。ディスク上のファイルが新しくなっていても、接続に新しい証明書が使われているとは限りません。
接続先アドレス、SNI、Hostを混同しない
ノード編集画面の「アドレス」は接続先を指定します。SNIはTLS ClientHelloで送信するサーバー名で、サーバーはこれを使って証明書を選ぶことがあります。WebSocketのHostは、TLSハンドシェイク後のHTTPリクエストヘッダーです。3つに同じドメインを使う場合も、別の値を使う場合もありますが、サーバーの設定に従う必要があります。「偽装ドメイン」を自由に差し替えられる項目と考えないでください。
| 設定項目 | 適用される段階 | 確認ポイント |
|---|---|---|
| アドレスとポート | ネットワーク接続 | サーバーから指定された接続先を使用します。ドメインの名前解決結果が、想定したサーバーを指していることを確認してください。 |
serverName / SNI | TLSハンドシェイク | 証明書に記載されたサーバー名を入力します。プロトコル、ポート、パスは含めません。 |
| WebSocket Host | HTTP Upgradeリクエスト | リバースプロキシの仮想ホストと一致させます。TLSのSNIの代わりにはなりません。 |
| WebSocket path | HTTPパスの照合 | サーバーで指定されたパスを使用します。パスの誤りは通常、証明書のドメインエラーとは別の問題です。 |
allowInsecure | 証明書の検証 | 一般的な公開証明書を使う場合は、falseのままにします。 |
説明用に予約されたドメインedge.example.comを例にします。証明書のSubject Alternative Nameにこの名前が含まれている場合、SNIにはこのホスト名を指定します。https://edge.example.com/pathのようなURLを入力してはいけません。IPアドレスで接続する場合も、サーバーが要求するドメイン名をSNIに指定できます。IPアドレスで直接証明書を検証するには、証明書に一致するIPアドレスの項目が必要です。ドメイン名だけでは不十分です。
判断のポイント:ポート番号から推測せず、サーバーの設定と照合する
ポート番号は慣例にすぎません。まずノードで通常のTLSが有効か確認し、次にSNIと証明書のドメイン名を照合してください。WebSocketのHostを変えても、HTTPリクエストより前に発生する証明書名のエラーは解消できません。
クライアントでSNIとallowInsecureを確認する場所
画面の項目名はバージョンによって異なるため、ここではノード編集画面と実際の設定項目を目印にします。サブスクリプションから取り込んだ設定は更新時に上書きされることがあるため、変更前にノードを複製して値を記録してください。一度のテストでアドレス、ポート、SNI、トランスポート方式を同時に変更すると、接続が復旧しても原因を特定しにくくなります。
- v2rayN:メイン画面で対象ノードをダブルクリックし、サーバー編集画面を開きます。「アドレス」「ポート」を確認した後、トランスポート層のセキュリティ設定にある
tls、「SNI」、「証明書検証をスキップ」または「安全でない接続を許可」を確認します。通常のTLSでは、後者はオフにしてください。カスタム設定を使っている場合は、実際に読み込まれたJSONを確認します。通常の編集画面では、そのファイルが変更されないことがあります。 - v2rayNG:ノード一覧で対象ノードの編集アイコンをタップし、下にスクロールしてTLS設定を確認します。トランスポート層のセキュリティが
tlsになっていることを確認し、「SNI」と「安全でない接続を許可(allowInsecure)」を照合してください。WebSocketを使う場合は、トランスポート設定のHostとpathも個別に確認します。このクライアントはXrayコアを使用します。REALITYノードは対応する項目を確認してください。 - v2flyNG:ノード一覧から編集画面を開き、TLS、サーバー名またはSNI、「安全でない接続を許可」の設定を確認します。このクライアントはv2flyコアを使用するため、Xray固有のセキュリティ設定をそのまま適用しないでください。編集画面に該当項目がない場合は、Hostに代わりの値を入れるのではなく、ノードの種類と使用中のバージョンを確認します。
以下は通常のTLSで使用するstreamSettingsの設定例です。項目を確認するための抜粋であり、ノード設定全体ではありません。例ではTCPを使用し、ドメイン名は説明用です。既存ノードがWebSocketなど別のトランスポートを使っている場合、例に合わせてTCPへ変更しないでください。利用できる項目は、実際に動作しているコアの仕様を確認してください。
{
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "edge.example.com",
"allowInsecure": false
}
}
}
証明書チェーンとSNI:個別のTLS接続で原因を絞り込む
ターミナルを使える環境では、同じ端末・同じネットワークからサーバーが返す証明書を個別に確認できます。以下のコマンドを実行するには、システムにOpenSSLがインストールされている必要があります。実行前に、例のホスト名、SNI、ポートを実際の値に置き換えてください。接続先アドレスとSNIは別々に指定するため、「IPアドレスで接続し、ドメイン名で検証する」設定の確認にも便利です。
openssl s_client -connect edge.example.com:443 -servername edge.example.com -showcerts -verify_hostname edge.example.com -verify_return_error
- まず証明書を受信できるか確認:接続が確立する前にタイムアウトする場合は、ネットワーク、DNS、ポート、ファイアウォールを先に確認してください。証明書が出力されないだけで、期限切れとは判断できません。
- 次に名前と有効期間を確認:受信した証明書のドメイン名、有効開始時刻、期限を確認します。SNIによってデフォルトサイトの証明書が選ばれている場合は、サーバーの仮想ホストと証明書の割り当てを確認してください。
- 証明書チェーンを確認:サーバーは通常、リーフ証明書と必要な中間証明書を送信します。ルート証明書はクライアントの信頼ストアから参照されます。ブラウザーで接続できても、すべてのコアで同じ信頼チェーンが構築されるとは限りません。
- 信頼環境を比較:OpenSSLとクライアントのコアでは、異なる信頼ストアを使うことがあります。コマンドの成功が示すのは、そのツールと接続先、指定したパラメーターでの結果です。クライアントでの再テストも必要です。
特定のネットワークだけで発行者の異なる証明書が返される場合は、そのネットワークでHTTPS検査、ポータルへのログイン、通信の転送が行われていないか確認してください。エラーダイアログに表示された情報をもとに、出所不明のルート証明書を安易にインストールしないでください。サーバーを他者が管理している場合は、個人情報を除いたエラー末尾、発生時刻、SNI、ポートを伝えます。サブスクリプションの完全なURL、UUIDなどの認証情報は共有しないでください。
よくある質問と修正後の確認
allowInsecureを有効にしたら接続できました。このまま使ってもいいですか?
通常の証明書検証が関係している可能性を示すだけで、ドメインの問題が確定したわけではありません。時刻を同期し、SNI、証明書の有効期間、完全な証明書チェーンを確認してください。修正後はこの設定をオフにし、実際にリクエストを送って接続を確かめます。
ブラウザーではノードのドメインにアクセスできますが、クライアントでエラーになるのはなぜですか?
まず、同じアドレス、ポート、SNIに接続しているか確認してください。ブラウザーでは別のプロキシを経由したり、異なる接続先に名前解決されたりすることがあります。使用する信頼ストアも異なる場合があります。クライアントが実際に接続した先と、受信した証明書を基準に確認してください。
サブスクリプションを更新するとSNIが元に戻ります。どうすればいいですか?
テスト用にノードを複製し、変更の効果を確認してから、サブスクリプションの提供元に配信設定の修正を依頼してください。更新のたびに元のノードも確認し、自動上書きをクライアントの保存失敗と取り違えないようにします。
ノードがREALITYの場合も、これらのTLS設定を確認すべきですか?
まずsecurityの実際の値を確認してください。REALITYには通常のTLSの証明書修復手順をそのまま適用できません。サーバーが指定するserverName、公開鍵、shortIdなどの項目を確認してください。通常のTLSに切り替えたり、検証をスキップしたりして解決を試みないでください。
変更後はノードを保存し、接続を再起動してから、同じリクエストで再テストしてください。遅延の数値だけでなく、ログに元の証明書エラーが出ないこと、実際のリクエストが完了すること、通常のTLSノードでは証明書検証が有効のままであることを確認します。ハンドシェイク後にパスエラー、異常なHTTPステータスコード、プロトコル認証エラーが発生する場合は、トランスポートのパスやアカウント設定を調べます。SNIを何度も変更する必要はありません。