SSL received a record that exceeded the maximum permissible length エラーの完全解説【Apache VirtualHost設定】

2011年9月27日

Apacheで「SSL received a record that exceeded the maximum permissible length」エラーに遭遇したとき、原因の特定と修正に手間取るケースが多い。このエラーは表面的にはSSLの問題に見えるが、実際にはVirtualHostのIPアドレス設定ミスが主因であることがほとんどだ。本記事ではエラーの仕組みから、Apache 2.4系での具体的な設定例、よくある誤設定パターンとその解決策まで詳しく解説する。

ApacheのSSLエラーログが表示されている端末画面

このエラーが発生する仕組み

「SSL received a record that exceeded the maximum permissible length」はMozillaのNSSライブラリ(Network Security Services)が出力するエラーメッセージで、Apache + mod_sslの環境で頻繁に見かける。

エラーコードはssl_error_rx_record_too_long(NSS)または同等のSSL_ERROR_RX_RECORD_TOO_LONGとして記録される。

なぜこのメッセージが出るのか

SSLハンドシェイクが始まる前に、クライアントとサーバが「TLSレコード」をやり取りする。TLSレコードには最大サイズの制限(RFC 5246では最大 16,384 バイト)がある。

このエラーが出るのは、クライアントがSSLで接続しようとしているポートが、実際にはSSLを処理していない(平文HTTPを処理している)場合だ。クライアントから送られてくるTLSのClientHelloパケットを、サーバ側がHTTPリクエストとして解釈しようとする。その結果、異常なサイズのデータと判断されてエラーになる。

[error] [client 203.0.113.1] SSL received a record that exceeded the maximum permissible length.
[error] [client 203.0.113.1] SSL handshake failed: HTTP spoken on HTTPS port; trying to send HTML error page

つまり根本原因はSSLの設定問題ではなく、VirtualHostのIPやポートの設定ミスである。

主な原因パターンと対処法

原因1: VirtualHostのIPアドレスが間違っている

最も多い原因がこれだ。SSLのVirtualHostで指定するIPアドレスが、実際にそのサーバに割り当てられているIPと一致していない場合、リクエストが非SSL用のVirtualHostにルーティングされてしまう。

誤った設定例:

# 実際のサーバIPが 192.168.1.10 なのに 0.0.0.0 や別IPを指定している
<VirtualHost 0.0.0.0:443>
    ServerName example.com
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/example.crt
    SSLCertificateKeyFile /etc/ssl/private/example.key
    DocumentRoot /var/www/html
</VirtualHost>

正しい設定例:

# サーバの実IPを明示的に指定する
<VirtualHost 192.168.1.10:443>
    ServerName example.com
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/example.crt
    SSLCertificateKeyFile /etc/ssl/private/example.key
    DocumentRoot /var/www/html
</VirtualHost>

または、全IPで受け付ける場合は *:443 を使う:

<VirtualHost *:443>
    ServerName example.com
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/example.crt
    SSLCertificateKeyFile /etc/ssl/private/example.key
    DocumentRoot /var/www/html
</VirtualHost>

原因2: Listenディレクティブの設定漏れ

Apache 2.4ではListenディレクティブで443番ポートを明示的に開放している必要がある。設定していないと、443へのリクエストが80番ポートの設定に吸収されてエラーになる。

確認すべきhttpd.confまたはports.confの設定:

Listen 80
Listen 443

SSL専用の設定ファイル(ssl.conf等)で以下が記述されているかも確認する:

Listen 443 https

原因3: SSLエンジンが有効になっていない

VirtualHostブロック内でSSLEngine onの記述が抜けていると、443番ポートで平文HTTPを処理しようとしてエラーになる。

<VirtualHost *:443>
    ServerName example.com
    SSLEngine on   # この行が必須
    ...
</VirtualHost>

原因4: 名前ベースのSSL VirtualHostでSNIが機能していない

Apache 2.2以前ではSNI(Server Name Indication)のサポートが不完全な場合があった。複数のSSLサイトをIPが1つのサーバで運用する場合、Apache 2.2ではNameVirtualHost *:443の記述が必要だったが、2.4以降では不要(むしろ非推奨)になっている。

Apache 2.2系の場合(参考):

NameVirtualHost *:443

<VirtualHost *:443>
    ServerName site1.example.com
    SSLEngine on
    ...
</VirtualHost>

<VirtualHost *:443>
    ServerName site2.example.com
    SSLEngine on
    ...
</VirtualHost>

Apache 2.4系の場合(現在の推奨):

# NameVirtualHostは不要
<VirtualHost *:443>
    ServerName site1.example.com
    SSLEngine on
    ...
</VirtualHost>

<VirtualHost *:443>
    ServerName site2.example.com
    SSLEngine on
    ...
</VirtualHost>

原因5: HTTPSでアクセスすべき場所にHTTPでアクセスしている

クライアント側の問題として、ブラウザやスクリプトがHTTPS(443番ポート)にHTTPリクエストを送っているケースもある。この場合エラーはサーバ側のログに記録されるが、修正すべきはクライアント側のURLだ。

# NG: HTTPSポートにHTTPでアクセス
curl http://example.com:443/

# OK: HTTPS URLで接続
curl https://example.com/

Apache 2.4系での完全な設定例

Apache 2.4系での推奨設定を示す。これはLet’s Encryptの証明書を使用するケースを想定している。

# /etc/apache2/sites-available/example.com-ssl.conf

<IfModule mod_ssl.c>
    <VirtualHost *:443>
        ServerName example.com
        ServerAlias www.example.com
        DocumentRoot /var/www/example.com/public

        # SSL設定
        SSLEngine on
        SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

        # TLSバージョン・暗号スイートの設定(セキュリティ強化)
        SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
        SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
        SSLHonorCipherOrder off
        SSLSessionTickets off

        # HSTSヘッダー(一度HTTPSにアクセスしたブラウザに強制)
        Header always set Strict-Transport-Security "max-age=63072000"

        <Directory /var/www/example.com/public>
            AllowOverride All
            Require all granted
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/example.com-ssl-error.log
        CustomLog ${APACHE_LOG_DIR}/example.com-ssl-access.log combined
    </VirtualHost>
</IfModule>

HTTPからHTTPSへのリダイレクト設定(80番ポート用):

# /etc/apache2/sites-available/example.com.conf

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com

    # すべてのHTTPアクセスをHTTPSへリダイレクト
    RewriteEngine on
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>

エラー発生時の調査手順

エラーが発生した場合、以下の手順で原因を特定する。

ステップ1: Apacheのエラーログを確認する

# Debian/Ubuntu系
tail -f /var/log/apache2/error.log

# RHEL/CentOS系
tail -f /var/log/httpd/error_log

ssl_error_rx_record_too_longHTTP spoken on HTTPS portというメッセージが出ていれば、このエラーに該当する。

ステップ2: 設定ファイルの構文チェック

# 設定ファイルの構文確認
apachectl configtest
# または
apache2ctl configtest

Syntax OKが返れば構文エラーはない。

ステップ3: 443番ポートがLISTEN状態か確認

# ポートのLISTEN状態確認
ss -tlnp | grep 443
# または
netstat -tlnp | grep 443

443番ポートがLISTENされていない場合、Listen 443の記述がないかApacheが起動していない。

ステップ4: VirtualHostの実際の設定を確認

# 有効なVirtualHostの一覧を表示
apachectl -S
# または
apache2ctl -S

出力例:

VirtualHost configuration:
*:443                  example.com (/etc/apache2/sites-enabled/example.com-ssl.conf:3)
*:80                   example.com (/etc/apache2/sites-enabled/example.com.conf:1)

この出力でIPとポートが期待通りに設定されているか確認する。

ステップ5: opensslコマンドで直接接続テスト

# SSLハンドシェイクが正常に行われるか確認
openssl s_client -connect example.com:443

# SNIを使う場合(複数VirtualHostがある場合)
openssl s_client -connect example.com:443 -servername example.com

正常であれば証明書情報が表示される。エラーが出る場合は接続自体の問題だ。

opensslコマンドで接続テストを実行している端末画面

mod_sslの有効化確認

このエラーの別の原因として、mod_sslモジュールが有効になっていないケースもある。

# mod_sslが有効か確認
apache2ctl -M | grep ssl

# 有効化(Debian/Ubuntu系)
a2enmod ssl
systemctl restart apache2

# 有効化(RHEL/CentOS系)
# httpd.confでLoadModule ssl_moduleの行が有効か確認
grep -i "mod_ssl" /etc/httpd/conf.modules.d/*.conf

よくある誤設定パターンまとめ

誤設定パターン 症状 修正方法
VirtualHostのIP指定ミス 443アクセスが非SSLのVirtualHostに当たる IPを正しく指定するか*:443に変更
Listen 443の記述漏れ 443番ポートが開かない Listen 443を追記
SSLEngine onの記述漏れ 443番ポートが平文HTTPを処理 VirtualHost内にSSLEngine onを追加
mod_sslが無効 SSLが一切機能しない a2enmod sslで有効化
証明書パスの誤り SSL起動時にエラー 証明書ファイルのパスを確認・修正
クライアントのURL誤り HTTPSポートにHTTP接続 クライアント側のURLをhttpsに修正

まとめ

「SSL received a record that exceeded the maximum permissible length」エラーは、名前の通りSSLのレコードサイズ超過のように見えるが、実際にはApacheの443番ポートがSSLを処理していない状態にHTTPSクライアントが接続していることで発生する。

修正の優先順位としては:

  1. apachectl -SでVirtualHostのIPとポートが正しいか確認する
  2. Listen 443が設定されているか確認する
  3. VirtualHost内にSSLEngine onがあるか確認する
  4. mod_sslが有効になっているか確認する

この順番でチェックすれば、ほとんどのケースで解決できる。Apache 2.4系ではNameVirtualHostは不要なため、古いドキュメントを参考にしている場合はこの点も注意が必要だ。

関連記事

webapache,SSL

Posted by GENDOSU