使用 Laravel 和 Docker 时出现“权限被拒绝”错误

40

我有两个 Docker 容器:Nginx 和 App。
App 容器扩展了 PHP-fpm,还拥有我的 Laravel 代码。

在我的 docker-compose.yml 文件中,我正在做如下操作:

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

在我的Nginx Dockerfile中,我正在执行以下操作:

FROM nginx:latest
WORKDIR /var/www
ADD ./nginx.conf /etc/nginx/conf.d/default.conf
ADD . /var/www
EXPOSE 80
在我的 App Dockerfile 中,我正在执行:
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

成功运行docker-compose up后,当我尝试访问localhost时出现以下错误:

无法打开流或文件“/var/www/storage/logs/laravel.log”:无法打开流:权限被拒绝

根据我的理解,存储文件夹需要由Web服务器具有写入权限。
我应该做什么来解决这个问题?

10个回答

64

将您的Dockerfile编写成以下类似形式 -

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

这会使得目录 /var/www 的所有者变成 www-data,该用户是 php-fpm 的默认用户。

因为它是使用用户 www-data 编译的。

参考文献-

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


21
这对我没有用。出现了同样的错误。有人有任何想法吗? - Janaka Pushpakumara
2
我也遇到了同样的问题。这个解决方案对我也没有起作用。 - Marcelo Noguti
5
您可以在ADDCOPY指令中使用--chown标志来缩小镜像大小,例如: COPY --chown=www-data:www-data . /var/www。在我的情况下,镜像大小从130MB减少到了100MB。 - J. Eggerstedt
4
对我来说,我需要使用这个命令 docker exec -i -t (这里是你的容器ID) bash,进入到容器本身中进行操作。 - FerdousTheWebCoder
2
找到了一篇文章,解释了这背后的原因。我的问题在于我使用的是Linux - https://github.com/shipping-docker/vessel-docs/blob/master/source/docs/linux-permissions.md - naneri

21

我遇到了类似的问题,解决方法如下:

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

chmod -R 755 /var/www/storage

17
我得到了这个错误信息:“无法访问'/var/www/storage':没有这个文件或目录”。 - naneri
尝试运行 chmod -R 755 /var/www/html/storage 命令,或者找到包含您的 Laravel 应用程序的文件夹。 - denied

15
在Docker中使用绑定挂载(bind mounts)时,Docker主机上的原始权限会保留在容器中。这使我们能够在Docker主机上设置适当的权限,以在容器内使用。
首先,您应该找到nginx的uidgid,例如: docker-compose exec nginx id www-data 此命令的输出将类似于: uid=33(www-data) gid=33(www-data) groups=33(www-data) 然后,您应该使用这些uidgid在Docker主机上设置权限,容器也将使用它们。因此,请在Docker主机上运行以下命令: sudo chown -R 33:33 site 现在一切都应该正常工作了。

谢谢!顺便说一下,您可以在Dockerfile中轻松执行此操作,只需使用COPY --chown=33:33 . .将数据复制进去即可。这样可以保留原始文件的所有权。(我读过这在Windows上是行不通的。) - Cameron Hudson
1
也许使用docker exec而不是docker-compose exec? - naneri

7

以下是我使用/正在使用的3件事

  1. 授予storage文件夹755权限(sudo chmod 755 storage/ storage/*

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

  3. 将项目文件夹移动到/home,无需特殊权限即可写入该目录(个人推荐此方法)(我使用的是/home/projects/并将所有项目都放在那里)。


注意:如果项目位于/var/www/,则如果您还编写了文件上传,您还需要对这些文件夹进行授权。当您将其移动到/home时,这将避免出现此类错误。


7
一个想法,777是Web服务器文件夹的不安全权限设置。一个建议是使用类似于"ug+rw"(为用户(所有者)和组添加读取和写入权限)。 - RoboBear
1
@SamuelBié 啊,刚看到这些评论。笔误 755。 - Abdulla Nilam

7

我尝试了所有这些方法,但都没有起作用。我的 Laravel 存储文件夹有访问权限,但是 /var/www/storage 没有权限。

在阅读多个建议后,特别是 这篇文章,我进行了以下操作(请注意,php 是我的容器镜像名称,并且我直接将 laravel 项目链接到 /var/www):

  1. 从我的 docker 中运行 docker-compose exec php ls -al /var/www/storage
    • 我发现只有 root 有访问权限,但是我需要让 www-data 有访问权限。
  2. 然后我运行了 docker-compose exec php chown -R $USER:www-data /var/www/storage
    • 这样就授予了 www-data 对存储文件夹的访问权限
  3. 然后我运行了 docker-compose exec php chown -R $USER:www-data /var/www/bootstrap/cache
    • 这样就授予了 www-data 对 bootstrap/cache 文件夹的访问权限

如果您再次运行第一个步骤,www-data 应该已经有了访问权限,那么您的 Laravel 应用程序就应该正常运行了。


7

您需要创建一个与本地机器上的用户匹配的用户(您使用该用户创建项目文件)。因此,在应用程序Dockerfile中,将您的文件更改如下:

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

快速提示:如果您仅在本地开发中使用Docker,则无需复制任何内容,只需使用绑定挂载。

在您的docker-compose文件中,进行以下更改:

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

奖励: 您可以使用上述Dockerfile来创建实用程序容器,在docker-compose文件中运行artisan和composer命令:

  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']

0
对我来说有效。
docker exec -it <your container name> bash
chmod 777 storage/ -R

你可以试一下,它会使你的存储文件夹可写。

0

针对Docker Compose

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

完整代码

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

0

在使用 Laravel 在 Docker 中使用 Sail 时,Web 服务器用户是 sail。确保确切的用户名的一种方法是运行:

var_dump(shell_exec('whoami'));

从服务器上的网页。我遇到了同样的问题,并授予了www-data用户权限。然而,在我的容器中,使用Sail,Web服务器用户名是sail。一旦我授予权限并将文件的所有者更改为sail,一切开始正常工作。

-6

您可以右键单击您的 Laravel 文件夹,选择属性,然后选择权限,在“组”字段中选择“docker”,并为“docker”组提供必要的权限 :) 这对我起作用了


这里涉及到Docker。一切都是通过终端控制,而不是GUI界面。 - Dinesh Suthar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接