Laravel Sail无法创建新日志文件:权限拒绝问题求解
解决Laravel Sail中日志文件权限拒绝问题
问题背景
使用Laravel Sail时,Laravel创建新日志文件时触发权限错误:
The stream or file "/var/www/html/storage/logs/laravel-2022-11-05.log" could not be opened in append mode: Failed to open stream: Permission denied
当前通过手动执行chmod -R 777 storage/logs临时修复,但希望通过Docker配置实现永久解决。
提供的Dockerfile和start-container脚本内容如下:
Dockerfile
FROM ubuntu:22.04 LABEL maintainer="Taylor Otwell" ARG WWWGROUP ARG NODE_VERSION=16 ARG POSTGRES_VERSION=14 WORKDIR /var/www/html ENV DEBIAN_FRONTEND noninteractive ENV TZ=UTC RUN apt-get update \ && apt-get install -y cron RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN apt-get update \ && apt-get install -y gnupg gosu curl ca-certificates zip unzip git supervisor sqlite3 libcap2-bin libpng-dev python2 \ && mkdir -p ~/.gnupg \ && chmod 600 ~/.gnupg \ && echo "disable-ipv6" >> ~/.gnupg/dirmngr.conf \ && echo "keyserver hkp://keyserver.ubuntu.com:80" >> ~/.gnupg/dirmngr.conf \ && gpg --recv-key 0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c \ && gpg --export 0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c > /usr/share/keyrings/ppa_ondrej_php.gpg \ && echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \ && apt-get update \ && apt-get install -y php8.1-cli php8.1-dev \ php8.1-pgsql php8.1-sqlite3 php8.1-gd \ php8.1-curl \ php8.1-imap php8.1-mysql php8.1-mbstring \ php8.1-xml php8.1-zip php8.1-bcmath php8.1-soap \ php8.1-intl php8.1-readline \ php8.1-ldap \ php8.1-msgpack php8.1-igbinary php8.1-redis php8.1-swoole \ php8.1-memcached php8.1-pcov php8.1-xdebug \ && php -r "readfile('https://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \ && curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \ && apt-get install -y nodejs \ && npm install -g npm \ && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /usr/share/keyrings/yarn.gpg >/dev/null \ && echo "deb [signed-by=/usr/share/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \ && curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/pgdg.gpg >/dev/null \ && echo "deb [signed-by=/usr/share/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt jammy-pgdg main" > /etc/apt/sources.list.d/pgdg.list \ && apt-get update \ && apt-get install -y yarn \ && apt-get install -y mysql-client \ && apt-get install -y postgresql-client-$POSTGRES_VERSION \ && apt-get -y autoremove \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.1 RUN groupadd --force -g 1000 sailRoot RUN useradd -ms /bin/bash --no-user-group -g 1000 -u 1337 sailRoot RUN usermod -aG sudo sail RUN usermod -aG sudo sailRoot COPY scheduler /etc/cron.d/scheduler RUN chmod 0644 /etc/cron.d/scheduler \ && crontab /etc/cron.d/scheduler COPY start-container /usr/local/bin/start-container COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf COPY php.ini /etc/php/8.1/cli/conf.d/99-sail.ini RUN chmod +x /usr/local/bin/start-container RUN chown -R www-data:www-data /var/www EXPOSE 8000 ENTRYPOINT ["start-container"]
start-container脚本
#!/usr/bin/env bash if [ ! -z "1000" ]; then usermod -u 1000 sail fi if [ ! -d /.composer ]; then mkdir /.composer fi chmod -R ugo+rw /.composer if [ $# -gt 0 ]; then exec gosu 1000 "$@" else exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf fi set -xe cd /var/www/html chmod -R 755 app chmod -R 755 public chmod -R 755 config chmod -R 755 storage chmod -R 777 storage/logs chmod -R 755 database chmod -R 755 bootstrap chmod -R 777 resources chmod -R 755 routes chmod -R 755 composer.json chmod -R 755 composer.lock
解决方案
1. 修复脚本执行顺序问题
当前脚本中权限修改代码位于exec命令之后,而exec会替换当前进程,导致权限调整代码永远不会执行。将权限调整逻辑移到exec之前:
修改后的start-container脚本:
#!/usr/bin/env bash if [ ! -z "1000" ]; then usermod -u 1000 sail fi if [ ! -d /.composer ]; then mkdir /.composer fi chmod -R ugo+rw /.composer # 先执行权限调整 set -xe cd /var/www/html chown -R www-data:www-data storage bootstrap/cache chmod -R 775 storage bootstrap/cache chmod -R 777 storage/logs # 再执行主命令 if [ $# -gt 0 ]; then exec gosu www-data "$@" else exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf fi
2. 同步宿主与容器用户UID
如果宿主机器的用户UID(通常为1000)与容器内用户UID不匹配,会导致挂载目录权限冲突。通过ARG和环境变量同步UID:
Dockerfile修改
ARG HOST_UID=1000 RUN groupadd --force -g ${WWWGROUP:-1000} sailRoot RUN useradd -ms /bin/bash --no-user-group -g ${WWWGROUP:-1000} -u ${HOST_UID} sailRoot
start-container脚本修改
if [ ! -z "$HOST_UID" ]; then usermod -u "$HOST_UID" sailRoot fi
docker-compose.yml补充
services: laravel.test: build: args: WWWGROUP: ${WWWGROUP:-1000} HOST_UID: ${UID:-1000} environment: - HOST_UID=${UID:-1000}
3. 配置容器以www-data用户运行
将容器内执行Laravel服务的用户改为www-data,确保与storage目录归属一致:
- 修改start-container脚本中的
exec gosu 1000 "$@"为exec gosu www-data "$@" - 在Dockerfile中明确设置关键目录归属:
RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache
- 同步修改supervisord.conf中Laravel服务的运行用户为
www-data
内容的提问来源于stack exchange,提问作者PHP User
相关产品推荐
相关产品推荐

