Menü schliessen
Created: June 20th 2025
Last updated: June 26th 2025
Categories: IT Development,  Laravel
Author: Ian Walser

How to Mount Public Storage in Laravel 12 Using Docker & Sail (Fix 404 and 403 Errors)

Donation Section: Background
Monero Badge: QR-Code
Monero Badge: Logo Icon Donate with Monero Badge: Logo Text
82uymVXLkvVbB4c4JpTd1tYm1yj1cKPKR2wqmw3XF8YXKTmY7JrTriP4pVwp2EJYBnCFdXhLq4zfFA6ic7VAWCFX5wfQbCC

Introduction

Skip to Step-By-Step Guide

If you’ve ever tried accessing uploaded files in a Laravel app running in Docker using Sail, only to be met with a dreaded 404 or missing file icon, you're not alone. Laravel’s "php artisan storage:link" command creates a symbolic link between "storage/app/public" and "public/storage" — a crucial step to serve uploaded files publicly. However, this doesn't "just work" when you're using Docker and Sail unless it's properly configured.

In this guide, we'll walk through how to mount a public volume in a Laravel 12.x application using Docker and Sail, and how to ensure your file uploads are accessible.

Why Laravel Needs "php artisan storage:link"

When your application handles file uploads — profile pictures, reports, PDFs, etc. — Laravel stores them in "storage/app/public". These files aren't web-accessible by default. The "php artisan storage:link" command creates a symbolic link in "public/storage" pointing to the real directory.

This is essential for your app to serve those files through HTTP.

What It Looks Like

$ php artisan storage:link

The [public/storage] directory has been linked.

Simple, right? But in Dockerized Laravel apps using Sail, things aren’t quite that straightforward.

Common Pitfalls with Docker and Laravel Storage

  • Symlinks inside the container don’t affect the host filesystem
  • Web servers (like nginx) may not see the linked path if it doesn’t exist at container boot
  • The command "php artisan storage:link" may need to be executed under the correct user context inside the container

Let’s fix that by running a proper sequence inside your Sail Docker container.

Step-by-Step: Mounting Laravel Storage Volume with Docker and Sail

1. Run the Sail container

If you haven’t already, boot up your Laravel environment using:

$ ./vendor/bin/sail up -d

2. Execute into the container

We’ll enter the container using Docker’s "exec" command. If your container is called "laravel.test" (the default), run:

$ docker exec -it laravel.test bash

3. Switch to the sail user

Inside the container, you’ll usually start as the "root" user. Laravel’s Sail environment expects you to be the "sail" user when running artisan commands. Switch using:

# su sail

4. Run "php artisan storage:link"

Now you're in the right context. Run the artisan command:

$ php artisan storage:link

If successful, you'll see:

The [public/storage] directory has been linked.

Understanding the Symlink Inside Docker

The symbolic link that Laravel creates is only valid inside the Docker container. If you're serving your app using Sail’s nginx config, this works fine because nginx reads paths within the container’s file system.

However, if you're accessing files or debugging from your host machine, make sure that your host has access to the volume. That’s where Docker volumes come in (but not our focus today).

File Structure After Linking

public/
├── index.php
├── ...
└── storage → ../storage/app/public  # symbolic link created

Common Errors

  • 404 Not Found: Likely the symbolic link wasn't created, or file permissions are wrong
  • Permission denied: Double-check Docker volumes and that files belong to the correct user/group

Security Note: Don’t Expose More Than You Need

By default, everything in "storage/app/public" becomes web-accessible via "/storage". Ensure you don’t accidentally place private files there.

Conclusion

Creating a symbolic link with "php artisan storage:link" is an essential step in any Laravel application that handles uploads. But inside Docker and Laravel Sail, you need to be aware of container boundaries and user permissions.

By using "docker exec", switching to the "sail" user, and running the command inside the container, you ensure your files are properly linked and publicly accessible.

Next Steps

  • Use Docker volumes to persist user-uploaded files between deployments
  • Always test file uploads and access paths when deploying

Happy coding, and may your uploads never go missing again!