Tominator
Tominator

Reputation: 1224

htaccess rewrite subdomain to some folder if exists else another

I know there are some similar questions about subdomain -> folder htaccess, but I already have a setup that works for me for that simple case.

What I want to add, is "rewrite to projects/subdomain/current/public/ if that current/public exists, else rewrite to projects/subdomain/"

It's because I'm hosting a laravel application, which is in 'public/', and I deployed it using a tool that symlinks 'current/' to its latest release.

My current setup is:

# Redirect everything non-www to /projects/...
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www.* [NC]
RewriteCond %{HTTP_HOST} ^([^\.]+)\.mydomain\.com
RewriteCond /var/www/mydomain.com/projects/%1 -d
RewriteRule ^(.*) /projects/%1/$1 [L]

Which is something like:

How would I update this to have an "IF /projects/subdomain/current/public exists, then that, ELSE IF /projects/subdomain exists, then that, ELSE 404"?

Thanks in advance!

Upvotes: 1

Views: 102

Answers (1)

MrWhite
MrWhite

Reputation: 45914

Just create another rule before the existing one. For example, following the same pattern as your existing rule:

RewriteEngine on

# Redirect to /projects/<subdomain>/current/public/
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^([^\.]+)\.mydomain\.com
RewriteCond /var/www/mydomain.com/projects/%1/current/public -d
RewriteRule (.*) /projects/%1/current/public/$1 [L]

# Redirect everything non-www to /projects/...
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^([^\.]+)\.mydomain\.com
RewriteCond /var/www/mydomain.com/projects/%1 -d
RewriteRule (.*) /projects/%1/$1 [L]

I removed the ^ from the RewriteRule pattern (^(.*)) since it was superfluous.

I also changed !^www.* (matches any hostname that simply starts "www") to !^www\. (any hostname that starts "www." - the subdomain only) to avoid potentially spurious matches.

Presumably /var/www/mydomain.com is the document-root, so you could use the DOCUMENT_ROOT server variable instead in the RewriteCond TestString. For example:

RewriteCond %{DOCUMENT_ROOT}/projects/%1/current/public -d

However, by themselves, these directives will result in a rewrite-loop (500 error), so I assume you already have directives in place that prevent this. eg. Another .htaccess file in the directory that you are rewriting to that contains mod_rewrite directives (relevant to the individual projects)? If not then you can either add another condition to each rule that checks against the REDIRECT_STATUS environment variable, or include an exception at the top of the file that prevents further processing after the request is rewritten. For example:

RewriteEngine On

# Stop further processing if the request has already been rewritten
RewriteCond %{ENV:REDIRECT_STATUS} !^$
RewriteRule ^ - [L]

: Remaining directives follow...

UPDATE: If you are on Apache 2.4 you can instead simply change the L flag to END to halt all processing by the rewrite engine, to prevent a rewrite loop. The END flag is a relatively recent addition and consequently often gets overlooked - but it's not strictly necessary as there are always other (perhaps more complex) ways to do this.

Why would it loop?

The L flag does not stop all processing. It simply stops the current round of processing and then the rewrite engine effectively starts over, passing the rewritten URL back into the rewrite engine. In the above example, the rewritten URL also matches the same rules, so the URL would be rewritten again, and again, and again, ....

For example (for simplicity, just using your original rule that rewrites to /projects):

  1. Request subdomain.mydomain.com/foo
  2. <doc-root>/projects/subdomain directory exists
  3. URL rewritten to /projects/subdomain/foo
  4. Rewriting process starts over... passing in the rewritten URL, essentially subdomain.mydomain.com/projects/subdomain/foo, back into the rewrite engine.
  5. <doc-root>/projects/subdomain directory exists (as previous)
  6. URL rewritten to /projects/subdomain/projects/subdomain/foo
  7. Rewriting process starts over... etc. etc.

The Rewriting process loops in this fashion until the URL passes through unchanged, unless something else steps in the way... for example, as mentioned above, if you have another .htaccess file located at /projects/subdomain/.htaccess that also contains mod_rewrite directives then control would pass to this .htaccess file after the first round of rewrite processing and prevent further rewrites (since mod_rewrite directives are not inherited by default).

Upvotes: 3

Related Questions