[launchd] 消除了以 root 身份运行守护进程的主要原因。因为 launchd 以 root 身份运行, 它可以创建低编号的 TCP/IP 侦听套接字并将它们交给守护进程。
那很好...但是怎么做呢?
我想要执行以下操作:
- 在启动时启动 Nginx 网络服务器
- 让它监听 80 端口
_www
以用户身份运行
这正是上述文档所讨论的情况。但我还没有找到一种不给出错误消息的方法bind() to 0.0.0.0:80 failed (13: Permission denied)
。
这是我的 .plist 文件/Systems/Library/LaunchDemons/homebrew.mxcl.nginx.plist
:
<!--
Adapted from the .plist file provided as part of
the Mac Homebrew distribution of nginx.
-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!--
Here's the problem!!
<key>Username</key>
<string>_www</string>
-->
<!--
I thought that Sock(et) declarations would be
the way to tell launchd to hand off a port to the
daemon. So I added these lines, but they don't
appear to make any difference at all.
-->
<key>SockServiceName</key>
<string>http</string>
<key>SockType</key>
<string>stream</string>
<key>SockFamily</key>
<string>IP4</string>
<key>Label</key>
<string>homebrew.mxcl.nginx</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
<key>StandardOutputPath</key>
<string>/var/log/nginx.log</string>
<key>StandardErrorPath</key>
<string>/var/log/nginx.log</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/opt/nginx/bin/nginx</string>
</array>
<key>WorkingDirectory</key>
<string>/usr/local</string>
</dict>
</plist>
如您所见,Username: _www
被注释掉了。因此,当我以 root 身份运行 launchd 时,nginx 以 root 身份运行,一切正常。但是当我包含声明时Username: _www
,nginx 失败并在日志文件中留下此错误消息:
nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
我错过了什么?
答案1
守护进程需要“获取”由 launchd 绑定的套接字(例如launch_data_get_fd
:) - 它需要能够识别 launchd 并在内部实现一些逻辑。据我所知,nginx 并非如此,因此我建议使用以下选项之一:
- 将 nginx 端口调整为 > 1024,然后设置防火墙以将来自/到端口 80 的流量重定向到/从 nginx 端口;
- 让 launchd 以 root 身份运行 nginx,然后通过更改
user
其配置文件中的指令让 nginx 放弃其权限;