Современный деплой Next.js: GitHub Actions, Docker и Zero-Downtime
Опубликовано 02.03.2026
Если ты до сих пор делаешь next build прямо на продакшен-сервере — твой сервер действительно страдает. CPU в полку, OOM-kill, 502-е ошибки и долгие простои — это классика, которой пора положить конец.
В 2026 году стандарт индустрии — это раздельная сборка:
- Собираем минимальный standalone-образ в облаке GitHub Actions.
- Пушим его в GHCR (GitHub Container Registry).
- На сервере делаем только pull + атомарный перезапуск.
Глава 1. Идеальный Dockerfile (Multi-stage + Standalone)
Весь секрет маленького и быстрого образа — в режиме standalone. Next.js сам вычисляет, какие файлы и части node_modules реально нужны для работы сервера, и копирует только их.
# syntax=docker/dockerfile:1
# СТАДИЯ 1 — Зависимости
FROM node:24-alpine AS deps
WORKDIR /app
COPY package.json yarn.lock* pnpm-lock.yaml* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else npm ci; \
fi
# СТАДИЯ 2 — Сборка
FROM node:24-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
# СТАДИЯ 3 — Production-образ (Runner)
FROM node:24-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Безопасность прежде всего: работаем не под root
RUN addgroup --system --gid 1001 nodejs && adduser --system --uid 1001 nextjs
# Копируем только артефакты standalone-сборки
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Проверка здоровья контейнера
HEALTHCHECK --interval=15s --timeout=3s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
CMD ["node", "server.js"]
Почему это круто?
- Вес: Образ весит ~200 МБ против 1.5 ГБ обычного.
- Безопасность: Использование
non-rootпользователя (nextjs) защищает хост-систему при взломе контейнера. - Healthcheck: Docker сам поймет, если приложение «зависло» на старте, и не пустит на него трафик.
Глава 2. Разбор GitHub Actions Workflow
Твой пайплайн разделен на два этапа (jobs): сборка в облаке и деплой на твоем “железе”.
1. Подготовка и билд
- name: Docker meta & tags
id: prepare
run: |
IMAGE_REPO="ghcr.io/${GITHUB_REPOSITORY,,}"
SHORT_SHA="${GITHUB_SHA::8}"
echo "image_repo=$IMAGE_REPO" >> $GITHUB_OUTPUT
echo "image_tag=sha-$SHORT_SHA" >> $GITHUB_OUTPUT
Важный нюанс: Синтаксис ${GITHUB_REPOSITORY,,} приводит название репозитория к нижнему регистру. Docker-реестры не переваривают заглавные буквы, а в GitHub они часто встречаются.
2. Кэширование сборки
cache-from: type=gha
cache-to: type=gha,mode=max
Мы используем нативное кэширование GitHub Actions. Если ты не менял package.json, стадия установки зависимостей пропустится, и билд займет 1–2 минуты вместо 10.
3. Умный деплой (Healthcheck Loop)
Самая важная часть — мы не просто говорим серверу “обновись”, мы проверяем, выжило ли приложение.
for i in {1..60}; do
STATUS=$(docker inspect --format='{{json .State.Health.Status}}' nextjs 2>/dev/null || echo '"not-found"')
if [[ $STATUS == '"healthy"' || $STATUS == '"no-healthcheck"' ]]; then
HEALTHY=1
break
fi
sleep 2
done
Если Next.js упадет из-за ошибки в переменных окружения, скрипт увидит это, не обновит прокси-сервер (Caddy/Nginx) и завершит экшен с ошибкой. Твой старый сайт останется работать, а ты получишь уведомление о проблеме.
Глава 3. Runtime vs Build-time переменные
Это “грабли”, на которые наступают почти все.
NEXT_PUBLIC_(Build-time): Эти переменные “впекаются” в JS-бандл во время командыnext build. Если ты поменяешь их на сервере в.env, ничего не изменится. Их нужно передавать в GitHub Actions какbuild-args.Секреты (Runtime):
DATABASE_URL,JWT_SECRET. Их нельзя класть в Docker-образ. Они подтягиваются в момент запуска контейнера черезdocker-compose.
Совет: По возможности делай API URL также runtime-переменной через проксирование или специальные конфиг-скрипты, чтобы один и тот же образ можно было катить и на стейджинг, и в прод без пересборки.
Отзывы по теме
Было несколько проблем касаясь как технической части так и понимания в целом. Михаил быстро ответил на запрос, помог разобраться и решил проблеммы технические и помог разобраться в понимании, за что отдельное спасибо. Результатом доволен.
abazawolf · Настройка vps, настройка сервера
18.02.2026 · ⭐ 5/5
Было несколько проблем касаясь как технической части так и понимания в целом. Михаил быстро ответил на запрос, помог разобраться и решил проблеммы технические и помог разобраться в понимании, за что отдельное спасибо. Результатом доволен.
Все было сделано быстро и четко. Рекомендую
Akelebra · Настройка vps, настройка сервера
17.01.2026 · ⭐ 5/5
Все было сделано быстро и четко. Рекомендую
Всё прошло хорошо, исполнитель быстро реагировал на вопросы и помог решить проблему. Спасибо!
visupSTUDIO · Настройка vps, настройка сервера
16.12.2025 · ⭐ 5/5
Всё прошло хорошо, исполнитель быстро реагировал на вопросы и помог решить проблему. Спасибо!
Все сделали оперативно. Будем и дальше обращаться. Рекомендую!
rotant · Настройка vps, настройка сервера
10.12.2025 · ⭐ 5/5
Все сделали оперативно. Будем и дальше обращаться. Рекомендую!
Все сделали оперативно. Михаил всегда на связи. Будем и дальше обращаться
samstiray · Настройка vps, настройка сервера
10.12.2025 · ⭐ 5/5
Все сделали оперативно. Михаил всегда на связи. Будем и дальше обращаться
Михаил, профессионал! Уже ни первый раз показал это на практике.
Vadim_U · Настройка vps, настройка сервера
Освоившийся покупатель03.12.2025 · ⭐ 5/5
Михаил, профессионал! Уже ни первый раз показал это на практике.