I know this is a very popular question but I haven't been able to find a working solution for Laravel 5. I've been trying to migrate from Codeigniter for a long time, but this convoluted installation process keeps putting me off.

I don't want to run a VM, this just seems awkward when switching between projects.

I don't want to set my document root to the public folder, this is also awkward when switching between projects.

I've tried the .htaccess mod_rewrite method

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

This just gives me a Laravel NotFoundHttpException in compiled.php line 7610.

When I tried L4 a while ago, I used the method of moving the contents of the public folder into the root. The structure of L5 is quite different and following the same steps completely broke Laravel (the server would only return a blank page).

Is there a decent method of removing 'public' in a development environment that:

  1. Works with L5
  2. Allows me to switch between projects with ease (I'm usually working on 2 or 3 at any one time).

Thanks

** I'm using MAMP and PHP 5.6.2

1 upvote
  flag
The folder structure in the guide is different to mine, I imagine he is not using L5? I omitted the changes he made to the Bootstrap/Paths file, because it doesn't exist. The project seems to be working though. Do you think this is ok? – user1537360
upvote
  flag
my mistake let me add answer for L5 – kamlesh.bar
upvote
  flag
no success trying for same – kamlesh.bar
1 upvote
  flag
It seems to work by just modifying the paths in the index.php file, but I'm new to Laravel so obviously can't comment on whether this is stable / safe. – user1537360
upvote
  flag
The other folders/files are supposed to be underneath your document root. – Mike Rockétt
upvote
  flag
Try this answer on this page : //allinonescript.com/a/28735930/3786343 – Kamlesh
upvote
  flag
This work for all laravel versions //allinonescript.com/questions/15586397/… – Wasim A.
upvote
  flag
This solution over here worked for me. justcode.me/laravel/… – Luzan Baral
upvote
  flag

19 Answers 11

1) I haven't found a working method for moving the public directory in L5. While you can modify some things in the bootstrap index.php, it appears several helper functions are based on the assumption of that public directory being there. In all honestly you really shouldn't be moving the public directory.

2) If your using MAMP then you should be creating new vhosts for each project, each serving that projects public directory. Once created you access each project by your defined server name. http://project1.dev, http://project2.dev

It's possible to remove public from url in laravel5. Follow these steps:

step 1 copy all file from public and paste on root directory

step 2 open index.php file replace with

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

to

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

and

$app = require_once __DIR__.'/../bootstrap/app.php';

to

$app = require_once __DIR__.'/bootstrap/app.php';

And remove all cache and cookies.

upvote
  flag
Hi, I have tried your method, performed the above steps but it shows the following errors: Warning: require_once(D:\Projects\laravel/public/index.php): failed to open stream: No such file or directory in D:\Projects\laravel\server.php on line 21 Fatal error: require_once(): Failed opening required 'D:\Projects\laravel/public/index.php' (include_path='.;C:\xampp\php\PEAR') in D:\Projects\laravel\server.php on line 21 – Ali Shahzad

Let's say you placed all the other files and directories in a folder named 'locale'.

enter image description here

Just go to index.php and find these two lines:

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

$app = require_once __DIR__.'/../bootstrap/app.php';

and change them to this:

require __DIR__.'/locale/bootstrap/autoload.php';

$app = require_once __DIR__.'/locale/bootstrap/app.php';
up vote 248 down vote accepted

For Laravel 5:

  1. Rename server.php in your Laravel root folder to index.php
  2. Copy the .htaccess file from /public directory to your Laravel root folder.

Thats it !! :)

upvote
  flag
Very nice it's working... Thanks – Kamlesh
2 upvote
  flag
you are welcome.. :) it also workes for Laravel 4.2 – Asfaq Tamim
57 upvote
  flag
whatchout as this may be unsafe, make sure no one can't request your .env file if you're doing this unless you're ok with people viewing your database password in clear text ;) – GabLeRoux
28 upvote
  flag
This wouldn't work if you are referencing your assets using the relative path from root ie. "/assets/styles.css" and so on. I am still struggling with finding best way to deploy it over servers – Ghazanfar Mir
3 upvote
  flag
not working for me – Richie
upvote
  flag
I love u, my hero :D – Raccoon
upvote
  flag
Works. Thank You. – Morteza Ziaeemehr
upvote
  flag
This works... But is there any consequence/disadvantage in using this? Many are suggesting setting up virtual host, or copying files manually, etc... Does this work in production too? – Bogz
2 upvote
  flag
This will work but when we include assets it will not work.. – Anand Singh
upvote
  flag
Very good thanks. I searched for a solution hours. There it is. A minute work :) – TreantBG
upvote
  flag
It works. It would be better if you can explain the reason too. – Krishnadas PC
upvote
  flag
It worked for me. – Hiroshi Rana
upvote
  flag
There is a problem. Doing so i am able to access the routes with and without public prefix. So rather renaming the server.php to index.php you must delete server.php and move index.php from public to document root. – Rahman Qaiser
upvote
  flag
it sure works.. @Bogz - I could view my env file before too..path="localhost/laravel/.env" , any way to avoid that? – T.Adak
upvote
  flag
nice..also works for me.. – Rahul Sharma
upvote
  flag
Guys after doing this it works but then my locahost:8000 is not working now, what should I do ? – Lim Guang Jian
4 upvote
  flag
all assets link not working with this method – Abdul Manan
upvote
  flag
worked for me . Thanks :) – Mrugesh Mistry
upvote
  flag
@MrugeshMistry you are welcome :) – Asfaq Tamim

Easy way to remove public from laravel 5 url. You just need to cut index.php and .htaccess from public directory and paste it in the root directory,thats all and replace two lines in index.php as

require __DIR__.'/bootstrap/autoload.php';
$app = require_once __DIR__.'/bootstrap/app.php';
upvote
  flag
its also working, thanks Sadiq – Abid
1 upvote
  flag
So easy and awesome... Thanks – Zohaib
upvote
  flag
it worked for me !! thanks – Mazino S Ukah
1 upvote
  flag
After that css not load, bcoz all css are in public and the public is removed from url – Tarzan
upvote
  flag
You can put "public/" before the js or css files while loading, eg Html::script("public/js/....."); --But the best solution would be virtual host... – Muhammad Sadiq
upvote
  flag
Thanks @Muhammad Sadiq it works ! – Manish Goswami

@rimon.ekjon said:

Rename the server.php in the your Laravel root folder to index.php and copy the .htaccess file from /public directory to your Laravel root folder. -- Thats it !! :)

That's working for me. But all resource files in /public directory couldn't find and request urls didn't work, because I used asset() helper.

I changed /Illuminate/Foundation/helpers.php/asset() function as follows:

function asset($path, $secure = null)
{
    return app('url')->asset("public/".$path, $secure);
}

Now everything works :)

Thank you @rimon.ekjon and all of you.

upvote
  flag
oh, you save my life. I love you brother. – Abu Taleb
upvote
  flag
This is not a good way to resolve this problem, as you are trying to update in vendors directory which is not good practice. – Shadman Jamil
upvote
  flag
you only need to add RewriteRule ^(.*)$ public/$1 [L] in your .htaccess file which you have copied from public directory, by removing this line RewriteRule ^(.*)/$ /$1 [L,R=301] – Shadman Jamil

I have solved the issue using 2 answers:

  1. Renaming the server.php to index.php (no modifications)
  2. Copy the .htaccess from public folder to root folder (like rimon.ekjon said below)
  3. Changing .htaccess it a bit as follows for statics:

    RewriteEngine On
    
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)/$ /$1 [L,R=301]
    
    RewriteCond %{REQUEST_URI} !(\.css|\.js|\.png|\.jpg|\.gif|robots\.txt)$ [NC]
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
    
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_URI} !^/public/
    RewriteRule ^(css|js|images)/(.*)$ public/$1/$2 [L,NC]
    

    If there are any other static files needed just add the extension to the previous declared list

upvote
  flag
Its worked like a charm :) – Asim Shahzad
upvote
  flag
Works well. thanks :-) – Fokwa Best
upvote
  flag
hello @KA_lin. How do I prevent someone from viewing .env like so localhost/oap/.env – Fokwa Best
4 upvote
  flag
Hmmm... try RewriteRule ^.env - [F,L,NC] – ka_lin
upvote
  flag
Or <Files ~ "\.env$"> Order allow,deny Deny from all </Files> – ka_lin
2 upvote
  flag
that works ! thanks – Rahman Qaiser
2 upvote
  flag
Works perfect! Thanks – Chris J Kikoti
1 upvote
  flag
Its work for me. thanks bro – Asfandiyar Khan
upvote
  flag
yahyyy works :) – Qubaish Bhatti
upvote
  flag
Glad it helped you out :D – ka_lin
upvote
  flag
Nice answer. Really helped – Mian Haseeb
upvote
  flag
works like a charm, thx – yenerunver
upvote
  flag
Thanks a lot @ka_lin, is there any way to then remove access through /public/ ? like www.yoursite.com works but www.yoursite.com/public also works, is it possible to remove the last one ? – adaba
upvote
  flag
Hmmm... try RewriteRule ^(public/) - [F,L,NC]. I am just guessing, please tell me if it works. I will update my answer – ka_lin
upvote
  flag
perfect solutions! – Bhavik Chauhan
upvote
  flag
Worked perfect for me ! – NZSteve
upvote
  flag
Thanks. It works! – erdemildiz
6 upvote
  flag
It is working but css, js and images are not loading – Chetan Khandla
upvote
  flag
@ChetanKhandla You can check my answer below to let it work. Remove "public" in Laravel 5.5 – Brigo
upvote
  flag
this didn't work for me, I have something like localhost:8080/public/public when I navigated to the root url localhost:8080/abimswake – Pianistprogrammer

I would like to add to @Humble Learner and note that the proper location to "fix" the url path for assets is /Illuminate/Routing/UrlGenerator.php/asset().

Update the method to match:

public function asset($path, $secure = null)
{
    if ($this->isValidUrl($path)) return $path;
    $root = $this->getRootUrl($this->getScheme($secure));
    return $this->removeIndex($root).'/public/'.trim($path, '/');
}

This will fix scripts, styles and image paths. Anything for asset paths.

For XAMPP user to remove public from url without touching laravel default filesystem is to set a Virtual Host for your application to do this jsut follow these steps

  1. Open the XAMPP control panel application and stop Apache. Be aware that late Windows machines might run it as a service, so check the box to the left of the Apache module.

  2. Navigate to C:/xampp/apache/conf/extra or wherever your XAMPP files are located.

  3. Open the file named httpd-vhosts.conf with a text editor.

  4. Around line 19 find # NameVirtualHost *:80 and uncomment or remove the hash.

  5. At the very bottom of the file paste the following code:

<VirtualHost *>
    ServerAdmin admin@localhost.com
    DocumentRoot "C:/xampp/htdocs" # change this line with your htdocs folder
    ServerName localhost
    ServerAlias localhost
    <Directory "C:/xampp/htdocs">
        Options Indexes FollowSymLinks Includes ExecCGI
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>
  1. Now you can copy and paste the code above below to add your Virtual Host directories. For example I’m working on a site called Eatery Engine so the following snippet will allow me to work with sub-domains on my local install:
<VirtualHost eateryengine.dev>
    ServerAdmin admin@localhost.com
    DocumentRoot "C:/xampp/htdocs/eateryengine" # change this line with your htdocs folder
    ServerName eateryengine.dev
    ServerAlias eateryengine.dev
    <Directory "C:/xampp/htdocs/eateryengine">
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>
  1. Next head over to your Windows host file to edit your HOSTS. the file will be located at C:/Windows/System32/drivers/etc/hosts, where hosts is the file. Open it with notepad.
  2. Look for #localhost name resolution is handled within DNS itself.

127.0.0.1 localhost

localhost name resolution is handled within DNS itself.

127.0.0.1       localhost
127.0.0.1       eateryengine.dev #change to match your Virtual Host.
127.0.0.1       demo.eateryengine.dev #manually add new sub-domains.
  1. Restart Apache and test everything.

The original article can be found here

METHOD 1:

I just rename server.php to index.php and it works

METHOD 2:

This work well for all laravel version...

Here is my Directory Structure,

/laravel/
... app
... bootstrap
... public
... etc

Follow these easy steps

  1. move all files from public directory to root /laravel/
  2. now, no need of public directory, so optionally you can remove it now
  3. now open index.php and make following replacements

require DIR.'/../bootstrap/autoload.php';

to

require DIR.'/bootstrap/autoload.php';

and

$app = require_once DIR.'/../bootstrap/start.php';

to

$app = require_once DIR.'/bootstrap/start.php';

  1. now open bootstrap/paths.php and change public directory path:

'public' => DIR.'/../public',

to

'public' => DIR.'/..',

and that's it, now try http:// localhost/laravel/

upvote
  flag
Its ok for everything. but artisan command is not working, just it show "Could not open input file: artisan" . Is there any suggestion ? – Kabir Hossain
upvote
  flag
Thanks wasim a, Method 2 is working for me – Faridul Khan
upvote
  flag
This method worked, If you are OK to expose your database credentials to users. localhost/laravel/.env – MasoodUrRehman

Another method that I use is to create a symbolic link (in Linux, don't know about Win) using the ln command in htdocs or www i.e. ln projectname/public project The site is thus accessible via localhost/project

I have read some article before and it's working fine but really don't know is safe or not

    a. Create new folder local.
    b. Move all project into the local folder expect public folder.
    c. Move all the content of public folder to project root.
    d. Delete the blank public folder
    f. Edit the index file. 

Edit the index.php

require __DIR__.'/../bootstrap/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';

to

require __DIR__.'/local/bootstrap/autoload.php';
$app = require_once __DIR__.'/local/bootstrap/app.php';

There is always a reason to have a public folder in the Laravel setup, all public related stuffs should be present inside the public folder,

Don't Point your ip address/domain to the Laravel's root folder but point it to the public folder. It is unsafe pointing the server Ip to the root folder., because unless you write restrictions in .htaccess, one can easily access the other files.,

Just write rewrite condition in the .htaccess file and install rewrite module and enable the rewrite module, the problem which adds public in the route will get solved.

1 upvote
  flag
You are correct .. Why we should break the things which framework is providing by default. We should try to understand the reason behind this before breaking this. – Mittul At TechnoBrave
1 upvote
  flag
I guess this answer should get more up-votes as it is suggesting users not to follow the steps which however are working as it will make security concerns by following those. – Mittul At TechnoBrave

Even if i do not recommend putting Laravel on the root folder there are some cases when it could not be avoided; for those cases the above methods do not work for assets so i made a quick fix changing the htaccess: after copying server.php to index.php edit the .htaccess file like so:

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    ### fix file rewrites on root path ###
    #select file url
    RewriteCond %{REQUEST_URI} ^(.*)$
    #if file exists in /public/<filename>
    RewriteCond %{DOCUMENT_ROOT}/public/$1 -f
    #redirect to /public/<filename>
    RewriteRule ^(.*)$ public/$1 [L]
    ###############

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)/$ /$1 [L,R=301]

    # Handle Front Controller...

    #RewriteCond %{REQUEST_FILENAME} -d # comment this rules or the user will read non-public file and folders!
    #RewriteCond %{REQUEST_FILENAME} -f #
    RewriteRule ^ index.php [L]
</IfModule>

This was a quick fix i had to make so anyone is welcome to upgrade it.

 You can follow only 2 step


 1- cut .htaccess from public folder and paste to root(mainFolder)  
 2- Rename server.php file to index.php AT your root dir. (mainFolder) 

Just create .htaccess file at root and add these lines to it

<IfModule mod_rewrite.c>
    RewriteEngine On

    RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

That's it!

upvote
  flag
I answered below before reading your answer and this must be the accepted answer. No file changes: just a simple, clever rule. – Brigo
upvote
  flag
Its not working... – Raham
upvote
  flag
@Raham what is your current url? – Abhinav Saraswat
upvote
  flag
@Abhinav Saraswat I fixed my issue.Thank you – Raham
upvote
  flag
This didn't work for me – Pianistprogrammer

Even if these solutions works for you guys, I would request you not to follow this. Here is the reason why.

You should be pointing your Apache host root to the $LARAVEL_PATH/public directory instead of $LARAVEL_PATH.

The point of having sub directory for www host root instead of project root is that you're not leaking any of your project files through your web server.

Even though all the PHP files have the file suffix .php, malicious user can access your $LARAVEL_PATH/storagedirectory and its subdirectory contents, read your composer.json or package.json to find vulnerable dependencies or read .env file etc.

If you're running on shared hosting and you have mandatory public_html, try installing Laravel outside of that public_html directory and either removing public_html (if empty) and replace it with symlink to $LARAVEL_PATH/public OR if you want the Laravel instance to be subdirectory of public_html, do the same but create symlink from $LARAVEL_PATH/public to public_html/$PROJECT_SUBDIR.

That public directory is there for reason to make project a bit more secure. Solve the actual problem and don't try to break this simple but nice security addition. :)

Hope this helps.

upvote
  flag
i accept your answer bcoz its secure for storage folder. Can you explain how to host the laravel app in shared hosting – Zaza
upvote
  flag
Check this out - //allinonescript.com/questions/19923091/… , hope this helps. – Mittul At TechnoBrave

Laravel 5.5

After having installed Laravel for the first time, I faced the renowned "public folder problem" and I came up with this solution that, in my personal opinion, is "cleaner" then the others I found on the Web.


Achievements

  • Don't have public word in the URI
  • Protect the .env file against curious people

Everything can be done just editing the .htaccess using mod_rewrite and four simple rules.


Steps

  1. Move the .htaccess file in public/.htaccess in the main root
  2. Edit it as below

I commented everything, so it should be clear (I hope) also to those who have never used mod_rewrite (not that I'm an expert, all the opposite). Also, to understand the rules, it must be clear that, in Laravel, if Bill connects to https://example.com, https://example.com/index.php is loaded. This file just contains the command header("refresh: 5; https://example.com/public/"), which sends the request to https://example.com/public/index.php. This second index.php is responsible to load the controller and other stuff.

# IfModule prevents the server error if the app is moved in an environment which doesn’t support mod_rewrite
<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    # RULES ORIGINALLY IN public/.htaccess ---
    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Handle Front Controller...
#    RewriteCond %{REQUEST_FILENAME} !-d
#    RewriteCond %{REQUEST_FILENAME} !-f
#    RewriteRule ^ index.php [L]

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    # --- END

    # PERSONAL RULES ---
    # All the requests on port 80 are redirected on HTTPS
    RewriteCond %{SERVER_PORT} ^80$
    RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R,L]

    # When .env file is requested, server redirects to 404
    RewriteRule ^\.env$ - [R=404,L,NC]

    # If the REQUEST_URI is empty (means: http://example.com), it loads /public/index.php
    # N.B.: REQUEST_URI is *never* actually empty, it contains a slash that must be set as match as below
    # .* means: anything can go here at least 0 times (= accepts any sequence of characters, including an empty string)
    RewriteCond %{REQUEST_URI} ^/$
    RewriteRule ^(.*) /public/index.php [L]

    # If the current request is asking for a REQUEST_FILENAME that:
    # a) !== existent directory
    # b) !== existent file
    # => if URI !== css||js||images/whatever => server loads /public/index.php, which is responsible to load the app and the related controller
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule !^(css|js|images|media)/(.*)$ /public/index.php [L,NC]

    # If the current request is asking for a REQUEST_FILENAME that:
    # a) !== existent directory
    # b) !== existent file
    # => if URI == css||js||images[=$1]/whatever[=$2] => server loads the resource at public/$1/$2
    # If R flag is added, the server not only loads the resource at public/$1/$2 but redirects to it
    # e.g.: bamboo.jpg resides in example.com/public/media/bamboo.jpg
    #       Client asks for example.com/media/bamboo.jpg
    #       Without R flag: the URI remains example.com/media/bamboo.jpg and loads the image
    #       With R flag: the server redirects the client to example.com/public/media/bamboo.jpg and loads the image
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(css|js|images|media)/(.*)$ /public/$1/$2 [L,NC]
    # --- END

</IfModule>

The following rule (originally in public/.htaccess) can be deleted. The same rule, in fact, is explicited in a more detailed way in the last two rules.

# Handle Front Controller...
#    RewriteCond %{REQUEST_FILENAME} !-d
#    RewriteCond %{REQUEST_FILENAME} !-f
#    RewriteRule ^ index.php [L]

EDIT: I missed Abhinav Saraswat's solution and his answer should be the accepted one. Just one, simple and clear rule that redirects all the traffic to the public folder without modifying any file.

In Laravel 5.5 create .htacess file in your root directory and placed the following code:- Reference Link

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    RewriteCond %{REQUEST_FILENAME} -d [OR]
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^ ^$1 [N]

    RewriteCond %{REQUEST_URI} (\.\w+$) [NC]
    RewriteRule ^(.*)$ public/$1 

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ server.php

</IfModule>

Not the answer you're looking for? Browse other questions tagged or ask your own question.