问题描述
项目中有一个下载日志文件的功能,大致流程是 WEB 后端调用底层方法收集并压缩一些 .log 文件生成一个 zip 压缩包,放在 /tmp 目录下,前端访问指定路径下载。
之前系统环境用的 CentOS 6.5,现在升级到了 CentOS 7,结果测试时发现下载文件下载失败。
处理过程
检查,调试,发现文件不存在,打印出的 /tmp 目录下只有一个文件:dashboard.13913.0.1.sock
。然后再用 locate 搜索一下,发现这个文件位于 /tmp/systemd-private-a5fd4296183645d9956fc7ea58f2c463-httpd.service-eRS5Hl/tmp
目录下。
看这个文件名,大致和 SystemD 有关,这就对上了,CentOS 7 嘛。有了针对性,就好办了。很快就了解到这是 SystemD 的一个 PrivateTmp 属性。
PrivateTmp 开启之后,该服务访问到的 /tmp 不是真实路径,而是一个私有的目录。可能是对安全有一些帮助。
如果是由 Apache 来写文件,再读文件,不会发现这个问题,不过是我这个场景下,下载的 zip 文件不是 Apache 生成的。
解决方法
服务配置文件(/usr/lib/systemd/system/httpd.service
):
[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Documentation=man:httpd(8)
Documentation=man:apachectl(8)
[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/httpd
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
ExecStop=/bin/kill -WINCH ${MAINPID}
# We want systemd to give httpd some time to finish gracefully, but still want
# it to kill httpd after TimeoutStopSec if something went wrong during the
# graceful stop. Normally, Systemd sends SIGTERM signal right after the
# ExecStop, which would kill httpd. We are sending useless SIGCONT here to give
# httpd time to finish.
KillSignal=SIGCONT
PrivateTmp=true
[Install]
WantedBy=multi-user.target
把 PrivateTmp 设置成 false,然后重启 httpd,就能直接访问到 /tmp 目录。
参考
- freedesktop.org,man systemd
- Pid Eins,systemd for Administrators, Part XII
- 红帽,New Red Hat Enterprise Linux 7 Security Feature: PrivateTmp