RewriteCond to not rewrite a specific URI not working
# THE LINE I'M ADDING # RewriteCond %{REQUEST_URI} !^/InvalidLink\.html$
There is nothing "wrong" with the condition you are adding, providing the requested URL is exactly /InvalidLink.html
(case-sensitive match), this .htaccess
file is in the document root and the browser cache has been cleared before testing. So, this is still a puzzle. Try adding the NC
flag - in case there is a mismatch in case, for example:
RewriteCond %{REQUEST_URI} !^/InvalidLink\.html$ [NC]
The fact that the exception "works" if you first create this file, in which case the first condition (!-f
) prevents the rewrite happening, suggests that the file is being processed OK and your cache is clear. And that the above condition is at fault. However, from what you have posted it looks OK!?
An alternative to adding a condition to your existing rule, is to create a separate "exception" at the top of your file. So, instead of saying, "rewrite the URL if the request is not for /InvalidLink.html
", we can add a separate rule that states "if the URL is /InvalidLink.html
then stop here and do nothing more".
So, instead of your condition, include a separate rule at the top of your file:
RewriteRule ^InvalidLink\.html$ - [NC,L]
Note there is no slash prefix on the RewriteRule
pattern in per-directory .htaccess
files. This will match /InvalidLink.html
and prevent the following mod_rewrite directives from being processed. Ideally, the NC
flag should not be necessary, however, I've included it "just in case".
This is really subsidiary to your main problem above...
RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$ RewriteCond %{REQUEST_URI} !^/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
This carbuncle is what cPanel automatically adds before every RewriteRule
when implementing the "Let's Encrypt" SSL cert. It's very messy and there is much argument in the cPanel forums requesting this be removed or changed. (Why they can't add a single code block/exception at the top of the file is a mystery.)
Anyway, in the interim, these directives can be safely removed (throughout the file) - they are not required (after the cert has been installed). This will simplify your directives, making the file more readable (and avoid any potential conflict). However, cPanel will later automatically re-add these directives when the certs are renewed (every 3 months).
RewriteCond %{HTTP_HOST} ^www\.example\.com$ RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$ RewriteCond %{REQUEST_URI} !^/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$ RewriteRule ^(.*)$ "http\:\/\/example\.com\/$1" [R=301,L]
As mentioned above, the middle conditions can be safely removed. However, this canonical redirect is in the wrong place! It needs to be at the very top of your file, otherwise none of your shortened URLs will be canonicalised. In short, cPanel is not very good (unreliable) at editing the .htaccess
file!
Summary
Bringing all the above together, your existing .htaccess
file can be rewritten as:
RewriteEngine On
# Canonical www to non-www redirect
RewriteCond %{HTTP_HOST} ^www\.(.+) [NC]
RewriteRule (.*) http://%1/$1 [R=301,L]
# Exceptions - avoid these URLs being rewritten
RewriteRule ^InvalidLink\.html$ - [NC,L]
# BEGIN YOURLS
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* /yourls-loader.php [L]
# END YOURLS
The <IfModule>
wrapper is not required. And the RewriteBase
directive was superfluous. .*
is the same as ^.*$
. Backslash escaping chars in the RewriteRule
substitution is unnecessary (that's "typical cPanel").
Related videos on Youtube
lfk
Updated on September 18, 2022Comments
-
lfk over 1 year
I am working with a URL shortener (YOURLS) and I'm trying to have a certain page not directed to the link processing script. Here's the original
.htaccess
:# BEGIN YOURLS <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$ RewriteCond %{REQUEST_URI} !^/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$ # THE LINE I'M ADDING # RewriteCond %{REQUEST_URI} !^/InvalidLink\.html$ RewriteRule ^.*$ /yourls-loader.php [L] </IfModule> # END YOURLS RewriteCond %{HTTP_HOST} ^www\.example\.com$ RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$ RewriteCond %{REQUEST_URI} !^/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$ RewriteRule ^(.*)$ "http\:\/\/example\.com\/$1" [R=301,L]
I've added a new condition right before the
RewriteRule
line (commented out and pointed out above):RewriteCond %{REQUEST_URI} !^/InvalidLink\.html$
to have
http://example.com/InvalidLink.html
ignored. But this is making no difference. What am I doing wrong here?-
MrWhite about 7 yearsThat's the correct condition, however, where are you putting it?
-
lfk about 7 yearsRight before RewriteRule line
-
MrWhite about 7 yearsThat already sounds correct, so there would seem to be something else going on here? Have you cleared your browser cache? If YOURLS uses 301 redirects then these will have been cached by your browser. Does
/InvalidLink.html
exist as a physical file? -
lfk about 7 yearsI have cleared the cache. But InvalidLinks.html does not exist. Let me try that
-
lfk about 7 yearsYou were right! Adding the file solved the problem. And I didn't need the new directive. But which part of the other directives is excluding InvalidLink.html? Is it the -f line?
-
MrWhite about 7 years"Adding the file solved the problem." - That isn't really a solution (unless
InvalidLinks.html
is meant to exist?) - it was just a test. If that works (and the browser cache was already cleared) then it implies that there was something wrong with the condition you were adding. Or are there any other directives? Or any other.htaccess
files? Yes the!-f
line would prevent any URLs that map to existing files from being rewritten. -
lfk about 7 yearsQuestion updated. Added full
.htaccess
. I can't find any other.htaccess
files. There is no parent directory anyway. -
lfk about 7 yearsThe lines after YOURLS directives are for forcing naked domain and were added by cPanel.
-
-
lfk about 7 yearsYou're right. www.example.com/keyword fails to redirect. YOURLS is expecting naked, but it gets www.
-
lfk about 7 yearsIn the first RewriteRule, how does %1 match domain name? e.g., what if we had two conditions, each with its own groups?
-
lfk about 7 yearsOkay. I finally figured it out. What was happening was that, since InvalidLink.html did not exist, the server was redirecting to the 404 error page (not sure where it's defined), which also did not exist, and thus would be forwarded to YOURLS! I added an ErrorDocument directive and created a 404 page. Now InvalidLink.html shows the 404 page. Though in practice, a 404 will never happen. Everything not a file will go to YOURLS, which does a 302 to another error page.
-
MrWhite about 7 years
%1
is a backreference to the first captured group in the last matched CondPattern. So, in the above example,%1
is a backreference to the(.+)
subpattern in the^www\.(.+)
CondPattern (if it matched). If you had two conditions then the backreference refers to the last one that matched (which isn't necessarily the lastRewriteCond
directive). -
MrWhite about 7 years"...and thus would be forwarded to YOURLS!" - That really shouldn't have happened. It suggests that the
ErrorDocument
defined in the server config was misconfigured. A missing error document by itself wouldn't normally have caused this problem. But if theErrorDocument
specified an absolute URL (instead of a root-relative URL) then it would have triggered an external redirect which would have resulted in the YOURLS script from answering the second (redirected) request.ErrorDocument 404 default
would also resolve it. Bit of a guess but that seems to fit. Glad you sorted it! :) -
lfk about 7 yearsThe bad configuration is hardly surprising. This is the cheapest shared hosting I could find.