%{DOCUMENT_ROOT} variable inside If statement in Apache 2.4 - apache

in Apache 2.4.6 (the up-to-date version from CentOS 7 repository) I am trying to pass all the PHP files for processing to a specially compiled PHP-FPM in case that "php7.enable" file is present in the root of the website.
If I try this:
<If "-f %{DOCUMENT_ROOT} . '/php7.enable'">
RewriteEngine On
RewriteRule "^/(.*\.php(/.*)?)$" "fcgi://127.0.0.1:9000/%{DOCUMENT_ROOT}/$1" [P]
</If>
the condition works, but the %{DOCUMENT_ROOT} on the RewriteRule line is not expanded to the variable value, but is everytime empty. Strange is, that outside the "If" block, the expansion works.
Does anybody have any idea why and how to make it work ?
Thanks.

I've found a workaround which is the solution of my problem:
<FilesMatch "\.php$">
Require all granted
<If "-f '%{DOCUMENT_ROOT}/php7.enable'">
SetHandler proxy:fcgi://127.0.0.1:9001
</If>
</FilesMatch>
so I don't need the DOCUMENT_ROOT value at all and it works perfectly.
If I put "php7.enable" file to the DOCUMENT_ROOT of the website, all PHP files are being interpreted by PHP-FPM (running PHP7). If there's no such file found in the DOCUMENT_ROOT, the Apache handler is used to let the PHP interpret by (OS built-in) PHP5.
Thanks for all the ideas, it helped me to find a way to the root cause of the problem (with VirtualDocumentRoot in the config file the DOCUMENT_ROOT is probably not filled-in correctly).
It can be also seen in this question - Mass virtual hosting with Apache 2.4

Related

Apache .htaccess <FilesMatch> // Setting as forbidden subfolder files

I'm going mad over Apache .htaccess
I'm trying to setting as protected my subfolders using relative address, but it seems impossible.
The path of Apache folder is structured like this:
/var/www/apachedir
now I want to protect
/var/www/apachedir/subfolder/*
What I tryied is putting in /var/www/apachedir/ an .htaccess file like this
<FilesMatch "subfolder\/.*">
Order Allow,Deny
Deny from all
</FilesMatch>
but it seems not woking good.
I don't want to use ModRewrite and I want to make this .htaccess reusable.
So, listen, if I put the site over an other server that has a direcory structure like /var/www/zzz it has to protect files in /var/www/zzz/subfolder/*.
Also the file .htaccess has to stay in the root folder /var/www/apachedir.
There's a way to do it?
Edit:
I don't want to use ModRewrite but also I don't want to use Redirectmatch.
I want to know if there's a way to set it up with FilesMatch without ModRewrite or Redirectmatch.
I don't want to use ModRewrite.
You can use RedirectMatch to block access to a known path:
Redirectmatch 403 ^/subfolder/
I want to know if there's a way to set it up with FilesMatch
No, because the FilesMatch (and the non-regex Files) directive(s) literally match against files only, not directories. eg. <Files "*.jpg"> matches all .jpg files in any subdirectory.
There are various methods to block access to that subdirectory...
Use a <Directory> section in the server config
If you have access to the server (virtual host) config then you can use the <Directory> (and <DirectoryMatch>) directive(s) to target specific directories. But this is not permitted in .htaccess. For example:
<Directory "/var/www/apachedir/subfolder">
Require all denied
</Directory>
Create an additional .htaccess file in that subdirectory
The equivalent userland .htaccess way of doing this is to create an additional .htaccess file in that subdirectory (ie. at /subfolder/.htaccess) with a single Require all denied directive. The .htaccess file itself is equivalent to the <Directory> directive in the server config.
Aside: Order, Deny and Allow are Apache 2.2 directives and formerly deprecated on Apache 2.4 (which you are far more likely to be using). You should be using the equivalent Require (mod_authz_core) directives instead, as used above.
Use Redirect 403 (mod_alias) - not a "redirect"
I don't want to use ModRewrite but also I don't want to use Redirectmatch
RedirectMatch (and Redirect) are part of mod_alias - this is a base module and compiled into Apache by default (unlike mod_rewrite), so using the prefix-matching Redirect directive (no need for the regex variant RedirectMatch) is a reasonable solution as #anubhava suggests in his answer, depending on the scenario and existing directives. For example:
Redirect 403 /subfolder/
Despite the use of the Redirect directive, this is not an external (HTTP) redirect. The 403 response is served via an internal subrequest.
Set an environment variable and check with mod_authz_....
Alternatively, you can set an environment variable when the /subfolder is requested (using SetEnvIf) and check for this using the Require directive. This allows you to keep the condition separate from the directives that actually permit access. For example (using Apache 2.4 mod_authz_core):
SetEnvIf Request_URI "^/subfolder/" BLOCK_ACCESS
<RequireAll>
Require all granted
Require not env BLOCK_ACCESS
</RequireAll>
NB: If you are doing any URL-rewriting with mod_rewrite then you might need to check for REDIRECT_BLOCK_ACCESS instead in the above Require directive.
<If> expression (Apache 2.4)
On Apache 2.4 you can also use an <If> expression to target that specific subfolder with a containing mod_authz_core directive. For example:
<If "%{REQUEST_URI} =~ m#^/subfolder/#">
Require all denied
</If>
Although, strictly speaking, these methods target the URL-path, not the file-path.

Meaning of apache2 CONTEXT_DOCUMENT_ROOT and CONTEXT_PREFIX?

How are the Apache2 (2.4) CGI environment variables CONTEXT_DOCUMENT_ROOT and CONTEXT_PREFIX defined?
From experimentation, I've determined the following:
CONTEXT_DOCUMENT_ROOT appears to be the full local path to the original request when DirectoryIndex or ErrorDocument call a CGI script.
CONTEXT_PREFIX appears to be the original REQUEST_URI, sans any query part, when DirectoryIndex or ErrorDocument have called a CGI script. (In these cases, REQUEST_URI is set to the URI of the CGI script, rather than the original.)
However, I can't seem to find any official documentation from Apache on these variables. Does anyone here have a link to such documentation, or more authoritative knowledge to share?
CONTEXT_PREFIX and CONTEXT_DOCUMENT_ROOT tell you how apache used an Alias directive (or similar feature - like mod_userdir) to translate the URL path to the file system path. The file system path will end up pointing to the the file to be served or a cgi script to run.
So, if apache translates the URL:
http://host/_CONTEXT_PREFIX/path/file
to the file system path:
/_CONTEXT_DOCUMENT_ROOT/path/file
it implies there is an Alias (or ScriptAlias or similar mechanism such as mod_userdir) like the following:
Alias /_CONTEXT_PREFIX /_CONTEXT_DOCUMENT_ROOT
The Alias directive saves /_CONTENT_PREFIX in ${CONTEXT_PREFIX} and /_CONTEXT_DOCUMENT_ROOT is saved in ${CONTEXT_DOCUMENT_ROOT}.
Here is one example of using it. In a <Directory> context RewriteRule translates a path name relative to the directory to a absolute URL path, or an absolute file name (which must exist). So if you wanted to translate URL's that ended in .htm to .php, you would have to write it like this:
<Directory "/_CONTEXT_DOCMENT_ROOT">
<FilesMatch "*.htm">
RewriteEngine On
RewriteRule (.*)[.]html$ /_CONTEXT_DOCUMENT_ROOT/$1.php
</FilesMatch>
</Directory>
Now you can write it without repeating /_CONTEXT_DOCUMENT_ROOT, but perhaps more importantly the file does not have to exist because we are rewriting it to a URL path:
<Directory "/_CONTEXT_DOCMENT_ROOT">
<FilesMatch *.htm>
RewriteEngine On
RewriteRule (.*)[.].* ${CONTEXT_PREFIX}/$1.php
</FilesMatch>
</Directory>

mod_rewrite doesnt work if file with same name as argument exists

I'm experiencing some issues with mod_rewrite in htaccess.
Let's for instance say I request example.com/foo/, it works perfectly if I don't have a file starting with "foo.*" in the root directory.
Let's say I have news.php, sitemape.xml, style.css in root, I can't use /news/ or /sitemap/ or /style/ , it will give a 404 like /news.php/ etc.
Here's my rewrite string. It works locally with my Apache 2.2.22 but not at my web-host with the same Apache version.
RewriteRule ^([A-Za-z0-9]+)/?$ index.php?category=$1 [NC,L]
Anyone has a clue?
This sounds like Multiviews rearing its ugly head when its not wanted. It may be that your host automatically turns on the Multiviews option by default, and mod_negotiation then tries to "guess" what the request is for, and if it's close enough (like with /news/ and /news.php), it will automatically serve it, and disregard whatever mod_rewrite rules you may have.
Try turning off multiviews. You can do this in your htaccess file using the Options directive (assuming your host has allowed Options):
Options -Multiviews

Apache and Rewrite Module

I created a file .htaccess in the /var/www directory. The rights are "root root --wxrwxrwxr".
The content of the file is:
Options +FollowSymlinks
RewriteEngine on
RewriteLogLevel 3
RewriteLog "/var/log/apache2/rewrite.log"
RewriteRule ^(.*?)$ testphp.php
When I call the page phpinfo.php, I've got: Loaded Modules ... mod_rewrite ...
Therefore, the modules is loaded.
After each modification, I restared the server manually with sudo /etc/init.d/apache2 restart.
The error.log gives
Apache/2.2.14 (Ubuntu) PHP/5.3.2-1ubuntu4.2 with Suhosin-Patch configured -- resuming normal operations
When I call a page anyone.htm or anyone.php, the rewrite.log does contain nothing and the real page is called. If I understand, the page anyone.php should be replaced by testphp.php
Did I make siomething wrong?
Thanks
If i were a web server, i'd ignore any config file that was world writable, for stability and security's sakes. I know there's places in Apache that do exactly that; i forget whether .htaccess processing is one of those places, but i'd assume/hope it is.
Thanks for your help
Here is what I made to get the Apache2 server running with the Rewrite Rule:
I re-installed the server from a new hard disk
I activated the Rewrite with 'sudo a2enmod rewrite'
I created the file '.htaccess' with the rules:
RewriteEngine On
RewriteRules ^(.*)$ test.php
In the "/etc/apache2/sites-available/default", I added in the directory/
AllowOverride all
Order deny,allow
Allow from all
and in the directory "/var/www", the same 2 lines. I don't know why, but the rules RewriteLog n does not word in the .htaccess. In the "/var/www", I created 2 files, index.html (the default) and test.php. The test.php contains
<?php phpinfo(); ?>
When I call the page index.html, the php info is displayed
One more time, thanks.

Strange behavior change in mod_rewrite

In a .htaccess context, I have a simple rewriting rule :
RewriteEngine on
RewriteRule ^dir/([^/]+)/(.*) action/do.php?a=$1&b=$2 [L,QSA]
dir and action are in the same directory, which is also my DocumentRoot.
When accessing http://example.org/dir/a/b the request should (and was) rewritten to http://example.org/action/do.php?a=a&b=b without redirection or anything visible.
However since I upgraded from Apache 1.3 + mod_php to Apache 2.2 (mpm_worker) + PHP FastCGI (don't know how it's related, but it seems to be), the precedent rule returns a 404 error :
The requested URL /var/www/action/do.php was not found on this server.
The DocumentRoot is now inserted in the request ! The file /var/www/var/www/action/do.php obviously doesn't exist.
As a workaround, I changed the rule : (added a / at the beginning of the second part)
RewriteEngine on
RewriteRule ^dir/([^/]+)/(.*) /action/do.php?a=$1&b=$2 [L,QSA]
And it works (because fortunately in this case, I'm in the DocumentRoot directory).
Do you know what caused this behavior change ? Did you notice the same thing ?
Ok, I found what happened.
Actually, I was not in my DocumentRoot but in a VirtualDocumentRoot thanks to mod_vhost_alias.
The issue does not happen when using "real" virtual hosts.