4wk_
4wk_

Reputation: 2743

Apache vhost: Alias and RewriteRule

I have one URL (domain), for multiple directories (project). And I have a very odd behaviour when putting a .htaccess in it.

VirtualHost:

<VirtualHost *:80>
    DocumentRoot /foo/bar/things
    ServerName sub.mywebsite.com
    Alias /pro /srv/www/new
</VirtualHost>

And it works perfectly. When I go on sub.mywebsite.com/ it hit the /foo/bar/things dir and the other way around.


Now, let's add a simple .htaccess in /srv/www/new :

RewriteEngine on
RewriteRule ^(.*)/$    php/file.php?text=$1   [L,QSA]

So when I go on sub.mywebsite.com/pro/hello/ the file called is supposed to be /srv/www/new/php/file.php with a GET arg. I double-checked, the rule is good.

Here is the end of the RewriteLogLevel 4:

192.168.123.123 - - [25/Apr/2018:19:28:11 +0200] [sub.mywebsite.com/sid#7f317dd08b8][rid#7f37eca9f78/initial] (1) 
[perdir /srv/www/new/] internal redirect with /srv/www/new/php/file.php [INTERNAL REDIRECT]

And an online htaccess checker confirm it: The new url is http://sub.mywebsite.com/php/file.php%3Ftext=testing

But I've got an apache 404 not found:

Not Found
The requested URL /srv/www/new/php/file.php was not found on this server.

And yes, ls -l /srv/www/new/php/file.php the file exists.

The VERY ODD part is this: in the apache error log, I've got:

[Wed Apr 25 19:45:30 2018] [error] [client 192.168.123.123] File does not exist: /foo/bar/things/srv

Questions:

  1. What the hell is that? Why the file in the error_log is not the same as the one displayed on my browser?
  2. Why apache can't load the right file /srv/www/new/php/file.php as the .htaccess ask it?

Feel free to ask me more data if needed. I want to understand!

NB: there is no .htaccess in /foo/bar/things ; I've tried a lot of things in my vhost, like adding a <directory>, etc.

Upvotes: 1

Views: 1346

Answers (2)

emaV
emaV

Reputation: 415

Update for Apache > 2.4.16

Since version 2.4.16 RewriteBase directive is not required when the request is mapped via Alias:

This directive is required when you use a relative path in a substitution in per-directory (htaccess) context unless any of the following conditions are true:

  • The original request, and the substitution, are underneath the [DocumentRoot](https://httpd.apache.org/docs/current/mod/core.html#documentroot) (as opposed to reachable by other means, such as [Alias](https://httpd.apache.org/docs/current/mod/mod_alias.html#alias)).
  • The filesystem path to the directory containing the [RewriteRule](https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule), suffixed by the relative substitution is also valid as a URL path on the server (this is rare).
  • In Apache HTTP Server 2.4.16 and later, this directive may be omitted when the request is mapped via [Alias](https://httpd.apache.org/docs/current/mod/mod_alias.html#alias) or [mod_userdir](https://httpd.apache.org/docs/current/mod/mod_userdir.html).

So basically you don't get any AH00128: File does not exist: errors anymore.

Worth noting that CentOS 7.x comes with Apache 2.4.6 with security patches: as for 2022/01/07 you get 2.4.6-97.2 that fixes CVE-2021-40438. So if you want to manage multiple alias you need to upgrade with a different package, but this is another story...

Upvotes: 1

Dusan Bajic
Dusan Bajic

Reputation: 10889

The answer to both of your questions is already shown on your screen and in your logs:

The requested URL /srv/www/new/php/file.php was not found on this server.

The requested URL.

AH00128: File does not exist: /foo/bar/things/srv/www/new/php/file.php

File does not exist.

So, apache is not trying to fetch the file file.php which is located in /srv/www/new/php/ folder on your filesystem. It is trying to open URL http://sub.mywebsite.com/srv/www/new/php/file.php, which explains both the browser error and the line in your error log, since for that URL it really should look into /foo/bar/things/srv/www/new/php/file.php.

From http://httpd.apache.org/docs/current/mod/mod_rewrite.html:

The rewrite engine may be used in .htaccess files and in sections, with some additional complexity.
(...)
See the RewriteBase directive for more information regarding what prefix will be added back to relative substitutions.
(...)
The RewriteBase directive specifies the URL prefix to be used for per-directory (htaccess) RewriteRule directives that substitute a relative path. This directive is required when you use a relative path in a substitution in per-directory (htaccess) context.
(...)
This misconfiguration would normally cause the server to look for an directory under the document root.

Solution: add RewriteBase "/pro" to your .htaccess

You can see the difference in Rewrite Log:

Without RewriteBase:

[perdir /srv/www/new/] rewrite 'hello/' -> 'php/file.php?text=hello'
[perdir /srv/www/new/] add per-dir prefix: php/file.php -> /srv/www/new/php/file.php
[perdir /srv/www/new/] internal redirect with /srv/www/new/php/file.php [INTERNAL REDIRECT]

With RewriteBase "/pro":

[perdir /srv/www/new/] rewrite 'hello/' -> 'php/file.php?text=hello'
[perdir /srv/www/new/] add per-dir prefix: php/file.php -> /srv/www/new/php/file.php
[perdir /srv/www/new/] trying to replace prefix /srv/www/new/ with /pro
strip matching prefix: /srv/www/new/php/file.php -> php/file.php
add subst prefix: php/file.php -> /pro/php/file.php
[perdir /srv/www/new/] internal redirect with /pro/php/file.php [INTERNAL REDIRECT]

Upvotes: 2

Related Questions