I'm trying to redirect all URLs from an old domain to a new one, except for two specific pages. I have implemented the following code in the .htaccess file:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(?:www\.)?olddomain\.com$ [NC]
RewriteCond %{REQUEST_URI} !^/contact-form [NC]
RewriteCond %{REQUEST_URI} !^/about [NC]
RewriteRule ^(.*)$ http://newdomain.com/$1 [R=301,L]
Although the redirection works correctly for all URLs, the excluded pages (contact-form and about) on the old domain become unavailable, resulting in a 404 error from the server:
404
Not Found
The resource requested could not be found on this server!
I'm unsure why these excluded pages are experiencing the 404 error. Any help in resolving this issue would be greatly appreciated."
Update:
To troubleshoot the problem, I switched to a staging environment on my localhost (XAMPP with Apache server). Initially, I left the default Wordpress codes in the .htaccess file (between "# BEGIN WordPress" and "# END WordPress") intact:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /wp/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /wp/index.php [L]
</IfModule>
# END WordPress
Then, I modified the above-mentioned code to the following one to ensure that all the static resources, including images and css/js files, needed to load the /contact-form and /about pages will be available and added it before "# BEGIN WordPress":
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(?:www\.)?localhost/wp$ [NC]
RewriteRule ^(contact-form|about)($|/) - [L]
# Exclude specific file extensions from redirection
RewriteCond %{THE_REQUEST} !/contact-form/?\s [NC]
RewriteCond %{REQUEST_URI} !\.(css|js|png|jpg|gif|webp|ico)$ [NC]
RewriteCond %{THE_REQUEST} !/about/?\s [NC]
RewriteCond %{REQUEST_URI} !\.(css|js|png|jpg|gif|webp|ico)$ [NC]
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]
The result was successful as all URLs of localhost/wp were redirected to their corresponding ones on example.com, except for the excluded pages (/contact-form and /about).
However, when I tested the same .htaccess file on a live website (LiteSpeed server), I encountered the 404 server error again when visiting /contact-form and /about.
Therefore, it seems that the problem lies in the LiteSpeed server configuration.
If the source website is WordPress then I would expect these "excluded URLs" to be redirected to /index.php
(or whatever the source website's front-controller is) on the "new domain" - which is then presumably triggering the 404?
The reason being is that whilst you are excluding these URLs on the initial request, the WordPress code block then rewrites the request to /index.php
, which then triggers a second pass by the rewrite engine. During the second pass, the URL-path is now /index.php
(which is not /contact-form
or /about
) so then triggers the redirect.
You need to make sure your redirect rule only applies to the initial request and not the rewritten request by the WordPress code block. You can do this by checking against the REDIRECT_STATUS
environment variable.
UPDATE: You also need to make sure that any static assets/scripts that these two pages require are not also redirected.
For example:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTP_HOST} ^(www\.)?olddomain\.com [NC]
RewriteCond %{REQUEST_URI} !\.(css|js|png|jpg|gif|webp|ico)$ [NC]
RewriteCond %{REQUEST_URI} !^/contact-form [NC]
RewriteCond %{REQUEST_URI} !^/about [NC]
RewriteRule ^(.*)$ https://newdomain.com/$1 [R=301,L]
The check against the REDIRECT_STATUS
env var ensures that only direct requests from the client are tested and not internally rewritten requests. REDIRECT_STATUS
is empty on the initial request and "200" (as in 200 OK HTTP status) after the first successful rewrite.
I've left the NC
flags in place, however, I would expect only /contact-form
(all lowercase) would be a successful request on the old domain?
Are the old and new domains pointing to the same place? I assume not, otherwise you would need additional rules to separate the two sites (although maybe that is also a problem?). If not, then the check against HTTP_HOST
is not required.
See also my answer to the following related question: Exclude folder in domain redirection in .htaccess using WordPress and also Redirect all URLS to new URL EXCEPT for /backend/ with .htaccess