non www url is redirecting to homepage

Viewed 102

I have .htaccess settings to get any non-www request to www.

It works for the home page, but when I check other URLs it goes to the home page.

Here are my settings (UPDATED): Top part is coming from laravel

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On


    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]


</IfModule>

    <IfModule mod_rewrite.c>
    
    RewriteEngine on
    
    RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
    RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]
    
    #First rewrite any request to the wrong domain to use the correct one (here www.)
    RewriteCond %{HTTP_HOST} ^[^.]+\.[^.]+$
    RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [L,R=301]
    
    #Now, rewrite to HTTPS:
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    
    
    RewriteCond %{HTTP_USER_AGENT} libwww-perl.*
    RewriteRule .* ? [F,L]
    </IfModule>

For example

https://example.com goes to https://www.example.com.

But https://example.com/contact doesn't go to https://www.example.com/contact. Instead, it goes to https://www.example.com.

What can be the problem and solution?

2 Answers

but https://example.com/contact doesn't go to https://www.example.com/contact

Assuming you are not simply using extensionless URLs (ie. /contact maps to /contact.php) with MultiViews/mod_negotiation then you must have other mod_rewrite directives that route these requests.

It looks like you may have put these directives in the wrong order.

The external redirects in your question need to go near the top of your .htaccess before any internal rewrites to a front-controller.

Aside:

#First rewrite any request to the wrong domain to use the correct one (here www.)
RewriteCond %{HTTP_HOST} ^[^.]+\.[^.]+$
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [L,R=301]

This rule should be redirecting to https://, not http://. Otherwise you are going to get multiple, unnecessary redirects (https to http and back to https).

RewriteCond %{HTTP_USER_AGENT} libwww-perl.*
RewriteRule .* ? [F,L]

This rule (currently last), needs to go at the top. Generally, any blocking directives should be first. You can also simplify/optimise this a bit...

RewriteCond %{HTTP_USER_AGENT} libwww-perl
RewriteRule ^ - [F]

L is implied when using F. If there is no substitution string then you should use -, not ?.


UPDATE: Following your updated question, my initial answer/hypothesis is confirmed... your directives are in the wrong order. Your external redirects need to go before the Laravel front-controller.

Otherwise, in its current order, a request of the form example.com/contact is first internally rewritten to index.php by the Laravel front-controller and then there will be an external redirect to the canonical scheme + hostname, so the net result is you are redirected to the homepage.

The cPanel redirect you mentioned in comments simply manifests itself as a rule in .htaccess (which you've already included). But note that all cPanel redirects are placed (often incorrectly) at the end of the .htaccess file (this is stated in the cPanel docs).

So, in summary, your directives should be written like this:

Options -MultiViews -Indexes
    
RewriteEngine on

#
# BLOCKING DIRECTIVES
#

# Block certain requests
RewriteCond %{HTTP_USER_AGENT} libwww-perl
RewriteRule ^ - [F]

#
# CANONICAL REDIRECTS
#
    
# Redirect non-www to www + HTTPS
RewriteCond %{HTTP_HOST} ^[^.]+\.[^.]+$
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [L,R=301]
    
# Redirect HTTP to HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# Remove index.php
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]
    
#
# Laravel directives follow...
#

# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]

# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

ıt seems that is working with this

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
        
    ## Force https and www
    RewriteCond %{HTTPS} off [OR]
    RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
    RewriteRule ^(.*)$ https://www.example.com/$1 [L,R=301]
    
    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]

RewriteCond %{HTTP_USER_AGENT} libwww-perl.*
RewriteRule .* ? [F,L]

RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]

</IfModule>

Any extra suggestions to optimize are accepted with pleasure

Related