Jean-Marc Zimmer
Jean-Marc Zimmer

Reputation: 555

Apache .htaccess to use subfolder as root

I know this kind of question is recurrent. But after several hours of searching I didn't find anything.

I'm making a website using Slim. However, in their documentation, they use /public as root directory, which I don't want. I want the website root to be /. Quite concerned about security, I created a .htaccess to redirect http://www.example.com/ to http://www.example.com/public/, so no user can reach /src and other folders :

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^$ /public [P]
</IfModule>

This causes a problem : the URI remains /public/, therefore the public/index.php file below returns a 404 error :

<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;

require __DIR__ . '/../vendor/autoload.php';

$app = AppFactory::create();

$app->get('/', function (Request $request, Response $response, $args) {
    $response->getBody()->write("Hello world!");
    return $response;
});

$app->run();

I have to replace '/' with '/public/' in the code for the page to work. I don't exactly like that.
What should I add to Slim's /public/.htaccess below to remove the /public from the URI ?

<IfModule mod_rewrite.c>
  RewriteEngine On

  RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
  RewriteRule ^(.*) - [E=BASE:%1]

  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^ index.php [QSA,L]
</IfModule>

Edit: Solution used

I redirected my vhost to /public/. The web hosting service I use supports this, so it's the best solution.

Thanks to MrWhite.

Upvotes: 2

Views: 780

Answers (1)

MrWhite
MrWhite

Reputation: 45829

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^$ /public [P]
</IfModule>

This only "forwards" requests for the root / homepage, ie. /, not /foo, etc. This also forwards the request using mod_proxy (as a reverse proxy), whereas you only need a simple internal rewrite.

You need to rewrite every request that would otherwise go to the root directory (outside of /public) to the /public subdirectory. ie. /foo rewrites to /public/foo and /images/bar.jpg to /public/images/bar.jpg, etc.

 RewriteEngine On
 RewriteRule (.*) /public/$1 [L]

(No need for the <IfModule> wrapper since mod_rewrite is mandatory here, it's not optional.)

All your URLs (to everything) should then omit the /public subdirectory.

UPDATE: However, it would seem that the BASE environment variable is still being set to the /public subdirectory by the following directives in /public/.htaccess:

RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]

You could simply comment out (remove) the above directives and hardcode the BASE env var:

SetEnv BASE /

However, it's unclear whether this would be a problem or not in the Slim framework. It's possible that this is being used to construct URLs (although it shouldn't, since this is the filesystem path, not the URL-path by which users access the pages - and can easily be calculated in PHP anyway).


Alternatively, everything in /public should be in your document root (ie. your public directory... public_html or htdocs etc.) then the /src (and other folders) will naturally be outside the document root and no additional directives / .htaccess files required to root the request. (Although not every shared server may give you access to above the document root - although they should.)

Or, simply change the DocumentRoot to /public in your server config.

Upvotes: 1

Related Questions