Complete deployment strategies and production considerations for the Qwe Framework.
- Overview
- Environment Setup
- Container Deployment
- Cloud Platforms
- Load Balancing
- Monitoring & Logging
- Security Considerations
- Performance Optimization
This guide covers deploying Qwe Framework applications from development to production, including containerization, cloud deployment, monitoring, and security best practices.
- 🐳 Containerized: Docker/Kubernetes deployment
- ☁️ Cloud Native: AWS, GCP, Azure platforms
- 🖥️ Traditional: VPS/Dedicated servers
- ⚡ Serverless: Edge computing and functions
- 🔄 CI/CD: Automated deployment pipelines
# Core Configuration
NODE_ENV=production
PORT=8080
HOST=0.0.0.0
# Security
JWT_SECRET=your-super-secure-jwt-secret-key
SESSION_SECRET=your-session-secret-key
# Database
DATABASE_URL=postgresql://user:password@host:5432/database
DB_POOL_SIZE=20
DB_SSL=true
# Monitoring
LOG_LEVEL=warn
METRICS_ENABLED=true
HEALTH_CHECK_PORT=8081
# Performance
COMPRESSION_ENABLED=true
CACHE_TTL=3600
RATE_LIMIT_WINDOW=900000
RATE_LIMIT_MAX=1000// config/production.ts
const productionConfig = {
server: {
port: parseInt(process.env.PORT || '8080'),
host: process.env.HOST || '0.0.0.0',
cluster: true,
workers: parseInt(process.env.WORKERS || '0') // 0 = CPU count
},
database: {
url: process.env.DATABASE_URL!,
pool: {
min: 5,
max: parseInt(process.env.DB_POOL_SIZE || '20'),
idle: 30000,
acquire: 60000
},
ssl: process.env.DB_SSL === 'true'
},
security: {
jwt: {
secret: process.env.JWT_SECRET!,
expiresIn: '15m'
},
cors: {
origin: process.env.ALLOWED_ORIGINS?.split(',') || false,
credentials: true
},
helmet: {
contentSecurityPolicy: true,
crossOriginEmbedderPolicy: true
}
},
logging: {
level: process.env.LOG_LEVEL || 'info',
format: 'json',
destinations: ['console', 'file']
}
};# Multi-stage build for optimal image size
FROM node:18-alpine AS builder
WORKDIR /app
# Copy package files
COPY package*.json ./
COPY tsconfig.json ./
# Install dependencies
RUN npm ci --only=production && npm cache clean --force
# Copy source code
COPY src/ ./src/
# Build application
RUN npm run build
# Production stage
FROM node:18-alpine AS production
# Create app user
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
WORKDIR /app
# Copy built application
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
# Security improvements
RUN apk --no-cache add dumb-init && \
rm -rf /var/cache/apk/*
# Switch to non-root user
USER appuser
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node dist/healthcheck.js
# Expose port
EXPOSE 8080
# Start application
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/index.js"]# docker-compose.prod.yml
version: '3.8'
services:
app:
build:
context: .
target: production
ports:
- "8080:8080"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:password@db:5432/qweapp
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
networks:
- app-network
restart: unless-stopped
db:
image: postgres:15-alpine
environment:
- POSTGRES_DB=qweapp
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- app-network
restart: unless-stopped
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis_data:/data
networks:
- app-network
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- app
networks:
- app-network
restart: unless-stopped
volumes:
postgres_data:
redis_data:
networks:
app-network:
driver: bridge# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: qwe-app
labels:
app: qwe-app
spec:
replicas: 3
selector:
matchLabels:
app: qwe-app
template:
metadata:
labels:
app: qwe-app
spec:
containers:
- name: qwe-app
image: your-registry/qwe-app:latest
ports:
- containerPort: 8080
env:
- name: NODE_ENV
value: "production"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: app-secrets
key: jwt-secret
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: qwe-app-service
spec:
selector:
app: qwe-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer{
"family": "qwe-app",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"executionRoleArn": "arn:aws:iam::account:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::account:role/ecsTaskRole",
"containerDefinitions": [
{
"name": "qwe-app",
"image": "your-account.dkr.ecr.region.amazonaws.com/qwe-app:latest",
"portMappings": [
{
"containerPort": 8080,
"protocol": "tcp"
}
],
"essential": true,
"environment": [
{
"name": "NODE_ENV",
"value": "production"
}
],
"secrets": [
{
"name": "DATABASE_URL",
"valueFrom": "arn:aws:secretsmanager:region:account:secret:prod/database-url"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/qwe-app",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]
}// lambda/handler.ts
import { createLambdaHandler } from 'qwe-framework';
import { app } from '../src/app';
export const handler = createLambdaHandler(app, {
binary: ['image/*', 'application/pdf'],
stripBasePath: '/prod'
});# cloudrun.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: qwe-app
annotations:
run.googleapis.com/ingress: all
spec:
template:
metadata:
annotations:
run.googleapis.com/cpu-throttling: "false"
run.googleapis.com/memory: "512Mi"
run.googleapis.com/cpu: "1000m"
spec:
containers:
- image: gcr.io/project-id/qwe-app:latest
ports:
- containerPort: 8080
env:
- name: NODE_ENV
value: "production"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
resources:
limits:
memory: "512Mi"
cpu: "1000m"{
"location": "East US",
"properties": {
"containers": [
{
"name": "qwe-app",
"properties": {
"image": "your-registry.azurecr.io/qwe-app:latest",
"ports": [
{
"port": 8080,
"protocol": "TCP"
}
],
"environmentVariables": [
{
"name": "NODE_ENV",
"value": "production"
}
],
"resources": {
"requests": {
"cpu": 1,
"memoryInGB": 1
}
}
}
}
],
"osType": "Linux",
"ipAddress": {
"type": "Public",
"ports": [
{
"port": 8080,
"protocol": "TCP"
}
]
}
}
}# nginx.conf
upstream qwe_app {
least_conn;
server app1:8080 max_fails=3 fail_timeout=30s;
server app2:8080 max_fails=3 fail_timeout=30s;
server app3:8080 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
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;
# WebSocket support
location /ws {
proxy_pass http://qwe_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;
}
# API routes
location /api {
proxy_pass http://qwe_app;
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;
# Rate limiting
limit_req zone=api burst=10 nodelay;
}
# Static files
location /static {
alias /var/www/static;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
# Rate limiting
http {
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
}// monitoring/setup.ts
import { createMonitoring } from 'qwe-framework';
const monitoring = createMonitoring({
prometheus: {
enabled: true,
endpoint: '/metrics',
defaultMetrics: true
},
healthChecks: {
endpoint: '/health',
checks: {
database: async () => {
const result = await db.query('SELECT 1');
return { status: 'healthy', response_time: Date.now() };
},
redis: async () => {
const start = Date.now();
await redis.ping();
return { status: 'healthy', response_time: Date.now() - start };
},
external_api: async () => {
try {
const response = await fetch('https://api.external.com/health');
return { status: response.ok ? 'healthy' : 'unhealthy' };
} catch (error) {
return { status: 'unhealthy', error: error.message };
}
}
}
},
logging: {
level: 'info',
format: 'json',
includeStack: process.env.NODE_ENV === 'development'
}
});
app.use(monitoring.middleware());// logging/logger.ts
import { createLogger } from 'qwe-framework';
const logger = createLogger({
level: process.env.LOG_LEVEL || 'info',
format: 'json',
transports: [
{
type: 'console',
colorize: process.env.NODE_ENV === 'development'
},
{
type: 'file',
filename: 'logs/app.log',
maxSize: '10MB',
maxFiles: 5
},
{
type: 'http',
host: 'logs.example.com',
port: 443,
ssl: true
}
],
metadata: {
service: 'qwe-app',
version: process.env.APP_VERSION || '1.0.0',
environment: process.env.NODE_ENV
}
});
// Usage in middleware
app.use((qwe, next) => {
const start = Date.now();
qwe.logger = logger.child({
requestId: qwe.generateId(),
ip: qwe.ip,
userAgent: qwe.headers['user-agent']
});
qwe.logger.info('Request started', {
method: qwe.method,
url: qwe.url,
headers: qwe.headers
});
const originalJson = qwe.json;
qwe.json = (data) => {
qwe.logger.info('Request completed', {
method: qwe.method,
url: qwe.url,
statusCode: qwe.statusCode,
duration: Date.now() - start
});
return originalJson.call(qwe, data);
};
return next();
});// security/production.ts
import { createSecurityMiddleware } from 'qwe-framework';
const security = createSecurityMiddleware({
// Helmet configuration
helmet: {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'", "wss:", "https:"],
fontSrc: ["'self'"],
objectSrc: ["'none'"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"]
}
},
crossOriginEmbedderPolicy: true,
crossOriginOpenerPolicy: true,
crossOriginResourcePolicy: true,
dnsPrefetchControl: true,
frameguard: { action: 'deny' },
hidePoweredBy: true,
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
ieNoOpen: true,
noSniff: true,
originAgentCluster: true,
permittedCrossDomainPolicies: false,
referrerPolicy: 'no-referrer',
xssFilter: true
},
// CORS configuration
cors: {
origin: process.env.ALLOWED_ORIGINS?.split(',') || false,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400
},
// Rate limiting
rateLimit: {
windowMs: 15 * 60 * 1000, // 15 minutes
max: 1000, // limit each IP to 1000 requests per windowMs
standardHeaders: true,
legacyHeaders: false,
skipSuccessfulRequests: false,
skipFailedRequests: false,
// Custom key generator
keyGenerator: (qwe) => {
return qwe.headers['x-forwarded-for'] || qwe.ip;
},
// Custom handler
handler: (qwe) => {
return qwe.tooManyRequests('Too many requests from this IP');
}
}
});
app.use(security);# Generate SSL certificate with Let's Encrypt
certbot certonly --webroot \
--webroot-path=/var/www/certbot \
--email admin@your-domain.com \
--agree-tos \
--no-eff-email \
-d your-domain.com \
-d www.your-domain.com
# Auto-renewal cron job
0 12 * * * /usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"// cluster.ts
import cluster from 'cluster';
import os from 'os';
import { createApp } from './app';
if (cluster.isPrimary) {
const numWorkers = process.env.WORKERS || os.cpus().length;
console.log(`Master ${process.pid} is running`);
console.log(`Starting ${numWorkers} workers`);
// Fork workers
for (let i = 0; i < numWorkers; i++) {
cluster.fork();
}
// Replace dead workers
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
cluster.fork();
});
// Graceful shutdown
process.on('SIGTERM', () => {
console.log('Shutting down gracefully');
for (const id in cluster.workers) {
cluster.workers[id]?.kill();
}
});
} else {
// Worker process
const app = createApp();
const server = app.listen(process.env.PORT || 8080, () => {
console.log(`Worker ${process.pid} started`);
});
// Graceful shutdown for workers
process.on('SIGTERM', () => {
console.log(`Worker ${process.pid} shutting down`);
server.close(() => {
process.exit(0);
});
});
}// caching/setup.ts
import { createCacheManager } from 'qwe-framework';
const cache = createCacheManager({
// Redis for distributed caching
redis: {
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379'),
password: process.env.REDIS_PASSWORD,
db: 0,
keyPrefix: 'qwe:',
ttl: 3600 // 1 hour default
},
// Memory cache for frequently accessed data
memory: {
max: 1000,
ttl: 300 // 5 minutes
}
});
// Cache middleware
app.use('/api', cache.middleware({
ttl: 300,
vary: ['Authorization'],
skip: (qwe) => qwe.method !== 'GET',
key: (qwe) => `${qwe.method}:${qwe.url}:${qwe.user?.userId || 'anonymous'}`
}));// database/optimization.ts
const dbConfig = {
// Connection pooling
pool: {
min: 5,
max: 20,
idle: 30000,
acquire: 60000,
evict: 1000
},
// Query optimization
benchmark: true,
logging: (sql, timing) => {
if (timing > 1000) { // Log slow queries
console.warn(`Slow query (${timing}ms): ${sql}`);
}
},
// Read replicas
replication: {
read: [
{ host: 'read-replica-1.example.com' },
{ host: 'read-replica-2.example.com' }
],
write: { host: 'master.example.com' }
}
};# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Run security audit
run: npm audit
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker image
run: |
docker build -t ${{ secrets.REGISTRY_URL }}/qwe-app:${{ github.sha }} .
docker build -t ${{ secrets.REGISTRY_URL }}/qwe-app:latest .
- name: Push to registry
run: |
echo ${{ secrets.REGISTRY_PASSWORD }} | docker login ${{ secrets.REGISTRY_URL }} -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin
docker push ${{ secrets.REGISTRY_URL }}/qwe-app:${{ github.sha }}
docker push ${{ secrets.REGISTRY_URL }}/qwe-app:latest
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Deploy to production
run: |
# Update Kubernetes deployment
kubectl set image deployment/qwe-app qwe-app=${{ secrets.REGISTRY_URL }}/qwe-app:${{ github.sha }}
kubectl rollout status deployment/qwe-appThis deployment guide provides comprehensive strategies for taking Qwe Framework applications from development to production. The combination of containerization, cloud platforms, monitoring, and security measures ensures robust, scalable, and secure deployments.
- 🐳 Containerization: Use Docker for consistent deployments
- ☁️ Cloud Ready: Deploy on any major cloud platform
- 📊 Monitoring: Implement comprehensive logging and metrics
- 🔒 Security: Follow production security best practices
- ⚡ Performance: Optimize for production workloads
- 🔄 Automation: Use CI/CD for reliable deployments
- 📚 Check API Reference for complete documentation
- 📊 Review Performance for optimization strategies
- 🔐 Explore Authentication for security implementation
- 🧪 Study Testing for deployment testing strategies
Need help? Check the API Reference for complete deployment and configuration documentation.