Docker: свой сервер
Для полного контроля — Docker. Деплой на свой VPS, AWS, Hetzner.
Dockerfile
Next.js поддерживает standalone-режим — минимальный образ.
next.config.ts:
const nextConfig = {
output: 'standalone',
};
export default nextConfig;
Dockerfile:
FROM node:22-alpine AS base
# Зависимости
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# Сборка
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Продакшен
FROM base 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 --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"
CMD ["node", "server.js"]
Standalone-сборка содержит только нужное — образ получается маленьким.
.dockerignore
node_modules
.next
.git
.env*.local
Dockerfile
.dockerignore
Сборка
docker build -t my-app .
Запуск
docker run -p 3000:3000 \
-e DATABASE_URL=postgresql://... \
-e AUTH_SECRET=... \
my-app
Или с env-файлом:
docker run -p 3000:3000 --env-file .env.production my-app
docker-compose
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- AUTH_SECRET=${AUTH_SECRET}
depends_on:
- db
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
- POSTGRES_PASSWORD=password
- POSTGRES_DB=myapp
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres_data:
Запуск:
docker compose up -d
Миграции
Перед запуском приложения:
CMD ["sh", "-c", "npx prisma migrate deploy && node server.js"]
Или отдельным сервисом.
Nginx как reverse proxy
server {
listen 80;
server_name example.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_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_cache_bypass $http_upgrade;
}
}
SSL через Let's Encrypt
sudo certbot --nginx -d example.com
Автоматически настроит SSL и продление.
Кеш статики
Next.js отдаёт статику из /public и /_next/static. Nginx может кешировать:
location /_next/static/ {
proxy_pass http://localhost:3000;
proxy_cache_valid 200 60m;
add_header Cache-Control "public, max-age=31536000, immutable";
}
Обновление
git pull
docker compose build
docker compose up -d
Или через CI/CD.
Логи
docker compose logs -f app
Мониторинг
- Prometheus + Grafana — метрики
- Sentry — ошибки
- Uptime Robot — доступность
Итоги
output: 'standalone'для маленького образа- Multi-stage Dockerfile
- docker-compose для приложения и БД
- Nginx как reverse proxy
- Let's Encrypt для SSL
- Миграции перед запуском