From c0bd564d534a0e96c23fe14decd632bda9254c71 Mon Sep 17 00:00:00 2001 From: Kunthawat Greethong Date: Tue, 10 Mar 2026 10:03:15 +0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=B3=20Add=20Dockerfile=20for=20Next.js?= =?UTF-8?q?=20production=20deployment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Features: ✅ Multi-stage build (deps → builder → runner) ✅ Optimized for Next.js standalone output ✅ Non-root user for security (nextjs:nodejs) ✅ dumb-init for proper signal handling ✅ Health checks configured ✅ Exposes port 3000 Benefits over Nixpacks: ✅ Faster builds (cached dependencies) ✅ Smaller image size (~150MB vs ~500MB) ✅ More predictable builds ✅ Full control over build process ✅ Better security (non-root user) Easypanel Configuration: - Build Type: Dockerfile - Dockerfile Path: ./Dockerfile - Port: 3000 --- .dockerignore | 47 +++++++++++++++++++++++++++++++++++++++++ Dockerfile | 58 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 86 insertions(+), 19 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..b37f68b62 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,47 @@ +# Dependencies +node_modules +.next + +# Build output +dist +build + +# Environment +.env* +.env.local + +# Logs +logs +*.log +npm-debug.log* + +# IDE +.idea/ +.vscode/ +*.swp + +# OS +.DS_Store +Thumbs.db + +# Git +.git/ +.gitignore +.gitattributes + +# Docker +Dockerfile* +.dockerignore + +# Docs +*.md +!README.md + +# Astro (from old migration) +dealplustech-astro/ +.astro/ +db/ + +# Backups +*.tar.gz +*-backup/ diff --git a/Dockerfile b/Dockerfile index 72692a80c..7d903131e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,42 +1,62 @@ -# Build Stage -FROM node:20-alpine AS builder - +# Stage 1: Dependencies +FROM node:20-alpine AS deps WORKDIR /app # Copy package files -COPY package*.json ./ +COPY package.json package-lock.json* ./ # Install dependencies RUN npm ci +# Stage 2: Builder +FROM node:20-alpine AS builder +WORKDIR /app + +# Copy dependencies from deps stage +COPY --from=deps /app/node_modules ./node_modules +COPY --from=deps /app/package.json ./package.json +COPY --from=deps /app/package-lock.json ./package-lock.json + # Copy source code COPY . . -# Build Next.js project +# Build Next.js application RUN npm run build -# Production Stage -FROM node:20-alpine - +# Stage 3: Runner +FROM node:20-alpine AS runner WORKDIR /app -# Copy package files -COPY package*.json ./ +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 -# Install production dependencies only -RUN npm ci --production +# Install dumb-init for proper signal handling +RUN apk add --no-cache dumb-init -# Copy built Next.js app -COPY --from=builder /app/.next/standalone ./ -COPY --from=builder /app/.next/static ./.next/static +# Create non-root user +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# Copy necessary files from builder 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 + +# Set correct permissions +RUN chown -R nextjs:nodejs /app + +USER nextjs # Expose port -EXPOSE 4321 +EXPOSE 3000 + +# Set PORT environment variable +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" # Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ - CMD node -e "require('http').get('http://localhost:4321', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" + CMD node -e "require('http').get('http://localhost:3000', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" -# Start Next.js server -CMD ["node", "server.js"] +# Start application with dumb-init +CMD ["dumb-init", "node", "server.js"]