Enforce HTTPS across thousands of 301 RewriteRule entries - apache

community. I'm migrating an ancient ColdFusion site (seriously), and we have literally thousands of 301 redirects from old versions of pages like
index.cfm?id=1&this=that
to more reasonable counterparts like
/what-this-page-really-is
Google says to list them out one by one, so that's what I'm doing. However, on ALL of these redirects we also want to enforce HTTPS. What we have now is this:
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
RewriteRule ^thing.cfm$ /thing/? [R=301,L,NC]
RewriteCond %{QUERY_STRING} id=1 [NC]
RewriteRule ^blah.cfm$ /awesome-sauce/? [R=301,L,NC]
It works fine, but Google complains that it's technically two redirects for these old links. A possible solution would be to exclude *.cfm files from the HTTPS redirect and explicitly make every single *.cfm redirect go to the HTTPS version of the page, like so:
RewriteCond %{SERVER_PORT} 80
RewriteCond %{REQUEST_URI} !(.*)cfm$
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
RewriteRule ^thing.cfm$ https://%{HTTP_HOST}/thing/? [R=301,L,NC]
RewriteCond %{QUERY_STRING} id=1 [NC]
RewriteRule ^blah.cfm$ https://%{HTTP_HOST}/awesome-sauce/? [R=301,L,NC]
But over thousands of lines, that's a lot of extra characters in an .htaccess file. I know this is better in apache config, but I don't have that option right now.
My question: is there a way to set a flag that's going to apply the HTTPS parameter to ALL of the subsequent *.cfm 301 redirects?
Thank you!

Rather than enforcing https:// in each 301 handler you can move your http->https rule at the bottom and remove R flag from your redirect flags so that Google (or any external client) gets only one single redirect.
RewriteEngine On
RewriteRule ^thing\.cfm$ /thing/? [L,NC]
RewriteCond %{QUERY_STRING} id=1 [NC]
RewriteRule ^blah\.cfm$ /awesome-sauce/? [L,NC]
# all other rules here but remove R=301 flag
# finally do a http->https with rewritten URI
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L,NE]
Make sure to clear your browser cache before testing.

Related

Using APACHE REWRITE To Force One Specific Page To Be HTTP (.htaccess)

I have tried using some rewrite to change my /welcome.php page to http. it is located in the root directory, but what I have done has seemingly forced all pages on my site to http instead of just the one. Here is what I have tried:
RewriteEngine On
#Force remove WWW
RewriteCond %{HTTP_HOST} ^www.w5unt.ga
RewriteRule (.*) http://w5unt.ga/$1 [R=301,L]
#Redirect HTTPS to HTTP
RewriteCond %{HTTP:X-Forwarded-Proto} =https
RewriteRule ^(.*)$ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
As you can see I am also force removing WWW from all urls at the same time I am trying to force my one page (welcome.php) to be http. I believe the error is in this bit of code
RewriteRule ^(.*)$ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
However I am not sure how to syntactically correct my issue, any advice?
Try with below I've edited the part of your rule and made a check to exclude welcome.php.
RewriteEngine On
#Force remove WWW
RewriteCond %{HTTP_HOST} ^www.w5unt.ga
RewriteCond %{REQUEST_URI} !^/welcome.php
RewriteRule (.*) https://w5unt.ga/$1 [R=301,L]

Simple htaccess mod rewrite

I have multiple domains that end with .nl .com and .de. For each domain name I have a different language. My files are on the .nl domain. What I would like is the following for all domains:
Redirect http://* to https://*
Redirect http://example.* to https://www.example.*
I Have the files on 1 server, and want them to look like it is on 3.
This is what I have on the main server (.NL)
RewriteCond %{HTTP_HOST} !www.example.nl$ [NC]
RewriteRule ^(.*)$ https://www.example.nl/$1 [L,R=301]
And this for the .DE
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://www.example.de/$1 [L,R=301]
RewriteCond %{HTTP_HOST} !www.example.de$ [NC]
RewriteRule ^(.*)$ http://www.example.de/$1 [L,R=301]
RewriteRule ^(.*)$ http://www.example.nl/$1 [P]
And this for the .COM
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://www.example.com/$1 [L,R=301]
RewriteCond %{HTTP_HOST} !www.example.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]
RewriteRule ^(.*)$ http://www.example.nl/$1 [P]
I've tried everything, but I could not figure it out.
# This rule will redirect users from their original location, to the same location but using HTTPS.
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://www.example.nl/$1 [R=301,L]
#primary site redirect
RewriteCond %{HTTP_HOST} !^www\.example\.nl [NC]
RewriteRule (.*) https://www.example.nl/$1 [R=301,L]
I believe that's all that's required, as you can see, you first redirect ALL requests that are not https to https example.nl, then you redirect anything that is NOT www.example.nl to https://www.example.nl
If I'm guessing wrong about what you need with [P] you can just replace I think [R=301,L] with [P], though I've never dealt with that configuration so I can't say for sure, but it's easy to test.
https://wiki.apache.org/httpd/RewriteHTTPToHTTPS
this is more or less what we use for https. I think you're getting confused and not realizing that all you need to know is that something is NOT example.nl/$1, there's no need to list all those nots, since all of them are not example.nl/$1
Note the following, which are all NOT the second rule, all will get redirected:
https://example.nl
https://www.example.com
https://example.de
https://www.example.de
Since these are all not:
https://www.example.nl
they get redirected. (.*) means everything, including /.
There's a subtle thing that you need to be aware of with https, you have to have a certificate for ALL versions of all the domains, that's www/non www, or you get those browser alert popups for any initial domain/subdomain that does not have certificate support when the page initially loads. For example, if you don't have a certificate for example.com but you have one for www.example.com if a url comes in: http://example.com you'll get that browser alert, which is very bad for usability and makes it look like it's a scammer site.
I can't remember the exact ordering of processing, but I think that's how it works.

Redirecting a domain with htaccess with a few specific 301s

Is it possible to do something like this to redirect old traffic to the new site with a 301.
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !new-example.com$ [NC]
RewriteRule ^(.*)$ http://new-example.com/$1 [L,R=301]
However, I will need to manually map some pages to their new equivalent pages like
Redirect 301 /about http://new-example.com/about-us
Is it possible to do both?
If you are going to use Rewrite, then use it only. I don't recommend use both mod-alias and mod-rewrite. You can use rewrite to map to individual pages too. Also the order matters. The catchall rule should be the last one. This would provide cleaner code IMO.
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !^new-example.com$ [NC]
RewriteRule ^about/?$ http://new-example.com/about-us [R=301,L]
RewriteCond %{HTTP_HOST} !new-example.com$ [NC]
RewriteRule ^(.*)$ http://new-example.com/$1 [L,R=301]

How to avoid chain redirections using mod_rewrite?

Basicly i'm working on my site to be SEO-friendly. I wanted to achieve following:
Rewrite urls to pretty ones
Remove multiple slashes (eg. example.com/////something/// to example.com/something/
Redirect www version to a non-www version.
Hide index.php file from all urls
Redirect from old (/?id=something/ to new urls /something/)
I came up with this .htaccess code:
RewriteCond %{THE_REQUEST} //
RewriteRule .* $0 [R=301]
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteCond %{QUERY_STRING} ^id=([a-z0-9\/-]+)
RewriteRule ^(.*)$ http://example.com/%1? [R=301]
RewriteRule ^index.php(.*)$ /$1 [R=301]
RewriteRule ^([a-z0-9\/-]+)$ /?id=$1 [L]
...and though it's working it has a side effect: chain redirects, eg. example.com/?id=something////// -> example.com/something////// -> example.com/something/
So is there a way to rewrite or modify this code so it'll be redirecting just once to the preferred version of the url?
Trying to interpret what you want, let's look at the rules in your question:
.1 Can't understand the purpose of this:
RewriteCond %{THE_REQUEST} //
RewriteRule .* $0 [R=301]
.2 This rule-set in your question removes www and converts the query string ?id=val to /val, but only when the incoming URI has www AND there is a query string as both conditions must be met:
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteCond %{QUERY_STRING} ^id=([a-z0-9\/-]+)
RewriteRule ^(.*)$ http://example.com/%1? [R=301]
.3 This rule
RewriteRule ^index.php(.*)$ /$1 [R=301]
Hides index.php, but only when it is in the root directory. Example:
http://www.example.com/index.php?id=val
Does not work when it is in a subdirectory. Example:
http://www.example.com/folder/index.php?id=val
.4 Can't understand the purpose of this:
RewriteRule ^([a-z0-9\/-]+)$ /?id=$1 [L]
I suggest this instead:
RewriteEngine On
RewriteBase /
#Redirects all www to non-www
RewriteCond %{HTTP_HOST} www\.example\.com$ [NC]
RewriteRule ^(.*)/?$ http://example.com/$1 [R=301,L]
#Hides "index.php" keeping the query if present
RewriteRule ^(.*)/index\.php$ $1/ [R=301,QSA,L]
#Converts query string `?id=val` to `/val`
RewriteCond %{QUERY_STRING} id=([^/]+)
RewriteRule .* /%1? [R=301,L]
Remember spiders will "adapt" to the correct new structure after a few months, and the problem may ultimately be a whole lot less severe than what it looks like initially. You can leave all the .htaccess code in place, knowing it always be there to correct any "old" references yet will in fact hardly ever actually be used.
I've never found an easy way to avoid multiple round trips back to the client when "fixing up" a URL to be in some sort of canonical form. mod_rewrite seems to be more focussed on the "local" redirect case where the client has no idea that the content it got back came out of a file structure that doesn't perfectly match that implied by the URL.
It is possible to save up all the URL mods locally, then provoke only one round trip to the client that delivers all the URL corrections all at once by setting everything in newly created "environment" variables then at the end asking basically "has anything changed?" However doing so is notably verbose and rather awkward and quite error-prone and has never become a "recommended technique".

htaccess for redirect to SSL

For the past few hours (days) I have been having some trouble redirecting a
page to SSL.
My setup is as follows: I have the following .htaccess for an e-commerce site
on Apache 2.2.16 on Debian (all required mods enabled)
RewriteEngine On
RewriteBase /shop
RewriteCond $1 !^(index\.php|products|img|theme\.php|checkout\.php)
RewriteRule ^(.*)$ index.php?/$1 [L]
all requests are passed to index.php which acts as my controller and includes
other .php files as necessary.
I now want to use HTTPS for the checkout process which is a php script
cleverly called checkout.php
I thought it would be as easy as changing my .htaccess to:
RewriteEngine On
RewriteBase /shop
RewriteCond %{SERVER_PORT} !^443$
RewriteCond %{SERVER_URI} checkout\.php
RewriteRule ^checkout.php?/$1 https://localhost/shop/checkout.php?/$1 [L,R]
RewriteCond $1 !^(index\.php|products|img|theme\.php|checkout\.php)
RewriteRule ^(.*)$ index.php?/$1 [L]
so that checkout.php is not processed by index.php.
Apparently it is not that simple. I could probably do it by using a hardcoded
https link to checkout but I would prefer to do it with mod_rewrite.
If anyone can share some insight into
this it would be really appreciated.
Thanks in advance
There are a few problems. First, the pattern in your first RewriteRule
RewriteRule ^checkout.php?/$1 https://localhost/shop/checkout.php?/$1 [L,R]
is written incorrectly. $1 isn't meaningful there (it's a capture result, but no capture has happened yet), and also the query string (part of the request after the ?) isn't part of what's matched, as the RewriteRule documentation says.
Second, I think you meant to use REQUEST_URI instead of SERVER_URI.
So I think you want something like this:
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} ^/checkout\.php
RewriteRule .* https://localhost/shop/checkout.php [L,R]
RewriteCond %{REQUEST_URI} !^/(index\.php|products|img|theme\.php|checkout\.php)
RewriteRule ^(.*)$ /index.php?/$1 [L]
A few notes:
You don't need to match or add back in the query string in the first RewriteRule; mod_rewrite will automatically add it back in.
It's conventional to test RewriteCond %{HTTPS} off instead of
RewriteCond %{SERVER_PORT} !443, as #Jon Lin suggests.
You may want to add the QSA flag in your second RewriteRule.