惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hugging Face - Blog
Hugging Face - Blog
Vercel News
Vercel News
C
Check Point Blog
G
Google Developers Blog
博客园 - 司徒正美
量子位
Engineering at Meta
Engineering at Meta
S
SegmentFault 最新的问题
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
A
About on SuperTechFans
美团技术团队
D
DataBreaches.Net
Stack Overflow Blog
Stack Overflow Blog
Jina AI
Jina AI
Y
Y Combinator Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Apple Machine Learning Research
Apple Machine Learning Research
J
Java Code Geeks
MongoDB | Blog
MongoDB | Blog
人人都是产品经理
人人都是产品经理
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The Cloudflare Blog
U
Unit 42

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Deploying a Node.js App to Production: The 2026 Guide
Alex Chen · 2026-05-16 · via DEV Community

Alex Chen

Deploying a Node.js App to Production: The 2026 Guide

From local development to live server. The complete deployment checklist.

Pre-Deployment Checklist

// 1. Environment variables
const requiredEnvs = ['DATABASE_URL', 'JWT_SECRET', 'PORT'];
for (const env of requiredEnvs) {
  if (!process.env[env]) {
    console.error(`Missing: ${env}`);
    process.exit(1);
  }
}

// 2. Health check endpoint
app.get('/health', (req, res) => {
  res.json({
    status: 'ok',
    uptime: process.uptime(),
    memory: process.memoryUsage(),
    timestamp: new Date().toISOString(),
    environment: process.env.NODE_ENV,
  });
});

// 3. Graceful shutdown
process.on('SIGTERM', gracefulShutdown);
process.on('SIGINT', gracefulShutdown);

let isShuttingDown = false;

function gracefulShutdown(signal) {
  if (isShuttingDown) return;
  isShuttingDown = true;

  console.log(`\n${signal} received. Shutting down gracefully...`);

  // Stop accepting new connections
  server.close(() => {
    console.log('HTTP server closed');
    process.exit(0);
  });

  // Force exit after 10 seconds
  setTimeout(() => {
    console.error('Forced shutdown');
    process.exit(1);
  }, 10000);
}

Enter fullscreen mode Exit fullscreen mode

PM2 Process Manager

# Install globally
npm install -g pm2

# Start your app
pm2 start server.js --name "my-app"

# Useful commands
pm2 list              # List all apps
pm2 logs my-app       # View logs
pm2 monit             # Monitor dashboard
pm2 restart my-app    # Restart
pm2 stop my-app       # Stop
pm2 delete my-app     # Remove

# Auto-restart on crash
pm2 start server.js --name "my-app" --max-memory-restart 500M

# Cluster mode (utilize all CPU cores)
pm2 start server.js -i max --name "my-app-cluster"

# Startup script (survives reboot)
pm2 startup          # Generates command to run as sudo
pm2 save             # Save current process list

Enter fullscreen mode Exit fullscreen mode

Nginx Reverse Proxy

# /etc/nginx/sites-available/my-app
upstream my_app {
    server 127.0.0.1:3000;
    keepalive 64;
}

server {
    listen 80;
    server_name example.com www.example.com;

    # Redirect HTTP → HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    # SSL certificates (Let's Encrypt)
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # Proxy to Node.js app
    location / {
        proxy_pass http://my_app;
        proxy_http_version 1.1;
        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;

        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;

        # Buffer settings for large responses
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
    }

    # Static files (serve directly, don't pass to Node)
    location /static/ {
        alias /var/www/my-app/public/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml image/svg+xml;
}

Enter fullscreen mode Exit fullscreen mode

Systemd Service (Alternative to PM2)

# /etc/systemd/system/my-app.service
[Unit]
Description=My Node.js Application
After=network.target

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/my-app
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=10
Environment=NODE_ENV=production
EnvironmentFile=/var/www/my-app/.env.production

# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadOnlyPaths=/usr /bin

[Install]
WantedBy=multi-user.target

Enter fullscreen mode Exit fullscreen mode

# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable my-app
sudo systemctl start my-app

# Commands
sudo systemctl status my-app
sudo systemctl restart my-app
sudo journalctl -u my-app -f   # Follow logs

Enter fullscreen mode Exit fullscreen mode

Let's Encrypt SSL

# Install certbot
sudo apt install certbot python3-certbot-nginx

# Get certificate (auto-configures Nginx!)
sudo certbot --nginx -d example.com -d www.example.com

# Auto-renewal (certbot sets this up automatically)
sudo certbot renew --dry-run    # Test renewal
sudo systemctl status certbot.timer  # Check auto-renew timer

Enter fullscreen mode Exit fullscreen mode

Monitoring & Logging

// Structured logging with pino (fast!)
import pino from 'pino';

const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  transport: {
    target: 'pino-pretty', // Pretty-print in dev
    options: { colorize: true }
  },
});

logger.info({ userId: 123 }, 'User logged in');
logger.error({ err: error }, 'Database query failed');

// Request logging middleware
app.use((req, res, next) => {
  const start = Date.now();
  res.on('finish', () => {
    logger.info(
      { method: req.method, url: req.url, statusCode: res.statusCode, duration: Date.now() - start },
      'Request completed'
    );
  });
  next();
});

Enter fullscreen mode Exit fullscreen mode

Deployment Script

#!/bin/bash
# deploy.sh — One-command deployment

set -e  # Exit on any error

echo "🚀 Starting deployment..."

APP_DIR="/var/www/my-app"
GIT_REPO="git@github.com:user/my-app.git"
BRANCH="main"

# 1. Pull latest code
cd $APP_DIR
git fetch origin
git reset --hard origin/$BRANCH

# 2. Install dependencies
npm ci --production  # Faster than npm install, uses package-lock.json

# 3. Build assets (if needed)
npm run build

# 4. Run migrations (if applicable)
npx prisma migrate deploy

# 5. Restart application
if command -v pm2 &> /dev/null; then
  pm2 restart my-app
else
  sudo systemctl restart my-app
fi

# 6. Verify health
sleep 3
if curl -sf http://localhost:3000/health > /dev/null; then
  echo "✅ Deployment successful!"
else
  echo "❌ Health check failed! Check logs."
  exit 1
fi

Enter fullscreen mode Exit fullscreen mode

Quick Reference

Task Tool Command
Process manager PM2 pm2 start server.js
Or use systemd systemctl start my-app
Reverse proxy Nginx Config in sites-available
SSL Certbot certbot --nginx
Logs PM2/journalctl pm2 logs / journalctl -u my-app
Restart PM2/systemd pm2 restart / systemctl restart
Zero-downtime PM2 reload pm2 reload my-app

What's your deployment setup? Do you use PM2, Docker, or something else?

Follow @armorbreak for more DevOps content.