最近有同事反馈,发现使用 Laravel/Lumen 框架的项目中,日志文件( storage/logs/laravel.log | storage/logs/lumen.log )权限莫名其妙变为 root:root ,导致程序运行时写入失败而报 500 错误。

这种情况,在很早之前的项目中也出现过,当时没有认真解决,只是增加了个计划任务,定时把日志文件权限重新改为 www:www ,也算是能解决问题,但毕竟不是从根本原因入手,算不上完美的方案。

导致日志文件权限变为 root:root 的原因,是因为项目中有 crontab ,且是以 root 用户来执行的。针对这个问题,网上有人提到把日志文件目录权限改为 www:www 即可,这其实是没有用的。因为一般来说,计划任务是每天 0 点就会执行,而此时项目很有可能根本没访问量,因此当天的日志文件很大概率是由计划任务的进程以 root 账号来生成的,自然文件权限是 root:root 。也就是说,文件被创建时,当前进程归所归属的用户,就决定了这个文件权限的归属。

要解决此问题的方法,就是把此计划任务的归属用户从 root 变更为 www 即可。

# 指定用户
crontab -u www -e
# 重启服务
/bin/systemctl restart crond.service

问题到这里并没有完,因为重启服务后,发现计划任务并没有执行。查看计划任务相关日志( /var/log/crond ),发现有如下报错:

(CRON) ERROR chdir failed (/home/www): No such file or directory

也就是说,如果要用 www 用户来执行计划任务,就要为其创建主目录,并注意目录权限。

mkdir /home/www
chown -R www:www /home/www

另外我们可能会创建一些自定义的命令,比如在我们的项目中,使用 Swoole 来实现常驻进程( RabbitMQ 队列的消费端)服务,为了方便进程的管理,我们就封装了一些自定义命令。在项目根目录正常执行命令如下:

php artisan swoole start
php artisan swoole stop

但是由于我们经常是以非 www 用户登录的系统,因此执行完以上命令后,所创建的守护进程所属的用户也就非 www 了,这样如果每天的新日志文件是由此进程创建的话,后续的项目中的正常日志就可能无法写入,导致访问项目会报 HTTP-500 错误。解决方案就是在运行命令时先切换用户。

# 以 www 用户启动
su www -s /bin/bash -c "php artisan swoole start"
# 以 www 用户停止
su www -s /bin/bash -c "php artisan swoole stop"
# 查看进程
ps -ef | grep artisan
# 结果如下|第一列为所属用户
www      25353     1  0 11:00 ?        00:00:00 php artisan swoole start
www      25354 25353  0 11:00 ?        00:00:00 php artisan swoole start
www      25359 25354  0 11:00 ?        00:00:00 php artisan swoole start
www      25360 25354  0 11:00 ?        00:00:00 php artisan swoole start
www      25361 25354  0 11:00 ?        00:00:00 php artisan swoole start
www      25362 25354  0 11:00 ?        00:00:00 php artisan swoole start

标签:Laravel