我有一个相当标准的设置,nginx 面向 django 应用程序。我希望 django 应用程序仅是 SSL,因此我的 nginx conf 中有两个监听块,来自端口 80(HTTP)的流量被重定向到端口 443(SSL)。这按预期工作。
我在打开了端口转发的 VM 中运行此设置,这样我就可以通过访问端口 8080 (HTTP) 或 8081 (SSL) 从主机浏览站点。同样,正如预期的那样,这项工作正常。
当我在注册工作流程期间从 Django 应用程序内部重定向时,问题就出现了。因为 Django 从来没有看到 SSL 状态(SSL 在 nginx 处终止,并且应用程序的流量通过 HTTP 在端口 5000 上转发),但确实看到了端口,所以重定向被破坏了**。
所有这一切的最终结果是我将流量定向到 SSL 端口上的 nginx,而不是 SSL,例如http://127.0.0.1:443/
. 有没有办法配置 nginx 来处理这个问题?
** 注意我在 Nginx 中设置 X-Forwarded-Proto 标头,而 Django 正在获取正确的 .is_secure() 值,这是外部库未检查 is_secure 并且仅重定向传入 URL 方案的特定问题。
[更新 1]
附件是相关的配置设置。这是来自 Vagrantfile 本身,显示了端口转发:
config.vm.forward_port 80, 8080 # website, via nginx (redirects to SSL:8081)
config.vm.forward_port 443, 8081 # website, via nginx (accepts SSL)
config.vm.forward_port 5000, 8180 # website, via gunicorn (direct)
使用上面的端口转发配置,如果我在 HTTP 端口(8080)上浏览到主机上的站点,则请求被接受,并且 nginx(见下文)将此请求重定向到 HTTPS(在端口 8081 上运行)。一旦我使用 HTTPS,网站本身就可以正常工作:
(host) http://127.0.0.1:8080 -> forwarded to -> (guest vm) http://127.0.0.1:80
(host) https://127.0.0.1:8081 -> forwarded to -> (guest vm) https://127.0.0.1:443
当我从 Django 内部获得混合方案和协议的重定向时,会出现问题,并以请求http:\\127.0.0.1:8081\...
失败告终,因为 nginx 期望 8081 上的流量是 SSL。
我真正想要的是一条规则,上面写着“在 443 上监听 SSL 和非 SSL 并重定向非 SSL”。
这是相关的nginx配置:
# Django app is served by Gunicorn, running under port 5000 (via Foreman)
upstream gunicorn {
server 127.0.0.1:5000 fail_timeout=0;
}
server {
listen 80;
# 8081 is the port I am forwarding to on the host machine
rewrite ^ https://127.0.0.1:8081$request_uri? permanent;
}
server {
listen 443;
ssl on;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers HIGH:!ADH:!MD5;
ssl_prefer_server_ciphers on;
ssl_certificate /etc/nginx/ssl/self-signed.crt;
ssl_certificate_key /etc/nginx/ssl/self-signed.key;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location /static/ {
alias /app/static/;
}
location /media/ {
alias /app/media/;
}
location / {
# everything else is to be served by the django app (upstream 'gunicorn')
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# this is set to ensure that django is_secure returns True
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://gunicorn;
}
}