← All Tutorials
FrameworksFeb 17, 20268 min read

Deploy a Node.js Express API

Deploy a Node.js Express API with PM2 process management, Nginx reverse proxy, and SSL.

Introduction

Express.js remains the most widely used Node.js web framework, now fully supporting ES modules and async middleware in its latest release. This tutorial covers building an Express API, managing it with PM2 for zero-downtime restarts, configuring Nginx as a reverse proxy, and securing it with SSL on Rackline.

Prerequisites

  • A Rackline account with an active droplet
  • Node.js 22 LTS installed locally

Step 1 — Create the Express Application

Initialize a new Node.js project with ES modules enabled and install Express. We will structure the project with a src directory for clean separation of concerns.

bash
mkdir my-express-api && cd my-express-api
npm init -y
npm install express cors helmet compression
npm install -D typescript @types/express @types/node tsx

Step 2 — Write the Server Code

Create a production-ready Express server with security middleware, CORS configuration, and health check endpoints. Helmet sets security headers, and compression reduces response sizes.

typescript
// src/server.ts
import express from "express";
import cors from "cors";
import helmet from "helmet";
import compression from "compression";

const app = express();
const port = process.env.PORT || 3000;

app.use(helmet());
app.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(",") }));
app.use(compression());
app.use(express.json());

app.get("/health", (_req, res) => {
  res.json({ status: "ok", uptime: process.uptime() });
});

app.get("/api/v1/items", (_req, res) => {
  res.json({ items: [], total: 0 });
});

app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});

Step 3 — Configure PM2 for Process Management

PM2 keeps your application running, automatically restarts it on crashes, and enables zero-downtime deployments with cluster mode. Create an ecosystem file to define your process configuration.

javascript
// ecosystem.config.cjs
module.exports = {
  apps: [{
    name: "my-express-api",
    script: "dist/server.js",
    instances: "max",
    exec_mode: "cluster",
    env_production: {
      NODE_ENV: "production",
      PORT: 3000,
    },
    max_memory_restart: "500M",
    log_date_format: "YYYY-MM-DD HH:mm:ss Z",
  }],
};

Pro Tip

Use instances: 'max' to spawn one process per CPU core. For a 4-vCPU droplet this means 4 processes, fully utilizing available resources.

Step 4 — Deploy with Nginx Reverse Proxy

Deploy to Rackline and configure Nginx as a reverse proxy. Rackline auto-configures Nginx when it detects a Node.js project, forwarding traffic from port 80/443 to your application port.

bash
# Initialize and deploy
rackline init --framework nodejs
rackline deploy --environment production

# Rackline generates this Nginx config automatically:
# server {
#   listen 443 ssl;
#   server_name yourdomain.com;
#   location / {
#     proxy_pass http://localhost:3000;
#     proxy_set_header Host $host;
#     proxy_set_header X-Real-IP $remote_addr;
#   }
# }

Step 5 — Enable SSL

Rackline provisions a free SSL certificate from Let's Encrypt automatically when you add a custom domain. The certificate renews automatically 30 days before expiration.

bash
# Add domain and enable SSL
rackline domains add api.example.com --project my-express-api
rackline domains verify api.example.com

# SSL is provisioned automatically
# Check certificate status
rackline domains ssl-status api.example.com

Conclusion

Your Express API is now running on Rackline with PM2 cluster mode, Nginx reverse proxy, and automatic SSL. The setup handles process crashes gracefully and distributes load across all available CPU cores. Next, consider adding a PostgreSQL database for persistent storage.