很多人给 VPS 做安全加固时,会改 SSH 端口、开防火墙、禁用密码登录,但会漏掉一件更日常的事:系统补丁到底有没有及时装。
更容易被忽略的是,补丁装了也不一定马上生效。尤其是内核、glibc、OpenSSL 这类底层组件,包管理器显示更新完成,不代表正在运行的进程已经用上新版本。Ubuntu/Debian 上经常会出现一个文件:
/var/run/reboot-required
它的意思很直接:这台机器需要重启。
我见过不少小站,unattended-upgrades 开着,管理员以为“安全更新自动处理了”。结果系统攒了几个月没重启,内核漏洞补丁早就安装在磁盘上,但机器还跑着旧内核。自动更新不是终点,重启计划才是闭环。
这篇按实际运维顺序讲:怎么确认自动安全更新是否启用,怎么看日志,什么时候必须重启,为什么不建议所有 VPS 都无脑自动重启,以及怎么安排一个不折腾的维护窗口。
Ubuntu Server 官方文档把 automatic updates 放在软件管理里,核心组件是 unattended-upgrades。它可以自动安装安全更新,也可以按配置决定是否自动清理、是否自动重启。
但这几个动作要分开看:
- 自动检查更新
- 自动下载更新
- 自动安装安全更新
- 更新后是否需要重启
- 是否真的自动重启
- 重启后服务是否恢复正常
很多 VPS 只做到了第三步。安全包确实装了,但机器没有重启,Web 服务、数据库、Docker 容器也没人检查。对个人博客可能只是小风险;对有订单、登录、支付回调的网站,就可能变成线上事故。
先确认包是否安装:
dpkg -l unattended-upgrades
如果没装,可以安装:
sudo apt update
sudo apt install unattended-upgrades
再看自动更新配置:
cat /etc/apt/apt.conf.d/20auto-upgrades
常见配置类似:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
这两行大概意思是:每天更新软件包列表,并运行 unattended-upgrades。
也可以用 apt 自己的配置输出确认:
apt-config dump | grep -E 'APT::Periodic|Unattended-Upgrade'
如果你只看到 Update-Package-Lists,没看到 Unattended-Upgrade,说明可能只是自动刷新包列表,并没有自动安装安全更新。
现在的 Ubuntu/Debian 通常通过 systemd timer 触发 apt 相关任务。可以看:
systemctl list-timers | grep apt
你可能会看到:
apt-daily.timer
apt-daily-upgrade.timer
再看具体状态:
systemctl status apt-daily.timer
systemctl status apt-daily-upgrade.timer
不要看到 timer active 就放心。timer active 只代表它会定时运行,不代表每次更新都成功。
看日志更靠谱:
sudo ls -lh /var/log/unattended-upgrades/
sudo tail -n 80 /var/log/unattended-upgrades/unattended-upgrades.log
如果要查 apt 相关历史:
sudo less /var/log/apt/history.log
sudo less /var/log/apt/term.log
重点看有没有 failed、kept back、dependency problem、dpkg interrupted 之类信息。
对一台普通 VPS,我更建议自动安装安全更新,而不是把所有普通更新都无人值守装上。
原因很现实:
- 安全更新通常更适合自动化
- 普通版本更新可能带来配置变更
- 数据库、语言运行时、Web 服务大版本变化更容易影响应用
- 小团队或个人站点没有完整回归测试
/etc/apt/apt.conf.d/50unattended-upgrades 里会配置允许自动更新的来源。Ubuntu 上常见会启用 security pocket。你可以查看:
sudo grep -n "Allowed-Origins" -A 20 /etc/apt/apt.conf.d/50unattended-upgrades
不要不看配置就直接复制网上一大段。不同 Ubuntu 版本、是否启用 Ubuntu Pro、是否有第三方源,配置都可能不一样。
我的建议是:
- 系统安全补丁:可以自动安装
- 第三方仓库:谨慎自动更新
- 数据库大版本:不要无人值守升级
- 业务应用:走自己的发布流程
自动更新是为了减少低级安全风险,不是替你做完整变更管理。
Ubuntu/Debian 上最直接的判断:
test -f /var/run/reboot-required && cat /var/run/reboot-required
如果存在,通常会输出:
*** System restart required ***
还可以看哪些包触发了重启需求:
cat /var/run/reboot-required.pkgs
常见会看到:
linux-base
linux-image-...
libc6
如果更新了内核,想确认当前正在运行哪个内核:
uname -r
dpkg -l 'linux-image*' | grep '^ii'
如果新内核已经安装,但 uname -r 还是旧版本,那就说明需要重启才能切过去。
unattended-upgrades 可以配置自动重启,例如相关选项通常长这样:
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Automatic-Reboot-Time "03:30";
这里我不建议所有人直接改成 true。
自动重启的风险很具体:
- 机器重启后服务没有自启动
- Docker 容器没有设置 restart policy
- 防火墙规则重启后丢了
- 数据库恢复慢,网站短时间 502
- 磁盘检查或云厂商维护导致启动时间变长
- 你正在 SSH 操作,机器突然重启
- 小网站没人值守,挂了半天才发现
如果是一台纯测试 VPS,自动重启没什么问题。如果是生产站点,我更喜欢“自动安装安全更新 + 固定维护窗口手动/半自动重启”。
对大多数小网站,我会这样安排:
- 每天自动检查并安装安全更新
- 每周固定一个低峰维护窗口,例如周二 03:30
- 维护窗口前检查
/var/run/reboot-required - 如果需要重启,先确认备份、服务状态、监控
- 重启后跑一组健康检查
一个简单的维护前检查:
hostnamectl
uptime
systemctl --failed
df -h
df -i
free -m
test -f /var/run/reboot-required && cat /var/run/reboot-required
如果 systemctl --failed 已经有失败服务,不要急着重启。先搞清楚失败服务是不是关键服务。否则重启后可能变成“原来只是一个服务失败,现在整个站打不开”。
重启 VPS 前,先看关键服务是否 enabled:
systemctl is-enabled nginx
systemctl is-enabled mysql
systemctl is-enabled postgresql
systemctl is-enabled docker
如果用 Docker Compose,确认容器重启策略:
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
docker inspect --format '{{.Name}} {{.HostConfig.RestartPolicy.Name}}' $(docker ps -q)
常见策略有:
always
unless-stopped
on-failure
如果你的网站完全依赖 Docker,但 Docker 没有开机自启,或者容器没有 restart policy,VPS 重启后网站很可能不会自动恢复。
维护窗口到了以后,建议先给自己留一个当前状态记录:
date
uptime
systemctl --failed
ss -lntp
然后重启:
sudo reboot
如果是远程 VPS,重启后等 1-3 分钟再重新 SSH。不同云厂商、不同内核更新、不同磁盘状态,启动时间会有差异。
回来后先看:
uptime
uname -r
systemctl --failed
journalctl -b -p warning --no-pager | tail -n 80
再查业务服务:
systemctl status nginx --no-pager
systemctl status docker --no-pager
curl -I https://example.com
如果网站后面有数据库、队列、缓存,也要查对应服务。不要只看 SSH 能连上就结束。
我一般会准备一个很土但有效的检查清单:
systemctl --failed
journalctl -b -p err --no-pager
ss -lntp
df -h
df -i
free -m
Web 站点再加:
curl -I https://example.com
curl -I https://example.com/login
Nginx:
sudo nginx -t
sudo tail -n 80 /var/log/nginx/error.log
Docker:
docker ps
docker compose ps
docker compose logs --tail 80
数据库:
systemctl status mysql --no-pager
systemctl status postgresql --no-pager
这里不是为了炫命令,而是避免“机器重启了,但业务没恢复”。安全更新的闭环应该是:安装、重启、验证、记录。
有些 VPS 确实不能随便重启,比如正在跑活动、数据迁移、长任务,或者你暂时没有人值守。
这时至少要做三件事:
- 记录当前需要重启的原因
- 评估涉及哪些包
- 约定一个明确的重启时间
可以看:
cat /var/run/reboot-required.pkgs
apt list --upgradable
如果是内核安全更新,长期不重启风险会越来越高。你可以推迟几天,但不要无限期拖着。
还有些发行版或商业方案支持 live patching,可以在不重启的情况下应用部分内核安全补丁。但它不是万能的,也不能替代所有重启。对普通便宜 VPS 来说,最靠谱的还是安排维护窗口。
如果你用的是 RHEL 系,思路一样,但工具不同。
常见命令:
sudo dnf update --security
sudo needs-restarting -r
needs-restarting 通常来自 dnf-utils 或对应工具包。它可以判断是否需要重启。
定时自动更新可以看 dnf-automatic:
sudo dnf install dnf-automatic
systemctl status dnf-automatic.timer
不同发行版的配置文件路径不一样,不要把 Ubuntu 的 unattended-upgrades 配置硬套到 Rocky/AlmaLinux 上。
如果你不想折腾复杂流程,可以照这个最低配方案做:
每周一次,低峰期执行:
sudo apt update
sudo apt list --upgradable
sudo unattended-upgrade --dry-run --debug
确认没有明显异常后,让系统自动安装安全更新,或者手动执行:
sudo unattended-upgrade
如果需要重启:
test -f /var/run/reboot-required && cat /var/run/reboot-required
cat /var/run/reboot-required.pkgs
重启前:
systemctl --failed
df -h
df -i
重启后:
uptime
uname -r
systemctl --failed
curl -I https://example.com
journalctl -b -p err --no-pager
最后把日期、更新包、是否重启、是否有异常记下来。哪怕只记在一个 Markdown 文件里,也比完全靠记忆强。
- 已确认
unattended-upgrades是否安装 - 已确认
/etc/apt/apt.conf.d/20auto-upgrades - 已检查
apt-daily.timer和apt-daily-upgrade.timer - 已查看
/var/log/unattended-upgrades/日志 - 自动更新范围只覆盖合适的软件源
- 已检查
/var/run/reboot-required - 已查看
/var/run/reboot-required.pkgs - 已决定是否启用自动重启
- 生产 VPS 有固定维护窗口
- 重启前检查
systemctl --failed、磁盘、内存 - Docker / Nginx / 数据库确认开机自启
- 重启后检查服务、端口、日志和网站 HTTP 状态
- 每次补丁和重启都有简单记录
VPS 安全更新最怕两种极端:一种是完全不更新,另一种是无脑自动重启。更稳的做法是把自动化用在重复、低风险的地方,把重启放进你能看着它恢复的维护窗口。这样既不会让漏洞补丁拖几个月,也不会半夜把网站重启挂了没人知道。
