Deployment
Docker Deployment
Deploy with Docker and Docker Compose.
Overview
Docker deployment packages your Next.js app into a container for consistent deployment anywhere.
Prerequisites
- Docker 24+
- Production server (VPS, cloud instance)
Dockerfile
Create a Dockerfile in the project root:
FROM node:20-alpine AS base
# Install dependencies
FROM base AS deps
WORKDIR /app
COPY package.json bun.lockb ./
RUN npm install
# Build the app
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
# Production image
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
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
CMD ["node", "server.js"]This requires output: 'standalone' in next.config.mjs. Already configured in the template.
Docker Compose
For easier deployment with environment variables:
version: '3.8'
services:
web:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL}
- NEXT_PUBLIC_SUPABASE_URL=${NEXT_PUBLIC_SUPABASE_URL}
- NEXT_PUBLIC_SUPABASE_ANON_KEY=${NEXT_PUBLIC_SUPABASE_ANON_KEY}
- DATABASE_URL=${DATABASE_URL}
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
- NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY}
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3Deployment Steps
Create Environment File
Create a .env file on your server with production values:
NEXT_PUBLIC_APP_URL=https://yourdomain.com
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
DATABASE_URL=postgresql://postgres:[password]@db.xxx.supabase.co:5432/postgres
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...Verify Deployment
docker compose ps
curl http://localhost:3000/api/healthNginx Reverse Proxy
Put Nginx in front for SSL and caching:
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://localhost:3000;
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;
}
}Enable the site:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginxSSL with Let's Encrypt
sudo certbot --nginx -d yourdomain.comUpdating the App
Pull latest code and rebuild:
git pull
docker compose up -d --buildFor zero-downtime updates, use rolling deployments or container orchestration.
Troubleshooting
Container won't start
Check logs:
docker compose logs webPort already in use
sudo lsof -i :3000Environment variables not loaded
Verify .env file exists and is readable:
docker compose configRelated
- VPS Deployment - Server setup guide
- Environment Variables - Production config
Was this page helpful?