apache - RewriteEngine doesn't work outside <VirtualHost> Directive - apache

I'm trying to configure apache to redirect the requests containing only hostname (domain) to another path.
I found the following directives useful, but as long as those are enclosed in VirtualHost, put in site_available folder (/etc/apache2/) and enabled as a separate site (with a2ensite command).
<VirtualHost *:80>
ServerName myserver:80
WSGIScriptAlias / /var/path/to/myproject/myproject.wsgi
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/?$
RewriteRule ^(.*)$ /path/path [R=301,L]
</VirtualHost>
Note that only Rewrite* directives don't work. The alias to my Python project works fine.
Morover, I found out that if I disable other virtual host(s) (000-default) with a2dissite command and put the directives mentioned above (without VirtualHost) to httpd.conf file everything (including the Rewrite* rules) work.
So, I am in doubt why I couldn't get this done in simple server config context, and what is the solution?

The reason why it appears that the Rewrite* directives do not work in the server configuration and need to be declared inside the VirtualHost is because (from the RewriteEngine documentation):
[...] rewrite configurations are not inherited by virtual hosts. This means that you need to have a RewriteEngine on directive for each virtual host in which you wish to use rewrite rules.
To change this behaviour, you can set RewriteOptions to something InheritDownBefore or similar. You then still need to have a RewriteEngine On on each VirtualHost but at least you won't need to copy the rewrite rules on each one.
So, taking your code example, this should work:
RewriteEngine On
RewriteOptions InheritDownBefore
RewriteCond %{REQUEST_URI} ^/?$
RewriteRule ^(.*)$ /path/path [R=301,L]
<VirtualHost *:80>
ServerName myserver:80
WSGIScriptAlias / /var/path/to/myproject/myproject.wsgi
RewriteEngine On
</VirtualHost>

Related

I'm trying to redirect /example to example.html in Apache's httpd.conf, but it doesn't work

Here's the code I'm trying to apply in httpd.conf:
<VirtualHost *:80>
ServerName www.test.com
ServerAlias www.test.com
DocumentRoot /home/test_com
ErrorLog /home/logs/apache/www_test/www.test.com-error_log
CustomLog /home/logs/apache/www_test/www.test.com.-access_log common env=!do_not_log
# https redirect
RewriteEngine On
RewriteCond %{HTTP_HOST} www.test.com
RewriteCond %{REQUEST_URI} /example
RewriteRule . https://www.test.com/example.html [R=303,L]
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}
<Directory "/home/test_com/">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</VirtualHost>
After applying the code and restarting apache, when I go to /example I get a 404 not found response.
When I test htaccess at (https://htaccess.madewithlove.be), the output is as https://www.test.com/example.html as I want. I wonder what the problem is.
RewriteCond %{HTTP_HOST} www.test.com
RewriteCond %{REQUEST_URI} /example
RewriteRule . https://www.test.com/example.html [R=303,L]
when I go to /example I get a 404 not found response.
Not sure if something has been lost in your exemplification, but from the rules as written, if you request /example it will result in a redirect-loop as it will continually redirect to /example.html again and again. (Unless you are actually making the request over HTTPS, in which case the directive isn't doing anything at all and you will indeed get a 404!)
This is because the second condition %{REQUEST_URI} /example also matches the target URL /example.html. You need to make the regex more specific and match only /example, not any URL that simply contains /example. This check can also be moved to the RewriteRule directive (the condition is not required). For example:
RewriteRule ^/example$ https://www.test.com/example.html [R=303,L]
The condition that checks the HTTP_HOST would not seem necessary, since these directives are in the vHost for www.test.com, so it cannot be any other hostname?
However, since this rule is in the vHost for port 80, it is only going to apply to HTTP requests (not HTTPS). If you are actually requesting https://www.test.com/example (ie. HTTPS) as would seem to be implied by your test results from the MWL tool, then the directive is never going to be processed and you will indeed get a 404.
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}
Your HTTP to HTTPS redirect is missing the last part so redirects everything to the homepage. The RewriteRule directive should read:
RewriteRule (.*) https://%{HTTP_HOST}$1 [R=301,L]
However, there's no point redirecting to HTTPS if all your directives are in the vHost:80 container.
This rule is also more complex than it needs to be. Since you are in the vHost:80 container, HTTPS is always going to be off - the check is redundant.
ServerName www.test.com
ServerAlias www.test.com
If you only have one hostname then you don't need two directives. Only the ServerName is required in this case.
When I test htaccess at (https://htaccess.madewithlove.be)
You don't have an .htaccess file here. You are using the directives directly in the vHost container, which is a different context. The directives behave slightly different here. For example, the RewriteRule pattern . (a single dot) has a different result here than when used in .htaccess. In a virtualhost context it is successful for every request, whereas in .htaccess it is successful for everything except the homepage (which is probably the intention here).
However, the MWL .htaccess tester only makes a "single" request (or single pass through the file). It does not "follow" redirects or make multiple passes through the file as it would do in a real server environment. So it cannot catch redirect/rewrite loops - which are a common cause of error.
The right part on RewriteRule is the destination file, try change :
RewriteCond %{REQUEST_URI} /example
To :
RewriteCond %{REQUEST_URI} /example.html

Apache httpd.conf - Link multiple domains to corresponding subfolders

I need a rule to internally rewrite several domains, with and without www:
www.a.com --> /m/n/o/
b.c.org --> /x/y/z/
The setup is Apache running locally on Windows (XAMPP). I've got the hosts file set up so all the domains point to localhost. I'd like every page to get redirected, i.e. I want to point each domain to it's own different root directory and have it work normally from there. e.g.
/ <-- Top level folder, everything is under here.
/root/of/domain/A/ <-- www.a.com
/root/of/domain/C/ <-- b.c.org
You have two choices.
(1) The one you asked (with mod_rewrite)
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(?:www\.)?a\.com$ [NC]
RewriteRule ^/(.*)$ /root/of/domain/A/$1 [L]
RewriteCond %{HTTP_HOST} ^b\.c\.org$ [NC]
RewriteRule ^/(.*)$ /root/of/domain/C/$1 [L]
</IfModule>
Note: don't forget to replace example values by real ones. Also, make sure mod_rewrite is enabled.
(2) the cleanest way: configure virtualhosts directly (without mod_rewrite)
NameVirtualHost *:80
<VirtualHost *:80>
DocumentRoot "X:/path/to/root/of/domain/A/"
ServerName a.com
ServerAlias www.a.com
</VirtualHost>
<VirtualHost *:80>
DocumentRoot "X:/path/to/root/of/domain/C/"
ServerName b.c.org
</VirtualHost>

Phabricator rewrite rules configuring issue

I'm having trouble installing phabricator. It actually seems like it would be a simple thing. I copied the example code exactly.
apache2.conf:
<VirtualHost *>
# Change this to the domain which points to your host.
ServerName localhost
# Change this to the path where you put 'phabricator' when you checked it
# out from GitHub when following the Installation Guide.
#
# Make sure you include "/webroot" at the end!
DocumentRoot /var/www/phabricator/webroot
RewriteEngine on
RewriteRule ^/rsrc/(.*) - [L,QSA]
RewriteRule ^/favicon.ico - [L,QSA]
RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA]
</VirtualHost>
<Directory "/var/www/phabricator/webroot">
Require all granted
</Directory>
Whenever I go to the server IP on a browser, it gives me this error:
Request parameter '__path__' is not set. Your rewrite rules are not configured correctly.
I found that this was part of the phabricator code:
if (!isset($_REQUEST['__path__'])) {
self::didFatal(
"Request parameter '__path__' is not set. Your rewrite rules ".
"are not configured correctly.");
}
Anyone have any idea how to get past this?
I had a similar issue with Phab and solved it with the following:
Place the Directory segment inside the VirtualHost segment.
Are you running any other Virtual Server in your system? If so, specify the port *:80 (Or try a different one Remember adding Listen 8081 before declaring the VirtualHost segment if you try another port)
And last replace the content of the Directory segment with this:
Order allow,deny
Allow from all
I was also facing same issue.
Just place
RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA]
and remove following line from your apache2.conf.
RewriteRule ^/rsrc/(.*) - [L,QSA]
RewriteRule ^/favicon.ico - [L,QSA]

Why is Apache Permanent Redirect removing the slash between the domain and the path?

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.

Dynamically configured virtual hosting

Helo!
I would like to prepare a dynamic virtual host for all subdomains that will be created in future using mod_rewrite. All subdomains would be configured prety much same way, so i thought of using dynamic VH configuration.
I want my document root for each subdomain to be /home/user/public_html/subdomainName.
I've tried with following configuration, but had no success:
<VirtualHost xxx.xxx.xxx.xxx:80>
# get the server name from the Host: header
UseCanonicalName Off
<Directory /home/user/public_html/>
# ExecCGI is needed here because we can't force
# CGI execution in the way that ScriptAlias does
Options FollowSymLinks ExecCGI
</Directory>
RewriteEngine On
# a ServerName derived from a Host: header may be any case at all
RewriteMap lowercase int:tolower
#rule that is suposed to set document root of virtual host!???
RewriteRule ^([a-z-]+)\.domain\.com/?(.*) /home/user/public_html/$1/$2
</VirtualHost>
The rule or somethinh seems to be wrong andit doesn't apply. I've never worked with dynamic VH before so i have no idea where i'm wrong...
This is a need a lot of people had before you. So there's an apache module which can do that for you mod_vhost_alias http://httpd.apache.org/docs/2.2/mod/mod_vhost_alias.html
Provides for dynamically configured
mass virtual hosting
instead of dynamic virtual hosts, you can also do this using wildcard dns which means configuring {anything}.yourdomain.tld to point to your server.
This will also get you same document root for each domain.
note that you will need to add ServerAlias *.yourdomain.tld to the virtual host entry
With RewriteRule you can't access the domainname. Also use RewriteCond for that part and use %1 etc. for backreference.
RewriteCond %{HTTP_HOST} ^([a-z-]+)\.domain\.com$ [NC]
RewriteRule (.*) %1/$1
The only problem is this will create a continues loop of prepending the subdomainname string. So what I normally do is create a separate folder for subdomains, like 'subdomains'
RewriteRule ^subdomains - [L]
RewriteCond %{HTTP_HOST} ^([a-z-]+)\.domain\.com$ [NC]
RewriteRule (.*) subdomains/%1/$1