最近遇到一个玄学问题,我在 Arch 中使用 Systemd 管理 Nginx 的自启动服务。当时在某次我服务器所在的腾讯云母机半夜宕机自动拉起后,我发现 Nginx 没有正确启动,我没有在意,直接手动拉起了 Nginx 。但是在上次,将内核切换到长期支持版后我发现 Nginx 仍然没有在开机后自启动,systemctl status nginx显示 timeout,但是随后使用systemctl start nginx启动 Nginx 没有遇到任何错误。

$ sudo systemctl status nginx
* nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
Active: failed (Result: timeout) since Sat 2018-08-04 16:26:14 CST; 10s ago

Aug 04 16:24:44 isthnew systemd[1]: Starting A high performance web server and a reverse proxy server...
Aug 04 16:26:14 isthnew systemd[1]: nginx.service: Start operation timed out. Terminating.
Aug 04 16:26:14 isthnew systemd[1]: nginx.service: Failed with result 'timeout'.
Aug 04 16:26:14 isthnew systemd[1]: Failed to start A high performance web server and a reverse proxy server.

我检查了我的 nginx.service

[Unit]
Description=A high performance web server and a reverse proxy server
After=network.target network-online.target nss-lookup.target

[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
PrivateDevices=yes
SyslogLevel=err

ExecStart=/usr/local/nginx/sbin/nginx -g 'pid /usr/local/nginx/logs/nginx.pid; error_log stderr;'
ExecReload=/usr/local/nginx/sbin/nginx -s reload
KillMode=mixed

[Install]
WantedBy=multi-user.target

感觉上是没有问题的,因为这个配置我在另外的服务器上也在使用。重启之后马上 ssh 登录服务器,检查 Systemd 启动 Nginx 的状态,Systemd 一直在等待 Nginx 启动,直到1min30s后提示 Nginx 启动失败。Systemd 只记录到了启动超时的日志,Nginx 的日志里面并没有任何东西。

我尝试过 Google 出的办法,例如将 Type = forking 改为 Type = simple,或者给 Nginx 加上参数 daemon on; 依然不工作。之后我甚至怀疑是部分服务或组建还没有启动的时候 Nginx 就开始启动了,所以启动不正常,但是 After=network.target network-online.target nss-lookup.target 是 Nginx 官方文档中建议的参数,我甚至在将 php-fpm.service 放在了里面也没有效果。

后面我发现手动启动 Nginx 之后 Systemd 中会提示无法读取它的 PID

nginx.service: Failed to read PID from file /usr/local/nginx/logs/nginx.pid: Invalid argument

https://bugs.launchpad.net/ubuntu/+source/nginx/+bug/1581864 中发现有人记录了这个错误,在单核服务器中 Systemd 与 Nginx 会产生竞争。解决方法就是让 Nginx 等一下 Systemd

mkdir /etc/systemd/system/nginx.service.d

printf "[Service]\nExecStartPost=/bin/sleep 0.1\n" > /etc/systemd/system/nginx.service.d/override.conf

systemctl daemon-reload

无法读取PID的错误是解决了,但是依然自启动超时,所以暂时是未解之迷了。