我可以用Nginx重定向SSL端口上的非SSL流量吗?



我有一个相当标准的设置与nginx前端的django应用程序。我希望django应用程序是SSL仅,所以我有两个监听块在我的nginx配置,与流量进入端口80 (HTTP)被重定向到端口443 (SSL)。

我在一个打开端口转发的VM中运行这个设置,这样我就可以通过转到端口8080 (HTTP)或8081 (SSL)从主机上浏览站点。同样,这个工作正常,正如预期的那样。

当我在注册流程中从Django应用程序内部重定向时,问题就出现了。因为Django从来没有看到SSL状态(SSL在nginx被终止,到应用程序的流量通过HTTP在端口5000上转发),但确实看到了端口,所以重定向被打乱了**。

所有这些的最终结果是,我有流量被定向到nginx上的SSL端口,这不是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;
    }
}

您应该查看本文档的"错误处理"部分:

http://nginx.org/en/docs/http/ngx_http_ssl_module.html

可能使用非标准错误码497来处理发送到HTTPS端口的普通HTTP请求。

像这样的东西应该可以工作(未经测试):

error_page 497 https://$host$request_uri;

命名位置也可以在error_page中使用,详见http://nginx.org/r/error_page。

最新更新