Solving Broken Image Uploads in Laravel on Shared Hosting (cPanel Addon Domains)

Admin May 07, 2026 Technology

Deploying a Laravel application on shared hosting can sometimes introduce unexpected issues — especially when working with image uploads and storage paths. One of the most common problems developers encounter is:

Uploaded images work locally but return 404 errors or broken images on production.

This issue is especially common on cPanel shared hosting environments using addon domains, where Laravel’s default storage system behaves differently from a VPS or dedicated server setup.

In this article, we’ll walk through:

  • Why uploaded images break on shared hosting
  • Common mistakes developers make
  • The correct way to upload images in Laravel + Livewire
  • How to fix image URLs permanently on cPanel hosting

The Problem

A typical broken image URL looks like this:

https://yourdomain.com/posts/example-image.png


But instead of displaying the image, the browser returns:

404 Not Found


Even worse:

  • The image may exist on the server
  • Uploads may appear successful
  • Everything works locally

This happens because Laravel’s storage system is designed differently from the file structure used by many shared hosting providers.

Why This Happens on Shared Hosting

Laravel normally stores uploaded files here:

storage/app/public


To make these files publicly accessible, Laravel expects you to create a symbolic link using:

php artisan storage:link


This creates:

public/storage → storage/app/public


However, on many cPanel shared hosting providers:

  • SSH access may be unavailable
  • Symlink creation may be restricted
  • Addon domains may not use the standard public_html structure
  • public_path() may not point where you expect

The result:

Laravel uploads successfully, but Apache cannot find the image publicly.

Common Mistakes

1. Using Incorrect Blade Syntax

Incorrect:

<img src="{$post->image}}">


Correct:

<img src="{{ asset($post->image) }}">

2. Saving Wrong Paths to Database

Incorrect:

$data['image'] = '/posts/' . $filename;


Correct:

$data['image'] = 'posts/' . $filename;

3. Relying on storage:link on Shared Hosting

On many shared hosting environments, symlinks are unreliable or blocked entirely.

Instead of fighting the hosting configuration, it is often easier and more reliable to upload directly into Laravel’s public directory.

The Best Solution for Shared Hosting + Livewire

The most reliable approach is:

✅ Upload directly into Laravel’s public/posts folder.

This bypasses:

  • storage symlink issues
  • addon domain path confusion
  • Apache access problems

Final Working Laravel + Livewire Upload Solution

Step 1 — Configure a Custom Disk

Open:

config/filesystems.php


Add this inside the disks array:

'posts' => [

   'driver' => 'local',

   'root' => public_path('posts'),

   'url' => env('APP_URL') . '/posts',

   'visibility' => 'public',

],

Step 2 — Create the Upload Logic

Inside your Livewire component:

if ($this->newImage) {


   $filename = time() . '.' . $this->newImage->getClientOriginalExtension();


   // Ensure folder exists

   if (!file_exists(public_path('posts'))) {

       mkdir(public_path('posts'), 0755, true);

   }


   // Store directly into public/posts

   $this->newImage->storeAs(

       '',

       $filename,

       'posts'

   );


   // Save image path

   $data['image'] = 'posts/' . $filename;

}

Step 3 — Display Images Correctly

In Blade:

<img src="{{ asset($post->image) }}" alt="{{ $post->title }}">


This generates:

https://yourdomain.com/posts/image.png


which Apache can serve directly.

Important Shared Hosting Tips

Use Correct Folder Permissions

Ensure:

/public/posts


has permission:

755


If uploads fail temporarily, try:

775

Clear Laravel Cache After Config Changes

Whenever you modify filesystems.php, clear config cache:

php artisan config:clear

php artisan cache:clear


If SSH is unavailable, use cPanel Terminal or a temporary route.

Why This Approach Works Better on cPanel

Uploading directly into the public directory:

  • avoids symlink problems
  • avoids addon-domain path confusion
  • works consistently on Truehost, Namecheap, Hostinger, and similar shared hosts
  • simplifies image URLs
  • reduces deployment headaches

For small to medium Laravel applications on shared hosting, this method is often the most practical and stable solution.

Final Thoughts

Laravel’s storage system is excellent on VPS and cloud infrastructure, but shared hosting environments often require a more direct approach.

If your Laravel images:

  • work locally but not on production
  • return 404 errors
  • break on addon domains
  • fail with storage:link

then uploading directly into Laravel’s public folder is usually the cleanest fix.

With the setup above, your uploads will work reliably across most cPanel shared hosting providers.


0 Comments
1 Shares
Share Article:

Comments 0

No comments yet. Be the first to share your thoughts!

Leave a Comment

Security: 1 + 2 =