but
localhost/mydomain.com/
simply says ‘localhost redirected you too many times’. How do I get the redirect to work fine both on a live server and localhost?
This is not the “root directory” as you’ve stated in the question title; it’s a subdirectory and that’s the problem…
RewriteCond %{REQUEST_URI} /(.*)/$ RewriteRule ^ /%1 [R=301,L]
The rule already excludes the root directory – as it should. (This is achieved because the regex /(.*)/$
would fail to match the root).
The problem with this rule is you are trying to remove the trailing slash from every other URL, including subdirectories (as in physical filesystem directories). You can’t do this – directories need the trailing slash*1. You would have the same problem on the live server if you requested a subdirectory. (I assume you do have subdirectories for assets, images, etc.?)
If you remove the trailing slash then mod_dir will (by default) append the slash again with a 301 redirect – resulting in an endless redirect loop.
(*1 You can suppress the trailing slash on directories, in terms of the URL you see – but the trailing slash still needs to be present in order to serve directory index documents from those directories. In order to achieve this you can internally rewrite the request to append the trailing slash – but this is messy – particularly when resolving canonicalization issues – and probably not necessary in your situation anyway.)
It’s a simple fix… you basically need to check that the request does not map to a directory before removing the trailing slash.
Try the following instead:
# Removing trailing slashes from non-directory URLs
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond ${REQUEST_URI} ^/(.+)/$
RewriteRule ./$ https://example.net/%1 [R=301,L]
Note that I’ve also included the scheme+hostname in the substitution string (as you have in the other canonical redirects) in order to minimise the number of redirects when also requesting HTTP and/or www (although these should be edge cases anyway).
You will need to clear your browser (and possibly other intermediary) caches before testing and test first with a 302 (temporary) redirect to avoid potential caching issues. 301 (permanent) redirects (including errors) are cached persistently by the browser.
when someone types
d/file/
ord/file
in the url bar, it loads the same content (duplicate content)
However, that is something you should really be controlling in your PHP router. Your PHP code must be resolving both requests into one for both URLs to return the same response – perhaps you should not be doing that. Then one or other URL (eg. the one with the trailing slash) will naturally result in a 404 (assuming that’s what your router does). Or redirect one to the other in your PHP router/script – by doing this in PHP you can selectively redirect only the URLs that need redirecting and not URLs that would otherwise result in a 404 anyway.
This also avoids the need to explicitly check for physical directories, since requests for physical directories are not hitting your router.
Aside:
On localhost, localhost/mydomain.com/folder/file/ redirects fine,
Instead of simply using a subdirectory off the localhost, why don’t you define the ServerName
and DocumentRoot
properly for mydomain.com
– or perhaps use a subdomain like local.mydomain.com
if you need to keep mydomain.com
(the live site) accessible? Then you have the same directory structure on both local and live sites.
(It could still be stored as a subdirectory off the localhost’s document root if you wish, but the files could literally be stored anywhere.)