Docker provides a consistent, portable deployment solution for Noteverse with full support for real-time WebSocket connections. This guide covers building and deploying Noteverse using Docker and Docker Compose.
Prerequisites
Before starting:
Docker Engine 20.10+
Docker Compose v2.0+
2GB+ available RAM
PostgreSQL database (or use Docker Compose setup)
Quick Start
Clone Repository
git clone https://github.com/your-username/noteverse-frontend.git
cd noteverse-frontend
Configure Environment
Create .env file with required variables:
Dockerfile Overview
Noteverse uses a multi-stage Dockerfile for optimized production images:
# syntax=docker.io/docker/dockerfile:1
FROM node:18-alpine AS base
# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* prisma emails ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN \
if [ -f yarn.lock ]; then yarn run build; \
elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
else echo "Lockfile not found." && exit 1; \
fi
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
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" ]
Build Stages Explained
Stage 1: Base
Uses Node.js 18 Alpine for minimal image size
Stage 2: Dependencies
Installs production and development dependencies with package manager auto-detection
Stage 3: Builder
Builds the Next.js application with all assets
Stage 4: Runner
Creates minimal production image with only necessary files
The multi-stage build reduces final image size by ~70% compared to single-stage builds.
Building the Docker Image
Standard Build
docker build -t noteverse:latest .
With Build Arguments
docker build \
--build-arg NODE_ENV=production \
-t noteverse:latest \
.
# For ARM64 (Apple Silicon, AWS Graviton)
docker build --platform linux/arm64 -t noteverse:latest .
# For AMD64 (most cloud providers)
docker build --platform linux/amd64 -t noteverse:latest .
# Multi-platform build
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t noteverse:latest \
--push \
.
Docker Compose Setup
Create a docker-compose.yml file for complete stack deployment:
version : '3.8'
services :
app :
build :
context : .
dockerfile : Dockerfile
ports :
- "3000:3000"
environment :
- NODE_ENV=production
- DATABASE_URL=postgresql://noteverse:password@db:5432/noteverse
- NEXTAUTH_URL=http://localhost:3000
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
- NEXT_PUBLIC_API_URL=http://localhost:3000
- NEXT_PUBLIC_SOCKET_URL=http://localhost:3000
depends_on :
db :
condition : service_healthy
restart : unless-stopped
networks :
- noteverse-network
db :
image : postgres:15-alpine
environment :
- POSTGRES_USER=noteverse
- POSTGRES_PASSWORD=password
- POSTGRES_DB=noteverse
ports :
- "5432:5432"
volumes :
- postgres-data:/var/lib/postgresql/data
healthcheck :
test : [ "CMD-SHELL" , "pg_isready -U noteverse" ]
interval : 10s
timeout : 5s
retries : 5
restart : unless-stopped
networks :
- noteverse-network
volumes :
postgres-data :
networks :
noteverse-network :
driver : bridge
Start Services
# Start all services
docker compose up -d
# View logs
docker compose logs -f app
# Stop services
docker compose down
Environment Configuration
Create a .env file in your project root:
# Database
DATABASE_URL = "postgresql://noteverse:password@db:5432/noteverse"
# Authentication
NEXTAUTH_URL = "http://localhost:3000"
NEXTAUTH_SECRET = "your-generated-secret"
# Application URLs
NEXT_PUBLIC_API_URL = "http://localhost:3000"
NEXT_PUBLIC_SOCKET_URL = "http://localhost:3000"
NEXT_PUBLIC_UPLOAD_URL = "http://localhost:3000/uploads"
# Node Environment
NODE_ENV = "production"
# Server Configuration
PORT = 3000
HOSTNAME = "0.0.0.0"
For production deployments, always use secure passwords and generate strong secrets:
Port Mappings
The default configuration exposes these ports:
Service Internal Port External Port Description App 3000 3000 Next.js + Socket.IO server PostgreSQL 5432 5432 Database (optional external)
Custom Port Configuration
services :
app :
ports :
- "8080:3000" # Map to custom external port
environment :
- PORT=3000 # Internal port stays 3000
Database Migrations
Run Prisma migrations in the Docker container:
Initial Migration
# Run migrations after starting services
docker compose exec app npx prisma migrate deploy
# Generate Prisma client
docker compose exec app npx prisma generate
Automated Migrations
Update your Dockerfile to run migrations automatically:
# Add to Dockerfile before CMD
RUN npx prisma generate
CMD npx prisma migrate deploy && node server.js
Automated migrations ensure your database schema is always up-to-date on container startup.
WebSocket Support
Docker deployments have full WebSocket support for Socket.IO real-time features.
Noteverse’s server.mjs runs in the container with persistent connections:
// server.mjs runs on port 3000
const httpServer = createServer ( handler )
const io = new Server ( httpServer )
io . on ( 'connection' , ( socket ) => {
// Handle real-time events
socket . on ( 'registerUser' , ({ userId , userName , notesId }, cb ) => {
// User registration logic
})
socket . on ( 'contentChanged' , ({ notesId , content }) => {
socket . to ( notesId ). emit ( 'contentUpdated' , content )
})
})
Nginx Reverse Proxy Configuration
For production deployments behind Nginx:
upstream noteverse {
server localhost:3000;
}
server {
listen 80 ;
server_name noteverse.com;
location / {
proxy_pass http://noteverse;
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 ;
}
# WebSocket configuration
location /socket.io/ {
proxy_pass http://noteverse;
proxy_http_version 1.1 ;
proxy_set_header Upgrade $ http_upgrade ;
proxy_set_header Connection "upgrade" ;
proxy_set_header Host $ host ;
proxy_cache_bypass $ http_upgrade ;
}
}
Production Deployment
Build Image
docker build -t your-registry.com/noteverse:latest .
Push to Registry
docker push your-registry.com/noteverse:latest
Deploy to Platform
Deploy using your cloud provider’s container service:
AWS ECS/Fargate
Google Cloud Run
Azure Container Instances
DigitalOcean App Platform
Docker Swarm
# Initialize swarm
docker swarm init
# Deploy stack
docker stack deploy -c docker-compose.yml noteverse
# Scale services
docker service scale noteverse_app= 3
Kubernetes
Create Kubernetes deployment:
apiVersion : apps/v1
kind : Deployment
metadata :
name : noteverse
spec :
replicas : 3
selector :
matchLabels :
app : noteverse
template :
metadata :
labels :
app : noteverse
spec :
containers :
- name : noteverse
image : your-registry.com/noteverse:latest
ports :
- containerPort : 3000
env :
- name : DATABASE_URL
valueFrom :
secretKeyRef :
name : noteverse-secrets
key : database-url
Monitoring and Logs
View Logs
# Real-time logs
docker compose logs -f app
# Last 100 lines
docker compose logs --tail=100 app
# Logs with timestamps
docker compose logs -t app
Health Checks
Add health check to Docker Compose:
services :
app :
healthcheck :
test : [ "CMD" , "curl" , "-f" , "http://localhost:3000/api/health" ]
interval : 30s
timeout : 10s
retries : 3
start_period : 40s
Resource Limits
services :
app :
deploy :
resources :
limits :
cpus : '2'
memory : 2G
reservations :
cpus : '1'
memory : 1G
Troubleshooting
Container Won't Start
Database Connection Failed
Build Failures
# Check container logs
docker compose logs app
# Inspect container
docker compose exec app sh
# Check environment variables
docker compose exec app env | grep DATABASE_URL
Backup and Recovery
Database Backup
# Backup database
docker compose exec -T db pg_dump -U noteverse noteverse > backup.sql
# Restore database
docker compose exec -T db psql -U noteverse noteverse < backup.sql
# Automated backup with cron
0 2 * * * docker compose exec -T db pg_dump -U noteverse noteverse > /backups/noteverse_ $( date + \% Y \% m \% d ) .sql
Volume Backup
# Backup PostgreSQL data volume
docker run --rm \
-v noteverse_postgres-data:/data \
-v $( pwd ) :/backup \
alpine tar czf /backup/postgres-backup.tar.gz -C /data .
# Restore volume
docker run --rm \
-v noteverse_postgres-data:/data \
-v $( pwd ) :/backup \
alpine tar xzf /backup/postgres-backup.tar.gz -C /data
Security Best Practices
Always follow these security practices for production deployments:
Use non-root user (already configured in Dockerfile)
Set secure environment variables via secrets management
Enable SSL/TLS with reverse proxy
Regular security updates: docker compose pull && docker compose up -d
Implement rate limiting and firewall rules
Use Docker secrets for sensitive data
Regular vulnerability scanning: docker scan noteverse:latest
Next Steps
Set up automated backups
Configure monitoring with Prometheus/Grafana
Implement SSL with Let’s Encrypt
Set up CI/CD pipeline for automated deployments
Deployment Overview Learn about other deployment options and requirements