3

I'm trying to set a wildcard subdomain RewriteRule by combining some .htaccess rules I'd successfully implemented before, under the belief that I can use the same rules for my Apache vhosts file.

In essence, example.com and www.example.com go to the root path and look for index.php. All other (dynamic) subdomain requests at root level such as abc.example.com get rewritten (invisible to the browser) to example.com/process.php?p=abc.

Secondly, any requests for files from the subdomain outside of a base/root level need to be rewritten to be obtained from the root path of the standard domain without the subdomain. So abc.example.com/css/style.css needs to come from example.com/css/style.css

This is my attempt at doing so. I get an Apache error:

You don't have permission to access /index.php on this server.

for any subdomain attempt, other than www, which works as expected, as well as the standard example.com, which still works fine.

<VirtualHost *:80> ServerAdmin [email protected] ServerName example.com ServerAlias www.example.com DocumentRoot /var/www/example.com/public_html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> <VirtualHost *:80> ServerAdmin [email protected] ServerName other.example.com ServerAlias *.example.com DocumentRoot /var/www/example.com/public_html/ <Directory /var/www/example.com/public_html/> Options FollowSymLinks AllowOverride all Require all granted RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC] RewriteCond %{HTTP_HOST} ^(www\.)?([^\.]+)\.example\.com$ [NC] RewriteRule ^$ /process.php?p=%2 [QSA,NC] RewriteCond %{REQUEST_FILENAME} !^$ [NC] RewriteRule ^(.*) http://www.example.com/$1 [P] </Directory> </VirtualHost> 

I'd based this off successfully redirecting a different domain's root directory to example.com using this .htaccess file, which incorporates process.php and sends all other requests to the root of example.com.

Options +FollowSymLinks RewriteEngine On RewriteBase / # Check the request isn't an existing file RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^$ http://www.example.com/process.php [P] RewriteCond %{REQUEST_FILENAME} !^$ [NC] RewriteRule ^(.*) http://www.example.com/$1 [P] 

And also off this .htaccess test I ran to redirect a subdomain as a variable to process.php succesfully, though it didn't catch other file requests, such as the css example above:

Options +FollowSymLinks RewriteEngine On RewriteBase / RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC] RewriteCond %{HTTP_HOST} ^(www\.)?([^\.]+)\.example\.com$ [NC] RewriteRule ^$ /process.php?p=%2 [QSA,NC] 


Update 1

I've had (seemingly) some success with using the following in place of my second virtualhost entry. The process.php page is being output if I use a subdomain. While the pattern matching seems to work in that regard, my actual process.php receives an empty variable, rather than the expected subdomain as a string (for: process.php?p=%2):

<VirtualHost *:80> ServerAdmin [email protected] ServerName other.example.com ServerAlias *.example.com DocumentRoot /var/www/example.com/public_html <Directory /var/www/example.com/public_html> Options FollowSymLinks AllowOverride all Require all granted RewriteEngine on RewriteBase / RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC] RewriteCond %{HTTP_HOST} ^(www\.)?([^\.]+)\.example\.com$ [NC] RewriteCond %{REQUEST_URI} ^/$ RewriteRule ^$ /process.php?p=%2 [NC,QSA] </Directory> </VirtualHost> 


Update 2

I've solved this in a roundabout way but I'm not sure if it's the most elegant way of doing so.

Using the above update 1 code, I saw that any query string was still being appended but %2 was not being received by GET in my process.php page. I may have assumed wrongly that although the url doesn't display the p=abc variable in the url to the browser, as per my code instructions, that the internal url still passed them on. Nonetheless, I realised that process.php could still determine the subdomain as a string using $_SERVER['HTTP_X_FORWARDED_HOST'] in PHP and use it as a variable on the page in a similar manner to my initial idea.

2
  • 1
    Probably not the cause of an error, but in your second VirtualHost you have defined the DocumentRoot and <Directory> container with a slash on the end of the directory path. It is more usual to omit the trailing slash, as in your first VirtualHost. You are also using mod_proxy (the P flag) - is mod_proxy and the associated modules enabled? However, I'm not sure why you even need to proxy the request here, since the subdomains appear to point to the same area on the filesystem? Commented Mar 23, 2017 at 12:03
  • Thanks @w3dk. Removing end slashes had no effect. I'm possibly using proxy out of ignorance. I deliberately want it to to go to the same area of the filesystem as it seems like the most straightforward way of providing a subdomain for a user that I can then utilise as a get variable in php through the same filesystem and hierarchy that I would sent a usual get variable. So rather than each user using example.com/process.php?p=abc, the user abc can go to abc.example.com to reach the same output. Commented Mar 23, 2017 at 13:20

1 Answer 1

1
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC] RewriteCond %{HTTP_HOST} ^(www\.)?([^\.]+)\.example\.com$ [NC] RewriteCond %{REQUEST_URI} ^/$ RewriteRule ^$ /process.php?p=%2 [NC,QSA] 

The %2 backreference was not being set because this is a backreference to the second captured group of the last matched CondPattern (RewriteCond pattern). The last matched CondPattern is ^/$ which doesn't have any captured groups, so %2 is always empty.

That 3rd RewriteCond directive looks superfluous anyway. This is already being checked by the RewriteRule pattern ^$ (in a per-directory context, the directory-prefix is removed - so this is correct).

The first RewriteCond directive also looks superfluous. Any request for www.example.com would be caught by the first VirtualHost, so the hostname inside this VirtualHost is never www.example.com anyway, so this directive always evaluates to true.

I would rewrite this as:

RewriteCond %{HTTP_HOST} ^(?:www\.)?([^.]+)\.example\.com$ [NC] RewriteRule ^$ process.php?p=%1 [QSA] 

I've made the first group non-capturing ie. (?:www\.) - the ?: makes it non-capturing. So, we only ever get %1 for the actual subdomain. Also, there's no need to escape the dot (to match a literal dot) in a character class. The NC flag on the RewriteRule is superfluous here.

I've also removed the slash prefix on the RewriteRule substitution since you have specified the URL-path in the RewriteBase directive.

This only rewrites abc.example.com/, ie. a request for the document root.

Secondly, any requests for files from the subdomain outside of a base/root level need to be rewritten to be obtained from the root path of the standard domain without the subdomain. So abc.example.com/css/style.css needs to come from example.com/css/style.css.

Since abc.example.com/ and example.com/ point to the same place on the file system I don't see as you need to do anything here? example.com/css/style.css should point to the same file as abc.example.com/css/style.css.

What about other files in the document root? eg. abc.example.com/file. At the moment this just passes through unchanged as for CSS files.

2
  • Thanks @w3dk, I appreciate the time taken to go through this. I certainly need to improve my regex, for a start. I'm going to go through this now so please excuse the time it takes for me to deconstruct it with the help of your explanations. Commented Mar 27, 2017 at 10:04
  • What about other files in the document root? eg. abc.example.com/file. At the moment this just passes through unchanged as for CSS files. Yes, this is the desired behaviour. The framework I've built suits all queries etc. coming from the same directory as its primarily structured in a mysql database. My only goal here is to give each user a subdomain for aesthetics and convenience sake, hiding the process file and the user get query to access it. Commented Mar 27, 2017 at 10:08

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.