[小ネタ] Drupal 8でALBのヘルスチェックが失敗しているときの対応

AWS事業本部 梶原@福岡オフィスです。

Drupal 8のサーバ構築する機会があったのですが、気が付いたらALBがターゲットのヘルスチェックに失敗していて、 「The provided host name is not valid for this server.」 のエラーメッセージがでていたんですが、対応に小ハマりしたのでやったことをまとめます

構成

CloudFront => ALB => EC2(Apache+PHP+Drupal) のWebサイトです。

EC2のWebサーバのIPアドレスは10.0.0.1 とします。

エラーの状況

  • ALBのヘルスチェックがDrupalのインストール前は正常に行えていた。
  • ヘルスチェックのパスは"/", HTTPステータスは200
  • TargetGroupのステータスはUnhealthy状態

調査

何はともあれ、エラーが起きたときはログを確認します。

/var/log/httpd/access_log

10.0.CCC.111 - - [XX/May/2019:14:55:34 +0900] "GET / HTTP/1.1" 400 52 "-" "ELB-HealthChecker/2.0"
10.0.CCC.222 - - [XX/May/2019:14:55:35 +0900] "GET / HTTP/1.1" 400 52 "-" "ELB-HealthChecker/2.0"
※AAA.BBB.CCC.111, AAA.BBB.DDD.222はALBのアドレスです

あれ?サイトは普通に表示できてるのになんでエラーコードが400? 確認のためにローカルからチェックしてみます。

$ curl http://localhost/
The provided host name is not valid for this server.
$ curl -I http://localhost/
HTTP/1.1 400 Bad Request

確かに400ですね。ただ、ここで、

「The provided host name is not valid for this server.」

とあるので、ホスト名の問題であろうことに気づきます。 クラウドフロントからはHostヘッダが送られているので、正常にアクセスできているとふみました。 ですので、Hostヘッダ付きでローカルからリクエストしてみます。

$ curl -I -H 'Host:www.exsample.com' http://localhost/
HTTP/1.1 200 OK

さて、原因はほぼ判明しました。CloudFrontからは通常のホスト名でのアクセスで、Hostヘッダが転送されているので正常に応答が返っていると思われます。

ただ、ここで、ちょっと困りました。ALBって各EC2にヘルスチェックをしている時って、どのようにリクエスト(サーバ名を何で送っているのか)知見がありませんでした そこで、アクセスログに出力を追加しました。

/etc/httpd/conf/httpd.conf の

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

に%Vを付けてアクセスログにサーバ名をログに出すようにしました。

LogFormat "%V %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

httpdサービスを再起動し、ログを確認します。

10.0.0.1 AAA.BBB.CCC.111 - - [07/Jun/2019:18:08:40 +0900] "GET / HTTP/1.1" 400 52 "-" "ELB-HealthChecker/2.0"
10.0.0.1 AAA.BBB.DDD.222 - - [07/Jun/2019:18:08:58 +0900] "GET / HTTP/1.1" 400 52 "-" "ELB-HealthChecker/2.0"
※AAA.BBB.CCC.111, AAA.BBB.DDD.222はALBのアドレスです

LogFormat のフォーマットはこちら https://httpd.apache.org/docs/2.4/ja/mod/mod_log_config.html#formats

対応

さて、あとは、制限がかかっている原因を解消するのですが、DrupalではTrusted Host settingsでリクエストされるホストヘッダをチェックして 制限をかけているようです。

https://www.drupal.org/docs/8/install/trusted-host-settings

ということで、該当の設定部分を更新します。

setting.phpを変更します。

    $settings['trusted_host_patterns'] = array(
      '^www\.exsample\.com$',
      '^10\.0\.0\.1' <<== これを追加
     );

ここで、通常のホスト名とローカルで割り当てられるIPアドレスを設定しました。 で、OKっと行こうとしたんですが、チェックがはいりました。orz
そう、スケールアウトしたら新しいIPアドレスがEC2に設定されます。これじゃまずいです。 かといって、全部列挙するわけにもいかない。

つ 正規表現

ということで、正規表現の知見を頂きましたので、割り当てられるIPアドレス範囲を設定することにしました

    $settings['trusted_host_patterns'] = array(
      '^www\.exsample\.com$',
      '^10\.0\.0\.\d{1,3}$' <<== これを追加
     );

ただ、もっと厳密にするなら、起動時に、インスタンスメタデータでIPアドレスを取得して、setting.phpを更新するのがいいのではないかなと思います。

$ curl -q http://169.254.169.254/latest/meta-data/public-ipv4
10.0.0.1

参考

[小ネタ] EC2インスタンスメタデータを簡単に確認する

+1 対応

トップでもいいのですが、負荷低減のために Drupalにヘルスチェック用のモジュールを導入して、

https://www.drupal.org/project/health_check

ヘルスチェックのパスを /health としました。

あとは、ALBのヘルスチェックのパスを変更すれば、Healthyになるはずです! (ダメな時は再度ログからトライします!)

まとめ

ピンポイントで「The provided host name is not valid for this server.」のエラーでないと役にたたないかと思いますが 同じエラーが出た人の役にたてれば幸いです。

参考URL

https://drupal.stackexchange.com/questions/145286/what-does-the-provided-host-name-is-not-valid-for-this-server-mean