Apache mod_rewrite - rewrite to folder name based on %{HTTP_HOST} - infinite loop - apache

I'm currently stuck with an infinite loop problem with mod_rewrite.
What I want (rules to be applied in order):
stript www (redirect)
rewrite request so that the files within the folder named %{HTTP_HOST} (if existent) are used
if the folder doesn't exist, redirect to domain.tld
Examples:
www.subdomain.domain.tld => redirect to subdomain.domain.tld
subdomain.domain.tld => load files within folder named subdomain.domain.tld (and pass the rest of the request)
unknown-subdomain.domain.tld => redirect to domain.tld
What I got so far:
RewriteEngine On
# Store protocol (HTTP or HTTPS) as ENV variable
RewriteCond %{HTTP:CF-Visitor} '"scheme":"http"' [OR]
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ - [env=proto:http]
RewriteCond %{HTTP:CF-Visitor} '"scheme":"https"' [OR]
RewriteCond %{HTTPS} =on
RewriteRule ^(.*)$ - [env=proto:https]
# Stript www
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^ %{ENV:proto}://%1%{REQUEST_URI} [L,NC,QSA,R=301]
# Directory exists => rewrite
RewriteCond %{REQUEST_URI} !^/%{HTTP_HOST} [NC]
RewriteCond %{HTTP_HOST} -d
RewriteRule ^ %{HTTP_HOST}%{REQUEST_URI} [L,NC,QSA]
# Directory doesn't exist => redirect
RewriteCond %{REQUEST_URI} !^/%{HTTP_HOST} [NC]
RewriteCond %{HTTP_HOST} !-d
RewriteRule ^ %{ENV:proto}://domain.tld%{REQUEST_URI} [L,NC,QSA,R]
I know all this can be achieved with virtual hosts. Unfortunately, I'm already on a shared virtual host and .htaccess is all I can make use of, so I'm kinda forced to go that way.
I'm thankful for any help or ideas to lead me to the right direction.

Hope this helps:
RewriteEngine On
RewriteBase "/"
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ - [env=proto:http]
RewriteCond %{HTTPS} =on
RewriteRule ^(.*)$ - [env=proto:https]
# Strip www
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^ %{ENV:proto}://%1%{REQUEST_URI} [L,NC,QSA,R=301]
#Prevent loop
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
# Directory exists => rewrite
RewriteCond %{DOCUMENT_ROOT}/%{HTTP_HOST} -d
RewriteRule ^ /%{HTTP_HOST}%{REQUEST_URI} [L,NC,QSA]
# Directory doesn't exist => redirect (but not if host=example.com)
RewriteCond %{DOCUMENT_ROOT}/%{HTTP_HOST} !-d
RewriteCond %{HTTP_HOST} !=example.com
RewriteRule ^ %{ENV:proto}://example.com%{REQUEST_URI} [L,NC,QSA,R]

Related

Problem with URL path and .htacces redirect

I have the following code in my .htaccess:
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
which redirects all traffic to HTTPS and non-www, perfectly. However if a user happens to visit a page on the website and includes www it doesn't keep the full path but redirects to the home page. For example:
www.example.com goes to example.com
but
www.example.com/page goes to example.com instead of example.com/page
this happens regardless of using HTTPS or HTTP. It's something to do with the www redirect that's causing the problem (?)... I just can't figure it out and I've googled many answers to no avail.
UPDATE
My full .htacces is:
RewriteEngine on
RewriteBase /
# block text files in the content folder from being accessed directly
RewriteRule ^content/(.*)\.(txt|md|mdown)$ index.php [L]
# block all files in the site folder from being accessed directly
# except for requests to plugin assets files
RewriteRule ^assets/plugins/([a-zA-Z0-9\.\-_%=]+)/(.*)$ site/plugins/$1/assets/$2 [L,N]
RewriteCond $1 !^plugins/[a-zA-Z0-9\.\-_%=]+/assets/.*
RewriteRule ^site/(.*) index.php [L]
# block direct access to kirby and the panel sources
RewriteRule ^(kirby|panel\/app|panel\/tests)/(.*) index.php [L]
# make panel links work
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^panel/(.*) panel/index.php [L]
# make site links work
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*) index.php [L]
# HTTP to HTTPS and WWW to non WWW
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
Could you please try following, based on your shown samples. Please keep these rules above all of your rules and make sure you clear your browser cache before testing these.
RewriteEngine ON
##For www requests changing to https.
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
##For non-www requests changing to https.
RewriteCond %{HTTPS} !on
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]

Force www and redirect root directory

I couldn't find a question that answered mine, or maybe I couldn't search using the right terms, but come on. I have the following rule in my htaccess:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^domain\.com\.br$ [OR]
RewriteCond %{HTTP_HOST} ^www\.domain\.com\.br$
RewriteRule ^(.*)$ "https\:\/\/www\.domain\.com\.br\/site" [R=301,L]
This works when the user enters only the URL (domain.com.br or www.domain.com.br), but I need it to redirect when the user accesses this way:
domain.com.br or www.domain.com.br --> https://www.domain.com.br/site
domain.com.br/XXX --> https://www.domain.com.br/XXX
What rule should I use for this?
Update: the server already has a default rule to force SSL, in which case it is unnecessary to put it in htaccess
Rule update:
**On virtual host:**
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP:X-Forwarded-Proto} !https [NC]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
**On htaccess file:**
RewriteCond %{HTTP_HOST} ^domain\.com\.br$ [OR]
RewriteCond %{HTTP_HOST} ^www\.domain\.com\.br$
RewriteRule ^/?$ https://www.domain.com.br/site/ [R=301,L]
Your code generates a redirect loop. Also, you don't need to escape slashes on targets.
You could merge everything inside your virtual host block (faster than using a htaccess):
RewriteEngine On
# force https
RewriteCond %{HTTPS} off [NC]
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# force www
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# redirect root directory to /site/
RewriteRule ^/?$ /site/ [R=301,L]
Of course, you will see a redirect chain for e.g. http://domain.tld/ as it will first redirect to https://domain.tld/ then to https://www.domain.tld/ and finally to https://www.domain/tld/site/. This is fine. However, if you really want to handle everything with only one redirect, you could. But, it will be less generic.
For instance, you would end up with those rules:
RewriteEngine On
# force root directory to /site/ (https+www)
RewriteRule ^/?$ https://www.domain.com.br/site/ [R=301,L]
# force any other pages to https+www if not the case already
RewriteCond %{HTTPS} off [NC,OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.domain.com.br%{REQUEST_URI} [R=301,L]

Is there any way to use If..Then..Else in .htaccess on Apache 2.2.29 on Shared Hosting Environment?

I learnt from this Q&A: How to write "if...else" mod_rewrite statements in .htaccess that it is possible to implement If statement in .htaccess but on Apache 2.4 and above.
I learnt from this Q&A: htaccess if statement, how to ipmlement If statement for Apache less than 2.4 versions. The answer by #julp almost solves my problem, but I don’t think I am allowed to do the “appending thing” on Shared Hosting.
Is there any workaround to using If..Then..Else in .htaccess on Apache 2.2.29 on Shared Hosting Environment?
Update:
As instructed by #Thakkie, I am adding my specific requirements.
I am trying to host two domains from one shared hosting account. My .htaccess file is as follows:
<If “%{HTTP_HOST} == ‘domain2.com’”>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ domain2.com-directory/domain2-index.php [QSA,L]
</IfModule>
</If>
<Else>
RequestHeader set X-Prerender-Token "<MyToken>"
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{HTTP_HOST} ^www.domain1.com/domain1-index.php$ [NC]
RewriteRule ^(.*)$ https://www.domain1.com/domain1-index.php$1 [R=301,L]
<IfModule mod_proxy_http.c>
RewriteCond %{HTTP_USER_AGENT} baiduspider|facebookexternalhit|twitterbot|rogerbot|linkedinbot|embedly|quora\ link\ preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator [NC,OR]
RewriteCond %{QUERY_STRING} _escaped_fragment_
# Only proxy the request to Prerender if its a request for HTML
RewriteRule ^(?!.*?(\.js|\.css|\.xml|\.less|\.png|\.jpg|\.jpeg|\.gif|\.pdf|\.doc|\.txt|\.ico|\.rss|\.zip|\.mp3|\.rar|\.exe|\.wmv|\.doc|\.avi|\.ppt|\.mpg|\.mpeg|\.tif|\.wav|\.mov|\.psd|\.ai|\.xls|\.mp4|\.m4a|\.swf|\.dat|\.dmg|\.iso|\.flv|\.m4v|\.torrent|\.ttf|\.woff))(.*) http://service.prerender.io/https://%{HTTP_HOST}/$2 [P,L]
</IfModule>
# Transfers to www.domain1.com when domain1.com is entered
RewriteCond %{HTTP_HOST} ^domain1.com$ [NC]
RewriteRule ^(.*)$ https://www.domain1.com/$1 [L,R=301]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ domain1.com-directory/domain1-index.php [QSA,L]
</Else>
I am assigning one set of operation for domain1.com and another set of operation for domain2.com depending on the HTTP_HOST using <If><Else>.
I tried the above .htaccess file on my friend’s dedicated server, which is running Apache 2.4, and it worked.
But, unfortunately, my shared hosting account provider is running Apache 2.2.29 and thus the <If></If> and <Else></Else> is not supported.
What is the workaround to the <If><Else> in my situation?
This may not be the most perfect solution, but it worked for me.
I was actually using the <If><Else> statement to perform domain specific actions.
As the <If> statement is not allowed in Apache 2.2.29, I appended RewriteCond %{HTTP_HOST} ^domainname.com$ [NC] before every RewriteRule which I wanted to be domain specific.
Thus
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ domain2.com-folder/domain2-index.php [QSA,L]
Becomes
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{HTTP_HOST} ^www.domain2.com$ [NC]
RewriteRule ^ domain2.com-folder/domain2-index.php [QSA,L]
The above lines mean: IF (the requested filename does not exist) AND (the HTTP_HOST is www.domain2.com) THEN use the RewriteRule.
Essentially, I used the RewriteCond to perform the function of the <If> operator, usable in Apache 2.4 or higher.
Now, the entire .htaccess file:
RequestHeader set X-Prerender-Token "<MyToken>"
RewriteEngine On
RewriteCond %{HTTP_HOST} ^domain2.com$ [NC]
RewriteRule ^(.*)$ http://www.domain2.com [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{HTTP_HOST} ^www.domain2.com$ [NC]
RewriteRule ^ domain2.com-folder/domain2-index.php [QSA,L]
# Since I want the HTTPS to be domain specific
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^(domain1.com|www.domain1.com)$ [NC]
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{HTTP_HOST} ^www.domain1.com/domain1-index.php$ [NC]
RewriteRule ^(.*)$ https://www.domain1.com/domain1-index.php$1 [R=301,L]
<IfModule mod_proxy_http.c>
RewriteCond %{HTTP_USER_AGENT} baiduspider|facebookexternalhit|twitterbot|rogerbot|linkedinbot|embedly|quora\ link\ preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator [NC,OR]
RewriteCond %{QUERY_STRING} _escaped_fragment_
# Only proxy the request to Prerender if its a request for HTML
RewriteRule ^(?!.*?(\.js|\.css|\.xml|\.less|\.png|\.jpg|\.jpeg|\.gif|\.pdf|\.doc|\.txt|\.ico|\.rss|\.zip|\.mp3|\.rar|\.exe|\.wmv|\.doc|\.avi|\.ppt|\.mpg|\.mpeg|\.tif|\.wav|\.mov|\.psd|\.ai|\.xls|\.mp4|\.m4a|\.swf|\.dat|\.dmg|\.iso|\.flv|\.m4v|\.torrent|\.ttf|\.woff))(.*) http://service.prerender.io/https://%{HTTP_HOST}/$2 [P,L]
</IfModule>
# Transfers to www.domain1.com when domain1.com is entered
RewriteCond %{HTTP_HOST} ^domain1.com$ [NC]
RewriteRule ^(.*)$ https://www.domain1.com/$1 [L,R=301]
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{HTTP_HOST} ^www.domain1.com$ [NC]
RewriteRule ^ domain1.com-folder/domain1-index.php [QSA,L]
P.S. I request the seniors to please rectify my description, if you feel it is inaccurate.

Reduce number of redirects in htaccess

I currently force HTTP to HTTPS and also drop www for my domain ahtag.com, but when you request the root it redirects to ahtag.com/en/home.
Here's the .htaccess rewrite rules that I'm using.
<IfModule mod_rewrite.c>
RewriteEngine On
# strip www subdomain
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1%{REQUEST_URI} [R=301,L]
SetEnvIf HOST "ahtag\.com$" LIVE=1
# forbid non-GET on non-HTTPS
RewriteCond %{ENV:LIVE} 1
RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_METHOD} !=GET
RewriteRule .* - [F,L]
# force HTTPS
RewriteCond %{ENV:LIVE} 1
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# cakephp rewrite rule
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
This works fine, but I want to add some specific rules for the root domain. This will reduce redirects and improve response time for first time visitors.
How can I rewrite the following (including schema, host and path).
http://www.ahtag.com --> https://ahtag.com/en/home
http://ahtag.com --> https://ahtag.com/en/home
https://www.ahtag.com --> https://ahtag.com/en/home
https://ahtag.com --> https://ahtag.com/en/home
You get the idea. I just want to redirect on a special URL to the default home URL.
I've read the Apache manual for RewriteCond but I don't feel confident enough to push changes to the production server.
You can add this rule just below RewriteEngine line:
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(ahtag\.com)$ [NC]
RewriteRule ^/?$ http://%1/en/home [L,R=301]
# strip www subdomain
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1%{REQUEST_URI} [R=301,L]
SetEnvIf HOST "ahtag\.com$" LIVE=1
# forbid non-GET on non-HTTPS
RewriteCond %{ENV:LIVE} 1
RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_METHOD} !=GET
RewriteRule .* - [F,L]
# force HTTPS
RewriteCond %{ENV:LIVE} 1
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# cakephp rewrite rule
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

Redirect parked domain (htaccess)

I have two domains in the format of foo.com and foo.net. I currently have the following in my .htaccess to redirect non-www to www:
# Rewrite URL to force WWW
RewriteCond %{HTTP_HOST} ^[^.]*\.[^.]*$
RewriteCond %{SERVER_PORT} !=443
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{HTTP_HOST} ^[^.]*\.[^.]*$
RewriteCond %{SERVER_PORT} =443
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{HTTP_HOST} ^www\.(.*\.[^.]*\.[^.]*)$ [NC]
RewriteCond %{SERVER_PORT} !=443
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
RewriteCond %{HTTP_HOST} ^www\.(.*\.[^.]*\.[^.]*)$ [NC]
RewriteCond %{SERVER_PORT} =443
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
However, I want to redirect URLs ending in .net to go to .com, including the subdomains.
Examples:
foo.net -> foo.com
www.foo.net -> www.foo.com
foo.net/bar -> foo.com/bar
sub.foo.net -> sub.foo.com
sub.foo.net/bar -> sub.foo.com/bar
I used to have this on another site, but it was years ago and I don't have the .htaccess anymore. Does anybody know an easy way of doing this?
Edit: Here is the rest of the .htaccess:
# BEGIN WordPress
#
RewriteEngine on
#
# Unless you have set a different RewriteBase preceding this point,
# you may delete or comment-out the following RewriteBase directive
# RewriteBase /
#
# if this request is for "/" or has already been rewritten to WP
RewriteCond $1 ^(index\.php)?$ [OR]
# or if request is for image, css, or js file
RewriteCond $1 \.(gif|jpg|png|php|ico|css|js)$ [NC,OR]
# or if URL resolves to existing file
RewriteCond %{REQUEST_FILENAME} -f [OR]
# or if URL resolves to existing directory
RewriteCond %{REQUEST_FILENAME} -d
# then skip the rewrite to WP
RewriteRule ^(.*)$ - [S=1]
# else rewrite the request to WP
RewriteRule . /index.php [L]
#
# END wordpress
# Rewrite URL to force WWW
-(see top of post)-
Ignoring the fact that this is by far the most devilish rewrite ruleset that I've ever written, this surprisingly seems to take care of what you currently have, plus what you want, in a nice, compact package.
Let me know if you have any problems with it:
RewriteCond %{HTTPS} =on
RewriteRule .* - [E=RW_HTTPS:s]
RewriteCond %{HTTP_HOST} ^www\.(.*\.[^.]*\.[^.]*)$ [NC,OR]
RewriteCond www.%{HTTP_HOST} ^(www\.[^.]*\.[^.]*)$
RewriteRule .* - [E=RW_THOST:%1]
RewriteCond %{ENV:RW_THOST} ^(.*)\.(net|com)$ [NC,OR]
RewriteCond %{HTTP_HOST} ^(.*)\.net$ [NC]
RewriteRule .* http%{ENV:RW_HTTPS}://%1.com%{REQUEST_URI} [R=301,L]
To Redirect Parked domain to main website domain with specific URL Try The following code on your htacess file :
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^parked-domain.com [OR]
RewriteCond %{HTTP_HOST} ^www.parked-domain.com
RewriteRule ^(.*)$ https://main-domain.com/custom-url [L,R=301]