我想知道如果nginx能够处理http和https请求在同一个端口 。 [*]
这就是我想要做的。 我正在运行处理http请求的web服务器(lighttpd),以及一个通过https服务文档树的特定部分的C程序。 这两个进程在同一台服务器上运行。
在防火墙级别, 我只能有一个端口将stream量转发到此服务器 。 所以我想要做的就是在这个服务器上设置nginx,以便它监听单个端口上的请求,然后:
A)redirect所有http://myhost.com/ *请求,以便它们转到localhost:8080(lighttpd正在侦听)
B)如果用户请求以https:// myhost.com/app开头的URL,则将该请求发送到localhost:8008(C程序)。 请注意,在这种情况下,远程浏览器和nginx之间的stream量必须encryption。
你认为这可能吗? 如果是这样,怎么办?
我知道如何使用两个不同的端口来做到这一点。 我面临的挑战是只用一个端口(不幸的是,我无法控制这个特定环境的防火墙configuration,所以这是我无法避免的限制)。 使用像通过ssh的反向端口技术绕过防火墙的技术也将无法正常工作,因为这应该适用于远程用户只有一个Web浏览器和互联网链接。
如果这超出了nginx的能力,你是否知道任何其他能满足这个要求的产品? (到目前为止,我已经用lighttpd和英镑设置这个不成功)。 我也更喜欢避免Apache(尽pipe我愿意使用它,如果它是唯一可能的select)。
在此先感谢,亚历克斯
[*]要清楚,我正在谈论通过同一个端口处理encryption和未encryption的HTTP连接。 encryption是通过SSL还是TLS完成并不重要。
对于那些可能正在search的人:
添加ssl on; 和error_page 497 $request_uri; 到你的服务器定义。
根据维基百科有关状态码的文章,当httpstream量发送到https端口时,Nginx具有自定义错误代码(错误代码497)
根据error_page上的nginx文档 ,您可以定义一个将显示特定错误的URI。
因此,我们可以创build一个uri,当错误代码497被引发时,客户端将被发送到uri。
#lets assume your IP address is 89.89.89.89 and also that you want nginx to listen on port 7000 and your app is running on port 3000 server { listen 7000 ssl; ssl_certificate /path/to/ssl_certificate.cer; ssl_certificate_key /path/to/ssl_certificate_key.key; ssl_client_certificate /path/to/ssl_client_certificate.cer; error_page 497 301 =307 https://89.89.89.89:7000$request_uri; location / { proxy_pass http://89.89.89.89:3000/; proxy_pass_header Server; proxy_set_header Host $http_host; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Protocol $scheme; } }
但是,如果客户端通过除GET之外的其他方法发出请求,则该请求将变成GET。 从而保留客户端通过的请求方式; 我们使用error handlingredirect,如error_page上的nginx文档所示
这就是为什么我们使用301 =307redirect。
使用这里显示的nginx.conf文件,我们可以让http和https在同一个端口上监听
如果你想要非常聪明,你可以使用连接代理的东西来嗅探传入数据stream的前几个字节,并根据字节0的内容交换连接:如果它是0x16(SSL / TLS'握手“字节),将连接传递给SSL端,如果是字母字符,则执行正常的HTTP。 我对端口编号的评论适用 。
是的,这是可能的,但需要修补nginx源代码(HoverHell有解决scheme,而不需要修补)。 Nginx认为这是错误的configuration,而不是有效的configuration。
variables$ ssl_session_id可以用来区分plain和ssl连接。
针对nginx-0.7.65的补丁:
--- src/http/ngx_http_request.c-orig 2011-05-03 15:47:09.000000000 +0200 +++ src/http/ngx_http_request.c 2011-05-03 15:44:01.000000000 +0200 @@ -1545,12 +1545,14 @@ c = r->connection; + /* disable plain http over https port warning if (r->plain_http) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent plain HTTP request to HTTPS port"); ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS); return; } + */ #if (NGX_HTTP_SSL)
服务器configuration:
server { listen 80; index index.html; location / { root html; if ($ssl_session_id) { root html_ssl; } } ssl on; ssl_certificate cert.crt; ssl_certificate_key cert.key; }
我不认为有任何东西可以处理单个端口上的两个不同的协议…
我很好奇,为什么你只能转发一个端口,但是这不是理想的,但如果我在你的鞋子,我会通过https服务的一切。
你不能在同一个端口上同时支持HTTP和HTTPS,因为连接的两端都希望讲一种特定的语言,如果另一端说的是别的,他们不够聪明。
正如你对Wil的回答build议,你可以使用TLS升级(我相信较新的nginx版本支持它,虽然我还没有尝试过),但是这不是运行HTTP和HTTPS,它只是运行HTTP升级TLS。 问题仍然是浏览器支持 – 大多数浏览器(仍然)不支持它。 如果你有一个有限的客户群,然而这是一个可能性。
我不确定它是如何实现的,但CUPSD在端口631上对http和https做出了响应。如果现在nginx无法做到这一点,也许他们可以从CUPS团队如何借鉴它,但CUPS是在GPL,所以如果nginx想要实现这样的function,并且在其他地方找不到代码,nginx可能不得不考虑更改其许可证。
从理论上讲,你可以有一个可以通过HTTP访问的网页,可以在https:443上打开一个WebSocket到任意位置。 WebSocket初始握手是HTTP。 所以,是的,有可能使一个不安全的页面实际上能够安全通信。 你可以用Netty库来做到这一点。