DB, Collections, Search
This commit is contained in:
81
docker/Dockerfile
Normal file
81
docker/Dockerfile
Normal file
@@ -0,0 +1,81 @@
|
||||
# Stage 1: Dependencies
|
||||
FROM node:22-alpine AS deps
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies for building native modules
|
||||
RUN apk add --no-cache \
|
||||
libc6-compat \
|
||||
openssl \
|
||||
python3 \
|
||||
make \
|
||||
g++
|
||||
|
||||
# Copy package files
|
||||
COPY package.json package-lock.json ./
|
||||
COPY prisma ./prisma
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci
|
||||
|
||||
# Generate Prisma Client
|
||||
RUN npx prisma generate
|
||||
|
||||
# Stage 2: Builder
|
||||
FROM node:22-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# Install openssl for Prisma
|
||||
RUN apk add --no-cache openssl
|
||||
|
||||
# Copy dependencies from deps stage
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Generate Prisma Client again for builder context
|
||||
RUN npx prisma generate
|
||||
|
||||
# Build Next.js application
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV NODE_ENV=production
|
||||
RUN npm run build
|
||||
|
||||
# Stage 3: Runner
|
||||
FROM node:22-alpine AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apk add --no-cache openssl
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup --system --gid 1001 nodejs && \
|
||||
adduser --system --uid 1001 nextjs
|
||||
|
||||
# Copy necessary files with ownership set during copy (more efficient)
|
||||
COPY --chown=nextjs:nodejs --from=builder /app/public ./public
|
||||
COPY --chown=nextjs:nodejs --from=builder /app/.next/standalone ./
|
||||
COPY --chown=nextjs:nodejs --from=builder /app/.next/static ./.next/static
|
||||
|
||||
# Copy node_modules for Prisma CLI and seed script (Prisma CLI has 33+ dependencies)
|
||||
COPY --chown=nextjs:nodejs --from=builder /app/node_modules ./node_modules
|
||||
COPY --chown=nextjs:nodejs --from=builder /app/prisma ./prisma
|
||||
|
||||
# Copy entrypoint script
|
||||
COPY --chown=nextjs:nodejs --from=builder /app/docker/entrypoint.sh ./entrypoint.sh
|
||||
RUN chmod +x ./entrypoint.sh
|
||||
|
||||
# Switch to non-root user
|
||||
USER nextjs
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3000
|
||||
|
||||
ENV PORT=3000
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
|
||||
# Start the application with automatic migrations
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
18
docker/entrypoint.sh
Normal file
18
docker/entrypoint.sh
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "🔄 Running database migrations..."
|
||||
# Check if migrations directory exists and has files
|
||||
if [ -d "prisma/migrations" ] && [ "$(ls -A prisma/migrations 2>/dev/null)" ]; then
|
||||
echo "Found migration files, running migrate deploy..."
|
||||
node_modules/.bin/prisma migrate deploy
|
||||
else
|
||||
echo "No migration files found, running db push..."
|
||||
node_modules/.bin/prisma db push --accept-data-loss
|
||||
fi
|
||||
|
||||
echo "🌱 Seeding database (if needed)..."
|
||||
node_modules/.bin/tsx prisma/seed.ts || echo "⚠️ Seed failed or already completed, continuing..."
|
||||
|
||||
echo "🚀 Starting application..."
|
||||
exec node server.js
|
||||
101
docker/nginx.conf
Normal file
101
docker/nginx.conf
Normal file
@@ -0,0 +1,101 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
# Rate limiting zones
|
||||
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
|
||||
limit_req_zone $binary_remote_addr zone=auth:10m rate=5r/m;
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/m;
|
||||
|
||||
# Upstream Next.js app
|
||||
upstream nextjs_app {
|
||||
server app:3000;
|
||||
}
|
||||
|
||||
# HTTP server - redirect to HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS server
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name _;
|
||||
|
||||
# SSL configuration
|
||||
ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||
ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
|
||||
|
||||
# Max body size for file uploads
|
||||
client_max_body_size 10M;
|
||||
|
||||
# Logging
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
# Rate limiting for auth endpoints
|
||||
location ~ ^/(api/auth|login|register) {
|
||||
limit_req zone=auth burst=10 nodelay;
|
||||
proxy_pass http://nextjs_app;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# Rate limiting for API endpoints
|
||||
location /api/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
proxy_pass http://nextjs_app;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# General rate limiting for all other requests
|
||||
location / {
|
||||
limit_req zone=general burst=20 nodelay;
|
||||
proxy_pass http://nextjs_app;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
# Cache static assets
|
||||
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
|
||||
proxy_pass http://nextjs_app;
|
||||
proxy_cache_valid 200 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
docker/ssl/README.md
Normal file
35
docker/ssl/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# SSL Certificates
|
||||
|
||||
This directory should contain SSL certificates for HTTPS.
|
||||
|
||||
## Development
|
||||
|
||||
For local development, you can generate self-signed certificates:
|
||||
|
||||
```bash
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||
-keyout key.pem -out cert.pem \
|
||||
-subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"
|
||||
```
|
||||
|
||||
## Production
|
||||
|
||||
For production, use certificates from a trusted Certificate Authority like:
|
||||
- Let's Encrypt (recommended, free)
|
||||
- Your domain provider
|
||||
- Commercial CA
|
||||
|
||||
### Let's Encrypt with Certbot
|
||||
|
||||
```bash
|
||||
sudo certbot certonly --standalone -d yourdomain.com
|
||||
sudo cp /etc/letsencrypt/live/yourdomain.com/fullchain.pem ./cert.pem
|
||||
sudo cp /etc/letsencrypt/live/yourdomain.com/privkey.pem ./key.pem
|
||||
```
|
||||
|
||||
## Required Files
|
||||
|
||||
- `cert.pem` - SSL certificate
|
||||
- `key.pem` - Private key
|
||||
|
||||
**Important:** Never commit real SSL certificates to version control!
|
||||
Reference in New Issue
Block a user