.htaccess 301 redirect not working for certain URLs

There are a few domains pointing towards the same server, and of course I need them all redirect to only one of them.

Redirects work, but only for certain URLs.

What works: http://www.domain.com, http://domain.com, domain.com/index.html, domain.com/index.php, , domain.com/nonExistentDirectory, and if I click in the menu the following URLs are also redirected correctly: domain.com/foo/bar, domain.com/foo/bar.html or .php or other extension.

What doesn’t work: domain.com/existentDirectory, domain.com/foo/bar (if I type the URL in the address bar).

If anyone will have the time and skill and will to tell me where’s the mistake, I’ll be deeply grateful.

Here’s my .htaccess file:

AddHandler x-httpd-php .html .htm

<ifModule mod_gzip.c>
  mod_gzip_on Yes
  mod_gzip_dechunk Yes
  mod_gzip_item_include file \\.(html?|txt|css|js|php|pl)$
  mod_gzip_item_include handler ^cgi-script$
  mod_gzip_item_include mime ^text/.*
  mod_gzip_item_include mime ^application/x-javascript.*
  mod_gzip_item_exclude mime ^image/.*
  mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</ifModule>

<ifModule mod_expires.c>
  ExpiresActive On
  ExpiresDefault "access plus 1 seconds"
  ExpiresByType text/html "access plus 1 seconds"
  ExpiresByType image/gif "access plus 2592000 seconds"
  ExpiresByType image/jpeg "access plus 2592000 seconds"
  ExpiresByType image/png "access plus 2592000 seconds"
  ExpiresByType text/css "access plus 2592000 seconds"
  ExpiresByType text/javascript "access plus 216000 seconds"
  ExpiresByType application/x-javascript "access plus 216000 seconds"
</ifModule>

<ifModule mod_headers.c>
  <filesMatch "\\\\.(ico|pdf|flv|jpg|jpeg|png|gif|swf)$">
    Header set Cache-Control "max-age=2592000, public"
  </filesMatch>
  <filesMatch "\\\\.(css)$">
    Header set Cache-Control "max-age=2592000, public"
  </filesMatch>
  <filesMatch "\\\\.(js)$">
    Header set Cache-Control "max-age=216000, private"
  </filesMatch>
  <filesMatch "\\\\.(xml|txt)$">
    Header set Cache-Control "max-age=216000, public, must-revalidate"
  </filesMatch>
  <filesMatch "\\\\.(html|htm|php)$">
    Header set Cache-Control "max-age=1, private, must-revalidate"
  </filesMatch>
</ifModule>

<ifModule mod_headers.c>
  Header unset ETag
</ifModule>
FileETag None

<ifModule mod_headers.c>
  Header unset Last-Modified
</ifModule>

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule . /index.php [L]

</IfModule>


# END WordPress


RewriteCond %{HTTP_HOST} ^foo\\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\\.foo\\.com$
RewriteRule (.*) http://domain.com/$1 [R=301,L,QSA]


RewriteCond %{HTTP_HOST} ^foo1\\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\\.foo1\\.com$
RewriteRule (.*) http://domain.com/$1 [R=301,L,QSA]


RewriteCond %{HTTP_HOST} ^foo2\\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\\.foo2\\.com$
RewriteRule (.*) http://domain.com/$1 [R=301,L,QSA]


RewriteCond %{HTTP_HOST} ^foo3\\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\\.foo3\\.com$
RewriteRule (.*) http://domain.com/$1 [R=301,L,QSA]


RewriteCond %{HTTP_HOST} ^foo8\\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\\.foo8\\.com$
RewriteRule (.*) http://domain.com/$1 [R=301,L,QSA]

Thinking that the above version was overkill, I’ve also tried to redirect all the requests for domains different than the main on to be redirected to it like this:


RewriteCond %{HTTP_HOST} !^domain\\.com$ [NC]
RewriteRule ^(.*)$ http://domain.com [L,R=301]

Is it also wrong? Because it doesn’t work either!

Removing or placing the following piece of code after the rewrites didn’t solve the issue either, so the problem must be somewhere else:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /


RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule . /index.php [L]

</IfModule>


# END WordPress

First of all, please check on the server for all the different modules if they are enabled, and once they are, remove the <IfModule …></IfModule> blocks. They are putting an unnecessary strain on your server.

Your code


RewriteCond %{HTTP_HOST} !^domain\\.com$ [NC]
RewriteRule ^(.*)$ http://domain.com [L,R=301]

Looks pretty okay, and should indeed replace all the other RewriteConds and RewriteRules you had earlier.
The one thing is that this rule just rewrites to the root of the domain and doesn’t propagate the requested URL. Also, (.*) is really not needed here, and is only slowing things down: .? would be much better.

I would change the code to:


RewriteCond %{HTTP_HOST} !^domain\\.com$ [NC]
RewriteRule .? http://domain.com%{REQUEST_URI} [L,R=301]

If you put that above the wordpress rules (after removing the <IfModule …></IfModule>) it should work as far as I can see.

What you could try is add the following at the start of the .htaccess


Options +FollowSymLinks -MultiViews

Just to make sure you have a good baseline for mod_rewrite to work in :slight_smile:

Lastly, you’re not using any Redirect* directives, so you really don’t need RewriteBase /. You can drop that line.

Thank you so much for your advices, and for replying. It seems very difficult to get advices on this issue - either is it too difficult, either too boring. I have applied all your advices except the one regarding removing the modules. I’ll still have to make some research to understand what they do and how to check if they are enabled.
The other changes I’ve made didn’t bring me any closer to a solution.
Anyway, the .htaccess file now looks like this:

Options +FollowSymLinks -MultiViews

RewriteEngine on

AddHandler x-httpd-php .html .htm


<ifModule mod_gzip.c>

  mod_gzip_on Yes
  
  mod_gzip_dechunk Yes

  mod_gzip_item_include file \\.(html?|txt|css|js|php|pl)$

  mod_gzip_item_include handler ^cgi-script$

  mod_gzip_item_include mime ^text/.*

  mod_gzip_item_include mime ^application/x-javascript.*
  
  mod_gzip_item_exclude mime ^image/.*

  mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*

</ifModule>



<ifModule mod_expires.c>

  ExpiresActive On

  ExpiresDefault "access plus 1 seconds"

  ExpiresByType text/html "access plus 1 seconds"

  ExpiresByType image/gif "access plus 2592000 seconds"

  ExpiresByType image/jpeg "access plus 2592000 seconds"
  ExpiresByType image/png "access plus 2592000 seconds"

  ExpiresByType text/css "access plus 2592000 seconds"

  ExpiresByType text/javascript "access plus 216000 seconds"

  ExpiresByType application/x-javascript "access plus 216000 seconds"

</ifModule>



<ifModule mod_headers.c>

  <filesMatch "\\\\.(ico|pdf|flv|jpg|jpeg|png|gif|swf)$">

    Header set Cache-Control "max-age=2592000, public"

  </filesMatch>

  <filesMatch "\\\\.(css)$">
    Header set Cache-Control "max-age=2592000, public"

  </filesMatch>

  <filesMatch "\\\\.(js)$">

    Header set Cache-Control "max-age=216000, private"

  </filesMatch>

  <filesMatch "\\\\.(xml|txt)$">

    Header set Cache-Control "max-age=216000, public, must-revalidate"
 
  </filesMatch>

  <filesMatch "\\\\.(html|htm|php)$">

    Header set Cache-Control "max-age=1, private, must-revalidate"

  </filesMatch>

</ifModule>



<ifModule mod_headers.c>

  Header unset ETag

</ifModule>


FileETag None



<ifModule mod_headers.c>

  Header unset Last-Modified

</ifModule>




RewriteCond %{HTTP_HOST} !^(www\\.)?domain\\.com$
RewriteRule .? http://domain.com%{REQUEST_URI} [R=301,L]



#BEGIN WordPress
<IfModule mod_rewrite.c>



RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule . /index.php


</IfModule>


# END WordPress




And the “symptoms” are the same - the root URLs are redirected (www.secondaryDomain.com, secondaryDomain.com) and so are URLs like secondaryDomain.com/index.html but secondaryDomain.com/existentDirectory, secondaryDomain.com/foo/bar don’t get redirected.

I’ll see what I can do about the if modules, and be back with a follow-up.