I want to redirect all content to:
www.example.com/public/...
but prevent direct access to
www.example.com/public/file1/
ww
After spending an inordinate amount of time trying to solve this problem, I found that the solution lies with the under-documented REDIRECT_STATUS environment variable.
Add this to the beginning of your top-level /.htaccess
code, and also to any .htaccess
files you have under it (e.g. /public/.htaccess
):
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} !=200
RewriteRule ^ /public%{REQUEST_URI} [L]
Now, if the user requests example.com/file1
then they are served the file at /public/file1
. However, if they request example.com/public/file1
directly then the server will attempt to serve the file at /public/public/file1
, which will fail (unless you happen to have a file at that location).
IMPORTANT:
You need to add those lines to all .htaccess
files, not just the top-level one in the web root, because if you have any .htaccess
files below the web root (e.g. /public/.htaccess
) then these will override the top-level .htaccess and users will again be able to access files in /public
directly.
Note about variables and redirects:
Performing a redirect (or a rewrite) causes the whole process to start again with the new URI, so any variables that you set before the redirect will no longer be set afterwards. This is done deliberately, because usually you do not want the final result to depend on how you got there (i.e. whether it was via a direct request or via a redirect).
However, for those special occasions where you do want to know how you got to a particular URI, you can use REDIRECT_STATUS
. Also, any environment variables set before the redirect (e.g. with SetEnvIf) will still be available after the redirect, but with REDIRECT_ prefixed to the name of the variable (so MY_VAR
becomes REDIRECT_MY_VAR
).