Skip to content

Instantly share code, notes, and snippets.

@tomasevich
Last active April 7, 2024 12:13
Show Gist options
  • Save tomasevich/a2fe588c451c5a192893e6521a813020 to your computer and use it in GitHub Desktop.
Save tomasevich/a2fe588c451c5a192893e6521a813020 to your computer and use it in GitHub Desktop.
Сервер в связке Nginx + NodeJs

Сервер в связке Nginx + NodeJs

Данная пошаговая инструкция поможет освоить основы на простом примере

Для справки

Сервер поднимался на Debian 8 c характеристиками:

CPU - 1 ядро x 500 МГц

RAM - 512 МБ

Диск - 5 ГБ SSD+HDD

Принцип работы на пальцах

Nginx будет отдавать статические файлы самостоятельно, динамический контент передавать из NodeJS.

Установка и настройка Nginx

Представим что у вас чистый сервер и ничего не установлено. Идем в папку /root и становим Nginx:

$ apt-get install -y nginx

После установки Nginx, в папке /var появилась папка /www, а в ней папка /html, а в ней файл index.html. Идем в папку /var и переименуем папку /html в папку /nginx:

$ mv /var/www/html /var/www/nginx

Создаем доп.файл style.css (для теста):

$ touch /var/www/nginx/style.css

В файле index.html пишем код, этот файл будет заглушкой:

<h1>Заглушка</h1>

В файле style.css пишем код:

* {background: #000;}

Еще нам нуно создать папку для NodeJS:

$ mkdir /var/www/nodejs

Далее прописывем на всякий случай права для папок:

$ chown www-data /var/www && chown www-data /var/www/nginx && chown www-data /var/www/nodejs

Теперь самое интересное, настраиваем файл конфига Nginx, редактируем файл default:

$ mcedit /etc/nginx/sites-available/default

Очищаем весь файл и пишем (комменты # ниже):

# Настройка сервера
server {
	# Nginx слушает порт 80
	# default_server - указан в /etc/nginx/nginx.conf
	listen 80 default_server;
	# Указываем "динамическую" папку NodeJS
	root /var/www/nodejs;
	# Указываем основной файл заглушки
	index index.html;
	# Устанавливаем страницы ошибок
	# В папке /var/www/errors должны быть файлы 
	# 50x.html и 40x.html соответственно
	error_page 500 502 503 504 /50x.html;
	error_page 400 401 402 403 404 /40x.html;
	location = /50x.html { 
		root /var/www/errors;
	}
	location = /40x.html { 
		root /var/www/errors;
	}
	# Указываем IP адрес сервера
	server_name IP_адрес_сервера;
	# Если мы обращаемся по любому УРЛ начиная с /
	# то сервер будет обрабатывать NodeJS
	location / {
		# Тут указываем IP|Url и порт (8000) для NodeJS
		# поскольку Nginx будет висеть на 80 порту
		proxy_pass http://IPorURL_адрес_сервера:8000;
		proxy_set_header Host $host;
	}
	# Если мы обращемся по УРЛ начинающийся с /nginx/
	# то мы будем подгружать "статичные" файлы хранящиеся в нем
	# в соответствии с наличием этих файлов в этой папке
	location /nginx/ {
		# Указываем корень
		root /var/www/;
		autoindex off;
		# Итого путь для Nginx будет
		# /var/www/static/
	}
}	 

Добавляем Nginx в автозагрузку и запускаем, что бы изменения применились, после проверяем статус:

$ systemctl enable nginx && systemctl start nginx && systemctl status nginx

Установка и настройка NodeJS

Идем в папку /root и под пользователем root устанавливаем cURL

$ apt-get install -y curl

С помощью cURL скачиваем NodeJS, в моем случае верся 6:

$ curl -sL https://deb.nodesource.com/setup_6.x -o nodesource_setup.sh

Запускаем скаченный файл:

$ bash nodesource_setup.sh

Устанавливаем NodeJS

$ apt-get install -y nodejs build-essential

Готово! Можно протестировать:

$ node
> console.log ('hello world')

Вместе с NodeJS установился и NPM (Node Package Manager), с помощью которого мы установим express и pm2:

С помощью демона pm2 можно позабыть о проблемах с падением NodeJS (устанавливаем глобально):

$ npm install pm2 -g

Инициализируем проект, создаем package.json в который будем фиксировать нужные пакеты (спасибо @niiu за подсказку)

$ npm init

С помощью библиотеки express код будет писаться намного проще и быстрее (устанавлиаем локально):

$ cd /var/www/nodejs/
$ npm install express --save

Создаем файл server.js для NodeJS, который будет основным (входным) файлом:

$ touch /var/www/nodejs/server.js

Код файла server.js описан ниже:

  // Настройки
  const setup = {port:8000}
  // Подключаем express
  const express = require ('express'); 
  // создаем приложение
  const app = express ();
  // Маршрутизируем GET-запрос http://ваш_сайт/test
  app.get('/test', (req, res) => {    
    res.send('Тест'); 
  });
  // Слушаем порт и при запуске сервера сообщаем
  app.listen(setup.port, () => {
    console.log('Сервер: порт %s - старт!', setup.port);
  });

Теперь можно добавить демону 1 процесс и запустить наш NodeJS сервер:

$ pm2 start /var/www/nodejs/server.js

При этом у нас запущен сервер Nginx

После перезагрузки ОС, pm2 сам себя не запустит и соответственно не запустит процессы. Выполняем команды:

  1. Сначала добавляем нужный процесс (в нашем случае скрипт NodeJS)
  2. Потом сохраняем конфигурацию
  3. После, добавляем PM2 в сервисы ОС
$ pm2 start server.js
$ pm2 save
$ pm2 startup

Готово

Если все запустилось, значит у вас ровные руки, а у меня талант писать пошаговые инструкции :)

Тестируем

Переходим на http://IP_адрес_сайта:80/test - дожны увидеть фразу "Тест"

Переходим на http://IP_адрес_сайта:80/nginx/style.css - дожны увидеть код стилей

Переходим на http://IP_адрес_сайта:80/nginx/ или http://IP_адрес_сайта:80/nginx/index.html - дожны увидеть заглушку

Итого

Nginx является прокси-сервером, NodeJS основным приложением. Первый висит на 80 порту, второй на 8000 и слушает первый. NodeJS отдает динамику, а Nginx отвечает за статику.

Если что-то не получилось или вы нашли ошибку, пишите в комментариях ниже!

Полезные материалы

Сайт GitHub
https://nginx.org/ https://github.com/nginx/nginx
https://nodejs.org/ https://github.com/nodejs/node
http://expressjs.com/ https://github.com/expressjs/express
https://www.npmjs.com/ https://github.com/npm
https://www.npmjs.com/package/pm2
https://packages.debian.org/ru/jessie/curl
@tomasevich
Copy link
Author

Очень помогло, спасибо огромное! Пытаюсь поднять сервер для своего проекта, и только с вашим гайдом удалось это сделать!
Пока не могу понять почему при переходе по ссылке у меня отображается надпись "Cannot GET /", но с этим уже буду разбираться в следующий раз)

@Excelsiorer Это так отрабатывает expressjs (скорей всего на этом пути у вас нет маршрута или обработчика исклюяений)

@sergewhite
Copy link

@tomasevich кажется логичней указывать в root папку со статикой и использовать try_files $uri /; В таком случае статика будет сразу отдаваться, остальное в ноду.

@tomasevich
Copy link
Author

@tomasevich кажется логичней указывать в root папку со статикой и использовать try_files $uri /; В таком случае статика будет сразу отдаваться, остальное в ноду.

@sergewhite, полностью согласен! На момент написания статьи, эти нюансы я не учитывал (возможно не осознавал)

@Demidov-Alex
Copy link

@tomasevich Большое спасибо - очень помогло!

@dimbos
Copy link

dimbos commented Aug 2, 2020

Добрый день. Подскажите, столкнулся с такой проблемой. Захожу в приложение по https и приложение не видит стили и скрипты.
В express указана папка со статическими файлами. Что с ними делать? Куда эту папку перенести? Ответа найти не могу. Какой путь указывать для стилей и скриптов.

@ratinart
Copy link

Ты лучший, спасибо! Все заработало с пол оборота:)

@tomasevich
Copy link
Author

@Demidov-Alex, @ratinart - рад что статья оказалась полезна

@dimbos - учись работать с консолью браузера, что бы найти проблему. Я не могу не видя кода помочь, возможно пути к стилям и скриптам указаны не корректно.

Примеры

// если указать путь маршрута /static и название папки public
app.use('/static', express.static('public'));
// то при запросе к адресу http://site.com/static/style.css будет доступен файл
// расположенный по адресу /папка_проекта/public/style.css
// при чем как с http, так и с httpS будет работать одинаково

// еще пример
app.use('/aaa/555', express.static(__dirname + '/my_new_path''));
// то при запросе к адресу http://site.com/aaa/555/style.css будет доступен файл
// расположенный по адресу /папка_проекта/my_new_path/style.css

@ChillMouse
Copy link

Если вы столкнётесь с проблемой "Error: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.27'":

  1. установите NodeJS этим способом: https://www.youtube.com/watch?v=NS3aTgKztis
  2. Запускайте команды через sudo
  3. Не используйте sudo su - это не поможет

p. s. Ubuntu Server 16.04 LTS

@ChillMouse
Copy link

ChillMouse commented Oct 18, 2022

Я вас @tomasevich процитирую:

  1. "Переходим на http://IP_адрес_сайта:80/ - дожны увидеть фразу "Тест""
  2. Если все запустилось, значит у вас ровные руки, а у меня талант писать пошаговые инструкции :)

Тем временем код JS:

  app.get('/test', (req, res) => {    
    res.send('Тест'); 
  });

Исправьте, пожалуйста, что нужно открывать адрес http://IP_адрес_сайта:80/test

@tomasevich
Copy link
Author

tomasevich commented Jan 11, 2023

Исправьте, пожалуйста, что нужно открывать адрес http://IP_адрес_сайта:80/test

@ChillMouse спасибо, внес правки в статью. Благодаря участникам, статья получилась более-менее корректной.

@tomasevich
Copy link
Author

@ratinart спасибо за отзыв, себе делал, с другими поделился. За это я и люблю Open Source!

@coderbara
Copy link

Благодарю, за статью! Очень круто!

@tomasevich
Copy link
Author

tomasevich commented Feb 4, 2023

Благодарю, за статью! Очень круто!

@coderbara очень рад, что статья до сих пор актуальна и полезна

@shushlyakovProjects
Copy link

Привет! Что делать, если "# default_server - указан в /etc/nginx/nginx.conf", не указан ?(

@ChillMouse
Copy link

Привет! Что делать, если "# default_server - указан в /etc/nginx/nginx.conf", не указан ?(

Укажи вручную

@Cergoo
Copy link

Cergoo commented Sep 18, 2023

почему nodejs не может отдавать статику так же эффективно как nginx ?

@tomasevich
Copy link
Author

почему nodejs не может отдавать статику так же эффективно как nginx ?

@Cergoo отличный вопрос, только для начала давай разберем, что для тебя эффективность? Какую задачу ты решаешь, какую проблему ты не можешь решить? Готов ли ты тратить ресурсы на велосипеды или проще применять проверенные решения?

Ответив на эти вопросы, ты поймешь, подходит ли NodeJS для твоих задач или Nginx предпочтительней. Может лучше использовать не NodeJS, а набирающий популярность Bun или Deno.

Считаю, что не стоит гнаться за лучшими практиками как за безальтернативным вариантом

@BagrovAnatoli
Copy link

Я не всё понял на счёт конфигураций. У меня VDS сервер от timeweb и nginx там уже работал.
nodejs установил.
по адресу /var/www/mydomen.ru/html/index.html находится страница заглушка, она работает, причём я ещё установил SSL от letsencrypt и заглушка открывается по адресу https://mydomen.ru (здесь я левый адрес пишу)
Потом создал каталог /var/www/mydomen.ru/html/bot/api
и уже в нём запускаю сервер на nodejs на порту 3000, который возвращает "Hello World!"
сервер запускается корректно, но я не пойму, по какому url до него можно добраться.
Ни так
https://mydomen.ru:3000
ни так
https://mydomen.ru:3000/bot/api
не работает
Подскажите, пожалуйста, какие настройки за это отвечают.

@exegguto
Copy link

npm install pm2 -g
не выполняется для меня
vps сервер, ошибка нет связи, хотя по curl показывает

npm WARN ERESOLVE overriding peer dependency
npm WARN While resolving: @babel/plugin-syntax-jsx@7.23.3
npm WARN Found: @babel/core@undefined
npm WARN node_modules/@babel/core
npm WARN
npm WARN Could not resolve dependency:
npm WARN peer @babel/core@"^7.0.0-0" from @babel/plugin-syntax-jsx@7.23.3
npm WARN node_modules/@babel/plugin-syntax-jsx
npm WARN @babel/plugin-syntax-jsx@"^7.22.5" from babel-plugin-styled-components@2.1.4
npm WARN node_modules/babel-plugin-styled-components
npm ERR! code ETIMEDOUT
npm ERR! syscall connect
npm ERR! errno ETIMEDOUT
npm ERR! network request to https://registry.npmjs.org/pg failed, reason: connect ETIMEDOUT 2606:4700::6810:1f22:443
npm ERR! network This is a problem related to network connectivity.
npm ERR! network In most cases you are behind a proxy or have bad network settings.
npm ERR! network
npm ERR! network If you are behind a proxy, please make sure that the
npm ERR! network 'proxy' config is set properly. See: 'npm help config'

npm ERR! A complete log of this run can be found in: /root/.npm/_logs/2024-02-15T10_49_13_966Z-debug-0.log

@exegguto
Copy link

npm install pm2 -g не выполняется для меня vps сервер, ошибка нет связи, хотя по curl показывает

npm WARN ERESOLVE overriding peer dependency npm WARN While resolving: @babel/plugin-syntax-jsx@7.23.3 npm WARN Found: @babel/core@undefined npm WARN node_modules/@babel/core npm WARN npm WARN Could not resolve dependency: npm WARN peer @babel/core@"^7.0.0-0" from @babel/plugin-syntax-jsx@7.23.3 npm WARN node_modules/@babel/plugin-syntax-jsx npm WARN @babel/plugin-syntax-jsx@"^7.22.5" from babel-plugin-styled-components@2.1.4 npm WARN node_modules/babel-plugin-styled-components npm ERR! code ETIMEDOUT npm ERR! syscall connect npm ERR! errno ETIMEDOUT npm ERR! network request to https://registry.npmjs.org/pg failed, reason: connect ETIMEDOUT 2606:4700::6810:1f22:443 npm ERR! network This is a problem related to network connectivity. npm ERR! network In most cases you are behind a proxy or have bad network settings. npm ERR! network npm ERR! network If you are behind a proxy, please make sure that the npm ERR! network 'proxy' config is set properly. See: 'npm help config'

npm ERR! A complete log of this run can be found in: /root/.npm/_logs/2024-02-15T10_49_13_966Z-debug-0.log

Добавили DNS сервер от Google в файле /etc/systemd/resolved.conf и все заработало

@tomasevich
Copy link
Author

Я не всё понял на счёт конфигураций. У меня VDS сервер от timeweb и nginx там уже работал. nodejs установил. по адресу /var/www/mydomen.ru/html/index.html находится страница заглушка, она работает, причём я ещё установил SSL от letsencrypt и заглушка открывается по адресу https://mydomen.ru (здесь я левый адрес пишу) Потом создал каталог /var/www/mydomen.ru/html/bot/api и уже в нём запускаю сервер на nodejs на порту 3000, который возвращает "Hello World!" сервер запускается корректно, но я не пойму, по какому url до него можно добраться. Ни так https://mydomen.ru:3000 ни так https://mydomen.ru:3000/bot/api не работает Подскажите, пожалуйста, какие настройки за это отвечают.

@BagrovAnatoli, почитай как работает Nginx. Судя по описанию проблемы, твои HTTP запросы перехватывает прокси-сервер (т.е. nginx слушает порты и выдает результаты, а запросы не попадают до nodejs). Твоя задача, объяснить nginx, что на таком-то порту висит nodejs и все запросы нужно отдавать ему и возвращать, то что он генерирует.

@tomasevich
Copy link
Author

npm install pm2 -g не выполняется для меня vps сервер, ошибка нет связи, хотя по curl показывает
npm WARN ERESOLVE overriding peer dependency npm WARN While resolving: @babel/plugin-syntax-jsx@7.23.3 npm WARN Found: @babel/core@undefined npm WARN node_modules/@babel/core npm WARN npm WARN Could not resolve dependency: npm WARN peer @babel/core@"^7.0.0-0" from @babel/plugin-syntax-jsx@7.23.3 npm WARN node_modules/@babel/plugin-syntax-jsx npm WARN @babel/plugin-syntax-jsx@"^7.22.5" from babel-plugin-styled-components@2.1.4 npm WARN node_modules/babel-plugin-styled-components npm ERR! code ETIMEDOUT npm ERR! syscall connect npm ERR! errno ETIMEDOUT npm ERR! network request to https://registry.npmjs.org/pg failed, reason: connect ETIMEDOUT 2606:4700::6810:1f22:443 npm ERR! network This is a problem related to network connectivity. npm ERR! network In most cases you are behind a proxy or have bad network settings. npm ERR! network npm ERR! network If you are behind a proxy, please make sure that the npm ERR! network 'proxy' config is set properly. See: 'npm help config'
npm ERR! A complete log of this run can be found in: /root/.npm/_logs/2024-02-15T10_49_13_966Z-debug-0.log

Добавили DNS сервер от Google в файле /etc/systemd/resolved.conf и все заработало

@exegguto, рад что удалось справиться с настройками VPS сервера, у каждого они свои и к счастью статья не об этом (видел твое сообщение, но не стал отвечать)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment