Day 5 of 5
⏱ ~60 minutes
Express.js in 5 Days — Day 5

Deploy to Production

Environment variables, CORS, rate limiting, and deploying to Railway with a MongoDB Atlas connection.

Production Hardening

Terminal
npm install cors helmet express-rate-limit
server.js — production middleware
const cors = require('cors');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');

// Security headers
app.use(helmet());

// CORS
app.use(cors({
  origin: process.env.ALLOWED_ORIGINS?.split(',') || '*',
  credentials: true,
}));

// Rate limiting
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,  // 15 minutes
  max: 100,                   // 100 requests per window
  message: { error: 'Too many requests' }
});
app.use('/api/', limiter);

// Auth rate limiter (stricter)
const authLimiter = rateLimit({ windowMs: 60*60*1000, max: 10 });
app.use('/api/auth/', authLimiter);
.env.example
PORT=3000
MONGODB_URI=mongodb+srv://...
JWT_SECRET=change-me-to-random-string
ALLOWED_ORIGINS=https://yourfrontend.com
Deploy to Railway
# railway.app → New Project → Deploy from GitHub
# Add environment variables in the Railway dashboard
# Railway auto-detects Node and runs: npm start

# package.json
"scripts": {
  "start": "node server.js",
  "dev": "nodemon server.js"
}
📝 Day 5 Exercise
Deploy Your Express API
  1. A
  2. d
  3. d
  4. h
  5. e
  6. l
  7. m
  8. e
  9. t
  10. ,
  11. C
  12. O
  13. R
  14. S
  15. ,
  16. a
  17. n
  18. d
  19. r
  20. a
  21. t
  22. e
  23. l
  24. i
  25. m
  26. i
  27. t
  28. i
  29. n
  30. g
  31. .
  32. S
  33. e
  34. t
  35. e
  36. n
  37. v
  38. i
  39. r
  40. o
  41. n
  42. m
  43. e
  44. n
  45. t
  46. v
  47. a
  48. r
  49. i
  50. a
  51. b
  52. l
  53. e
  54. s
  55. p
  56. r
  57. o
  58. p
  59. e
  60. r
  61. l
  62. y
  63. .
  64. P
  65. u
  66. s
  67. h
  68. t
  69. o
  70. G
  71. i
  72. t
  73. H
  74. u
  75. b
  76. a
  77. n
  78. d
  79. d
  80. e
  81. p
  82. l
  83. o
  84. y
  85. t
  86. o
  87. R
  88. a
  89. i
  90. l
  91. w
  92. a
  93. y
  94. .
  95. C
  96. o
  97. n
  98. n
  99. e
  100. c
  101. t
  102. y
  103. o
  104. u
  105. r
  106. M
  107. o
  108. n
  109. g
  110. o
  111. D
  112. B
  113. A
  114. t
  115. l
  116. a
  117. s
  118. d
  119. a
  120. t
  121. a
  122. b
  123. a
  124. s
  125. e
  126. .

Day 5 Summary

  • helmet() sets security headers with one line — always include it in production.
  • CORS: restrict origin to your actual frontend domain in production. Don't leave it as '*'.
  • Rate limiting prevents brute-force attacks on auth endpoints. Auth routes get stricter limits.
  • Never commit .env. Use .env.example as a template with placeholder values.
Finished this lesson?