skip to Main Content

I have managed to “rebase” the root from a directory in order to keep public files separated from configs, helpers, and controllers, thanks to this answer and this answer.

However I realized that if a user type http://domain.com/public it will not redirect to http://domain.com this is harmful for SEO because robots will treat them as two urls thus duplicate.

I need to 301 redirect /public to root but as long as I am trying. It doesn’t work.

My htaccess looks like the following:

# Options
Options +FollowSymLinks +MultiViews -Indexes
DirectorySlash off

# Enable Rewrite Engine
RewriteEngine on
RewriteBase /

# Exceptions
RewriteCond %{REQUEST_URI} ^/(images|javascripts|stylesheets)/ [NC]
RewriteRule ^ - [L]

# www to non-www
RewriteCond %{HTTP_HOST} ^www.(.+)$ [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%2://%1%{REQUEST_URI} [L,R=301]

# Make /public like it was root
RewriteCond %{THE_REQUEST} /public/([^s]+) [NC]
RewriteRule ^ /%1 [NC,L,R]
RewriteCond %{REQUEST_URI} !^/public
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /public/$1 [NC,L,QSA]

# Error pages
ErrorDocument 403 /errors/403.php
ErrorDocument 404 /errors/404.php
ErrorDocument 500 /errors/500.php

<files .htaccess="">
  order allow,deny
  deny from all
</files>

In this way it will redirect to http://domain.com//

How can I fix this issue?

EDIT

My website directory structure is:

·
|__data
|__controllers
|__helpers
|__partials
|__layouts
|__images
|__javascripts
|__stylesheets
|__public
   |__index.php
   |__subfolder
      |__index.php

In root there won’t be any index.php pages. So I need to make the /public dir as it was my root, in order to keep configs and other directories that users don’t have to see separate.

3

Answers


  1. There’s a number of things here that you need to address, but it appears that the core of it is here:

    # Make /public like it was root
    RewriteCond %{THE_REQUEST} /public/([^s]+) [NC]
    RewriteRule ^ /%1 [NC,L,R]
    RewriteCond %{REQUEST_URI} !^/public
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ /public/$1 [NC,L,QSA]
    

    That block is going to generate a loop. It says “if the URL contains public, redirect it to root, but if it does NOT contain public, redirect it to public”.

    I think what you’re trying to do is just:

    RewriteRule ^public/(.*) /$1 [R=301,L]
    

    It’s also worth pointing out that your block at the bottom isn’t going to do anything. I suspect that what you meant was:

    <Files .htaccess>
    

    However, for good measure, you might try

    <FilesMatch ^.>
    

    for all “dot-files”.

    Login or Signup to reply.
  2. Replace your 2 public/ related rules to this:

    # add a trailing slash if public/$1 is a directory
    RewriteCond %{DOCUMENT_ROOT}/public/$1 -d
    RewriteRule ^(.*?[^/])$ %{REQUEST_URI}/ [L,R=301,NE]
    
    # Make /public like it was root
    RewriteCond %{THE_REQUEST} s/+public/(S*)s [NC]
    RewriteRule ^ /%1 [L,R=301,NE]
    
    # internally add public/ to URIs
    RewriteRule ^(?!public/).*$ public/$0 [L,NC]
    

    Without first trailing slash add rule if you use a URL for sub-directory e.g. http://domain.com/subfolder then after 3rd rule adding public/ in the URI it internally becomes http://domain.com/public/subfolder which is a valid directory and Apache’s mod_dir module adds a trailing slash in the end doing a 301 redirect to http://domain.com/public/subfolder/ and this will expose public/ part to your clients.

    When first trailing slash is there we check if destination is directory and add a trailing slash in original non-/puclic/ URL itself.

    Login or Signup to reply.
  3. Ok, with your edit, it now appears that you’re asking the opposite of how I initially interpreted it. It kind of looks to me as though you’re introducing an additional layer of complexity in order to protect files that shouldn’t be inside the document directory to begin with.

    What I would recommend is more from a security perspective than an httpd configuration perspective. If files aren’t meant to be public, move them out of the document directory. You’d end up with your regular content, plus images, js and css, in the document directory, and the rest of that stuff outside of it.

    Failing that, if you insist on using mod_rewrite to accomplish this, I’d recommend something like the following:

    RewriteCond %{DOCUMENT_ROOT}public%{REQUEST_FILENAME} -f
    RewriteRule ^ /public%{REQUEST_URI} [PT]
    

    However, note that this doesn’t actually solve the problem, since that “private” content is still there, inside the document directory, waiting for someone to figure out how to get at it.

    What I’d recommend is that you take a step back and figure out what problem you’re actually trying to solve. If it’s the problem of private files being in the document root, the right solution is to move them out of that document root, not try to route around them being there.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search