๐Ÿšข Next.js ์‹ฌํ™” 10์žฅ: Deployment & Infrastructure โ€” Vercel vs Docker vs Node.js ์„œ๋ฒ„

2026๋…„ 4์›” 30์ผ ์ˆ˜์ •๋จ

๐Ÿ“‹ ๊ฐœ์š”

Vercel, Docker, Node.js ์„œ๋ฒ„ ๊ฐ ๋ฐฐํฌ ๋ฐฉ์‹์˜ ์ฐจ์ด์™€ ์ธํ”„๋ผ ์„ค๊ณ„ ๊ธฐ์ค€์„ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.

๐Ÿ“‹ ๋ชฉ์ฐจ


๐Ÿ“Œ ์ด ๋ฌธ์„œ๋ฅผ ์ฝ๊ธฐ ์ „์—

โฑ๏ธ ์˜ˆ์ƒ ์ฝ๊ธฐ ์‹œ๊ฐ„: 18๋ถ„ (์ „์ฒด) / ํ•ต์‹ฌ ํŒŒํŠธ๋งŒ: 9๋ถ„

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ๋ฐฐ๊ฒฝ ์„ธ๊ณ„๊ด€: '์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ'

  • ์˜์ˆ˜(PM): "์ด์ œ ์„œ๋น„์Šค๋ฅผ ์‹ค์ œ๋กœ ๋ฐฐํฌํ•ด์•ผ ํ•ด์š”. Vercel๋กœ ๋น ๋ฅด๊ฒŒ ๋‚˜๊ฐ€์•ผ ํ•˜๋‚˜์š”, ์•„๋‹ˆ๋ฉด ํšŒ์‚ฌ ์„œ๋ฒ„(AWS EC2)์— Docker๋กœ ์˜ฌ๋ ค์•ผ ํ•˜๋‚˜์š”? ์ฐจ์ด๊ฐ€ ๋ญ”์ง€ ์•Œ๊ณ  ๊ฒฐ์ •ํ•˜๊ณ  ์‹ถ์–ด์š”."
  • ์˜ํ˜ธ(๋ฆฌ๋“œ): "ํŒ€ ๊ทœ๋ชจ, ๋น„์šฉ, ๊ธฐ์ˆ  ์„ฑ์ˆ™๋„์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์š”. ์Šคํƒ€ํŠธ์—… ์ดˆ๊ธฐ๋ผ๋ฉด Vercel์ด ์ตœ์ ์ด์—์š”. ISR, Edge Functions, ํ”„๋ฆฌ๋ทฐ ๋ฐฐํฌ๊ฐ€ ๊ธฐ๋ณธ์ด๊ณ  ์ธํ”„๋ผ ๊ฑฑ์ •์„ ์•„์˜ˆ ์•ˆ ํ•ด๋„ ๋˜๊ฑฐ๋“ ์š”. ๋ฐ˜๋ฉด ๊ธฐ์—… ๋‚ด๋ถ€ ์„œ๋ฒ„๋‚˜ ํŠน์ • ๊ทœ์ •(์ปดํ”Œ๋ผ์ด์–ธ์Šค)์ด ์žˆ์œผ๋ฉด Docker๋กœ ์ž์ฒด ์„œ๋ฒ„์— ์˜ฌ๋ ค์•ผ ํ•ด์š”."

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ํ๋ฆ„
์„ธ ๊ฐ€์ง€ ์ „๋žต ๋น„๊ต โ†’ Vercel ๋ฐฐํฌ ์„ค์ • โ†’ Docker ์ตœ์  Dockerfile โ†’ Node.js ์„œ๋ฒ„ ์ง์ ‘ ๋ฐฐํฌ โ†’ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ด€๋ฆฌ

๐ŸŽฏ ์ด ๋ฌธ์„œ๋ฅผ ๋‹ค ์ฝ์œผ๋ฉด ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ

  • ํŒ€๊ณผ ์„œ๋น„์Šค ์ƒํ™ฉ์— ๋งž๋Š” ๋ฐฐํฌ ์ „๋žต์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค
  • Next.js ์•ฑ์„ ์œ„ํ•œ ์ตœ์ ํ™”๋œ Dockerfile์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค
  • ๋น„๋ฐ€ํ‚ค๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๋Š” ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์›์น™์„ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ๋‹ค

๐Ÿค” ์™œ ์•Œ์•„์•ผ ํ•˜๋Š”๊ฐ€

๋กœ์ปฌ์—์„œ ์ž˜ ๋™์ž‘ํ•˜๋˜ ์ฝ”๋“œ๊ฐ€ ๋ฐฐํฌ ํ›„ ๊ฐ‘์ž๊ธฐ ์•ˆ ๋™์ž‘ํ•˜๊ฑฐ๋‚˜, ์„œ๋ฒ„ ๋น„์šฉ์ด ์˜ˆ์ƒ๋ณด๋‹ค 10๋ฐฐ ๋‚˜์˜ค๊ฑฐ๋‚˜, ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ํด๋ผ์ด์–ธํŠธ์— ๋…ธ์ถœ๋˜๋Š” ์‚ฌ๊ณ  โ€” ๋ฐฐํฌ๋ฅผ ๋ชจ๋ฅด๋ฉด ์ด๋Ÿฐ ์ผ์ด ์ƒ๊ฒจ.

๋ฐฐํฌ๋Š” "์–ด๋–ค ์ธํ”„๋ผ์—์„œ ์–ด๋–ป๊ฒŒ ์‹คํ–‰ํ•  ๊ฒƒ์ธ๊ฐ€"์— ๋Œ€ํ•œ ์•„ํ‚คํ…์ฒ˜ ๊ฒฐ์ •์ด์•ผ. ์ฝ”๋”ฉ๋งŒํผ ์ค‘์š”ํ•œ ์„ ํƒ์ด์•ผ.


๐Ÿ—๏ธ ๋น„์œ ๋กœ ๋จผ์ € ์ดํ•ดํ•˜๊ธฐ

๐Ÿง’ 5์‚ด์—๊ฒŒ ์„ค๋ช…ํ•œ๋‹ค๋ฉด?
์Œ์‹ ๋ฐฐ๋‹ฌ ๋ฐฉ์‹์— ๋น„์œ ํ•ด๋ด:

  • Vercel = ๋ฐฐ๋‹ฌ์˜๋ฏผ์กฑ ์ž…์ . ์ฃผ๋ฐฉ๋งŒ ์žˆ์œผ๋ฉด ๋˜๊ณ , ๋ฐฐ๋‹ฌยท๊ฒฐ์ œยท๊ด‘๊ณ ๋Š” ํ”Œ๋žซํผ์ด ๋‹ค ํ•ด์ค˜. ๋น ๋ฅธ ๋Œ€์‹  ์ˆ˜์ˆ˜๋ฃŒ(๋น„์šฉ)๊ฐ€ ์žˆ๊ณ , ํ”Œ๋žซํผ ๊ทœ์น™์„ ๋”ฐ๋ผ์•ผ ํ•ด.
  • Docker = ์Œ์‹์  ์ง์ ‘ ์šด์˜ + ๋ฐฐ๋‹ฌ ํŠธ๋Ÿญ ๋ณด์œ . ๋ชจ๋“  ๊ฑธ ์ง์ ‘ ๊ด€๋ฆฌํ•ด์•ผ ํ•˜์ง€๋งŒ ์ž์œ ๋„๊ฐ€ ์ตœ๊ณ ์•ผ.
  • Node.js ์ง์ ‘ ๋ฐฐํฌ = ์Œ์‹์  ์ง์ ‘ ์šด์˜์ธ๋ฐ ๋ฐฐ๋‹ฌ ํŠธ๋Ÿญ์€ ์„ธ๋†“๊ธฐ. Docker๋ณด๋‹ค ์กฐ๊ธˆ ๋” ๋‹จ์ˆœํ•˜์ง€๋งŒ ๊ด€๋ฆฌํ•  ๊ฒŒ ์—ฌ์ „ํžˆ ๋งŽ์•„.

๐Ÿงฉ ์„ธ ๊ฐ€์ง€ ๋ฐฐํฌ ์ „๋žต ๋น„๊ต ๐ŸŸข

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • ์„ธ ๊ฐ€์ง€ ๋ฐฐํฌ ์ „๋žต์˜ ์žฅ๋‹จ์ ์„ ์ •ํ™•ํžˆ ์•Œ๊ณ  ์ƒํ™ฉ์— ๋งž๋Š” ์„ ํƒ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค
๊ธฐ์ค€VercelDocker (K8s ํฌํ•จ)Node.js ์„œ๋ฒ„ ์ง์ ‘
์„ค์ • ๋ณต์žก๋„โญ ๊ฑฐ์˜ ์—†์Œ๐Ÿ”ด ๋†’์Œ๐ŸŸก ์ค‘๊ฐ„
๋น„์šฉ ์˜ˆ์ธก์„ฑ๐ŸŸก ํŠธ๋ž˜ํ”ฝ ๋”ฐ๋ผ ๋ณ€๋™โœ… ์˜ˆ์ธก ๊ฐ€๋Šฅโœ… ์˜ˆ์ธก ๊ฐ€๋Šฅ
ISR / Edge ์ง€์›โœ… ์™„๋ฒฝ ์ง€์›๐ŸŸก ์„ค์ • ํ•„์š”๐ŸŸก ์ œํ•œ์ 
์ž์ฒด ์„œ๋ฒ„ ํ†ตํ•ฉโŒ ์–ด๋ ค์›€โœ… ์™„๋ฒฝ ํ†ตํ•ฉโœ… ๊ฐ€๋Šฅ
์ปดํ”Œ๋ผ์ด์–ธ์Šค๐ŸŸก ๋ฐ์ดํ„ฐ ๋ฏธ๊ตญ ์„œ๋ฒ„โœ… ์ž์ฒด ์„œ๋ฒ„ ์™„์ „ ์ œ์–ดโœ… ์ž์ฒด ์ œ์–ด
๊ฐ€์žฅ ์ ํ•ฉํ•œ ์ƒํ™ฉ์Šคํƒ€ํŠธ์—…, ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ, ๋น ๋ฅธ ์ถœ์‹œ๊ธฐ์—…, ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค, ๊ณ ๊ฐ€์šฉ์„ฑ๊ธฐ์กด VM ๋ณด์œ , ์ค‘์†Œ ๊ทœ๋ชจ

2026๋…„ ๊ธฐ์ค€ ์„ ํƒ ๊ฐ€์ด๋“œ:

ํŒ€ ๊ทœ๋ชจ ์†Œ + ๋น ๋ฅธ ์ถœ์‹œ + ๋น„์šฉ ์ตœ์†Œํ™” โ†’ Vercel
๋ฐ์ดํ„ฐ ๊ตญ๋‚ด ์„œ๋ฒ„ ํ•„์ˆ˜ + ๊ธฐ์—… ๋ณด์•ˆ ๊ทœ์ • โ†’ Docker (์‚ฌ๋‚ด K8s)
๊ธฐ์กด VM ๋ณด์œ  + ๋‹จ์ˆœ ๋ฐฐํฌ + ์˜ˆ์ธก ๋น„์šฉ โ†’ Node.js ์ง์ ‘ ๋ฐฐํฌ

๐Ÿš€ Vercel ๋ฐฐํฌ โ€” ์ œ๋กœ ์„ค์ •์˜ ๋งˆ๋ฒ• ๐ŸŸก

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • Vercel์—์„œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜๊ณ  ์ปค์Šคํ…€ ๋„๋ฉ”์ธ์„ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค
  • vercel.json์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ์™€ ํ—ค๋”๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค

Vercel ๋ฐฐํฌ ๊ณผ์ •:

# 1. Vercel CLI ์„ค์น˜
npm i -g vercel
 
# 2. ํ”„๋กœ์ ํŠธ ์—ฐ๊ฒฐ ๋ฐ ๋ฐฐํฌ
vercel
 
# 3. ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ
vercel --prod

๋˜๋Š” GitHub ์—ฐ๋™์œผ๋กœ pushํ•  ๋•Œ๋งˆ๋‹ค ์ž๋™ ๋ฐฐํฌ (๊ถŒ์žฅ).

vercel.json ์„ค์ •:

{
  "framework": "nextjs",
  "buildCommand": "npm run build",
  "devCommand": "npm run dev",
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "X-Frame-Options", "value": "DENY" },
        { "key": "X-Content-Type-Options", "value": "nosniff" },
        { "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" }
      ]
    }
  ],
  "redirects": [
    { "source": "/old-blog/(.*)", "destination": "/posts/$1", "permanent": true }
  ]
}

Vercel ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •:

Vercel Dashboard โ†’ ํ”„๋กœ์ ํŠธ โ†’ Settings โ†’ Environment Variables

๊ฐœ๋ฐœ: DATABASE_URL=postgresql://localhost:5432/dev
ํ”„๋ฆฌ๋ทฐ: DATABASE_URL=postgresql://preview-server/preview
ํ”„๋กœ๋•์…˜: DATABASE_URL=postgresql://prod-server/prod

โš ๏ธ NEXT_PUBLIC_ ์ ‘๋‘์‚ฌ๊ฐ€ ๋ถ™์€ ๋ณ€์ˆ˜๋งŒ ํด๋ผ์ด์–ธํŠธ์— ๋…ธ์ถœ๋จ!

Vercel์˜ ํŠน๋ณ„ ๊ธฐ๋Šฅ:

โœ… Preview URL: PR๋งˆ๋‹ค ๊ณ ์œ ํ•œ ๋ฏธ๋ฆฌ๋ณด๊ธฐ URL ์ž๋™ ์ƒ์„ฑ
   - https://my-app-pr-123-team.vercel.app

โœ… ISR ์ง€์›: revalidate ์„ค์ • ์ฆ‰์‹œ ๋™์ž‘
โœ… Edge Functions: middleware๊ฐ€ Vercel Edge์—์„œ ์ž๋™ ์‹คํ–‰
โœ… Analytics: Core Web Vitals ์‹ค์ œ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ์ž๋™ ์ˆ˜์ง‘

๐Ÿณ Docker ์ปจํ…Œ์ด๋„ˆ ๋ฐฐํฌ โ€” ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ํ‘œ์ค€ ๐ŸŸก

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • Next.js ์•ฑ์„ ์œ„ํ•œ ์ตœ์ ํ™”๋œ ๋ฉ€ํ‹ฐ ์Šคํ…Œ์ด์ง€ Dockerfile์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์ด๋ฏธ์ง€ ํฌ๊ธฐ๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š” ๋นŒ๋“œ ํŒจํ„ด์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค

Next.js ๊ณต์‹ ๊ถŒ์žฅ ๋ฉ€ํ‹ฐ ์Šคํ…Œ์ด์ง€ Dockerfile:

# Dockerfile
 
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# Stage 1: ์˜์กด์„ฑ ์„ค์น˜
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
FROM node:20-alpine AS deps
WORKDIR /app
 
# package.json๊ณผ lock ํŒŒ์ผ๋งŒ ๋จผ์ € ๋ณต์‚ฌ (๋ ˆ์ด์–ด ์บ์‹ฑ ์ตœ์ ํ™”)
COPY package.json package-lock.json ./
RUN npm ci --only=production
 
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# Stage 2: ๋นŒ๋“œ
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
FROM node:20-alpine AS builder
WORKDIR /app
 
# ๋นŒ๋“œ์— ํ•„์š”ํ•œ ์ „์ฒด ์˜์กด์„ฑ ์„ค์น˜ (devDependencies ํฌํ•จ)
COPY package.json package-lock.json ./
RUN npm ci
 
COPY . .
 
# ๋นŒ๋“œ ํƒ€์ž„ ํ™˜๊ฒฝ ๋ณ€์ˆ˜
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
 
# standalone ๋ชจ๋“œ๋กœ ๋นŒ๋“œ (์„œ๋ฒ„์— ํ•„์š”ํ•œ ํŒŒ์ผ๋งŒ ์ถœ๋ ฅ)
RUN npm run build
 
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# Stage 3: ์‹คํ–‰ ์ด๋ฏธ์ง€ (์ตœ์†Œ ํฌ๊ธฐ)
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
FROM node:20-alpine AS runner
WORKDIR /app
 
ENV NODE_ENV=production
 
# ๋ณด์•ˆ: ๋ฃจํŠธ ๊ถŒํ•œ์œผ๋กœ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ธฐ
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
 
# standalone ๋นŒ๋“œ ๊ฒฐ๊ณผ๋ฌผ๋งŒ ๋ณต์‚ฌ (์ตœ์†Œ ํŒŒ์ผ)
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"]
// next.config.ts โ€” standalone ๋ชจ๋“œ ํ™œ์„ฑํ™” (Docker ํ•„์ˆ˜ ์„ค์ •)
const nextConfig = {
  output: 'standalone',    // ์„œ๋ฒ„์— ํ•„์š”ํ•œ ์ตœ์†Œ ํŒŒ์ผ๋งŒ .next/standalone์— ์ถœ๋ ฅ
}
# docker-compose.yml โ€” ๋กœ์ปฌ ๊ฐœ๋ฐœ/์Šคํ…Œ์ด์ง•์šฉ
services:
  app:
    build:
      context: .
      args:
        NEXT_PUBLIC_API_URL: https://api.youngsu.community
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://postgres:password@db:5432/youngsu
      - SESSION_SECRET=your-secret-key-here
    depends_on:
      - db
 
  db:
    image: postgres:16
    environment:
      POSTGRES_DB: youngsu
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
 
volumes:
  postgres_data:
# ์ด๋ฏธ์ง€ ๋นŒ๋“œ ๋ฐ ์‹คํ–‰
docker build -t youngsu-community .
docker run -p 3000:3000 --env-file .env.production youngsu-community
 
# ๋˜๋Š” compose๋กœ
docker-compose up -d

๐Ÿ–ฅ๏ธ Node.js ์„œ๋ฒ„ ์ง์ ‘ ๋ฐฐํฌ ๐ŸŸก

๊ธฐ์กด EC2, NCP ๊ฐ™์€ VM์— ์ง์ ‘ ๋ฐฐํฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด์•ผ.

# server.sh โ€” ์„œ๋ฒ„ ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ
#!/bin/bash
set -e
 
echo "๐Ÿ“ฆ ์˜์กด์„ฑ ์„ค์น˜..."
npm ci
 
echo "๐Ÿ”จ ๋นŒ๋“œ..."
npm run build
 
echo "๐Ÿ”„ ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ (PM2 ์‚ฌ์šฉ)..."
pm2 restart youngsu-community || pm2 start npm --name youngsu-community -- start
 
echo "โœ… ๋ฐฐํฌ ์™„๋ฃŒ!"
// ecosystem.config.js โ€” PM2 ์„ค์ •
module.exports = {
  apps: [
    {
      name: 'youngsu-community',
      script: 'npm',
      args: 'start',
      instances: 'max',    // CPU ์ฝ”์–ด ์ˆ˜๋งŒํผ ํ”„๋กœ์„ธ์Šค ์‹คํ–‰
      exec_mode: 'cluster',
      env: {
        NODE_ENV: 'production',
        PORT: 3000,
      },
    },
  ],
}

โš™๏ธ ํ™˜๊ฒฝ ๋ณ€์ˆ˜์™€ ๋น„๋ฐ€ํ‚ค ๊ด€๋ฆฌ ๐Ÿ”ด

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • NEXT_PUBLIC_ ์ ‘๋‘์‚ฌ์˜ ์˜๋ฏธ์™€ ์œ„ํ—˜์„ฑ์„ ์ดํ•ดํ•œ๋‹ค
  • ๋น„๋ฐ€ํ‚ค๊ฐ€ ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค์— ํฌํ•จ๋˜๋Š” ์‚ฌ๊ณ ๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๊ทœ์น™์„ ์•ˆ๋‹ค

๐Ÿค” ์ž ๊น, ๋จผ์ € ์ƒ๊ฐํ•ด๋ด
NEXT_PUBLIC_DATABASE_URL=postgresql://...์ด๋ผ๊ณ  ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜๋ฉด ์–ด๋–ค ์ผ์ด ์ƒ๊ธธ๊นŒ?

ํ™˜๊ฒฝ ๋ณ€์ˆ˜์˜ ๋‘ ์ข…๋ฅ˜:

NEXT_PUBLIC_ ์ ‘๋‘์‚ฌ ์žˆ์Œ โ†’ ํด๋ผ์ด์–ธํŠธ(๋ธŒ๋ผ์šฐ์ €) ๋ฒˆ๋“ค์— ํฌํ•จ
                           โ†’ ๋ˆ„๊ตฌ๋‚˜ DevTools์—์„œ ๋ณผ ์ˆ˜ ์žˆ์Œ โš ๏ธ

NEXT_PUBLIC_ ์ ‘๋‘์‚ฌ ์—†์Œ โ†’ ์„œ๋ฒ„์—์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ
                           โ†’ ๋ธŒ๋ผ์šฐ์ €์— ์ ˆ๋Œ€ ๋…ธ์ถœ ์•ˆ ๋จ โœ…
# .env.local (๋กœ์ปฌ ์ „์šฉ โ€” .gitignore์— ๋ฐ˜๋“œ์‹œ ํฌํ•จ!)
DATABASE_URL=postgresql://localhost:5432/dev     # ์„œ๋ฒ„ ์ „์šฉ โœ…
SESSION_SECRET=dev-secret-key                    # ์„œ๋ฒ„ ์ „์šฉ โœ…
NEXT_PUBLIC_API_URL=http://localhost:3000         # ํด๋ผ์ด์–ธํŠธ ์ ‘๊ทผ ๊ฐ€๋Šฅ (๊ณต๊ฐœ OK)
 
# โŒ ์ ˆ๋Œ€ ๊ธˆ์ง€!
NEXT_PUBLIC_DATABASE_URL=postgresql://...        # DB ์ ‘์† ์ •๋ณด๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์— ๋…ธ์ถœ!
NEXT_PUBLIC_SESSION_SECRET=secret-key            # ์•”ํ˜ธํ™” ํ‚ค๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์— ๋…ธ์ถœ!

server-only ํŒจํ‚ค์ง€๋กœ ์‹ค์ˆ˜ ๋ฐฉ์ง€:

// lib/db.ts โ€” ์„œ๋ฒ„์—์„œ๋งŒ ์‹คํ–‰๋˜๋Š” ํŒŒ์ผ
import 'server-only'
import { PrismaClient } from '@prisma/client'
 
// ์ด ํŒŒ์ผ์ด ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ import๋˜๋ฉด ๋นŒ๋“œ ์—๋Ÿฌ ๋ฐœ์ƒ
// โ†’ ์‹ค์ˆ˜๋กœ DB ์—ฐ๊ฒฐ ์ •๋ณด๊ฐ€ ํด๋ผ์ด์–ธํŠธ์— ๋…ธ์ถœ๋˜๋Š” ์‚ฌ๊ณ  ๋ฐฉ์ง€
export const db = new PrismaClient()

.env ํŒŒ์ผ ๊ณ„์ธต:

.env              โ†’ ๊ธฐ๋ณธ๊ฐ’ (git ์ถ”์  ๊ฐ€๋Šฅ, ๋ฏผ๊ฐ ์ •๋ณด ์—†์–ด์•ผ ํ•จ)
.env.local        โ†’ ๋กœ์ปฌ ๊ฐœ๋ฐœ (git ์ œ์™ธ, ๊ฐœ์ธ ์„ค์ •)
.env.development  โ†’ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ (git ์ถ”์  ๊ฐ€๋Šฅ)
.env.production   โ†’ ํ”„๋กœ๋•์…˜ (git ์ œ์™ธ! ๋˜๋Š” ๋น„๋ฐ€ ๊ด€๋ฆฌ ์„œ๋น„์Šค๋กœ)

๐Ÿ’ฅ ์—๋Ÿฌ ํ•ด๊ฒฐ ์นดํƒˆ๋กœ๊ทธ


โŒ Docker ๋นŒ๋“œ ํ›„ output: 'standalone' ๊ฒฐ๊ณผ๋ฌผ์— public ํŒŒ์ผ ์—†์Œ

์›์ธ: standalone ๋ชจ๋“œ๋Š” public ํด๋”๋ฅผ ์ž๋™์œผ๋กœ ํฌํ•จํ•˜์ง€ ์•Š์•„.

ํ•ด๊ฒฐ์ฑ…:

# Dockerfile์—์„œ public ํด๋”๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๋ณต์‚ฌ
COPY --from=builder /app/public ./public

โŒ ๋ฐฐํฌ ํ›„ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ๋ชป ์ฝ์Œ (undefined)

์›์ธ ์ฒดํฌ๋ฆฌ์ŠคํŠธ:

  1. .env.local์€ ๋กœ์ปฌ ์ „์šฉ. ์„œ๋ฒ„์—์„œ๋Š” ์‹œ์Šคํ…œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋˜๋Š” .env.production ์‚ฌ์šฉ
  2. NEXT_PUBLIC_ ์—†๋Š” ๋ณ€์ˆ˜๋ฅผ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์—์„œ ์ฝ์œผ๋ ค ํ•œ ๊ฒฝ์šฐ
  3. Docker ์‹คํ–‰ ์‹œ --env-file ์˜ต์…˜ ๋ˆ„๋ฝ

โŒ Vercel ๋ฐฐํฌ ํ›„ API Route๊ฐ€ 504 Timeout

์›์ธ: Vercel์˜ ๋ฌด๋ฃŒ ํ”Œ๋žœ์—์„œ ํ•จ์ˆ˜ ์‹คํ–‰ ์‹œ๊ฐ„ ํ•œ๋„(10์ดˆ) ์ดˆ๊ณผ.

ํ•ด๊ฒฐ์ฑ…:

// vercel.json์—์„œ ํŠน์ • ๊ฒฝ๋กœ ํƒ€์ž„์•„์›ƒ ์—ฐ์žฅ (Pro ํ”Œ๋žœ ํ•„์š”)
{
  "functions": {
    "app/api/heavy-task/route.ts": {
      "maxDuration": 60
    }
  }
}

๐Ÿ ์ด๋ฒˆ์— ๋ฐฐ์šด ๋‚ด์šฉ ์ด์ •๋ฆฌ

๐Ÿ“‹ ๋ฐฐํฌ ์ „๋žต ์„ ํƒ ๊ธฐ์ค€

์ƒํ™ฉ๊ถŒ์žฅ ๋ฐฐํฌ ์ „๋žต
์Šคํƒ€ํŠธ์—…, ์ดˆ๊ธฐ ์ถœ์‹œ, ์†Œ๊ทœ๋ชจ ํŒ€Vercel
๊ธฐ์—… ๋‚ด๋ถ€ ์„œ๋ฒ„, ๋ฐ์ดํ„ฐ ๊ตญ๋‚ด ๋ณด๊ด€ ํ•„์š”Docker + ์‚ฌ๋‚ด ์„œ๋ฒ„
๊ธฐ์กด VM ๋ณด์œ , ๋‹จ์ˆœ ๋ฐฐํฌNode.js ์ง์ ‘ (PM2)

โš ๏ธ ์ ˆ๋Œ€ ํ•˜์ง€ ๋ง ๊ฒƒ

์ƒํ™ฉโŒ ๋‚˜์œ ์˜ˆโœ… ์ข‹์€ ์˜ˆ
DB ์—ฐ๊ฒฐ ๋ฌธ์ž์—ดNEXT_PUBLIC_DATABASE_URLDATABASE_URL (์„œ๋ฒ„ ์ „์šฉ)
๋น„๋ฐ€ํ‚ค git ์ถ”์ .env.production git commitVercel ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋˜๋Š” AWS Secrets Manager
Docker์—์„œ root ์‹คํ–‰๊ธฐ๋ณธ root userUSER nextjs ์„ค์ •

๐Ÿ“ ๋งˆ๋ฌด๋ฆฌ ํ€ด์ฆˆ

Q1. NEXT_PUBLIC_SESSION_SECRET์ฒ˜๋Ÿผ ๋น„๋ฐ€ํ‚ค์— NEXT_PUBLIC_ ์ ‘๋‘์‚ฌ๋ฅผ ๋ถ™์ด๋ฉด ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋Š”๊ฐ€?

โœ… ์ •๋‹ต: ๊ฐ’์ด ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์–ด ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋…ธ์ถœ๋œ๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: NEXT_PUBLIC_์€ "๋ธŒ๋ผ์šฐ์ €์—์„œ ์ฝ์–ด๋„ ๋˜๋Š” ๊ฐ’"์ด๋ผ๋Š” ์„ ์–ธ์ด๋‹ค. ์„ธ์…˜ ์„œ๋ช…ํ‚ค, DB URL, API secret์—๋Š” ์ ˆ๋Œ€ ๋ถ™์ด๋ฉด ์•ˆ ๋œ๋‹ค. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ด๋ฆ„์€ ๋ฐฐํฌ ์ „๋žต๋ณด๋‹ค ๋จผ์ € ํ™•์ธํ•ด์•ผ ํ•˜๋Š” ๋ณด์•ˆ ๊ฒฝ๊ณ„๋‹ค.


Q2. Docker ๋ฐฐํฌ์—์„œ output: 'standalone'์„ ์‚ฌ์šฉํ•  ๋•Œ public ํด๋”์™€ .next/static์„ ๋ณ„๋„๋กœ ๋ณต์‚ฌํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋Š”?

โœ… ์ •๋‹ต: standalone ์ถœ๋ ฅ์€ ์‹คํ–‰ ์„œ๋ฒ„์— ํ•„์š”ํ•œ ์ตœ์†Œ ํŒŒ์ผ ์ค‘์‹ฌ์ด๋ผ ์ •์  ์ž์‚ฐ์„ ์ž๋™์œผ๋กœ ๋ชจ๋‘ ํฌํ•จํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: standalone์€ ์ด๋ฏธ์ง€ ํฌ๊ธฐ๋ฅผ ์ค„์ด๋Š” ๋ฐ ์œ ์šฉํ•˜์ง€๋งŒ, Dockerfile์—์„œ public๊ณผ .next/static์„ ๋ช…์‹œ์ ์œผ๋กœ ๋ณต์‚ฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ด๋ฏธ์ง€, ํฐํŠธ, JS ์ •์  ํŒŒ์ผ์ด 404๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. ๋นŒ๋“œ ์„ฑ๊ณต๊ณผ ๋Ÿฐํƒ€์ž„ ์ •์  ์ž์‚ฐ ์ œ๊ณต์€ ๋ณ„๊ฐœ์˜ ๊ฒ€์ฆ์ด๋‹ค.


Q3. ์˜์ฒ ์ด์˜ ํ…Œ์ŠคํŠธ ํƒ€์ž„: ์ž์ฒด Node ์„œ๋ฒ„๋ฅผ ์—ฌ๋Ÿฌ ์ธ์Šคํ„ด์Šค๋กœ ๋„๋ ธ๋”๋‹ˆ ISR/ํƒœ๊ทธ ์บ์‹œ ๋ฐ˜์˜ ์‹œ์ ์ด ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ๋‹ค๋ฅด๋‹ค. ๋ฌด์—‡์„ ๊ฒ€ํ† ํ•ด์•ผ ํ• ๊นŒ?

โœ… ์ •๋‹ต: ๊ณต์œ  ์บ์‹œ, ํƒœ๊ทธ ๋ฌดํšจํ™” ์ „ํŒŒ, CDN ์บ์‹œ ์ •์ฑ…์ฒ˜๋Ÿผ ๋‹ค์ค‘ ์ธ์Šคํ„ด์Šค์—์„œ ์บ์‹œ ์ผ๊ด€์„ฑ์„ ๋งž์ถ”๋Š” ์ธํ”„๋ผ๋ฅผ ๊ฒ€ํ† ํ•ด์•ผ ํ•œ๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: ๊ณต์‹ ๋ฐฐํฌ ๋ฌธ์„œ๋„ ๊ธฐ๋ณธ Node ์„œ๋ฒ„๋Š” ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ, ๋‹ค์ค‘ ์ธ์Šคํ„ด์Šค์—์„œ๋Š” ๊ณต์œ  ์บ์‹œ์™€ ๋ฌดํšจํ™” ์กฐ์œจ์ด ์šด์˜ ํ’ˆ์งˆ์„ ์ขŒ์šฐํ•œ๋‹ค๊ณ  ์„ค๋ช…ํ•œ๋‹ค. Vercel์€ ๋งŽ์€ ๋ถ€๋ถ„์„ ํ”Œ๋žซํผ์ด ๋งก์ง€๋งŒ, ์ž์ฒด ๋ฐฐํฌ๋Š” ํŒ€์ด ์ง์ ‘ ๊ด€์ธก๊ณผ ์ „ํŒŒ ๊ฒฝ๋กœ๋ฅผ ์„ค๊ณ„ํ•ด์•ผ ํ•œ๋‹ค.

๐Ÿฃ ์˜์ฒ ์ด์˜ ํ‡ด๊ทผ ์ผ๊ธฐ

์˜ค๋Š˜์€ ๋ฐฐํฌ๋ฅผ "์„œ๋ฒ„์— ์˜ฌ๋ฆฌ๊ธฐ"๊ฐ€ ์•„๋‹ˆ๋ผ Next.js ๋Ÿฐํƒ€์ž„ ๊ธฐ๋Šฅ์ด ์‹ค์ œ ํ™˜๊ฒฝ์—์„œ ๋๊นŒ์ง€ ์ž‘๋™ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์ผ๋กœ ๋ณด๊ฒŒ ๋๋‹ค. Server Components, streaming, ISR, Server Actions, ์ •์  ์ž์‚ฐ์ด ๋ชจ๋‘ ๋ฐฐํฌ ํ”Œ๋žซํผ์˜ ์ง€์›๊ณผ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์—ˆ๋‹ค.

๐Ÿ’ก "๋ฐฐํฌ ์ „๋žต์€ ๋น„์šฉํ‘œ๊ฐ€ ์•„๋‹ˆ๋ผ ๋Ÿฐํƒ€์ž„ ๊ธฐ๋Šฅ ์š”๊ตฌ์‚ฌํ•ญ์˜ ๊ฒฐ๊ณผ๋‹ค."

๋‹ค์Œ ๋ฐฐํฌ ์„ค๊ณ„์—์„œ๋Š” Vercel, Docker, ์ž์ฒด Node ์„œ๋ฒ„๋ฅผ ์ทจํ–ฅ์œผ๋กœ ๊ณ ๋ฅด์ง€ ์•Š๊ฒ ๋‹ค. ์ŠคํŠธ๋ฆฌ๋ฐ์ด ํ•„์š”ํ•œ์ง€, ์„œ๋ฒ„ ์•ก์…˜ ๋ณธ๋ฌธ ์ œํ•œ์€ ์ถฉ๋ถ„ํ•œ์ง€, ์ด๋ฏธ์ง€ ์ตœ์ ํ™”์™€ ๊ณต์œ  ์บ์‹œ๋Š” ๋ˆ„๊ฐ€ ์ฑ…์ž„์ง€๋Š”์ง€๋ถ€ํ„ฐ ํ™•์ธํ•˜๊ณ  ์„ ํƒ์ง€๋ฅผ ์ œ์•ˆํ•˜๊ฒ ๋‹ค.

๐Ÿ”— ๋” ์•Œ์•„๋ณด๊ธฐ