Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# ============================================
# .dockerignore for OverLearn
# Exclude files from Docker build context
# ============================================

# Dependencies
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# Testing
coverage
*.lcov
.nyc_output

# Next.js
.next/
out/
build/
dist/

# Production
*.log

# Environment variables
.env
.env*.local
.env.development
.env.test
.env.production

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.swp
*.swo
*~
.DS_Store
*.sublime-project
*.sublime-workspace

# OS files
Thumbs.db

# Git
.git
.gitignore
.gitattributes
.github

# Docker
Dockerfile*
docker-compose*.yml
.dockerignore

# Documentation
README.md
CHANGELOG.md
LICENSE
docs/
*.md

# Prisma (exclude local database, but keep schema and migrations)
prisma/*.db
prisma/*.db-journal
prisma/data/

# TypeScript
*.tsbuildinfo

# Debugging
.vscode/launch.json
.vscode/settings.json

# Turbopack cache
.turbo/

# System files
**/.DS_Store
**/Thumbs.db

# Temporary files
tmp/
temp/
*.tmp

# Scripts (optional, depending on if you need them in container)
scripts/install.sh
scripts/setup-systemd.sh

# Tauri (desktop app files not needed in Docker)
src-tauri/
target/

# Systemd
systemd/

# CI/CD
.gitlab-ci.yml
.travis.yml
azure-pipelines.yml
107 changes: 107 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# ============================================
# Multi-stage Dockerfile for OverLearn
# Optimized for Next.js 15 with Turbopack
# ============================================

# ============================================
# Stage 1: Dependencies
# ============================================
FROM node:20-alpine AS deps

WORKDIR /app

# Install dependencies needed for native modules
RUN apk add --no-cache libc6-compat openssl

# Copy package files
COPY package*.json ./
COPY prisma ./prisma/

# Install dependencies
RUN npm ci --only=production && \
npm cache clean --force

# Generate Prisma Client
RUN npx prisma generate

# ============================================
# Stage 2: Builder
# ============================================
FROM node:20-alpine AS builder

WORKDIR /app

# Install build dependencies
RUN apk add --no-cache libc6-compat openssl

# Copy package files and install ALL dependencies (including dev)
COPY package*.json ./
RUN npm ci

# Copy prisma schema and generate client
COPY prisma ./prisma/
RUN npx prisma generate

# Copy source code
COPY . .

# Build Next.js application
# Disable telemetry during build
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production

RUN npm run build

# ============================================
# Stage 3: Runner (Production)
# ============================================
FROM node:20-alpine AS runner

WORKDIR /app

# Install runtime dependencies
RUN apk add --no-cache \
libc6-compat \
openssl \
ca-certificates

# Create non-root user
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs

# Copy necessary files from builder
COPY --from=builder /app/next.config.ts ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/package*.json ./

# Copy .next folder (includes build output and static files)
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next

# Copy node_modules from deps stage (production only)
COPY --from=deps --chown=nextjs:nodejs /app/node_modules ./node_modules

# Copy Prisma files
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma

# Create directory for SQLite database with correct permissions
RUN mkdir -p /app/prisma/data && \
chown -R nextjs:nodejs /app/prisma

# Switch to non-root user
USER nextjs

# Expose port
EXPOSE 3000

# Set environment variables
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"

# Start the application
CMD ["npm", "start"]
Loading