.htaccess restrict subdomain by IP - Wordpress Multisite - regex

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.

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/

Redirect specific url to homepage

I am building a React (frontend) with Wordpress (Backend - REST API) website. My domain is example.com which is going to have my React app (frontend) and on example.com/backend I have the Wordpress installation.
My problem is: I want to redirect example.com/backend and everything on to example.com except example.com/backend/wp-admin (so i can login). Is that do-able?
In a sentence: Can u redirect example.com/backend but have example.com/backend/wp-admin working (not redirecting)?
I tried lots of reggex in my .htaccess but none would do the trick.
RewriteEngine On
RewriteCond %{HTTP_HOST} ^fanismahmalat.com/backend$ [NC]
RewriteCond %{REQUEST_URI} !^(.)?wp-login.php(.)$
RewriteCond %{REQUEST_URI} !^(.)?wp-admin$
RewriteRule ^(.)$ https://example.com/ [R=301,L]
One way to exclude a URL is to have a rule before the "real" redirect, e.g.
RewriteRule ^backend/wp-admin - [L]
RewriteRule ^backend/ https://example.com [R,L]
The first rule will handle the wp-admin case. The second rule will catch anything else starting with backend/.
Another solution would be to exclude the specific URL from being rewritten
RewriteCond %{REQUEST_URI} !^/backend/wp-admin
RewriteRule ^backend/ https://example.com [R,L]
When the .htaccess file is in the backend sub-folder, the rules are almost the same, but the RewriteRule pattern does not include the backend prefix
RewriteCond %{REQUEST_URI} !^/backend/wp-admin
RewriteRule ^ https://example.com [R,L]
or
RewriteRule ^wp-admin - [L]
RewriteRule ^ https://example.com [R,L]

.htaccess redirect based on country and language

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.

.htaccess issue with ExpressionEngine and YOURLS

I have a primary site running ExpressionEngine and I am trying to get YOURLS running in a subfolder called "work", ie: http://foo.com/work/ for short urls and EE is running at the root, ie: http://foo.com/. Please note there is no 'www'.
The problem I am having is that when I use a short URL and a user adds "www" to the URI, such as http://www.foo.com/work/123 I get a redirect chain that looks like this:
http://www.foo.com/work/123 302 redirects to
http://www.foo.com/work 301 redirects to
http://www.foo.com/work/ which returns 200
Everything works fine if you omit the 'www' from the URI. YOURLS is set up to use the non-www but the worry is that some users might habitually type the 'www' as these URIs are being placed on printed ads.
The root .htaccess file looks like this:
SetOutputFilter DEFLATE
DirectoryIndex index.php index.html
# BEGIN ExpressionEngine Rewrite
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^www.foo.com [NC]
RewriteRule ^(.*)$ http://foo.com/$1 [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteRule ^(.*)$ /index.php?$1 [NC,L]
</IfModule>
# END ExpressionEngine Rewrite
The /work/ (YOURLS) .htaccess looks like this:
# BEGIN YOURLS
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /work/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /work/yourls-loader.php [L]
</IfModule>
# END YOURLS
How can I get the 'www' URIs to work like the non-www URIs do without completely hosing EE? :)
I faced a similar issue. Some end users or people publishing the short urls tend to append them with www while the short url was bought with the intention of using it without www.
I also installed the YOURLS redirect index plugin to forward homepage visitors to our regular homepage.
So I had a few different types of urls:
short domain homepage, should lead to the regular https homepage
short domain YOURLS admin panel, should lead to the https admin panel
short domain shortened urls, should lead to the long url
I wanted all urls to work with or without www and make sure http was forwarded to https.
My solution was to start .htaccess with these lines:
# Force HTTPS (because of passwords via /admin) and use clean domain (non www)
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www.examp.le [NC]
RewriteRule ^(.*)$ https://examp.le/$1 [L,R=301]

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.