NGINX 代理传递到 WebSocket 和 PHP 无法使用 SSL

NGINX 代理传递到 WebSocket 和 PHP 无法使用 SSL

我试图路线Nginx 中的请求方式如下:

  1. 向 发出的请求/应该转到 PHP 脚本(proxy.php,它本身就是一个代理)
  2. 请求/websocket应代理至http://localhost:4000/websocket
  3. 所有其他请求都应代理至http://localhost:4000/

我可以得到2.3.使用以下配置工作:

server {
    listen 443 ssl;

    server_name proxy.domain.com;

    ssl_certificate /etc/nginx/ssl/proxy.domain.com/468446/server.crt;
    ssl_certificate_key /etc/nginx/ssl/proxy.domain.com/468446/server.key;

    location = /websocket/ {
        proxy_pass http://127.0.0.1:4000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   Host      $http_host;
        proxy_pass         http://127.0.0.1:4000;
    }

}

然后我尝试找到一种方法来添加1.并得出了以下结论:

server {
    listen 443 ssl;

    server_name proxy.domain.com;

    root /var/www/dowmain;

    ssl_certificate /etc/nginx/ssl/proxy.domain.com/468446/server.crt;
    ssl_certificate_key /etc/nginx/ssl/proxy.domain.com/468446/server.key;

    location = /websocket/ {
        proxy_pass http://127.0.0.1:4000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   Host      $http_host;
        proxy_pass         http://127.0.0.1:4000;
    }

    location = / {
        include fastcgi_params;
        fastcgi_param   SCRIPT_FILENAME  $document_root/proxy.php;
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
    }

}

然而,在这种配置下,2.不再起作用。对 的请求/websocket由 PHP 脚本处理。似乎/websocket位置块不再起作用。

有趣的是,如果我将配置切换为http://,一切都会正常工作。

知道我做错了什么吗?

更新

我认为我可以排除location /websocket { ... }是问题的根源,因为如果我location = / { ... }用块中的规则替换块中的 PHP 配置内容location / { ... },它会正常工作(但这不是我需要的)。所以我怀疑是 PHP 把一切都搞乱了。

更新二

它甚至可以在我的本地机器上使用来自的证书mkcert,并且具有完全相同的配置。

所以唯一的区别是让我们加密证书与本地证书。甚至 Nginx 和 PHP 版本也基本相同(我本地机器上的 PHP 7.2.7、Nginx 1.15.1 与 PHP 7.2.13、Nginx 1.15.6)

答案1

似乎包含 proxy_pass 指令的位置末尾的斜杠有问题。您可以尝试将其添加到您的 websocket 位置:

location /websocket/ {
    proxy_pass http://127.0.0.1:4000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

也因为我从 proxy_pass 指令中删除了 /websocket/,因为您将 URI 的“/webconfig”部分替换为“/webconfig/”,这很令人困惑

如果 proxy_pass 指令指定了 URI,那么当请求传递给服务器时,规范化请求 URI 中与位置匹配的部分将被指令中指定的 URI 替换。

对于主要问题——基于Nginx 文档

如果位置由以斜杠字符结尾的前缀字符串定义,并且请求由 proxy_pass、fastcgi_pass、uwsgi_pass、scgi_pass、memcached_pa​​ss 或 grpc_pass 之一处理,则将执行特殊处理。响应 URI 等于此字符串但没有尾部斜杠的请求,将返回带有代码 301 的永久重定向到附加了斜杠的请求 URI。

我认为您的情况下,websocket 位置没有尾随斜杠,并且根据此规则它被 301 重定向到 / 位置。

答案2

您的配置对我来说看起来不错,我在我的 nginx 设置中仔细检查了它,它做了它需要做的事情。我通过在不同位置添加标头进行了检查:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name proxy.domain.com;
    root /var/www/dowmain;

    ssl_certificate /etc/nginx/ssl/proxy.domain.com/468446/server.crt;
    ssl_certificate_key /etc/nginx/ssl/proxy.domain.com/468446/server.key;

    ssl_protocols TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/nginx/dhparams.pem;

    location /websocket {
        proxy_pass http://127.0.0.1:4000/websocket/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        add_header X-location websocket always;
    }

    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   Host      $http_host;
        proxy_pass         http://127.0.0.1:4000;
        add_header X-location wildcard always;
    }

    location = / {
        include fastcgi_params;
        fastcgi_param   SCRIPT_FILENAME  $document_root/proxy.php;
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
        add_header X-location root always;
    }
}

然后使用以下命令检查标题:

$ curl -I https://proxy.domain.com
$ curl -I https://proxy.domain.com/anythingelse
$ curl -I https://proxy.domain.com/websocket

输出应包含:

X-location: websocket
或者:
X-location: wildcard
或者:
X-location: root

X-location 的值应该与您在 nginx 配置中为该块设置的值相匹配。

我的 nginx 版本是:

# nginx -v
nginx version: nginx/1.10.1

相关内容