.htaccess redirect based on country and language - regex

I have already asked a question about .htacess rules and everything works fine.
I've also found solutions to 301 redirect users based on detected language (HTTP:Accept-Language), but I haven't found answer to how can I redirect users from pt-PT, pt-BR, en-US to specific main pages:
www.example.com/pt-pt/inicio.html
www.example.com/pt-br/inicio.html
www.example.com/en-us/home.html
Here is my working .htaccess file:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
# This is for not allowing access from libwww-perl User-Agent
RewriteCond %{HTTP_USER_AGENT} libwww-perl.*
RewriteRule .* – [F,L]
# This is for IP Canonicalization
RewriteCond %{HTTP_HOST} ^999\.999\.999\.999
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
# This is for URL Canonicalization
RewriteCond %{HTTP_HOST} !^www.example.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]
# This is from another StackOverflow question
RewriteRule ^([^/]+)/(.+?)\.html?$ index.php?lang=$1&page=$2 [NC,L,QSA]
</IfModule>
AddHandler application/x-httpd-php55 .php .php5 .php4 .php3
How can I achieve that? I'm a little affraid of touching the .htaccess file...
Edit: Does the order of lines makes difference until IP canonicalization? The website is in a shared host and it hasn't passed the test on this for SEO. Also, the root PHP page is already detecting the language and I could make the redirect, but I guess .htaccess would be a more elegant and efficient way to do it.

Related

Redirect non-www to www giving me hundreds of 404's

Thanks to anyone who can take a moment to look at this.
Recently I created a new section "subdomain" in my website and in this new folder I have includes a Joomla CMS installation the url looks like this: http://www.example.com/subdomain/
In this folder I have a htaccess file to which I have added.
## No directory listings
# Redirect non-www to www:
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
When I try to access say http://example.com/subdomain/anytrailingstring then it's NOT redirecting me to http://www.example.com/subdomain/anytrailingstring as I expected, it is redirecting to http://www.example.com/anytrailingstring leaving out the /subdomain/ and this is of course a page that doesnt exist and therefore a 404.
This is a problem.
I do not have any directive in the root .htacces file except for this :
DirectoryIndex index.php
Options +FollowSymLinks
RewriteEngine on
RewriteBase /
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Can someone perhaps see why the subdomain htaccess isnt redirecting to correctly? Did I miss something?
I am not good with htaccess at all, if anybody can help me I would really appreciate it.
Thanks!
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
You need to use the REQUEST_URI server variable instead of the backreference ($1). The URL-path matched by the RewriteRule pattern (first argument) is relative to the current directory, so excludes the parent subdirectory (ie. /subdomain in your example).
Do it like this instead:
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
You will need to clear your browser cache since the erroneous (301 - permanent) redirect will have been cached by the browser. Test with 302 (temporary) redirects to avoid potential caching issues.
However, a couple of questions:
Why are you not using HTTPS? (You are redirecting to HTTPS in the parent .htaccess file - but this is now being overridden by the mod_rewrite directives in the subdirectory.)
Why not include this in the parent .htaccess file?
UPDATE: So, taking the above points into consideration... if you want to move this rule to the parent .htaccess file in the root then have it like this:
DirectoryIndex index.php
Options +FollowSymLinks
RewriteEngine on
# Redirect non-www to www (and HTTPS)
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Redirect HTTP to HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
The order of the directives is to ensure there is only ever at most 1 redirect (assuming you are not implementing HSTS).
You were unnecessarily duplicating the RewriteEngine directive (so I removed the second instance).
The RewriteBase directive was not being used.
The capturing subgroup in your HTTP to HTTPS rule was not required. ie. ^ is better than ^(.*)$ in this instance.
Aside:.
...a new section "subdomain" in my website and in this new folder I have includes a Joomla CMS installation the url looks like this: http://www.example.com/subdomain/
This is a subdirectory, not a "subdomain".
This is a "subdomain":
http://subdomain.example.com/

Apache rewrite rules for maintenance, htaccess not allowing my IP address through

I'm working on a template to use for site maintenance. Took a while to figure out that Apache wanted absolute paths, but now everything is working, short of the IP.
I'm trying to allow my IP and the IP of the server (domain) when maintenance is activated, so the maintenance page will only be served to guests. However, I'm also getting served the maintenance page. I suck at regex, so it might be a simple error.
Here are my Apache directives.
## Maintenance
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# local ip
RewriteCond %{REMOTE_ADDR} !^111\.111\.33\.44
# server ip
RewriteCond %{REMOTE_ADDR} !^222\.222\.333\.444
# maintenance folder
RewriteCond %{REQUEST_URI} ^/maintenance/
RewriteRule .+ - [L]
# maintenance files
RewriteCond %{REQUEST_URI} !\.(jpe?g?|png|gif|css|woff|woff2|eot|ttf|svg) [NC]
RewriteCond %{REQUEST_URI} !^/maintenance/maintenance\.html$
RewriteRule ^(.*) https://example.com/maintenance/maintenance.html [R=307,L]
</IfModule>
ErrorDocument 503 /maintenance/maintenance.html
ErrorDocument 307 /maintenance/maintenance.html
<IfModule mod_headers.c>
#do not cache
Header Set Cache-Control "max-age=0, no-store"
</IfModule>
## End Maintenance
# Force HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.*)$ [NC]
RewriteRule (.*) https://%1%{REQUEST_URI} [L,R=301]
# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php74” package as the default “PHP” programming language.
<IfModule mime_module>
AddHandler application/x-httpd-ea-php74 .php .php7 .phtml
</IfModule>
# php -- END cPanel-generated handler, do not edit
I managed to figure this out, so in case anyone else who's as bad at regex as I am comes across this, it may help them.
I had two unneeded lines of directives and the ^ was unnecessary or causing problems. $ after IP is to make sure a similar longer IP can't get through. I also switched to a 302 error since it is a temporary redirect for maintenance.
Make sure your folder and html file path is set correctly and uses absolute paths. If you aren't using a folder, the path directly to the html should work. I used a folder because I have images and fonts also loading and like to keep things tidy.
<IfModule mod_rewrite.c>
RewriteEngine On
# local ip
RewriteCond %{REMOTE_HOST} !^111\.111\.22\.33$
# server ip
RewriteCond %{REMOTE_ADDR} !^222\.222\.333\.444$
# maintenance folder
RewriteCond %{REQUEST_URI} !^/maintenance/(.)*$
# maintenance files
RewriteCond %{REQUEST_URI} !\.(jpe?g?|png|gif|css|woff|woff2|eot|ttf|svg) [NC]
RewriteCond %{REQUEST_URI} !/maintenance/maintenance\.html$ [NC]
RewriteRule .* /maintenance/maintenance.html [R=302,L]
</IfModule>
<IfModule mod_headers.c>
#do not cache
Header Set Cache-Control "max-age=0, no-store"
</IfModule>

.htaccess restrict subdomain by IP - Wordpress Multisite

I'd like to redirect traffic away from a subdomain install of Wordpress Multisite unless it's coming from a specific IP address/range, and without affecting the root domain traffic. Is this possible?
Conceptually, I've been thinking something like this:
# IF we're dealing with the subdomain
RewriteCond %{HTTP_HOST} subdomain\.example\.com [NC]
# AND the user is NOT from our allowed IP
RewriteCond %{REMOTE_ADDR} !111\.222\.333\.444
# THEN redirect them to the root domain
RewriteRule ^(.*)$ http://example.com/$1 [L,R=302]
In other words, restrict access to the subdomain from all traffic that doesn't originate from a defined IP address. I've literally just learned regex and .htaccess for this, so apologies in advance for anything that's glaringly wrong.
The reason I'm not doing this with directory specific .htaccess is that I'm working with a subdomain install of Wordpress Multisite, so there are no directories. It's all in the URL.
Some possible complications that come from Wordpress itself:
Ideally these rules should be added in such a way that they aren't overwritten every time the permalink cache is refreshed in WP.
I'm not sure what RewriteBase / evaluates to, or how it's affecting URIs (if that's the correct acronym) in my file.
EDIT:
Per #Prix feedback, here is the complete .htaccess file I'm working with:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} subdomain\.example\.com [NC]
RewriteCond %{REMOTE_ADDR} !111\.222\.333\.444
RewriteRule ^(.*)$ http://example.com/$1 [L,R=302]
RewriteRule ^index\.php$ - [L]
# add a trailing slash to /wp-admin
RewriteRule ^wp-admin$ wp-admin/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^(.*\.php)$ $1 [L]
RewriteRule . index.php [L]
</IfModule>
# END WordPress
This is Wordpress' Multisite default rules, with my own additions included immediately after RewriteBase /. I incorporated #hjpotter92's suggestion.
The desired affect it to redirect all traffic from subdomain.example.com to example.com, unless it's coming from a specific IP address. This is for a client who's essentially using part of their Wordpress Multisite as a company extranet.
The rule looks fine yes, the only thing I would change is this:
RewriteRule ^(.*)$ http://example.com/$1 [L,R=302]
Into this
RewriteRule ^ http://example.com/ [L,R=302]
As you don't want a 404 on the redirect aside from that given the subdomain share the same DocumentRoot, then yes, it should work as I have tested it myself.
And I hope at this line:
RewriteCond %{HTTP_HOST} subdomain\.example\.com [NC]
You're not adding noise to it like http:// or anything other than the qualified domain name, such as for example intranet\.mydomainname\.com no slash, no http, etc.

301 redirect to new domain and redirect individual old pages at the same time

I hope you can help me with this 301 issue.
Introduction
I've just published a re-design of a website with new clean urls. The old webpage had urls like this: www.domain.dk/Default.aspx?ID=66. And the new website urls look like this: www.domain.com/contact
So I wan't to redirect all these old urls to the new ones, and therefor i'm not keeping the old urls and no general rule can be applied.
That's just simple 301 redirects, but at the same time the old domain points to a new domain, and this is where things get dirty, I think. The old domain was www.domain.dk, but i wan't to 301 all traffic to the new domain www.domain.com and at the same time I wan't to make all the individual 301 redirects.
The problem
When I click on the link www.domain.dk/Default.aspx?ID=66 in Google I get this URL in my browser: www.domain.comindex.php/?ID=66.
On other links I get www.domain.comdefault.aspx/?ID=2
So the redirecting to the new domain works fine? But the individual redirects doesn't apply at all.
The code
This code is pasted as is from my .htaccess file on the server running apache.
The first bit is auto-generated by Concrete5 CMS to make pretty URLs.
# -- concrete5 urls start --
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}/index.html !-f
RewriteCond %{REQUEST_FILENAME}/index.php !-f
RewriteRule . index.php [L]
</IfModule>
# -- concrete5 urls end --
This is the code I found to 301 redirect all traffic to urls that is not using www.esvagt.com to www.esvagt.com
## --- 301 Redirects --- ##
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\.domain\.com$ [NC]
RewriteRule ^(.*)$ http://www.domain.com$1 [R=301,L]
This is just one of the manual 301 redirects.
## General - Redirects ##
redirect 301 /Default.aspx?ID=66 http://www.domain.com/contact/contact-us
Thanks in advance. If you need more information I'll gladly provide that.
I have zero knowledge about writing code in .htaccess, so I'm pretty clueless. I hope you can help. :)
Avoid mixing mod_rewrite and mod_alias rules.
Ordering of rules is also very important so have 301 rules first and then have your catch all controller rule
Use this code for 301 redirect:
## --- 301 Redirects --- ##
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?domain\.dk$ [NC]
RewriteRule ^ http://www.domain.com%{REQUEST_URI} [R=301,L]
## General - Redirects ##
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+Default\.aspx\?ID=66[&\s] [NC]
RewriteRule ^ http://www.domain.com/contact/contact-us? [R=301,L]
# -- concrete5 urls start --
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}/index.html !-f
RewriteCond %{REQUEST_FILENAME}/index.php !-f
RewriteRule . index.php [L]
</IfModule>
# -- concrete5 urls end --
RewriteRule www.domain.dk/Default.aspx?ID=66 domain.com/contact/contact-us [R=301,L]
If you want to redirect all posts automatically:
RewriteRule /Artical.aspx?ID=(.+?) domain.com/article-title-$1.html [R=301,L]
or
RewriteRule /Artical.aspx?ID=(.+?) domain.com/Post.aspx?ID=$1 [R=301,L]
Then the dynamic url Artical.aspx?ID=20 will be redirect to http://www.domain.com/article-title-30.html,
I successfully apply this method for my blog http://downloadapp.info

htaccess: redirect old domain and all pages to a new domain

I know that there is a lot of examples on Stackoverflow but I still miss something.
I'm trying to redirect http://old.domain.com/fr/ to http://brand.new-domain.com/fr/ with the following rules, but that doesn't work:
# Enable Rewrite Engine
RewriteEngine On
RewriteBase /
# Add a trailing slash to paths without an extension
RewriteCond %{REQUEST_METHOD} !=POST
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule ^(.*)$ $1/ [L,R=301]
# Redirect domain
Options +FollowSymLinks
RewriteCond %{HTTP_HOST} ^old.domain.com [OR]
RewriteCond %{HTTP_HOST} ^other-old.domain.com [NC]
RewriteRule ^(.*)$ http://brand.new-domain.com/$1 [r=301,L]
# Remove index.php
# Uses the "exclude method"
# http://expressionengine.com/wiki/Remove_index.php_From_URLs/#Exclude_List_Method
# This method seems to work best for us, you might also use the include method.
# http://expressionengine.com/wiki/Remove_index.php_From_URLs/#Include_List_Method
# Exclude root files
RewriteCond $1 !^(index\.php) [NC]
# Exclude EE folders
RewriteCond $1 !^(assets|ee-admin|images|templates|themes|fr|nl)/ [NC]
# Exclude user created folders
RewriteCond $1 !^(assets|css|img|js|swf|uploads)/ [NC]
# Exlude favico, robots, ipad icon
RewriteCond $1 !^(favicon\.ico|robots\.txt|pple-touch-icon\.png) [NC]
# Remove index.php
RewriteCond %{QUERY_STRING} !^(ACT=.*)$ [NC]
RewriteCond %{QUERY_STRING} !^(URL=.*)$ [NC]
RewriteRule ^(.*)$ /index.php?/$1 [L]
It correctly redirect when I call the root URL, but not when I call a page. What am I doing wrong?
Thanks in advance!
Pv
When writing mod_rewrite rules, the rules get applied in the order that they appear.
To redirect an old domain to a new domain, you'll want that rule to be first in your .htaccess or httpd.conf file — all other rules should appear after it.
If you only want to redirect a certain directory, the following rule will do so, while allowing the rest of the site to function normally:
<IfModule mod_rewrite.c>
RewriteEngine On
# Redirect Only Matching Directories
RewriteCond %{REQUEST_URI} ^/(fr|fr/.*)$
RewriteRule ^(.*)$ http://brand.new-domain.com/fr/$1 [R=301,L]
</IfModule>
If you want to redirect the entire site, the following rule will do so:
<IfModule mod_rewrite.c>
RewriteEngine On
# Redirect Entire Site to New Domain
RewriteCond %{HTTP_HOST} ^old.domain.com$ [OR]
RewriteCond %{HTTP_HOST} ^other-old.domain.com$ [NC]
RewriteRule ^(.*)$ http://brand.new-domain.com/$1 [R=301,L]
</IfModule>
If you care about letting crawlers know your content has moved and want to make the transition as seamless as possible, be sure to keep the 301 Redirect flag in the RewriteRule.
This will ensure that users and search engines are directed to the correct page.
While we're on the subject, as part of the EE 2.2 release, EllisLab now "officially" offers limited technical support for removing index.php from ExpressionEngine URLs.
Simply add or update your code to the following, making sure to consider any rules you may already have in place:
<IfModule mod_rewrite.c>
RewriteEngine On
# Removes index.php
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
# If 404s, "No Input File" or every URL returns the same thing
# make it /index.php?/$1 above (add the question mark)
</IfModule>
Try to use the following ruke as the first one:
# Redirect domain
Options +FollowSymLinks
RewriteCond %{HTTP_HOST} ^old.domain.com [OR]
RewriteCond %{HTTP_HOST} ^other-old.domain.com [NC]
RewriteRule ^(.*)$ http://brand.new-domain.com/$1 [R=301,L]
Also mind the upper case R with is the short form for the lower case redirect.
Have you tried using mod_alias simple redirect instructions (a core module that you have), before trying the hacky-mod-rewrite thing?
I would do a VirtualHost with ServerName old.domain.com and in this VH I would add this rule:
Redirect /fr http://brand.new-domain.com/fr
from doc:
Then any request beginning with URL-Path will return a redirect request to the client at the location of the target URL. Additional path information beyond the matched URL-Path will be appended to the target URL.
So get a separate VirtualHost for brand.new-domain.com (with ServerName brand.new-domain.com) and in this one do not set the Redirect Rule.
If you still want to handle the 2 domains in the same VirtualHost then you'll have to use mod-rewrite as even RedirectMatch cannot check the request domain on the query.