user812120
user812120

Reputation: 585

Apache htaccess rewrite root and all root folders to subfolder without redirecting

Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /
RewriteRule ^$ /subdir/ [L,NC]

I want to rewrite the root domain to subfolder without changing the URL in the browser. The above code works just for the root domain but not any folders and files.

For example, I have https://example.com/ and https://example.com/subdir/.

With the above code in .htaccess file, when I go to https://example.com/ I see the contents of https://example.com/subdir/ which is good.

But when I go to https://example.com/test.txt I should see https://example.com/subdir/test.txt but I get The requested URL was not found on this server.

Same happens when I go to https://example.com/abc expecting to see contents of https://example.com/subdir/abc

Any idea?

Upvotes: 1

Views: 1314

Answers (1)

MrWhite
MrWhite

Reputation: 45829

RewriteRule ^$ /subdir/ [L,NC]

Change this to read:

RewriteRule !^subdir/ subdir%{REQUEST_URI} [L]

Any request that does not start /subdir/ is internally rewritten to /subdir/<url>. The REQUEST_URI server variable contains the full URL-path (including the slash prefix).

I removed the slash prefix from the substitution string since you have defined a RewriteBase /. (Although neither are strictly necessary here.)

UPDATE:

...when I go to example.com/s I am being redirected to example.com/subdir/s/
s is a subfolder within subdir, does that make any difference?

Ah yes, if /s is a subdirectory then mod_dir will append the trailing slash (to "fix" the URL) with an external 301 redirect. This redirect occurs after the URL has been rewritten to /subdir/s - thus exposing the /subdir subdirectory.

To handle this situation we can add another rule (a redirect) before the existing rewrite that first checks whether the request would map to a directory within the /subdir subdirectory and append a slash if it is omitted (before mod_dir would append the slash to the rewritten URL).

For example:

RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/subdir%{REQUEST_URI} -d
RewriteRule !\.\w{2,4}$ %{REQUEST_URI}/ [R=301,L]

This states... for any request that:

  • !\.\w{2,4}$ - does not contain (what looks like) a file extension of between 2 and 4 characters (assuming your directories aren't named this way)
  • !/$ - and does not currently end in a slash.
  • -d - and exists as a physical directory in the /subdir subdirectory.
  • THEN redirect to append the trailing slash on the original request

Whilst this probably should be a 301 (permanent) redirect, you should first test with a 302 (temporary) redirect to avoid potential caching issues.

You will need to clear your browser cache before testing, since the erroneous 301 redirect from /s to /subdir/s/ will have been cached by the browser.

A potential optimisation is to remove the filesystem check and simply assume that any request that does not contain a file extension should map to a directory. (But this depends on whether you are handling these URLs in any other way.)

Summary

Options +FollowSymLinks -MultiViews

# Turn mod_rewrite on
RewriteEngine On

# If the requested URL exists as a directory in "/subdir" then append a slash
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/subdir%{REQUEST_URI} -d
RewriteRule !\.\w{2,4}$ %{REQUEST_URI}/ [R=301,L]

# Rewrite everything to "/subdir"
RewriteRule !^subdir/ subdir%{REQUEST_URI} [L]

Upvotes: 1

Related Questions