Deployment

Website Rebuild with Express

Chapter 11 · Deployment

server.js is already a plain, standalone Node HTTP server — the identical situation Astro's own Node adapter produced in its Chapter 11. This chapter reuses that exact mechanism deliberately, rather than forcing a sixth distinct deployment story to exist for its own sake.

No Build Step at All

node server.js

Unlike every framework-based sibling in this series, there's nothing to compile, bundle, or transpile — server.js runs directly, exactly as written.

Secrets: One More Small Explicit Step

npm install dotenv
// server.js — must be the very first line require('dotenv').config();

A plain .env file — the same simplest secrets story as Next.js, Django, Laravel, and Astro, not Rails' own reversed encrypted-commit approach. Even loading it needs one more explicit step here: dotenv is a separate package, where several sibling frameworks bundle some form of .env loading by convention.

Keeping the Process Alive: PM2, Reused Unchanged

pm2 start server.js --name website-express pm2 save pm2 startup

Apache's mod_proxy_http, Reused Unchanged

# Apache VirtualHost — the site's own already-running Apache <VirtualHost *:443> ServerName osztromok.com ProxyPreserveHost On ProxyPass / http://127.0.0.1:3000/ ProxyPassReverse / http://127.0.0.1:3000/ SSLEngine on SSLCertificateFile /etc/letsencrypt/live/osztromok.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/osztromok.com/privkey.pem </VirtualHost>
Honest reuse, not a forced sixth mechanism
Astro's own Chapter 11 used mod_proxy_http because its Node adapter produces a plain standalone HTTP server on a local port. Express's own server.js is exactly that same thing, with no framework layer in between. There's no genuine reason for a different Apache mechanism here — reusing the identical configuration is the honest answer, not a missed opportunity for a "sixth variant."

No Migration Tooling Either

A real, honest gap — schema.sql applied by hand
With no ORM, there's no drizzle-kit migrate equivalent. Chapter 2's own schema.sql is applied directly via the mysql CLI, and any future schema change would need to be written and applied the same way — by hand, with no tracked migration history. A real production project at this scale would likely want a lightweight migration runner; this course doesn't build one, the same honest-scope-note tradition every capstone in this series already follows.

Six Deployment Stories, Compared One Final Time

Next.jsDjangoLaravelRailsAstroExpress
App server processNode (PM2)gunicornPHP-FPMPassenger-embeddedNode adapter (PM2)Plain server.js (PM2)
Apache module usedN/AN/Amod_proxy_fcgimod_passengermod_proxy_httpmod_proxy_http — reused unchanged
Build step?YesNoYes (assets)NoYesNone at all
The most minimal deployment in the series, too
No build step, no framework-specific adapter, no bundler output to verify — node server.js is genuinely the entire production artifact. Consistent with every other chapter in this course: the least is provided by default, and the least ceremony is required to run it.

Hands-On Exercises

Exercise 1

Run the production server directly via node server.js, with no build step, and confirm it serves the full site correctly.

📄 View solution
Exercise 2

Configure PM2 to run the server, simulate a crash by killing the process directly, and confirm PM2 restarts it automatically.

📄 View solution
Exercise 3

Configure the Apache VirtualHost with mod_proxy_http reverse-proxying to the Node server, and confirm the site is reachable through Apache's own domain rather than the raw Node port directly.

📄 View solution

Chapter 11 Quick Reference

  • node server.js — the entire production artifact, no build step at all
  • dotenv — one more explicit package needed, even for the simplest possible secrets story
  • PM2 and mod_proxy_http — reused unchanged from Astro's own Chapter 11, the honest answer for the identical situation
  • No migration tooling — a real, named gap; schema.sql applied by hand
  • Next chapter: Capstone — A Complete, Working Flexible-Routing Site