Wiring a Static Frontend to a Render Backend
A walk-through of splitting an Express app into a static frontend (Hostinger) and a JSON API (Render) without breaking auth.
You can host a static frontend almost anywhere for free, but once you want users to log in and do real things, the backend needs a place to run too. Render's free tier is convenient but spins down after 15 minutes of idle. The pattern that handles both well: static frontend on Hostinger (or Vercel), API on Render, and a tiny bit of glue.
The pieces
customputing.com— static HTML on Hostinger. Loads instantly, no cold-start ever.api.customputing.com— the Node backend on Render. Cold-starts when nobody's used it for a while.- A shared session cookie scoped to
.customputing.comso signing in on the API also "signs in" the frontend.
The gotchas
A few things change once you cross origins:
- Cookies need
SameSite=None; Secureto be sent on cross-origin requests. The browser also won't send them at all without that flag over HTTPS. - CORS needs
Access-Control-Allow-Credentials: trueand an explicit origin (you can't use*with credentials). - CSRF protection has to switch from the synchronizer-token pattern (which assumes the server renders the form) to the double-submit-cookie pattern.
The cold-start fix
The frontend pings /api/health on every page load. By the time the
user actually clicks "Sign in," Render is awake. It costs almost
nothing on the API side — /api/health doesn't touch the database.
fetch('https://api.customputing.com/api/health', { credentials: 'omit' })
.catch(() => { /* fine if it fails; the click will wake it */ });
If you want even less cold-start risk, point an uptime monitor at
/api/health every 14 minutes. The service never sleeps.
That's the shape of it. The actual code lives in this site's repository.