'Docker Laravel - could not be opened in append mode: failed to open stream: Permission denied

Have been trying to fix this error for almost an entire day now and have no idea what is possibly causing this issue.

The error I get is: UnexpectedValueException The stream or file "/var/www/storage/logs/laravel.log" could not be opened in append mode: failed to open stream: Permission denied

Below are my docker-compose.yml, Dockerfile and conf.d files.

docker-compose.yml:

version: "3"
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: /laravelproject
    container_name: app
    restart: unless-stopped
    volumes:
      - ./:/var/www
      - ./config/php/local.ini:/usr/local/etc/php/conf.d/local.ini

  webserver:
    build:
      context: .
      dockerfile: Dockerfile_Nginx
    image: /nginx
    container_name: webserver
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./:/var/www
      - ./config/nginx/conf.d/:/etc/nginx/conf.d/
    depends_on:
      - app

Dockerfile:

FROM php:7.3-fpm-alpine

WORKDIR /var/www

RUN apk update && apk add \
    build-base \
    freetype-dev \
    libjpeg-turbo-dev \
    libpng-dev \
    libzip-dev \
    zip \
    jpegoptim optipng pngquant gifsicle \
    vim \
    unzip \
    git \
    curl

RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl
RUN docker-php-ext-configure gd --with-gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/
RUN docker-php-ext-install gd

# copy config
COPY ./config/php/local.ini /usr/local/etc/php/conf.d/local.ini

RUN addgroup -g 1000 -S www && \
    adduser -u 1000 -S www -G www

USER www

COPY --chown=www-data:www-data . /var/www

EXPOSE 9000

app.conf:

server{
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/public;
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }
}

I have tried many solutions but none of them have worked.

Thanks.



Solution 1:[1]

You need to make sure the user inside the docker container is running with the same uid and gid as the user that owns the files on your host.

You can inspect the container user privileges using

docker-compose exec <service-name> ls -la /path/to/app/directory

in your example the path is /var/www/

and then inspect the user privileges int the host

ls -la /path/to/host/mount/point

in your example the path is ./

To test it you can just change the uid and gid in your Dockerfile to be the same as your user on the host and it should work. To be able to pass in this data through your docker-compose.yml you can add build-args to your compose file like int the Documentation.

You can also review the way that Laravel Sail does it.

Solution 2:[2]

The answer to your question is pretty easy indeed.

First of all, remember that docker runs as root by default so all the actions taken during the creation of your container are done by the root user.

What is happening is that you are running the command COPY --chown=www-data:www-data . /var/www after having switched to the newly created www user: this user does not have the rights to change the owner of a folder own by root!

Another error is that the user you want to set the folder ownership to is not www-data but the www user you just created.

What you want, in the end, is to switch the order of the 2 commands and change the user from www-data to www, look below:

CHANGE THIS

USER www

COPY --chown=www-data:www-data . /var/www

INTO THIS

COPY --chown=www:www . /var/www

USER www

Solution 3:[3]

Try this:

FROM php:7.3-fpm-alpine

WORKDIR /var/www

RUN apk update && apk add \
    build-base \
    freetype-dev \
    libjpeg-turbo-dev \
    libpng-dev \
    libzip-dev \
    zip \
    jpegoptim optipng pngquant gifsicle \
    vim \
    unzip \
    git \
    curl

RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl
RUN docker-php-ext-configure gd --with-gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/
RUN docker-php-ext-install gd

# copy config
COPY ./config/php/local.ini /usr/local/etc/php/conf.d/local.ini

RUN addgroup -g 1000 -S www && \
    adduser -u 1000 -S www -G www

#USER root

COPY --chown=www:www-data . /var/www

RUN chown -R www:www-data /var/www/storage
RUN chmod -R ug+w /var/www/storage

EXPOSE 9000

Login to the container terminal and check the directory and file permissions

>ls -al

drw-r--r-- 1 www www-data      0 Apr 25 11:57 storage
-rwxrw-rw- 1 www www-data 34434 Apr 25 12:45 laravel.log

Also, php-fpm must be executed by www-data user.

>top

17 root      20   0  236968   8232   2140 S   0.0   0.0   0:00.00 php-fpm7.3 
18 www-data  20   0  236968   8264   2164 S   0.0   0.0   0:00.00 php-fpm7.3 
19 www-data  20   0  236968   8264   2164 S   0.0   0.0   0:00.00 php-fpm7.3 

If this isn't the case then override the /etc/php/7.3/fpm/pool.d directory with www-data.conf file (copy or mount as a volume)

[www-data.conf]

user = www-data
group = www-data

listen = /run/php/php7.3-fpm.sock

listen.owner = www-data
listen.group = www-data

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 lgflorentino
Solution 2 Dharman
Solution 3