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
Related
I'm trying to have two different directory associated to two different ports. (8001 and 8004), but whenever I try to access port 8004 in a browser, it redirects automatically to port 8001.
Here's some extract of the config files that seems relevant:
In httpd.conf:
Listen 80
Listen 8001
Listen 8004
Removed comment to line:
Include etc/apache24/extra/httpd-vhosts.conf
In file httpd-vhosts.conf:
<VirtualHost *:8001>
DocumentRoot "<path_to_site_1>"
<Directory "<path_to_site_1>">
Require all granted
</Directory>
<Directory "<path_to_site_1>">
AllowOverride All
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^ index.php [L]
</Directory>
</VirtualHost>
<VirtualHost *:8004>
DocumentRoot "path_to_site_2"
<Directory "path_to_site_2">
Require all granted
</Directory>
<Directory "path_to_site_2">
AllowOverride All
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^ index.php [L]
</Directory>
</VirtualHost>
Here's a list of things I've tried, that didn't change anything:
Having the VirtualHost declaration in httpd.conf
Changing the order of the Virtual host declaration
Changing port 8004 to another port
Clear the browser cache and try a different browser
If I comment Listen 8001, it breaks everything.
Port 80 seems to point to the default www directory of this FreeBSD installation and still works properly, for phpMyAdmin is installed there and is still accessible.
Maybe of note, it's a FreeBSD installation running on Oracle VM VirtualBox.
Thank you for any help or ideas to follow.
Unfortunately, in this case, the comportment wasn't due to Apache configuration but to the website installations. One was a WordPress installation and the other was a Drupal installation. I wasn't aware that by moving those website in the directory structure, they would no longer point at the right place. WordPress was doing the redirection.
The issue was solved with two different solution, one for each platform.
For WordPress:
In the file functions.php, located in the theme directory:
Add the following lines:
update_option( 'siteurl', '<new_url>' );
update_option( 'home', '<new_url>' );
In the browser, fefresh the website a few time
Remove both lines from the file
For Drupal:
(using drush) In the directory where the website is located:
drush cache-rebuild
The combination of both commands solved the issue with both installation.
I'm trying to setup Kirby locally using MAMP. My MAMP setup I have it so I can point run multiple sites as virtual hosts. I use this code:
NameVirtualHost *
<VirtualHost *>
DocumentRoot "/Applications/MAMP/htdocs"
ServerName localhost
</VirtualHost>
<VirtualHost *>
DocumentRoot "/Users/oscargodson/Dropbox/projects/icarus"
ServerName dev.icarus
</VirtualHost>
When I go to dev.icarus the initial page loads totally fine. All the CSS, images, everything. Once I try to go to a subpage, including the panel, I get the 404. I know for sure the htaccess file is in the folder. I tried using the git install and the manual zip install. I also made sure in in my httpd.conf file I have rewrite turned on
LoadModule rewrite_module modules/mod_rewrite.so
I'm not sure what else to look up. Googling just kept returning results for htaccess file being missing.
EDIT
Here's the htaccess file per request. It is the default one that works if I keep my project inside of the htdocs directory in MAMP. I tried uncommenting the RewriteBase and making it just / (a total guess) but that didn't help at all.
# Kirby .htaccess
# rewrite rules
<IfModule mod_rewrite.c>
# enable awesome urls. i.e.:
# http://yourdomain.com/about-us/team
RewriteEngine on
# make sure to set the RewriteBase correctly
# if you are running the site in a subfolder.
# Otherwise links or the entire site will break.
#
# If your homepage is http://yourdomain.com/mysite
# Set the RewriteBase to:
#
# RewriteBase /
# block text files in the content folder from being accessed directly
RewriteRule ^content/(.*)\.(txt|md|mdown)$ index.php [L]
# block all files in the site folder from being accessed directly
RewriteRule ^site/(.*) index.php [L]
# block all files in the kirby folder from being accessed directly
RewriteRule ^kirby/(.*) index.php [L]
# make panel links work
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^panel/(.*) panel/index.php [L]
# make site links work
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*) index.php [L]
</IfModule>
# Additional recommended values
# Remove comments for those you want to use.
#
# AddDefaultCharset UTF-8
#
# php_flag short_open_tag on
Mike Rockett in the comments pointed me in the right direction. In the httpd.conf file I had to change
<Directory />
Options Indexes FollowSymLinks
AllowOverride None
</Directory>
to
<Directory />
Options Indexes FollowSymLinks
AllowOverride All
</Directory>
Then I restarted MAMP and it worked!
I'm using Apache 2.4, and I set up two virtual directories. One requires SSL, and the other one redirects to it.
If a user attempts to visit https://www.derp.com/derp without /derp existing, they correctly get a 404. But when a user visits http://www.derp.com/derp, Apache incorrectly redirects the user to https://www.derp.comderp, removing the slash between the path and the domain name.
I have no idea what would be causing this.
The following is the setup of my Virtual Host.
<VirtualHost *:443>
ServerAdmin derp#derp.com
ServerName www.derp.com
ServerAlias derp.com
DocumentRoot "C:\Users\derp\Documents\Web Projects\derp"
SSLEngine on
SSLCertificateFile "C:\Apache24\certs\cert.cer"
SSLCertificateKeyFile "C:\Apache24\certs\key.key"
</VirtualHost>
<VirtualHost *:80>
ServerAdmin derp#derp.com
ServerName www.derp.com
ServerAlias derp.com
Redirect permanent / https://www.derp.com/
</VirtualHost>
<Directory "C:\Users\derp\Documents\Web Projects\derp">
Options Indexes FollowSymLinks Includes ExecCGI
AllowOverride All
Require all granted
SSLRequireSSL
</Directory>
Why would Apache be behaving this way?
Bonus Question: Should redirects be handled in my virtual host definition, or should it be handled in the .htaccess file in the web site's physical directory?
Edit:
I'm starting a Laravel project, and by default the public folder does contain a .htaccess file, so here's that guy:
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
Edit Two:
I tried:
adding a slash at the end of the DirectoryRoot path
replacing the backslashes with forward slashes in the DirectoryRoot path
replacing the backslashes with double backslashes in the DirectoryRoot path
I also removed the .htaccess file from the directory completely.
It redirects correctly when you go from http://www.derp.com to https://www.derp.com. It's just when you specify a path and attempt https that it removes the slash between the domain and the path.
Edit Three:
I also attempted the following suggestion:
Redirect permanent / https://www.derp.com/
Try
RedirectMatch permanent /(.*) https://www.derp.com/$1
or
RedirectMatch permanent (.*) https://www.derp.com/$1
... and instead of redirecting to https://www.derp.comderp, it instead does not redirect, attempts and gives a 404 for http://www.derp.com/derp, but using Apache's 404, instead of throwing a Not Found Exception, as Laravel does without configuration.
Edit Four:
I have also tried:
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
In the .htaccess file and the behavior did not change at all.
I got it.
The issue did not lay with the rewriting at all, it was the SSLRequireSSL directive under my Directory definition that was causing the problem.
I simply removed this directive, refreshed the cache in all of my browsers, and the site then continued to work correctly. This was discovered through the process of elimination.
The documentation notes:
This directive forbids access unless HTTP over SSL (i.e. HTTPS) is enabled for the current connection. This is very handy inside the SSL-enabled virtual host or directories for defending against configuration errors that expose stuff that should be protected. When this directive is present all requests are denied which are not using SSL.
The emphasis is my own. SSLRequireSSL may have Apache only return a 403 or 404 if HTTP over SSL is not enabled, interfering with the Redirect rule. A rewrite rule such as the one in this answer on Server Fault may be a better alternative depending on your use case:
RewriteEngine On
RewriteCond %{SERVER_PORT} !443
RewriteRule ^(/(.*))?$ https://%{HTTP_HOST}/$1 [R=301,L]
My issue was related to browser caching.
I tried it in a different browser and it worked and then tried again in a private session in the first browser and it also worked.
I'm having trouble setting up my httpd.conf or .htaccess files to recognize multiple zend framework sites on one server.
For development, I have just one server and I'm trying to setup the sites so I can access them like localhost/app1, localhost/app2, etc.
So right now, when I go to localhost/app1 it does successfully redirect to localhost/app1/public/index.php, however when I go to localhost/app1/index/index I get a 404.
Here is my vhosts file:
<VirtualHost *:80>
ServerAdmin webmaster#localhost
DocumentRoot "/var/www"
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory "/var/www/app1/public">
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
ErrorLog logs/error.log
CustomLog logs/access.log common
</VirtualHost>
and here is my .htaccess file from the /var/www/app1 directory:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ /app1/public/index.php [NC,R,L]
If I change the DocumentRoot line in the vhosts file to DocumentRoot "/var/www/app1/public" then app1 does work correctly, but I can only access that one... at http://localhost. Is this possible? What I want to happen is if /var/www is the document root, then if I go to localhost/app1, those requests need to redirect to localhost/app1/public/index.php and if I go to localhost/app2 those requests need to redirect to localhost/app2/public/index.php.
I hope I explained this clearly, any help is appreciated.
In the end
I liked Phil's solution best because I didn't want to have to change my local hosts file and use the ServerName directive. It would be fine in a production environment if you own a separate domain name for each app, but not for development.
In addition to that, I was having a 403 forbidden problem when using an alternate directory for serving up web content. As I stated, the perms seemed correct the problem was with SE_Linux, and the security context of the files not being set to httpd_sys_content_t. I'm posting that solution that i found here, as it deals specifically with the issue. Thanks.
Here's what I'd do...
Install your applications somewhere arbitrary but outside the document root, eg /home/sudol/apps/app1 and /home/sudol/apps/app2. Make sure your Apache user can traverse this path and read the files.
Alias the public directories in your <VirtualHost> section
Alias /app1 /home/sudol/apps/app1/public
Alias /app2 /home/sudol/apps/app2/public
Setup your access and rewrite rules in the appropriate <Directory> sections (one for each app), eg
<Directory "/home/sudol/apps/app1/public">
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
RewriteEngine On
RewriteBase /app1
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
</Directory>
Delete the .htaccess files as you will no longer need them
Addendum
Make sure you set unique session names in your application config. You can also set specific cookie paths but this is optional, eg
; app1/application/configs/application.ini
resources.session.name = "app1"
resources.session.cookie_path = "/app1/"
; app2/application/configs/application.ini
resources.session.name = "app2"
resources.session.cookie_path = "/app2/"
Its better to use subdomain i.e app1.localhost then localhost/app1 . Since the way cookies are stored (including session cookie) can give you problem latter . They will mismatch or can even overlap .
Here is a good tutorial to setup the preferred way
http://www.dennisplucinik.com/blog/2007/08/16/setting-up-multiple-virtual-hosts-in-wamp/
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