尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

tmux会话自动保存与恢复:服务器重启也不丢现场

tmux会话自动保存与恢复:服务器重启也不丢现场 先确认一个场景你正通过 Xshell 或者 Windows Terminal 连着远程 Linux 服务器开着好几个 tmux 窗口里面跑着编译任务、数据同步脚本还有一个 vim 正在改配置。SSH 一断你重新连回去tmux 会话还好端端挂在那里这是 tmux 被当成运维标配的核心原因。可一旦服务器因为断电、内核升级、云平台强制重启而重新启动再登上去你就会发现之前的 tmux 会话全部消失了所有窗口布局、当前目录、正在跑的命令全都得从头来。那种感觉就像你写了一半的文档没保存直接断电。更难受的是服务器重启往往是突发状况等你发现会话丢了可能已经过了好几个小时哪些任务跑到哪一步、哪个窗口对应哪个目录全得靠回忆。这篇内容就围绕“服务器自动保存 tmux 会话以及恢复 tmux 会话”这件事展开我会把 tmux 为什么会丢会话的原理讲清楚然后用 tmux-resurrect tmux-continuum 这套方案从安装、配置、手动保存、自动恢复到避坑心得一次性说透。不管你是刚接触 tmux 的运维新人还是已经用了很久但没做持久化的老手这套方案都能直接落地。1. 先搞清楚tmux 会话到底为什么会消失先说结论tmux 本身就是一个“内存态”工具它没有把会话状态持久化到磁盘的机制。很多人以为只要 tmux 会话在SSH 断开也能保持那 tmux 就是万无一失的其实这只是它的一半能力。SSH 断开后会话还在是因为背后有一个独立的 tmux server 进程在托管这些会话而你的 SSH 连接只是客户端之一。可一旦服务器整体重启tmux server 进程跟着消亡内存里所有会话状态就全部归零。1.1 tmux 的运行模型Session、Window、Pane 和 Server要理解自动保存和恢复得先理解 tmux 的四层结构。最底层是 server它是你登录用户下运行的一个守护进程负责真正承载所有会话server 之上是 session你可以理解为一个完整的“工作台”每次tmux new -s xxx都会在 server 里建一个 sessionsession 里面是 window对应你看到的标签页window 再往下切成 pane也就是窗口里的分屏。保存 tmux 会话本质就是把这棵“session - window - pane”的逻辑树完整地记录下来同时还要记录每个 pane 的当前目录、屏幕内容、以及正在运行的前台程序。我做一个不算严谨但特别好懂的类比server 像一个正在运行的虚拟机session 是虚拟机里的操作系统窗口window 是桌面上打开的文件夹pane 是文件夹里切出来的视图分栏。你关闭 SSH 客户端相当于只是切断了显示器的线虚拟机后台还在跑但服务器重启相当于整台物理机断电所有内存里的东西全没了。这也解释了为什么 tmux 的开发者没有天然提供“重启后恢复”功能——因为 tmux 的定位就是终端复用它不是会话管理服务更不是工作环境快照工具。1.2 丢失的真正原因内存态与 /tmp 清理tmux 运行时会把自己的一些 socket 文件、临时状态放在/tmp/tmux-uid目录下这个目录名称后面跟的是当前用户的 UID。Linux 的/tmp目录默认会在系统重启后被清空再加上 tmux server 本身没有把 session 信息写回磁盘的持久化逻辑所以服务器一重启这棵逻辑树就彻底断了。你可以做个验证在你常用的 tmux 会话里执行echo $TMUX会看到类似/tmp/tmux-1000/default,12345,123的输出这个路径就直观地告诉你 tmux 的状态其实一直躺在内存和临时文件里。这也是为什么网上总有人问“我用 tmux 挂了个跑了几天的任务服务器重启后怎么没了”。不是 tmux 不好而是它压根没做“断电保护”这件事。如果你想在服务器重启后还能回到之前的操作现场就必须额外给 tmux 补上“定期把状态写到磁盘 启动后自动恢复”的能力。这正好是 tmux-resurrect 和 tmux-continuum 这两个插件解决的核心问题。2. 自动保存与恢复的方案怎么选我的建议是直接用 tmux-plugins 官方生态里的 tmux-resurrect tmux-continuum 这套组合不要自己写一堆脚本硬扛。原因很简单tmux 的会话保存不是一个“把窗口名存下来再新建一遍”这么简单的事它涉及 pane 布局、当前工作目录、前台进程、shell 环境变量、甚至是 vim 里打开的文件位置。自己做很容易顾此失彼而 resurrect 这套方案经过多年迭代已经覆盖了绝大多数场景。2.1 为什么是 tmux-resurrect tmux-continuum这里的职责划分非常清晰tmux-resurrect 负责“手动快照”和“手动恢复”它能够捕获 session 树、pane 布局、工作目录、环境变量以及可恢复的程序进程tmux-continuum 则负责“自动化”它会在 tmux server 运行期间每隔固定时间自动调用 resurrect 执行一次保存并且在 tmux server 启动后等待几秒再自动执行恢复。一个管保存的格式和内容一个管保存的时机和触发恢复两个插件搭在一起才算把“自动保存 tmux 会话以及恢复 tmux 会话”这个需求闭环。有人可能会说我自己写一段 shell 脚本把tmux list-sessions、tmux list-windows、tmux list-panes的输出抓下来存文件再在开机时反推回去不也能实现吗能但很脆。先不说 pane 分屏布局的还原非常麻烦光是把每个 pane 的当前目录和正在运行的命令比如 ssh、vim、tail -f重新拉起代码量就不小。你还需要处理 session 重名、环境变量丢失、vim 崩溃恢复这类边界情况。与其造轮子不如站在 resurrect 的肩膀上把精力留给真正有价值的事。2.2 你需要接受的限制不是所有程序都能 100% 恢复说句实在话任何方案都不是魔法。tmux-resurrect 对 pane 的恢复逻辑是去检查每个 pane 的当前进程命令如果你跑的是 bash、ssh、vim、htop 这类常见程序它可以把这些程序重新启动但如果你正在跑一个交互式 TUI 程序或者某个程序有自身的状态文件要求恢复后也可能只还原到“程序启动界面”而不是还原到它内部的某个操作步骤。这是我在使用中最需要先跟队友对齐的一点自动保存恢复的是“工作现场”不是“程序内存级还原”。平时写代码、敲命令、查日志这些场景它已经能覆盖 90% 以上的需求了。搞清楚这一层后面安装配置就不会有预期落差。3. 安装与基础配置两条命令把环境备好下面进入实操阶段。我的服务器环境是 Ubuntu 22.04tmux 版本 3.2a理论上 2.5 以上的版本都能用这套方案。如果你还没有 tmux先用发行版自带的方式装好然后安装 TPMTmux Plugin Manager。TPM 是 tmux 的插件管理器负责后续下载、加载、更新 resurrect 和 continuum省去手动 clone 再 source 的麻烦。3.1 用 TPM 管理插件安装 TPM 只要克隆仓库到固定目录git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm然后在~/.tmux.conf文件底部加入以下几行# 启用 TPM 插件管理 set -g plugin tmux-plugins/tpm set -g plugin tmux-plugins/tmux-resurrect set -g plugin tmux-plugins/tmux-continuum # 初始化 TPM必须放在最后 run ~/.tmux/plugins/tpm/tpm保存配置文件后在 tmux 会话内按下prefix I注意是大写 ITPM 就会自动下载并加载所有列出的插件。我一般用prefix U来更新插件这个操作会逐个检查远程仓库更新非常省心。安装完成后~/.tmux/plugins/目录下会出现tmux-resurrect和tmux-continuum两个子目录说明已经加载成功。3.2 核心配置项保存内容与自动恢复开关tp_m 只管插件的下载和加载真正决定行为的是配置项。我推荐在安装完插件后立刻把下面这些配置补进~/.tmux.conf再tmux source-file ~/.tmux.conf或重启 tmux server 让配置生效# resurrect 配置保存 pane 的屏幕内容 set -g resurrect-capture-pane-contents on # resurrect 配置额外恢复这些进程常见命令 set -g resurrect-processes ssh vim htop # continuum 配置每 15 分钟自动保存一次 set -g continuum-save-interval 15 # continuum 配置tmux server 启动后自动恢复上次会话 set -g continuum-restore on # continuum 配置恢复前等待 5 秒避免插件环境未就绪 set -g continuum-restore-delay 5resurrect-capture-pane-contents这个配置很多人会忽略但它非常关键。它会在保存会话时把每个 pane 当前屏幕上的文字内容也抓下来这样即使某个进程无法重启你至少还能看到这块屏幕上最后显示的日志、报错、命令输出这一点在排查事故时极其有价值。保存间隔我建议设置成 15 分钟如果你平时跑的都是编译、同步这种重要任务可以调到 5 分钟但代价是每次保存都会写一次文件IO 开销虽小任务多了还是会有感知。3.3 验证插件是否生效配置完成后来一个快速验证。先建一个测试会话在里面开两个窗口分若干 pane然后手动执行保存见下一节查看保存目录下是否生成了快照文件ls -la ~/.tmux/resurrect/正常情况下你会看到类似tmux_resurrect_20250321T153000.txt这样的文件里面的内容就是可读的 session/window/pane 状态描述。有了这个文件说明 resurrect 已经在正常工作之后 continuum 的自动保存只是定时调用它而已。若目录为空多半是配置文件没有被正确加载检查~/.tmux.conf里有没有语法错误即可。4. 手动保存与恢复实操先学会走再学跑自动化是在手动能力之上叠加的。我建议即使你已经配置好 continuum也先手动把“保存-删除-恢复”这个流程完整走一遍感受一下恢复后的现场还原度。这样等自动恢复真派上用场时你心里有底不会慌乱。4.1 保存一次会话prefix Ctrl-s在你想保存的 tmux 会话内依次按下prefix默认是Ctrl b然后按Ctrl s屏幕上会短暂闪现一个保存提示表示 resurrect 已经开始工作。这一步会把当前整个 tmux server 下的所有 session 全部保存不是只保存当前这一个 session。好处是一次保存相当于全局快照坏处是如果你的服务器上同时开了很多不相关 session恢复时也会一次性全部恢复出来。多数情况下我们都只开一两个 session影响不大。保存完成后可以用cat命令直接看保存文件的内容你会看到非常友好的文本格式每一行代表一个 session 或 windowpane 的分屏比例、当前目录、前台命令都记录在内。我最初第一次看这个文件时还挺惊讶原来 tmux 的布局在这里是按坐标和百分比保存的这也是它能精准还原分屏布局的原因。4.2 恢复会话prefix Ctrl-r恢复前如果你还在同一个 session 里操作稍微有点心理冲突——此刻 tmux server 正在运行resurrect 恢复时会尝试创建新的 session。如果老的 session 还存在且同名恢复会跳过避免冲突。所以更好的测试方法是保存完毕后把所有 tmux session 全部 kill 掉例如tmux kill-server这会让你彻底回到“服务器重启后什么都没有”的状态。然后重新进入 tmuxtmux new -s test在这个新的空 session 里按下prefix Ctrl r你会看到窗口一个接一个地重建出来。恢复完成后用tmux list-sessions查看之前的 session 名字、窗口数量、甚至 pane 的分割比例都回来了。每个 pane 的工作目录也会回到保存前的状态前台命令如果是 bash 会重新开启一个 shell如果是 ssh、vim 这类被配置过的程序也会尝试拉起。我在本地实测时保存前我在第二个窗口的 pane 里tail -f /var/log/syslog恢复后这个 pane 自动重新执行了 tail虽然日志位置因为时间变化多了几条但整个现场确实是原样恢复了。4.3 被保存的内容到底有哪些很多刚用这套方案的人会好奇“到底保存了什么”我整理了一个表方便你对齐理解内容类型是否默认保存说明Session 列表及名称是每个 session 的完整列表和会话名Window 顺序及名称是每个 session 下窗口的排列和标签名Pane 分屏布局是每个窗口里 pane 的分割方式、比例Pane 当前工作目录是每个 pane 所处的绝对路径Shell 历史与状态部分通过重建 shell 实现不是保存 .bash_history前台进程bash/ssh/vim 等部分默认支持常见命令其他命令需配置Pane 屏幕内容否需要开启resurrect-capture-pane-contents环境变量否需要额外配置resurrect-shell-variables我建议把“Pane 屏幕内容”一定要打开。它是排障时的救命稻草假设你恢复后发现某个 pane 的程序没起来但屏幕上保留了保存前的最后几行日志你至少能判断当时程序卡在哪一步如果不打开这个 pane 恢复后就是全新 shell什么痕迹都没有。5. 自动化定时保存 开机/重连自动恢复手动保存恢复只是基础真正的价值是让 tmux 像有“存档点”一样自动工作。这一节重点讲两件事一是让 continuum 按照固定周期自动保存二是解决服务器重启后 tmux server 起来并自动恢复的触发链。5.1 自动保存机制与触发链其实配置了continuum-save-interval 15后自动保存就开始了不需要额外做什么。continuum 会在 tmux server 的进程空间里挂一个定时器每 15 分钟执行一次 resurrect 保存。你可以在~/.tmux/resurrect/目录下观察到新文件不断出现这就是自动保存在跑的证据。continuum-restore on的触发时机则是“tmux server 启动后”。这带来一个很多人会忽略的问题服务器重启后如果你不手动执行tmux相关命令tmux server 就不会启动continuum 自然也没有机会触发恢复。也就是说插件层面的配置只能保证“tmux 起来后自动恢复”但无法保证“重启后 tmux 自动起来”。两者之间还缺一环得靠系统层面补上。5.2 让 tmux server 在重启后自动拉起这里我用了最符合我日常习惯的方式用户登录 shell 时如果检测到当前终端不是 tmux 会话就尝试 attach 到默认 session如果 attach 失败说明还没有这个 session就新建一个。把这个逻辑写进~/.bashrc或~/.zshrcif [ -z $TMUX ] [ -n $PS1 ]; then tmux attach-session -t main 2/dev/null || tmux new-session -s main fi这样服务器重启后你只要 SSH 登录并进入交互式 shelltmux server 就会自动以main会话的身份启动。server 一启动continuum 会先等待你配置的延迟时间我设置的是 5 秒然后自动执行恢复把之前所有 session 都还原出来。因为main这个会话本身也可能是从旧会话恢复出来的所以 attach 时可能直接进入恢复后的完整现场。要注意一个边界登录 shell 自动 attach 这个逻辑会影响一些非交互式命令的执行环境判断。所以我在条件里特意加了[ -n $PS1 ]确保脚本工具、scp、rsync 这类非交互会话不会被干扰只有真正进入交互终端时才触发 tmux。这个细节帮我避免了无数次“自动进 tmux 导致脚本行为异常”的坑。5.3 更稳妥的方案systemd 用户服务可选如果你希望即使没有 SSH 登录重启后 tmux 也能在后台自动恢复并跑着那可以把 tmux 拉起交给 systemd 用户服务。先确保用户 systemd 服务可用一般桌面或服务器发行版默认开启然后创建~/.config/systemd/user/tmux.service[Unit] Descriptiontmux default session Afternetwork.target [Service] Typeforking ExecStart/usr/bin/tmux new-session -d -s main Restarton-failure [Install] WantedBydefault.target启用服务systemctl --user daemon-reload systemctl --user enable tmux.service systemctl --user start tmux.service这样操作系统启动后、用户 systemd 实例初始化时tmux server 会被拉起来。continuum 检测到 server 启动延迟几秒后执行恢复所有 session 在一台“无人登录”的服务器上也能自动还原。这个方案对纯后台服务器特别友好我后来在跑批任务的节点上就一直用它。需要注意systemd 用户服务在部分云镜像上可能需要开启loginctl enable-linger才能正常后台运行sudo loginctl enable-linger 用户名一下就够。6. 进阶让更多程序也被恢复默认配置下resurrect 能恢复 bash、ssh、vim 这些高频命令但如果你想让更多程序也在恢复时重新拉起需要了解它的进程匹配机制并针对性地做配置。6.1 resurrect 的进程恢复机制resurrect 判断“某个 pane 该恢复什么进程”靠的是读取该 pane 当前运行的前台命令行。它会在保存时把命令行写入快照文件恢复时再去系统 PATH 里寻找对应命令并重新执行。配置resurrect-processes时可以用空格分隔多个命令名比如我上面写的ssh vim htop只要你保存当时 pane 里跑的是这些命令恢复时就会自动把它们重新执行。有个小技巧如果某个命令需要带参数或者不在标准 PATH 里你可以写成如下格式set -g resurrect-processes ssh htop -d 5这其实就是给 resurrect 一个“命令行模板”恢复时会按模板执行。不过还有一点要明白resurrect 不会恢复命令执行到一半的内部状态比如 vim 里你改了哪些地方、htop 当前选中哪个进程这些程序自身不提供会话恢复接口的话插件只能保证“程序重新打开了”。想让 vim 恢复到文件指定位置需要额外做 vim 会话集成。6.2 给 Vim 加会话恢复vim 本身是支持 session 文件的resurrect 也提供了对应的集成策略。配置方法是在~/.tmux.conf里加一行set -g resurrect-strategy-vim session同时你的 vim 需要支持保存 session 的能力。我习惯在 vim 配置里加上set sessionoptions-blank避免 session 恢复时把空白 buffer 也带出来。这样当你 tmux 保存时如果某个 pane 正在 vim 里resurrect 会自动执行mksession相关逻辑恢复时 vim 会加载 session打开的文件列表、窗口分割、光标所在行都能回到保存前。这套组合对开发者的日常效率提升非常明显我很多次从断电事故里恢复后直接回到当时的编辑现场。6.3 环境变量与 shell 历史的坑resurrect 默认不恢复环境变量因为它不确定哪些变量需要保存、哪些只是临时值。如果你在容器里跑程序、或者用到很多自定义路径变量恢复后的新 shell 里这些变量可能为空。可以在配置里指定要保存的变量set -g resurrect-shell-variables PATH LD_LIBRARY_PATH MY_CUSTOM_VAR但要注意PATH 这类变量通常由 shell 的 profile 文件自动设置有时不需要手动存手动存了反而可能覆盖新系统里的路径变化。我的经验是只保存真正属于“运行环境上下文”的变量比如某个任务节点必需的调度器配置变量常规 PATH 就别折腾了。另外恢复出来的 shell 是一个全新的交互 shell.bash_history里的命令历史不会因为你恢复了会话而被清空但也不会自动把保存前的历史合并进来。如果你比较依赖命令历史建议在.bashrc里打开HISTTIMEFORMAT并设置一个足够大的HISTSIZE至少能让重启前敲过的部分命令还在历史文件里。7. 常见问题与排查技巧实录最后这部分我把实际使用中踩过、以及社区里高频出现的问题整理成一张速查表方便你直接对号入座。其中不少问题我自己都折腾过能避一个是一个。7.1 问题速查表问题可能原因解决办法prefix Ctrl-s保存无反应插件未安装或未加载检查~/.tmux/plugins/下目录是否存在重新prefix I安装恢复后找不到旧 session没有先 kill-server老 session 和新恢复的同名 session 冲突恢复前砍掉旧 servertmux kill-server后再进入新 tmux 恢复保存目录~/.tmux/resurrect/不存在resurrect 从未成功执行过保存手动执行一次prefix Ctrl-s确认有快照文件生成continuum-restore on配置后不自动恢复tmux server 没有在重启后被拉起补上.bashrc自动 attach 或 systemd 用户服务恢复后 pane 屏幕是空的没开启resurrect-capture-pane-contents开启该配置保存一次再恢复ssh命令恢复后没有自动连接ssh 客户端需要交互确认 host key提前把目标主机的 host key 写入~/.ssh/known_hosts加载配置时报错command not found: set配置文件里混入了普通 shell 语法tmux.conf 只保留 tmux 的set-option、set -g等命令服务器重启后 systemd 服务没起来用户 linger 未开启sudo loginctl enable-linger 用户名continuum 保存太频繁IO 有压力保存间隔设置得太短调到 30 分钟或只在关键任务前手动保存一次7.2 我的排查思路与心得这套方案最大的坑从来不是插件本身而是“自动触发链”断了。很多人配置完后发现重启还是不恢复第一反应是插件坏了其实十有八九是 tmux server 根本没自动启动。我在本地反复模拟过把continuum-restore on配好然后reboot开机后直接看ps aux | grep tmux会发现 tmux 进程完全不存在这时候别说恢复连保存都没地方存。所以排查顺序一定是先确认 tmux server 是否启动再看~/.tmux/resurrect/里有没有最新的快照文件最后才怀疑插件配置。另一个非常实用的排查技巧是在恢复前用tmux kill-server清场。我自己最常遇到的恢复失败场景几乎都是因为旧 session 还挂着resurrect 发现同名 session 后直接跳过看起来就像“没恢复成功”。所以我会写一个简单的恢复脚本在 tmux server 启动后先杀掉旧 server 再 attach逻辑干净利落#!/bin/bash tmux kill-server 2/dev/null tmux start-server sleep 6 tmux attach-session -t main 2/dev/null || tmux new-session -s main这个脚本很适合在系统重启后手动执行一次也可以挂到 systemd 的用户服务里。核心是tmux kill-server之后新启动的 server 没有任何旧会话continuum 恢复时不会撞名恢复成功率接近 100%。还有一个小细节如果你经常用 VSCode 的 Remote SSH 插件连接服务器再在集成终端里开 tmux那么 VSCode 会自动设置很多环境变量比如TERM_PROGRAM、COLORTERM。恢复出来的 shell 可能没有这些变量导致部分输出颜色异常或某些插件行为变化。不用慌这是正常的毕竟普通 SSH 终端本来也不会有这些变量。想让 VSCode 下的体验更一致可以在resurrect-shell-variables里临时加上TERM_PROGRAM COLORTERM但我个人觉得没有必要因为新开 shell 的兼容性更好。另外在 Docker 容器或者最小化 Linux 环境里跑这套方案需要注意~/.tmux/plugins/和~/.tmux/resurrect/对应的是容器内文件系统容器被杀、镜像重建后这些目录会清零。如果你需要容器内 tmux 也做持久化务必将这两个目录挂载到宿主机 volume。我在容器化业务里体验过“镜像更新后所有会话没了”的痛挂载后这个问题才算根治。根据我个人实际操作中的体会tmux-resurrect 和 tmux-continuum 的组合已经是我在每台新服务器上必装的环境之一。它不改变 tmux 任何原有操作习惯只是把一个本来没做持久化的工具补上了“存档读档”能力。只要把保存间隔、恢复开关、自动拉起这三件事配齐以后不管服务器重启、SSH 断开、还是临时宕机重新登录后都能像什么都没发生过一样回到工作现场。这套方案的收益是隐性的可一旦你经历过一次“帮你省了几个小时恢复时间”的时刻就再也不想用回裸的 tmux 了。
返回列表