Apply secure HTTP headers, an explicit CORS allowlist, proxy-aware rate limiting, small request limits, and production-safe Express settings.
What you will build
This tutorial produces a working, verifiable result rather than a command list. Read each command before running it, keep configuration in version control without secrets, and record the versions used for repeatable deployment.
1. Prepare the project
npm install express@5 helmet cors express-rate-limit
export ALLOWED_ORIGIN='https://app.example.com'
Run preparation commands as an unprivileged application user unless a command explicitly requires sudo. A clean working tree and lockfile make rollback much easier.
2. Implement the solution
import express from 'express'; import helmet from 'helmet'; import cors from 'cors'; import {rateLimit} from 'express-rate-limit';
const app=express(); app.disable('x-powered-by'); app.set('trust proxy',1);
app.use(helmet()); app.use(cors({origin:process.env.ALLOWED_ORIGIN,methods:['GET','POST'],credentials:true,maxAge:600}));
app.use(rateLimit({windowMs:60_000,limit:100,standardHeaders:'draft-8',legacyHeaders:false}));
app.use(express.json({limit:'100kb',strict:true}));
app.get('/api/status',(req,res)=>res.json({status:'ok'})); app.listen(3000);
Save the example in the filename indicated by its comment or surrounding instructions. Treat it as a minimal baseline: production applications should separate transport, business logic, persistence, and configuration into testable modules.
3. Verify end to end
node server.js
curl -i -H 'Origin: https://app.example.com' http://127.0.0.1:3000/api/status
curl -i -H 'Origin: https://evil.example' http://127.0.0.1:3000/api/status
Verification should cover both process state and a real request or data operation. A process that is merely running is not necessarily ready to serve traffic.
4. Troubleshooting and production notes
CORS is a browser rule, not API authentication. Configure trust proxy to match the actual proxy hops or clients can share/spoof rate-limit identities. Use a shared rate-limit store across replicas and tune Content-Security-Policy for applications that serve HTML.
Production checklist
- The supported Node.js LTS version and dependency lockfile are recorded.
- Configuration is validated at startup and secrets are stored outside source control.
- Input limits, authentication, authorization, timeouts, and error boundaries are explicit.
- Logs identify a request without exposing credentials or personal data.
- Health checks, graceful termination, resource limits, backup, and rollback have been tested.
Reference: official topic documentation. For production version selection, use a supported LTS line from the Node.js release schedule.