nohup 和 setsid 启动 Node Nitro,为什么 SSH 一断服务就不行

29次阅读
没有评论

nohup 和 setsid 启动 Node Nitro,为什么 SSH 一断服务就不行

最近排查一个很典型的问题:在服务器上通过 SSH 执行 nohupsetsid 启动 Node Nitro 服务,SSH 还开着的时候访问正常,一旦关闭 SSH,服务就不可用了。

这类问题第一反应很容易以为是 Nitro 或 Node 本身有问题,但多数时候真正原因在进程托管方式、登录会话清理、标准输入输出、监听地址或 SSH 端口转发上。

先判断是进程没了,还是进程还在但访问不到

不要一上来就改启动命令,先分清楚是哪一种情况。

SSH 断开前后分别执行:

“`bash

pgrep -af ‘node|nitro|nuxt’

ss -lntp | grep 3000

tail -n 100 nohup.out

“`

如果 SSH 断开后 pgrep 查不到 Node 进程,说明进程被登出会话带走了。

如果进程还在,但 ss 里只监听 127.0.0.1:3000,外部访问不到,那更可能是监听地址或反向代理问题。

如果之前是通过 SSH 端口转发访问,比如本地访问 localhost:3000 实际转发到远端,那么 SSH 一断端口转发也会断,这时服务本身可能还活着,只是访问路径没了。

nohup 不是服务管理器

nohup 的作用主要是忽略 SIGHUP,让进程不要因为终端挂起信号直接退出。它并不等于把程序交给系统长期托管。

如果服务器启用了 systemd-logind 的登录会话清理,或者进程仍然留在用户登录 session 的 cgroup 下面,SSH 退出时系统可能会把这批进程一起清掉。这个时候,只靠 nohup 不一定稳。

setsid 能让命令启动到新的 session 中,但如果标准输入、标准输出、标准错误还和 SSH 终端有关,或者外层 shell/job/cgroup 没处理干净,断开 SSH 后仍然可能出问题。

所以 nohupsetsid 更像临时保活手段,不应该作为生产服务的长期方案。

临时启动时要把输入输出彻底摘掉

如果只是临时跑一下,可以这样启动 Nitro:

“`bash

cd /path/to/your/app

nohup env NODE_ENV=production HOST=0.0.0.0 PORT=3000 node .output/server/index.mjs > app.log 2>&1 < /dev/null &

echo $! > app.pid

disown

“`

这里几个点都很关键:

  • > app.log 2>&1:标准输出和错误输出写入日志文件,不再写 SSH 终端。
  • < /dev/null:标准输入不再占用 SSH。
  • HOST=0.0.0.0:让服务监听所有网卡,不只监听本机回环地址。
  • disown:从当前 shell 的 job 表里摘掉。

也可以用 setsid

“`bash

setsid sh -c ‘cd /path/to/your/app && exec env NODE_ENV=production HOST=0.0.0.0 PORT=3000 node .output/server/index.mjs >> app.log 2>&1 < /dev/null’ &

“`

这比单纯 nohup node .output/server/index.mjs & 稳一些,但依然只是临时方案。

Nitro 要注意 HOST 配置

Nitro、Nuxt、Node 服务在不同环境下可能默认监听本机地址。如果只监听 127.0.0.1,外部机器当然访问不到。

生产环境通常需要明确指定:

“`bash

HOST=0.0.0.0

PORT=3000

NODE_ENV=production

“`

然后确认:

“`bash

ss -lntp | grep 3000

“`

如果看到 0.0.0.0:3000,说明对外网卡在监听。后面还要继续检查服务器防火墙、安全组、Nginx 反向代理是否放行。

如果看到 127.0.0.1:3000,说明它只允许本机访问。这种情况下,可以让 Nginx 在同机反代到 127.0.0.1:3000,也可以让应用直接监听 0.0.0.0,看你的部署策略。

长期运行应该交给 systemd

真正稳的方式是用 systemd 管理服务。比如创建:

“`ini

[Unit]

Description=Nitro App

After=network.target

[Service]

User=your-user

WorkingDirectory=/path/to/your/app

Environment=NODE_ENV=production

Environment=HOST=0.0.0.0

Environment=PORT=3000

ExecStart=/usr/bin/node /path/to/your/app/.output/server/index.mjs

Restart=always

RestartSec=3

[Install]

WantedBy=multi-user.target

“`

保存为:

“`bash

/etc/systemd/system/nitro-app.service

“`

然后执行:

“`bash

sudo systemctl daemon-reload

sudo systemctl enable –now nitro-app

sudo systemctl status nitro-app

“`

查看日志:

“`bash

journalctl -u nitro-app -f

“`

这样服务就不依赖 SSH 会话了。SSH 断开、终端关闭、shell 退出,都不会影响服务运行。服务异常退出后,systemd 也可以按 Restart=always 自动拉起。

还要检查登录会话清理配置

如果你确认进程就是在 SSH 断开时被杀掉,可以看看:

“`bash

grep -E ‘KillUserProcesses|RemoveIPC’ /etc/systemd/logind.conf

loginctl show-user "$USER" | grep -E ‘Kill|Linger’

“`

某些系统或安全基线会启用用户进程清理。对长期服务来说,绕着这些配置打补丁不如直接使用 systemd 服务单元。

如果确实需要允许用户服务在退出登录后继续运行,也可以了解:

“`bash

loginctl enable-linger your-user

“`

不过对 Web 服务来说,我更推荐写成系统服务,边界清楚,也方便查看状态、日志和重启。

我的结论

遇到“SSH 开着服务正常,SSH 一断服务就不行”,排查顺序可以按这几步走:

  • 先确认 SSH 断开后 Node 进程是否还存在。
  • 再确认端口监听的是 127.0.0.1 还是 0.0.0.0
  • 再看是否依赖 SSH 端口转发。
  • 临时运行时把 stdin/stdout/stderr 全部摘掉,并 disown
  • 长期运行直接上 systemd,不要把 nohup 当生产服务管理器。

一句话:nohupsetsid 可以救急,但不能替代服务管理。Node Nitro 这类 Web 服务,最终还是交给 systemd 或 PM2 这类进程管理器更稳。

正文完
 0
bdspAdmin
版权声明:本站原创文章,由 bdspAdmin 于2026-06-01发表,共计2808字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)