Как установить Node.js в Debian 12 и запустить Next.js приложение?

1. Установка Node.js 22.x LTS

Рекомендую установить через NodeSource репозиторий для получения актуальной версии:

# Обновляем систему
sudo apt update && sudo apt upgrade -y

# Устанавливаем необходимые пакеты
sudo apt install -y curl software-properties-common

# Добавляем NodeSource репозиторий для Node.js 22.x
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -

# Устанавливаем Node.js
sudo apt install -y nodejs

# Проверяем версии
node --version  # должно показать v22.x.x
npm --version

Альтернативный способ через NVM (Node Version Manager)

Если хотите иметь возможность легко переключаться между версиями Node.js:

# Устанавливаем NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

# Перезагружаем shell или выполняем
source ~/.bashrc

# Устанавливаем Node.js 22 LTS
nvm install --lts
nvm use --lts
nvm alias default lts/*

# Проверяем
node --version  # покажет v22.x.x

Node.js 22 LTS имеет ряд преимуществ:

  • Улучшенная производительность
  • Встроенная поддержка WebSocket клиента
  • Улучшенная поддержка ESM модулей
  • Обновлённый V8 движок
  • Поддержка до апреля 2027 года

2. Установка PM2 (менеджер процессов)

PM2 — это специальная программа, которая следит за работой вашего Node.js приложения на сервере. Представьте её как надёжного администратора, который работает круглосуточно и следит, чтобы ваш сайт всегда оставался доступным.

Основная проблема

Когда вы запускаете Node.js приложение обычным способом, оно работает только пока открыт терминал. Стоит закрыть окно терминала или разорвать SSH-соединение — приложение останавливается. Если приложение падает из-за ошибки, оно не перезапускается самостоятельно. После перезагрузки сервера приложение не запустится автоматически — нужно вручную подключаться и запускать его снова.

Что делает PM2

PM2 решает все эти проблемы. Он запускает ваше приложение в фоновом режиме и постоянно следит за его состоянием. Если приложение упадёт из-за ошибки, PM2 моментально его перезапустит. При перезагрузке сервера PM2 автоматически запустит все необходимые приложения без вашего участия.

Кроме базового функционала «держать приложение живым», PM2 предоставляет удобные инструменты для production-окружения: ведение логов, мониторинг потребления памяти и процессора, возможность запуска нескольких экземпляров приложения для распределения нагрузки, обновление кода без остановки сервиса.

Почему это важно

Для production-сервера критически важна стабильность и непрерывность работы. PM2 обеспечивает эту стабильность, автоматизируя рутинные задачи администрирования Node.js приложений. Это стандартный инструмент в индустрии — практически каждый Node.js проект в production использует PM2 или аналогичные решения.

В контексте Next.js приложения PM2 особенно полезен, так как позволяет эффективно использовать серверные ресурсы, автоматически перезапускать приложение при обновлениях и вести подробные логи работы приложения, что упрощает отладку и мониторинг.

sudo npm install -g pm2

3. Создание Next.js приложения

# Создаём директорию для проекта
mkdir -p /var/www/nextjs-app
cd /var/www/nextjs-app

# Создаём новое Next.js приложение
npx create-next-app@latest

# Устанавливаем зависимости
npm install

# Собираем production версию
npm run build

4. Настройка PM2 для Next.js

Создайте файл ecosystem.config.js в корне проекта:

module.exports = {
  apps: [{
    name: 'nextjs-app',
    script: 'npm',
    args: 'start',
    cwd: '/var/www/nextjs-app',
    instances: 1,
    autorestart: true,
    watch: false,
    max_memory_restart: '1G',
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    }
  }]
}

Запустите приложение:

# Запускаем через PM2
pm2 start ecosystem.config.js

# Сохраняем конфигурацию PM2
pm2 save

# Настраиваем автозапуск при перезагрузке
pm2 startup systemd -u $USER --hp /home/$USER

Если всё сделано правильно, то вы увидите в консоли это:

image 2 - Как установить Node.js в Debian 12 и запустить Next.js приложение?

В процессе PM2 сгенерирует команду, которую нужно выполнить. Скопируйте и выполните эту команду:

sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u ВАШ_ЮЗЕР --hp /home/ВАШ_ЮЗЕР

5. Настройка nginx для проксирования

Создайте конфигурационный файл для вашего сайта:

sudo nano /etc/nginx/sites-available/nextjs-app

Добавьте следующую конфигурацию:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;  # Замените на ваш домен

    # Максимальный размер загружаемых файлов
    client_max_body_size 20M;

    # Gzip сжатие
    gzip on;
    gzip_comp_level 5;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    # Проксирование на Next.js
    location / {
        proxy_pass http://localhost:3000;
        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;
        
        # Дополнительные заголовки
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        
        # Таймауты
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # Кеширование статических файлов Next.js
    location /_next/static {
        proxy_pass http://localhost:3000;
        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;
        
        # Кеширование на 1 год
        add_header Cache-Control "public, max-age=31536000, immutable";
    }
}

6. Активация конфигурации

# Создаём символическую ссылку
sudo ln -s /etc/nginx/sites-available/nextjs-app /etc/nginx/sites-enabled/

# Проверяем конфигурацию
sudo nginx -t

# Перезапускаем nginx
sudo systemctl reload nginx

7. Настройка SSL (опционально, но рекомендуется)

# Устанавливаем Certbot
sudo apt install -y certbot python3-certbot-nginx

# Получаем SSL сертификат
sudo certbot --nginx -d example.com -d www.example.com

# Автообновление сертификатов уже настроено автоматически

Теперь ваш Next.js сайт должен быть доступен по адресу вашего домена. Next.js будет работать на порту 3000, а nginx будет проксировать все запросы к нему.

Полезные команды для управления

# PM2 команды
pm2 status          # Статус приложений
pm2 logs           # Логи
pm2 restart all    # Перезапуск
pm2 monit          # Мониторинг

# Просмотр логов nginx
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log

# Перезапуск после изменений в коде
cd /var/www/nextjs-app
git pull           # Если используете git
npm install        # Если изменились зависимости
npm run build      # Пересборка
pm2 restart nextjs-app

Решение проблемы ERR_EMPTY_RESPONSE при настройке Nginx в WSL2

При настройке локальной среды разработки с использованием WSL2 и Nginx часто возникает проблема: браузер показывает ошибку ERR_EMPTY_RESPONSE при попытке доступа к локальным сайтам. В этой статье мы разберем причины возникновения проблемы и предоставим пошаговое решение.

Причина проблемы

Проблема возникает из-за особенностей архитектуры WSL2:

  • WSL2 работает как полноценная виртуальная машина
  • Имеет собственный IP-адрес в виртуальной сети
  • Windows и WSL2 находятся в разных сетевых пространствах
  • Прямой доступ к localhost WSL2 из Windows невозможен

ERR_EMPTY_RESPONSE возникала потому что:

  • Браузер в Windows пытался получить доступ к localhost (127.0.0.1)
  • Но Nginx в WSL2 работал на другом IP-адресе (в виртуальной сети WSL2)
  • Соединение не могло быть установлено напрямую

    Решение

    Настройка Port Proxy в Windows

    # Получение IP-адреса WSL2
    $wslip = (wsl hostname -I).Trim()
    Write-Host "WSL IP: $wslip"
    
    # Настройка port proxy
    netsh interface portproxy delete v4tov4 listenport=80 listenaddress=0.0.0.0
    netsh interface portproxy add v4tov4 listenport=80 listenaddress=0.0.0.0 connectport=80 connectaddress=$wslip
    
    # Проверка настроек
    netsh interface portproxy show all

    $wslip — это «айпи» Вашей WSL

    Что произошло?

    Эта команда создаст «мост» между:

    • Windows (0.0.0.0:80) — куда приходят запросы от браузера
    • WSL2 (внутренний IP:80) — где работает Nginx

    Процесс работы теперь выглядит так:

    Браузер (Windows) -> localhost:80 -> Port Proxy -> WSL2 IP:80 -> Nginx

    Не забудьте сделать:

    Очистка DNS-кэша в Windows ipconfig /flushdns и перезапуск Nginx sudo service nginx restart

    Как скрыть версию Nginx в заголовке ответа сервера?

    Директива server_tokens разрешает или запрещает выдавать версию nginx’а на страницах ошибок и в поле “Server” заголовка ответа.

    Для того чтобы отключить вывод версии http-сервера необходимо добавить в контекст http, server или location строку:

    server_tokens off;

    Было:

    root@SERVER:~$ curl -I localhost
    HTTP/1.1 200 OK
    Server: nginx/1.18.0 (Ubuntu)
    Date: Thu, 06 Jun 2024 15:45:36 GMT
    Content-Type: text/html
    Content-Length: 612
    Last-Modified: Tue, 21 Apr 2020 14:09:01 GMT
    Connection: keep-alive
    ETag: "1e9efe6d-264"
    Accept-Ranges: bytes
    

    Стало:

    root@SERVER:~$ curl -I localhost
    HTTP/1.1 200 OK
    Server: nginx
    Date: Thu, 06 Jun 2024 15:45:36 GMT
    Content-Type: text/html
    Content-Length: 612
    Last-Modified: Tue, 21 Apr 2020 14:09:01 GMT
    Connection: keep-alive
    ETag: "1e9efe6d-264"
    Accept-Ranges: bytes
    

    P.S. чтобы изменения вступили в силу не забудьте перезагрузить Nginx

    sudo systemctl restart nginx
    ИЛИ
    sudo service nginx restart

    Как проверить получен ли ответ из кэша Nginx?

    В Nginx существует встроенная переменная $upstream_cache_status модуля ngx_http_upstream_module, которая хранит статус доступа к кэшу ответов. Статус может быть одним из

    • “MISS”,
    • “BYPASS”,
    • “EXPIRED”,
    • “STALE”,
    • “UPDATING”,
    • “REVALIDATED” или
    • “HIT”.

    В случае правильной работы сервера в ответе из кэша должно находится значение “HIT”, но как это проверить?

    Первым делом вам нужно добавить специальный заголовок, который будет в ответе сервера возвращать значение переменной $upstream_cache_status:

    Открываем конфигурационный файл Nginx ( /etc/nginx/nginx.conf ) и добавляем строчку, к блоку бэкенда:

    add_header FastCGI-Cache $upstream_cache_status;

    Например, так:

    добавили заголовок add_header FastCGI-Cache $upstream_cache_status;

    Проверить заголовки ответа можно в браузере. Если ответ получен из кэша вы непременно увидите статус HIT

    статус HIT

    Как узнать версию Nginx на сервере и проверить его работу?

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

    nginx -v

    или

    sudo nginx -v

    Ответ в консоли:

    nginx version: nginx/1.26.0

    Для получения расширенной информации укажите заглавную букву «V» (вывод версии nginx, версии компилятора и параметров конфигурации сборки)

    sudo nginx -V

    Ответ в консоли:

    nginx version: nginx/1.26.0
    built by gcc 10.2.1 20210110 (Debian 10.2.1-6) 
    built with OpenSSL 1.1.1n  15 Mar 2022 (running with OpenSSL 1.1.1w  11 Sep 2023)
    TLS SNI support enabled
    configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp ...

    Проверка работы HTTP-сервера Nginx

    Для просмотра списка всех запущенных процессов nginx может быть использована утилита ps:

    ps -ax | grep nginx

    Ответ в консоли:

        699 ?        Ss     0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
     149300 ?        S      2:26 nginx: worker process
     149301 ?        S      0:00 nginx: worker process
     149302 ?        S      0:00 nginx: worker process
     149303 ?        S      0:01 nginx: worker process
     149304 ?        S      0:00 nginx: cache manager process
     158423 pts/0    S+     0:00 grep nginx

    Текущий статус работы мы также можем посмотреть при помощи команды

    sudo systemctl status nginx

    Если всё хорошо и служба работает, то вы непременно должны увидеть подобный сигнал

    nginx запущен

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

     curl localhost

    Если всё правильно работает, то по идее вы должны получить в ответ страницу приветствия в виде HTML:

    ответ в виде HTML

    Как сделать постоянное перенаправление с кодом 301 на веб-сервере Nginx?

    Задача: Изменился URL у страницы и требуется сделать постоянное перенаправление на новую страницу.

    Чтобы не мудрить, предлагаю для этой цели использовать простую директиву return.

    Обратимся к документации и взглянем на информацию об этой директиве, которую мы будем использовать для постоянного перенаправления.

    Syntax: return code [text]; return code URL; return URL; Context: server, location, if

    https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return

    Нам подойдёт для решения поставленной задачи контекст location и синтаксис return code URL;

    Открываем конфигурационный файл HTTP-сервера Nginx и добавляем в него

    #
    # Redirect
    #
    location /old-page/ {
    	return 301 /new-page/;
    }

    /old-page/ будет перенаправлять и без последнего слеша. Если требуется задать строгое сравнение, то с помощью модификатора “=” можно задать точное совпадение URI

    #
    # Redirect с точным соответствием символов в URI
    #
    location = /old-page {
    	return 301 /new-page-2/;
    }

    Если требуется перенаправление на другой домен, то можно сделать перенаправление таким образом:

    #
    # Redirect
    #
    location /old-page/ {
    	return 301 $scheme://new-site.ru/about;
    }

    А вот простой пример постоянного перенаправления (со статусом 301) всех посетителей на новое доменное имя, но только уже в контексте server

    server {
        listen 80;
        listen 443 ssl;
        server_name old-site.ru;
        return 301 $scheme://new-site.ru$request_uri;
    }

    Важно понимать, что в указании $request_uri есть смысл только тогда, когда у вас на сайте в адресах после домена происходит полное соответствие, то есть old-site.ru/contact == new-site.ru/contact