# SSH 断开后继续运行任务

临时维护任务可用终端复用器；需要长期运行并自动恢复的服务，应该交给服务管理器。单纯加一个后台符号无法提供完整监控。

更新日期：2026-09-16

规范地址：https://stock.iftalking.com/guides/persistent-jobs/

## 1. 交互任务与长期服务用不同工具

临时编译、升级或数据导入需要断线后继续，可以使用 tmux/screen；网站进程、定时采集和长期机器人适合 systemd。nohup 能让简单命令在退出终端后继续，但不会自动重启、管理依赖或提供完善的运行状态。

| 任务 | 合适方式 | 如何找回结果 |
| --- | --- | --- |
| 临时交互式操作 | tmux / screen | 重新连接会话 |
| 一次性批处理 | nohup 或 oneshot service | 日志和退出状态 |
| 长期 Web 服务 | systemd service | systemctl + journal |
| 按时间重复运行 | systemd timer / cron | 执行记录与产物 |

## 2. 使用 tmux 保留终端会话

```bash
tmux new -s maintenance
```

在会话里执行任务。按 Ctrl+B，松开后再按 D，可以分离而不结束任务。重新 SSH 登录后查看并接回：

```bash
tmux ls
tmux attach -t maintenance
```

screen 的对应流程是 `screen -S maintenance`，Ctrl+A 后按 D 分离，`screen -ls` 查看，`screen -r maintenance` 恢复。显示会话已被其他终端连接时，先确认是不是自己另一个窗口，不要直接强制夺取他人的运维会话。

## 3. 简单后台命令要显式写日志

```bash
nohup /usr/bin/python3 /home/deploy/job.py > /home/deploy/job.log 2>&1 &
```

这个例子会在后台运行，但机器重启后不会自动恢复。检查进程和日志，任务完成后确认真实产物。不要用“终端没报错”作为成功标准，也不要把需要输入密码的交互程序直接放进 nohup。

## 4. 用 systemd 管理正式服务

假设应用已安装在 `/opt/myapp`，已有权限合适的 `deploy` 用户，并能在前台运行。新建 `/etc/systemd/system/myapp.service`：

```ini
[Unit]
Description=My application
After=network.target

[Service]
Type=simple
User=deploy
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=on-failure
RestartSec=5
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target
```

这是服务管理示例，不会替你安装应用。替换真实解释器和启动参数；Python 虚拟环境应指向其 `bin/python`，Node 项目也要使用实际 Node 路径。应用应以前台模式运行，让 systemd 跟踪主进程。

```bash
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
systemctl status myapp
journalctl -u myapp -n 50 --no-pager
```

## 5. 验证重启与失败恢复

确认本地健康检查、网页或任务结果正常，再在维护窗口测试一次服务 restart。应用重启循环时先看日志，常见原因是工作目录错误、端口占用、缺少环境变量或文件权限不足。

密钥放在受限的 EnvironmentFile 或应用配置中，避免打印到日志。服务上线后还要配置备份和日志保留；定期任务继续看[时间与计划任务](https://stock.iftalking.com/guides/time-cron/)。


## 完成后检查

不要把依赖交互输入的安装器盲目放到后台。任务日志应能说明它最终成功还是失败。

## 参考资料

- [Ubuntu Server 文档](https://documentation.ubuntu.com/server/)
