Minimal .htaccess code for a set of redirection rules - apache

I want to achieve the following behavior with the least number of rules:
Enforce HTTPS
Redirect www to non-www
Remove .php and .html extensions from all URLs
Redirect example.com/index.php and example.com/index to example.com
Redirect example.com/static/*.html to example.com/*
Remove trailing slashes
Right now I use the following rules:
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
RewriteRule ^ /%1 [R=301,L]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.*?)/?$ /$1.html
RewriteCond %{THE_REQUEST} ^.*/index
RewriteRule ^(.*)index /$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [R=301,L]
which don't include a rule for the static directory as I don't have introduced it yet. I plan to do it for caching reasons now.

Related

How to resolve conflicting mod_rewrite rules and conditions

I have a couple of rewrite rules in my .htaccess that seem to be conflicting.
I am running an ExpressionEngine (CodeIgniter) website that resolves all URI's using an index.php file. I have removed the index.php from the URI's for aesthetic reasons.
What I am trying to achieve:
Redirect 301 all pages with a trailing slash (example.com/bla/ =>
example.com/bla)
Remove index.php from all URI's
What I have now:
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{SERVER_ADDR} !=127.0.0.1
RewriteCond %{SERVER_ADDR} !=::1
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond $1 !^(images|system|themes|index\.php|admin\.php|favicon\.ico|robots\.txt|humans\.txt|crossdomain\.xml) [NC]
RewriteRule ^(.*)$ index.php/$1 [L]
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]
</IfModule>
What works:
All deeplinks are redirected to their non-trailing-slash version
(example.com/bla/ => example.com/bla).
index.php is removed from all deeplink pages.
What does not work:
The homepage (example.com) gives me an error in Google Chrome, saying "Too many redirects".
How do I update the conditions and rules so that I achieve clean links without a trailing slash, and without index.php, regardless of which page it is.
Have it like this:
RewriteCond %{HTTPS} !=on
RewriteCond %{SERVER_ADDR} !=127.0.0.1
RewriteCond %{SERVER_ADDR} !=::1
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteRule ^(.*?)index\.php(/.*)?$ /$1$2 [R=301,NE,L]
RewriteCond $1 !^(images|system|themes|index\.php|admin\.php|favicon\.ico|robots\.txt|humans\.txt|crossdomain\.xml) [NC]
RewriteRule ^(.*)$ index.php/$1 [L]
Clear your browser cache before testing.

.htaccess force to SSL and remove filename extensions

I am trying to rewrite my URL at the moment using .htaccess basically I want to force all connections to https:// and also remove any trailing .html extensions.
Here is what I have so far,
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R,L]
RewriteCond %{HTTP_HOST} ^www.%{HTTP_HOST}$ [NC]
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1 [R=301,L]
RewriteRule ^([^\.]+)$ $1.html [NC,L]
This forces the user to use https but it does not remove the .html from the URL where am I going wrong?
You need an additional rule to strip off .html from URLs. Moreover you can combine that rule and www and https rules into one to avoid mumtiple 301 redirects:
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC,OR]
RewriteCond %{THE_REQUEST} \.html[\s?] [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^(.*?)(?:\.html)?$ https://%1/$1 [R=301,L,NC,NE]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+?)/?$ $1.html [L]

Merge into one rewrite rule: removal of trailing slashes, and www

How may I merge the removal of the trailing slash, and the www re-write rules?
RewriteEngine on
# prevent redirect loop on directory
DirectorySlash Off
# remove the trailing slash
RewriteRule ^(.*)/$ /$1 [L,R=301]
# remove www. (generic method with HTTPS support)
RewriteCond %{HTTP_HOST} ^www\.
RewriteCond %{HTTPS}s ^on(s)|off
RewriteCond http%1://%{HTTP_HOST} ^(https?://)(www\.)?(.+)$
RewriteRule ^ %1%3%{REQUEST_URI} [R,L]
# send everything (except existing files) to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
I use to do this, but the removal of www. didn't support https:
# removes www. and trailing slash
RewriteCond %{REQUEST_URI} /$ [OR]
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*?)/?$ http://%1/$1 [R=301,QSA,NC,L]
Maybe you can try it this way to support https.
# removes www. and trailing slash and add https
RewriteCond %{REQUEST_URI} /$ [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC,OR]
RewriteCond %{HTTPS} !^on
RewriteRule ^(.*?)/?$ https://yoursite.com/$1 [R=301,QSA,NC,L]
To do all that in one rule and to make it work across the hostname (including localhost) you can use this code in root .htaccess:
RewriteEngine On
# hostname without www
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ - [E=host:%1]
RewriteCond %{REQUEST_URI} /$ [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTPS}s on(s)|
RewriteRule ^(.+?)/?$ http%1://%{ENV:host}/$1 [R=302,NE,L]

mod_rewrite rules for my site

I have these rules on my site:
RewriteCond $1 !^(support|about-us|profile|support|features|videos|terms-of-service|about-us|signup|media|includes|modules|cgi-bin|templates|xmlrpc|language|libraries|plugins|administrator|component|images|dev|data)
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([a-z0-9\-]+)/[^\ ]*\ HTTP/
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule ^([a-z0-9\-]+)/(.*)$ https://$1.example.com/$2 [R=301,L]
#
RewriteCond %{HTTP_HOST} ^([a-z0-9\-]+)\.example\.com
RewriteCond %1 !^www\.
RewriteRule ^(support|about-us|profile|support|features|newserver|videos|about-us|terms-of-service|signup|component|includes|media|cgi-bin|templates|xmlrpc|language|modules|libraries|plugins|administrator|images(/.*))$ https://example.com/$1 [R=301,L]
# Externally redirect all www hostnames to non-www hostnames
RewriteCond %{HTTP_HOST} ^(([a-z0-9\-]+\.)*)www\.(([a-z0-9\-]+\.)*)example\.com
RewriteRule ^(.*)$ https://%1%3example.com/$1 [R=301,L]
I added these below to redirect these types: https://example.com/firstnamelastname?mv=0 etc
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com$ [NC]
RewriteCond %{QUERY_STRING} ^mv=[0-4]$
RewriteRule ^([A-Za-z0-9]+)$ https://$1.example.com/? [L,R]
However I cannot get these to redirect https://example.com/firstnamelastname
If i remove the Query string from the last 3 lines then If i would click on features link on my website It would redirect to https://features.example.com which is what the rules at the top are preventing.
Can anyone assist with this.

.htaccess - force www, trailing slash and remove extension

I've been playing about with my .htaccess file and so far, it's working, but there's a few bugs.
I'm trying to force the WWW prefix (just the root, not on subdomains) while removing the .php extension and adding a trailing slash.
Code
# Force WWW prefix
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Remove .php extension
RewriteCond %{THE_REQUEST} ^GET\ /[^?\s]+\.php
RewriteRule (.*)\.php$ /$1/ [L,R=301]
RewriteRule (.*)/$ $1.php [L]
# Force trailing slash
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule .*[^/]$ $0/ [L,R=301]
It successfully force the WWW, even if I remove it, the .php extension is removed, even if I add it, and the the trailing slash is forced, even if I remove it. However, sometimes I get a 404 not found error saying that the requested URL (generally ending with the .php extension) was not found on the server, and often directories do not actually work.
Edit
often directories do not actually work
meaning the server throws a 404 error saying "/directory.php was not found on this server".
Can anyone lend me a hand?
You need to check that you're actually rewriting to a php file before you blindly attach the php extension. So this rule:
RewriteRule (.*)/$ $1.php [L]
Needs some conditions:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/(.+)/$
RewriteCond %{DOCUMENT_ROOT}/%1.php -f
RewriteRule ^(.*)/$ $1.php [L]
You can also avoid redirecting to include www in the hostname for subdomains if you check that there is at least 1 host before the TLD, try adding another condition to your prefix rule:
# Force WWW prefix
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} ^([^.]+)\.([a-z]{2,4})$ [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
EDIT:
Here's what the full file should look like:
RewriteBase /
# Force WWW prefix
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} ^([^.]+)\.([a-z]{2,4})$ [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Remove .php extension
RewriteCond %{THE_REQUEST} ^GET\ /[^?\s]+\.php
RewriteRule (.*)\.php$ /$1/ [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/(.+)/$
RewriteCond %{DOCUMENT_ROOT}/%1.php -f
RewriteRule ^(.*)/$ $1.php [L]
# Force trailing slash
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule .*[^/]$ $0/ [L,R=301]