VPS关闭SSH连接后,之前跑的程序为什么会停止

在VPS上跑一个耗时挺长的任务,比如下载大文件、跑个数据处理脚本,中途把SSH窗口关了或者网络断了一下,回来一看进度直接没了,程序不知道什么时候就被杀掉了。第一次遇到这种情况很容易怀疑是VPS不稳定、内存不够,其实跟这些都没关系,是SSH本身的机制在起作用。

为什么会被杀掉

SSH连接建立之后,这个会话下敲的所有命令,本质上都是这个SSH会话进程的子进程。一旦SSH连接断开(不管是主动关闭窗口还是网络意外掉线),系统会给这个会话下所有还在跑的进程发送一个叫SIGHUP(挂断信号)的信号,默认情况下大部分程序收到这个信号就会直接退出,这是设计上的默认行为,不是故障。

最简单的办法:nohup

nohup的全称是no hang up,作用就是让程序忽略SIGHUP信号,SSH断了也不受影响:

1
nohup 你的命令 &

末尾的&是把命令放到后台执行,不然当前终端会一直被占着动不了。程序的输出默认会写进当前目录下的nohup.out文件,想实时看进度:

1
tail -f nohup.out

nohup的局限是只能看输出日志,没法重新"接管"这个程序做交互操作,跑一些不需要中途干预的任务(比如下载、批处理脚本)用它比较合适。

需要中途还能接回去操作:用tmux

如果任务跑到一半可能需要看看情况、敲点命令进去,nohup就不够用了,这种场景更适合用tmux这类终端复用工具:

1
tmux new -s 随便起个名字

进到这个会话里正常执行命令,跑起来之后不用管它,直接关掉SSH窗口都没事,因为这个程序现在属于tmux自己开的进程组,不属于SSH会话,SIGHUP传不到它身上。

下次想回来看进度,重新SSH连上VPS,接回这个会话:

1
tmux attach -t 刚才起的名字

界面会恢复成你离开时的样子,该干嘛干嘛,跟没断开过一样。不用的会话记得清理:

1
tmux kill-session -t 名字

screen是另一个类似的工具,用法上跟tmux差不多,两者选一个顺手的用就行。

有些程序天生就不受影响

像Nginx、MySQL这类通过systemctl启动的服务,本身不属于SSH会话的进程组,是独立的守护进程,SSH断不断跟它们没关系,不需要额外套nohup或者tmux。这个坑主要出现在手动在SSH窗口里直接敲命令启动的临时任务上。

平时如果习惯用手机通过Termux手机管理VPS教程里的方式连VPS,出门在外网络更容易波动,中途意外断连的概率比在电脑上更高,跑长任务之前养成套一层tmux或者nohup的习惯,能少踩不少这种"进度突然没了"的坑。