为了将我的域切换到 HTTPS,我是否需要更改 Apache 或我的 Node.js 应用程序?

In order to switch my domain to HTTPS, do I need to change Apache or my Node.js app?

我有一个网络应用 运行 在我的域中。首先,我有一个常规的 HTTP 站点,它在我服务器上的端口 8082 上 运行ning,而 Apache 服务器(使用虚拟主机)将请求从端口 80 重定向到 localhost:8082

现在我得到了一个 SSL 证书,我试图在我的网站上安装它。我在 Node 中创建了一个 HTTPS 服务器,在 https://localhost:8082 上一切正常。

但后来我尝试通过 HTTPS 为我的域提供服务。我尝试编辑我的虚拟主机文件以使用证书,但我认为我没有正确编写它。另外,我试图让它将 HTTP 重定向到 HTTPS,但它没有用。

我该怎么办?我应该 运行 Node 中的 HTTP 还是 HTTPS 服务器,我应该在 Apache 虚拟主机配置中添加什么?

这是我的虚拟主机文件:

<VirtualHost *:80>
        ServerName www.domain.com
        Redirect permanent / https://www.domain.com
</VirtualHost>

<VirtualHost *:443>

        ServerName domain.com
        ServerAlias www.domain.com

        SSLEngine On
        SSLProxyEngine On
        SSLCertificateFile "/home/USERNAME/Projects/NODEAPP/chained.pem"
        SSLCertificateKeyFile "/home/USERNAME/Projects/NODEAPP/domain.key"

        ProxyPreserveHost On
        ProxyRequests off

        <Proxy *>
                Order deny,allow
                Allow from all
        </Proxy>

        <Location />
                ProxyPass http://localhost:8082/

                ProxyPassReverse http://localhost:8082/
        </Location>

</VirtualHost>

(公平警告:我对你的问题的理解是你希望 https://www.domain.com 出现在浏览器的 URL 栏中,而不是 https://www.domain.com:8082。如果不是这样的话,很多以下是错误的,但可能仍会帮助您更好地理解您的问题。)

背景

(又名 HTTP 设计速成班,因为我认为您不太了解发生了什么,但如果您了解,请随时跳过:)

我认为您对 Apache 正在做什么有误解 - 主要是因为您说它是 "redirecting" 请求。

HTTP 重定向是状态代码在 3xx 范围内的任何(?)响应,它告诉您的浏览器它所请求的资源已移动到其他地方。例如,假设 http://example.com/foo 曾经存在,但后来被移至 http://example.org/bar(注意 .com.org 的区别)。如果您在 URL 栏中输入 http://example.com/foo,您的浏览器将向 example.com 请求 /foo(具体来说,它将发送一个 HTTP GET 请求)。 example.com 然后会将 HTTP 响应发送回浏览器 重定向 http://example.org/bar。然后浏览器将向 /bar 发送一个 HTTP GET 请求到 example.org 并返回一个包含资源的响应。

这是一张图表:

Step 1:

-------------                                   --------------------------
|           |                                   |                        |
|  Browser  | -------- HTTP GET /foo ---------> | example.com web server |
|           | <-- HTTP 301 Moved Permanently -- |                        |
-------------                                   --------------------------

Step 2:

-------------                        --------------------------
|           |                        |                        |
|  Browser  | --- HTTP GET /bar ---> | example.org web server |
|           | <---- HTTP 200 OK ---- |                        |
-------------                        --------------------------

现在,事情是这样的。那是不是你正在做的,也不是你想做的。您正在做的事情称为反向代理,只要 Web 服务器(在您的情况下是 Apache)收到请求,它就会将其转发到其他地方。在您最初的 (all-HTTP) 设置中,Web 浏览器会向 Apache 请求 www.domain.com,然后 Apache 会简单地将该请求转发到 http://localhost:8082,几乎没有任何修改。这是图表:

Step 1:

-------------                        ----------                        ------------------
|           |                        |        |                        |                |
|           | ----- HTTP GET / ----> |        |                        |                |
|  Browser  |                        | Apache | ----- HTTP GET / ----> | localhost:8082 |
|           |                        |        | <---- HTTP 200 OK ---- |                |
|           | <---- HTTP 200 OK ---- |        |                        |                |
-------------                        ----------                        ------------------

Step 2:

There is no step 2. BOOM.

这里要注意的真正重要的事情是浏览器不会 "see" Node.js,它在另一端看到 Apache。同样,Node.js 不会 "see" 浏览器,它会看到 Apache(尽管通常 Apache 会使用有关浏览器连接的详细信息来增加请求 - 例如参见 [​​=29=] header) .

这是 HTTP 设计的有意部分 - HTTP 请求和响应语义不暗示有关如何处理请求的内部实现细节的任何内容。这就是 HTTP 如此强大的原因。它可以让你创建非常复杂的设置——想想你在做什么,但规模更大,组件更多——然后用一个向外部世界显示的简单、统一的界面来抽象复杂的事情:你的URL 层次结构与 HTTP request/response 循环相结合。

如何解决你的实际问题

现在我们已经确定了您想要做什么,这就是您的问题所在:您将协议 Node.js 与什么通信混为一谈Apache 正在说话的协议(以及外部世界所看到的)。

您的最终目标是让人们通过 HTTPS 连接到您的网站,对吧?在那种情况下,您不需要 Node.js 来使用 HTTPS,因为唯一直接与 Node.js 对话的是 Apache。 Apache 是与浏览器对话的东西,所以 Apache 是您使用 HTTPS 所需要的。理想情况下,您应该让 Apache 向浏览器发送 HTTPS 并向 Node.js 发送 HTTP - Apache 是否加密到 Node 的流量并不重要,因为 Node 位于本地主机上。图表形式:

-------------                         ----------                        ------------------
|           |                         |        |                        |                |
|           | ----- HTTPS GET / ----> |        |                        |                |
|  Browser  |                         | Apache | ----- HTTP GET / ----> | localhost:8082 |
|           |                         |        | <---- HTTP 200 OK ---- |                |
|           | <---- HTTPS 200 OK ---- |        |                        |                |
-------------                         ----------                        ------------------

因此让您的 Node 应用程序侦听 HTTP 请求,然后修复您的 Apache 配置以使用 HTTPS 提供内容,但将 HTTP 传送到 Node 后端。

我认为您的配置有问题,您需要在路径周围加上引号,即 <Location "/">。或者,在我拥有的反向代理配置中,我设置了没有 <Location> 块的 ProxyPass 指令,如下所示:

ProxyPass / http://localhost:8082/
ProxyPassReverse / http://localhost:8082/

所以你也可以试试。

如果它仍然不起作用,请尝试删除 <Proxy>/</Proxy> 块 - 我不太确定它的作用,但我没有类似的东西反向代理配置(有效)- 所以它可能会干扰某些东西。

至于您的 HTTP 到 HTTPS 重定向,我真的没有发现任何问题。您确定要连接到 www.domain.com 而不是 domain.com 吗?第二个 VirtualHost 为两者提供服务,但第一个仅为前者提供服务。

根据您的描述,我将您的问题总结如下:

  1. 您已将 node.js 配置为接受 TLS 连接

  2. 您希望 Apache 接受 TLS 连接

好的。所以第一个问题。你说:

I made https server in Node, and on https://localhost:8082 everything worked as it should.

在不做任何更改的情况下,当您尝试访问 http://localhost:8082 时会发生什么?我可以告诉你会发生什么(没有猜测,没有 "should",我可以肯定地告诉你)但你至少应该尝试一下,以便自己看看会发生什么。

剧透:HTTP 不支持在单个端口上同时侦听 TLS 和未加密的连接。这只是指定协议的方式。其他协议(如 POP3、SMTP、FTP 等)可以执行此操作,但 HTTP 不能。所以尝试访问 http://localhost:8082 会失败。

现在,仔细查看您的 Apache 配置:

# THIS is the problematic part:
ProxyPass         http://localhost:8082/
ProxyPassReverse  http://localhost:8082/
#                   ^
#                   |______ notice this?

所以问题是您正在代理到一个不起作用的 url。

这里有两种选择。它们都有效,具体取决于您希望如何设计架构。

  1. 代理 https 而不是 http

    ProxyPass         https://localhost:8082/
    ProxyPassReverse  https://localhost:8082/
    

    这样做的好处是您可以获得端到端的加密。即使有人设法登录到您的服务器,他们也无法监听连接。这样做的缺点是您要加密两次,这意味着您要使用更多 CPU 时间来处理请求。

  2. 从 node.js 移除 TLS。

    这样做的好处是您让 Apache 处理所有加密,因此您的 Web 应用程序不需要花费任何 CPU 时间来处理加密本身。对于像 Google 或 Facebook 这样的非常大的服务,他们甚至可以将加密卸载到另一个前端服务器(或更可能的服务器),这样服务器 运行 您的网络应用程序就不会忙于加密和解密HTTP 连接。缺点是任何可以登录到您的服务器的人都可以轻松监听连接。

有些人还有第三种方法,但它越来越不流行了。 运行 node.js 侦听两个端口。例如,配置一个监听 8082 的 http 和 8084 的 https,然后你可以将 http 页面代理到 8082,将 https 页面代理到 8084。但是,查看你的 Apache 配置我可以告诉你这不是你想要做的.