aschmelyun / docker-compose-laravel

A docker-compose workflow for local Laravel development
https://youtube.com/user/aschmelyun
MIT License
2.56k stars 1.16k forks source link

The stream or file "/var/www/html/storage/logs/laravel.log" could not be opened: failed to open stream: Permission denied #49

Closed joeariasc closed 1 year ago

joeariasc commented 4 years ago

I got the following error. Screenshot from 2020-06-27 16 09 45

Currently I'm working on the Ubuntu 18.04 and created a laravel project with the version ^7.0.

On the console, the containers and the initial configuration ran well. Screenshot from 2020-06-27 16 14 30

suhacb commented 4 years ago

I have the same issue. I am running Debian 10, my Laravel project source code in stored in a home subdirectory, owned by my user. I've already tried over 10 solutions proposed by various Stackoverflow posts and other sites, but the problem persists. I understand that the problem due to my local username, who owns the source directory, is different from php container's user, but I don't know how to fix it.

When I ran migration in the artisan container, there were a few migration errors which were written successfully in Laravel's log file. This also works:

The above procedure creates a new log file on my local drive. The new file is owned by root:root.

It seems like the artisan container runs with user root, which is able to modify local files, but the php container running my app uses the www-data user, which can't modify local files.

Furthermore, I added my local user to the www-data group, but the issue persists.

vladutt commented 4 years ago

Try to give permissions to the storage folder. sudo chmod -R 777 storage - local

Edit 2y later bcs i saw few emails on this: Production: sudo chmod -R a+rw storage

after that run: php artisan cache:clear php artisan config:clear php artisan config:cache

suhacb commented 4 years ago

Dear @vladutt, thank you for responding quickly.

The above solution works. Exact steps are:

I am concerned about security of the proposed solution though. On local development environment, this is not a problem. But for public testing and production, when app is exposed publicly, should there be a different approach of setting up the storage directory permissions?

AdrienPoupa commented 4 years ago

You should set the user in docker-compose.yml: https://medium.com/redbubble/running-a-docker-container-as-a-non-root-user-7d2e00f8ee15

Then, a chmod 755 will work

Juan-de-Costa-Rica commented 4 years ago

After searching for hours and a lot of trial and error, I found a solution that doesn't require the dreaded chmod 777 !

Adding RUN apk add shadow && usermod -u 1000 www-data && groupmod -g 1000 www-data to the Dockerfile seems to make all the permissions play nice. I'm not sure if there are undesired consequences to this, but working for me.

Found from: https://stackoverflow.com/questions/36824222/how-to-change-the-nginx-process-user-of-the-official-docker-image-nginx

ecsuae commented 4 years ago

After searching for hours and a lot of trial and error, I found a solution that doesn't require the dreaded chmod 777 !

Adding RUN apk add shadow && usermod -u 1000 www-data && groupmod -g 1000 www-data to the Dockerfile seems to make all the permissions play nice. I'm not sure if there are undesired consequences to this, but working for me.

Found from: https://stackoverflow.com/questions/36824222/how-to-change-the-nginx-process-user-of-the-official-docker-image-nginx

do we need to set any permissions on /src folder also? adding user in docker file only doesn't resolve the problem.

suhacb commented 4 years ago

After searching for hours and a lot of trial and error, I found a solution that doesn't require the dreaded chmod 777 ! Adding RUN apk add shadow && usermod -u 1000 www-data && groupmod -g 1000 www-data to the Dockerfile seems to make all the permissions play nice. I'm not sure if there are undesired consequences to this, but working for me. Found from: https://stackoverflow.com/questions/36824222/how-to-change-the-nginx-process-user-of-the-official-docker-image-nginx

do we need to set any permissions on /src folder also? adding user in docker file only doesn't resolve the problem.

Just adding RUN apk add shadow && usermod -u 1000 www-data && groupmod -g 1000 www-data to the php container doesn't solve the issue. (note: the code is for alpine containers which I use) Same goes for RUN deluser www-data && adduser -DH -h /home/www-data -s /sbin/nologin -u 1000 www-data, as suggested in one of the comments here: https://stackoverflow.com/questions/36824222/how-to-change-the-nginx-process-user-of-the-official-docker-image-nginx I wishfully tried running both commands, but the same problem occurs.

suhacb commented 4 years ago

Update: it seems I've figured it out.

Running RUN deluser www-data && adduser -DH -h /home/www-data -s /sbin/nologin -u 1000 www-data in the PHP container is important, but it is not the full solution.

The problem is also cause by the composer container. The composer container initially creates the Laravel application, with all the directories and files. This image is, by default, run as root. As a consequence, all the directories and files created by composer are owned by root:root. The solution is to also run the composer image as user 1000. For now, I do it when I run docker-compose run on composer image.

docker-compose run --rm --user 1000:1000 composer create-project --prefer-dist laravel/laravel .

If you already have a directory with Laravel application, the above solution won't work, as the directories and files are already created and owned by root:root. You need to delete the directory containing Laravel application and then re-install the application using the above docker-compose command.

I would also suggest a PR to improve the entire docker-compose setup in this repo.

P.S.: On MacOS, I has no problem with file permissions. Only on Windows 10. The above solution was tested on Windows 10 2004, Docker using WSL 2. I have Debian installed in WSL. Will verify the proposed solution on Debian machine later.

AdrienPoupa commented 4 years ago

The solution is to also run the composer image as user 1000

Yeah this is precisely what I said here: https://github.com/aschmelyun/docker-compose-laravel/issues/49#issuecomment-651131620

For your existing files, you just need to run chown -R 1000:1000 /yourproject && chmod -R 755 /yourproject in your projects folder

You should do that for the artisan and app containers

paranoiasystem commented 4 years ago

The solution is to also run the composer image as user 1000

Yeah this is precisely what I said here: #49 (comment)

For your existing files, you just need to run chown -R 1000:1000 /yourproject && chmod -R 755 /yourproject in your projects folder

You should do that for the artisan and app containers

I have cloned the project, startup the envirorment and I have create via composer container a new laravel app, but after I have the same issue I have applied this but i receive a 404 error, I have tried to launch a docker-compose run --rm artisan route:cache but this is the result:

Starting mysql ... done
Route cache cleared!

   LogicException 

  Unable to prepare route [api/user] for serialization. Uses Closure.

  at vendor/laravel/framework/src/Illuminate/Routing/Route.php:1150
    1146|      */
    1147|     public function prepareForSerialization()
    1148|     {
    1149|         if ($this->action['uses'] instanceof Closure) {
  > 1150|             throw new LogicException("Unable to prepare route [{$this->uri}] for serialization. Uses Closure.");
    1151|         }
    1152| 
    1153|         $this->compileRoute();
    1154| 

      +15 vendor frames 
  16  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))

image

AdrienPoupa commented 4 years ago

@paranoiasystem this is a different issue, unrelated to permission. It simply means that you need to remove any closure route before caching routes. The error message is self explanatory.

https://stackoverflow.com/a/45266424/11989865

aschmelyun commented 3 years ago

Hey all! This issue is a bit old, but I wanted to give an update. Sorry it took me a while to get around to it.

I've pushed out a large update to this repo, specifically involving permissions. There's now a .env.example file, which contains two sets of user/group names. This file should be copied to .env, and modified to match the username and group of the src directory that stores your Laravel application's source files. Then, run docker-compose build --no-cache before spinning your container network up again.

What the main permissions issue was:

Since we're using mounted volumes, Docker was overwriting any permissions or chowns in the Dockerfiles, and instead was using the username and group from the host system. This was only occurring on Linux and Windows WSL-2 systems as far as I can tell, since MacOS uses a virtualization layer that masks that ownership. PHP was expecting a www-user user and group, likewise with Nginx.

How it's solved now:

The best way I figured around it is either dropping the volumes and using ADD in the dockerfiles to copy over the source code, modifying the permissions at build-time. The problem with this was that you lost the ability to work on your application and have your changes update in real-time.

Instead, during build-time I take the values from the .env file for username/group, and create them in the containers. By matching the user and group that exists on the host system with the same one in the container(s), the application doesn't encounter any read/write errors and can proceed smoothly. There was also a fix to allow php to run as root, even if it's not recommended, since some webservers have their single user set to root/root.

Let me know if you have any questions about this, or if it's still a problem after using the updated repo!

yoanyahemdi commented 3 years ago

Hi @aschmelyun thank you for your recent last update on this! When you say to copy the .env and modify to match username and group (www-data / www-data). How do we get to know what are the username and group? For instance using the laravel/laravel default app you suggest from your video example: https://www.youtube.com/watch?v=5N6gTVCG_rw&list=RDCMUCc07-IBVwRlOsMg2WMdd8Sg&index=26

Thank you!

RobertPlaiasu commented 3 years ago

I still have this problem after the update

yoanyahemdi commented 3 years ago

It worked for me following the steps:

The username to be used, is the username of your linux/computer: username@repertory Then you need to create a new .env directly where you found the .env-example file Then I needed to replace "127.0.0.1" to "mysql" in the .env file of my application.

Thank you!

RobertPlaiasu commented 3 years ago

It worked for me following the steps:

The username to be used, is the username of your linux/computer: username@repertory Then you need to create a new .env directly where you found the .env-example file Then I needed to replace "127.0.0.1" to "mysql" in the .env file of my application.

Thank you!

Thank you ! Now it works for me .

rizkytegar commented 1 year ago

thanks

murraygunn commented 1 year ago

I'm getting this same problem in Ubuntu 22.04. I've checked the .env and .env.example files, but neither have anything that looks like user/group names. What exactly do I need to add/change?

Here's my .env-example file.

APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=example_app
DB_USERNAME=root
DB_PASSWORD=

BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

MEMCACHED_HOST=127.0.0.1

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1

VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
aschmelyun commented 1 year ago

It worked for me following the steps:

The username to be used, is the username of your linux/computer: username@repertory Then you need to create a new .env directly where you found the .env-example file Then I needed to replace "127.0.0.1" to "mysql" in the .env file of my application.

Thank you!

Following this advice should work going forward. If you have any other issues that aren't fixed by this, the advice above, or what's in the README file under "Permissions Issues" please open up another ticket!

enkracken commented 1 year ago

I use Ubuntu 22.04. The solution is: SSH into Docker container: docker exec -it app_name-laravel.test-1 /bin/bash Change the owner of storage/framework and storage/logs to sail not www-data:

chown -R sail:sail storage/framework
chown -R sail:sail storage/logs

If it still don't work, try to install htop inside that docker container. Run htop. Find the user of /var/www/artisan serve. Then repeat the commands above but with that user, not sail. Good luck!

Update

Or much better, create a group for root and user from docker (mine is sail): groupadd sailroot then add both root and sail to the group: usermod -a -G sailroot sail usermod -a -G sailroot root Change group owner of storage logs and framework to the group: chown root:sailroot -R storage/framework Change file permission to 775 for both: chmod 775 -R storage/framework In this way, you can using php artisan serve using php installed locally, or with docker using sail. Remember to leave the user to root, and group sailroot (or whatever you named)

ronald-kimeli commented 1 year ago

Use this technique for Ubuntu 22.04

You need to start your Laravel Sail container like this

docker exec -it app_name-laravel.test-1 /bin/bash

h1 Next create storage file by

mkdir /.storage
cd /storage
mkdir -p framework/{sessions,views,cache}

Get back to root file or root container by

cd ..
chmod -R ugo+rw /.storage || chmod 775 -R storage/

Thank you Hope your problem solved!

fernandomullerjr commented 3 months ago

Fixing Laravel log permission errors permanently: https://devopsmind.com.br/en/troubleshooting-en/laravel-log-permission-errors/