Docker — Next.js ni containerlashtirish

~20 daq · Next.js · Deployment va DevOps

Muammodan boshlaylik

Vercel qulay, lekin:

  • Kompaniya o'z serverlarida ishlashni talab qiladi (ma'lumotlar mamlakat ichida)
  • Trafik katta — Vercel hisobi qimmatlashdi
  • Ilova boshqa xizmatlar (baza, Redis, worker) bilan birga Kubernetes da ishlashi kerak

Serverga to'g'ridan-to'g'ri npm install && npm run build — "mening kompyuterimda ishlaydi" muammolari: boshqa Node.js versiyasi, boshqa OS kutubxonalari.

Docker — ilovani muhiti bilan birga qadoqlash: hamma joyda bir xil ishlaydi.


Hayotiy o'xshatma

Tayyor ovqat konteyneri. Restoran taomni maxsus idishda muhrlab beradi — uni qayerga olib borsangiz ham, ichidagi narsa bir xil. Qabul qiluvchi oshxona jihozlariga (serverga) bog'liq emas — faqat isitib (ishga tushirib) yeydi.


standalone rejim

Odatiy next build natijasi — node_modules bilan birga yuzlab MB. Standalone rejimda Next.js faqat kerakli fayllarni alohida papkaga yig'adi:

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  output: 'standalone',
}

export default nextConfig
.next/standalone/
├── server.js          ← ishga tushirish fayli (next start shart emas)
├── node_modules/      ← faqat kerakli paketlar
└── .next/

Image hajmi — ~1 GB o'rniga ~150–200 MB.


Dockerfile

# 1. Bog'liqliklar
FROM node:22-alpine AS deps
WORKDIR /app
RUN apk add --no-cache libc6-compat
COPY package.json package-lock.json ./
RUN npm ci

# 2. Build
FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npx prisma generate
RUN npm run build

# 3. Ishga tushirish
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs && 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"]
Bosqich Nima
deps npm ci — kesh: package.json o'zgarmasa qayta bajarilmaydi
builder next build
runner Faqat standalone natija — kichik va xavfsiz image

[!WARNING] public/ va .next/static standalone papkaga avtomatik nusxalanmaydi — ularni alohida COPY qiling. Aks holda sahifa ochiladi, lekin CSS, JS va rasmlar 404 bo'ladi.

.dockerignore

node_modules
.next
.git
.env*
!.env.example
npm-debug.log
e2e
coverage

.env fayllarini image ga qo'shmang — maxfiy kalitlar image ichida qoladi va image ni olgan har kim ularni o'qiydi.


Build va run

docker build -t dokon-web .

docker run -d --name dokon-web -p 3000:3000 \
  --env-file .env.production \
  --restart unless-stopped \
  dokon-web

NEXT_PUBLIC_ muammosi

NEXT_PUBLIC_ o'zgaruvchilar build paytida yoziladi (65-dars). docker run --env-file da berilgani ularga ta'sir qilmaydi.

# builder bosqichida
ARG NEXT_PUBLIC_SITE_URL
ENV NEXT_PUBLIC_SITE_URL=$NEXT_PUBLIC_SITE_URL
RUN npm run build
docker build --build-arg NEXT_PUBLIC_SITE_URL=https://dokon.uz -t dokon-web .

Bitta image ni ko'p muhitda ishlatish kerak bo'lsa — ochiq qiymatlarni ham server o'zgaruvchisi sifatida o'qib, client ga uzating (65-dars).


Docker Compose — baza bilan

# compose.yaml
services:
  web:
    build:
      context: .
      args:
        NEXT_PUBLIC_SITE_URL: https://dokon.uz
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://dokon:${DB_PAROL}@db:5432/dokon
      AUTH_SECRET: ${AUTH_SECRET}
      AUTH_TRUST_HOST: "true"
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_USER: dokon
      POSTGRES_PASSWORD: ${DB_PAROL}
      POSTGRES_DB: dokon
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U dokon"]
      interval: 5s
      retries: 10
    restart: unless-stopped

volumes:
  pgdata:
docker compose up -d --build
docker compose exec web npx prisma migrate deploy

[!INFO] Standalone image da prisma CLI bo'lmasligi mumkin (u devDependencies da). Migratsiyalarni alohida bosqichda (CI, alohida "migrate" container) yoki CLI ni dependencies ga o'tkazib bajaring.


Self-hosted da e'tibor berish kerak

Mavzu Tafsilot
ISR va kesh Kesh container ichida, diskda. Bir nechta nusxa bo'lsa — har birining o'z keshi; umumiy kesh uchun cacheHandler (Redis)
Rasm optimizatsiyasi sharp — CPU talab qiladi; katta trafikda CDN
Health check /api/health Route Handler — orkestrator uchun
Signallar CMD ["node", "server.js"] — SIGTERM to'g'ri uzatiladi (npm start emas)
Proxy ortida Nginx (68-dars), AUTH_TRUST_HOST=true

[!TIP] Rasmiy Next.js repozitoriyasidagi examples/with-docker — har bir yangi versiya uchun yangilanib turadigan tavsiya etilgan Dockerfile. Uni boshlang'ich nuqta sifatida oling.


Tez-tez uchraydigan xatolar

1. Statik fayllar 404

public va .next/static nusxalanmagan.

2. Container tashqaridan ochilmaydi

HOSTNAME=0.0.0.0 yo'q — server faqat container ichidagi localhost da tinglaydi.

3. NEXT_PUBLIC_ qiymati undefined

docker run -e bilan berilgan — kech; build ARG orqali.


Xulosa

output: 'standalone' — faqat kerakli fayllar, kichik image
Multi-stage: deps → builder → runner; root emas (USER nextjs)
public va .next/static — alohida COPY
CMD ["node", "server.js"]; HOSTNAME=0.0.0.0
.dockerignore: node_modules, .next, .env*
NEXT_PUBLIC_ — build ARG; maxfiy — runtime --env-file
Compose — baza bilan; migratsiya — alohida qadam
Self-hosted: kesh, sharp, health check, proxy

Keyingi dars

68-dars: Self-hosted — VPS da deploy, Nginx sozlash

O'z serveringizda Next.js — PM2 yoki Docker, Nginx va SSL bilan.