Деплой nodejs приложения на Ubuntu сервер

В данной статье рассмотрим настройку сервера Ubuntu с нуля и развертыванию nodejs приложения с диспетчером процессов PM2 и Nginx. Для примера будем использовать виртуальный сервер на beget, но можно использовать другого облачного провайдера, свою собственную машину или виртуальную машину. Установка и настройка будет идентична.

Подготовка сервера

Первым делом создаём новый vps сервер через панель управления, в примере используется beget.

SSH ключи

Есть несколько способов войти на сервер. Можно входить на сервер используя пароли, но для более безопасного входа лучше настроить ключи SSH, а затем отключить пароли. Таким образом, можно войти на свой сервер только с ПК, на котором настроены правильные ключи.

Приступим к настройке аутентификацию с помощью SSH, но этот шаг не обязательный, можете продолжить использовать пароль для входа на сервер, и пропустить часть этого материала.

Необходимо сгенерировать ключ SSH на локальном компьютере для удаленного входа на сервер, для этого открываем терминал и вводим

ssh-keygen

По умолчанию открытый и закрытый ключ создаются в каталоге .ssh на локальном компьютере и имеют названия id_rsa и id_rsa.pub. Можно изменить имена ключей, для этого во время вопроса имени ключа нужно указать полный путь к ключу, а также имя файла. Для примера введём id_rsa_beget

Можно использовать команду cat, а затем скопировать ключ

cat ~/.ssh/id_rsa_beget.pub

После этого нужно скопировать открытый ключ на удаленный сервер, для этого используется команда ssh-copy-id, в ней указывается путь до ключа, а затем имя пользователя и хост, на который нужно скопировать открытый ключ. Введем команду, заменив имя пользователя и хост на нужные

ssh-copy-id -i ~/.ssh/id_rsa_beget.pub root@11.111.222.33

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

Подключение через root

Подключаемся к созданному, заменив ip адрес на тот что был получен после создания vps.

ssh root@11.111.222.33

Если используется авторизация без ssh ключа, то будет предложено ввести пароль root.

После авторизации должны увидеть приветственное сообщение, а в приглашении теперь должно быть написано root@localhost:~#. Это ваш удаленный сервер

Предлагаю сразу обновиться и обновить пакеты

sudo apt update && sudo apt upgrade -y

Создание нового пользователя

Прямо сейчас вы вошли в систему как root, и было бы неплохо создать новую учетную запись. Использование учетной записи root может представлять угрозу безопасности.

Можно узнать текущего пользователя с помощью команды:

whoami

В данный момент должно показываться root.

Добавим нового пользователя. Для примера назовём его moon

adduser moon

Нажимаем Enter отвечая на все вопросы. Также потребуется ввести пароль для данного пользователя.

Используем следующую команду, чтобы просмотреть информацию о пользователе, включая группы, к которым он принадлежит.

id moon

Теперь добавим этого пользователя в группу sudo, что даст ему привилегии root.

usermod -aG sudo moon

Запустив следующую команду, увидим sudo

id moon

Добавить ключи SSH для новой учетной записи

Если вы используете SSH, вам нужно настроить SSH ключи для новой учетной записи.

В локальном терминале вводим команду как вводили ранее для пользователя root, только теперь указав пользователя moon

ssh-copy-id -i ~/.ssh/id_rsa_beget.pub moon@11.111.222.33

Теперь можем подключиться к серверу без ввода пароля через пользователя moon

ssh moon@11.111.222.33

Отключение входа через пароль

Этот шаг проходим только при условии, что подключаемся к серверу через ssh ключ

Это дополнительная мера безопасности. Можно отключить пароли, чтобы только ваша локальная машина с правильными ключами SSH могла войти в систему.

Откройте следующий файл на вашем сервере

sudo nano /etc/ssh/sshd_config

Ищем где написано

PasswordAuthentication Yes

Удаляем #, если он есть, и измените Yes на No.

Если вы хотите полностью отключить вход в систему root, вы также можете изменить permitRootLogin на no. Обязательно удалите знак #, потому что он комментирует строку.

Сохраните файл, выйдя (ctrl+x) и нажав Y для сохранения.

Теперь вам нужно сбросить службу sshd

sudo systemctl restart sshd

Теперь вы можете выйти из системы, просто набрав logout

Попробуйте снова войти под своим пользователем (используйте свое имя пользователя и IP-адрес сервера)

ssh moon@11.111.222.33

Если вы получили сообщение «Public key denied» или что-то в этом роде, выполните следующие команды:

eval `ssh-agent -s`
ssh-add ~/.ssh/id_rsa_beget # замените это тем, как назвали свой файл с ключом

Попробуйте снова войти в систему, и вы должны увидеть приветственное сообщение, без необходимости ввода пароля.

Конфигурация сервера для Node.js

Предварительно установим утилиты, которые необходимы для дальнейшей работы (если вдруг они в вашей редакции системы небыли установлены по умолчанию)

sudo apt install curl git

Установка Node.js

После подготовки сервера пришло время приступить к настройке среды нашего приложения. Начнем с установки Node.js

Мы можем установить Node.js с помощью curl, используя следующие команды

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs

# Проверяем, установился ли node.js
node --version
npm --version

Загрузка файлов на сервер

Загрузим приложение используя git. Для примера скопируем из репозитория стартовое приложение express. Предварительно создав директорию sites, в которой будут храниться все приложения.

mkdir sites
cd sites
git clone https://github.com/alexsoin/express-template.git

Теперь должна появиться папка express-template со всеми файлами и подпапками.

Настройка приложения

Нам нужно сделать несколько вещей, включая настройку файла .env, установку зависимостей.

.env файл

В этом конкретном приложении нужно создать .env файл из файла заготовки .env.example, так как отправлять фактический файл .env на GitHub является плохой практикой и может быть причиной взломов приложения.

Итак, нужно сначала скопировать .env.example:

cp .env.example .env

# Проверяем
ls -a

В данном приложении только одна переменная, это порт запуска приложения SERVER_PORT, по умолчанию стоит порт 5000. Если нужно изменить порт, то правим его в файле .env:

sudo nano .env

Зависимости и сборка

Нам нужно установить зависимости сервера.

Должно быть запущено из корня папки приложения - express-template.

npm install

Запуск приложения

Теперь можем запускать приложение так же, как на локальном компьютере.

npm start

Если перейти на ip адрес сервера и порт 5000, вы должны увидеть приложение.

http://11.111.222.33:5000

Даже если мы видим, что наше приложение работает, мы еще не закончили. Мы не хотим оставлять терминал открытым при запуске npm. Мы также не хотим переходить на порт 5000. Так что давайте это исправим.

Остановите запуск приложения с помощью ctrl+C

Настройка PM2

PM2 — менеджер производственных процессов для Node.js. Позволяющий поддерживать работу приложений Node без открытия терминала с запуском npm и т. д., как делается для разработки.

Установим PM2 глобально с помощью NPM.

sudo npm install -g pm2

Запуск с PM2

pm2 start server.js   # или другая ваша стартовая точка приложения

Теперь, если вы вернетесь к IP-адресу вашего сервера и порту 5000, вы увидите, что он работает. Вы даже можете закрыть свой терминал, и он все равно будет работать.

Есть и другие команды pm2 для различных задач, которые говорят сами за себя:

  • pm2 show app
  • pm2 status
  • pm2 restart app
  • pm2 stop app
  • pm2 logs (Show log stream)
  • pm2 flush (Clear logs)

Настройка брандмауэра

Очевидно, мы не хотим, чтобы пользователям приходилось вводить порт 5000 или что-то еще. Мы собираемся решить эту проблему с помощью сервера NGINX. Прежде чем мы настроим это, давайте настроим брандмауэр, чтобы люди не могли получить прямой доступ к любому порту, кроме портов для ssh, http и https.

Брандмауэр, который мы используем, называется UFW. Давайте включим его.

sudo ufw enable

Вы заметите, что теперь, если вы зайдете на сайт, используя: 5000, это не сработает. Это потому, что мы настроили брандмауэр, чтобы заблокировать все порты.

Вы можете проверить состояние брандмауэра с помощью

sudo ufw status

Теперь давайте откроем нужные нам порты: 22, 80 и 443.

sudo ufw allow ssh   # Port 22
sudo ufw allow http  # Port 80
sudo ufw allow https # Port 443

Настройка NGINX

Теперь нам нужно установить NGINX для обслуживания нашего приложения на порту 80, который является портом http.

sudo apt install nginx

Если вы зайдете на свой IP-адрес без номера порта, вы увидите страницу Welcome to nginx!.

Теперь нам нужно настроить прокси для нашего приложения.

Откройте следующий файл конфигурации

sudo nano /etc/nginx/sites-available/default

Найдите область location/ и замените ее

location / {
    proxy_pass http://localhost:5000;    # или на каком другом порту работает ваше приложение
    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;
}

Выше вы также можете указать домен, который планируете использовать:

server_name yourdomain.com www.yourdomain.com;

Сохраните и закройте файл

Вы можете проверить конфигурацию nginx с помощью следующей команды

sudo nginx -t

Теперь перезапустите службу NGINX:

sudo service nginx restart

Теперь вы должны увидеть свое приложение при переходе на свой IP-адрес в браузере.

Доменное имя

Заходим в панель управления, где приобретён домен и указываем А запись с IP адресом вашего сервера, на котором располагается приложение.

Настроить SSL

Вы можете приобрести SSL и установить его у своего регистратора домена или использовать Let's Encrypt и настроить его бесплатно, используя следующие команды:

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Обновление сертификатов

Сразу при установке Certbot добавляет cron-задание для автоматического обновления полученных им сертификатов. Задание будет запускаться дважды в день и обновлять те сертификаты, срок действия которых истекает через 30 дней и менее. Чтобы убедиться в этом, откройте файл /etc/cron.d/certbot и проверьте наличие задания.

Протестировать автоматическое обновление сертификатов вы можете, выполнив команду:

certbot renew --dry-run