39

I have two docker containers: Nginx and App.
The app container extends PHP-fpm and also has my Laravel Code.

In my docker-compose.yml I'm doing:

version: '2'
services:
    nginx:
        build:
            context: ./nginx
            dockerfile: ./Dockerfile
        ports:
            - "80:80"
        links:
            - app
    app:
        build:
            context: ./app
            dockerfile: ./Dockerfile

In my Nginx Dockerfile i'm doing:

FROM nginx:latest
WORKDIR /var/www
ADD ./nginx.conf /etc/nginx/conf.d/default.conf
ADD . /var/www
EXPOSE 80

In my App Dockerfile I'm doing:

FROM php:7-fpm
WORKDIR /var/www
RUN apt-get update && apt-get install -y libmcrypt-dev mysql-client && docker-php-ext-install mcrypt pdo_mysql
ADD . /var/www

After successfully running docker-compose up, I have the following error when I try localhost

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

From my understanding, the storage folder needs to writable by the webserver.
What should I be doing to resolve this?

Abdulla Nilam
  • 36,589
  • 17
  • 64
  • 85
Anand Naik B
  • 689
  • 1
  • 7
  • 20

9 Answers9

64

Make your Dockerfile something as below -

FROM php:7-fpm
WORKDIR /var/www
RUN apt-get update && apt-get install -y libmcrypt-dev mysql-client && docker-php-ext-install mcrypt pdo_mysql
ADD . /var/www
RUN chown -R www-data:www-data /var/www

This makes directory /var/www owned by www-data which is the default user for php-fpm.

Since it is compiled with user www-data.

Ref-

https://github.com/docker-library/php/blob/57b41cfc2d1e07acab2e60d59a0cb19d83056fc1/7.0/jessie/fpm/Dockerfile

vivekyad4v
  • 13,321
  • 4
  • 55
  • 63
  • 21
    This didn't work for me. Same error. Anyone has any idea. – Janaka Pushpakumara Apr 23 '18 at 08:10
  • 2
    I'm also having the same problem. This solution did not work for me either. – Marcelo Noguti May 07 '18 at 19:27
  • 5
    You can use the `--chown` flag on the `ADD` or `COPY` instruction to reduce your image size. Like `COPY --chown=www-data:www-data . /var/www`. In my case, the size of the image got reduced from 130MB to 100MB. – J. Eggerstedt May 27 '18 at 10:38
  • 4
    for me, I had to dive into the container itself using this command `docker exec -i -t (here is you container id) bash` – FerdousTheWebCoder Jan 28 '19 at 20:45
  • 2
    Found an article that explains the reason behind this. The problem with me - was that I am using Linux - https://github.com/shipping-docker/vessel-docs/blob/master/source/docs/linux-permissions.md – naneri Mar 10 '19 at 13:29
20

I found similar problem and I fixed it by

chown -R www-data:www-data /var/www

chmod -R 755 /var/www/storage
KHACHORNCHIT
  • 2,222
  • 23
  • 19
15

When using bind mounts in Docker, the original permissions in the Docker host are preserved in the container. This enables us to set appropriate permissions on the Docker host, to be used inside the container.

First, you should find the uid and gid of the nginx, for example:

docker-compose exec nginx id www-data

The output of this command would be something like this:

uid=33(www-data) gid=33(www-data) groups=33(www-data)

Then, you should use these uid and gid to set permissions on Docker host, which will be used by the container too. So, run the following command on the Docker host:

sudo chown -R 33:33 site

Now everything must be working.

Hamid Mohayeji
  • 3,977
  • 3
  • 43
  • 55
  • Thank you! By the way, you can perform this easily in your Dockerfile as you copy in the data with `COPY --chown=33:33 . .`. This preserves the ownership of the original files. (I've read that this will not work on Windows, however.) – Cameron Hudson Jun 17 '19 at 00:03
  • 1
    maybe docker exec instead of docker-compose exec? – naneri Jun 24 '19 at 12:14
7

You can do 3 things as I used/using

  1. Grant 755 permission to storage folder (sudo chmod 755 storage/ storage/* )

  2. RUN chown -R www-data:www-data /var/www RUN chmod 755 /var/www

  3. Move project folder to /home which is no need of special permission to write on that directory(Personally Recommend this) (In mine I have used /home/projects/ and all of them placed there).


Note: If the project is in /var/www/ then if you wrote file upload also you need permission to that folders too. this will avoid such error when you moved that to /home

Abdulla Nilam
  • 36,589
  • 17
  • 64
  • 85
  • 7
    Just an idea, but 777 is an unsafe permissions setting for web server folders. One suggestion is to instead use something like "ug+rw" (add READ and WRITE for USER (owner) and GROUP). – RoboBear Jun 30 '19 at 01:26
  • 1
    @SamuelBié ah just saw these commnts. typo 755 – Abdulla Nilam May 11 '21 at 07:25
6

I tried all of these, and it didn't work. My Laravel storage folder had access. But /var/www/storage still didn't had permission.

After reading multiple suggestions, with this in particular. I did the following (kindly note that php is the name of my container image, and i linked my laravel project directly to /var/www):

  1. From my docker, I ran docker-compose exec php ls -al /var/www/storage
    • I saw that only root had access but i need www-data to have access.
  2. Then I ran docker-compose exec php chown -R $USER:www-data /var/www/storage
    • This gives www-data access to the storage folder
  3. Then I ran docker-compose exec php chown -R $USER:www-data /var/www/bootstrap/cache
    • This gives www-data access to the bootstrap/cache folder

If you run item 1 again, www-data should have access, and your Laravel app should be fine.

Zadat Olayinka
  • 441
  • 3
  • 8
6

You need to create a user that matches the one on your machine (the one you created the project files with). So in the app Dockerfile, change your file like this:

FROM php:fpm

# Arguments defined in docker-compose.yml
ARG user
ARG uid

# Install system dependencies
RUN apt-get update && apt-get install -y libmcrypt-dev mysql-client

# Install PHP extensions
RUN docker-php-ext-install mcrypt pdo_mysql

# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
    chown -R $user:$user /home/$user

# Set working directory
WORKDIR /var/www

# Set the user
USER $user

# Copy your files
COPY . . # You can use "." as a destination since you already changed the workdir

Quick note: if you're using docker purely for local development, you don't to copy anything, just use bind mounts.

And in your docker-compose file, make the following changes:

app:
    build:
        args:
            user: essana3 # your username on your machine, you can get it by running echo $USER
            uid: 1000 # your uid which you can get by running id -u
        context: ./app
        dockerfile: Dockerfile # if your dockerfile is called Dockerfile, you don't need to add the dockerfile option
    volumes:
        - ./app:/var/www

BONUS: You can use the dockerfile above to create utility containers in your docker-compose file to run artisan and composer commands:

  composer:
    build:
      args:
        user: essana3 # your username (echo $USER)
        uid: 1000 # your uid (id -u)
      context: ./app
    working_dir: /var/www
    volumes:
      - ./app:/var/www
    entrypoint: ['composer']

  artisan:
    build:
      args:
        user: essana3 # your username (echo $USER)
        uid: 1000 # your uid (id -u)
      context: ./app
    working_dir: /var/www
    volumes:
      - ./app:/var/www
    entrypoint: ['php', 'artisan']
essana3
  • 71
  • 1
  • 4
0

For Docker Compose

//Add this line:
user: 'www-data:www-data'

Full Code

services:
php:
    restart: always
    container_name: app-php
    user: 'www-data:www-data'
    build:
        context: ./docker/images/php
        dockerfile: Dockerfile
    working_dir: /var/www/html
    expose:
        - ${PHP_INTERNAL_PORT:-9000}
    volumes:
        - ./:/var/www/html
    networks:
        default:
            ipv4_address: 172.20.0.10
Murat Çakmak
  • 151
  • 2
  • 7
0

Adding to what others have contributed, when using Laravel in Docker using Sail, the web server user is sail. One way to make sure what the exact username is to run:

var_dump(shell_exec('whoami'));

from a web page on the server. I had the same issue and granted permission to the www-data user. However, in my container, using Sail, the web server username was sail. Once I granted permissions and made sail the owner of the files, everything started working.

Mehdi
  • 26
  • 3
0

It works for me.

docker exec -it <your container name> bash
chmod 777 storage/ -R

You can try it. It make your storage folder writeable

Zahid Hassan Shaikot
  • 1,066
  • 10
  • 18