Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.htaccess rewrite to subfolder

The goal:

In a virtual server on a shared Apache 2.2 box, I've attempted to configure .htaccess to seamlessly represent files in a subfolder of the public_html folder as if they are in the root.

That is, when the user accesses http://www.example.com/home, I need him or her to seamlessly (without rewriting the URL in the client browser) see the files from http://www.example.com/subfolder/home.

My .htaccess file looks like this:

RewriteEngine on
RewriteRule !^subfolder/ subfolder%{REQUEST_URI}

The problem:

This works, but it rewrites the URL in the client browser.

That is, the user sees http://www.example.com/subfolder/home/ in their address bar, but I need them to see just http://www.example.com/home

My understanding is that what I've done in .htaccess should result in an "internal" rewrite that's invisible to the end user, but it appears that I'm getting an "external" rewrite.

What am I doing wrong?


[EDIT] Additional details:

When the user accesses www.example.com, it does work as desired, in that the user sees home page content served up from public_html/subfolder/default.html, and the browser address bar says www.example.com.

However, when the user clicks the 'Contact' link on that home page (coded href="/contact"), it gets there, but shows www.example.com/subfolder/contact/ in the browser address bar, as if it has done a redirect instead of an internal rewrite.

If I then delete the /subfolder text in the address bar and force a reload of the page, it works--it loads the correct content, and the address bar remains www.example.com/contact/

Implementation note: In case it helps, public_html/subfolder/contact is a folder containing a default.html file.

Another observation:

If I open a new tab and type www.example.com/contact/ (note the trailing slash), it works as expected and desired.

But if I open a new tab and type www.example.com/contact (no trailing slash), it redirects to www.example.com/subfolder/contact/, which is what I don't want.

I feel like that should tell me what's wrong, but the answer still eludes me.

like image 260
bland328 Avatar asked Dec 27 '12 08:12

bland328


People also ask

Can I put htaccess in a subfolder?

You can add a . htaccess file to any directory that requires lenient permissions settings (such as 760, 766, 775 or 777). You can prevent the execution of scripts inside the directory and all its sub-directories.


1 Answers

The reason why this is happening is because of mod_dir. It has a directive called DirectorySlash that redirects the browser when it thinks a request is made for a directory and the trailing slash is missing to the same URI with a trailing slash appended. The problem is mod_dir and mod_rewrite get applied at different places in the URL/file mapping pipeline. So mod_rewrite mangles the URI at one point, then when mod_dir does its thing, the rewritten URI gets redirected so the URL in the browser's address bar changes to include the "hidden" internal rewrite.

You can do a couple of things here.

  1. You can enforce trailing slashes yourself in mod_rewrite, so the browser gets redirected to include the trailing slash before the URI reaches mod_dir. This means all of your URLs for things like /home and /contact will include a trailing slash, if one is missing, your rewrite code will redirect and add one. Something like this, above your current rule so that it gets applied first:

    RewriteCond %{REQUEST_URI} !^/subfolder
    RewriteCond %{DOCUMENT_ROOT}/subfolder%{REQUEST_URI} !-f
    RewriteRule ^(.*[^/])$ /$1/ [L,R=301]
    
  2. Turn off DirectorySlash so mod_dir stops doing this redirect. You can simply include DirectorySlash Off at the top of your htaccess file. However, the downside here is a possible information disclosure security issue when the trailing slash is missing.


EDIT:

In order to use the index file, without a trailing slash, you need to map to it. Try changing your rules to:

    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/subfolder
    RewriteCond %{DOCUMENT_ROOT}/subfolder%{REQUEST_URI} -d
    RewriteRule ^(.*?)/?$ /subfolder/$1/ [L]

    RewriteCond %{REQUEST_URI} !^/subfolder
    RewriteRule ^(.*)$ /subfolder/$1 [L]
like image 70
Jon Lin Avatar answered Sep 20 '22 04:09

Jon Lin