Ubuntu服务器长期不更新漏洞补丁,等于把已知的入侵路径明晃晃地暴露在公网上。很多运维人员以为手动执行apt upgrade就够了,实际上生产环境里经常因为疏忽、休假或服务器数量多而漏更。更现实的问题是,Ubuntu默认的无人值守升级功能虽然存在,但配置不够精细,很多关键服务的安全更新并没有被覆盖到。要把漏洞自动修复这件事真正落地,需要从软件源、自动升级策略、内核热补丁、服务重启行为以及告警通知几个层面一起配合,而不是简单装个包就完事。

先确认基础软件源和更新通道是否正常

自动修复的前提是系统能稳定获取到安全更新。Ubuntu把更新分为几个仓库:主仓库、安全仓库、更新仓库等。安全更新主要来自“-security”这个套件。先检查/etc/apt/sources.list以及/etc/apt/sources.list.d/目录下的源配置,确保至少包含类似下面这样的安全源:

deb http://archive.ubuntu.com/ubuntu jammy main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu jammy-updates main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu jammy-security main restricted universe multiverse

这里的jammy是22.04的代号,如果你用的是20.04就换成focal,24.04换成noble。很多人只配了主仓库,没配security仓库,导致系统永远拿不到安全公告对应的修复包。确认源之后执行sudo apt update,观察是否有报错。如果服务器在国内,可以把archive.ubuntu.com和security.ubuntu.com换成速度更快的镜像地址,但不要使用来源不明的第三方源,否则自动更新会引入不可控的软件版本。

安装并启用unattended-upgrades

Ubuntu官方提供的自动更新工具叫unattended-upgrades,它本质上是一个apt的封装,只安装安全更新,不主动升级系统大版本。先安装:

sudo apt install unattended-upgrades

安装完成后,主配置文件位于/etc/apt/apt.conf.d/50unattended-upgrades。这个文件决定了哪些更新源被允许自动安装。默认情况下,它只允许来自安全仓库的更新。打开文件,找到Unattended-Upgrade::Allowed-Origins这一段,确认包含:

Unattended-Upgrade::Allowed-Origins {
        "${distro_id}:${distro_codename}";
        "${distro_id}:${distro_codename}-security";
        "${distro_id}ESMApps:${distro_codename}-apps-security";
        "${distro_id}ESM:${distro_codename}-infra-security";
};

第一行允许的是普通更新仓库,第二行是安全仓库,后面两行是Ubuntu Pro的扩展安全维护源。如果你没有购买Ubuntu Pro订阅,后面两行不会生效,但保留不影响。关键是第二行必须存在,否则自动修复形同虚设。

调整自动更新的具体行为

光启用还不够,默认配置里有很多细节需要根据服务器角色调整。比如自动更新的邮件通知、自动重启行为、黑名单等。在同一个配置文件里,找到Unattended-Upgrade::Mail和Unattended-Upgrade::MailReport这两个选项。Mail用来指定接收通知的邮箱,MailReport可以设置为on-change或only-on-error。on-change表示每次有更新安装就发邮件,only-on-error只在出错时发邮件。对于生产服务器,建议设置成on-change,这样每次自动修复都有记录可查:

Unattended-Upgrade::Mail "ops@example.com";
Unattended-Upgrade::MailReport "on-change";

另一个关键选项是Unattended-Upgrade::Automatic-Reboot。默认是false,也就是自动更新完不重启。但很多安全更新涉及内核或关键库,不重启等于没生效。对于可以接受短暂重启的服务器,可以设置为true,并配合Unattended-Upgrade::Automatic-Reboot-Time指定重启时间,比如凌晨4点:

Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";

如果服务器不能随意重启,比如数据库主库或核心业务节点,就不要开启自动重启,而是配合内核热补丁或计划维护窗口手动重启。但至少要把自动下载和安装做好,减少漏洞暴露窗口。

处理依赖问题和更新黑名单

有些软件包升级后可能引发兼容性问题,比如特定版本的MySQL、Redis或某些商业软件依赖固定版本的库。unattended-upgrades允许设置黑名单,禁止自动更新某些包。在50unattended-upgrades文件里找到Unattended-Upgrade::Package-Blacklist段落,把需要排除的包写进去:

Unattended-Upgrade::Package-Blacklist {
    "mysql-server";
    "mysql-client";
    "redis-server";
};

黑名单不是偷懒的借口。如果某个包被列入黑名单,意味着它永远不会被自动修复,漏洞风险会一直存在。更合理的做法是定期审查黑名单,确认这些包是否还需要排除,或者是否有替代方案。另外,unattended-upgrades默认不会自动处理依赖关系复杂的情况,如果更新时出现依赖错误,它会跳过并记录日志。日志位置在/var/log/unattended-upgrades/目录下,每次自动更新后都应该检查一下,看看有没有包因为依赖问题被跳过。

启用定时任务让自动更新真正跑起来

安装unattended-upgrades后,它并不会自动运行,需要配合apt的定时任务。Ubuntu通过/etc/apt/apt.conf.d/20auto-upgrades文件控制自动更新的频率。这个文件里有两个关键选项:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

第一个选项表示每天更新一次软件包列表,第二个选项表示每天执行一次无人值守升级。数字代表天数,1就是每天。如果希望更频繁,比如每12小时一次,可以设置为0.5,但一般每天一次足够。修改完这个文件后,系统会通过systemd timer触发,不需要额外配置cron。可以用systemctl list-timers | grep apt确认定时器是否正常加载。

内核漏洞修复的特殊处理

Ubuntu的安全更新里很大一部分是内核更新。内核更新后如果不重启,旧内核仍然在运行,漏洞依然存在。对于不能频繁重启的服务器,Livepatch是一个更优的选择。Ubuntu的Livepatch服务可以在不重启的情况下给运行中的内核打补丁,修复高危漏洞。启用Livepatch需要Ubuntu Pro订阅,个人用户或少量服务器可以免费使用。启用命令:

sudo pro enable livepatch

启用后,系统会自动连接到Livepatch服务,定期检查并应用内核热补丁。Livepatch只能修复部分类型的内核漏洞,不能替代完整的内核升级,但它能显著减少因安全更新导致的重启次数。对于没有订阅Ubuntu Pro的服务器,建议把内核更新纳入计划维护窗口,至少每月重启一次,确保累积的内核补丁真正生效。

监控自动修复的效果和失败情况

自动修复不是设置完就一劳永逸。需要定期确认三件事:第一,安全更新是否真的在安装;第二,有没有包因为依赖或黑名单被跳过;第三,更新后服务是否正常。可以写一个简单的脚本,每天检查/var/log/unattended-upgrades/下的日志,把关键信息汇总后发送到运维群或邮件。比如用grep过滤出“Packages that were upgraded”和“Packages with upgradable origin but kept back”这两行,前者是成功升级的包,后者是被跳过的包。如果被跳过的包数量持续增加,说明有依赖问题需要人工介入。

另外,自动更新后服务是否正常,不能只看进程在不在。建议配合监控系统,对关键端口和接口做健康检查。比如Nginx更新后,自动重启是否成功,443端口是否正常响应;MySQL更新后,主从复制是否中断。这些检查可以放在自动更新的定时任务之后执行,或者由监控系统在每天固定时间点做一次全量巡检。

结合Ubuntu Pro扩展安全维护

Ubuntu的LTS版本有5年的标准支持期,但很多生产服务器的使用周期超过5年。超过标准支持期后,普通的安全仓库不再提供更新,漏洞修复就断了。Ubuntu Pro可以把安全维护延长到10年,并且覆盖universe仓库里的软件包。对于运行老版本Ubuntu的服务器,启用Ubuntu Pro是继续自动修复漏洞的唯一可行方案。启用后,unattended-upgrades会自动识别ESM源,把扩展安全更新也纳入自动安装范围。免费个人用户最多可以注册5台机器,企业用户按机器数付费。从安全合规角度看,超过5年的系统如果不接Pro,等于在裸奔。

自动修复策略的分级建议

不是所有服务器都适合用同一套自动更新策略。根据业务重要性和可重启性,建议分成三级。第一级是边缘节点、测试服务器、开发环境,可以开启完全自动更新和自动重启,更新时间设为凌晨,邮件通知设为on-change。第二级是普通生产服务器,开启自动下载和安装安全更新,但不自动重启,由运维在维护窗口手动重启,邮件通知设为on-change。第三级是核心数据库、中间件、关键业务节点,只自动下载更新包,不自动安装,由运维在变更窗口手动执行安装和重启。这样既保证了大部分服务器的漏洞能被及时修复,又避免自动更新对核心业务造成意外冲击。

实现分级策略也很简单,通过修改/etc/apt/apt.conf.d/20auto-upgrades里的参数即可。第一级和第二级的区别在于50unattended-upgrades里的Automatic-Reboot选项。第三级则把APT::Periodic::Unattended-Upgrade设置为0,只保留Update-Package-Lists为1,让系统每天下载更新列表但不安装。

常见误区和故障排查

很多运维配置完unattended-upgrades后发现没有生效,最常见的原因是安全源配置错误。检查/etc/apt/sources.list里是否包含security.ubuntu.com,并且执行sudo apt update时没有报错。第二个常见原因是时区问题,Automatic-Reboot-Time使用的是系统本地时间,如果服务器时区设置错误,自动重启可能发生在业务高峰期。第三个原因是邮件通知不生效,很多服务器没有配置本地MTA,unattended-upgrades默认使用mail命令发送邮件,如果系统里没有安装mailutils或postfix,邮件根本发不出去。可以安装mailutils并配置一个简单的SMTP中继,或者改用脚本把日志推送到企业微信、钉钉等内部工具。

还有一个容易被忽略的点是,unattended-upgrades默认不会自动清理旧内核。随着内核更新次数增加,/boot分区可能被占满,导致后续更新失败。可以在/etc/apt/apt.conf.d/50unattended-upgrades里设置Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"和Unattended-Upgrade::Remove-New-Unused-Dependencies "true",让系统自动清理不再使用的旧内核和依赖包。对于/boot分区本来就比较小的服务器,这个设置非常关键。

Ubuntu服务器漏洞自动修复的核心是把安全更新从手动动作变成系统默认行为,同时通过分级策略、黑名单、邮件通知和日志监控来保证可控性。单纯安装unattended-upgrades只是第一步,真正可靠的自动修复体系需要结合内核热补丁、定期重启计划、监控告警和Ubuntu Pro扩展支持。对于任何暴露在公网的Ubuntu服务器,至少要做到每天自动检查安全更新并安装,否则漏洞修复的速度永远赶不上扫描器发现的速度。