79

I'm using a shared hosting which uses cPanel as its control panel and within the cPanel public_html is the default root directory, because of this I can't get my Laravel application work properly.

Is there any way to make Laravel use public_html instead of public folder?

AmerllicA
  • 29,059
  • 15
  • 130
  • 154
Ravexina
  • 2,406
  • 2
  • 25
  • 41

14 Answers14

102

Quite easy to find this with a simple search.

See: https://laracasts.com/discuss/channels/general-discussion/where-do-you-set-public-directory-laravel-5

In your index.php add the following 3 lines.

/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/

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

// set the public path to this directory
$app->bind('path.public', function() {
    return __DIR__;
});

Edit:


As Burak Erdem mentioned, another option (and more preferable) is to put this in the \App\Providers\AppServiceProvider register() method.

/**
 * Register any application services.
 *
 * @return void
 */
public function register()
{
    // ...

    $this->app->bind('path.public', function() {
        return base_path('public_html');
    });
}
Robert
  • 5,703
  • 2
  • 31
  • 32
  • it's not working for me: Fatal error: Call to a member function make() on a non-object in... – Ravexina May 13 '15 at 17:14
  • Just by adding that? I'm able switch it around without any errors. Can you post the full error message, it's not telling me much as it is. – Robert May 13 '15 at 19:45
  • 1
    @Robert when I use your solution, it give me error `[ErrorException] chdir(): No such file or directory (errno 2) `. – Faisal Ahsan Mar 18 '16 at 07:54
  • 2
    I know it's been quite a while ago, but this question still is high ranked in Google. Therefore I wanted to point out that, for me, these lines of code should be added AFTER the `Turn On The Lights`-section. Then you should update `path.public` to `path.public_html`. At least, that worked for me. :) – Carsten Jul 01 '16 at 08:22
  • 1
    This does not work for laravel-mix, which still compiles assets to the `public` directory. – Lars Nyström Feb 04 '18 at 15:11
  • This is still the correct solution. I used the second method on 5.7 and it works great! – KingRichard Feb 12 '19 at 06:07
  • This would not work for me until I changed `base_path('public_html')` to `base_path() . '/public_html'` – Metoniem Aug 05 '19 at 17:24
  • "Quite easy to find this with a simple search" Such comments are superfluous. Actually this page shows up as the first result right now. – Gabe Hiemstra Dec 27 '21 at 09:35
27

If Robert's index.php solution is not working for you, you can also register the following code at Application Service Provider (App\Providers\AppServiceProvider.php).

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

public function register()
{
    $this->app->bind('path.public', function() {
        return base_path().'/public_html';
    });
}
Burak Erdem
  • 19,630
  • 7
  • 36
  • 56
16

Server

Methods described in topic are working just fine, so modyfing App\Providers\AppServiceProvider.php register method should do the job:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

public function register()
{
    $this->app->bind('path.public', function() {
        return base_path() . '/public_http';
    });
}

Local php artisan serve development

However, there is one more issue you can experience. If you're developing your app on local machine and you're using php artisan serve command to serve your app you're going to break it with above syntax only. You still need to adjust server.php file which exists in main directory. Edit the contents of it and replace each occurance of /public to /public_html, so it looks like this:

<?php

/**
 * Laravel - A PHP Framework For Web Artisans
 *
 * @package  Laravel
 * @author   Taylor Otwell <taylor@laravel.com>
 */

$uri = urldecode(
    parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
);

// This file allows us to emulate Apache's "mod_rewrite" functionality from the
// built-in PHP web server. This provides a convenient way to test a Laravel
// application without having installed a "real" web server software here.
if ($uri !== '/' && file_exists(__DIR__.'/public_html'.$uri)) {
    return false;
}

require_once __DIR__.'/public_html/index.php';

After that. Just stop your server and reload it with php artisan serve.

Front end laravel-mix development

If you're using webpack and laravel-mix to generate your css and js files then this also needs some update. Without tweaking webpack.mix.js you will end up with something like this on npm run watch or npm run production:

.
..
public
  _html
    js
  public_html
    css
public_html

So it's going to mess up your code. To clarify this you have to provide a public path to your webpack.mix.js file. It could look like this:

const mix = require('laravel-mix');

mix.setPublicPath('public_html/');
mix.js('resources/js/app.js', 'js')
mix.sass('resources/sass/app.scss', 'css');

This is going to change the default definition of public directory from public to public_html and next lines provides a relative path to your setPublicPath value.

Happy coding.

David
  • 1,932
  • 3
  • 27
  • 35
  • Thank you for your answer! this works great, except for vue. it compiles css and js in the proper folder, (in my case it is /../public_html) but they dont work. when it compiles the app.js it does not take the path of the .vue files into account: `./resources/js/components/SetBgImg.vue?vue&type=script&lang=js&":`, should be `./../projectname/resources/js/components/SetBgImg.vue?vue&type=script&lang=js&":` how can this be fixed`? – sharkyenergy Apr 11 '20 at 13:50
  • Don't forget restarting `npm run` to let changes take effect. – Fer Toasted Feb 19 '21 at 18:00
  • I dont use vue but nowadays this answer indeed works for localhost and i rid off of copypasting assets to synced project's public folder in the cloud each damn time. – CodeToLife Apr 22 '21 at 19:02
9

Go to this address:

/app/Providers/AppServiceProvider.php

and append this code to end of file:

public function register()
{   $this->app->bind('path.public', function() {
    return realpath(base_path().'/../public_html');
  });
}
peterh
  • 11,875
  • 18
  • 85
  • 108
Ahmadreza
  • 91
  • 1
  • 1
5

Just want to update all previous answers, if your public_html is not inside laravel folder, then you need to use this code:

$this->app->bind('path.public', function() {
   return realpath(base_path().'/../public_html');
});
Alex
  • 2,707
  • 4
  • 29
  • 42
4

Simple root directory create .htaccess file and add code:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*)$ public/$1 [L]
</IfModule>
Saif uddin
  • 459
  • 4
  • 7
3

For those that need to change the public path so that it is also available to Artisan, add the following to bootstrap/app.php, just after the last singleton method:

$app->bind('path.public', function () {
    return base_path("<your public directory name>");
});
Mike Rockétt
  • 8,947
  • 4
  • 45
  • 81
3

These answers did not work for laravel 5.5, but my own method can help you.

Step 1: Discard all files except the public file to the main directory on the server.

Step 2: Public file to the public_html file on the server.

Step 3: Pull index.php file from public_html and change it like this.

Step 3A:

Orginal -> require __DIR__.'/../vendor/autoload.php';

Changes -> require __DIR__.'/../**created_folder**/vendor/autoload.php';

Original -> $app = require_once __DIR__.'/../bootstrap/app.php';

Changes -> $app = require_once __DIR__.'/../**Created_folder**/bootstrap/app.php';

Step 4: Create symlinkcreate.php

Step 4A: <?php symlink('/home/**server_directory**/**created_folder**/storage/app/public','/home/**server_directory**/public_html/storage');

Step 4B: yourwebsite.com/symlinkcreate.php visit

Step 4C: symlinkcreate.php delete your server.

Finally, the directory structure looks like this:

/etc
/logs
/lscache
/mail
/Your_Created_Folder
  ../LARAVEL_FOLDERS
/public_html
  ../css
  ../js
  ../.htaccess
  ../index.php
  ../web.config
/ssl
/tmp

Finish.

Laravel 5.5 public_html sorunu için bu cevabı gönül rahatlığıyla kullanabilirsiniz.

T.Arslan
  • 123
  • 8
3

It took two days for me to figure out but finally I deployed my Laravel-project to my cPanel webhosting by doing next steps:

  1. Change the server.php file as following:
if ($uri !== '/' && file_exists(__DIR__ . '/public_html' .$uri)) {
    return false;
}

require_once __DIR__ . '/public_html/index.php';
  1. Change webpack.mix.js as following:
mix.js('resources/js/app.js', 'public_html/js')
    .postCss('resources/css/app.css', 'public_html/css', [
        //
    ]);
  1. Change the name of "public" folder in Laravel-project to "public_html" and upload the code to the root directory cPanel. Make sure that you have a back-up from the current public_html directory. If you have the correct PHP version on your hosting and edited .env file then everything should work properly.
miken32
  • 42,008
  • 16
  • 111
  • 154
Reza
  • 167
  • 3
  • 10
3

I use Laravel version 10 and testing all suggestion solution, none of it works. So in bootstrap file under following code.

$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);

added following line code and working well

$app->usePublicPath(__DIR__.'/../../public_html');
2
  1. In bootstrap/app.php:

    Add

    $app->bind('path.public', function() {
      return __DIR__;
    });
    

    right after

    $app = new Illuminate\Foundation\Application(
      realpath(__DIR__)
    );
    
  2. Fixing server.php:

    Change

    if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
      return false;
    }
    
    require_once __DIR__.'/public/index.php';
    

    to

    if ($uri !== '/' && file_exists(__DIR__.'/public_html'.$uri)) {
      return false;
    }
    
    require_once __DIR__.'/public_html/index.php';
    
  3. In .gitignore, change

    /public/hot
    /public/storage
    

    to

    /public_html/hot
    /public_html/storage
    
  4. In webpack.mix.js, change

    mix.js('resources/js/app.js', 'public/js')
      .sass('resources/sass/app.scss', 'public/css');
    

    to

    mix.js('resources/js/app.js', 'public_html/js')
      .sass('resources/sass/app.scss', 'public_html/css');
    

I'm still looking for a fix for the asset() function, which remains broken...

Cameron Hudson
  • 3,190
  • 1
  • 26
  • 38
2

The simplest solution as for me is to create symbolic link.

  1. Make backup of your public_html folder.
  2. Connect to your server via ssh.
  3. In my particular scenario, whole application is located in ~/laravel folder.
  4. Now you have to be in the ~/ folder:
  5. Run rm -r public_html. This command will delete public_html folder and all its contents.
  6. Make symbolic link ln -s $(pwd)/laravel/public $(pwd)/public_html. $(pwd) will be substituted with absolute path from root of the server.
  7. Now you should be able to see desired result.
rela589n
  • 817
  • 1
  • 9
  • 19
  • I don't know why this is not getting more upvotes? It's such a good solution, instead of making changes to the code. Thank you kind stranger. – Svetoslav Stefanov Jul 06 '22 at 11:39
-1

For me none of this worked until I changed the root public folder in server settings. In production it is in /etc/nginx/sites-enabled/<your_site_name>. Edit it with a text editor and just scroll until you see root path pointing to /public folder. Change that to whatever is your new public folder and restart the server. On local, I had to change path in Homestead.yaml and /etc/nginx/sites-enabled/<your_site_name> after I SSHed into Vagrant. vagrant reload --provision to make sure it caught on. Then I also edited index.php and registered a new path in the service provider just in case, but it seems to work without it. I don't use any 3rd party dependencies with Laravel though so I don't know if this will work in that case.

Arthur Tarasov
  • 3,517
  • 9
  • 45
  • 57
-1
  1. Put the contents of /public folder of your laravel application in: public_html or a subfolder in case of subdomain.
  2. Put all other laravel folders and files in a new folder in the top level of the public_html folder for example
/home/{yourcpanelfoldername}/{applicationname}
  1. open file named index.php in the public folder and replace all
    __DIR__.'/../

with

    __DIR__.'/../../{applicationname}/
  1. For laravel versions < 10 put this line
    $app->bind('path.public', function() {
        return __DIR__;
    });

just after this line

    $app = require_once __DIR__.'/../../{applicationname}/bootstrap/app.php';
  1. For laravel version >= 10 add this line
    $app->usePublicPath(__DIR__);

just after this line

    $app = require_once __DIR__.'/../../{applicationname}/bootstrap/app.php';