Hosting ReactJS App as Static Site using Apache: Solving Client-Side 404 Issues
In this article I will explain the process of hosting a production-ready ReactJS app on CentOS as static site and then handling client-side routing which otherwise would result in 404 on direct load or page refresh.
When developing in ReactJS, running your app for testing is easy since you could use npm to run a quick dev-server and be done with it. Things get complicated when you need to host your ReactJs app for production. There are multiple ways to do that including serving directly with node using
serve -s build , to running as a part of other server-side apps e.g. using expressjs and using pm2 to continue serving. One of these methods is hosting your app as static site and then use client-side routing.
First thing to understand is the flow where, and how, a URL is interpreted. A simpler flow is, user sends a request for
http://example.com/about to the server, which would inspect the path of the URL, determine the page that user is requesting and then sends that page back.
With client-side routing in ReactJS, enabled by React-Router, things are not that simple. When user loads the site for the first time, the first request will always be to the server, and at this point, the client (browser) does not have any app code (JS) loaded yet until server returns a page containing required script tags to load React and React Router. Part 2 of this flow starts only when these scripts have loaded. In part 2, when the user clicks on the ‘about’ navigation link for example, the URL is changed locally only to
http://example.com/about (made possible by the History API), but no request to the server is made. Instead, React Router, on the client side, determines which React view to render and renders it. Assuming your ‘about’ page does not need to make any REST (API) calls, it's rendered already (and if you were looking into Network tab under Dev Console you would see no network calls for the page but only for the assets). This way, you have transitioned from site home-page to next page (‘about’ in this example) without any server request having fired further.
But now consider what happens if you copy the URL (
http://example.com/about) from address bar and share it with a friend. Your friend has not loaded your website yet so, no React Router is running on her machine yet. So, here browser will make a server request directly to
And this is where the problem starts. The same URLs which work fine on the client side, because React Router is doing the routing, fails on the server side since server does not understand them, as there isn’t really an ‘about’ html page (file) in your webroot, so you end up with
404errors for all such URLs when requested from the server. This same problem occurs when you refresh such a page rendered by React Router, in which case the browser makes a call to the URL in the address bar over network and gets a
Solving The Routing Problem
To solve the problem of server unable to find a file thus, it needs to be configured to serve a static file, mostly
index.html, in such cases.
This article explains the process when you are using Apache HTTP Server.
Step 1: Build your react app
Run the following command to generate a production build for your ReactJS app:
npm run build.
- Ensure to specify the hostname/path in
homepagee.g. “homepage”: “http://example.com/path", if you are hosting the app at a path instead of root.
Step 2: Copy Contents of
build folder to the above specified path on server
- At this stage you also need to configure your Apache to point to this folder as
VirtualHostfor this domain.
Step 3: Place
.htaccess file in the root of your app’s folder with the following contents
.htaccessfile is a distributed server configuration file which allows you to set server configurations for a specific directory.
- It will be executed by the Apache web server when a request is made from your app’s folder.
Know more about
.htaccess file here.
That’s it! Now Apache will handle the routes which would otherwise result in 404.