pm2 | Nginx как HTTP-прокси

pm2 | Nginx как HTTP-прокси

Это распространённый метод использования NGINX в качестве прокси-сервера HTTP для PM2. NGINX позволит быстро обслуживать статические файлы, управлять протоколом SSL и перенаправлять трафик в ваше приложение Node.js.

Вот пример приложения Node.js, прослушивающего порт 3001, и NGINX, перенаправляющего трафик с порта 443 (HTTPS) на 3001. Этот пример также будет обрабатывать соединения Websocket.

 

Конфигурационный файл для виртуального хоста nginx.conf:

upstream my_nodejs_upstream {
    server 127.0.0.1:3001;
    keepalive 64;
}

server {
    listen 443 ssl;
    
    server_name www.my-website.com;
    ssl_certificate_key /etc/ssl/main.key;
    ssl_certificate     /etc/ssl/main.crt;
   
    location / {
    	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    	proxy_set_header Host $http_host;
        
    	proxy_http_version 1.1;
    	proxy_set_header Upgrade $http_upgrade;
    	proxy_set_header Connection "upgrade";
        
    	proxy_pass http://my_nodejs_upstream/;
    	proxy_redirect off;
    	proxy_read_timeout 240s;
    }
}

Узнайте больше об этих параметрах в документации Nginx! После этого всё, что вам понадобится, — это связанный с PM2 сервер Node.js, работающий на порту 3001, и у вас будет готовый к работе HTTP-сервер!

 

Директива proxy_http_version

Ссылка: https://nginx.org/ru/docs/http/ngx_http_proxy_module.html#proxy_http_version

Синтаксис: proxy_http_version 1.0 | 1.1;
Умолчание:
proxy_http_version 1.0;
Контекст: httpserverlocation

Эта директива появилась в версии 1.1.4.

Задаёт версию протокола HTTP для проксирования. По умолчанию используется версия 1.0. Для работы постоянных соединений и проверки подлинности NTLM рекомендуется версия 1.1.

 

Директива proxy_set_header

Ссылка: https://nginx.org/ru/docs/http/ngx_http_proxy_module.html#proxy_set_header

Синтаксис: proxy_set_header поле значение;
Умолчание:
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
Контекст: httpserverlocation

Позволяет переопределять или добавлять поля заголовка запроса, передаваемые проксируемому серверу. В качестве значения можно использовать текст, переменные и их комбинации. Директивы наследуются с предыдущего уровня конфигурации при условии, что на данном уровне не описаны свои директивы proxy_set_header. По умолчанию переопределяются только два поля:

proxy_set_header Host       $proxy_host;
proxy_set_header Connection close;

Если включено кэширование, поля заголовка “If-Modified-Since”, “If-Unmodified-Since”, “If-None-Match”, “If-Match”, “Range” и “If-Range” исходного запроса не передаются на проксируемый сервер.

Неизменённое поле заголовка запроса “Host” можно передать так:

proxy_set_header Host       $http_host;

 

Однако, если это поле отсутствует в заголовке запроса клиента, то ничего передаваться не будет. В этом случае лучше воспользоваться переменной $host — её значение равно имени сервера в поле “Host” заголовка запроса, или же основному имени сервера, если поля нет:

proxy_set_header Host       $host;

 

Кроме того, можно передать имя сервера вместе с портом проксируемого сервера:

proxy_set_header Host       $host:$proxy_port;

 

Если значение поля заголовка — пустая строка, то поле вообще не будет передаваться проксируемому серверу:

proxy_set_header Accept-Encoding "";

 

Директива proxy_pass

Ссылка: https://nginx.org/ru/docs/http/ngx_http_proxy_module.html#proxy_pass

Синтаксис: proxy_pass URL;
Умолчание:
Контекст: locationif в locationlimit_except

Задаёт протокол и адрес проксируемого сервера, а также необязательный URI, на который должен отображаться location. В качестве протокола можно указать “http” или “https”. Адрес может быть указан в виде доменного имени или IP-адреса, и необязательного порта:

proxy_pass http://localhost:8000/uri/;

или в виде пути UNIX-сокета, который указывается после слова “unix” и заключается в двоеточия:

proxy_pass http://unix:/tmp/backend.socket:/uri/;

 

Если доменному имени соответствует несколько адресов, то все они будут использоваться по очереди (round-robin). Кроме того, в качестве адреса можно указать группу серверов.

В значении параметра можно использовать переменные. В этом случае, если адрес указан в виде доменного имени, имя ищется среди описанных групп серверов и если не найдено, то определяется с помощью resolver’а.

URI запроса передаётся на сервер так:

  • Если директива proxy_pass указана с URI, то при передаче запроса серверу часть нормализованного URI запроса, соответствующая location, заменяется на URI, указанный в директиве:
    location /name/ {
        proxy_pass http://127.0.0.1/remote/;
    }
    
  • Если директива proxy_pass указана без URI, то при обработке первоначального запроса на сервер передаётся URI запроса в том же виде, в каком его прислал клиент, а при обработке изменённого URI — нормализованный URI запроса целиком:
    location /some/path/ {
        proxy_pass http://127.0.0.1;
    }
    

    До версии 1.1.12, если proxy_pass указана без URI, в ряде случаев при изменении URI на сервер мог передаваться URI первоначального запроса вместо изменённого URI.

 

В ряде случаев часть URI запроса, подлежащую замене, выделить невозможно:

  • Если location задан регулярным выражением, а также в именованных location’ах.В этих случаях proxy_pass следует указывать без URI.
  • Если внутри проксируемого location с помощью директивы rewrite изменяется URI, и именно с этой конфигурацией будет обрабатываться запрос (break):
    location /name/ {
        rewrite    /name/([^/]+) /users?name=$1 break;
        proxy_pass http://127.0.0.1;
    }
    

    В этом случае URI, указанный в директиве, игнорируется, и на сервер передаётся изменённый URI запроса целиком.

  • При использовании переменных в proxy_pass:
    location /name/ {
        proxy_pass http://127.0.0.1$request_uri;
    }
    

    В этом случае если в директиве указан URI, он передаётся на сервер как есть, заменяя URI первоначального запроса.

 

Проксирование WebSocket требует особой настройки и поддерживается начиная с версии 1.3.13.

 

Директива proxy_redirect

Ссылка: https://nginx.org/ru/docs/http/ngx_http_proxy_module.html#proxy_redirect

Синтаксис: proxy_redirect default;
proxy_redirect off;
proxy_redirect перенаправление замена;
Умолчание:
proxy_redirect default;
Контекст: httpserverlocation

Задаёт текст, который нужно изменить в полях заголовка “Location” и “Refresh” в ответе проксируемого сервера. Предположим, проксируемый сервер вернул поле заголовка “Location: http://localhost:8000/two/some/uri/”. Директива

proxy_redirect http://localhost:8000/two/ http://frontend/one/;

перепишет эту строку в виде “Location: http://frontend/one/some/uri/”.

В заменяемой строке можно не указывать имя сервера:

proxy_redirect http://localhost:8000/two/ /;

тогда будут подставлены основное имя сервера и порт, если он отличен от 80.

Стандартная замена, задаваемая параметром default, использует параметры директив location и proxy_pass. Поэтому две нижеприведённые конфигурации одинаковы:

location /one/ {
    proxy_pass     http://upstream:port/two/;
    proxy_redirect default;

 

location /one/ {
    proxy_pass     http://upstream:port/two/;
    proxy_redirect http://upstream:port/two/ /one/;

Параметр default недопустим, если в proxy_pass используются переменные.

В строке замена можно использовать переменные:

proxy_redirect http://localhost:8000/ http://$host:$server_port/;

 

В строке перенаправление тоже можно использовать (1.1.11) переменные:

proxy_redirect http://$proxy_host:8000/ /;

 

Директиву также можно задать (1.1.11) при помощи регулярных выражений. При этом перенаправление должно начинаться либо с символа “~”, если при сравнении следует учитывать регистр символов, либо с символов “~*”, если регистр символов учитывать не нужно. Регулярное выражение может содержать именованные и позиционные выделения, а замена ссылаться на них:

proxy_redirect ~^(http://[^:]+):\d+(/.+)$ $1$2;
proxy_redirect ~*/user/([^/]+)/(.+)$      http://$1.example.com/$2;

 

На одном уровне может быть указано несколько директив proxy_redirect:

proxy_redirect default;
proxy_redirect http://localhost:8000/  /;
proxy_redirect http://www.example.com/ /;

Если к полям заголовка в ответе проксируемого сервера могут быть применены несколько директив, будет выбрана первая из них.

Параметр off отменяет действие унаследованных с предыдущего уровня конфигурации директив proxy_redirect.

С помощью этой директивы можно также добавлять имя хоста к относительным перенаправлениям, выдаваемым проксируемым сервером:

proxy_redirect / /;

 

Директива proxy_read_timeout

Ссылка: https://nginx.org/ru/docs/http/ngx_http_proxy_module.html#proxy_read_timeout

Синтаксис: proxy_read_timeout время;
Умолчание:
proxy_read_timeout 60s;
Контекст: httpserverlocation

Задаёт таймаут при чтении ответа проксированного сервера. Таймаут устанавливается не на всю передачу ответа, а только между двумя операциями чтения. Если по истечении этого времени проксируемый сервер ничего не передаст, соединение закрывается.

 

Информационные ссылки

Документация PM2 — Раздел «Nginx as a HTTP proxy» — https://pm2.keymetrics.io/docs/tutorials/pm2-nginx-production-setup