6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Apache 「Misdirected Request」421 エラーを SNI なしで回避した話

6
Last updated at Posted at 2025-11-29

発生した問題

Apacheのセキュリティアップデート後、HostヘッダーだけではSSL証明書を判断できず、特定のアクセスで421 Misdirected Request エラーが発生するようになりました。

「421 Misdirected Request」は、RFC 7540(HTTP/2)で導入されたステータスで、クライアントが意図したリクエスト(例: サイトA)を、サーバー側が「このTLSコネクションはサイトB用だ」 と判断した際に返すエラーです。

今回のケースでは、SNI(Server Name Indication)が付いていないため、TLSハンドシェイクの時点ではApache側で「どの証明書/どのVirtualHostか」を特定できません。
その状態で、HostヘッダーのみでVirtualHostを切り替えようとする動作を、Apacheのセキュリティアップデート(厳格化)によってより厳しく拒否するようになった、というのが421エラーの主な原因と考えられます。

通常はSNIを付けてリクエストすれば解決しますが、今回は上位のロードバランサ(LB)側がSNIを付けられないという制約があり、別の対策が必要となりました。

対策

インターネット上にもSNIを付ける以外の根本的な対応策が少ないため、SNIの仕組みから調査を開始しました。

SNIの仕組みについて
複数のWebサイトが1つのサーバーでホストされ、単一のIPアドレスを共有し、各Webサイトに独自のSSL証明書がある場合、クライアントが安全に接続しようとしてもサーバー側で表示する証明書が特定できないことがあります。これは、クライアントがHTTPを介して接続先Webサイトを示す前にSSL/TLSハンドシェイクが発生するためです。SNIはこの問題を解決する仕組みです。

(参考サイト:https://www.cloudflare.com/ja-jp/learning/ssl/what-is-sni/

Apacheでは、同じIPアドレス・ポートで 複数のTLS VirtualHost(=複数証明書)を出し分けたい場合に、どの証明書を出すかをSNIで識別 します。

■httpd -S (変更前)

VirtualHost configuration:
*:443 is a NameVirtualHost
         default server site-a.example.com (/etc/httpd/conf.d/vh-site-a.conf:2)
         port 443 namevhost site-b.example.com (/etc/httpd/conf.d/vh-site-b.conf:2)

この状態では、site-b.example.com にSNIなしでアクセスするとdefaultである site-a.example.com の証明書が提示され、Hostヘッダーでルーティングしようとする際にApacheの厳格なチェックに引っかかり、421エラーが発生していました。( site-a.example.com はアクセス可能)
上記から「同じ IP・ポートで複数証明書を使うから SNI が必要になる」という理解に基づき、IPアドレスを分ければSNIなしでも正しいサイトに飛ばせるはずと考えました。


■Apache 設定例

<VirtualHost 192.168.100.10:443>
    ServerName site-a.example.com
    DocumentRoot "/var/www/html/sitea"
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/example-a.crt
    SSLCertificateKeyFile /etc/ssl/private/example-a.key
</VirtualHost>

<VirtualHost 192.168.100.20:443>
    ServerName site-b.example.com
    DocumentRoot "/var/www/html/siteb"
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/example-b.crt
    SSLCertificateKeyFile /etc/ssl/private/example-b.key
</VirtualHost>

VirtualHostを異なるIPアドレスに紐づけます。
httpd -SでVirtualHostの配置を確認し、IPアドレスが分けられたことを確認します。

■httpd -S (変更後)

VirtualHost configuration:
192.168.100.10:443     site-a.example.com (/etc/httpd/conf.d/vh-site-a.conf:2)
192.168.100.20:443     site-b.example.com (/etc/httpd/conf.d/vh-site-b.conf:2)

この対応により、上位LB側で各ドメインへのアクセス時に宛先IPを分ける設定にすることで、421エラー問題は解消しました。

更にcurlやブラウザアクセスではデフォルトでSNIが付帯されてしまい再現試験ができなかったので、下記からopensslをインストール試験を実施しました。(opensslには SNI無しオプション -noservername があり)

■ダウロードサイト

■opensslコマンド

openssl s_client -connect localhost:10001 -noservername

まとめ

・IP を分ける方法は泥臭いけど、現場ではこういう局所的な対応が求められることもある
・理想は上位 LB で SNI 対応してもらうこと
・個人的にもマイナーな情報の記事に救われたこともあるので、記録として残しておきます

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?