Как настроить приложение Node.js для работы в CentOS 7
Введение
Node.js — это среда выполнения Javascript с открытым исходным кодом, позволяющая легко создавать серверные и сетевые приложения. Платформа работает на Linux, OS X, FreeBSD и Windows, а ее приложения написаны на JavaScript. Приложения Node.js можно запускать из командной строки, но мы научим вас запускать их как службу, чтобы они автоматически перезапускались при перезагрузке или сбое, чтобы вы могли использовать их в производственной среде.
В этом руководстве мы рассмотрим настройку готовой к работе среды Node.js, состоящей из двух серверов CentOS 7; на одном сервере будут запускаться приложения Node.js, управляемые PM2, а другой предоставит пользователям доступ к приложению через обратный прокси-сервер Nginx к серверу приложений.
Версию этого руководства для Ubuntu можно найти здесь.
Предпосылки
В этом руководстве используются два сервера CentOS 7 с частной сетью (в одном центре обработки данных). Частную сеть можно настроить на новых серверах при их создании (в разделе Выберите дополнительные параметры
). Мы будем называть их следующими именами:
- приложение: сервер, на котором мы установим среду выполнения Node.js, ваше приложение Node.js и PM2.
- web: сервер, на котором мы установим веб-сервер Nginx, который будет действовать как обратный прокси-сервер для вашего приложения. Пользователи получат доступ к общедоступному IP-адресу этого сервера, чтобы получить доступ к вашему приложению Node.js.
Примечание. Обратитесь к документации DigitalOcean — Как включить частную сеть в каплях, если вы собираетесь использовать существующий сервер, на котором в настоящее время не настроена частная сеть.
Прежде чем приступить к работе с этим руководством, у вас должен быть обычный пользователь без полномочий root с привилегиями sudo
, настроенный на обоих ваших серверах — это пользователь, под которым вы должны войти на свои серверы. Вы можете узнать, как настроить учетную запись обычного пользователя, следуя нашему руководству по начальной настройке сервера для CentOS 7.
Команды, выполняемые на сервере приложений:
- an_example_command_on_app
Команды, выполняемые на веб-сервере:
- an_example_command_on_web
Для этого руководства можно использовать один сервер, но вам придется внести несколько изменений по пути. Просто используйте IP-адрес локального хоста, например 127.0.0.1
, везде, где используется частный IP-адрес сервера приложений.
Вот диаграмма того, какой будет ваша установка после выполнения этого руководства:
Если вы хотите иметь доступ к своему веб-серверу через доменное имя, а не через общедоступный IP-адрес, купите доменное имя и следуйте этим инструкциям:
- Как настроить имя хоста в DigitalOcean
- Как указать серверы имен DigitalOcean от общих регистраторов доменов
Начнем с установки среды выполнения Node.js на сервер приложений.
Шаг 1 — Установка Node.js
Мы установим последнюю версию LTS Node.js на сервер приложений.
SSH к вашему серверу приложений, используя обычного пользователя без полномочий root с привилегиями sudo
.
На сервере приложений воспользуемся curl
для загрузки файла конфигурации NodeSource RPM Repository:
- curl -L -o nodesource_setup.sh https://rpm.nodesource.com/setup_10.x
CURL
будет использовать протокол HTTPS для загрузки сценария установки на ваш сервер, при этом вывод будет включать информацию, относящуюся к загрузке:
Output % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 11109 100 11109 0 0 70128 0 --:--:-- --:--:-- --:--:-- 70757
Затем вы должны проверить содержимое скрипта. Следующая команда откроет сценарий установки NodeSource в консоли вашего сервера, который вы затем можете сопоставить со сценарием установки NodeSource (из репозитория NodeSource Distributions Github), чтобы подтвердить правильность загрузки сценария:
- vi nodesource_setup.sh
Удовлетворившись файлом, выйдите из vi
, набрав :q
для quit
и вернитесь в командную строку.
Теперь давайте запустим скрипт установки, чтобы установить репозиторий NodeSource RPM. Это позволит нам получить доступ к репозиторию NodeSource из менеджера пакетов yum
:
- sudo -E bash nodesource_setup.sh
Скрипт выводит информацию о настройке для нашей справки:
Output## Installing the NodeSource Node.js 10.x repo...
## Inspecting system...
+ rpm -q --whatprovides redhat-release || rpm -q --whatprovides centos-release || rpm -q --whatprovides cloudlinux-release || rpm -q --whatprovides sl-release
+ uname -m
## Confirming "el7-x86_64" is supported...
+ curl -sLf -o /dev/null 'https://rpm.nodesource.com/pub_10.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm'
## Downloading release setup RPM...
+ mktemp
+ curl -sL -o '/tmp/tmp.2aCcULVx8n' 'https://rpm.nodesource.com/pub_10.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm'
## Installing release setup RPM...
+ rpm -i --nosignature --force '/tmp/tmp.2aCcULVx8n'
## Cleaning up...
+ rm -f '/tmp/tmp.2aCcULVx8n'
## Checking for existing installations...
+ rpm -qa 'node|npm' | grep -v nodesource
## Run `sudo yum install -y nodejs` to install Node.js 10.x and npm.
## You may also need development tools to build native addons:
sudo yum install gcc-c++ make
## To install the Yarn package manager, run:
curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
sudo yum install yarn
Перед установкой Node.js важно очистить всю кэшированную информацию из yum
. Очистка кеша гарантирует, что yum
использует сетевое подключение для получения Node.js из нашего нового репозитория NodeSource (что предотвратит любые потенциальные конфликты, вызванные устаревшими пакетами):
- sudo yum clean all
Далее мы загрузим и сделаем пригодными для использования все метаданные для включенных в данный момент репозиториев yum
. Это обеспечит максимально быстрое выполнение наших запросов yum
:
- sudo yum makecache fast
Чтобы скомпилировать и установить собственные надстройки из npm
, нам также необходимо установить инструменты сборки:
- sudo yum install -y gcc-c++ make
Теперь мы можем установить последнюю версию пакета Node.js:
- sudo yum install -y nodejs
Убедитесь, что Node установлен, проверив его версию с помощью этой команды:
- node -v
Ваш вывод покажет номер версии, которую вы используете:
Outputv10.16.3
Теперь среда выполнения Node.js установлена и готова к запуску приложения. Давайте напишем приложение Node.js.
Шаг 2 — Создание приложения Node.js
Теперь мы создадим приложение Hello World, которое просто возвращает Hello World
на любые HTTP-запросы. Это пример приложения, которое поможет вам настроить Node.js, который вы можете заменить своим собственным приложением — просто убедитесь, что вы изменили свое приложение, чтобы прослушивать соответствующие IP-адреса и порты.
Поскольку мы хотим, чтобы наше приложение Node.js обслуживало запросы, поступающие с нашего обратного прокси-сервера (веб), мы будем использовать частный сетевой интерфейс нашего сервера приложений для связи между серверами. Найдите частный сетевой адрес вашего сервера приложений.
Если вы используете дроплет DigitalOcean в качестве своего сервера, вы можете найти частный IP-адрес сервера через службу Метаданные. На сервере приложений используйте команду curl
, чтобы получить IP-адрес прямо сейчас:
- curl -sw "\n" http://169.254.169.254/metadata/v1/interfaces/private/0/ipv4/address
Вы захотите скопировать вывод (частный IP-адрес), так как он будет использоваться для настройки приложения Node.js.
Затем создайте и откройте приложение Node.js для редактирования. В этом руководстве мы будем использовать vi
для редактирования примера приложения с именем hello.js
:
- vi hello.js
Вставьте следующий код в файл и обязательно замените частный IP-адрес сервера приложений на оба выделенных элемента APP_PRIVATE_IP_ADDRESS
. При желании вы также можете заменить выделенный порт 8080
в обоих местах (обязательно используйте порт без прав администратора, т. е. 1024
или больше):
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8080, 'APP_PRIVATE_IP_ADDRESS');
console.log('Server running at http://APP_PRIVATE_IP_ADDRESS:8080/');
Теперь сохраните и выйдите, нажав ESC
для выхода из режима --INSERT--
, а затем :wq
для записи
и выход
в одной команде.
Это приложение Node.js просто прослушивает указанный IP-адрес и порт и возвращает Hello World
с HTTP-кодом успеха 200
. Это означает, что приложение доступно только с серверов в той же частной сети, например, с нашего веб-сервера.
Если вы хотите проверить, работает ли ваше приложение, запустите эту команду node
на сервере приложений:
- node hello.js
Примечание. Запуск приложения Node.js таким образом блокирует дополнительные команды до тех пор, пока приложение не будет завершено нажатием CTRL+C
.
Это сэкономит много времени на отладку Nginx, если мы сначала проверим, что наш веб-сервер может взаимодействовать с приложением Node.js в приложении.
Чтобы протестировать приложение, откройте другой сеанс терминала и подключитесь к своему веб-серверу. Поскольку веб-сервер находится в той же частной сети, он должен иметь доступ к частному IP-адресу сервера приложений с помощью curl
. Не забудьте заменить частный IP-адрес сервера приложений на APP_PRIVATE_IP_ADDRESS
и порт, если вы его изменили:
- curl http://APP_PRIVATE_IP_ADDRESS:8080
Если вы видите следующий вывод, приложение работает правильно и прослушивает правильный IP-адрес и порт:
Node Application OutputHello World
Если вы не видите правильный вывод, убедитесь, что ваше приложение Node.js запущено и настроено для прослушивания правильного IP-адреса и порта.
На сервере приложений обязательно завершите приложение, нажав CTRL+C
.
Шаг 3 — Установка и использование PM2
Теперь мы установим PM2, менеджер процессов для приложений Node.js. PM2 предоставляет простой способ управления и демонизации приложений (запуск их как службы).
Мы будем использовать Node Packaged Modules (NPM), который по сути представляет собой менеджер пакетов для модулей Node, устанавливаемых с помощью Node.js, для установки PM2 на наш сервер приложений. Используйте эту команду для установки PM2:
- sudo npm install pm2@latest -g
Мы рассмотрим несколько основных способов использования PM2.
Первое, что вам нужно сделать, это использовать команду pm2 start
для запуска приложения hello.js
в фоновом режиме:
- pm2 start hello.js
Это также добавит ваше приложение в список процессов PM2, который выводится каждый раз, когда вы запускаете приложение:
Output┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ hello │ 0 │ fork │ 30099 │ online │ 0 │ 0s │ 14.227 MB │ disabled │
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘
Как видите, PM2 автоматически присваивает имя приложения (на основе имени файла, без расширения .js
) и идентификатор PM2. PM2 также поддерживает другую информацию, такую как PID процесса, его текущий статус и использование памяти.
Приложения, работающие под управлением PM2, будут автоматически перезапущены в случае сбоя или уничтожения приложения, но необходимо выполнить дополнительный шаг, чтобы приложение запускалось при запуске системы (загрузка или перезагрузка). К счастью, PM2 предоставляет простой способ сделать это с помощью подкоманды startup
.
Подкоманда startup
создает и настраивает сценарий запуска для запуска PM2 и управляемых им процессов при загрузке сервера. Вы также должны указать систему инициализации, на которой вы работаете, в нашем случае это systemd
:
- sudo pm2 startup systemd
Вы увидите следующий вывод, указывающий на то, что служба PM2 установлена:
Output[PM2] Generating system init script in /etc/systemd/system/pm2.service
[PM2] Making script booting at startup...
[PM2] -systemd- Using the command:
su root -c "pm2 dump && pm2 kill" && su root -c "systemctl daemon-reload && systemctl enable pm2 && systemctl start pm2"
[PM2] Dumping processes
[PM2] Stopping PM2...
[PM2] All processes have been stopped and deleted
[PM2] PM2 stopped
[PM2] Done.
Чтобы PM2 знал, какие приложения запускать при загрузке, нам нужно сохранить текущий список процессов. Чтобы сохранить список:
- pm2 save
Вы увидите следующий вывод, который указывает на то, что список процессов PM2 был сохранен:
Output[PM2] Saving current process list...
[PM2] Successfully saved in /home/deployer/.pm2/dump.pm2
Теперь ваши приложения, управляемые PM2, должны запускаться автоматически при загрузке.
PM2 предоставляет множество подкоманд, которые позволяют вам управлять или искать информацию о ваших приложениях. Обратите внимание, что запуск pm2
без каких-либо аргументов отобразит страницу справки, включая пример использования, который описывает использование PM2 более подробно, чем этот раздел руководства.
Остановите приложение этой командой (укажите PM2 Имя приложения
или id
):
- pm2 stop example
Перезапустите приложение этой командой (укажите PM2 Имя приложения
или id
):
- pm2 restart example
Список приложений, которыми в настоящее время управляет PM2, также можно просмотреть с помощью подкоманды list
:
- pm2 list
Дополнительную информацию о конкретном приложении можно найти с помощью подкоманды info
(укажите имя приложения или id PM2):
- pm2 info example
Монитор процессов PM2 можно вызвать с помощью подкоманды monit
. Это отображает состояние приложения, ЦП и использование памяти:
- pm2 monit
Примечание. Выполнение команды monit
PM2 заблокирует дополнительные команды до тех пор, пока приложение не будет уничтожено нажатием CTRL+C
.
Теперь, когда ваше приложение Node.js запущено и управляется PM2, давайте настроим обратный прокси-сервер.
Шаг 4 — Настройка обратного прокси-сервера Nginx
Теперь, когда ваше приложение запущено и прослушивает частный IP-адрес, вам нужно настроить способ доступа к нему для ваших пользователей. Для этой цели мы настроим веб-сервер Nginx в качестве обратного прокси-сервера. В этом руководстве мы настроим сервер Nginx с нуля. Если у вас уже есть настроенный сервер Nginx, вы можете просто скопировать блок location
в блок сервера по вашему выбору (убедитесь, что местоположение не конфликтует ни с каким существующим содержимым вашего веб-сервера).
На веб-сервере установим пакет epel-release
с помощью yum:
- sudo yum install epel-release
Затем установите Nginx:
- sudo yum install nginx
Теперь откройте файл конфигурации Nginx для редактирования:
- sudo vi /etc/nginx/nginx.conf
Сначала найдите строку, в которой определено server_name
, в блоке server по умолчанию. Это должно выглядеть примерно так:
server_name _;
Обновите имя сервера, заменив символ подчеркивания (_
) своим собственным доменным именем в директиве server_name
(или IP-адресом, если у вас не настроен домен).
server_name your-domain;
Затем найдите строку, в которой определяется location /
(обычно на несколько строк ниже server_name), в том же блоке сервера по умолчанию. Это должно выглядеть примерно так:
location / {
}
Замените его следующим блоком кода и обязательно замените APP_PRIVATE_IP_ADDRESS
частным IP-адресом сервера приложений. Кроме того, измените порт (8080
), если ваше приложение настроено на прослушивание другого порта:
location / {
proxy_pass http://APP_PRIVATE_IP_ADDRESS:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
Это настраивает веб-сервер для ответа на запросы в его корне. Предполагая, что наш сервер доступен по адресу ваш-домен
, при доступе к http://ваш-домен/
через веб-браузер будет отправлен запрос на частный IP-адрес сервера приложений на порту 8080
, который будет получен и отправлен приложением Node.js.
Вы можете добавить дополнительные блоки location
в тот же блок сервера, чтобы обеспечить доступ к другим приложениям на том же веб-сервере. Например, если вы также запускали другое приложение Node.js на сервере приложений через порт 8081
, вы можете добавить этот блок местоположения, чтобы разрешить доступ к нему через http://ваш-домен. /приложение2
:
location /app2 {
proxy_pass http://APP_PRIVATE_IP_ADDRESS:8081;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
После того, как вы закончите редактирование блока (блоков) местоположения для вашего приложения (я), сохраните и выйдите, нажав ESC
, чтобы выйти из режима --INSERT--
, а затем :wq
, чтобы написать
и выйти
в одной команде.
На веб-сервере перезапустите Nginx:
- sudo systemctl start nginx
Далее мы хотим убедиться, что Nginx запускается при каждом перезапуске сервера:
- sudo systemctl enable nginx
Команда enable
должна предоставить следующий вывод
OutputCreated symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
Вы также можете убедиться, что Nginx запущен и включен, запросив его статус у systemctl
:
- sudo systemctl status nginx
Команда состояния выведет информацию о конфигурации для службы Nginx:
Output● nginx.service - The nginx HTTP and reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
Active: active (running) since Mon 2019-10-14 09:37:23 UTC; 3min 29s ago
Main PID: 12818 (nginx)
CGroup: /system.slice/nginx.service
├─12818 nginx: master process /usr/sbin/nginx
└─12819 nginx: worker process
Oct 14 09:37:23 centos-s-1vcpu-1gb-sgp1-01 systemd[1]: Starting The nginx HTTP and reverse proxy server...
Oct 14 09:37:23 centos-s-1vcpu-1gb-sgp1-01 nginx[12814]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Oct 14 09:37:23 centos-s-1vcpu-1gb-sgp1-01 nginx[12814]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Oct 14 09:37:23 centos-s-1vcpu-1gb-sgp1-01 systemd[1]: Failed to read PID from file /run/nginx.pid: Invalid argument
Oct 14 09:37:23 centos-s-1vcpu-1gb-sgp1-01 systemd[1]: Started The nginx HTTP and reverse proxy server.
Наконец, предоставьте Nginx возможность ретрансляции трафика через Security-Enhanced Linux (SELinux). SELinux обеспечивает уровень безопасности, реализующий обязательный контроль доступа (MAC) в ядре Linux. Каждый объект операционной системы (процесс, дескриптор файла, файл и т. д.) помечен контекстом SELinux, который определяет разрешения и операции, которые может выполнять объект.
Nginx помечен контекстом httpd_t
и, как следствие, имеет ряд конфигураций, заблокированных SELinux, если это явно не разрешено. Чтобы продемонстрировать это, выполните следующую команду, чтобы убедиться, что служба Nginx помечена как httpd_t
:
- ps -eZ
Эта команда предоставляет информацию о состоянии процесса, найдите информацию о конкретном процессе Nginx, чтобы увидеть метку. Вы увидите httpd_t
аналогично следующему:
Output...
system_u:system_r:httpd_t:s0 10208 ? 00:00:00 nginx
system_u:system_r:httpd_t:s0 10209 ? 00:00:00 nginx
...
Теперь давайте проверим состояние логических значений по умолчанию, связанных с меткой httpd_t
SELinux. Мы можем показать эту информацию, выполнив следующую команду:
- getsebool -a
В этом руководстве нас интересуют только логические значения, связанные с httpd
:
Output...
httpd_anon_write --> off
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
httpd_can_connect_ftp --> off
httpd_can_connect_ldap --> off
httpd_can_connect_mythtv --> off
httpd_can_connect_zabbix --> off
httpd_can_network_connect --> off
httpd_can_network_connect_cobbler --> off
httpd_can_network_connect_db --> off
httpd_can_network_memcache --> off
httpd_can_network_relay --> off
httpd_can_sendmail --> off
httpd_dbus_avahi --> off
httpd_dbus_sssd --> off
httpd_dontaudit_search_dirs --> off
httpd_enable_cgi --> on
httpd_enable_ftp_server --> off
httpd_enable_homedirs --> off
httpd_execmem --> off
httpd_graceful_shutdown --> on
httpd_manage_ipa --> off
httpd_mod_auth_ntlm_winbind --> off
httpd_mod_auth_pam --> off
httpd_read_user_content --> off
httpd_run_ipa --> off
httpd_run_preupgrade --> off
httpd_run_stickshift --> off
httpd_serve_cobbler_files --> off
httpd_setrlimit --> off
httpd_ssi_exec --> off
httpd_sys_script_anon_write --> off
httpd_tmp_exec --> off
httpd_tty_comm --> off
httpd_unified --> off
httpd_use_cifs --> off
httpd_use_fusefs --> off
httpd_use_gpg --> off
httpd_use_nfs --> off
httpd_use_openstack --> off
httpd_use_sasl --> off
httpd_verify_dns --> off
...
Следует особо отметить два логических значения: httpd_can_network_connect
и httpd_can_network_relay
. Документация Redhat содержит подробную информацию о каждом из логических значений httpd
и связанных с ними функциях (если вы хотите узнать больше о каждом логическом значении), хотя ниже приведены пояснения двух логических значений, относящихся к этому руководству:
...
httpd_can_network_connect: When disabled, this Boolean prevents HTTP scripts and modules from initiating a connection to a network or remote port. Enable this Boolean to allow this access.
httpd_can_network_relay: Enable this Boolean when httpd is being used as a forward or reverse proxy.
...
Поскольку наша конфигурация предназначена только для ретрансляции трафика, нам просто нужно сообщить SELinux, что сервер httpd
, в нашем случае Nginx, может использовать сеть для ретрансляции трафика в настроенной нами конфигурации обратного прокси-сервера. Мы будем использовать флаг -P
, чтобы гарантировать, что изменения будут постоянными (опускание этого флага приведет к тому, что httpd_can_network_relay
вернется к своему состоянию по умолчанию, выключенному, после перезапуска сервера ):
- sudo setsebool -P httpd_can_network_relay on
Предполагая, что ваше приложение Node.js запущено и ваше приложение и конфигурации Nginx верны, вы сможете получить доступ к своему приложению через обратный прокси-сервер веб-сервера. Попробуйте это, открыв URL-адрес вашего веб-сервера (его общедоступный IP-адрес или доменное имя).
Примечание. Если вы также планировали использовать свой веб-сервер для размещения других сайтов (в качестве обычных виртуальных хостов), вам также необходимо включить параметр httpd_can_network_connect
.
Заключение
Теперь у вас есть приложение Node.js, работающее за обратным прокси-сервером Nginx. Эта настройка обратного прокси-сервера достаточно гибкая, чтобы предоставить вашим пользователям доступ к другим приложениям или статическому веб-контенту, которым вы хотите поделиться.
Кроме того, если вы хотите зашифровать передачу между вашим веб-сервером и вашими пользователями, вот руководство, которое поможет вам настроить поддержку HTTPS (TLS/SSL).