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
Edit: 'On' need to be uppercase in current apache version
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>
Thank you! This worked for me.
I am pasting my config if you are serving multiple sites (virtualhost) and also SSL certificates (SSL was made with certbot), with redirect http to https
This setting works on Linode / Ubuntu
yoursite.com-le-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>
# Admin email, Server Name (domain name), and any aliases
ServerAdmin webmaster#yoursite.com
ServerName yoursite.com
ServerAlias www.yoursite.com
# Index file and Document Root (where the public files are located)
DirectoryIndex index.html index.php
DocumentRoot /var/www/html/yoursite.com/public_html
<Directory "/var/www/html/yoursite.com/public_html">
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>
# Log file locations
LogLevel warn
ErrorLog /var/www/html/yoursite.com/log/error.log
CustomLog /var/www/html/yoursite.com/log/access.log combined
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/yoursite.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/yoursite.com/privkey.pem
</VirtualHost>
</IfModule>
This is what we use at work for our production react app which is using BrowserRouter from react-router:
httpd.conf
<VirtualHost *:3000>
DocumentRoot "/var/www/html"
<Directory /var/www/html/>
Header set Cache-Control "no-cache"
# https://stackoverflow.com/a/34154531/2089675
FallbackResource /index.html
</Directory>
<Directory /var/www/html/static/>
# https://create-react-app.dev/docs/production-build/#static-file-caching
Header set Cache-Control "public, max-age=31536000"
# https://stackoverflow.com/a/54943214/5600537
RequestHeader edit "If-None-Match" '^"((.*)-gzip)"$' '"$1", "$2"'
</Directory>
</VirtualHost>
As you can see most of the comments in there are answers from SO, so I'm just giving back :)
configuration
Place the above file in /usr/local/apache2/conf/httpd.conf.
The config also assumes that you have put the contents of the build folder inside /var/www/html/. If you've placed them elsewhere, then adjust the path accordingly.
ports
The VirtualHost *:3000 part is just for exposing the server's port in the docker container (httpd:buster) used to run it. This is also the same port CRA defaults to in dev. An external proxy is used to manage where the application can be accessed from.
compression
Finally, if you are interested in serving gzipped files you may want to remove the RequestHeader edit line, and then do some more work to make sure .gz files can be served:
ex.
AddOutputFilterByType DEFLATE text/html application/javascript
React routing issue fixed on ubantu server
Solution:
Open the file using the console.
If you are using SSL
nano /etc/apache2/sites-available/000-default-le-ssl.conf
Add the following lines
===================================================================================
DocumentRoot /var/www/project
<Directory "/var/www/project">
RewriteEngine on
RewriteCond %{HTTP_ACCEPT} text/html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [last]
RewriteRule ^ - [last]
AllowOverride None
Options FollowSymLinks Multiviews
Require all granted
Solution:
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
If you've multiple virtual host then follow these steps
Goto to that VH and open the .htaccess file
add these lines and save it
restart the apache service again so that it can reflect into the settings
Go on this directory
/etc/apache2/sites-available
open File : 000-default.conf
Change its permission : 777
Paste code on bottom of file
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]
Restart server
The Idea: I want to make it that anything that comes after the domain name and ends with .html is treated as a get variable by index.php
Example: www.test.ro/1/2/3.html should actually be www.test.ro/index.php?var=1/2/3.html.
www.test.ro is setup as a virtual host for development, and AllowOverride has value All.
The .htaccess file seems to be processed, but not all the time. If I write a non-recognized rule like 'BizzareRule', the server works without returning a code 500 error.
If I put correct rules between <IfModule mod_rewrite.c></IfModule>, I get an 500 error, even though I have other vhosts using the same conditions and working perfectly.
Here are the contents of my vhost:
<VirtualHost *:80>
ServerAdmin eu#localhost.com
ServerName www.test.ro
ServerAlias test.ro
DocumentRoot D:/Projects/grabsite/test.ro
Options Indexes FollowSymLinks MultiViews
DirectoryIndex index.php index.html
LogLevel warn
ErrorLog D:/Projects/grabsite/test.ro/error.log
CustomLog D:/Projects/grabsite/test.ro/access.log combined
<Directory "D:/Projects/grabsite/test.ro">
Options -Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
And test content for .htaccess:
RewriteEngine On
RewriteRule ^/?([^/]*)\.html$ /index.php?seo=$1 [L]
It seems that you enters in infinite loop. Try first to simplify the rule:
RewriteRule ^(.*)\.html$ /index.php?seo=$1 [L]
Or just
RewriteRule ^index.html$ /index.php?seo=$1 [L]
Next, it's best to have RewriteCond -f and RewriteCond -d in order not to execute the rule if you are requesting existing file/folder. In some situations, this can prevent an infinite loop in the rule
The problem is in regex pattern. You said: "The .htaccess file seems to be processed, but not all the time".
If you check your pattern^/?([^/]*)\.html$ you will see that this will work for files in root folder ONLY (e.g. /index.html).
Solution: change pattern to ^(.+)\.html$ and all will be fine -- now it will match ANY URL that ends with .html (e.g. /index.html as well as /hello/pink-kitten.html etc).
I am not an apache guru. But I want to configure my server for mass virtual hosting using CakePHP. The idea is that we will be able to easily set up multiple versions of the same application based on directory location:
production.domain.com
testv1.domain.com
etc...
So I know I have mod_vhost_alias working just fine. I have a basic directory set up where I have added a test index.html file (/var/www/htdocs/cake/test/webroot). When I point my browser to the location (test.domain.com), the index.html is displayed in the browser. My vhost is configured to pull %1 from the URL to know what directory to point to:
VirtualDocumentRoot /var/www/htdocs/cake/%1/webroot
But when I point my browser to the cake application, I get a page not found error. I suspect it has something to do with the mod_rewrite in the .htaccess file. Here are the full configs for both:
mod_vhost_alias (in .conf file)
<VirtualHost *:80>
ServerAlias *
UseCanonicalName Off
VirtualDocumentRoot /var/www/htdocs/cake/%1/webroot
<Directory /var/www/htdocs/cake/%1/webroot>
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
.htaccess (in webroot - default as it comes from CakePHP)
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>
Any ideas how to get them to work together?
Turns out all it needed was:
DirectoryIndex index.html index.php
I just started learning Zend. I managed to get the basic working (using zf create project) in my local web server. Let's just say my project is called square
The only .htaccess that I have: square/public/.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
httpd.conf
DocumentRoot "/home/amree/web"
<Directory />
Options FollowSymLinks
AllowOverride All
Order deny,allow
Deny from all
</Directory>
<Directory "/home/amree/web">
Options Indexes FollowSymLinks
AllowOverride all
Order allow,deny
Allow from all
</Directory>
NameVirtualHost square
<VirtualHost square>
DocumentRoot "/home/amree/web/square/public"
ServerName square
</VirtualHost>
hosts
127.0.0.1 square
I'm running my application on Linux.
From what I've gathered, I can open (loaded without any problems) the site using:
http://square/
http://square/default/index/index
http://192.168.1.10/square/public/
http://192.168.1.10/square/public/default/index/index
But I can't open it using:
http://square/square/public (An error occurred message from Zend)
http://192.168.1.10/square/ (got a directory listing)
I also have other web applications in the same web server. For example, the meh application can be opened using http://192.168.1.10/meh/ but cannot be opened using http://square/meh
My question is, how can I load my Zend application without getting problems to other applications in the same server? At the moment, I prefer accessing it using my local IP (192.168.1.10). It should be possible to open it from another computer in the same network.
So, in the end I should be able to load the Zend project using
http://192.168.1.10/square
http://192.168.1.10/square/public
http://192.168.1.10/square/public/default/index/index
And I can also open my other meh application using http://192.168.1.10/meh
Thanks in advance.
You can't indeed access your application using
http://square/square/public
Using the square domain will match your vhost and /square/public will be rewritten to Zend, whom will try to run Square_PublicController::indexAction()
http://192.168.1.10/square/ (got a directory listing)
you got a directoy listing (allowed by Options Indexes in <Directory "/home/amree/web">) because your .htaccess is located in http://192.168.1.10/square/public
You have to make a choice between:
http://192.168.1.10/square
http://192.168.1.10/square/public
Or maybe try an Alias in Apache
Alias /square /square/public
I am building a web application with Zend Framework, and I need to point my app to the "public" folder of the application:
So basically when I call http://localhost/myapp
it should display http://localhost/myapp/public/
I created a virtual host file called myapp into /etc/apache2/sites-available/:
<VirtualHost *:80>
DocumentRoot /var/www/myapp/public/
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/www/myapp/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
</VirtualHost>
But it doesn't work. When I call http://localhost/myapp, it displays the directory structure of the app, and when I click on the "public" folder, then it displays what I want to be displayed by default...
I never configured vhosts before and that's as far as I got with the tutorials about it.
In your first listing, you had a different value for the Directory tag, leaving off 'public' altogether. There was also a trailing slash after 'public' in the DocRoot value, but removed on your second attempt. Not sure that made a difference, but I believe it's recommended that you don't include trailing slashes.
Also, just wondering...are you running this on a local machine? I had trouble with Skype wanting to use port 80 if I started running that before my apache server. Skype will use a different port if 80 is already used. If not Skype, there may be another app that's using port 80 and interfering. That could be why you had success on another port.
Ok I found a way somehow... I don't think it's necessary the right/best way but...
in httpd.conf (in apache2 folder):
Listen 10089
<VirtualHost *:10089>
DocumentRoot "/var/www/myapp/public"
<Directory "/var/www/myapp/public">
Order allow,deny
Allow from all
AllowOverride all
</Directory>
</VirtualHost>
My app is now accessible via localhost:10089
After enabling the rewrite mod in apache, I added the necessary .htaccess, one at the root of my app, redirecting everything to index.php (Zend framework support friendly url navigation and works that way):
RewriteEngine on
RewriteRule .* index.php
and a second .htaccess file inside my public folder to allow people to access .jpg,.ico,etc files and not being redirected to index for everything:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ /index.php [NC,L]
Hope this will help some!