How to fix Laravel permission denied errors

The Permission Denied error in Laravel is one of the most frustrating problems that developers and DevOps/SRE teams can encounter when working with the Laravel framework. This problem usually occurs due to incorrect permissions settings for files and directories related to Laravel logs, especially in production environments. In this article, we’ll explore the main causes and present definitive solutions to resolve this error and avoid downtime in your PHP application.

Laravel’s main permissions errors

Laravel permission denied
Laravel permission denied

Laravel is a popular framework used by many developers to create PHP web applications. A common problem that can occur when working with Laravel is the error:

The stream or file "/var/www/html/storage/logs/laravel.log" could not be opened in append mode: failed to open stream: permission denied

This error occurs when Laravel cannot write to its log file because it does not have permission to access the storage folder.

Another very common error, which can happen when we do not have the permissions defined correctly in Laravel, is the error below:

Error in exception handler: The stream or file "/var/www/laravel/app/storage/logs/laravel.log" could not be opened: failed to open stream: Permission denied in /var/www/laravel/bootstrap/compiled.php:8423

Palliative solution

One solution that is recommended in many forums and blogs is to apply the chmod 777 permission, which ends up leaving our server very exposed.

In some cases, other commands are suggested, such as chmod, chgrp, which may not make the server less secure but do not provide a definitive solution to permission errors in Laravel.

This error Laravel The stream or file occurs when Laravel cannot write to its log file because it is not permitted to access the storage folder.

Definitive solution

Fortunately, there is a relatively easy solution to this problem. You can apply permissions and inheritance to the permissions in the /var/www/html/storage/logs folder on the server.

To do this, you’ll need to access the server where Laravel is hosted and run a few commands in the project folder (in this example we’re using /var/www/html/).

Another important point is that I try to add the users who work with Laravel to the www-data group, so that after applying the solution they can manipulate the files without causing problems and new permission errors in Laravel.

Here is the script we should use, adapt it to your needs:

## laravel log permission
cd /var/www/html/
sudo chgrp -R www-data bootstrap/ storage/ storage/logs/
sudo chmod -R 755 bootstrap/ storage/ storage/logs/
sudo chmod -R g+w bootstrap/ storage/ storage/logs/
cd bootstrap/
sudo find -type d -exec chmod g+s {} +
cd ..
cd storage/
sudo find -type d -exec chmod g+s {} +
cd ..
cd storage/logs/
sudo find -type d -exec chmod g+s {} +

A little more about each command

This Bash script is used to grant correct permissions to the bootstrap/, storage/ and storage/logs/ directories of a Laravel project that is located in /var/www/html/. Specifically, the script sets the owner group of these directories to www-data, which is the default user and group of the web server on Ubuntu. In addition, the script ensures that these directories have write permissions for the www-data group.

The part of the script that refers to the inheritance of permissions is the following line:

sudo find -type d -exec chmod g+s {} +

This line sets the SGID bit in all directories within the bootstrap/, storage/ and storage/logs/ directories. When the SGID bit is set on a directory, it ensures that all new files created within that directory inherit the ownership group of the parent directory. This is useful to ensure that all files created within the bootstrap/, storage/ and storage/logs/ directories have the same ownership group(www-data) and can therefore be read and written to by the web server.

In summary, the script performs the following actions:

  1. Navigate to the Laravel project folder in /var/www/html/.
  2. Sets the owner group of the bootstrap/, storage/ and storage/logs/ directories to www-data.
  3. Grants permissions 755(The owner of the file has full permission. The file’s group has read and execute permission. Other users have read and execute permission.) and write to the www-data group in the bootstrap/, storage/ and storage/logs/ directories.
  4. Sets the SGID bit on all directories within the bootstrap/, storage/ and storage/logs/ directories, to ensure inheritance of group permissions on new files created in these directories.

Detailing each command option

sudo chgrp -R

sudo: the sudo command is used to execute commands with superuser (root) privileges in the Linux or Unix operating system.

chgrp: the chgrp command is used to change the ownership group of a file or directory.

-R: is an option for the chgrp command that means “recursively”. It causes the command to be run on all directories and subdirectories below the current directory.

In short, the sudo chgrp -R command recursively changes the ownership group of all files and directories below the current directory.

sudo chmod 755

The 755 permission is a permissions setting commonly used in Unix-based operating systems such as Linux and macOS. It defines the following access levels:

  • File owner:
    • Reading (r)
    • Writing (w)
    • Execution (x)
  • File group:
    • Reading (r)
    • Execution (x)
  • Other users:
    • Reading (r)
    • Execution (x)

This means

  • The owner of the file has full permission (read, write and execute).
  • The file’s group has read and execute permission.
  • Other users have read and execute permission.

sudo chmod -R g+w

sudo: The sudo command allows you to temporarily execute commands with administrator (root) privileges on Unix/Linux systems, requiring a password for authorization.

chmod: is a command that is used to change the access permissions of a file or directory.

-R: same as above

g+w: is an option for the chmod command which means “add write permission for the group”. “g” is the group that owns the file or directory.

In short, the sudo chmod -R g+w command adds write permission for the owner group to all files and directories below the current directory.

sudo find -type d -exec chmod g+s {} +

sudo: same as above

find: is a command used to find files and directories based on specific criteria.

-type d: is an option for the find command which means “find directories only”.

-exec: is an option for the find command that executes a command on each file or directory found.

chmod g+s: is the command that will be executed on each directory found by find. “g” is the group that owns the directory and “s” is an option that means “set the setgid bit”. This causes all files created within the directory to inherit the directory’s owner group.

{}: is a placeholder for the name of the file or directory found by find.

+: indicates that the chmod g+s command should be run once for each group of files or directories found.

In summary, the command sudo find -type d -exec chmod g+s {} + finds all the directories below the current directory and executes the command chmod g+s on each of them, ensuring that all files created within these directories have the same ownership group.

Example in practice

Here in my lab I like to use the Travellist – Laravel Demo App project, which uses the Laravel PHP framework, to practice the installation and basic use of Laravel. It builds an example travel list application, to show a list of places a user would like to travel to and a list of places they have already visited.

After uploading the project and accessing it via Browser, this is the page that is displayed:

laravel log errors
App – Travellist

As you can see in the image below, the files and folders have their permissions set correctly and the Containers are working as expected:

laravel folder permissions
laravel folder permissions

One directory that is very important, as it stores all of Laravel’s logs, is the storage/logs directory

Checking the permissions of this directory and the directories inside the:

laravel log permission

Permission errors in Laravel and its storage directory or in the logs directory can lead to crashes in your application and the occurrence of “Permission denied” errors related to the /var/www/storage/logs folder.

In the example below, I am incorrectly setting the permissions on the storage directory to force the permission error to occur:

laravel log permissions

With the permissions set incorrectly, if I try to access the Travellist page again in my local environment, the following error occurs:

storage laravel permission denied
storage laravel permission denied

Error message:

UnexpectedValueException
There is no existing directory at "/var/www/storage/logs" and its not buildable: Permission denied 

To regularize the permissions of the storage directory and the directories below it, I ran the following commands:

docker exec -u 0 -it travellist-app /bin/bash
chgrp -R www-data storage/ storage/logs/
chmod -R 755 storage/ storage/logs/
chmod -R g+w storage/ storage/logs/
cd storage/
find -type d -exec chmod g+s {} +

It is important to note that, in this case, I used a Docker command to access the container as the root user, in order to be able to apply these commands, according to the parameter:

-u 0: Specifies the user ID(0 is the root ID)

No errors should occur during the application of the commands, as shown below:

fix laravel permission denied
laravel permission denied – permanent solution

After applying the commands, access to the Laravel project page is restored:

travellist ok

Support material


The Laravel Permission Denied error may seem complicated, but the solutions are straightforward once you understand how the permissions system works. Correctly configuring the storage and bootstrap/cache directories, adjusting the user and group, and ensuring that permissions are not modified inappropriately are fundamental steps to prevent this error from disrupting the functioning of the project.

More troubleshooting tips? Visit: Troubleshooting


Cover image from freepik

Compartilhe / Share
Fernando Müller Junior
Fernando Müller Junior

I am Fernando Müller, a Tech Lead SRE with 16 years of experience in IT, I currently work at Appmax, a fintech located in Brazil. Passionate about working with Cloud Native architectures and applications, Open Source tools and everything that exists in the SRE world, always looking to develop and learn constantly (Lifelong learning), working on innovative projects!

Articles: 44

Receba as notícias por email / Receive news by email

Insira seu endereço de e-mail abaixo e assine nossa newsletter / Enter your email address below and subscribe to our newsletter

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

    • Hello,
      Have you tried adjusting the permissions?
      Is it possible to adjust the Dockerfile so that the permissions are always correct? Have you already applied changes to your Dockerfile?