htaccess - Redirect to subfolder without changing browser URL - apache

I've a domain that contains a subfolder with the web app structure. I added a .htaccess on my root domain to point the public folder on my subfolder web app. It works fine, but when I type www.example.com the browser URL changes to www.example.com/subfolder/public, but I would like that it doesn't change.
This is my .htaccess:
RewriteEngine On
RewriteRule ^.*$ subfolder/public [NC,L]
EDIT
This first .htaccess is used to redirect on subfolder/public, where there is an other .htaccess that makes all the works.
Here the code of the second .htaccess located on www.example.com/subfolder/public/:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

Sorry, just realised what is happening. It has nothing to do with the second .htaccess file in the subdirectory, as mentioned in comments.
RewriteRule ^.*$ subfolder/public [NC,L]
Since public is a physical directory on the file system, you need to include a trailing slash when internally rewriting to that directory. Otherwise, mod_dir is going to try to "fix" the URL by appending a slash - that is where the external redirect is coming from. (mod_dir implicitly triggers an external redirect from subfolder/public to subfolder/public/.)
So, try the following instead in your root .htaccess file:
RewriteRule .* subfolder/public/ [L]
The important thing is the trailing slash. The anchors (^ and $) on the RewriteRule pattern are not required, since you are matching everything. And the NC flag is also not required for the same reason.
As always, make sure the browser cache is clear before testing.
UPDATE#1: The single directive above rewrites everything, including static resources, to the directory subfolder/public/ which then relies on the second .htaccess file in the subdirectory to correctly route the request. In order to allow static resources to be rewritten correctly (represented in the HTML as root-relative URL-paths, of the form "/js/myjs.js") then you will need additional directives in order to rewrite these.
For example, to specifically rewrite all .js and .css files to the real location in /subfolder/public/...
# Rewrite static resources
RewriteRule (.+\.(?:js|css))$ subfolder/public/$1 [L]
# Rewrite everything else to the "public" directory
RewriteRule .* subfolder/public/ [L]
UPDATE#2: To make the above more general, and to rewrite any static resource (images, PDFs, .txt, etc...) we can check for the existence of the file before rewriting, something like:
# Rewrite static resources
RewriteCond %{DOCUMENT_ROOT}/subfolder/public/$1 -f
RewriteRule (.+) subfolder/public/$1 [L]
# Rewrite everything else to the "public" directory
RewriteRule .* subfolder/public/ [L]
This will mean that if any .css does not exist it will be passed through to subfolder/public/.

Related

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?
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]

How to redirect any URL to my index.html using apache?

I want my website to point at my index.html no matter what the URL is.
http://localhost/WebsiteName/
http://localhost/WebsiteName/whatever
http://localhost/WebsiteName/whatever/whatever-1/whatever-2/whatever-3/etc
By using this rewrite code in my apache config:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.html [L]
My URL works correctly when URL is any of these:
http://localhost/WebsiteName/
http://localhost/WebsiteName/whatever
But breaks when it is like this or further extended:
http://localhost/WebsiteName/whatever/
http://localhost/WebsiteName/whatever/whatever-1/whatever-2/whatever-3/etc
It acts as if there was another folder "whatever" in the directory whenever I use one of the URLs that break.
I don't want the URL to change, I just want it to point at my index.html no matter what it is.
Based off what you have there, all of those url's should go to your index.html. The index.html is assumed to be at the DOCUMENT_ROOT.
I'm not sure what your problem is, but maybe instead of having a condition for rewriting non-files. Stop rewriting when it's a file. I notice any changes on my website, with either config, but maybe it can work for yours.
RewriteEngine on
### If a uri leads to an actual file or directory (presumably with it's own index.html), then don't rewrite any further
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
### everything else
RewriteRule . /index.html [L]

Apache - Redirection - Paths

I have a problem with redirect. Right now I have one page on address like:
http://localhost/Stella/Wiki/index.php
Also in the same directory I have my .htaccess file, which should redirect all requests to the index.php.
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/Stella/Wiki/index.php
RewriteRule (.*)$ /Stella/Wiki/index.php?id=$1 [L,QSA]
This redirection works really good, but I want to use it in relative way, like:
RewriteCond %{REQUEST_URI} !^/index.php
RewriteRule (.*)$ /index.php?id=$1 [L,QSA]
Like without absolute path, because I am going to have many subfolders, and I don't want to have long rules like: /xxx/xxx/xxx/xxx/index.php.
Can you help me to solve this problem? I don't know what to do, or if is it even possible?
RewriteCond %{REQUEST_URI} !^/Stella/Wiki/index.php
RewriteRule (.*)$ /Stella/Wiki/index.php?id=$1 [L,QSA]
If the .htaccess is located at /Stella/Wiki/.htaccess then you can write these directives like:
RewriteRule ^index\.php$ - [L]
RewriteRule (.*) index.php?id=$1 [L,QSA]
As you suggested, this now uses relative paths. Note that relative paths don't start with a slash. If you use a slash prefix then that will be root-relative (ie. relative to the document root of the site).
When you use a relative path in per-directory .htaccess files then the directory-prefix (the filesystem path of where the .htaccess file is located) is added back at the end. So, index.php is in the directory where the .htaccess file is located. You can override this with the RewriteBase directive.
However, this a little different to your directives. Instead of a condition that only processes the directive if we are not already requesting the target URL. We have an exception that prevents any further directives being processed if that URL is already being requested.
Note, however, that this directs all requests to index.php (as your original directive does). Including requests for existing files and directories - if that is a concern?

Force subfolders to follow parent htaccess redirect rules?

I am currently using the following .htaccess code on my server to enable me to host the primary domain files from a subfolder in the public_html folder:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/subdirectory/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /subdirectory/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^(/)?$ subdirectory/index.php [L]
This doesn't solve the problem of subfolders of this new root, however. For example, I have two folders:
public_html\example\ - which should correspond to www.example.com
and
public_html\example\subfolder - which should correspond to www.example.com/subfolder
My problem is that navigating to www.example.com/subfolder in the browser redirects me to www.example.com/example/subfolder.
EDIT: Further to the response from #Jon, this is only occurring when navigating to the URL without a trailing slash. Navigating to www.example.com/subfolder/ is working as expected.
How do I prevent the redirect to www.example.com/example/subfolder?
When you go to a URL that's a folder and you are missing the trailing slash, apache will redirect the browser to so that there's a trailing slash at the end. This can sometimes mess with rewrite rules that are internally rewriting requests.
You either must go to example.com/subfolder/ or turn off the directory slash function. However, turning this off can be very dangerous:
Security Warning
Turning off the trailing slash redirect may result in an information disclosure. Consider a situation where mod_autoindex is active (Options +Indexes) and DirectoryIndex is set to a valid resource (say, index.html) and there's no other special handler defined for that URL. In this case a request with a trailing slash would show the index.html file. But a request without trailing slash would list the directory contents.
This means, if someone goes to: example.com/subfolder, they'll see your directory contents, eventhough there's an index.php file there. You can turn off indexes but then they'll just see a 403, and still won't see your index.php.

mod_autoindex does not respect mod_rewrite rules

I have a directory structure similar to:
public_html/
example.com/
index.php
subdir/
file.jpg
I'm using shared hosting, so http://example.com maps to /public_html/ for its root, and I can't change this. I've added a mod_rewrite rule to handle this issue:
RewriteEngine On
RewriteRule ^$ example\.com/ [L]
RewriteRule (.*) example\.com/$1/ [L]
If I browse to http://example.com/subdir (without the trailing /) it will list file.jpg , but the URL for it will be http://example.com/file.jpg. The parent directory link is http://example.com/example.com/.
If I browse to http://example.com/subdir/ (with the trailing /) it will list file.jpg with the proper URL: http://example.com/subdir/file.jpg. However, the parent directory link is http://example.com/example.com/subdir/.
I'm very confused for what's going on and I'd love any help on this.
(Note that if I take off the final / in the mod_rewrite rule then going to http://example.com/subdir without the / will redirect to the http://example.com/example.com/subdir/ variant. Also, the parent directory for the listing at http://example.com/subdir/ changes to http://example.com/example.com/, which is almost correct.)
This could be caused by a disabled DirectorySlash. So try to enable it or use this rule to do the same with mod_rewrite:
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .*[^/]$ %{REQUEST_URI}/ [L,R=301]