Combine mod_rewrite rules - apache

In my .htaccess I've got the usual rewrite rules but I need to add a HTTP to HTTPS rule. If I put the new rule after the existing rules it does not work but putting it before works but then I suspect the vanilla WordPress code does not work.
I've put the rules together by adding the last two lines of the second rule to the end of the first one but that does not work either. I'm not sure what I'm doing!
What is the best way to combine these two?
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://127.0.0.1/$1 [R,L]
</IfModule>

The ruleset that's responsible for ensuring https is doing an external redirect, while the other one (wordpress) is doing internal rewrites.
It's often a good practice to first put the external redirects (if they don't depend on any previous internal rewrite).
Note the L flag:
The [L] flag causes mod_rewrite to stop processing the rule set. In most contexts, this means that if the rule matches, no further rules will be processed. This corresponds to the last command in Perl, or the break command in C. Use this flag to indicate that the current rule should be applied immediately without considering further rules.
If you put wordpress rewrite rules before the https ruleset, the rewrite engine will never get to the second ruleset. That's because of the L flag that instructs the rewrite engine to stop processing of any other rules. This reason aside, you don't want to rewrite the request to wordpress' index.php and then ensure that it's https using an external redirect (R flag), right?
So, you might want to try this:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
# HTTPS:
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://127.0.0.1/$1 [R,L]
# WordPress:
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
Few final notes:
You only need one RewriteEngine on and one IfModule.
It's better to use a 301 redirect for https and www redirects. (R=301)

Related

.htaccess 301 redirect with exclusion does not work

I try to use a simple 301 redirect
from domain1.com/folder/ to domain2.com/
but excluding domain1.com/folder/subfolder
I use the following code in .htaccess:
RedirectMatch 301 ^/folder/((?!subfolder).*)$ https://domain2.com/$1
but it simply redirects all the requests, including the requests to subfolder.
Please, help to fix the line to make it work as described. Thank you!
here is the complete code of .htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /folder/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /folder/index.php [L]
</IfModule>
RedirectMatch 301 ^/folder/((?!subfolder).*)$ https://domain2.com/$1
Try it like this using mod_rewrite instead:
(NB: This assumes the .htaccess file is located in the document root.)
# /.htaccess
# Redirect all direct requests, except "subfolder"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond $1 !^subfolder($|/)
RewriteRule ^folder/(.*) https://domain2.com/$1 [R=301,L]
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /folder/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /folder/index.php [L]
</IfModule>
It is important that the redirect goes before the rewrite to your front-controller.
You will need to ensure your browser cache is cleared before testing and test with a 302 (temporary) redirect to avoid potential caching issues.
UPDATE:
Yes, /folder has it's own .htaccess (this is the file I am working at all this time). Yes, /folder is where Wordpress is installed.
In that case you would need to change the above redirect to read as follows (it won't do anything otherwise):
# /folder/.htaccess
# Redirect all direct requests, except "subfolder"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond $1 !^subfolder($|/)
RewriteRule (.*) https://domain2.com/$1 [R=301,L]
Basically, you need to remove folder/ from the start of the regex that matches the URL-path. The URL-path that the RewriteRule pattern matches against is relative to the directory that contains the .htaccess file.
The addition of the check against the REDIRECT_STATUS env var is to ensure that rewritten requests to the WP front-controller (when subfolder is requested) are not redirected.
You can also "simplify" the WordPress directives that follow (although if these are enclosed in # BEGIN WordPress / # END WordPress comment markers then you should leave the directives as they are since they are maintained by WordPress). For example:
RewriteEngine On
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
The RewriteBase directive is not required. And neither is the <IfModule> wrapper. (But as I said above, only change this if you are hand-coding the .htaccess and not letting WordPress maintain it.)

override apache rewrite rules with htaccess

working on a server that hosts multiple domains.
Somewhere in apache config is a rewrite rule that is set for ALL domains.
What happens is if a user goes to example.com/foo they are supposed to get redirected to example.com/foo_bar
However, in one domain, I want to override this behavior so that the url stays at example.com/foo and does not redirect. I've been searching and trying various rules and conditions to no avail. I don't have access to the apache config, but I am using .htaccess for some rewrite rules on this domain.
here's my rewrite rules in .htaccess:
<IfModule mod_rewrite.c>
RewriteEngine on
# this isn't working
# RewriteRule ^(foo)($|/) - [L]
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?/$1
# this didn't work either
# RewriteRule ^/foo index.php?/$1 [L]
</IfModule>
Try redirecting /foo_bar back to /foo.
When Apache processes the rewrite rules it runs through them multiple times, which you can see when you turn on debugging. I think what's happening in your case is that you're trying to match the URI in the first pass, but Apache has already modified it to /foo_bar.
Also, as a matter of debugging, you should try to recreate the problem in an environment you control. Ask your sysadmin for a copy of the global configuration and mirror the set up you're constrained to.
You can create exception for one domain:
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_HOST} !^(?:www\.)?domain\.com$ [NC]
RewriteRule ^foo(/.*)?$ /foo_bar$1 [L,R=302]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?/$1 [L,QSA]

mod_rewrite - redirect a page to index

I'm looking prevent people from accessing login URLs on certain servers.
Ideally I want a solution without having to reference the domain (there are many domains, and many server environments), and I'd like to put the rule within the global httpd.conf, rather than individual vhosts.
I've tried all kinds of mod_rewrite, to no avail, or terrible performance, eg;
RewriteRule ^/login$ /index.php [R,L]
RewriteRule ^login/?$ $1/$2 [R=301,L]
One caveat is that it needs to work with my URL rewrites;
<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>
..and in short, I want these;
http://mysite.co.uk/login
http://mysite.co.uk/index.php/login
to go here;
http://mysite.co.uk/
The below should redirect the examples you provided to your site root:
RewriteEngine On
RewriteRule ^/(index.php/)?login/?$ / [R,L]
As long as you place them before your existing rules, they should do what you want.

Redirecting all Requests on a Domain to a Specific URL

It's been a long time since I've used Apache (a very long time) and even then I didn't really do much URL rewriting or anything like that, just simple hosting. But now I'm trying to piece together a simple redirect for a small business that's re-branded to a new domain.
The way it's set up is that the host for the old domain has a web control panel based redirect to a specific URL, which is a "looking for the old us?" page on the new domain. All requests are redirected, but they carry with them the entire request path which results in a 404 on the new site.
I've been looking through some Apache documentation and some examples I can find online, but I'm not quite there yet. Where I've left off so far is with something like this:
RewriteCond %{REQUEST_URI} .*looking-for-blah.* [NC]
RewriteRule ^ http://newsite.com/looking-for-blah [L,R=301]
The idea is that any request coming in for any path which contains looking-for-blah, regardless of what's before or after it, should go to the explicit http://newsite.com/looking-for-blah. So when the old host redirects somebody to:
http://newsite.com/looking-for-blah/foo/baz
They get redirected by the new site to:
http://newsite.com/looking-for-blah
However, it doesn't seem to be catching the incoming requests and redirecting them. Am I missing some fundamental concept in the RewriteCond? Maybe there's a better way to do this that I haven't even considered?
Edit: Here's the current state of the .htaccess as a whole:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
# BEGIN custom redirect
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule looking-for-icamp http://empow.me/looking-for-icamp [L,R=301]
</IfModule>
# END icamp redirect
But doing a simple wget on http://empow.me/looking-for-icamp/foo results in a 404 instead of the desired 301.
The Wordpress default catch-all routing is matching your rule before it can be reached, so your rule will need to be placed above any Wordpress rewrites. I also added a RewriteCond to be more explicit about the circular rewrite avoidance than your .+ trick, which seems a little hacky to me and would be hard to understand on later readings.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# BEGIN custom redirect
# This must take place before the Wordpress redirect to index.php
# Added condition to avoid circular rewrite
RewriteCond %{REQUEST_URI} !^/looking-for-icamp$
RewriteRule looking-for-icamp http://empow.me/looking-for-icamp [L,R=301]
# END icamp redirect
# Note - you had two identical WP blocks. I've removed one.
# BEGIN WordPress
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# This rule was the one blocking your custom rule earlier....
RewriteRule . /index.php [L]
# END WordPress
</IfModule>

mod_rewrite equivalent of a RedirectMatch rule

I have a RedirectMatch rule in my .htaccess file that works fine, but I'm having trouble coming up with a comparable rule using mod_rewrite.
My goal is to have this URL: mysite.com/anything/print show this page: mysite.com/anything?view=print.
The rule that works to Redirect it is this:
RedirectMatch 301 ^(.*)/print/?$ http://mysite.com/$1?view=print
But now I'd like to change this from a visible 301 redirect to an "invisible" rewrite using mod_rewrite. I have tried many different variations on this (with and without RewriteBase), and none have worked:
RewriteEngine On
RewriteBase /
RewriteRule ^(.*)/print/? $1?view=print
What am I doing wrong? Mod_rewrite is definitely enabled, and there are functioning Wordpress-based mod_rewrite rules in the same .htaccess file.
UPDATE
Using tips from #Nathan, I now have this. However, I still get a 404 when I visit mypost/print.
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteRule ^(.*)/print/?$ /index.php/$1?view=print [L]
When I append /print/ to a permalink, the WP_Debug plugin indicates the following:
Request: myposttype/mypost/print
Query String: attachment=print
Matched Rewrite Rule: myposttype/[^/]+/([^/]+)/?$
Matched Rewrite Query: attachment=print
If you have typical wordpress rules in the htaccess file, your rules should come before the # BEGIN WordPress block. Otherwise the wordpress rules will stop the rewrite matching before your rules get called.
Also, you should add $ after your regex pattern unless you also want to match something like: http://domain.com/page/print/something/else/here
Lastly, in order for Wordpress to recognize the change in the URL without redirecting the page, you need to append the URL to index.php/ so that Wordpress will use path info permalinks.
E.g.
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteRule ^(.*)/print/?$ /index.php/$1?view=print [L]
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
RewriteEngine on
RewriteRule ^(.*)/print/$ /$1?view=print [L]
or
RewriteRule ^(.*)/print$ /$1?view=print [L]
without "/" in the end of URL string