Я пытаюсь маршрут запросы в Nginx следующим образом:
/
должен перейти к сценарию PHP (proxy.php
, который сам по себе является прокси) /websocket
должен быть проксирован на http://localhost:4000/websocket
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 { ... }
как источник проблемы, потому что если я заменю конфигурационный файл PHP в location = / { ... }
блок с правилами из location / { ... }
блок, он работает нормально (но это не то, что мне нужно). Я подозреваю, что PHP все испортил.
ОБНОВЛЕНИЕ II
Он работает даже на моем локальном компьютере с сертификатами от mkcert
, с точно такой же конфигурацией.
Так что единственная разница в том, Давайте зашифровать сертификат по сравнению с местным. Даже версии Nginx и PHP в основном одинаковы (PHP 7.2.7, Nginx 1.15.1 на моем локальном компьютере против PHP 7.2.13, Nginx 1.15.6)
Похоже, проблема с завершающей косой чертой в месте и, которое содержит директиву proxy_pass. Вы можете попробовать добавить его в местоположение своего веб-узла:
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";
}
Также из-за этот Я удалил / websocket / из директивы proxy_pass, поскольку вы заменяете часть URI «/ webconfig» на «/ webconfig /», что сбивает с толку
Если директива proxy_pass указана с URI, тогда, когда запрос передается на сервер, часть нормализованного URI запроса, соответствующая местоположению, заменяется URI, указанным в директиве.
На главный вопрос - исходя из Документация Nginx:
Если местоположение определяется строкой префикса, которая заканчивается символом косой черты, и запросы обрабатываются одним из proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass или grpc_pass, то выполняется специальная обработка. В ответ на запрос с URI, равным этой строке, но без косой черты в конце, постоянное перенаправление с кодом 301 будет возвращено на запрошенный URI с добавленной косой чертой.
Я полагаю, что в вашем случае местоположение веб-сокета не имеет завершающей косой черты, и это правило 301 перенаправляется в местоположение / по этому правилу.
Ваша конфигурация мне нравится, я дважды проверил ее в настройках 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
Or: X-location: wildcard
Or: X-location: root
Значение X-location должно соответствовать тому, что вы установили в конфигурации nginx для этого блока.
Моя версия для nginx:
# nginx -v
nginx version: nginx/1.10.1