Elastic Beanstalk 运行状况严重,失败并显示代码 400——即使我可以访问我的站点

Elastic Beanstalk Health Severe, failing with a code 400 -- even though I can visit my site

我在 Elastic Beanstalk 上有一个 Django 应用程序 运行。我可以在 example.com 毫无问题地访问我的网站。我已经设置了自动 https 重定向,所以它总是指向 https。我已将其设置为您无法查看站点 example.elasticbeanstalk.com 域 - 如果您去那里,您最终会收到响应代码 400。

我的 Auto Scaling 组是负载均衡的。我的应用程序未通过状态代码 400 的运行状况检查,即使我可以导航到我的站点,响应代码 200 也没有问题。我的日志显示:

***amazon IP*** (-) - - [date] "GET / HTTP/1.1" 400 26 "-" "ELB-HealthChecker/2.0"

我猜错误来自

  1. example.elasticbeanstalk.com
  2. 不允许连接
  3. Haivng 自动 HTTP -> HTTPS 重定向(尽管我猜这会产生 302)

当运行状况检查 ping 站点时,它是在 ping 您的自定义域 (example.com) 还是在固定 elasticbeanstalk.com 域?我该怎么做才能解决这个问题或进一步诊断错误?我宁愿不允许 elasticbeanstalk.com 域的流量,因为我认为我无法在该域上获得 SSL。

失败的原因是运行状况检查检查的是 EC2 实例私有 IP。这可以随 ELB 改变,因此您需要动态获取实例的私有 IP 并将其添加到主机。参见 How to dynamically add EC2 ip addresses to Django ALLOWED_HOSTS

import requests
EC2_PRIVATE_IP = None
try: EC2_PRIVATE_IP = requests.get('http://169.254.169.254/latest/meta-data/local-ipv4', timeout=0.01).text
except requests.exceptions.RequestException: pass
if EC2_PRIVATE_IP: ALLOWED_HOSTS.append(EC2_PRIVATE_IP)

(可能)错误答案

我在另一个 SO post 找到了这个答案。虽然它解决了问题,但我认为这不是一个好的答案并且可能不安全。

如果您将此代码添加到您的 .ebextensions/something.config 文件,它会将来自 Health Checker 的具有特定状态请求的任何请求重定向到您的域。

files:
  "/etc/httpd/conf.d/eb_healthcheck.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
        <If "req('User-Agent') == 'ELB-HealthChecker/2.0' && %{REQUEST_URI} == '/status/'">
            RequestHeader set Host "sub.example.com"
        </If>

/status/ 替换为 Config -> Loan Balancer -> Health Check Path 中指定的运行状况检查 url,并将 sub.example.com 替换为您的域。他们还更新了运行状况检查程序,现在 ELB-HealthChecker/2.0 -- 另一件需要注意的事情。

但是:出于安全原因,它可能不是很好,我认为这可能是欺骗性的。如果您使用默认的 / link,有人可能会欺骗 ELB-HealthChecker/2.0,然后很容易猜出您的 link。我不太了解有人可以用 set Host 命令做什么,它可能是无害的。

如果您最近迁移到 Amazon Linux2 并遇到了 IMDSv2,那么您必须像这样使用安全令牌

import requests
EC2_PRIVATE_IP = None
try:
    security_token = requests.put(
        'http://169.254.169.254/latest/api/token',
        headers={'X-aws-ec2-metadata-token-ttl-seconds': '60'}).text

    EC2_PRIVATE_IP = requests.get(
        'http://169.254.169.254/latest/meta-data/local-ipv4',
        headers={'X-aws-ec2-metadata-token': security_token},
        timeout=0.01).text
except requests.exceptions.RequestException:
    pass

if EC2_PRIVATE_IP:
    ALLOWED_HOSTS.append(EC2_PRIVATE_IP)