#nodejs #nginx
Нужно ли ставить nginx перед нодой?
У нас в компании занимаются поиском Т-функции у новичков, и поэтому на новый проект
я назначен главным backdoor разработчиком.
До этого ребята у нас ставили nginx перед нодой
и имели, с моей точки зрения кучу, проблем и неявных состояний.
Например между nginx и нодой рвется ws соединения, но nginxs об этом никому ничего
не говорит.
А между клиентом и nginx соединение в порядке, но данные почему-то не приходят.
Пришлось городить свой пинг-понг.
На мой вопрос, а зачем вам вообще nginx, мне ответили что:
1) ничто так быстро не отдает статику как nginx;
2) в конце концов все всегда так делают.
Ну статику мы отдаем клиенту 1 раз и ее не так уж много.
А вот json'ы потом гоняем туда-сюда сутками, сгусями и с прочими птицами.
А по поводу того, что nginx отдает статику так быстро потому, что он ее никак не
обрабатывает,
а видит из запроса что это "просто" статика и "просто" отдает ее (так мне объяснили) -
разве написав
арр.use(express.static( path.join(__dirname, '/static') ))
я не "просто" отдаю статику, никак ее не обрабатывая?
На своем проекте я пока стучусь непосредственно на ноду.
Прав ли я? Рационально ли это?
Или меня в будущем ждут непредвиденные трудности? На данном уровне моей квалификации
мне кажется, что стучаться сразу на ноду - это само собой напрашивающийся шаг к отказу
от ненужного усложнения системы и от ненужной прослойки. Действительно ли прослойка
в виде nginx - ненужная?
Буду благодарен услышать Ваши комментарии.
Ответы
Ответ 1
Да, nginx добавляет сложности, требуя настроить себя, но по-моему это с лихвой компенсируется
получаемыми плюшками.
Масштабируемость
Работать с одной-единственной нодой получится только до тех пор, пока на сервере
находится один-единственный сайт. Однако в моей практике такого не было почти никогда:
я как минимум ставлю ещё Munin для наблюдения за состоянием сервера. Придётся или вешать
сайт на отдельный порт/айпишник (неудобно), или дописывать в ноде код для проксирования
запросов на другой сайт (замусоривание кода всякими сложностями). В то время как в
nginx новый сайт легко подключить парой строчек в конфиге.
Ещё один пример — A/B тестирование: запускаем две разные версии сайта, половину пользователей
направляем на одну версию сайта, половину на другую, сравниваем их поведение и решаем,
какая версия сайта лучше. Если изменения значительные, то скорее всего придётся запустить
две ноды, и опять же нужно каким-то чудом решать, какой пользователь на какую ноду
будет отправлен. Опять же в nginx это делается парой строчек (split_clients).
Когда сайт станет большой и популярный, нода может перестать помещаться в одном процессе
или одном сервере, и придётся запускать несколько экземпляров ноды или даже докупать
новые серверы. nginx позволит равномерно распределить нагрузку между процессами/серверами,
принимая все запросы на себя и пересылая его на один из случайно выбранных процессов/серверов
(или не случайно — смотря как настроить).
Безопасность
Использовать стандартные порты 80/443 может только root. А когда код сайта запускается
от рута, это ОЧЕНЬ плохо: малейшая RCE-уязвимость — и злоумышленник без проблем получает
полный доступ к серверу. Если нода будет работать от рута, то малейшая уязвимость в
коде сайта может позволить с лёгкостью получить контроль над сервером целиком (как
с помощью RCE, так и с помощью чтения какого-нибудь ../../../../../../etc/shadow и
последующего подбора пароля от рута в оффлайне, например).
В идеале код должен быть максимально изолирован от всего (вплоть до помещения в изолированный
Docker-контейнер (ходят слухи, что докер ещё и для разработки и развёртывания очень
удобен, но я не верю)). Если нода будет изолирована от всех, то максимум, что получит
злоумышленник — контроль над нодой. Ну и доступ к базе данных, если она используется.
Это плохо, но не совсем плохо, потому что взломанную ноду можно просто выключить до
исправления уязвимости. А вот выпнуть злоумышленника, получившего root, будет уже гораздо
тяжелее (вплоть до необходимости отключения сервера от интернета и полной переустановки
системы).
Но, допустим, вы перекостыляли с роутингом или форками или пропатчили ядро или ещё
что-то и в итоге каким-то чудом умудрились поднять ноду на порту 80/443 без root. Тогда
пришло время вспомнить про HTTPS и сертификаты для него. Для работы SSL/TLS ноде нужен
будет доступ к приватному ключу, и опять же, если злоумышленник откопает RCE-уязвимость,
то он сможет прочитать приватный ключ и начать организовывать MitM-атаки. Если же HTTPS
будет настроен на nginx и доступ к приватному ключу будет только у nginx, то злоумышленник
обломается. (Хотя, конечно, налажать могут всегда и везде, даже у nginx+openssl однажды
утекали приватные ключи... поэтому переходим на libressl)
Кроме того, есть ряд менее серьёзных атак, которые всё же могут подпортить нервы.
Например, манипуляции с медленными HTTP-запросами. В nodejs была уязвимость CVE-2013-4450,
позволяющая завалить её HTTP pipelining запросами и тем самым скушать ресурсы сервера.
Теоретически подобное, конечно, может найтись и в nginx, но всё же сама его архитектура
неплохо спасает от подобных пакостей. При наличии nginx на ноду уже будут приходить
белые и пушистые HTTP-запросы, доставляющие минимум проблем, в то время как всякий
мусор будет отфильтрован или забуферизован самим nginx'ом. (Хотя от терабитных DDoS-атак
ничего не спасёт, но не будем о грустном)
Прочие плюшки
Обязательно будут моменты, когда нода не будет работать (например, она может быть
просто выключена на техработы). Без nginx пользователи получат просто какую-то невнятную
ошибку браузера, уведомляющую о невозможности подключения. С nginx можно отдать статическую
страницу с более понятным описанием ошибки и предложением сообщить о проблеме администраторам
сайта, или же повесить плашку техработ и предложение подписаться на твиттер.
Про вебсокеты
Непонятно, что у вас за проблемы были — без подрбоностей понять, кто виноват и что
делать, трудно; у меня всё проксируется через nginx вполне стабильно. А пинги должны
быть в любом случае, потому что отвалиться по таймауту может что угодно где угодно
даже не на вашем сервере (например, мобильный оператор Теле2 обрубает TCP-соединения
после пяти минут бездействия). «Городить свой пинг-понг» не нужно, потому что эта фича
встроена в протокол — не знаю, как именно вы реализуете вебсокеты в ноде, но пинги
где-то там наверняка уже должны быть.
Ответ 2
Например между nginx и нодой рвется ws соединения, но nginxs об этом
никому ничего не говорит. А между клиентом и nginx соединение в
порядке, но данные почему-то не приходят.
Видимо, криво настроили.
1) ничто так быстро не отдает статику как nginx;
Правда.
я не "просто" отдаю статику, никак ее не обрабатывая?
Вы считываете файл средствами node.js и отдаёте в стрим. nginx, который на такие
вещи заточен, явно будет быстрее.
На своем проекте я пока стучусь непосредственно на ноду. Прав ли я?
Возможно пока правы.
Рационально ли это?
Если сервис только для себя, то возможно.
Или меня в будущем ждут непредвиденные трудности?
При росте нагрузок как будете масштабировать? Если бы вы использовали nginx, то могли
бы поднять несколько node.js сервисов на разных портах, а балансили бы их с помощью nginx.
Если ваш сервис упадёт, что будете делать?
Если понадобится SSL соединение, что будете делать?
К тому же, если понадобится для статики в будущем CDN, то они очень хорошо умеют
работать с nginx.