Documentation Index
Fetch the complete documentation index at: https://asyncfunc.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Docker Deployment Guide
This comprehensive guide covers everything you need to know about deploying DeepWikiOpen using Docker, from basic setups to production-grade deployments.Table of Contents
- Prerequisites
- Quick Start with Pre-built Images
- Building Custom Images
- Docker Compose Setup
- Environment Configuration
- Volume Mounts and Data Persistence
- Container Networking
- Health Checks and Monitoring
- Scaling Strategies
- Security Considerations
- Troubleshooting
- Production Deployments
Prerequisites
Before you begin, ensure you have the following installed:- Docker (version 20.10+)
- Docker Compose (version 2.0+)
- Git (for cloning repositories)
Installation Verification
# Check Docker version
docker --version
docker-compose --version
# Verify Docker is running
docker info
Quick Start with Pre-built Images
Using GitHub Container Registry
DeepWikiOpen provides pre-built images through GitHub Container Registry (GHCR). This is the fastest way to get started.# Pull the latest image
docker pull ghcr.io/your-org/deepwikiopen:latest
# Run a simple container
docker run -d \
--name deepwikiopen \
-p 3000:3000 \
-e NODE_ENV=production \
ghcr.io/your-org/deepwikiopen:latest
Available Image Tags
| Tag | Description | Use Case |
|---|---|---|
latest | Latest stable release | Production |
develop | Development branch | Testing |
v1.2.3 | Specific version | Production pinning |
slim | Minimal image size | Resource-constrained environments |
Basic Docker Run Command
docker run -d \
--name deepwikiopen-app \
--restart unless-stopped \
-p 3000:3000 \
-e DATABASE_URL="postgresql://user:pass@host:5432/db" \
-e JWT_SECRET="your-secret-key" \
-e REDIS_URL="redis://redis:6379" \
-v deepwikiopen-data:/app/data \
ghcr.io/your-org/deepwikiopen:latest
Building Custom Images
Dockerfile Explanation
Hereβs a production-ready Dockerfile with explanations:# Use Node.js LTS Alpine for smaller image size
FROM node:18-alpine AS base
# Install system dependencies
RUN apk add --no-cache \
python3 \
make \
g++ \
cairo-dev \
jpeg-dev \
pango-dev \
musl-dev \
giflib-dev \
pixman-dev \
pangomm-dev \
libjpeg-turbo-dev \
freetype-dev
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
COPY yarn.lock ./
# Install dependencies
FROM base AS dependencies
RUN npm ci --only=production --frozen-lockfile
# Development dependencies for building
FROM base AS dev-dependencies
RUN npm ci --frozen-lockfile
# Build stage
FROM dev-dependencies AS build
COPY . .
RUN npm run build
RUN npm run test:unit
# Production stage
FROM base AS production
# Create non-root user for security
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
# Copy production dependencies
COPY --from=dependencies /app/node_modules ./node_modules
# Copy built application
COPY --from=build --chown=nextjs:nodejs /app/.next ./.next
COPY --from=build --chown=nextjs:nodejs /app/public ./public
COPY --from=build --chown=nextjs:nodejs /app/package.json ./package.json
# Create data directory
RUN mkdir -p /app/data && chown -R nextjs:nodejs /app/data
# Switch to non-root user
USER nextjs
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
# Start the application
CMD ["npm", "start"]
Building the Image
# Build with default tag
docker build -t deepwikiopen:local .
# Build with specific tag and build args
docker build \
--build-arg NODE_ENV=production \
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
-t deepwikiopen:v1.0.0 .
# Multi-platform build
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t deepwikiopen:multi-arch \
--push .
Optimized Development Dockerfile
FROM node:18-alpine AS development
# Install development tools
RUN apk add --no-cache \
git \
curl \
vim
WORKDIR /app
# Copy package files
COPY package*.json ./
RUN npm install
# Copy source code
COPY . .
# Expose port and start dev server
EXPOSE 3000
CMD ["npm", "run", "dev"]
Docker Compose Setup
Complete Production Setup
# docker-compose.yml
version: '3.8'
services:
# Main application
app:
image: ghcr.io/your-org/deepwikiopen:latest
container_name: deepwikiopen-app
restart: unless-stopped
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
- REDIS_URL=redis://redis:6379
- JWT_SECRET=${JWT_SECRET}
- NEXTAUTH_URL=${NEXTAUTH_URL}
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
volumes:
- app-data:/app/data
- app-logs:/app/logs
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- deepwikiopen-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# PostgreSQL database
postgres:
image: postgres:15-alpine
container_name: deepwikiopen-postgres
restart: unless-stopped
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
volumes:
- postgres-data:/var/lib/postgresql/data
- ./docker/postgres/init:/docker-entrypoint-initdb.d
ports:
- "5432:5432"
networks:
- deepwikiopen-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
# Redis cache
redis:
image: redis:7-alpine
container_name: deepwikiopen-redis
restart: unless-stopped
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
- ./docker/redis/redis.conf:/usr/local/etc/redis/redis.conf
ports:
- "6379:6379"
networks:
- deepwikiopen-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
# Elasticsearch for search
elasticsearch:
image: elasticsearch:8.8.0
container_name: deepwikiopen-elasticsearch
restart: unless-stopped
environment:
- discovery.type=single-node
- ES_JAVA_OPTS=-Xms512m -Xmx512m
- xpack.security.enabled=false
volumes:
- elasticsearch-data:/usr/share/elasticsearch/data
ports:
- "9200:9200"
networks:
- deepwikiopen-network
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:9200/_cluster/health"]
interval: 30s
timeout: 10s
retries: 3
# Nginx reverse proxy
nginx:
image: nginx:alpine
container_name: deepwikiopen-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./docker/nginx/conf.d:/etc/nginx/conf.d
- ./docker/ssl:/etc/nginx/ssl
- nginx-logs:/var/log/nginx
depends_on:
- app
networks:
- deepwikiopen-network
# Monitoring with Prometheus
prometheus:
image: prom/prometheus:latest
container_name: deepwikiopen-prometheus
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- ./docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/consoles'
networks:
- deepwikiopen-network
# Grafana for visualization
grafana:
image: grafana/grafana:latest
container_name: deepwikiopen-grafana
restart: unless-stopped
ports:
- "3001:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
volumes:
- grafana-data:/var/lib/grafana
- ./docker/grafana/provisioning:/etc/grafana/provisioning
networks:
- deepwikiopen-network
volumes:
app-data:
driver: local
app-logs:
driver: local
postgres-data:
driver: local
redis-data:
driver: local
elasticsearch-data:
driver: local
nginx-logs:
driver: local
prometheus-data:
driver: local
grafana-data:
driver: local
networks:
deepwikiopen-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
Development Compose Setup
# docker-compose.dev.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
container_name: deepwikiopen-dev
ports:
- "3000:3000"
- "9229:9229" # Node.js debugger
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:password@postgres:5432/deepwikiopen_dev
- REDIS_URL=redis://redis:6379
volumes:
- .:/app
- /app/node_modules
- dev-logs:/app/logs
depends_on:
- postgres
- redis
networks:
- dev-network
command: npm run dev
postgres:
image: postgres:15-alpine
container_name: deepwikiopen-postgres-dev
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=deepwikiopen_dev
volumes:
- postgres-dev-data:/var/lib/postgresql/data
ports:
- "5432:5432"
networks:
- dev-network
redis:
image: redis:7-alpine
container_name: deepwikiopen-redis-dev
ports:
- "6379:6379"
networks:
- dev-network
volumes:
postgres-dev-data:
dev-logs:
networks:
dev-network:
driver: bridge
Environment Configuration
Environment Variables Structure
Create a comprehensive.env file:
# .env
# Application Settings
NODE_ENV=production
PORT=3000
APP_URL=https://your-domain.com
APP_NAME="DeepWikiOpen"
# Database Configuration
DATABASE_URL=postgresql://username:password@postgres:5432/deepwikiopen
DB_HOST=postgres
DB_PORT=5432
DB_NAME=deepwikiopen
DB_USER=username
DB_PASSWORD=secure_password
# Redis Configuration
REDIS_URL=redis://redis:6379
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=redis_password
# Authentication
JWT_SECRET=your-super-secret-jwt-key-change-this
NEXTAUTH_URL=https://your-domain.com
NEXTAUTH_SECRET=another-super-secret-key
# OAuth Providers
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
# Email Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
# Storage Configuration
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_REGION=us-east-1
S3_BUCKET_NAME=your-s3-bucket
# Monitoring
SENTRY_DSN=https://your-sentry-dsn
NEW_RELIC_LICENSE_KEY=your-new-relic-key
# Security
CORS_ORIGIN=https://your-domain.com
RATE_LIMIT_MAX=100
RATE_LIMIT_WINDOW_MS=900000
# Feature Flags
ENABLE_SEARCH=true
ENABLE_ANALYTICS=true
ENABLE_NOTIFICATIONS=true
Environment Files for Different Stages
# .env.local (development)
NODE_ENV=development
DATABASE_URL=postgresql://postgres:password@localhost:5432/deepwikiopen_dev
REDIS_URL=redis://localhost:6379
JWT_SECRET=dev-secret
# .env.staging
NODE_ENV=staging
DATABASE_URL=postgresql://user:pass@staging-db:5432/deepwikiopen_staging
REDIS_URL=redis://staging-redis:6379
# .env.production
NODE_ENV=production
DATABASE_URL=postgresql://user:pass@prod-db:5432/deepwikiopen
REDIS_URL=redis://prod-redis:6379
Docker Compose Environment Override
# docker-compose.override.yml
version: '3.8'
services:
app:
environment:
- DEBUG=true
- LOG_LEVEL=debug
volumes:
- ./logs:/app/logs
Volume Mounts and Data Persistence
Volume Types and Use Cases
# Named volumes (recommended for production)
volumes:
# Database data persistence
postgres-data:
driver: local
driver_opts:
type: none
o: bind
device: /opt/deepwikiopen/postgres
# Application data
app-data:
driver: local
driver_opts:
type: none
o: bind
device: /opt/deepwikiopen/data
# Logs
app-logs:
driver: local
driver_opts:
type: none
o: bind
device: /opt/deepwikiopen/logs
# Backups
backup-data:
driver: local
driver_opts:
type: none
o: bind
device: /opt/deepwikiopen/backups
Bind Mounts for Development
services:
app:
volumes:
# Source code (development)
- ./src:/app/src
- ./public:/app/public
- ./package.json:/app/package.json
# Configuration files
- ./config:/app/config
- ./docker/app/entrypoint.sh:/app/entrypoint.sh
# Exclude node_modules
- /app/node_modules
NFS Volumes for Multi-Host Setup
volumes:
shared-data:
driver: local
driver_opts:
type: nfs
o: addr=nfs.example.com,rw
device: ":/path/to/shared/data"
Volume Backup Strategy
# Backup script
#!/bin/bash
# Create backup directory
mkdir -p /backups/$(date +%Y%m%d)
# Backup PostgreSQL
docker exec deepwikiopen-postgres pg_dump -U postgres deepwikiopen > \
/backups/$(date +%Y%m%d)/postgres-backup.sql
# Backup volumes
docker run --rm \
-v deepwikiopen_postgres-data:/source \
-v /backups/$(date +%Y%m%d):/backup \
alpine tar czf /backup/postgres-data.tar.gz -C /source .
docker run --rm \
-v deepwikiopen_app-data:/source \
-v /backups/$(date +%Y%m%d):/backup \
alpine tar czf /backup/app-data.tar.gz -C /source .
Container Networking
Custom Bridge Network
networks:
deepwikiopen-network:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.20.0.0/16
gateway: 172.20.0.1
Service Discovery
services:
app:
networks:
deepwikiopen-network:
aliases:
- webapp
- api
postgres:
networks:
deepwikiopen-network:
aliases:
- database
- db
Port Configuration
services:
# Internal communication only
app-internal:
expose:
- "3000"
networks:
- internal
# External access
app-external:
ports:
- "80:3000" # HTTP
- "443:3000" # HTTPS
- "3000:3000" # Direct access
networks:
- external
networks:
internal:
driver: bridge
internal: true
external:
driver: bridge
Network Security
# docker-compose.security.yml
version: '3.8'
services:
app:
networks:
- frontend
- backend
postgres:
networks:
- backend
# No external ports exposed
redis:
networks:
- backend
# No external ports exposed
nginx:
networks:
- frontend
ports:
- "80:80"
- "443:443"
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
Health Checks and Monitoring
Application Health Checks
# Dockerfile health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
# Docker Compose health checks
services:
app:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
Custom Health Check Endpoint
// pages/api/health.js
export default function handler(req, res) {
const checks = {
status: 'ok',
timestamp: new Date().toISOString(),
checks: {
database: 'checking...',
redis: 'checking...',
memory: process.memoryUsage(),
uptime: process.uptime()
}
};
// Check database connection
try {
// Your database check logic
checks.checks.database = 'healthy';
} catch (error) {
checks.checks.database = 'unhealthy';
checks.status = 'error';
}
// Check Redis connection
try {
// Your Redis check logic
checks.checks.redis = 'healthy';
} catch (error) {
checks.checks.redis = 'unhealthy';
checks.status = 'error';
}
const statusCode = checks.status === 'ok' ? 200 : 503;
res.status(statusCode).json(checks);
}
Monitoring with Docker Stats
# Monitor container resources
docker stats deepwikiopen-app
# Get detailed container information
docker inspect deepwikiopen-app
# View container logs
docker logs -f deepwikiopen-app
# Execute commands in running container
docker exec -it deepwikiopen-app sh
Prometheus Metrics
# docker/prometheus/prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'deepwikiopen'
static_configs:
- targets: ['app:3000']
metrics_path: '/api/metrics'
- job_name: 'postgres'
static_configs:
- targets: ['postgres-exporter:9187']
- job_name: 'redis'
static_configs:
- targets: ['redis-exporter:9121']
- job_name: 'nginx'
static_configs:
- targets: ['nginx-exporter:9113']
Scaling Strategies
Docker Compose Scale
# Scale application horizontally
docker-compose up -d --scale app=3
# Scale with load balancer
docker-compose -f docker-compose.yml -f docker-compose.scale.yml up -d
# docker-compose.scale.yml
version: '3.8'
services:
app:
deploy:
replicas: 3
nginx:
depends_on:
- app
volumes:
- ./docker/nginx/nginx-scale.conf:/etc/nginx/nginx.conf
Load Balancer Configuration
# docker/nginx/nginx-scale.conf
upstream app_servers {
server app_1:3000;
server app_2:3000;
server app_3:3000;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://app_servers;
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;
}
}
Docker Swarm Setup
# Initialize Docker Swarm
docker swarm init
# Deploy stack
docker stack deploy -c docker-compose.swarm.yml deepwikiopen
# Scale services
docker service scale deepwikiopen_app=5
# docker-compose.swarm.yml
version: '3.8'
services:
app:
image: ghcr.io/your-org/deepwikiopen:latest
deploy:
replicas: 3
placement:
constraints:
- node.role == worker
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
order: start-first
postgres:
image: postgres:15-alpine
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
resources:
limits:
memory: 1G
reservations:
memory: 512M
networks:
deepwikiopen-network:
driver: overlay
attachable: true
Auto-scaling with Docker Swarm
# Create auto-scaling service
docker service create \
--name deepwikiopen-app \
--replicas 2 \
--limit-cpu 0.5 \
--limit-memory 512m \
--reserve-cpu 0.25 \
--reserve-memory 256m \
--update-parallelism 1 \
--update-delay 10s \
ghcr.io/your-org/deepwikiopen:latest
Security Considerations
Container Security Best Practices
# Use non-root user
FROM node:18-alpine
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
# Set proper file permissions
COPY --chown=nextjs:nodejs . .
USER nextjs
# Use read-only root filesystem
docker run --read-only --tmpfs /tmp deepwikiopen:latest
# Drop capabilities
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE deepwikiopen:latest
# Set security options
docker run --security-opt=no-new-privileges:true deepwikiopen:latest
Secrets Management
# docker-compose.secrets.yml
version: '3.8'
services:
app:
secrets:
- db_password
- jwt_secret
environment:
- DATABASE_PASSWORD_FILE=/run/secrets/db_password
- JWT_SECRET_FILE=/run/secrets/jwt_secret
secrets:
db_password:
file: ./secrets/db_password.txt
jwt_secret:
file: ./secrets/jwt_secret.txt
Network Security
services:
app:
networks:
- frontend
# Only expose necessary ports
expose:
- "3000"
postgres:
networks:
- backend
# No external ports
# Use internal network only
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # No external access
Security Scanning
# Scan images for vulnerabilities
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
-v /tmp:/tmp anchore/grype:latest \
ghcr.io/your-org/deepwikiopen:latest
# Use Trivy for comprehensive scanning
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image ghcr.io/your-org/deepwikiopen:latest
Resource Limits
services:
app:
deploy:
resources:
limits:
cpus: '0.50'
memory: 512M
pids: 100
reservations:
cpus: '0.25'
memory: 256M
ulimits:
nofile:
soft: 1024
hard: 2048
Troubleshooting
Common Issues and Solutions
Container Wonβt Start
# Check container logs
docker logs deepwikiopen-app
# Check container configuration
docker inspect deepwikiopen-app
# Debug with shell access
docker run -it --entrypoint /bin/sh ghcr.io/your-org/deepwikiopen:latest
Database Connection Issues
# Test database connection
docker exec deepwikiopen-app nc -zv postgres 5432
# Check PostgreSQL logs
docker logs deepwikiopen-postgres
# Test with psql
docker exec -it deepwikiopen-postgres psql -U postgres -d deepwikiopen
Memory Issues
# Monitor memory usage
docker stats deepwikiopen-app
# Check for memory leaks
docker exec deepwikiopen-app cat /proc/meminfo
# Increase memory limits
docker run -m 1g deepwikiopen:latest
Permission Issues
# Check file permissions
docker exec deepwikiopen-app ls -la /app
# Fix ownership
docker exec deepwikiopen-app chown -R nextjs:nodejs /app/data
# Run as different user
docker run --user 1001:1001 deepwikiopen:latest
Debugging Tools
# Enter running container
docker exec -it deepwikiopen-app sh
# Copy files from container
docker cp deepwikiopen-app:/app/logs ./local-logs
# Run health checks manually
docker exec deepwikiopen-app curl -f http://localhost:3000/api/health
# Check network connectivity
docker exec deepwikiopen-app nslookup postgres
docker exec deepwikiopen-app ping redis
Performance Debugging
# Monitor container performance
docker stats --no-stream deepwikiopen-app
# Profile application
docker exec deepwikiopen-app node --prof app.js
# Check disk usage
docker exec deepwikiopen-app df -h
docker system df
Production Deployments
Production-Ready Compose File
# docker-compose.prod.yml
version: '3.8'
x-common-variables: &common-variables
POSTGRES_DB: ${POSTGRES_DB:-deepwikiopen}
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
services:
app:
image: ghcr.io/your-org/deepwikiopen:${TAG:-latest}
restart: unless-stopped
environment:
<<: *common-variables
NODE_ENV: production
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
volumes:
- app-data:/app/data:rw
- app-logs:/app/logs:rw
networks:
- app-network
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
memory: 1G
cpus: '1.0'
reservations:
memory: 512M
cpus: '0.5'
postgres:
image: postgres:15-alpine
restart: unless-stopped
environment:
<<: *common-variables
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
volumes:
- postgres-data:/var/lib/postgresql/data:rw
- postgres-backups:/backups:rw
networks:
- app-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
deploy:
resources:
limits:
memory: 2G
cpus: '1.0'
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data:rw
networks:
- app-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 3s
retries: 3
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
- nginx-logs:/var/log/nginx:rw
depends_on:
- app
networks:
- app-network
volumes:
app-data:
driver: local
driver_opts:
type: none
o: bind
device: /opt/deepwikiopen/data
app-logs:
driver: local
driver_opts:
type: none
o: bind
device: /opt/deepwikiopen/logs
postgres-data:
driver: local
driver_opts:
type: none
o: bind
device: /opt/deepwikiopen/postgres
postgres-backups:
driver: local
driver_opts:
type: none
o: bind
device: /opt/deepwikiopen/backups
redis-data:
driver: local
nginx-logs:
driver: local
networks:
app-network:
driver: bridge
Deployment Scripts
#!/bin/bash
# deploy.sh
set -e
echo "π Starting production deployment..."
# Load environment variables
source .env.production
# Pull latest images
echo "π₯ Pulling latest images..."
docker-compose -f docker-compose.prod.yml pull
# Create backup before deployment
echo "πΎ Creating backup..."
./scripts/backup.sh
# Stop services gracefully
echo "π Stopping services..."
docker-compose -f docker-compose.prod.yml down --remove-orphans
# Start services
echo "βΆοΈ Starting services..."
docker-compose -f docker-compose.prod.yml up -d
# Wait for health checks
echo "β³ Waiting for services to be healthy..."
timeout 300 docker-compose -f docker-compose.prod.yml exec app \
bash -c 'while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:3000/api/health)" != "200" ]]; do sleep 5; done'
# Run database migrations
echo "π Running database migrations..."
docker-compose -f docker-compose.prod.yml exec app npm run migrate
# Clean up old images
echo "π§Ή Cleaning up..."
docker image prune -f
echo "β
Deployment completed successfully!"
Zero-Downtime Deployment
#!/bin/bash
# zero-downtime-deploy.sh
set -e
# Blue-green deployment script
CURRENT_COLOR=$(docker-compose -f docker-compose.prod.yml ps -q app | head -1)
NEW_COLOR=$([ "$CURRENT_COLOR" == "blue" ] && echo "green" || echo "blue")
echo "π Starting zero-downtime deployment (switching to $NEW_COLOR)..."
# Start new version alongside current
docker-compose -f docker-compose.$NEW_COLOR.yml up -d
# Health check new version
echo "β³ Waiting for new version to be ready..."
timeout 300 bash -c "until curl -f http://localhost:3001/api/health; do sleep 5; done"
# Switch traffic
echo "π Switching traffic..."
./scripts/switch-traffic.sh $NEW_COLOR
# Stop old version
echo "π Stopping old version..."
docker-compose -f docker-compose.$CURRENT_COLOR.yml down
echo "β
Zero-downtime deployment completed!"
Monitoring and Alerting
# monitoring/docker-compose.monitoring.yml
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
ports:
- "9090:9090"
grafana:
image: grafana/grafana:latest
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
volumes:
- grafana-data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
ports:
- "3001:3000"
alertmanager:
image: prom/alertmanager:latest
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
ports:
- "9093:9093"
volumes:
prometheus-data:
grafana-data:
SSL/TLS Configuration
# nginx/nginx.conf
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
location / {
proxy_pass http://app:3000;
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;
}
}
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
- Always test deployments in a staging environment first
- Keep your images updated with security patches
- Monitor resource usage and adjust limits accordingly
- Implement proper backup and disaster recovery procedures
- Use secrets management for sensitive data
- Regular security audits of your containers and configurations