Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Puankare's avatar

How to link storage when "public" folder is renamed to "public_html"?

I am having trouble linking my storage folder correctly using "php artisan storage:link"

On prod server I have "public_html" instead of "public". Thus, I have:

in AppServiceProvider.php

  public function register(): void
  {
    //Public folder name changed with public_html
    $this->app->bind('path.public', function () {
      return base_path() . '/public_html';
    });
  }

app.php

  ->registered(function ($app) {
    $app->usePublicPath(path: realpath(base_path('public_html')));
  })

and filesystems.php

        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public_html'),  
            'url' => env('APP_URL') . '/storage', //'url' => env('APP_URL') . '/storage',
            'visibility' => 'public',
            'throw' => false,
        ],
...
    'links' => [
        public_path('storage') => storage_path('app/public_html'), // org: app/public
    ],

But still, when I runphp artisan storage:link, it tries to link "\public\storage" to "\storage\app/public_html", where I expect it to link "\public_html\storage" to "\storage\app/public_html",

I don't know if there are any other config files where I have to tell Laravel it's "public_html" and not "public"

0 likes
22 replies
aruszala's avatar

@puankare It looks like you're using a Windows OS which uses \ as directory separator, but configuring your app using a *nix / directory separator. Try using the DIRECTORY_SEPARATOR php constant instead:

  public function register(): void
  {
    //Public folder name changed with public_html
    $this->app->bind('path.public', function () {
      return base_path() . DIRECTORY_SEPARATOR . 'public_html';
    });
  }
        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public_html'),  
            'url' => env('APP_URL') . DIRECTORY_SEPARATOR . 'storage', //'url' => env('APP_URL') . '/storage',
            'visibility' => 'public',
            'throw' => false,
        ],
...
    'links' => [
        public_path('storage') => storage_path('app' . DIRECTORY_SEPARATOR . 'public_html'), // org: app/public
    ],
Puankare's avatar

Thanks @aruszala. Though I appreciate the tip, and will be using DIRECTORY_SEPARATOR moving worward, that didn't solve my issue.

With php artisan storage:link, this is what I get:

The system cannot find the path specified.

   INFO  The [D:\xampp\htdocs\Projects\test\public\storage] link has been connected to [D:\xampp\htdocs\Projects\test\storage\app\public_html].

and of course, nothing is connected because D:\xampp\htdocs\Projects\test\public\storage doesn't exist.

aruszala's avatar

@Puankare Only change your AppServiceProvider.php file:

  public function register(): void
  {
    //Public folder name changed with public_html
    $this->app->bind('path.public', function () {
      return base_path() . DIRECTORY_SEPARATOR . 'public_html';
    });
  }

Do NOT change anything else, ex.: your config/filesystems.php file should be:


        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
            'throw' => false,
        ],
...

    'links' => [
        public_path('storage') => storage_path('app/public'),
    ],
Puankare's avatar

@Tray2, thanks. But I don't think the issue is related to xampp. I don't even run xampp apache, I only artisan serve. I used to code in pure php and thus I keep my project folders under xampp/ and didn't change that after started learning laravel.

Puankare's avatar

@aruszala , ah ok! :) Though I liked the consistent directory separators after using . DIRECTORY_SEPARATOR ., I will follow your advice. I am back to:

The system cannot find the path specified.

   INFO  The [D:\xampp\htdocs\Projects\test\public\storage] link has been connected to [D:\xampp\htdocs\Projects\test\storage\app/public_html].
aruszala's avatar

@Puankare It looks like you still have the wrong path:

D:\xampp\htdocs\Projects\test\storage\app/public_html

vs:

D:\xampp\htdocs\Projects\test\storage\app\public
aruszala's avatar

@Puankare Also, in your config file make sure you have:


    'links' => [
        public_path('storage') => storage_path('app/public'),
    ],

This is what controls what the php artisan storage:link command uses to symlink the directories.

Puankare's avatar

@aruszala - now I am confused :) Let me share the current.

As you said, I set filesystems.php back to default:

        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public'), // 'root' => storage_path('app/public'), 
            'url' => env('APP_URL') . 'storage', //'url' => env('APP_URL') . '/storage',
            'visibility' => 'public',
            'throw' => false,
        ],
		...
    'links' => [
        public_path('storage') => storage_path('app/public'), 
    ],

AppServiceProvider.php

  public function register(): void
  {
    //Public folder name changed with public_html
    $this->app->bind('path.public', function () {
      return base_path() . DIRECTORY_SEPARATOR . 'public_html';
    });
  }

app.php

  ->registered(function ($app) {
    $app->usePublicPath(path: realpath(base_path('public_html')));
  })

Regarding the wrong path separator, as long as I use:

    'links' => [
        public_path('storage') => storage_path('app/public'), 
    ],

I get:

The system cannot find the path specified.

   INFO  The [D:\xampp\htdocs\Projects\test\public\storage] link has been connected to [D:\xampp\htdocs\Projects\test\storage\app/public].

when I use:

    'links' => [
        public_path('storage') => storage_path('app' . DIRECTORY_SEPARATOR . 'public'), 
    ],

I get:

The system cannot find the path specified.

   INFO  The [D:\xampp\htdocs\Projects\test\public\storage] link has been connected to [D:\xampp\htdocs\Projects\test\storage\app\public].

In both options, it still says: "The system cannot find the path specified". The problem lies with the initial part: there is no 'D:\xampp\htdocs\Projects\test\public\storage', it should be D:\xampp\htdocs\Projects\test\public_html\storage'

aruszala's avatar

@Puankare It seems the public path is not registering. In Laravel 10 and newer, you could try this instead in the AppServiceProvider.php file:

public function register()
{
    app()->usePublicPath( __DIR__ . '/../../public_html' );
}

Also, you're missing a directory separator in your config file:

'url' => env('APP_URL') . 'storage',

vs:

'url' => env('APP_URL') . '/storage',
Puankare's avatar

@aruszala I am on Laravel 11, and it doesnt have usePublicPath :(

I corrected to: 'url' => env('APP_URL') . '/storage',

aruszala's avatar

@Puankare Sorry it's app()->usePublicPath( __DIR__ . '/../../public_html' );, I updated the previous reply.

Puankare's avatar

@aruszala, thanks. I changed AppServiceProvider.php to:

  public function register(): void
  {
    //Public folder name changed with public_html
    $this->app->bind('path.public', function () {
      return base_path() . DIRECTORY_SEPARATOR . 'public_html';
      // return base_path('/public_html');
    });
    app()->usePublicPath(__DIR__ . '/../../public_html');
  }

Still the same error...

aruszala's avatar

@Puankare You should take the old code out:

  public function register(): void
  {
    app()->usePublicPath( __DIR__ . '/../../public_html' );

/* OLD CODE
    //Public folder name changed with public_html
    $this->app->bind('path.public', function () {
      return base_path() . DIRECTORY_SEPARATOR . 'public_html';
      // return base_path('/public_html');
    });
*/
  }

Take a look here:

https://laravel.com/docs/10.x/upgrade#public-path-binding

Puankare's avatar

@aruszala, I gave up, and put:

    'links' => [
        ('D:\xampp\htdocs\Projects\test\public_html\storage') => storage_path('app/public'), 
    ],

which seems to work... anything wrong with that?

aruszala's avatar

@Puankare Personally I would reconfigure apache to use the public directory as web root or keep the public folder and create a symlink for public_html to point to the public folder.

Is there a specific reason why you have to move the public folder to public_html?

Puankare's avatar

@aruszala hostinger cloud server public folder is named "public_html", not "public" - and I can't change that to "public" on cloud. I am using vscode and git to upload from local dev to > git and to > prod server, and changing the laravel "public" to "public_html" was the best solution I could come up with to deal with it.

Tray2's avatar

@Puankare Then why are you changing the directory names, that makes no sense.

Stanoid's avatar

@puankare Replace links array in config/FileSystem.php with: [base_path('public_html/storage') => storage_path('app/public'),] this should create the links to public_html instead of public folder.

Please or to participate in this conversation.