How to setup apache server for React route?
I have my react app running great on my local dev server but it did not work when I dump my production ready files straight into Apache's htdocs directory:
Here is what I have:
/var/www/index.html
/var/www/bundle.js
and I have
DocumentRoot /var/www
in /etc/apache2/sites-available/000-default.conf
The fact is that
1). when I access http://...com/ that routed me to Login page
2). After I clicked a link
<Link to="main"><button>Log In</button></Link>
the content in the browser location field become:
http://...com/main
3). Now if I reload this url (http://...com/main), I got
The requested URL /main was not found on this server
My rounting in React:
<Router history={browserHistory }>
<Route path="/" component={TopContainer}>
<IndexRoute component={Login} />
<Route path='main' component={MainContainer} />
</Route>
</Router>
What else I am missing in the apache configuration?
thanks
Change the VirtualHost configuration (typically found in /etc/httpd/conf.d\vhosts.conf
) by adding the following Rewrite* lines:
<VirtualHost *:8080>
ServerName example.com
DocumentRoot /var/www/httpd/example.com
<Directory "/var/www/httpd/example.com">
...
RewriteEngine on
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.html [L]
</Directory>
</VirtualHost>
This tells Apache to serve any files that exist, but if they don't exist, just serve /index.html
rather than a 404: not found
.
Apache Reference: Configuring Apache Virtual Hosts
react-router
History Reference: Configuring Your Server
Complete answer gratefully stolen from here
The above solution works for Ubuntu as well but I have struggled a bit with it so here are the steps necessary to make it work.
Location of the file where you need to place the above mentioned configuration is under
/etc/apache2/sites-enabled
default is
/etc/apache2/sites-enabled/000-default.conf
Then you need to make sure that RewriteEngine is running (otherwise you will get an error when restarting Apache server).
sudo a2enmod rewrite
Finally, restart Apache server
sudo /etc/init.d/apache2 restart
Now, it should work.
When you are using default configuration (root of the website is under /var/www/html
), then all you need to do is to place
<Directory "/var/www/html">
RewriteEngine on
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.html [L]
</Directory>
to the above mentioned file under <VirtualHost ...>
If you have to use .htaccess and a sub directory then following works for me.
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
What worked for me, echoing many of the answers and comments here:
sudo a2enmod rewrite
- Open up
/etc/apache2/apache2.conf
- Paste in this with the path to your root:
<Directory "/var/www/PATH_TO_YOUR_ROOT">
RewriteEngine on
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.html [L]
</Directory>
sudo service apache2 restart
Pasting into the site-specific conf file did not work as earlier answers suggested.
None of the solutions posted so far appear to address the issue where missing ressources incorrectly return 200 instead of 404, which can make debugging when certain files are missing rather annoying.
My solution is to instead watch what type of resource the request expects to recieve, since browsers will ask for HTML when navigating to a page (Firefox asks for text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
) but not when accessing resources after the initial load (JS files imported via <script>
or as ES6 modules ask for */*
, CSS files ask for text/css,*/*;q=0.1
, accessing JSON via the fetch()
API will specify application/json, text/plain, */*
and so on). By relying on that assumption, one can configure Apache to serve the Single page app when trying to access a non-existent file (such as a route that only works within the Single-page app) without also sending it whenever said SPA asks for a CSS file that has been renamed or a missing JSON file.
EDIT: MDN has a list of common values for the Accept header.
<Directory "/var/www/httpd/example.com">
RewriteEngine on
# Browsers will specifically ask for HTML (among other things) on initial page load
# That is, if the *user* tries to access a *nonexisting* URL, the app is loaded instead
# but if a webpage attempts to load a missing resource it will return 404.
# (You can still go to /myreactapp/favicon.ico, but a missing /myreactapp/favicon.png resource won't return 200)
# if (HTTP_ACCESS.contains('text/html') && file_not_exists(REQUEST_FILENAME))
RewriteCond %{HTTP_ACCEPT} text/html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [last]
# Any ressources loaded by index.html should behave correctly (i.e: Return 404 if missing)
RewriteRule ^ - [last]
AllowOverride None
Options FollowSymLinks Multiviews
Require all granted
</Directory>