apache.htaccess

map subfolder content to root with .htaccess


I have the following directory structure:

/html
  .git
  project-folder
    build
      index.html
  .htaccess

The apache server see the directory /html as a root folder for the domain https://example.com.

What should I put to .htaccess to be able to see index.html as a root index for the domain https://example.com?

Could DirectoryIndex help? If so, how to write the RewriteRule and RewriteCond then?


Solution

  • Could DirectoryIndex help?

    Not really, that would only help with requests to the root directory itself and not /<something>. This should be left as the default, in order to serve index.html from the requested directory (including /html/project-folder/build). For example:

    DirectoryIndex index.html
    

    I'm assuming you don't need to access anything outside of the /build subdirectory publicly. I'm also assuming you are on Apache 2.4 (as opposed to Apache 2.2).

    Here are two methods, depending on whether you will have one or two .htaccess files. The second being in the /build subdirectory.

    One .htaccess file in the document root

    In the root .htaccess file (at /html/.htaccess) you can internally rewrite any internal requests that are not already for the /project-folder/build subdirectory to that subdirectory.

    Any external requests for /project-folder/build need to be externally redirected back to the root (or blocked altogether).

    For example:

    # Single .htaccess file in document root at /html/.htaccess
    
    DirectoryIndex index.html
    
    RewriteEngine On
    
    # Redirect any direct requests to the subdirectory back to root
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteRule ^project-folder/build/(.*) /$1 [R=301,L]
    
    # Internally rewrite all requests to the subdirectory
    RewriteRule (.*) project-folder/build/$1 [END]
    

    The use of the REDIRECT_STATUS environment variable in the RewriteCond directive ensures we are only checking direct (external) requests and not internal rewrites (by other rules). Although, in this limited example, the use of the END flag on the second rule makes this check redundant.

    Two .htaccess files (one in document root and one in project subdirectory)

    This is required if the project (directory) has its own .htaccess file that also contains mod_rewrite directives.

    In this scenario, the external redirect back to root would need to be in the project folder's .htaccess file (not in the root .htaccess file), this is because mod_rewrite directives are not inherited (by default).

    For example:

    # /html/.htaccess (in the document root)
    
    DirectoryIndex index.html
    
    RewriteEngine On
    
    # Internally rewrite all requests to the subdirectory
    RewriteRule (.*) project-folder/build/$1 [L]
    

    In this case, it doesn't matter whether L or END is used on the above rule.

    # /html/project-folder/build/.htaccess
    
    RewriteEngine On
    
    # Redirect any direct requests to this subdirectory back to root
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteRule (.*) /$1 [R=301,L]
    

    At a casual glance, the above redirect might look like it's redirecting back to itself, but note that the captured URL-path (from the RewriteRule pattern) is relative to the directory that contains the .htaccess file. So, a request for /project-folder/build/<something> is redirected back to /<something> in the "root".

    Always test first with 302 (temporary) redirects first to avoid potential caching issues.