TL;DR: クイックフィックス
このエラーの原因は、通常、単純な理解不足(設定ミス)に集約されます。ブラウザがHTTPSの暗号化されたハンドシェイクを期待しているのに対し、Nginxが平文のHTTPで応答してしまっています。最も一般的な修正方法は、listenディレクティブにsslパラメータを追加することです。
# 間違った設定
server {
listen 443;
server_name example.com;
...
}
# 正しい設定
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
...
}
ファイルを更新したら、nginx -tを実行して構文エラーがないか確認し、systemctl reload nginxで変更を適用します。
SSL_ERROR_RX_RECORD_TOO_LONGの実際の原因は?
FirefoxでSSL_ERROR_RX_RECORD_TOO_LONGと表示される場合も、ChromeでERR_SSL_PROTOCOL_ERRORと表示される場合も、根本的な原因はプロトコルの不一致です。ブラウザはTLSハンドシェイクを開始するために「Client Hello」を送信し、暗号化された応答を期待します。
しかし、サーバーは平文(多くの場合404ページや301リダイレクト)で返信します。ブラウザはその平文の最初の数バイトをTLSレコードの長さとして読み取ろうとします。「HTTP」などのASCII文字はバイナリでは巨大な数値に変換されるため、ブラウザはレコードが巨大であると判断し、ハードリミットに達してしまいます。技術的には、応答が標準の16,384バイトのTLSレコード最大値を超えている状態です。
一般的な修正方法
1. Listenディレクティブに'ssl'パラメータを追加する
Nginxは指示に忠実です。ポート443が業界標準だからといって、自動的に暗号化が必要だと判断することはありません。その特定のソケットに対してSSLエンジンを明示的に有効にする必要があります。
server {
listen 443 ssl; # この 'ssl' タグが必須です
server_name myapp.io;
ssl_certificate /etc/letsencrypt/live/myapp.io/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myapp.io/privkey.pem;
# ... その他の設定
}
2. デフォルトサーバーの競合を解消する
もし/etc/nginx/sites-enabled/ディレクトリに複数のファイルがある場合、そのうちの1つがSSLが無効な状態でポート443のdefault_serverとして動作している可能性があります。Nginxは、実際のサイト設定に到達する前に、その「平文」ブロックでリクエストを処理してしまっているかもしれません。
設定内のすべてのポート443の使用箇所をスキャンします:
grep -r "443" /etc/nginx/sites-enabled/
443をリッスンしているすべてのブロックにsslパラメータが必要です。もし欠けているものがあれば、それが原因です。
3. ポート80でのSSL設定ミスを避ける
テンプレートをコピーする際に、誤ってポート80でSSLを強制してしまっているケースを見かけます。もし設定がlisten 80 ssl;となっており、https://yourdomain.com(デフォルトでポート443を使用)にアクセスすると接続に失敗します。しかし、https://yourdomain.com:80にアクセスすると、即座にレコード長エラーが発生します。
4. Cloudflareの「Flexible」モードによるループを修正する
Cloudflareユーザーがよく遭遇するのが、SSL/TLS設定が「Flexible(フレキシブル)」になっている場合です。このモードでは、Cloudflareはポート80経由でNginxサーバーと通信します。もしNginxの設定ですべてのポート80トラフィックをHTTPSに自動リダイレクトするようにしていると、プロトコルのループが発生します。有効な証明書(Let's Encryptなど)がある場合は、Cloudflareの設定を**「Full (strict)(フル(厳密))」**モードに変更して、エンドツーエンドの暗号化を確保してください。
5. Proxy Passのロジックを確認する
あまり一般的ではありませんが、Nginxをリバースプロキシとして使用している場合にも発生する可能性があります。ヘッダーを正しく処理せずに、HTTPSリクエストをHTTPしか理解できないバックエンドにプロキシしようとした場合(またはその逆)、レスポンスが文字化けすることがあります。ただし、通常このエラーはブラウザとNginx間の最初の接続時に発生します。
確認手順
ブラウザのキャッシュは強力で、修正結果が反映されないことがあります。curlを使用して、サーバーが実際に何を返しているかを確認しましょう。
ステップ1:詳細テストの実行
curl -v https://example.com
出力結果を確認します。TLS handshake, Client helloの後に400 Bad Requestや平文のHTMLスニペットが表示された場合、プロトコルの不一致が確定します。
ステップ2:SSLポートでHTTPを強制する
サーバーがセキュアポートで誤って平文を提供していないかテストします:
curl http://example.com:443
これで200 OKや301リダイレクトが返ってくる場合、Nginxの設定は間違いなく壊れています。ポート443での平文HTTPの提供は拒否されるべきです。
ステップ3:プロセスの確認
sudo ss -tulpn | grep :443
別のサービスや同じホストポートにバインドされたDockerコンテナではなく、実際にnginxプロセスがそのポートをリッスンしていることを確認してください。
参考文献
- [Nginx公式ドキュメント:HTTPSサーバーの設定](https://nginx.org/en/docs/http/configuring_https_servers.html)
- [Let's Encrypt:NginxでCertbotを使用する](https://letsencrypt.org/docs/getting-started/)

