diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..110fc07 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +.git +.gitignore +.env +.env.local +.env.production +node_modules +.next +src/generated +prisma/migrations +*.md +docker-compose.yml +docker-compose.prod.yml +Dockerfile +.dockerignore diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a41ab5e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,49 @@ +# Stage 1: Install all dependencies +FROM node:20-alpine AS deps +WORKDIR /app +COPY package.json package-lock.json ./ +RUN npm ci + +# Stage 2: Build +FROM node:20-alpine AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +# Generate Prisma client before build +RUN npx prisma generate +RUN npm run build + +# Stage 3: Production runner (standalone) +FROM node:20-alpine AS runner +WORKDIR /app +ENV NODE_ENV=production + +RUN addgroup --system --gid 1001 nodejs \ + && adduser --system --uid 1001 nextjs + +# Standalone output +COPY --from=builder /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +COPY --from=builder /app/public ./public + +# Prisma: migrations + generated client +COPY --from=builder /app/prisma ./prisma +COPY --from=builder /app/src/generated ./src/generated +COPY --from=builder /app/prisma.config.ts ./prisma.config.ts +COPY --from=builder /app/tsconfig.json ./tsconfig.json + +# Copy prisma CLI + dotenv for migrate deploy in entrypoint +COPY --from=builder /app/node_modules/.bin/prisma /usr/local/bin/prisma +COPY --from=builder /app/node_modules/prisma ./node_modules/prisma +COPY --from=builder /app/node_modules/@prisma ./node_modules/@prisma +COPY --from=builder /app/node_modules/dotenv ./node_modules/dotenv + +COPY entrypoint.sh ./entrypoint.sh +RUN chmod +x entrypoint.sh + +USER nextjs +EXPOSE 3000 +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" + +CMD ["./entrypoint.sh"] diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..1367c91 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,36 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile + restart: unless-stopped + ports: + - "3010:3000" + environment: + DATABASE_URL: "postgresql://lms_user:${DB_PASSWORD}@db:5432/lms_db" + BETTER_AUTH_SECRET: "${BETTER_AUTH_SECRET}" + BETTER_AUTH_URL: "https://school.second-brain.ru" + NEXT_PUBLIC_APP_URL: "https://school.second-brain.ru" + RESEND_API_KEY: "${RESEND_API_KEY}" + EMAIL_FROM: "${EMAIL_FROM}" + depends_on: + db: + condition: service_healthy + + db: + image: postgres:16-alpine + restart: unless-stopped + environment: + POSTGRES_USER: lms_user + POSTGRES_PASSWORD: "${DB_PASSWORD}" + POSTGRES_DB: lms_db + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U lms_user -d lms_db"] + interval: 5s + timeout: 5s + retries: 10 + +volumes: + postgres_data: diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..376047c --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +echo "Running database migrations..." +npx prisma migrate deploy + +echo "Starting Next.js..." +exec node server.js diff --git a/next.config.ts b/next.config.ts index e9ffa30..68a6c64 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + output: "standalone", }; export default nextConfig;