Replace parts of the URL with mod_rewrite - apache

I need a mod_rewrite rule to redirect url depending on the hostname they are comming from.
The situation:
We have multiple domains pointing to a same webspace and we need to restrict what the specific host can see/download.
domainname.com/images/logo.jpg and /www.domainname.com/images/logo.jpg should transform into domainname.com/domainname_com/images/logo.jpg
So basically I need a rule/function that replaces the dots in the %{HTTP_HOST} with _ and removes/replaces the www subdomain.
Is there any way to do this with mod_rewrite?

Try these rules:
RewriteCond %{ENV:DOMAIN_DIR} ^$
RewriteCond %{HTTP_HOST} ^(www\.)?(.+)
RewriteRule ^images/.+ - [E=DOMAIN_DIR:%2]
RewriteCond %{ENV:DOMAIN_DIR} ^([^.]*)\.(.+)
RewriteRule ^images/.+ - [E=DOMAIN_DIR:%1_%2,N]
RewriteCond %{ENV:DOMAIN_DIR} ^[^.]+$
RewriteRule ^images/.+ %{ENV:DOMAIN_DIR}/$0 [L]
The first rule will take the host and store it without www. in the environment variable DOMAIN_DIR. The second rule will replace one dot at a time; the N flag allows to restart the rewriting process without incrementing the internal recursion counter. Finally, the third rule will rewrite the request to the corresponding directory.

Related

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:
if it doesn't start with www
get the subdomain in a var
if the /projects/subdomain folder exists
rewrite the request to look into that folder
else 404
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!
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):
Request subdomain.mydomain.com/foo
<doc-root>/projects/subdomain directory exists
URL rewritten to /projects/subdomain/foo
Rewriting process starts over... passing in the rewritten URL, essentially subdomain.mydomain.com/projects/subdomain/foo, back into the rewrite engine.
<doc-root>/projects/subdomain directory exists (as previous)
URL rewritten to /projects/subdomain/projects/subdomain/foo
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).

htaccess - Simple rewrite rule not triggering

I'm trying to match a simple rule to rewrite a url but it's just not matching. I want to redirect
https://example.com/web/thanks/
to
https://example.com/thanks.php
Here's what I've tried
RewriteEngine On
RewriteBase /
RewriteRule ^thanks/$ https://example.com/thanks.php [R=302,L]
RewriteEngine On
RewriteRule ^thanks/$ https://example.com/thanks.php [R=302,L]
RewriteEngine On
RewriteBase /
RewriteRule ^/(.*)/thanks/$ https://example.com/thanks.php [R=302,L]
RewriteEngine On
RewriteBase /
RewriteRule ^web/thanks/$ https://example.com/thanks.php [R=302,L]
and many more tiny variations but none of them are triggering. I tried using this online tool and it returns "This rule was not met". What am I doing wrong?
To rewrite, just use your last rule
RewriteRule ^web/thanks/?$ /thanks.php [L]
with the following changes
no RewriteBase, this is only relevant for some relative URLs
optional trailing slash /?, if you want both /web/thanks or /web/thanks/ to work
no domain name, because this might trigger a redirect instead of a rewrite, see RewriteRule
Absolute URL
If an absolute URL is specified, mod_rewrite checks to see whether the hostname matches the current host. If it does, the scheme and hostname are stripped out and the resulting path is treated as a URL-path. Otherwise, an external redirect is performed for the given URL. To force an external redirect back to the current host, see the [R] flag below.
no R|redirect flag, because this triggers a redirect instead of a rewrite
The pattern ^.*thanks/$ or ^(.*)thanks/$ also works, but it matches any URL ending in thanks/, like /hellothanks/, /areyousurethanks/, /some/path/thanks/, ...

.htaccess 301 redirects based on TLD

We're in the process of switching our current site from a multiple domain configuration into a single domain, multiple folder format. i.e.
.co.uk/<uri> is becoming .com/en-gb/<uri>
.com/<uri> is becoming .com/en-us/<uri>
I'm hoping that I'll be able to handle this via a couple of well-crafted .htaccess rules, but I'm not sure of code I'm going to need to achieve this. Can you help?
(PS, I've left the actual domain blank, as we only need to test for the TDL, not the entire domain - although whatever the original domain was need to stay the same, with only the TLD changing - i.e. whatever.co.uk would redirect to whatever.com/en-gb/, whatever2.co.uk would redirect to whatever2.com/en-gb/, and whatever.com would redirect to whatever.com/en-us/)
add the following directives to your .htaccess:
RewriteCond %{HTTP_HOST} (.+)\.co\.uk$
RewriteRule (.*) http://%1.com/en-gb/$1 [R=301,L,QSA]
RewriteCond %{HTTP_HOST} \.com$
RewriteCond %{REQUEST_URI} !^/(en-us|en-gb)/
RewriteRule (.*) /en-us/$1 [R=301,L,QSA]
if you have so many domain TLDs, you maybe want to use RewriteMap to avoid duplicating the first rule for every TLD, RewriteMap will map TLD to Uri string (ex: .co.uk to en-gb),

Redirect Multiple Subdomains to another domain name

Got a question about using mod_rewrite to redirect specific subdomains to use another domain. I am looking for the shortest possible way to do this without the need to create a separate rewrite rule for each of my domain names. I will be adding many new domain names (roughly 20-30 domains total).
So let's say my main domain name is example.com and I want to use that domain name for everything. So if any of my other domains are used, they will automatically be redirected to the main domain, preserving the subdomain prefix and the URL path.
Example:
test.example.org => test.example.com
test2.example.co.uk => test2.example.com
test3.example.net/hello/world.php => test3.example.com/hello/world.php
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(.*)\.([a-zA-Z]+)\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1\.example.com/$1 [R=301,L]
I am unsure if the above will work correctly or if it is proper syntax. But basically, I would like to have it match the subdomain prefix, then any domain name, and any TLD (.org, .info, .biz, .co.uk, .net, etc.). I would assume it would need to make sure that it is not the correct main domain (example.com) first to prevent a infinite redirect loop.
Also, is there a possibility to check if HTTPS is ON or OFF and set the redirect correctly? If not, I can always have HTTPS set to ON.
Sorry for this confusion, although I want to make sure I get this right the first time without needing to program each and every one of the domains into the .htaccess.
Thanks! :)
(.*) is greedy so you don't want to use that, and I assume that you don't want to recreate an infinite loop.
RewriteEngine on
RewriteCond %{HTTPS}s ^..(s?)
RewriteRule ^ - [E=PROTO:http%1]
RewriteCond %{HTTP_HOST} !^\w+\.example\.com$ [NC]
RewriteCond %{HTTP_HOST} ^(\w+)\.\w+\..+ [NC]
RewriteRule ^/?(.*) %{ENV:PROTO}://%1.example.com/$1 [R=301,L]
That rule will not work because it will redirect any host ending with example.com back to example.com and you'll get a redirect loop. You need to change the regex to look like this, to match anything that doesn't end with .com:
RewriteCond %{HTTP_HOST} ^([^\.]+)\.?([a-zA-Z]+)\.(?:(?!com).)*$ [NC]

htacces rewrite tld without changing subdomain or dirs

I am trying to rewrite the following url:
the subdomain should match any subdomain. same for the TLD.
both: http://car.example.com/ and http://cat.example.co.uk should be rewritten
http://subdomain.example.com/some/dir
to
http://subdomain.example.nl/some/dir
and
http://example.com/some/dir
to
http://exampkle.nl/some/dir
(also with www. adress)
but my knowledge of htaccess and rewrite rules in general aren't good enough for this :(
I hope one of you knows the solution.
ps. I did try a search ;)
The challenge comes with having to detect and account for four different possible domain patterns:
example.com → example.nl
example.co.uk → example.nl
sub.example.com → sub.example.nl
sub.example.co.uk → sub.example.nl
So, what this ruleset does is checks that the TLD is not .nl (preventing a loop from occurring), then pulls the subdomain, www or not, off the front (read as "capture anything other than a dot followed by a dot, optional), followed by the base domain, followed by a dot. We don't have to match the entire URL, since we aren't keeping the TLD.
RewriteEngine On
RewriteCond %{HTTP_HOST} !example\.nl$
RewriteCond %{HTTP_HOST} ^([^.]+\.)?example\.
RewriteRule ^ http://%1example.nl%{REQUEST_URI} [NC,L,R=301]
The RewriteRule's ^ matches any URL, then inserts the contents of the first set of parens in the preceding RewriteCond (the subdomain) with %1, and completes the rewriting by appending the requested path and flags to ignore case, make this the last rule, and redirect with a search-engine-friendly 301, ensuring the rewritten URL appears in the user's browser. Any query string (text appearing after a ? in the URL) is automatically included by default.
Try this:
EDIT: See changes to subdomain, using %1 to capture from RewriteCond
RewriteEngine On
# Check if the hostname requested is subdomain.example.com or empty
# Now we attempt to capture the subdomain with (.*)? and reuse with %1
RewriteCond %{HTTP_HOST} ^(.*)?example.com$ [NC]
RewriteCond %{HTTP_HOST} !^$
# Rewrite it as subdomain.example.nl and redirect the browser
RewriteRule ^(.*) http://%1example.nl$1 [L,R,NE,QSA]
# Note: With the above edit for %1, this part should no longer be necessary.
# Then do the same for example.com, with or without the www
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$ [NC]
RewriteCond %{HTTP_HOST} !^$
RewriteRule ^(.*) http://www.example.nl$1 [L,R,NE,QSA]