目次
TLS handshake failed が表示されたら、まずエラー全文と失敗した段階を保存する
証明書エラー、システム時刻のずれ、SNI の設定ミスはいずれも TLS ハンドシェイク失敗として表示されますが、対処方法はまったく異なります。まずログにある原文全体をコピーし、エラーがサブスクリプションのダウンロード、プロキシノードとのハンドシェイク、対象 Web サイトを開く処理のどこで発生したかを確認してください。この二点を特定して初めて、時刻、証明書チェーン、ノードのフィールドのどれを調べるべきか判断できます。
代表的な原文
| ログの文言 | 優先して確認する項目 |
|---|---|
| x509: certificate has expired or is not yet valid | システム時刻と証明書の有効期間 |
| x509: certificate signed by unknown authority | システム CA、企業による SSL 検査、プライベート証明書 |
| remote error: tls: handshake failure | SNI、プロトコルのフィールド、サーバー側の TLS 設定 |
| tls: failed to verify certificate: x509 | 証明書チェーン、servername、実際の証明書名 |
| EOF / connection reset by peer | 接続先による早期切断またはネットワークでの遮断。この一文だけで証明書の問題とは断定できない |
エラーの前後数行をコピーし、時刻、対象ドメイン、ポートは残したまま、サブスクリプションの token、UUID、パスワードを伏せます。「TLS failed」だけを切り取ると、原因の判別に必要な部分が失われます。
サブスクリプションのダウンロード、ノードのハンドシェイク、対象 Web サイトは、それぞれ別の接続である
まず簡単な比較を行います。既存のノードでほかの HTTPS サイトへアクセスできるか、サブスクリプションを手動更新できるかを確認してください。この二つの結果を組み合わせれば、通常はハンドシェイクがどの区間で失敗したかを判断できます。
Profile の更新で TLS エラーが出るが、既存のノードは使用できる
サブスクリプションの URL で失敗しています。そのドメインの証明書、システム時刻、ネットワーク検査機器を確認します。
一つのノードだけで handshake failure が発生する
クライアントからプロキシサーバーまでの区間で失敗しています。そのノードの server、port、SNI、TLS フィールドを比較します。
ノードには接続できるが、一つの HTTPS サイトだけで証明書エラーが出る
対象サイトの証明書、ブラウザーまたはアプリの証明書ストア、セキュリティソフトによる復号の有無を確認します。
すべてのノードで同時に x509 エラーが発生し始める
まずシステム時刻、カーネルのアップグレード、ネットワーク全体で証明書が置き換えられていないかを確認します。
時刻が誤っていると、どの証明書設定も正しく判定できない
# Linux
date -R
timedatectl status
# Windows PowerShell
Get-Date
w32tm /query /status証明書には Not Before と Not After があります。デュアルブートの切り替え、仮想マシンのスナップショット、長期間電源を切っていた OpenWrt、自動時刻合わせの無効化によって、時刻がずれることがあります。日付、タイムゾーン、NTP 同期を直した後、Mihomo を再起動してもう一度再現してください。エラーがまったく同じ場合に限り、ハンドシェイクのフィールドを引き続き確認します。
一つのノードだけが失敗する場合は、SNI とサーバー証明書の名前を照合する
TLS ノードの接続先となる server が IP で、証明書はドメイン向けに発行されている場合があります。この場合、通常は正しい servername または sni を設定する必要があります。値はサーバー側の設定に基づく必要があり、インターネット上でよく見かけるドメインを推測で指定してはいけません。ポート、転送方式、ALPN、Reality public-key/short-id などのフィールドも、一式を正しく対応させる必要があります。
proxies:
# 下列 IP、域名和密码都是占位值,不能直接连接
- name: tls-example
type: trojan
server: 203.0.113.10
port: 443
password: REDACTED
sni: edge.example.com
skip-cert-verify: false同じネットワークから、サーバーが実際に返す証明書を確認する
openssl s_client -connect edge.example.com:443 -servername edge.example.com -showcerts </dev/null
curl -Iv https://edge.example.com/openssl の出力では、subject、issuer、有効期間、Verify return code を確認します。-servername の有無で異なる証明書が返るなら、サーバー側が SNI に依存しています。スマートフォンのテザリングでは正常な証明書が返り、社内ネットワークでは企業 CA に変わる場合は、SSL 検査または中間ゲートウェイが存在します。
プロキシプロトコルのポートが通常の HTTPS ページを提供するとは限らないため、curl の失敗だけでノードの故障とは判断できません。openssl が示す証明書とハンドシェイク情報のほうが有用です。Reality などのプロトコルも通常の Web サイト証明書と同じ項目で判断せず、対応するプロトコルのドキュメントを確認してください。
社内ネットワークだけで失敗する場合は、管理された証明書検査の有無を先に確認する
企業プロキシ、セキュリティゲートウェイ、一部のウイルス対策ソフトは、HTTPS 証明書を再発行します。管理対象端末では、管理者が組織の CA をインストールし、検査を許可する通信の範囲を説明する必要があります。個人の判断でエラーページから見覚えのないルート証明書をダウンロードしたり、Clash の更新を成功させるためにシステム全体の証明書検証を無効にしたりしないでください。
スマートフォンのテザリングへ切り替えると同じサブスクリプション URL がすぐ正常になる場合は、ネットワーク経路の違いを示す証拠になります。社内ネットワークで確認した issuer、エラー時刻、対象ドメインを管理者へ伝えるほうが、ノードを次々に切り替えるより有効です。
修正後、当初失敗した接続を同じ条件でもう一度試す
「ほかのサイトも開ける」だけで検証を済ませないでください。最初にエラーが出たサブスクリプション、ノード、対象 Web サイトへ戻り、同じネットワークでもう一度試して、ログから元のエラーが消えたことを確認します。
検証結果
- システム時刻とタイムゾーンが正しく、カーネルの再起動後は not yet valid/expired が表示されない
- サブスクリプションが失敗していた場合、手動更新が成功し、更新時刻も変化する
- ノードが失敗していた場合、同じノードでハンドシェイクが完了し、実際の接続記録が生成される
- 対象 Web サイトが失敗していた場合、証明書の issuer とドメインが想定どおりである
- 一時的に無効にした証明書検査またはセキュリティ設定を元に戻している
- 管理されたテストに明確な理由がない限り、skip-cert-verify は false のままにする
