Non www to www redirect doesn't removes trailing backslash - apache

I'm having a bit of problem with Apache redirect.
While bellow rules work for any page on site, mydomain.com will get redirected to mydomain.com//, which ignores trailing slash removal rule.
Also is it efficient to use multiple rules such as this or should I try to combine them or chain them somehow together in order to avoid multiple redirects for single url?
Thanks
#Turn on options for url rewriting
Options +FollowSymlinks
RewriteEngine on
#lovercase all urls
RewriteMap lc int:tolower
RewriteCond %{REQUEST_URI} [A-Z]
RewriteCond %{REQUEST_URI} ^/fonts/.*
RewriteCond %{REQUEST_URI} ^/css/.*
RewriteCond %{REQUEST_URI} ^/js/.*
RewriteRule (.*) ${lc:$1} [R=301,L]
#redirect all requests made to http:// to http://www.
RewriteCond %{HTTP_HOST} ^mydomain\.com$ [NC]
RewriteRule ^(.*)$ http://www.mydomain.com/$1 [R=301,L]
#removes trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_HOST} !^\.localhost$ [NC]
RewriteRule ^(.+)/$ http://%{HTTP_HOST}$1 [R=301,L]

The reason the mydomain.com gets redirected to www.mydomain.com// is because you have an extra "/" in your rewrite rule target:
RewriteRule ^(.*)$ http://www.mydomain.com/$1 [R=301,L]
^----here
When you have rules in your server/vhost config, the leading slash isn't removed so that gets match and used as a backreference, so mydomain.com is / which matches ^(.*)$ and the target becomes http://www.mydomain.com//. So you can either remove the slash in the target or add one to the regex:
RewriteRule ^(.*)$ http://www.mydomain.com$1 [R=301,L]
or
RewriteRule ^/(.*)$ http://www.mydomain.com/$1 [R=301,L]
Your other rule you have:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_HOST} !^\.localhost$ [NC]
RewriteRule ^(.+)/$ http://%{HTTP_HOST}$1 [R=301,L]
are fine. They are for removing trailing slashes when there is something between them, e.g. /something/, because of the (.+). It wouldn't match // anyways because that inherently gets turned into just /. You just need to prevent redirecting to http://www.mydomain.com//

Related

.htaccess - remove everything after third slash in path

On my website, I only use 3 slashes in my URL path:
https://example.com/this/isatest/
Right now I use .htaccess which makes it possible (as a side effect) to add as many stuff on the URL as you like:
https://example.com/this/isatest/hipperdihopperdus/pizza/bacon/with/cheese
I'd like to automatically remove everything after "isatest" while keeping the trailing slash using .htaccess.
This is what my .htaccess currently looks like:
Options -Indexes
Options +FollowSymLinks
RewriteEngine on
# 301 Redirect all requests that don't contain a dot or trailing slash to
# include a trailing slash
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{REQUEST_URI} !\.
RewriteRule ^(.*) %{REQUEST_URI}/ [R=301,L]
RewriteCond %{THE_REQUEST} /index\.html [NC]
RewriteRule ^index\.html$ /? [R=301,L,NC]
RewriteRule ^listen/$ /console/ [NC,L]
# Rewrites urls in the form of /parent/child/
# but only rewrites if the requested URL is not a file or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?page=$1 [L,QSA]
How can I achieve this?
As your first rule, after the RewriteEngine directive, you can do something like the following:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]+/[^/]+/). /$1 [R=302,L]
This checks if there is anything else (the dot) after two path segments and a slash, and redirects to removed "anything else".
Note that this is a 302 (temporary) redirect. Only change this to a 301 (permanent) redirect - if that is the intention - once you have confirmed that it works OK. This is to avoid the browser caching erroneous redirects whilst testing.
UPDATE: It may be more efficient to simply avoid redirecting files that end in a recognised file extension. Or perhaps exclude known directory location(s) of your static resources. For example:
RewriteCond %{REQUEST_URI} !\.(css|js|jpg|png|gif)$ [NC]
RewriteRule ^([^/]+/[^/]+/). /$1 [R=302,L]
OR,
RewriteCond %{REQUEST_URI} !^/static-resources/
RewriteRule ^([^/]+/[^/]+/). /$1 [R=302,L]
You can add this rule just below RewriteEngine On line:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+/[^/]+/).+$ /$1 [R=301,L,NE]

Htaccess Redirects - Combine many rules in one single redirect

I am trying to combine more rules in a single redirect, right now I have many rules and many redirects, like in the picture attached, but for SEO purpose this is not a good behavior.
The story is this: I have an old url, which doesn't exist anymore and a new one, where I want to be redirected. If the requested url doesn't have www. and https then I want to add them.Also if the url has an slash at the end, I want to remove it.
All is working right now, but in many steps.
This is what I have in my .htaccess file:
301 redirect from old url to the new one with www.
RewriteRule ^source1/source2$ https://www.domain.com/destination1/destination2 [L,R=301]
Remove the slash from the end of URL
RewriteCond %{REQUEST_URI} !^/system [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)/$ /$1 [R=301,L,QSA]
Redirect to https
#-----------------redirect to https-----------------
RewriteCond %{HTTPS} !on [OR]
RewriteCond %{HTTP_HOST} !^www.domain.com(.*)$ [NC]
RewriteRule (.*) https://www.domain.com%{REQUEST_URI} [L,R=301]
I use all of these rules inside this directive:
<IfModule mod_rewrite.c>
Have it like this to avoid multiple 301 for SEO purpose:
# specific redirects
RewriteRule ^source1/source2/?$ https://www.domain.com/destination1/destination2 [L,R=301,NC]
# Remove the slash from the end of URL
RewriteCond %{REQUEST_URI} !^/system [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ https://www.domain.com/$1 [R=301,L,NE]
#-----------------redirect to https-----------------
RewriteCond %{HTTPS} !on [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.domain.com%{REQUEST_URI} [L,R=301,NE]
Make sure to clear your browser cache completely before testing this change.

How can I direct all pages except one to HTTPS in an htaccess?

Currently I am redirecting all pages to https using the following htaccess directive:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
But I have one page, http://foo.bar/baz which needs to be accessed http-only. Using an htaccess directive, how can I redirect to https on all pages except this one, where users are forced to http?
Edit: I should have mentioned that this is a Laravel 4 application, and I currently also have the following rules to handle the front-controller
# Redirect Trailing Slashes...
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
You can use a negative regex pattern in RewriteRule:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{THE_REQUEST} !/baz[/?\s] [NC]
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,NE,L]
RewriteCond %{HTTPS} on
RewriteCond %{THE_REQUEST} /baz[/?\s] [NC]
RewriteRule ^ http://%{HTTP_HOST}%{REQUEST_URI} [R=301,NE,L]
RewriteRule ^index\.php - [L,NC]
# Redirect Trailing Slashes...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301,NE]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
A negative lookahead works especifically for these cases when you want one or more exceptions:
RewriteRule ^(?!baz)(.*) https://%{HTTP_HOST}/$1 [R,L]
This basically says, redirect everything except baz.
SideNote: Remember ".htaccess" is not some sort of rewrites depot for Apache, if you have access to the config in the virtualhost, make sure to add these rewrites in there. htaccess adds overhead and complexity.

RewriteRule ssl conf combining various

I need to Rewrite every Dir to https, www and trailing slash and for SEO i need every redirect with only one 301.
The first twoo are solved, but the third doesn't work if de URW comes with www (it returns a 302 if a URL exist, and then write de trailing slash), but i've a rule to handle that case, can you see something wrong?
ssl.conf:
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\.
RewriteCond %{REQUEST_URI} !^/(.*)\.(.*)
RewriteCond %{REQUEST_URI} !^(.*)/$
RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI}/ [L,R=301]
RewriteCond %{HTTP_HOST} !^www\.
RewriteCond %{REQUEST_URI} ^/(.*)\.(.*)
RewriteCond %{REQUEST_URI} ^(.*)/$
RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} ^www\.
RewriteCond %{REQUEST_URI} !^/(.*)\.(.*)
RewriteCond %{REQUEST_URI} !^(.*)/$
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI}/ [L,R=301]
It was my fault, the rules above works fine, the problem was with my hosts file that hadn't the www entry to test.
I leave the Rule for help anyone if needed.

Rewrite to add a trailing slash, but independent of domain?

I'm using Apache and mod_rewrite to rewrite URLs for my web app. You can see it here:
RewriteEngine On
RewriteBase /
# www. to non-www.
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
# Redirect non-existant files so there's a trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ $1/ [R=301,L]
# Send the URL to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L,QSA]
All working fine, but the problem is the trailing slash rewrite. It works when I'm at the root of the domain, but in my staging environment I'm running this app within a subdirectory. I'm having to modify the RewriteBase directive to include the subdirectory or the rewrite fails.
I'm looking for a solution that will add a trailing slash to the URL - regardless of whether the app is running on the root of the server, without having to change the RewriteBase. Thanks in advance.
After poking around and some help by #MortBM, looks like the below works well:
RewriteEngine On
# www. to non-www.
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
# Add a trailing slash to any non-existent files
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ %{REQUEST_URI}/ [R=301,L]
# Send the URI to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [QSA,L]
Summary: removing the RewriteBase, and using %{REQUEST_URI} within the redirect did it :)