Production Deployment & Optimization
Complete guide for deploying SveltyCMS in production with Nginx, Redis, and enterprise-grade optimization strategies.
On this page
This comprehensive guide covers deploying SveltyCMS in production with Nginx reverse proxy, optional Redis caching, and enterprise-grade optimizations for maximum performance and security.
New: See Enterprise Scaling Layers for the complete composable scaling story — PgBouncer connection pooling, optional Redis, pre-compressed cache HITs (Brotli/zstd), CDN purge, and deployment diagrams. Start simple (single-node SQLite) and add layers as you grow.
Architecture Overview
The recommended production architecture is composable — start minimal and add layers:
- Nginx / Caddy — Reverse proxy, TLS termination, static asset serving, optional rate limiting
- SveltyCMS — Bun runtime (3-4× faster than Node.js), Turbo pipeline, LocalCMS zero-tax SDK
- Redis (optional) — Distributed L2 cache, cross-node invalidation, session sharing
- PgBouncer (optional) — Connection pooling for Postgres at scale (see scaling-layers.mdx)
- Database — SQLite (single-node), PostgreSQL, MariaDB, or MongoDB with connection pooling
Internet → Nginx (443) → PM2 Cluster → SveltyCMS → Redis → Database
↓
Static Assets
Prerequisites
Before starting, ensure you have:
- Linux server (Ubuntu 20.04+ or similar)
- Root or sudo access
- Domain name with DNS configured
- SSL certificate (Let’s Encrypt recommended)
- Node.js 24+ installed
- Redis 6+ installed
- Nginx installed
- ImageMagick & Ghostscript (Optional, for PDF thumbnails)
1. Nginx Configuration
Static Asset Optimization
Configure Nginx to serve static assets directly, bypassing Node.js entirely for maximum performance.
File: /etc/nginx/sites-available/sveltycms.conf
# Upstream Node.js application
upstream sveltycms_backend {
server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
keepalive 32;
}
# Rate limiting zones
limit_req_zone $binary_remote_addr zone=general:10m rate=100r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=50r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name your-domain.com;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security Headers (defense in depth)
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Root directory
root /var/www/sveltycms/build/client;
# Logging
access_log /var/log/nginx/sveltycms.access.log;
error_log /var/log/nginx/sveltycms.error.log warn;
# ===== STATIC ASSETS (Nginx serves directly) =====
# 🚀 IMPORTANT: SveltyCMS handles compression internally for dynamic paths.
# Turbo GET + API cache HITs already ship pre-compressed brotli/gzip/zstd
# with Content-Encoding set. Do NOT enable gzip/brotli on dynamic locations
# (proxy_pass) — this would double-compress and waste CPU.
# Static assets below can use Nginx's gzip_static/brotli_static safely.
# SvelteKit immutable assets
location ~ ^/_app/immutable/ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header X-Served-By "nginx-static";
access_log off;
try_files $uri =404;
gzip_static on;
brotli_static on;
}
# SvelteKit version files
location ~ ^/_app/version\.json$ {
expires 1h;
add_header Cache-Control "public, max-age=3600";
try_files $uri =404;
}
# Static folder
location ~ ^/static/ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header X-Served-By "nginx-static";
access_log off;
try_files $uri =404;
gzip_static on;
brotli_static on;
}
# Common static files
location ~ ^/(favicon\.ico|robots\.txt|sitemap\.xml|manifest\.webmanifest)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000";
access_log off;
try_files $uri =404;
}
# Media assets by extension
location ~ \.(svg|png|jpg|jpeg|gif|webp|avif|ico)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
try_files $uri =404;
}
# Fonts
location ~ \.(woff|woff2|ttf|eot|otf)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Access-Control-Allow-Origin "*";
access_log off;
try_files $uri =404;
}
# JavaScript and CSS
location ~ \.(js|css|map)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
try_files $uri =404;
gzip_static on;
brotli_static on;
}
# ===== SECURITY BLOCKS (Early rejection) =====
# Block hidden files
location ~ /\. {
deny all;
return 404;
}
# Block sensitive file extensions
location ~ \.(env|git|sql|bak|config|ini|log)$ {
deny all;
return 404;
}
# Block SQL injection patterns
location ~ (union.*select|concat.*\(|benchmark\(|sleep\(|load_file) {
deny all;
return 403;
}
# Block path traversal
location ~ (\.\./|\.\.\\|%2e%2e|%252e%252e) {
deny all;
return 403;
}
# ===== API ENDPOINTS (Rate limited, proxied to Node.js) =====
# Login endpoint (strict rate limiting)
location = /api/user/login {
limit_req zone=login burst=3 nodelay;
limit_req_status 429;
proxy_pass http://sveltycms_backend;
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;
# Timeouts
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
# API endpoints (moderate rate limiting)
location ~ ^/api/ {
limit_req zone=api burst=20 nodelay;
limit_req_status 429;
proxy_pass http://sveltycms_backend;
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;
# Timeouts for API
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# Buffer settings
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
# ===== ALL OTHER REQUESTS (Proxied to Node.js) =====
location / {
limit_req zone=general burst=50 nodelay;
# Try static files first, then proxy
try_files $uri @proxy;
}
location @proxy {
proxy_pass http://sveltycms_backend;
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;
# Buffer settings
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 16 8k;
proxy_busy_buffers_size 16k;
}
}
# HTTP to HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
Enable Configuration
# Create symbolic link
sudo ln -s /etc/nginx/sites-available/sveltycms.conf /etc/nginx/sites-enabled/
# Test configuration
sudo nginx -t
# Reload Nginx
sudo systemctl reload nginx
Performance Impact
| Metric | Before Nginx Optimization | After | Improvement |
|---|---|---|---|
| Static asset latency | 15-20ms | <1ms | 95% faster |
| Static asset CPU | Node.js process | None | 100% CPU reduction |
| Malicious requests | Reach Node.js | Blocked at Nginx | 80-90% blocked early |
2. Redis Configuration
Redis Setup
File: /etc/redis/redis.conf
# Network
bind 127.0.0.1
port 6379
protected-mode yes
tcp-backlog 511
# Security
requirepass your_strong_redis_password_here
# Memory Management
maxmemory 512mb
maxmemory-policy allkeys-lru # Evict least recently used keys
# Persistence
save 900 1 # Save if 1 key changed in 15 minutes
save 300 10 # Save if 10 keys changed in 5 minutes
save 60 10000 # Save if 10000 keys changed in 1 minute
# Append-only file (AOF) for durability
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# Performance
timeout 300
tcp-keepalive 60
databases 16
# Logging
loglevel notice
logfile /var/log/redis/redis-server.log
# Snapshotting
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis
Restart Redis
sudo systemctl restart redis-server
sudo systemctl enable redis-server
Update Environment Variables
Add to your .env file:
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=your_strong_redis_password_here
3. Application Configuration
PM2 Process Manager
PM2 provides cluster mode, auto-restart, and zero-downtime deployments.
File: ecosystem.config.js (in project root)
module.exports = {
apps: [
{
name: "sveltycms",
script: "build/index.js",
// Cluster mode (uses all CPU cores)
instances: "max",
exec_mode: "cluster",
// Environment variables
env: {
NODE_ENV: "production",
PORT: 3000,
HOST: "127.0.0.1",
},
// Memory management
max_memory_restart: "500M",
// Logging
error_file: "logs/error.log",
out_file: "logs/out.log",
merge_logs: true,
log_date_format: "YYYY-MM-DD HH:mm:ss Z",
// Restart behavior
autorestart: true,
max_restarts: 10,
min_uptime: "10s",
restart_delay: 4000,
// Graceful shutdown
kill_timeout: 5000,
listen_timeout: 3000,
shutdown_with_message: true,
// Watch options (disabled in production)
watch: false,
ignore_watch: ["node_modules", "logs", ".git"],
// Environment-specific overrides
env_development: {
NODE_ENV: "development",
watch: true,
},
},
],
deploy: {
production: {
user: "deploy",
host: "your-server.com",
ref: "origin/main",
repo: "git@github.com:yourorg/sveltycms.git",
path: "/var/www/sveltycms",
"post-deploy":
"bun install && bun run build && pm2 reload ecosystem.config.js --env production",
},
},
};
Install and Start PM2
# Install PM2 globally
npm install -g pm2
# Start application
pm2 start ecosystem.config.js --env production
# Save PM2 process list
pm2 save
# Enable auto-start on system boot
pm2 startup
# Monitor processes
pm2 monit
PM2 Commands
# View logs
pm2 logs sveltycms
# Restart application
pm2 restart sveltycms
# Reload (zero-downtime)
pm2 reload sveltycms
# Stop application
pm2 stop sveltycms
# View process info
pm2 info sveltycms
# View process list
pm2 list
4. Middleware Optimization
Remove Redundant Static Middleware
Since Nginx now handles static assets, you can optionally remove handleStaticAssetCaching from your middleware sequence.
File: src/hooks.server.ts
// Before (with static middleware)
export const handle: Handle = sequence(
handleStaticAssetCaching, // ← Remove this (Nginx handles it)
handleSystemState,
handleRateLimit,
handleFirewall,
// ... rest of middleware
);
// After (optimized for Nginx)
export const handle: Handle = sequence(
handleSystemState,
handleRateLimit,
handleFirewall,
handleSetup,
handleLocale,
handleTheme,
handleAuthentication,
handleAuthorization,
addSecurityHeaders,
);
Benefits:
- Faster application startup
- Lower memory usage
- Reduced CPU overhead
- Simplified middleware stack
Session Cache TTL Optimization
For high-traffic production, increase session cache TTL to reduce database queries.
File: src/hooks/handleAuthentication.ts
// Current (5 minutes)
const SESSION_CACHE_TTL_MS = 5 * 60 * 1000;
// Recommended for production (15 minutes)
const SESSION_CACHE_TTL_MS = 15 * 60 * 1000;
Impact: Reduces Redis/database queries by 66% while maintaining security through automatic session rotation.
5. Database Optimization
Connection Pooling
MongoDB {#pooling-mongodb}
import { MongoClient } from "mongodb";
const client = new MongoClient(process.env.MONGODB_URI, {
maxPoolSize: 50, // Maximum connections
minPoolSize: 10, // Minimum connections
maxIdleTimeMS: 60000, // Close idle connections after 60s
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
retryWrites: true,
w: "majority",
});
await client.connect();
PostgreSQL {#pooling-postgresql}
import { Pool } from "pg";
const pool = new Pool({
max: 50, // Maximum connections
min: 10, // Minimum connections
idleTimeoutMillis: 60000, // Close idle connections
connectionTimeoutMillis: 5000,
allowExitOnIdle: false,
});
Database Indexes
Create indexes for frequently queried fields to improve performance.
MongoDB {#mongodb-2}
// User collection
db.users.createIndex({ email: 1 }, { unique: true });
db.users.createIndex({ tenantId: 1, role: 1 });
db.users.createIndex({ createdAt: -1 });
// Session collection
db.sessions.createIndex({ sessionId: 1 }, { unique: true });
db.sessions.createIndex({ userId: 1 });
db.sessions.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 }); // TTL index
// Collections
db.collections.createIndex({ tenantId: 1, name: 1 });
db.collections.createIndex({ status: 1 });
// Media
db.media.createIndex({ tenantId: 1, type: 1 });
db.media.createIndex({ uploadedAt: -1 });
PostgreSQL {#postgresql-2}
-- Users table
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_tenant_role ON users(tenant_id, role);
CREATE INDEX idx_users_created ON users(created_at DESC);
-- Sessions table
CREATE UNIQUE INDEX idx_sessions_id ON sessions(session_id);
CREATE INDEX idx_sessions_user ON sessions(user_id);
CREATE INDEX idx_sessions_expires ON sessions(expires_at);
-- Collections table
CREATE INDEX idx_collections_tenant_name ON collections(tenant_id, name);
CREATE INDEX idx_collections_status ON collections(status);
-- Media table
CREATE INDEX idx_media_tenant_type ON media(tenant_id, type);
CREATE INDEX idx_media_uploaded ON media(uploaded_at DESC);
6. Monitoring & Observability
Health Check Endpoint
File: src/routes/api/health/+server.ts
import { json } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
import { getSystemState } from "@stores/system";
export const GET: RequestHandler = async () => {
const systemState = getSystemState();
const isHealthy = systemState.overallState === "READY";
const health = {
status: isHealthy ? "ok" : "degraded",
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: {
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
external: Math.round(process.memoryUsage().external / 1024 / 1024),
},
system: {
state: systemState.overallState,
setup: systemState.setupComplete,
database: systemState.databaseConnected,
},
};
return json(health, {
status: isHealthy ? 200 : 503,
headers: {
"Cache-Control": "no-cache, no-store, must-revalidate",
},
});
};
Prometheus Metrics Endpoint
File: src/routes/api/metrics/+server.ts
import { metricsService } from "@src/services/metrics-service";
import type { RequestHandler } from "./$types";
export const GET: RequestHandler = async () => {
const metrics = metricsService.getReport();
// Convert to Prometheus format
const prometheus = [
`# HELP sveltycms_requests_total Total HTTP requests`,
`# TYPE sveltycms_requests_total counter`,
`sveltycms_requests_total ${metrics.requests.total}`,
``,
`# HELP sveltycms_errors_total Total errors`,
`# TYPE sveltycms_errors_total counter`,
`sveltycms_errors_total ${metrics.requests.errors}`,
``,
`# HELP sveltycms_cache_hits_total Cache hit count`,
`# TYPE sveltycms_cache_hits_total counter`,
`sveltycms_cache_hits_total ${metrics.cache.hits}`,
``,
`# HELP sveltycms_cache_misses_total Cache miss count`,
`# TYPE sveltycms_cache_misses_total counter`,
`sveltycms_cache_misses_total ${metrics.cache.misses}`,
``,
`# HELP sveltycms_security_violations_total Security violation count by type`,
`# TYPE sveltycms_security_violations_total counter`,
`sveltycms_security_violations_total{type="rate_limit"} ${metrics.security.rateLimitViolations}`,
`sveltycms_security_violations_total{type="firewall"} ${metrics.security.firewallBlocks}`,
`sveltycms_security_violations_total{type="auth_failure"} ${metrics.security.authFailures}`,
].join("\n");
return new Response(prometheus, {
headers: {
"Content-Type": "text/plain; version=0.0.4",
"Cache-Control": "no-cache",
},
});
};
Nginx Monitoring
# Add to server block
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
Log Analysis
# Real-time request monitoring
tail -f /var/log/nginx/sveltycms.access.log
# Top requesting IPs
awk '{print $1}' /var/log/nginx/sveltycms.access.log | sort | uniq -c | sort -rn | head -20
# Response time analysis
awk '{print $NF}' /var/log/nginx/sveltycms.access.log | sort -n | tail -100
# 4xx/5xx errors
grep -E ' (4[0-9]{2}|5[0-9]{2}) ' /var/log/nginx/sveltycms.access.log | tail -50
7. Security Hardening
SSL/TLS Best Practices
# Generate strong DH parameters
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
# Add to Nginx SSL configuration
ssl_dhparam /etc/nginx/dhparam.pem;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
Firewall Configuration (UFW)
# Enable UFW
sudo ufw enable
# Allow SSH
sudo ufw allow 22/tcp
# Allow HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Check status
sudo ufw status verbose
Fail2Ban for Brute Force Protection
# Install Fail2Ban
sudo apt install fail2ban
# Create Nginx jail
sudo nano /etc/fail2ban/jail.local
File: /etc/fail2ban/jail.local
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/sveltycms.error.log
[nginx-noscript]
enabled = true
port = http,https
logpath = /var/log/nginx/sveltycms.access.log
[nginx-badbots]
enabled = true
port = http,https
logpath = /var/log/nginx/sveltycms.access.log
maxretry = 2
[nginx-noproxy]
enabled = true
port = http,https
logpath = /var/log/nginx/sveltycms.access.log
maxretry = 2
# Restart Fail2Ban
sudo systemctl restart fail2ban
# Check status
sudo fail2ban-client status
8. Backup Strategy
Automated Backups
File: /usr/local/bin/backup-sveltycms.sh
#!/bin/bash
# Configuration
BACKUP_DIR="/var/backups/sveltycms"
RETENTION_DAYS=30
DATE=$(date +%Y%m%d_%H%M%S)
# Create backup directory
mkdir -p "$BACKUP_DIR"
# Backup application files
tar -czf "$BACKUP_DIR/app_$DATE.tar.gz" -C /var/www sveltycms
# Backup database (MongoDB example)
mongodump --uri="mongodb://localhost:27017/sveltycms" --out="$BACKUP_DIR/db_$DATE"
tar -czf "$BACKUP_DIR/db_$DATE.tar.gz" -C "$BACKUP_DIR" "db_$DATE"
rm -rf "$BACKUP_DIR/db_$DATE"
# Backup Redis data
cp /var/lib/redis/dump.rdb "$BACKUP_DIR/redis_$DATE.rdb"
# Remove old backups
find "$BACKUP_DIR" -type f -mtime +$RETENTION_DAYS -delete
echo "Backup completed: $DATE"
# Make executable
sudo chmod +x /usr/local/bin/backup-sveltycms.sh
# Add to crontab (daily at 2 AM)
sudo crontab -e
Add line:
0 2 * * * /usr/local/bin/backup-sveltycms.sh >> /var/log/sveltycms-backup.log 2>&1
9. Performance Benchmarking
Apache Bench
# Test homepage
ab -n 1000 -c 100 https://your-domain.com/
# Test API endpoint
ab -n 1000 -c 50 https://your-domain.com/api/collections
K6 Load Testing
File: load-test.js
import http from "k6/http";
import { check, sleep } from "k6";
export const options = {
stages: [
{ duration: "2m", target: 100 }, // Ramp up to 100 users
{ duration: "5m", target: 100 }, // Stay at 100 users
{ duration: "2m", target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ["p(95)<500"], // 95% of requests under 500ms
},
};
export default function () {
const res = http.get("https://your-domain.com");
check(res, {
"status is 200": (r) => r.status === 200,
"response time < 500ms": (r) => r.timings.duration < 500,
});
sleep(1);
}
# Install K6
curl https://github.com/grafana/k6/releases/download/v0.46.0/k6-v0.46.0-linux-amd64.tar.gz -L | tar xvz
sudo mv k6-v0.46.0-linux-amd64/k6 /usr/local/bin/
# Run test
k6 run load-test.js
10. Deployment Checklist
Pre-Deployment
- Environment variables configured in
.env - Database indexes created
- Redis configured with authentication
- SSL certificates installed and valid
- Nginx configuration tested (
nginx -t) - Application built (
bun run build) - PM2 ecosystem file configured
- Backup strategy implemented
- Monitoring endpoints accessible
- Firewall rules configured
Deployment
- Start Redis:
sudo systemctl start redis-server - Start Nginx:
sudo systemctl start nginx - Start application:
pm2 start ecosystem.config.js --env production - Save PM2 state:
pm2 save - Enable PM2 startup:
pm2 startup - Test health endpoint:
curl https://your-domain.com/api/health - Test metrics endpoint:
curl https://your-domain.com/api/metrics - Verify static assets load (check DevTools Network tab)
- Test login functionality
- Monitor logs:
pm2 logs sveltycms
Post-Deployment
- Monitor for 24 hours
- Check error logs:
tail -f /var/log/nginx/sveltycms.error.log - Verify cache hit rates
- Test automatic session rotation
- Verify rate limiting works
- Run load tests
- Test backup script
- Document any custom configurations
Expected Performance Improvements
| Metric | Before Optimization | After Optimization | Improvement |
|---|---|---|---|
| Static asset latency | 15-20ms | <1ms | 95% faster |
| API response (cached) | 50ms | 5-10ms | 80-90% faster |
| Memory usage (per worker) | 500MB | 250-350MB | 30-50% reduction |
| Concurrent connections | 1,000 | 5,000+ | 5x capacity |
| CPU usage (static assets) | 20-30% | 0-2% | 90%+ reduction |
| Malicious requests blocked | Node.js level | Nginx level | 80-90% early rejection |
| Session cache hit rate | 75% | 85-90% | 10-15% improvement |
Troubleshooting
Application Won’t Start
# Check PM2 logs
pm2 logs sveltycms --lines 100
# Check application port
sudo netstat -tlnp | grep 3000
# Test application directly
NODE_ENV=production node build/index.js
Static Assets Not Loading
# Verify Nginx serves static files
curl -I https://your-domain.com/_app/version.json
# Check file permissions
ls -la /var/www/sveltycms/build/client/_app/
# Verify Nginx root path
sudo nginx -T | grep root
High Memory Usage
# Check PM2 memory per process
pm2 list
# Reduce max_memory_restart in ecosystem.config.js
# Reduce number of instances
pm2 scale sveltycms 2 # Run only 2 instances
Redis Connection Errors
# Test Redis connection
redis-cli -a your_password ping
# Check Redis logs
sudo tail -f /var/log/redis/redis-server.log
# Restart Redis
sudo systemctl restart redis-server
Nginx 502 Bad Gateway
# Check if Node.js is running
pm2 status
# Check Nginx error logs
sudo tail -f /var/log/nginx/sveltycms.error.log
# Verify upstream connection
curl http://127.0.0.1:3000/api/health
Related Documentation
- Server Hooks Architecture - Middleware system
- Cache System - Caching strategies
- Security Plugin - Security implementation
- Database Methods - Database optimization
Summary
This production deployment guide covers:
✅ Nginx - Reverse proxy with static asset optimization and rate limiting ✅ Redis - Distributed caching configuration ✅ PM2 - Cluster mode for multi-core utilization ✅ Security - TLS, firewall, Fail2Ban, and early threat blocking ✅ Monitoring - Health checks, metrics, and log analysis ✅ Optimization - Database indexes, connection pooling, caching ✅ Backups - Automated backup strategy ✅ Performance - 5x capacity increase, 95% faster static assets
Follow this guide to achieve enterprise-grade performance, security, and reliability for your SveltyCMS production deployment.