Node.js

How to host a React app (Vite or Create React App) with your own domain — and fix the refresh 404 (2026)

6 min read By Cloud Ninza

A React app is a folder of static files after the build — hosting it is easy once you know three things: what to upload, how routing works on refresh, and how environment variables really behave.

In short To host a React app, run npm run build to produce static files (dist/ for Vite, build/ for Create React App) and serve that folder from a web server with an SPA fallback, so every unknown path returns index.html and page refreshes do not show 404. On Cloud Ninza, choose a Node.js plan, pick the "Static build (React, Vue, Angular, Vite)" preset in App settings, connect your GitHub repository or upload the code, and point your domain; the build, the fallback and free HTTPS are handled for you.

What you are actually hosting

A React app runs in the visitor's browser. When you run npm run build, Vite (or Create React App) compiles your components into plain HTML, JavaScript and CSS files: dist/ for Vite, build/ for Create React App. Those files are all a server needs to deliver — there is no React running on the server, no database connection and nothing to keep "awake".

That has two consequences. First, hosting a React front end is cheap and fast, and a CDN can cache it all. Second, anything secret cannot live in it: every API key you put into a React build is visible to anyone who opens the browser's developer tools. Secrets belong in a back-end API (Node.js, Python, PHP or Java), which the React app calls.

Step 1: make a production build locally first

Before deploying anywhere, prove the build works on your own computer:

  • npm ci (or npm install) — install exactly the dependencies in package-lock.json.
  • npm run build — create the production files; fix any errors it reports.
  • npm run preview (Vite) or npx serve -s build (Create React App) — open the printed address and click through the app.
  • Commit package-lock.json, and never commit node_modules or the dist/build folder to Git.

Step 2: environment variables behave differently in React

This trips up almost everyone. In a React app, environment variables are read at build time and copied into the JavaScript files. Changing them on the server afterwards does nothing until you build again.

Only variables with the right prefix are exposed: VITE_ for Vite (read as import.meta.env.VITE_API_URL) and REACT_APP_ for Create React App (process.env.REACT_APP_API_URL). A variable without the prefix is silently undefined in the browser — the most common reason an app works locally and breaks in production. And again: these values are public. Put API base URLs and public keys here, never secret keys.

Step 3: the refresh 404 and how to fix it

Your app works when you click through it, but refreshing /dashboard or opening a shared link to /products/42 shows 404 Not Found. This happens because React Router handles those paths inside the browser; the server has no file called /dashboard, so it answers 404 before React ever loads.

The fix is an SPA fallback: the server must return index.html for every path that is not a real file, and let React Router take over. How you set it depends on the server:

  • A Node.js static server: serve -s dist (the -s flag means single-page app) or an Express catch-all route that sends index.html.
  • nginx: try_files $uri $uri/ /index.html; in the site's location block.
  • Apache: a rewrite rule in .htaccess that sends unknown paths to index.html.
  • No server control at all: switch to HashRouter (URLs like /#/dashboard) — it works anywhere but looks less clean and is worse for SEO.

Hosting a React app on Cloud Ninza, step by step

React apps run on the Node.js plans, which build the app on the server and serve it with the fallback already set:

  • Create an app → Node.js → choose a plan and enter your domain (or take a free cloudninza.in address to start).
  • In App settings, pick the preset "Static build (React, Vue, Angular, Vite)". It fills in install (npm ci), build (npm run build) and a start command that serves dist with SPA fallback on the app's own port. For Create React App, change dist to build in the start command.
  • Add your VITE_ or REACT_APP_ variables under environment variables before the first build.
  • Bring the code: connect GitHub on the Git page (every push to your branch builds and deploys automatically, with health check and automatic rollback), or upload a zip in the File Manager and press Deploy.
  • Point the domain with the A records from the Domains page; free HTTPS is issued automatically.

Plans for apps start at ₹199 a month billed yearly, and every plan includes free SSL and backups twice a day.

React with a back-end API

Most real apps have an API too: Express or NestJS, Django or FastAPI, Laravel, Spring Boot. Two common layouts work well. Put the API on its own subdomain (api.yourdomain.in) as a second app and call it from React with VITE_API_URL=https://api.yourdomain.in — remember to allow that origin in the API's CORS settings. Or serve the React build from the API itself (Express static files plus a catch-all), so both share one domain and you avoid CORS entirely. Either way, keep secrets and database credentials only on the API side.

Production checklist for React apps

A few details separate a demo from a site that feels fast and reliable:

  • Set the right base path: if the app lives in a subfolder, set base in vite.config.js (or homepage in package.json for CRA).
  • Cache wisely: built files have hashed names and can be cached for a year; index.html should not be cached, so new deploys show at once.
  • Check bundle size with the build output; lazy-load heavy routes with React.lazy.
  • Add a real 404 route inside React Router for paths that do not exist.
  • Add a page title and meta description per route if search traffic matters — or consider Next.js for server rendering.

Common errors after deploying React

A blank white page usually means the JavaScript files 404 because the base path is wrong — open the browser console and look at the failing URLs. "undefined" API URLs mean a variable is missing its VITE_/REACT_APP_ prefix or was added after the build. CORS errors mean the API does not allow your domain. An old version showing after a deploy is caching of index.html — hard-refresh once and check the cache headers. And 404 on refresh is the missing SPA fallback described above.

React, Next.js or plain static hosting?

A plain React (Vite) app is perfect for dashboards, admin panels, tools and apps behind a login, where search engines do not need to read each page. For marketing sites, blogs and shops that live on Google traffic, Next.js renders pages on the server and is usually the better choice — we have a separate Next.js hosting guide. If your site is just a few pages without interactivity, a static HTML site on a PHP plan is the simplest of all.

Key takeaways

The short version, for anyone skimming:

  • A React build is static files: dist/ for Vite, build/ for Create React App.
  • Environment variables are baked in at build time, need the VITE_ or REACT_APP_ prefix, and are public.
  • Fix 404 on refresh with an SPA fallback that returns index.html for unknown paths.
  • Keep secrets in a back-end API, never in the React build.
  • On Cloud Ninza, the "Static build" preset, Git deploys and automatic HTTPS do the hosting work for you.
Host it with us

Node.js Hosting from ₹2,388/year

Run Express APIs and Next.js apps on the Node.js version you choose, with environment variables, logs and a set RAM allowance. Node.js 18, 20, 22, 24 or 26 · From 256 MB app RAM · Your code from Git or a ZIP.

Ready when you are

Hosting from ₹99 a month on servers in India

WordPress, PHP, Node.js, Python and Java plans with free SSL and your choice of version. Create your account, pick a plan and pay by UPI, card or netbanking; your hosting is created automatically and you get your login by email, usually within minutes.

Questions

Questions on this topic

How do I host a React app with my own domain?

Build it with npm run build, serve the output folder with an SPA fallback, and point your domain's A records to the server. On Cloud Ninza the Static build preset does the serving for you.

Why does my React app show 404 when I refresh the page?

The server has no file for that path. Add an SPA fallback that returns index.html for unknown paths (serve -s, nginx try_files, or an Express catch-all).

Where is the build folder in Vite?

Vite builds into dist/. Create React App builds into build/.

Why are my environment variables undefined in production?

They need the VITE_ (Vite) or REACT_APP_ (CRA) prefix and must be set before the build runs, because they are baked into the files.

Can I put API keys in a React app?

Only public keys. Everything in a React build can be read in the browser, so secret keys belong on a back-end API.

Do I need Node.js on the server to host React?

Not to run React itself, but a Node.js plan lets the server build the app from Git and serve it with the right fallback automatically.

How do I deploy a React app from GitHub automatically?

Connect the repository on Cloud Ninza's Git page; each push to your branch installs, builds, health-checks and goes live, with automatic rollback if it fails.

Should I use React or Next.js for SEO?

For pages that must rank on Google, Next.js with server rendering is usually better. Plain React suits apps behind a login and dashboards.

Why is my React app a blank page after deployment?

Usually the JavaScript files 404 because of a wrong base path. Check the browser console and set base in vite.config.js.

How much does it cost to host a React app on Cloud Ninza?

Node.js plans start at ₹199 a month, billed yearly, with free SSL and twice-daily backups included.