Использование nginx вместе с Node.js
У Node.js есть один серьёзный недостаток — ей неудобно отдавать файлы. А без этой функции делать полноценный веб-сервис не очень то удобно. И если отдавать текстовые файлы вроде HTML/JavaScript/CSS ещё можно как то приспособиться, то с двоичными всё сложнее. Поэтому будем ставить nginx в пару к node.
Nginx — очень быстрый веб-сервер, основанный как и node.js на event loop. У нас он будет выполнять почти ту же роль, что и Apache для PHP-сайтов: статические файлы отдавать самостоятельно, динамический контент передавать из node. Для этого нам сначала надо продумать структуру директорий.
Чтобы сильно не заморачиваться, в своей инсталляции я всё устроил довольно просто. Всё что находится в /files/
, отдаётся из определённой папки напрямую nginx’ом, остальное обрабатывает Node. Таким образом, если мы вызываем /files/css/style.css
, этот запрос в Ноду вообще не попадёт: nginx отдаст файл самостоятельно. Но запрос /page/hello-world
уже будет передан Node.
Итак, сначала ставим nginx. Если Вы используете виртуальную машину с Debian из прошлой статьи, то установка предельно проста:
apt-get install nginx
В других дистрибутивах всё может быть сложнее. Всё, nginx установлен. Теперь идём в /etc/nginx
, и редактируем файл nginx.conf
. Можно использовать vim, можно передать файл на основной компьютер и с комфортом открыть в любимом текстовом редакторе. Находим в файле директиву http
, прописываем внутрь следующее:
server { # IP, который мы будем слушать listen 192.168.175.128:80; location / { # IP и порт, на которых висит node.js proxy_pass http://192.168.175.128:8000; proxy_set_header Host $host; } location ^~ /files/ { # Путь к корневому каталогу со статическими файлами root /home/www; } }
Итак, по порядку. IP адрес можно узнать, выполнив команду ifconfig eth0
, он будет в начале второй строки. Также надо знать порт, на котором висит node.js (для nerve это по умолчанию 8000, у Вас может быть по другому). Nginx будет обрабатывать только HTTP-запросы, поэтому если Вам захочется например поднять TCP-сервер на node, он не будет мешать.
Правила в nginx — достаточно большая и сложная тема, поэтому сейчас мы её касаться не будем. Достаточно сказать что эти два правила берут контент для /files/
из папки /home/www
, а остальные запросы отдают Node.
Имейте в виду, что к указанному во втором location
пути будет прибавлена строка запроса вместе с /files/
. То есть, если пользователь запросит файл http://192.168.175.128/files/style.css
, nginx попытается отдать файл /home/www/files/style.css
.
После сохранения надо создать указанный каталог и дать пользователю www-data
(по умолчанию) к нему доступ:
mkdir /home/www mkdir /home/www/files chown www-data /home/www chown www-data /home/www/files
Пользователь, под которым работает nginx, указывается в первой строке конфигурационного файла (user www-data;
).
Запускаем nginx:
nginx
Пробуем получить файл из /files/
и запрашиваем обычный путь или какой нибудь Callback. Я использовал для тестов модифицированный nerve, о котором писал в статье про горячую замену кода.
Если что то не работает как задумано, логи nginx по умолчанию можно найти в /var/log/nginx
.
Ссылки по теме
Вики nginx с описанием формата конфигурационного файла
Мой nginx.conf на gist.github.com
Да что ж такое. Только подумывал написать статью про использование nodejs под nginx и вот, нате 🙂
Видимо, нужно поменьше мне лениться.
Все, ушел читать)
В Интернете вполне найдётся место для двух таких статей (и даже трёх). Так что рано опускать руки 🙂
Не, не буду писать — про то же самое хотел написать 🙂 Незачем повторяться. Я уж лучше про что-нибудь другое.
Расскажите про ssl-проксирование, стоит ли заботы, связанные с шифрованием трафика переложить на nginx?
спасибо за статью!
> В других дистрибутивах всё может быть сложнее
угу, для тех, кто, как и я, в первый раз видит убунту (и линукс вообще) пригодятся такие команды:
sudo /etc/init.d/nginx start
sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx restart
кроме того, чтобы через обозреватель файлов работать с каталогом:
1. в nginx.conf сменил пользователя на своего
2. chown делал тоже не для www-data
для listen (уж не знаю, правильно ли это) указал не ip из «ifconfig eth0», а то же, что и в proxy_pass
хм… зря для listen указал тоже, что и для ноды… потому что понял все с точностью до наоборот 🙂 это ж он ноду проксит
Спасибо за статью! Можно только уточнить у Вас, как в данном случае запустить сам node? Желательно ответить как чайнику, который редко урывками полгода читал про ноду, вот только что таки собрал ее и поставил на убунту, и успешно протестил работу тестового скрипта (из статьи http://www.giantflyingsaucer.com/blog/?p=894)
Просто как я понял, сам nodejs — просто среда для исполнения js, а тот тестовый скрипт, что я тестил — как бы веб-сервер. Хочется знать, подойдет ли этот скрипт для бэкенда к nginx. И, как я догадываюсь, есть что-то для этих целей получше, чем сей helloworld-style скрипт? ))
Сама нода запускается именно так как вы это делали с HelloWorld-скриптом: node script.js. Для production environment лучше чтобы что нибудь поддерживало node в запущенном состоянии — ведь любая ошибка в скрипте роняет весь сервер. Я рекомендую комбинацию Init + Monit или supervise.
а как насчет pm2?
Хотел сначала использовать strongloop pm, но он с шестой нодой что-то вообще не захотел и поход на монстра
Спасибо!
Очень полезная статья!
спасибо! Я улучшил конфиг. Теперь nodejs (express) работает в связке с nginx на одном порте, очень удобно для нормального проекта.
server {
listen 127.0.0.1:8000;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $Host;
#proxy_read_timeout 120s;
proxy_set_header Host $Host;
proxy_http_version 1.1;
proxy_set_header обновления $http_upgrade;
proxy_set_header связи «upgrade»;
}
location ^~ /javascript/ {
root /home/protected/static;
}
location ^~ /stylesheet/ {
root /home/protected/static;
}
location ^~ /upload/ {
root /home/protected/static;
}
location ^~ /image/ {
root /home/protected/static;
}
}
Админ, немного исправил..
server {
listen 127.0.0.1:80;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
#proxy_read_timeout 120s;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection «upgrade»;
}
location ^~ /javascript/ {
root /home/protected/static;
}
location ^~ /stylesheet/ {
root /home/protected/static;
}
location ^~ /upload/ {
root /home/protected/static;
}
location ^~ /image/ {
root /home/protected/static;
}
}
Спасибо, Джейс )