Apache Rewrite Rule www to non-www + http to https + add trailing slash
.htaccess files are extremely useful in many cases for users who either do not have root permissions or for users who simply aren't comfortable in making changes in their web server's configuration file. Trying to debug .htaccess not working isn't always the easiest thing to do, however, hopefully by checking the discuss below mentioned about htaccess, redirects, 301-redirect, codeigniter, .htaccess common problems as well as the troubleshooting tips, you'll have a better grasp on what you may have to modify to get your .htaccess file running smoothly.Problem :I really need the following 3 features of my website:
- www to non-www
- HTTP to HTTPS
- force trailing slash at the end of the URLs
I have a current implementation but I face a very bad bug.
When I manually enter the URL example.com/page in the browser the browser redirects to example.com/?page/. This, of course, opens my homepage and not the required /page/.
I've tried many examples and read a lot of similar questions for the last few weeks. No success.
Here is my full .htaccess file:
RewriteEngine on
RewriteBase /
# Redirects www to non-www
RewriteCond %HTTP_HOST ^www.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
# Force ending url traling slash
RewriteCond %REQUEST_FILENAME !-f
RewriteCond %REQUEST_URI !(.*)/$
RewriteRule ^(.*)$ /$1/ [L,R=301]
# Prevent CI index.php
RewriteCond $1 !^(index.php|resources|robots.txt)
RewriteCond %REQUEST_FILENAME !-f
RewriteCond %REQUEST_FILENAME !-d
#RewriteRule .* index.php/$0 [PT,L]
RewriteRule ^(.*)$ index.php?$0 [L]
# Prevent user access to the CI system folder.
RewriteCond %REQUEST_URI ^system.*
RewriteRule ^(.*)$ /index.php?/$1 [L]
# Prevent user access to the CI application folder
RewriteCond %REQUEST_URI ^application.*
RewriteRule ^(.*)$ /index.php?/$1 [L]
# Redirects http to https protocol
RewriteCond %HTTPS !on
RewriteRule (.*) https://%HTTP_HOST%REQUEST_URI
# Redirect index.php to the root /
RewriteCond %THE_REQUEST ^.*/index.php
RewriteRule ^(.*)index.php$ /$1 [R=301,L]
# One month for most static assets
<filesMatch ".(css|jpg|jpeg|png|gif|js|ico)$">
Header set Cache-Control "max-age=2628000, public"
</filesMatch>
RedirectPermanent /free-project-management-certification/ https://example.com/projectmanagement/
RedirectPermanent /free-scrum-master-certification/ https://example.com/scrummaster/
RedirectPermanent /product-owner-certification/ https://example.com/productowner/
RedirectPermanent /human-resources-management-certification/ https://example.com/humanresources/
RedirectPermanent /product-management-certification/ https://example.com/productmanagement/
RedirectPermanent /project-management-certification/ https://example.com/projectmanagement/
RedirectPermanent /index.php/ https://example.com/
<IfModule mod_deflate.c>
# Compress HTML, CSS, JavaScript, Text, XML and fonts
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
# Remove browser bugs (only needed for really old browsers)
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch bMSIE !no-gzip !gzip-only-text/html
Header append Vary User-Agent
</IfModule>
I changed the positions of all redirects, tried different combinations, changed characters, a lot of things. I would really appreciate some help.
# Redirects http to https protocol
RewriteCond %HTTPS !on
RewriteRule (.*) https://%HTTP_HOST%REQUEST_URI
Your HTTP to HTTPS redirect is in the wrong place. It needs to be at the top of your .htaccess file, immediately after the RewriteBase directive and before the www to non-www redirect. (You are also missing R and L flags to trigger a permanent redirect and prevent further processing.)
It is currently being called after the URL has been rewritten to index.php?page/ (which is after the first redirect to append the slash). So, the HTTP to HTTPS redirect ends up redirecting to https://example.com/index.php?page/ and another redirect then removes the index.php to finally end up at /?page/ - 3 redirects in all!
In other words:
- Request
http://example.com/page(HTTP) - 301 redirect to
http://example.com/page/(append trailing slash) - Internal rewrite to
http://example.com/index.php?page/ - 302 redirect to
http://example.com/index.php?page/(since missingR=301flag on directive) - 301 redirect to
http://example.com/?page/(removal ofindex.php).
As mentioned, you need to move your HTTP to HTTPS redirect to the start of the file (this is the correct order if you intend to implement HSTS in the future):
RewriteEngine on
RewriteBase /
# Redirects http to https protocol
RewriteCond %HTTPS !on
RewriteRule (.*) https://%HTTP_HOST%REQUEST_URI [R=301,L]
# Redirects www to non-www
RewriteCond %HTTP_HOST ^www.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
You could reverse these two rules to prevent a potential double redirect when requesting http://www.example.com/ (ie. HTTP + www), however, this won't be HSTS compliant (which states that you must redirect to HTTPS on the same host).
However, you still have further conflicts between your mod_rewrite (RewriteRule, RewriteCond) rewrites and mod_alias (RedirectPermanent) redirects. You should avoid mixing redirects from both modules.
RedirectPermanent /index.php/ https://example.com/
This RedirectPermanent directive is not required. You are already performing the necessary redirect (to remove index.php from the visible URL) with mod_rewrite earlier in the code. Although the corresponding mod_rewrite directive would not catch a URL that contained trailing path-info:
# Redirect index.php to the root /
RewriteCond %THE_REQUEST ^.*/index.php
RewriteRule ^(.*)index.php$ /$1 [R=301,L]
Omit the trailing $ on the RewriteRule pattern to allow for optional trailing slashes (ie. path-info) to also be caught. ie. RewriteRule ^(.*)index.php /$1 [R=301,L].
RedirectPermanent /free-project-management-certification/ https://example.com/projectmanagement/
RedirectPermanent /free-scrum-master-certification/ https://example.com/scrummaster/
RedirectPermanent /product-owner-certification/ https://example.com/productowner/
RedirectPermanent /human-resources-management-certification/ https://example.com/humanresources/
RedirectPermanent /product-management-certification/ https://example.com/productmanagement/
RedirectPermanent /project-management-certification/ https://example.com/projectmanagement/
You should also convert the remaining mod_alias RedirectPermanent directives to corresponding mod_rewrite RewriteRule redirects and place them near the start of your file (either at the very top, immediately after the RewriteBase directive or after the canonical www to non-www / HTTP to HTTPS redirects) in order to avoid further conflicts.
Currently, with using mod_alias RedirectPermanent, requesting any one of these "redirected" URLs will also exhibit similar behaviour. eg. Request /free-project-management-certification/ and you will be externally redirected to /projectmanagement/?free-project-management-certification/ due to earlier rewrites (regardless of whether you request HTTP or HTTPS initially).
I assume these are intended to be 1 to 1 redirects. (Although the RedirectPermanent directive is strictly a many to many redirect due to its prefix-matching nature.)
For example:
RewriteRule ^free-project-management-certification/$ /projectmanagement/ [R=301,L]
RewriteRule ^free-scrum-master-certification/$ /scrummaster/ [R=301,L]
RewriteRule ^product-owner-certification/$ /productowner/ [R=301,L]
RewriteRule ^human-resources-management-certification/$ /humanresources/ [R=301,L]
RewriteRule ^product-management-certification/$ /productmanagement/ [R=301,L]
RewriteRule ^project-management-certification/$ /projectmanagement/ [R=301,L]
UPDATE: If you include these redirects at the very top of the file then you could include a full absolute URL (as you did initially) for the target URL, to avoid multiple redirects when requesting the non-canonical HTTP or www subdomain. eg. https://example.com/projectmanagement/.
You will need to clear your browser cache before testing. Test with 302 (temporary) redirects and/or with browser caching disabled to avoid potential caching issues.
Comments
Post a Comment