customputing

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.com so signing in on the API also "signs in" the frontend.

The gotchas

A few things change once you cross origins:

  1. Cookies need SameSite=None; Secure to be sent on cross-origin requests. The browser also won't send them at all without that flag over HTTPS.
  2. CORS needs Access-Control-Allow-Credentials: true and an explicit origin (you can't use * with credentials).
  3. 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.