带有 Nginx 的 Django 的 build_absolute_uri 中的本地主机

Fom*_*aut 7 django nginx docker

在生产中,我使用链 Django - UWSGI - Docker - Nxing。UWSGI使用50012端口,Ngxin配置为:

proxy_pass http://localhost:50012;
Run Code Online (Sandbox Code Playgroud)

Django 进程认为它的主机localhost:50012不是 Nginx 监听的域。所以当函数build_absolute_uri被调用时,localhost:50012不是我的域。有没有办法让 Django 在build_absolute_uri被调用时使用自定义主机名?

注意:在某些build_absolute_uri隐式调用的库中(如social-django或 example),因此在我的情况下避免使用此函数不是解决方案。

Pau*_*ine 10

问题

当用于访问代理的公共主机名与应用程序服务器的内部主机名不同时,除非代理传递此信息,否则 Django 无法知道原始请求中使用了哪个主机名。

可能的解决方案

1) 设置代理沿原主机传递

来自MDN

X-Forwarded-Host (XFH) 标头是事实上的标准标头,用于在 Host HTTP 请求标头中标识客户端请求的原始主机。

反向代理(负载均衡器、CDN)的主机名和端口可能与处理请求的源服务器不同,在这种情况下,X-Forwarded-Host 标头可用于确定最初使用的是哪个主机。

你应该做两件事:

  1. 确保 Django 前面的所有代理都沿着X-Forwarded-Host标头传递
  2. USE_X_FORWARDED_HOST在设置中开启
  3. 如果内部和外部方案也不同,则设置SECURE_PROXY_SSL_HEADER一个有意义的值并设置服务器发送相应的标头

USE_X_FORWARDED_HOST设置为Truein 时settings.pyHttpRequest.build_absolute_uri使用X-Forwarded-Host标题而不是request.META['HTTP_HOST']or request.META['SERVER_NAME']

我不会深入研究代理设置部分(因为它与专业网络管理相关,而不是与本站点范围内的编程相关),但对于 nginx,它应该是这样的:

location / {
    ...
    proxy_set_header X-Forwarded-Host $host:$server_port;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    ...
    proxy_pass http://upstream:port;
}    
Run Code Online (Sandbox Code Playgroud)

可能是最好的解决方案,因为它是完全动态的,如果将来公共方案/主机名发生变化,您无需更改任何内容。

如果内部和外部的方案也不同,你可能要设置SECURE_PROXY_SSL_HEADERsettings.py来是这样的:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
Run Code Online (Sandbox Code Playgroud)

然后将以下内容添加到服务器配置中:

proxy_set_header X-Forwarded-Proto https;
Run Code Online (Sandbox Code Playgroud)

2)对公共和私人服务器使用相同的主机名

假设您的公共主机名是“host.example.com”:您可以将这样的行添加到您的/etc/hosts(在 Windows 上%windir%\System32\drivers\etc\hosts):

127.0.0.1    host.example.com
Run Code Online (Sandbox Code Playgroud)

现在您可以在 nginx 配置中使用主机名:

proxy_pass http://host.example.com:port;
Run Code Online (Sandbox Code Playgroud)

当内部和外部方案也不同(外部 https、内部 http)时,您可能需要SECURE_PROXY_SSL_HEADER按照第一个解决方案中的描述进行设置。

每次公共主机名更改时,您都必须更新配置,但我想这对于小型项目来说是可以的。

  • 谢谢,这对我的情况非常有效!如果需要的话,我会添加到您的答案中的一项可选内容是“X-Forwarded-Proto:https”。 (2认同)