CentOS 7 设置httpd (apache) 创建文件的umask
最近在部署网页后端脚本的时候碰到一个关于创建文件的权限问题。
系统版本是CentOS 7,在我的场景中,网页(html/php)由Apache驱动,用户/组为apache/apache。同时后端有一组应用Apps需要以另一个用户(websrv)的身份运行,没有同样使用apache用户是因为涉及到特定软件和环境变量的问题。这些Apps需要在Apache产生的目录中写/改/删文件,同时Apache也需要读取Apps生成的文件。
现在的策略是将websrv用户的group设置为apache,并使websrv和apache用户生成的文件具有group的写权限(g+w),后者是通过设置用户进程的umask实现。
这里[1]介绍了 linux下umask的原理和用法。在我的场景中,就是设置websrv和apache的umask为0002,使创建的目录权限为775,创建的文件权限为664,这样同属一个group的websrv和apache其进程就可以互相往对方创建的目录写文件了。
修改websrv用户的umask很简单,因为这是一个可登录用户,有自己的家目录和配置文件,于是直接修改其用户配置文件,向~/.bashrc文件中加入umask命令即可:
echo 'umask 002' >> ~/.bashrc
重新登录websrv用户(也即source ~/.bashrc
)或在这之后以websrv用户身份重新运行的进程,其创建目录及文件的umask已经是002了。
但是,Apache的umask的设置需要通过其他方式,一则apache用户并没有自己的配置文件,二则httpd进程是由systemd进程以apache身份运行。于是google了一下,发现不少帖子都提到,CentOS下修改httpd的umask需要在/etc/sysconfig/httpd中加入umask 002
命令(相应地,在Debian/Ubuntu系是在/etc/apache2/envvars中)。修改之后,systemctl restart httpd
重启httpd进程。重新测试发现,哦哟,新创建目录的umask仍然不变。这是怎么回事?
排查的过程中首先注意到,/etc/sysconfig/httpd文件中的注释写着,其中内容是以OPTION = $option
的形式记录。OK,我将umask 002
改为UMask = 0002
(大小写及首位多加的0是综合各种google结果而来,略去不表),然后systemctl restart httpd
重启httpd进程,再测试,WC,新创建目录的umask仍旧岿然不动。WTF?!
尽管原因尚未找到,但网站还需要运行,只好采用前面google到的另一种并不推荐的方案,就是修改httpd的Service配置文件(/usr/lib/systemd/system/httpd.service),向其中[Service]
块加入UMask=0002
,然后要先systemctl daemon-reload
重新加载修改后的配置文件,再systemctl restart httpd
重启服务(否则会运行不了并报错甩你一脸)。这样一番操作之后再测试,咦,果然可以了。
然而,上面的方式并不优雅也不安全,因为usr/lib/systemd/system/httpd.service是系统文件,有被系统改回去的危险。果不其然,第二天我在这个系统上运行了一次yum update
,更新了部分软件,结果第三天发现网站异常,一排查,是创建文件夹写权限的问题,再一看httpd的Service配置文件,好嘛,改回去了(而且文件的时间戳都回到了2019-11-27)。真是君子不立危墙之下啊。
那么现在的问题是,如何优雅安全地修改Service文件呢?在这里[2]看到在/etc/systemd/system/下创建httpd.service.d目录并放入自定义额外配置文件的方式,
This was the first result in Google search results for "CentOS 7 apache umask", so I will share what I needed to do to get this work with CentOS 7.
With CentOS 7 the echo "umask 002" >> /etc/sysconfig/httpd -method did not work for me.
I did overwrite the systemd startup file by creating a folder /etc/systemd/system/httpd.service.d and there I created a file umask.conf with lines:[Service] UMask=0007
Booted and it worked for me
经测试有效,而且这个自定义配置文件不需要修改系统文件并且不会被系统命令覆盖掉,算是一种比较好的方式。
虽然问题算是解决了,但为什么网络上SO/SE/SF等各大IT问答网站大家频繁提到的修改/etc/sysconfig/httpd的方式会无效呢?碰巧的是google过程中在这里[3]看到一个帖子:
With sysV init script, /etc/syconfig/httpd was a bash script which can alter the environment of httpd process.
With systemd, this in no more a bash script, only a list of variables which will be add to the environment, so umask isn't expected to work there.
You must use the systemd UMask option in the service file.
Remember : don't alter provided service file.
Create your own service file : /etc/systemd/system/httpd.service, with.include /lib/systemd/system/httpd.service [Service] UMask = 0002
Don't forget to reload systemd daemon using systemctl daemon-reload after editing a unit file.
See http://fedoraproject.org/wiki/Systemd#HowdoIcustomizeaunitfile.2Faddacustomunit_file.3F
这里解释了为什么umask 002
命令放在/etc/sysconfig/httpd文件中不起作用,因为CentOS 7使用systemd来管理系统服务(systemd作为1号进程,是后面所有启动进程的父进程),而不是CentOS 6中的sysVinit系统,网上流传的CentOS 7的/etc/sysconfig/httpd的改法可能是想当然或者以讹传讹吧。作为引申,可以去这里[4]简要了解sysVinit与systemd管理方式的区别。
最后,还是有一个小问题没有搞清楚。既然CentOS 7下安装httpd确实生成了/etc/sysconfig/httpd这个文件,还煞有介事地在注释中写了如何使用,说明systemd应该是用到了这个文件。即便是systemd不将其作为bash脚本执行,也就是不能直接使用umask 002
这种命令的方式,那么我之前按照UMask=0002
的形式写为什么也不起作用呢?
参考内容: