我正在使用 Django,并且我有
ALLOWED_HOSTS
设置来包含我的 EC2
的私有 IP,如下所示:
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 and not DEBUG:
ALLOWED_HOSTS.append(EC2_PRIVATE_IP)
问题是上述内容没有考虑将请求转发到我的
ELB
实例的 EC2
。有没有办法让它以编程方式工作?我可以请求公共 IP 地址或设置检查 DNS 吗?
我发现 ELB 的公共 IP 地址存在此问题。
另一个简单的解决方案是编写一个自定义的
MIDDLEWARE
,它将在检查 ALLOWED_HOSTS
之前向 ELB 提供响应。所以现在您不必动态加载 ALLOWED_HOSTS
。
中间件可以很简单:
project/app/middleware.py
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin
class HealthCheckMiddleware(MiddlewareMixin):
def process_request(self, request):
if request.META["PATH_INFO"] == "/ping/":
return HttpResponse("pong")
settings.py
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'app.middleware.HealthCheckMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
...
]
Django 中间件参考 https://docs.djangoproject.com/en/dev/topics/http/middleware/
获取AWS内部IP并添加到ALLOWED_HOST并不是最好的解决方案。由于此获取仅在应用程序重新加载时发生。 ELB IP 可以随时更改。
取而代之的是,我们可以在 nginx 中设置实际的主机标头,如果请求来自 IP。
功劳归于: https://www.xormedia.com/django-allowed-hosts-and-amazon-elastic-load-balancer/
我最近也遇到这个问题了。目前的答案大致是OP所描述的,但它还涉及预先获取访问令牌并在请求中使用它。我的设置位于负载均衡器后面的 Elastic Beanstalk 上,运行状况检查器请求 EC2 实例的私有 IP,如果私有 IP 不在 ALLOWED_HOSTS 中,则会失败。当获取并添加私有IP后,它就可以工作了。 EB 运行状况检查器似乎需要实例的私有 IP,而不是负载均衡器的私有 IP。
我从这个问题的答案中得到了答案。我对其进行了一些修改,将生成的 ip 缓存在临时文件中一段时间,这样站点就不需要每次有人加载页面时都发出请求。
private_ip = None
private_ip_filepath = "{dir}/private-ip.txt".format(dir=tempfile.gettempdir().rstrip('/'))
if os.path.exists(private_ip_filepath):
if datetime.datetime.now() - datetime.datetime.fromtimestamp(os.path.getmtime(private_ip_filepath)) < datetime.timedelta(seconds=3600):
with open(private_ip_filepath, "r") as f:
private_ip = f.read().strip()
else:
os.remove(private_ip_filepath)
if not private_ip:
if STAGE == 'local':
private_ip = "127.0.0.1"
else:
# https://stackoverflow.com/questions/47277541/how-to-dynamically-add-ec2-ip-addresses-to-django-allowed-hosts
try:
IMDSv2_token = requests.put('http://169.254.169.254/latest/api/token', headers={
'X-aws-ec2-metadata-token-ttl-seconds': '3600',
}).text
private_ip = requests.get('http://169.254.169.254/latest/meta-data/local-ipv4', timeout=0.01, headers={
'X-aws-ec2-metadata-token': IMDSv2_token
}).text
except requests.exceptions.RequestException:
pass
with open(private_ip_filepath, "w") as f:
f.write(private_ip)
if private_ip:
ALLOWED_HOSTS.append(private_ip)
目前接受的答案是编写中间件以始终返回健康响应,这违背了健康检查器的目的。另一种答案是忽略来自客户端的 Host 标头并将其替换为有效的标头,这违背了 ALLOWED_HOSTS 的目的。