使用 nginx 的单个端口处理 http 和 https 请求

ale*_*ini 19 http nginx https lighttpd

我想知道 nginx 是否能够在同一个端口上处理 http 和 https 请求。[*]

这就是我想要做的。我正在运行处理 http 请求的 Web 服务器 (lighttpd),以及通过 https 为文档树的特定部分提供服务的 C 程序。这两个进程运行在同一台服务器上。

在防火墙级别,我只能有一个端口将流量转发到此服务器。所以我想做的是在这台服务器上设置 nginx 以便它侦听单个端口上的请求,然后:

A) 重定向所有http://myhost.com/*请求,以便它们转到 localhost:8080(lighttpd 正在侦听的位置)

B) 如果用户请求以 https://myhost.com/app 开头的 URL,它会将该请求发送到 localhost:8008(C 程序)。请注意,在这种情况下,远程浏览器和 nginx 之间的流量必须加密。

你认为这可能吗?如果是,怎么做?

我知道如何使用两个不同的端口来做到这一点。我面临的挑战是仅使用一个端口来完成此操作(不幸的是,我无法控制此特定环境中的防火墙配置,因此这是我无法避免的限制)。使用诸如通过 ssh 进行反向端口转发来绕过防火墙的技术也不起作用,因为这应该适用于只有 Web 浏览器和 Internet 链接的远程用户。

如果这超出了 nginx 的能力,您知道还有其他产品可以满足此要求吗?(到目前为止,我在使用 lighttpd 和 pound 进行设置时没有成功)。我也更喜欢避免使用 Apache(尽管如果这是唯一可能的选择,我愿意使用它)。

提前致谢,亚历克斯

[*] 为了清楚起见,我说的是通过同一端口处理加密未加密的 HTTP 连接。加密是通过 SSL 还是 TLS 完成都没有关系。

小智 21

根据维基百科关于状态代码的文章,当 http 流量发送到 https 端口时,Nginx 有一个自定义错误代码(错误代码 497)

根据error_page上的nginx 文档,您可以定义一个 URI,该 URI 将针对特定错误显示。
因此,我们可以创建一个 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果客户端通过 GET 以外的任何其他方法发出请求,则该请求将转换为 GET。从而保留客户端通过的请求方法;我们使用错误处理重定向,如error_page 上的 nginx 文档中所示

这就是我们使用301 =307重定向的原因。

使用此处显示的 nginx.conf 文件,我们可以让 http 和 https 侦听同一端口


小智 18

对于那些可能正在搜索的人:

添加ssl on;error_page 497 $request_uri;到您的服务器定义。

  • HoverHells 答案几乎没有改进:将 `ssl on;` 和 `error_page 497 =200 $request_uri;` 添加到您的服务器定义中。这会将状态代码更改为 200。 (9认同)

Sam*_*ull 5

从 1.15.2 开始,这终于可以正确执行了。请参阅此处的信息。

在你的 nginx.conf 中添加一个这样的块(在 http 块之外):

stream {
    upstream http {
        server localhost:8000;
    }

    upstream https {
        server localhost:8001;
    }

    map $ssl_preread_protocol $upstream {
        default https;
        "" http;
    }

    server {
        listen 8080;
        listen [::]:8080;
        proxy_pass $upstream;
        ssl_preread on;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以创建你的普通服务器块,但是监听这些不同的端口:

server {
    listen 8000;
    listen [::]:8000;
    listen 8001 ssl;
    listen [::]:8001 ssl;
...
Run Code Online (Sandbox Code Playgroud)

这样,流块能够预读并检测它是否是 TLS(在本例中在端口 8080 上),然后代理将其传递到本地正确的服务器端口。


Wil*_*sum 1

我认为没有任何东西可以在单个端口上处理两种不同的协议......

我很好奇为什么你只能转发一个端口,但除此之外......这并不理想,但如果我处于你的位置,我会通过 https 提供所有服务。