Chuck Le Butt
Chuck Le Butt

Reputation: 48758

Deploying Laravel to Elastic Beanstalk: "failed to open stream: Permission denied"

Sometimes when I deploy a Laravel project to AWS Elastic Beanstalk I'm faced with an annoying error saying that the log file cannot be opened:

The stream or file "/var/app/current/storage/logs/laravel-2020-10-21.log" could not be opened: failed to open stream: Permission denied

In my eb deploy.config file I have a statement which, in theory, should fix things, but doesn't:

files:
  "/opt/elasticbeanstalk/hooks/appdeploy/post/99_make_storage_writable.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/usr/bin/env bash
      echo "Making /storage writeable..."
      chmod -R 755 /var/app/current/storage

      if [ ! -f /var/app/current/storage/logs/laravel.log ]; then
          echo "Creating /storage/logs/laravel.log..."
          touch /var/app/current/storage/logs/laravel.log
          chown webapp:webapp /var/app/current/storage/logs/laravel.log
      fi

This is because it's not referencing the daily log file.

I have an .ebignore file in place which explicitly prevents local logs from being deployed, so it isn't the presence of an existing log file that's causing problems:

/storage/logs/*

The issue is that Laravel is creating the daily log as root so it cannot be written to by the normal user (webapp).

I just don't know why it's doing it?

Upvotes: 3

Views: 1463

Answers (3)

Rbbn
Rbbn

Reputation: 725

If anyone else stumbles upon this one, and can't solve it despite all the great solutions, one other thing that causes the original problem "could not be opened: failed to open stream: Permission denied" is that it seems like the log file is being written by the root user, not the ec2-user or webapp, which means no matter how much the right chmod or chown is done, we can't touch the file. So the workaround to that is to make sure the log file is saved with the user id and then it will be different files.

Add ".get_current_user()." to the storage_path

config/logging.php

'single' => [
        'driver' => 'single',
        'path' => storage_path('logs/'.get_current_user().'laravel.log'),
        'level' => env('LOG_LEVEL', 'debug'),
    ],

    'daily' => [
        'driver' => 'daily',
        'path' => storage_path('logs/'.get_current_user().'laravel.log'),
        'level' => env('LOG_LEVEL', 'debug'),
        'days' => 14,
    ],

Further though, one can discuss why log files are stored on a Beanstalk instance as it will anyway be overwritten the next time, so I would advice Horizon, S3 storage or whatever else, but that's a different topic. I guess you just want to solve the issue. I spent like a week until I found out the root user wrote the file first...

You can check who owns the file if you can SSH in to the Beanstalk instance "eb ssh". Then go to the folder var/app/current/storage/logs then write "ls -la" (which will list permissions). Then you can see that the root user has written the file once first and then has rights to it. I tried to change predeploy and postdeploy settings but didn't work. Writing it as a separate file name worked fine.

Upvotes: 0

Chuck Le Butt
Chuck Le Butt

Reputation: 48758

The solution is to allow each process to create its own log file. That way each process will have the correct permissions to write to it.

You can do this in the config/logging.php file and adding the process name (php_sapi_name()) to the file name:

    'daily' => [
        'driver' => 'daily',
        'path' => storage_path('logs/' . php_sapi_name() . '-laravel.log'),
        'level' => 'debug',
        'days' => 14,
    ],

Now each process will be able to write to its own file and there will be no permission problems.

Important Note: The above example uses "Daily", but make sure you make the change to right logging channel for you.

Upvotes: 1

Mahmoud Mekkawy
Mahmoud Mekkawy

Reputation: 44

Try to set storage folder permissions to this

chmod -R gu+w storage/
chmod -R guo+w storage/

Upvotes: 0

Related Questions