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

Ligonsker's avatar

How to restrict access to folders after creating symlink to storage?

I am storing users uploaded files to app/storage/uploads/ I then created a symlink to public folder in order to be able to view them.

But how am I supposed to restrict access to only the users I want to when I use AJAX or Fetch API to get the files? Right now anyone can simply get the files via the URL because it's publicly available now that the symlink has been connected

I want only the user that uploaded the files (Or users who got permission) to be able to access these files.

What is the correct way to do that? What is the work flow

0 likes
4 replies
Ligonsker's avatar

@Sinnbeck Thanks :D But if a user uploaded images and then I want to display it to him on the browser? If it's in the storage/ folder, how can I access it?

Ligonsker's avatar

@Sinnbeck But in the docs you linked to, it's either force user to download files - which I do not want, because what I want is to display it on the browser from a fetch/ajax request (I am displaying the images as a list)

Or, get URL after it is symlinked to public (which you just said I should not do)

Ligonsker's avatar

@sinnbeck Update: I found a nice solution for that!

I am using nginx X-Accel-Redirect header. What I did was to add a location block in my nginx config with internal directive:

location /uploads{
  internal;
}

Now when I go directly to mysite.test/uploads/image.jpeg (In the browser) I get 404 response from nginx

So in order to view the image, what I do is, I set the path to a Laravel controller containing some identifier to get the image path from the DB, for example:

<img src="mysite.test/image_id?id=1">

Then web.php redirects to the controller:

Route::get('image_id', [Controller::class, 'get_image']);

Then the Controller returns an empty response with X-Accel-Redirect header:

    public function get_image(Request $request)
    {
		$image = Image::find($request->id);
        $image_path = $image->path;
        return response('')
        ->header('X-Accel-Redirect', $image_path);   
    }

And then this header tells nginx that I can access this image and it shows up!

I can even set alias for the uploads folder so it won't be the same as the actual path to further obscure it. It's quite cool.

So the entire flow now is:

  1. User go to /mysite.test/images/
  2. The Laravel Backend returns list of images to show and the frontend appends them as list of <img>s
  3. Each <img> element in turn sends a GET request to Laravel backend again and gets a response with X-Accel-Redirect and show the image!

Please or to participate in this conversation.