Production-деплой Next.js на VPS: пошаговое руководство

18 марта 2026 г.

После того как Next.js приложение готово и отлично работает на локальной машине, встаёт главный вопрос: как правильно выкатить его в production? Платформы вроде Vercel делают деплой максимально простым, но часто требования к инфраструктуре, стоимость или необходимость полного контроля заставляют выбирать самостоятельный хостинг на VPS.

В этом руководстве мы детально разберём production-деплой Next.js на виртуальный выделенный сервер (VPS). Вы узнаете о двух основных подходах: классической настройке с использованием PM2 и современном способе через Docker. Мы настроим веб-сервер Nginx в качестве reverse proxy, обеспечим безопасность с помощью SSL-сертификатов от Let's Encrypt и рассмотрим ключевые моменты оптимизации.

Что такое production-деплой и почему VPS?

Production-деплой — это процесс размещения вашего приложения на сервере, доступном конечным пользователям. В отличие от development-среды, production требует стабильности, безопасности, производительности и автоматического восстановления после сбоев.

VPS (Virtual Private Server) — это виртуальный сервер, который даёт вам полный контроль над окружением. Вы сами выбираете ПО, настраиваете безопасность и оптимизируете ресурсы. Это отличный выбор для проектов, которые переросли бесплатные лимиты serverless-платформ или требуют специфической инфраструктуры.

Подготовка сервера (VPS)

Для начала вам потребуется арендованный VPS. Мы будем использовать сервер с Ubuntu 22.04 LTS, так как это наиболее распространённый и стабильный дистрибутив. Подойдёт практически любой провайдер, например TimewebCloud или хостинг 1Gb.

Базовая настройка сервера

Первым делом подключаемся к серверу по SSH:

ssh root@ip-адрес-вашего-сервера

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

apt update && apt upgrade -y
adduser deploy
usermod -aG sudo deploy

Настройте SSH-ключи для нового пользователя и отключите вход по паролю в файле /etc/ssh/sshd_config для повышения безопасности.

Установка зависимостей

Для работы Next.js на сервере нам понадобятся Node.js, npm, Git и, опционально, Docker. Установим Node.js 20.x (LTS):

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
apt install -y nodejs git nginx

Проверьте версии: node -v, npm -v.

Метод 1: Классический деплой с PM2 и Node.js

Этот метод подразумевает запуск Next.js как Node.js-процесса под управлением менеджера процессов PM2. PM2 автоматически перезапустит приложение в случае падения и поможет управлять логами.

Подготовка приложения

Переключитесь на пользователя deploy и клонируйте репозиторий вашего проекта:

sudo -i -u deploy
cd ~
git clone ваш-репозиторий my-next-app
cd my-next-app
npm ci

Команда npm ci используется для чистой установки зависимостей точно по package-lock.json, что предпочтительнее для production-сборок.

Сборка и запуск

Соберите production-версию приложения:

npm run build

Запустить сервер можно командой npm start, но для production мы будем использовать PM2. Установите PM2 глобально:

sudo npm i -g pm2

Затем запустите Next.js через PM2:

pm2 start npm --name "next-app" -- start
pm2 save
pm2 startup systemd

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

Настройка PM2 для управления процессом

Для более тонкой настройки создайте файл ecosystem.config.js в корне проекта:

module.exports = {
apps: [
{
name: 'next-app',
script: 'node_modules/next/dist/bin/next',
args: 'start',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
PORT: 3000
}
}
]
};

Запускать приложение теперь можно командой pm2 start ecosystem.config.js.

Метод 2: Современный деплой с Docker

Docker позволяет упаковать приложение со всеми зависимостями в изолированный контейнер. Это гарантирует идентичность окружения на всех этапах — от разработки до продакшна.

Dockerfile для Next.js

Создайте в корне проекта файл Dockerfile:

# Этап сборки
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json .
RUN npm ci
COPY . .
RUN npm run build

# Этап запуска
FROM node:20-alpine AS runner
WORKDIR /app

ENV NODE_ENV production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# Копируем необходимые файлы из этапа сборки
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["node", "server.js"]

.dockerignore и multi-stage build

Важно создать файл .dockerignore, чтобы не копировать в образ лишние файлы:

node_modules
.git
.next
Dockerfile
.dockerignore
README.md

Обратите внимание на флаг standalone. Чтобы он работал, в файле next.config.js должна быть включена опция:

module.exports = {
output: 'standalone',
// ... остальные настройки
}

Это создаст минимальную самостоятельную сборку, включающую только необходимые файлы.

Запуск контейнера

Соберите образ и запустите контейнер:

docker build -t my-next-app .
docker run -d --name next-app -p 3000:3000 my-next-app

Для автоматического перезапуска можно использовать политики рестарта Docker (--restart unless-stopped) или более продвинутые инструменты оркестрации.

Настройка Nginx как reverse proxy

Независимо от того, запустили ли вы приложение через PM2 или Docker, оно слушает порт 3000. Напрямую открывать этот порт в мир — не лучшая идея. Мы используем Nginx в качестве reverse proxy: он будет принимать запросы пользователей на 80-м (HTTP) и 443-м (HTTPS) портах и перенаправлять их на наш Next.js сервер.

Конфигурация Nginx

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

sudo nano /etc/nginx/sites-available/my-next-app

Содержимое:

server {
listen 80;
server_name your-domain.com www.your-domain.com;

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;
}

# Для статических файлов можно добавить кеширование
location /_next/static {
alias /path/to/your/app/.next/static;
expires 365d;
}
}

Активируйте конфигурацию:

sudo ln -s /etc/nginx/sites-available/my-next-app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Добавление SSL-сертификата (Let's Encrypt)

Безопасность превыше всего. Установим Certbot и получим бесплатный SSL-сертификат:

apt install -y certbot python3-certbot-nginx
certbot --nginx -d your-domain.com -d www.your-domain.com

Certbot автоматически обновит конфигурацию Nginx, добавив настройки для HTTPS, и настроит автоматическое продление сертификатов.

Настройка environment-переменных

Переменные окружения для production (например, API-ключи, строки подключения к БД) не должны храниться в коде. Для Next.js важно помнить, что переменные с префиксом NEXT_PUBLIC_ встраиваются в сборку на этапе build. Поэтому для них нужно передавать значения непосредственно перед npm run build.

Самый простой способ — создать файл .env.production в корне проекта на сервере (и убедиться, что он добавлен в .gitignore!). Пример:

DATABASE_URL=postgresql://user:pass@localhost:5432/db
API_SECRET=supersecretkey
NEXT_PUBLIC_ANALYTICS_ID=UA-XXXXX

При использовании Docker переменные можно передать через -e или использовать файл .env.

Оптимизация для production

Простой деплой — это только начало. Для боевого проекта стоит обратить внимание на следующие моменты:

  • Кеширование: Настройте Nginx для кеширования статических файлов (_next/static, изображения).
  • Сжатие: Включите gzip или brotli сжатие в Nginx для уменьшения размера передаваемых данных.
  • Мониторинг: Используйте pm2 monit, логи Docker или подключайте специализированные сервисы для отслеживания состояния приложения.
  • Балансировка: Для высоких нагрузок можно запустить несколько экземпляров приложения (через pm2 с instances: max или несколько Docker-контейнеров) и настроить Nginx для балансировки нагрузки между ними.

Типичные ошибки и их решение

ПроблемаВероятная причинаРешение
502 Bad Gateway от NginxNext.js сервер не запущен или упалПроверьте pm2 status или docker ps. Посмотрите логи: pm2 logs или docker logs.
404 на страницах, кроме главнойНеверная конфигурация Nginx для клиентской маршрутизацииУбедитесь, что в location / настроен proxy_pass и передаются все необходимые заголовки.
Ошибки, связанные с переменными окруженияПеременные NEXT_PUBLIC_* не были доступны на этапе сборкиПередайте их в команду npm run build или определите в файле .env.production перед сборкой.
Приложение не стартует после перезагрузки сервераPM2 не настроен на автозапуск или Docker контейнер не имеет политики restartВыполните pm2 startup и pm2 save. Для Docker используйте флаг --restart unless-stopped.

Заключение

Мы рассмотрели два основных подхода к деплою Next.js приложения на VPS: классический с PM2 и современный с Docker. Каждый из них имеет право на жизнь. PM2 проще для понимания, если вы только начинаете, Docker же даёт большую воспроизводимость и изоляцию.

Выбор VPS-провайдера — важный шаг. Обратите внимание на репутацию, качество поддержки и удобство панели управления. Например, TimewebCloud предлагает гибкие тарифы и удобные инструменты для управления серверами.

Помните, что деплой — это не разовая задача. Регулярно обновляйте зависимости, следите за логами и безопасностью сервера. Автоматизируйте процессы с помощью CI/CD (например, GitHub Actions) — это тема для отдельной статьи.