Я собираюсь развернуть новое приложение node.js, и мне нужна помощь в его настройке.
Моя установка сейчас выглядит следующим образом.
У меня работает лак external_ip:80
У меня за спиной Nginx работает internal_ip:80
Оба прослушивают порт 80, один внутренний порт, один внешний.
ПРИМЕЧАНИЕ: приложение node.js работает на WebSockets
Теперь у меня есть новое приложение node.js, которое будет прослушивать порт 8080.
Могу ли я настроить лак так, чтобы он находился перед nginx и node.js.
Varnish должен проксировать веб-сокет на порт 8080, но тогда статические файлы, такие как css, js и т. Д., Должны пройти через порт 80 на nignx.
Nginx не поддерживает веб-сокеты из коробки, иначе я бы сделал такую настройку, как:
лак -> nignx -> node.js
Просто настроив проект, который по сути идентичен тому, что вы описываете, я поделюсь своим подходом - никаких гарантий, что он «лучший», но он действительно работает.
Мой стек серверов
Мое приложение Node.js использует Websockets (sockets.io - v0.9.0) и Express (v2.5.8) - и запускается с использованием навсегда. (На этом же сервере также есть другие сайты - в основном PHP, которые используют те же экземпляры Nginx и Varnish).
Основная цель моего подхода заключается в следующем:
Конфигурация Varnish - /etc/varnish/default.vcl:
#Nginx - on port 81
backend default {
.host = "127.0.0.1";
.port = "81";
.connect_timeout = 5s;
.first_byte_timeout = 30s;
.between_bytes_timeout = 60s;
.max_connections = 800;
}
#Node.js - on port 1337
backend nodejs{
.host = "127.0.0.1";
.port = "1337";
.connect_timeout = 1s;
.first_byte_timeout = 2s;
.between_bytes_timeout = 60s;
.max_connections = 800;
}
sub vcl_recv {
set req.backend = default;
#Keeping the IP addresses correct for my logs
if (req.restarts == 0) {
if (req.http.x-forwarded-for) {
set req.http.X-Forwarded-For =
req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
#remove port, if included, to normalize host
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
#Part of the standard Varnish config
if (req.request != "GET" &&
req.request != "HEAD" &&
req.request != "PUT" &&
req.request != "POST" &&
req.request != "TRACE" &&
req.request != "OPTIONS" &&
req.request != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
if (req.request != "GET" && req.request != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
#Taken from the Varnish help on dealing with Websockets - pipe directly to Node.js
if (req.http.Upgrade ~ "(?i)websocket") {
set req.backend = nodejs;
return (pipe);
}
###Removed some cookie manipulation and compression settings##
if(req.http.Host ~"^(www\.)?example.com"){
#Removed some redirects and host normalization
#Requests made to this path, even if XHR polling still benefit from piping - pass does not seem to work
if (req.url ~ "^/socket.io/") {
set req.backend = nodejs;
return (pipe);
}
#I have a bunch of other sites which get included here, each in its own block
}elseif (req.http.Host ~ "^(www\.)?othersite.tld"){
#...
}
#Part of the standard Varnish config
if (req.http.Authorization || req.http.Cookie) {
/* Not cacheable by default */
return (pass);
}
#Everything else, lookup
return (lookup);
}
sub vcl_pipe {
#Need to copy the upgrade for websockets to work
if (req.http.upgrade) {
set bereq.http.upgrade = req.http.upgrade;
}
set bereq.http.Connection = "close";
return (pipe);
}
#All other functions should be fine unmodified (for basic functionality - most of mine are altered to my purposes; I find that adding a grace period, in particular, helps.
Конфигурация Nginx - /etc/nginx/*/example.com.conf:
server {
listen *:81;
server_name example.com www.example.com static.example.com;
root /var/www/example.com/web;
error_log /var/log/nginx/example.com/error.log info;
access_log /var/log/nginx/example.com/access.log timed;
#removed error page setup
#home page
location = / {
proxy_pass http://node_js;
}
#everything else
location / {
try_files $uri $uri/ @proxy;
}
location @proxy{
proxy_pass http://node_js;
}
#removed some standard settings I use
}
upstream node_js {
server 127.0.0.1:1337;
server 127.0.0.1:1337;
}
Я не особо без ума от повторения оператора proxy_pass, но, к сожалению, пока не удосужился найти более чистую альтернативу. Один из подходов может заключаться в том, чтобы в блоке местоположения явно указывались расширения статических файлов, а оператор proxy_pass оставался вне любого блока местоположения.
Несколько настроек из /etc/nginx/nginx.conf:
set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;
log_format timed '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$request_time $upstream_response_time $pipe';
port_in_redirect off;
Среди других моих серверных блоков и настроек у меня также включены gzip и keepalive в моей конфигурации nginx. (Кстати, я считаю, что для Nginx существует TCP-модуль, который позволит использовать веб-сокеты, однако мне нравится использовать «ванильные» версии программного обеспечения (и связанные с ними репозитории), так что на самом деле это не вариант для меня. ).
Предыдущая версия этой настройки привела к необычному «блокировочному» поведению трубопровода в Varnish. По сути, как только было установлено соединение с сокетом по каналу, следующий запрос будет отложен до истечения времени ожидания канала (до 60 секунд). Я еще не видел такого же повтора в этой настройке, но мне было бы интересно узнать, видите ли вы подобное поведение.