I have this rule in htaccess:
1 ## Protect from spam bots ##
2 RewriteEngine On
3 RewriteCond %{REQUEST_METHOD} POST
4 RewriteCond %{REQUEST_URI} .wp-comments-post\.php*
5 RewriteCond %{HTTP_REFERER} !.DOMAIN.COM.* [OR]
6 RewriteCond %{HTTP_USER_AGENT} ^$
7 RewriteRule (.*) ^http://%{REMOTE_ADDR}/$ [R=301,L]
I want to replace the DOMAIN.COM at line 5 with dynamic hostname.
I would like to use the same rule with other domain without having to modify htaccess.
RewriteCond %{HTTP_REFERER} !.DOMAIN.COM.* [OR]
The complexity comes about because server variables of the form %{HTTP_HOST} are not expanded in the CondPattern (2nd argument to the RewriteCond directive), since it is a PCRE (regular expression).
Instead of the above line, you can do something like this instead:
RewriteCond %{HTTP_HOST}##%{HTTP_REFERER} !^(.*?)##https?://\1/ [OR]
This checks that the requested Host header matches the hostname part of the HTTP Referer header.
The \1 backreference (in the Referer) matches against the Host. The ## string is just any unique string that cannot otherwise occur.
Note that it is possible for legitimate users to not send an HTTP Referer header at all, in which case your current ruleset will also fail.
RewriteRule (.*) ^http://%{REMOTE_ADDR}/$ [R=301,L]
Note that the substitution string in your RewriteRule is malformed. It is an "ordinary" string, not a regex. Consequently, the anchors ^ and $ will be seen as literal characters and should be removed:
RewriteRule .* http://%{REMOTE_ADDR}/ [R=301,L]
Related
I try to redirect user from Joomla plugins links that have specific IDs to the default admin page as following:
When user login in Joomla backend, he can reach this page of plugins:
https://www.example.com/administrator/index.php?option=com_plugins
Then if he wants to open a plugin with the id like 422 to edit it, he's to click on this link:
https://www.example.com/administrator/index.php?option=com_plugins&task=plugin.edit&extension_id=422
But instead of opening the plugin, I want the user to get redirected to this page:
https://www.example.com/administrator/index.php
To achieve this, I created a .htaccess in the folder administrator and placed the code at the end. So, I set a range of IDs of plugins that user cannot edit, but gets redirected.
Please find the all content of .htaccess file as following:
# Canonical https/www
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule (.*) https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
# Redirect plug id from 350 to 423:
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteCond %{QUERY_STRING} (^|&)option\=com_plugins($|&)
RewriteCond %{QUERY_STRING} (^|&)extension_id=\b(3[5-8][0-9]|39[0-9]|4[01][0-9]|42[0-3])\b($|&)
RewriteRule ^administrator/index\.php$ https://www.example.com/administrator/index.php? [L,R=302]
# Redirect plug id from 425 to 10864:
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteCond %{QUERY_STRING} (^|&)option\=com_plugins($|&)
RewriteCond %{QUERY_STRING} (^|&)extension_id=\b(42[5-9]|4[3-9][0-9]|[5-9][0-9]{2}|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|10[0-7][0-9]{2}|108[0-5][0-9]|1086[0-4])\b($|&)
RewriteRule ^administrator/index\.php$ https://www.example.com/administrator/index.php? [L,R=302]
But does not work.
I create a .htaccess in the folder administrator and placed the code at the end.
# Redirect plug id from 350 to 423:
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteCond %{QUERY_STRING} (^|&)option\=com_plugins($|&)
RewriteCond %{QUERY_STRING} (^|&)extension_id=\b(3[5-8][0-9]|39[0-9]|4[01][0-9]|42[0-3])\b($|&)
RewriteRule ^administrator/index\.php$ https://www.example.com/administrator/index.php? [L,R=302]
If the .htaccess file is inside the /administrator subdirectory then you need to remove administrator/ from the start of the RewriteRule pattern (1st argument), otherwise the rule will never match.
In .htaccess, the RewriteRule pattern matches against a relative URL-path to the directory that contains the .htaccess file.
In other words, it should look like this:
:
RewriteRule ^index\.php$ https://www.example.com/administrator/index.php [QSD,R=302,L]
Also, on Apache 2.4 you can use the QSD (Query String Discard) flag instead of appending an empty query string to remove the original query string.
The preceding conditions that match the query string and plugin id are OK and should match the requested URL. (Although the word boundary \b elements are unnecessary.)
Depending on what other directives you have, this rule should be near the top of the .htaccess file, not "at the end". Since you have used an absolute substitution string it would be more optimal to include these rules before your general canonical redirects (although this does assume you are not implementing HSTS).
You are also missing the RewriteEngine On directive from the rules in question.
So, it should look like this instead:
RewriteEngine On
# Redirect plug id from 350 to 423:
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteCond %{QUERY_STRING} (^|&)option\=com_plugins($|&)
RewriteCond %{QUERY_STRING} (^|&)extension_id=(3[5-8][0-9]|39[0-9]|4[01][0-9]|42[0-3])($|&)
RewriteRule ^index\.php$ https://www.example.com/administrator/index.php? [QSD,R=302,L]
# Redirect plug id from 425 to 10864:
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteCond %{QUERY_STRING} (^|&)option\=com_plugins($|&)
RewriteCond %{QUERY_STRING} (^|&)extension_id=(42[5-9]|4[3-9][0-9]|[5-9][0-9]{2}|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|10[0-7][0-9]{2}|108[0-5][0-9]|1086[0-4])($|&)
RewriteRule ^index\.php$ https://www.example.com/administrator/index.php [QSD,R=302,L]
# Canonical https/www
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Additional notes:
I assume you have not implemented HSTS.
I reversed the order of your two canonical redirects to reduce the number of redirects when requesting http://example.com/ (HTTP + non-www). But this does assume #1 above.
Optimised the regex on the canonical redirects... no need to traverse and capture the entire URL-path when using the REQUEST_URI server variable.
Removed the word boundary \b from the regex as this would seem unnecessary here.
I have successfully added the following code to my Apache HTTPD configuration:
# Force www.
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
# Force https (SSL)
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Although it works as expected, I have a theoretical question:
Why are there a ^ and $ in 3rd line enforcing "www.", and not in the 6th line enforcing "https"?
Sincerely, Dovid.
For both of your regex patterns ^(.*)$ and (.*) will behave same. However guess what, you don't need to use any of them. In fact it is far less error prone also to not to use .* and use %{REQUEST_URI} variable that matches full URI (not the relative one like .*). So I suggest change your rules to this:
# Force www.
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
# Force https (SSL)
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
Flag NE is used for not escaping. It is useful to have this flag in case your original URI has some special characters like # or (,),[,] etc.
^ in RewriteRule pattern above does nothing but returns true for every match since ^ means start position of a string and it will be always match.
Both rules can be combined into a single rule but it will look a bit complicated.
Here it is:
RewriteCond %{HTTP_HOST} !^www\. [NC,OR]
RewriteCond %{HTTPS} !on
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L,NE]
Here is the explanation of this rule:
RewriteCond %{HTTP_HOST} !^www\. [NC,OR]: if HOST_NAME doesn't start with www.
[NC,OR]: Ignore case match and ORs next condition
RewriteCond %{HTTPS} !on: HTTPS is not turned on
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]: This condition will always match since www. is an optional match here. It is used to capture substring of HTTP_HOST without starting www. by using (.+) pattern in capture group #1 (to be back-referenced as %1 later). Note that (?:..) is a non-capturing group.
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L,NE]: ^ will always match. This rule will redirect to https://www.%1%{REQUEST_URI} with R=301 code by adding https:// and www. to %1. %1 is back-reference of capture group #1 from RewriteCond, as mentioned above.
If using Apache's module mod_rewrite then you can define a RewriteRule.
RewriteRule uses a Regular Expression
The keyword or directive RewriteRule is followed by a Regular Expression (also known as RegEx or pattern). This RegEx (e.g. ^(.*)$) is used to match input URL's in order to rewrite them.
Regular Expressions are coded using special characters
Within a RegEx pattern ^ marks the start of the line to match, whereas the end is denoted by $.
Both are called metacharacters and have special meaning:
^: Matches the starting position within the string. In line-based tools, it matches the starting position of any line.
$: Matches the ending position of the string or the position just before a string-ending newline. In line-based tools, it matches the ending position of any line.
Why they often are obsolete?
Since URLs reaching the HTTP-server always are represented by one single line, these line-delimiting metacharacters can also be omitted without affecting the pattern/rewrite-rule.
They're the same. There's no difference between ^(.*)$ and (.*).
.* matches any string. ^ and $ don't change that since all strings have a start and end.
It depends if you made the certificate for the domain without www or with www.
In the provided example the redirection (6th line) is done to the domain without www. That guarantees that the correct certificate will be served and browser won't display an alert while visiting your site.
The first rule works fine when the maintenance file is in place. When it's not - the second rule is not redirecting to the specific URI. Is there an ordering issue of rules or ?
#########################################
RewriteCond %{DOCUMENT_ROOT}/server_maintenance.html -f
RewriteCond %{REQUEST_FILENAME} !/server_maintenance.html
RewriteRule ^.*$ /server_maintenance.html [L]
#########################################
## the %{HTTP_HOST} evaluates to the HTTP header with the name given in this case host.server.org, with NC being non case sensitive.
## it will rewrite the url at the server side to append the URI of lawson/portal
##########################################################################
RewriteCond %{HTTP_HOST} ^host\.server\.org$ [NC]
RewriteRule ^host\.server\.org$ "https\:\/\/host\.server\.org\/lawson\/portal" [L]
#########################################
You don't match a hostname in a RewriteRule, even so with more reason if you are already matching it in a previously defined RewriteCond.
So just do:
RewriteCond %{HTTP_HOST} ^host\.server\.org$ [NC]
RewriteRule ^ https://host.server.org/lawson/portal [L]
Note: RewriteRule target/destination is not regix so do not need to escape every single little thing.
Note2: a single ^ will match anything
I have setup a *.mydomain.com subdomain in cpanel (cpanel, no shell access)
Going to anything.mydomain.com gets me to the same directory which I mounted for *.mydomain.com
So when I go to test.mydomain.com with the following in .htaccess,
What works properly is:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(.+)\.(.+?\..+?)$ [NC]
RewriteCond %{REQUEST_URI} !^/test/(.+)?$
RewriteRule ^(.*) /%1/$1
What doesn't work and gives a 500 Error is this (Just replaced the test with %1):
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(.+)\.(.+?\..+?)$ [NC]
RewriteCond %{REQUEST_URI} !^/%1/(.+)?$
RewriteRule ^(.*) /%1/$1
What I want to do is allow dynamic setup of subdomains if a subdirectory with it's name exists. The rewriting is done gracefully when I hardcode the subdomain name test in the .htaccess and not when I use a backrefrence %1 for it.
You can't use a % variable or a backreference as part of the regular expression in a RewriteCond. You can create a string usimg a backreference and a # regex backreference:
RewriteCond %1:%{REQUEST_URI} !^([^:]+):/\1/(.+)?$
So you create a string made up of the subdomain of the host match, a colon, then the URI, match against the subdomain in your regex, and reference it using \1.
Additionally, you may need to add another %{HTTP_HOST} match right after because the %1 backreference might have gotten reset because you can't backreference a non match.
I have an apache vhost listening on port :443
I am trying to redirect any https requests back to http unless they meet the condition of being
from the domain www.site.co.uk
and contain either /alpha or /beta in the uri part of the request
I have the following statements in the config along with commented logic I though the process follows, but https://www.mysite.co.uk/alpha and https://www.mysite.co.uk/beta are being 301'd somehow
have I misunderstood the logic flow for conditional rewrites ?
RewriteEngine On
# if host submitted is not 'www.mysite.co.uk' un-https the url (i.e. catchall)
RewriteCond %{HTTP_HOST} !^www\.mysite\.co\.uk [NC]
RewriteRule ^(.*)$ http://%{HTTP_HOST}$1 [NC,L,R=301]
# otherwise IF THE domain is 'www.mysite.co.uk
# *and* if the uri does not contain 'alpha' *or* 'beta' un-https the url
RewriteCond %{HTTP_HOST} ^www\.mysite\.co\.uk [NC]
RewriteCond %{REQUEST_URI} !^\/alpha/? [NC,OR]
RewriteCond %{REQUEST_URI} !^\/beta/? [NC]
RewriteRule ^(.*)$ http://%{HTTP_HOST}$1 [NC,L,R=301]
# otherwise the domain must be www.mysite.co.uk
# and the uri must contain '/alpha' *or* '/beta'
# in which case do nothing
The rules that you have is a logical OR of URI not contains /alpha or /beta. You need all the conditions to be and'ed together. Just remove the [OR] flag:
RewriteCond %{REQUEST_URI} !^\/alpha/? [NC]
RewriteCond %{REQUEST_URI} !^\/beta/? [NC]
It's a logical negation expansion. Say A is /alpha and B is /beta. !A is thus not /alpha. So when you say !(A or B), if you expand the !, you get !A and !B.