NGINX 作为 Apache 前面的反向代理在启用 SSL 的情况下无法工作

NGINX 作为 Apache 前面的反向代理在启用 SSL 的情况下无法工作

我已经阅读了论坛上的每篇帖子、教程和评论,但一旦在 Nginx 服务器块内启用 SSL,我仍然无法让 Nginx 代理正常工作。

Apache 已完全设置虚拟主机,用于常规和 SSL 访问。Apache 正在监听端口 8081,ports.conf 如下:

NameVirtualHost *:8081
Listen 8081

<IfModule ssl_module>
        Listen 443
</IfModule>

<IfModule mod_gnutls.c>
        Listen 443
</IfModule>

我的 SSL apache vhost 如下:

开启 nginx 并注释掉 ssl 设置(如以下配置所示)(见下文),一切正常,因为我能够正确访问站点的 SSL 和非 SSL 版本。

    server {
        listen 80;
  #      listen 443 ssl;
        server_name foobar.net;

   # ssl on;
   #     ssl_certificate /etc/letsencrypt/live/foobar.net/fullchain.pem;
   #     ssl_certificate_key /etc/letsencrypt/live/foobar.net/privkey.pem;

        location / {
            proxy_pass http://104.236.224.53:8081;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }

当我修改上述文件并通过取消注释服务器块中的选项来打开 SSL 时,Nginx 和 Apache 在端口 443 上似乎存在冲突?

更新且取消注释的服务器块如下所示:

    server {
        listen 80;
        listen 443 ssl;
        server_name foobar.net;

    ssl on;
        ssl_certificate /etc/letsencrypt/live/foobar.net/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/foobar.net/privkey.pem;

        location / {
            proxy_pass http://104.236.224.53:8081;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }

尝试启动 nginx 返回以下错误:

 nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Mon 2017-02-20 18:35:20 EST; 16s ago
  Process: 14505 ExecStop=/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid (code=exited, status=0/SUCCESS
  Process: 14475 ExecReload=/usr/sbin/nginx -g daemon on; master_process on; -s reload (code=exited, status=0/SUCCESS)
  Process: 14671 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=1/FAILURE)
  Process: 14652 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
 Main PID: 14328 (code=exited, status=0/SUCCESS)

Feb 20 18:35:18 foo.foobar.net nginx[14671]: nginx: [emerg] listen() to 0.0.0.0:443, backlog 511 failed (98: Address already in use)
Feb 20 18:35:18 foo.foobar.net nginx[14671]: nginx: [emerg] listen() to 0.0.0.0:443, backlog 511 failed (98: Address already in use)
Feb 20 18:35:19 foo.foobar.net nginx[14671]: nginx: [emerg] listen() to 0.0.0.0:443, backlog 511 failed (98: Address already in use)
Feb 20 18:35:19 foo.foobar.net nginx[14671]: nginx: [emerg] listen() to 0.0.0.0:443, backlog 511 failed (98: Address already in use)
Feb 20 18:35:20 foo.foobar.net nginx[14671]: nginx: [emerg] listen() to 0.0.0.0:443, backlog 511 failed (98: Address already in use)
Feb 20 18:35:20 foo.foobar.net nginx[14671]: nginx: [emerg] still could not bind()
Feb 20 18:35:20 foo.foobar.net systemd[1]: nginx.service: Control process exited, code=exited status=1
Feb 20 18:35:20 foo.foobar.net systemd[1]: Failed to start A high performance web server and a reverse proxy server.
Feb 20 18:35:20 foo.foobar.net systemd[1]: nginx.service: Unit entered failed state.
Feb 20 18:35:20 foo.foobar.net systemd[1]: nginx.service: Failed with result 'exit-code'.

我在实现 SSL 从 Nginx 正确传递到 Apache 的过程中遗漏了什么?


编辑1: 为了解决@Tim 的观点,我将编辑我的主要意图,让 Nginx 处理所有请求。

  • 我最初的意图是将 Discourse 安装到 Docker 容器中,安装在已经使用 Apache 作为主服务器的同一台机器上。
  • 因为 Discourse 需要访问端口 80 才能正常运行,所以建议在前面设置 nginx 作为反向代理来处理所有传入请求,以便相应地传递它们。
  • 我想在后端使用 apache 来处理所有动态内容,并让 nginx 处理静态位。因此,我的理解是,为了做到这一点,需要在 apache 上为每个实例建立一个虚拟主机:http 和 https 请求。也许我在这一点上错了?

我遵循了建议的配置DigitalOcean:快进到他们的可选步骤 9。

从逻辑上讲,正如我在 Apache 上有一个 HTTP 主机监听端口 8081 以接收从 nginx 传递过来的请求一样,我假设我可以做同样的事情,让 Apache 上的 HTTPS 主机监听端口 8081,并优雅地将标头传递给 Apache 来处理其余部分。这个实现并没有完全发挥作用,因为我被错误所困扰400: the plain http request was sent to https port

我进一步假设,也许因为 Apache HTTP 和 HTTPS 都在监听端口 8081,如果我将指定的 apache HTTP 分配给端口 8081,将 HTTPS 分配给端口 1443,那么一切都会无缝运行。同样,它不能完全工作,因为当我尝试使用此实现通过 HTTPS 访问我的 worpress 博客时,我收到错误

Your browser sent a request that this server could not understand.
Reason: You're speaking plain HTTP to an SSL-enabled server port.
Instead use the HTTPS scheme to access this URL, please.

在这一点上,尽管似乎很多人已经让数字海洋建议的实施方案正常运行,但我确实已经没有什么想法了。:-/

答案1

您已告知 Apache 和 Nginx 监听端口 443,我假设它们在同一台机器上。一个端口只能有一个应用程序监听。

也许您可以编辑您的问题以告诉我们您为什么要同时使用 Nginx 和 Apache - 您可以使用其中任何一个完成大多数事情。这样您可能会得到更多有用的建议。

答案2

看来我终于实现了,这要感谢你们提供的所有反馈。谢谢@AlexeyTen 和@Tim

  • 首先,我在 apache 上为域名 foobar.net 禁用了 https vhostsudo a2dissite foobar.net.cong

  • 我编辑了 apache ports.conf 文件以仅监听端口 8081 并删除了对端口 443 的监听:

NameVirtualHost *:8081

Listen 8081
  • 最后,我编辑了 nginx 服务器块以监听端口 443,并确保注释掉ssl on。不这样做是行不通的。
> server {
>     listen 80;
>     listen 443 ssl;
>     server_name foobar.net;
> 
>   # ssl on;
>     ssl_certificate /etc/letsencrypt/live/foobar.net/fullchain.pem;
>     ssl_certificate_key /etc/letsencrypt/live/foobar.net/privkey.pem;
> 
>     location / {
>         proxy_pass http://104.236.224.53:8081;
>         proxy_set_header Host $host;
>         proxy_set_header X-Real-IP $remote_addr;
>         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
>         proxy_set_header X-Forwarded-Proto $scheme;
>     } }

该实现看起来运行良好,并且无缝地将 php 处理移交给 Apache。

答案3

@Robert,您的解决方案有效,但没有在浏览器中加载 SSL 证书。

我的解决方案如下:

将 apache 的默认端口从 80 更改为 8080

将 apache 的默认 SSL 端口从 443 更改为 444

以下是我的 ngnix 配置:

server 
{

listen 80;

    server_name servername.com;

location / {

        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        expires off;
    }
}


server {

    listen 443 ssl http2;
    server_name servername.com;
    ssl on;
    ssl_certificate /etc/nginx/ssl/keyname.crt;
    ssl_certificate_key /etc/nginx/ssl/private/keyname.key;

location / {

        proxy_pass https://127.0.0.1:444;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        expires off;
    }
}

笔记:

  1. 如果使用 SSL,需要将 proxy_pass 更改为 https。
  2. 当 nginx 作为 apache 的反向代理时,这种方法可以正常工作。
  3. 需要修改 apache vhost 以包含 444 而不是 443 来进行 SSL 配置。
  4. 在 apache 中将 ports.conf 配置为 444 以用于 SSL

相关内容