setEnvIf and RewriteCond doesn't catch it - apache

I'm setting this in my vhost in Apache 2.4
SetEnvIf X-Forwarded-Proto https HTTPS=on
And in my .htaccess I add this rule :
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
but I get an infinit loop since my RewriteCond doesn't see the value of HTTPS.
I do a phpinfo(INFO_VARIABLES); and I get $_SERVER['HTTPS'] on
I had debug in my errorLog to get this RewriteCond: input='off' pattern='off' => matched
As you see the RewriteCond doesn't see the value I set.
I read some doc as
The SetEnv directive runs late during request processing meaning that
directives such as SetEnvIf and RewriteCond will not see the variables
set with it.
or this link : http://www.onlinesmartketer.com/2010/05/27/apache-environment-variables-visibility-with-setenv-setenvif-and-rewriterule-directives/#Summary
And what I did is supposed to work.
What's wrong ?
Thanks ;)

Related

Redirect https://www.website.com to https://website.com not working

I make following post on redirection of https://www.website.com to https://website.com :
Issue with Let's Encrypt certificate : https://www.website.com not working with redirection to https://website.com
I can't get to achieve this redirection and I don't understand what is the reason.
If I type https://www.website.com, it remains on https://www.website.com and doesn't perform the redirection to https://website.com.
My config is a little special with a Zope server working with Apache2.
For the moment, here below are my rewrite rules (http://www.website.com and http//website.com are both redirected fine to https://website.com) :
<VirtualHost *:443>
# REWRITE to get https://www.website.com to https://website.com except for cgi-bin scripts
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/cgi-bin/search [NC]
RewriteCond %{REQUEST_URI} !^/cgi-bin/awstats [NC]
RewriteRule ^/(.*) https://localhost:8443/++vh++https:%{SERVER_NAME}:443/++/$1 [P,L]
</VirtualHost>
<VirtualHost *:80>
<IfModule mod_rewrite.c>
# www to non www for HTTP and HTTPS
RewriteCond %{REQUEST_URI} ^/www\. [NC,OR]
RewriteCond %{REQUEST_URI} !^/podcast [NC]
# Rewrite below works : redirect 80 => https
RewriteRule ^/(.*) https://website.com/$1 [R=301,L]
RewriteRule ^/(.*) http://localhost:9674/++vh++http:%{SERVER_NAME}:80/++/$1 [P,L]
</IfModule>
</VirtualHost>
What could be wrong here?
I believe there are few things of note:
One or more RewriteCond can precede a RewriteRule directive. The following rule is then only used if both the current state of the URI matches its pattern, and if these conditions are met.
The RewriteRule directive......can occur more than once, with each instance defining a single rewrite rule. The order in which these rules are defined is important - this is the order in which they will be applied at run-time.
In VirtualHost context, The Pattern will initially be matched against the part of the URL after the hostname and port, and before the query string (e.g. "/app1/index.html"). This is the (%-decoded) URL-path.
If you wish to match against the hostname, port, or query string, use a RewriteCond with the %{HTTP_HOST}, %{SERVER_PORT}, or %{QUERY_STRING} variables respectively.
You also make use of L|last flags, which makes the engine stop processing further rules after RewriteRule is run.
The above sorta gives you an idea how the engine runs your rewrites:
RewriteRules are processed sequentially (unless you specify L flag, which you do for all rules)
Each RewriteRule can have many RewriteCond which all must match before RewriteRule is considered. It also means that RewriteCond must be repeated for each RewriteRule individually (there's however an interesting technique to group RewriteRules into if-then-else blocks)
In your case (VirtualHost context), only the URL-paths are matched by default unless you manually match HTTP_HOST variable.
With this in mind, I see a few issues with your rewrite rules (I swapped http and https vhosts around for readability but it does not matter):
<VirtualHost *:80> <!-- your http:// requests will end up with this block, because 80 is the port for http -->
<IfModule mod_rewrite.c>
# www to non www for HTTP and HTTPS <!-- I believe HTTPS traffic is NOT handled by this vhost at all, it arrives straight to *:443 queue -->
RewriteCond %{REQUEST_URI} ^/www\. [NC,OR] <!-- you evaluate path component of your request uri to begin with "www." (i.e. /www.index.html) - this will obviously never match, you however have OR flag, which proceeds to the second condition -->
RewriteCond %{REQUEST_URI} !^/podcast [NC] <!-- you check if the path does not start with "/podcast" - this is easy to test - try http://www.website.com/podcast and see if you get redirected to HTTPS - I suspect you will not -->
# Rewrite below works : redirect 80 => https <!-- I suspect it works by accident, please test it out with http://www.website.com/podcast to confirm my theory -->
RewriteRule ^/(.*) https://website.com/$1 [R=301,L] <!-- we end up here, and regardless of the requested path we issue a 301 redirect to https version of the website. This is marked as Last rule, so the engine should stop processing here -->
RewriteRule ^/(.*) http://localhost:9674/++vh++http:%{SERVER_NAME}:80/++/$1 [P,L] <!-- this I believe kicks in when you request a "/podcast" path - this will proxy the request to your http://localhost:9674/ -->
</IfModule>
</VirtualHost>
<VirtualHost *:443><!-- this is where your 301 redirect will com after bouncing through first set of rules above -->
# REWRITE to get https://www.website.com to https://website.com except for cgi-bin scripts
RewriteEngine On <!-- this is important, keep it on -->
RewriteCond %{REQUEST_URI} !^/cgi-bin/search [NC] <!-- you check whether url path does not contain /cgi-bin/search -->
RewriteCond %{REQUEST_URI} !^/cgi-bin/awstats [NC]<!-- AND does not contain /cgi-bin/awstats-->
RewriteRule ^/(.*) https://localhost:8443/++vh++https:%{SERVER_NAME}:443/++/$1 [P,L]<!-- if both conditions above are met - proxy the request to backend and stop further processing. -->
</VirtualHost>
As far as I see - there's no rule to rewrite https://www.website.com -> https://website.com, the only bit your https rewrite is checking is /cgi-bin
My suggestion would be along the following lines (it's probably not a copy and paste solution, but hopefully you will have gotten the gist):
<VirtualHost *:443>
RewriteEngine On
# www to non www for HTTPS
<!-- checking for the same thing again -->
RewriteCond %{HTTP_HOST} ^www\.(.+) [NC]
RewriteRule ^/(.*) https://website.com/$1 [R=301,L] <!-- some people might argue second redirect here is excessive since you already arrived at correct host, but I'd leave this for you to sort out -->
<!-- your /cgi-bin checks can be merged into one regex -->
RewriteCond %{REQUEST_URI} !^/cgi-bin/(search|awstats) [NC]
RewriteRule ^/(.*) https://localhost:8443/++vh++https:%{SERVER_NAME}:443/++/$1 [P,L]
</VirtualHost>
<VirtualHost *:80>
<IfModule mod_rewrite.c>
# www to non www for HTTP
<!-- if you want to keep your `/podcast` on http check it first -->
RewriteCond %{REQUEST_URI} !^/podcast [NC]
RewriteRule ^/(.*) http://localhost:9674/++vh++http:%{SERVER_NAME}:80/++/$1 [P,L]
<!-- everything else will get redirected to https -->
RewriteCond %{HTTP_HOST} ^www\.(.+) [NC]
RewriteRule ^/(.*) https://website.com/$1 [R=301,L]
</IfModule>
</VirtualHost>
I had the same problem, for only one website of many that were virtually hosted on a amazon lightsail bitnami implementation.
After commenting out the line
ServerName mywebsite.com:80
In the /opt/bitnami/apache2/conf/httpd.conf file the problem was sovled.

Stop virtualhost rewrite rules executing if a rule was matched in the global config

I have the following setup.
Apache running with a separate VirtualHost file for each site.
Each of these has their own set of rewrite rules, for http to https for example which is all running fine.
What we would like to happen is this, from the global config we need to be able to check if a request is for a particular subdirectory. If it is then we should allow this request to process as it should but at that point we do not want the individual virtual host file rewrite rules to kick in. Therefore allowing this directory to be served on non https connections and not be redirected to https.
I have set up the rewrite rules and can match on the directories and redirect to an external url if it matches from the global which shows its inheriting but if I try to just allow it through the virtual hosts rewrites kick in and it redirects.
I have tried using L and END but this did not work either.
Is there any way of achieving this without editing the virtual host files that are already configured?
Main httpd config entry
<Directory "/www">
Options Indexes Includes FollowSymLinks MultiViews
AllowOverride All
allow from all
Order allow,deny
Require all granted
RewriteEngine On
RewriteOptions InheritDownBefore
RewriteCond %{REQUEST_URI} ^/sub_directory/$ [NC]
RewriteRule ^(.*) $1 [L,END]
#RewriteRule ^(.*) - [L,END]
#RewriteRule ^(.*) http://www.google.com [L,END] # This does get triggered
</Directory>
sample virtual host file.
<VirtualHost *:80>
ServerName urlone.com
ServerAlias urltwo.com
DocumentRoot /www/
RewriteEngine On
# redirect to https
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*) https://urlone.com$1 [R=301,L]
</VirtualHost>
so if I visit urlone.com it should redirect to https://urlone.com but if I visit urlone.com/sub_directory it needs to not allow the redirect to https.
I hope this makes sense to someone and thanks in advance for any help.
In global httpd.conf:
RewriteEngine On
RewriteOptions InheritDownBefore
RewriteCond %{REQUEST_URI} ^/sub_directory$ [NC]
RewriteRule ^ - [E=PATH_MATCHED:true]
(if needed, you can add additional rules, or additional flags to the above rule)
In virtual_host.conf
RewriteCond %{ENV:PATH_MATCHED} !=true
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://urlone.com%{REQUEST_URI} [R=301,L]

RewriteCond QUERY_STRING or/and ProxyPass?

I have to forward requests from internet client like this one :
https://www.app.com/AppServer?User=guest&ID=8PKX3Q2DT45&Type=laptop&Cmd=exec
to internal server with changing some parameters :
https://192.168.0.1/AppServer?User=guest&ID=NEW_ID&Type=NEW_TYPE&Cmd=exec
with Apache web server. NEW_ID and NEW_TYPE are static variables.
I've tried differents things with ProxyPass and RewriteCond %{QUERY_STRING} but without success.
RewriteEngine On
RewriteCond %{QUERY_STRING} .*User=(\w+).*&ID=(\w+).*&Type=(\w+).*&Cmd=(\w+).*$ [NC]
RewriteRule . HOST/AppServer?User=$1&ID=NEW_ID&Type=NEW_TYPE&Cmd=Exec [R=301,L]
ProxyPass HOST/AppServer
ProxyPassReverse HOST/AppServer
(URL has been replaced with HOST because of post restriction)
Also, I should be able to change header with RequestHeader (this work properly).
Could you help me to build the configuration ?
Kindest regards,
I answer to my question, this work :
#NEW UA
RequestHeader set User-Agent "NEW_UA"
RewriteEngine On
RewriteCond %{QUERY_STRING} ^(.*)OLD_ID(.*)OLD_DEVICE(.*)$
RewriteRule (.*) HOST/AppServer/?%1NEW_ID%2NEW_DEVICE%3 [P,L]
ProxyPass / HOST/
ProxyPassReverse / HOST
Thanks,

Redirect URL in browser before Proxy Pass

I am trying to remove the trailing slash from all of my URLs and redirect.
I've accomplished this here:
<Directory /var/www/html/ >
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+[^/])/$ ${BaseUrl}/$1 [R=301,L]
</Directory>
However, I am also running a service locally and want to proxy to it visits /${ServiceRoot}.
ProxyPass /${ServiceRoot} http://localhost:${ServicePort}/
ProxyPassReverse /${ServiceRoot} http://localhost:${ServicePort}/
Each of these works fine individually. However, if I try to visit a URL like this: ${BaseUrl}/${ServiceRoot}/some/path/
The trailing slash is left on. I would like to force a redirect so the URL in the browser shows without the trailing slash.
Thanks in advance!
Just remove the L from the RewriteRule:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+[^/])/$ ${BaseUrl}/$1 [R=301]
That should apply the rule to your ProxyPass directive. Just remember to check DirectorySlash if you plan to support directory listings, it will try to redirect directories to / and then back in a loop.
You probably got something like this in your apache config:
ProxyRequests On
ProxyVia On
<Proxy *>
Order deny,allow
Allow from xx.xx.xx.xx
</Proxy>
Then you have to add the following in order to proxy-pass all requests to www.olddomain.com/foo to www.newdomain.com/bar
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.olddomain\.com$
RewriteRule /foo(.*)$ http://www.newdomain.com/bar/$1 [P,L]
What this does is:
When a request is made to host www.olddomain.com the RewriteRule will fire
This rule substitutes /foo to http://www.newdomain.com/bar/
The substitution is handed over to mod_proxy (P)
Stop rewriting (L)
Example result:
Browser is configured to use your apache as proxy server
It requests www.olddomain.com/foo/test.html
Your apache will rewrite this to www.newdomain.com/bar/test.html
It will request this page from the responsible webserver
Return the result to the browser as www.olddomain.com/foo/test.html

mod_rewrite rule to redirect all requests except for one specific path

I'm trying to redirect all requests to my domain to another domain using mod_rewrite in an Apache 2.2 VirtualHost declaration. There is one exception to this -- I'd like all requests to the /audio path not to be redirected.
I've written a RewriteCond and RewriteRule to do this but it's not quite right and I can't figure out why. The regular expression contains a negative lookahead for the string "/audio", but for some reason this isn't matching. Here's the definition:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(.*\.)?mydomain\.net(?!/audio) [NC]
RewriteRule ^(.*)$ http://www.newdomain.example [L,R=301]
If I change the RewriteCond to:
RewriteCond %{HTTP_HOST} ^(.*\.)?mydomain\.example/(?!audio) [NC]
(i.e. put the forward slash outside of the negative lookahead part) then it works, but the downside of this is that requests to mydomain.example without a trailing slash will not be redirected.
Can anyone point out what I'm doing wrong?
Here are the rules:
<VirtualHost *:80>
ServerAdmin me#mydomain.example
DocumentRoot "/var/www/mydomain.example/htdocs"
ServerName www.mydomain.example
ServerAlias mydomain.example
RewriteEngine on
RewriteCond {REQUEST_URI} !^/audio
RewriteRule ^(.*)$ http://www.newdomain.example [L,R=301]
RewriteLog logs/mod_rewrite_log
RewriteLogLevel 3
ErrorLog logs/error_log
CustomLog logs/access_log common
</VirtualHost>
Thanks #mercutio -- that makes perfect sense but it still doesn't seem to work.
Here's what the mod_rewrite log says when I make a request to http://mydomain.example/audio/something.mp3:
(2) init rewrite engine with requested uri /audio/something.mp3
(3) applying pattern '^(.*)$' to uri '/audio'
(2) rewrite '/audio' -> 'http://www.newdomain.example/'
(2) explicitly forcing redirect with http://www.newdomain.example
(1) escaping http://www.newdomain.example for redirect
(1) redirect to http://www.newdomain.example [REDIRECT/301]
Since the REQUEST_URI does start with /audio I would expect the RewriteRule to be ignored.
The HTTP_HOST only contains the host name, not the path of the URL requested.
RewriteCond %{REQUEST_URI} !^/audio
Should be all you need.
Further, you can get debug info from the rewrite engine with the following, which is really useful to see how your conditions and rules are being matched:
RewriteLog /path/to/log/file
RewriteLogLevel 3