Ubuntu服务器安全加固20条:账户、网络到备份的完整实操指南
2026/9/18 5:00:01 网站建设 项目流程

先说一个实话:跟安全沾边的东西,平时没人在意,等真出事的时候基本都是大事。我之前接手过一台被矿机脚本打穿的 Ubuntu 服务器,CPU 直接拉满,跑业务的进程被 kill 一空。排查后才发现问题特别低级——22 端口裸奔、root 密码是八位纯字母、防火墙压根没开、系统补丁几个月没打。那台机器的遭遇其实代表了大多数中小业务的真实状态:不是不想做安全,而是不知道从哪里入手。

安全加固不是装一个杀毒软件就完事,它是一整套从账户、网络、系统配置到监控审计的操作体系。这篇文章我按照自己这几年运维 Ubuntu 服务器的实际操作习惯,整理出 20 条加固方案,按五个层面排好:账户与登录入口、网络暴露面收敛、系统纵深防御、检测审计、备份与应急恢复。每条都给出可以直接抄的命令和配置,适合刚入手第一台 Ubuntu 服务器的小白,也适合想系统性梳理一遍安全基线的老手。

1. 账户体系与登录入口:先管住谁能进你的机器

1.1 root 账户必须"隐身后台"

第 1 条:禁止 root 直接远程登录。

Ubuntu 装完系统后,sshd 默认配置里PermitRootLoginprohibit-password,意思是 root 可以通过密钥登录,但如果你给 root 设置过密码,也能用密码登录。很多人图省事,装完系统直接就把 root 密码设成常用密码,然后开始远程操作。攻击者拿到你的 IP,第一件事就是用 root 加字典暴力破解,一旦中招就是最高权限,后面所有加固措施全白搭。

/etc/ssh/sshd_config里改这一行:

PermitRootLogin no

如果你确实有必须在 root 下操作的场景,可以考虑prohibit-password保留密钥登录,但我的建议是直接改成no,从根上断掉这条路径。改完后验证一下配置再重启服务:

sshd -t systemctl restart ssh

这里有个排错经验要提醒:sshd -t只能帮你检查语法,不能保证你改完能连上。重启 sshd 之前一定要另开一个 SSH 会话测试,避免把自己锁在门外。

1.2 日常操作一律走 sudo 用户

第 2 条:创建一个普通用户,加入 sudo 组,日常所有操作都用这个用户。

不要因为嫌麻烦就一直用 root。普通用户加 sudo 的好处不只是安全,还有一个容易被忽略的点:审计。用 root 操作,日志里只显示 root;用普通用户加 sudo,/var/log/auth.log里能看到是谁在什么时间执行了特权命令,出问题的时候可以定位到人。

创建用户很简单:

adduser ops usermod -aG sudo ops

adduser会自动创建家目录、设置密码,比useradd顺手得多,这也是 Ubuntu 系和 CentOS 系习惯上的差别。建议再顺手配一下 sudo 的密码有效期,避免一次输入 sudo 密码后长时间免密执行:

sudo visudo

在文件里加一行:

Defaults:ops timestamp_timeout=5

这个值表示 sudo 记住密码的时间是 5 分钟,超时要重新输入。对共享运维账号来说,这个配置很实用。

1.3 SSH 登录改为密钥认证

第 3 条:在自己的电脑上生成 ed25519 密钥对,把公钥放到服务器上,然后关掉密码登录。

这应该在 Ubuntu 服务器加固里优先级最高的一条,没有之一。密码认证最大的问题不是密码强度不够,而是它给了所有攻击者一个持续尝试的机会。密钥认证基于非对称加密,私钥不出本地机器,远程爆破基本行不通。

本地生成密钥:

ssh-keygen -t ed25519 -a 100

ed25519是目前 SSH 密钥里推荐的做法,比 RSA 短,安全性足够,-a 100是 KDF 迭代次数,数值越大,私钥暴力破解越难。

把公钥推上服务器:

ssh-copy-id ops@your_server_ip -p 22

然后修改 sshd 配置:

PasswordAuthentication no ChallengeResponseAuthentication no UsePAM no

改完重启 sshd,确认密钥能正常登录之后再关闭密码。千万记住:先开着密码验证,用第二个 SSH 会话测试密钥登录,成功后再关密码,顺序反了就要跑机房了。

1.4 密码口令策略与登录失败锁定

第 4 条:给系统用户设置密码复杂度和有效期,同时加上登录失败锁定。

/etc/login.defs里可以设置几项默认策略:

PASS_MAX_DAYS 90 PASS_MIN_DAYS 7 PASS_MIN_LEN 12

意思是密码最长使用 90 天必须改,最短使用 7 天防止用户频繁改回旧密码,最小长度 12 位。真正起作用的复杂度策略在 PAM 里,安装 libpam-pwquality:

apt install libpam-pwquality

然后在/etc/pam.d/common-password里找到pam_pwquality.so那一行,加上:

retry=3 minlen=12 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1

表示至少 12 位,必须包含大写字母、小写字母、数字、特殊字符。

登录失败锁定用 pam_faillock。在/etc/pam.d/common-auth文件最前面插入两段配置:

auth required pam_faillock.so preauth audit silent deny=5 unlock_time=300 auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=300

再在/etc/pam.d/common-account最前面加一段:

account required pam_faillock.so

意思是连续失败 5 次锁 300 秒。我建议把 root 排除在锁定之外,防止攻击者故意把 root 锁掉导致运维进不去。在 preauth 那一行加even_deny_root你可能还要考虑 root 在 1.1 里已经禁止登录了,锁不锁其实无所谓,但稳妥起见还是在 failock 文件配置里排除:

PAM 配置改错了很容易导致所有登录失效,一定是种常见翻车现场。我自己的习惯是永远保留一个已经登录的 SSH 会话,改完配置不要马上测试新连接,先把语法检查好,再小范围验证。

2. 网络暴露面收敛:让扫描器扫完就想放弃

2.1 变更 SSH 默认端口

第 5 条:把 SSH 从 22 端口挪走,改成高位端口。

这条和上面的密钥认证配合起来效果最好。改端口的主要目的不是为了防住真正的攻击者——他们用端口扫描器几秒钟就能发现新端口——而是为了减少大量无差别扫描器的噪音。我在生产环境统计过,22 端口开放的机器一天能收到几千条Failed password日志,改成高位端口后瞬间降到个位数。

修改/etc/ssh/sshd_config

Port 60231

推荐用 1024 以上的高位端口,避免和常见服务冲突。记得更新防火墙规则,把新端口放行,不然下一秒你就连不上服务器了。

重要:改完 SSH 端口后,立刻用新端口连接测试,确认通了再退出当前会话。这个操作和改密钥认证一样,顺序一颠倒就会把自己锁在门外。

2.2 UFW 默认拒绝所有入站流量

第 6 条:开启 UFW 防火墙,默认策略设成拒绝入站。

Ubuntu 自带的 UFW 是 iptables 的前端封装,对不熟悉防火墙的人来说是最容易上手的选择。核心思路是白名单模式:默认拒绝所有进来的连接,只放行明确需要的端口。

ufw default deny incoming ufw default allow outgoing ufw allow 60231/tcp ufw allow 80/tcp ufw allow 443/tcp ufw enable

执行完可以看到规则列表。注意ufw enable之后要确认 SSH 端口已经放行,否则当前连接会直接断掉。

我习惯把 UFW 视为第一层过滤,云平台的安全组是第二层。两道防火墙配置相同规则,不冲突,反而多一层保险。但要注意,两层防火墙的规则可能会让你排查问题时产生混乱——连不上时先确认安全组,再确认 UFW,别绕圈。

2.3 限制管理来源 IP

第 7 条:如果管理和运维入口的 IP 基本固定,直接在防火墙层面对 SSH 做来源限制。

比如办公室出口 IP 是203.0.113.10,那就只允许这个 IP 访问 SSH:

ufw allow from 203.0.113.10 to any port 60231 proto tcp

这个配置比 fail2ban 更硬核:IP 都不对,根本摸不到你的 SSH 服务。但它的前提是你的 IP 真的固定,如果家里宽带是动态 IP,或者你经常出差换网络,这个方案会让自己很难受。

IP 来源限制建议结合云平台安全组来做。像阿里云、腾讯云、AWS 上,直接在 VPC 安全组里只放行固定 IP 到 SSH 端口,服务器本地的 UFW 都不用额外配置。

2.4 业务服务和管理面分离

第 8 条:数据库、缓存、消息队列这类服务,绝对不要绑定0.0.0.0

很多人装完 MySQL、Redis 之后直接默认配置启动,服务监听了所有网卡接口。如果云平台安全组没挡住 3306、6379 端口,Redis 未授权访问、MySQL 被爆破就是分分钟的事。

检查本机服务监听情况:

ss -lntup

看到类似0.0.0.0:3306的输出就要警惕。MySQL 建议在配置文件里改成:

bind-address = 127.0.0.1

如果业务需要远程访问数据库,也建议通过内网网段访问,比如 private 网络的 IP 是10.0.0.1,就写bind-address = 10.0.0.1,不要把公网 IP 绑上去。

Redis 更要注意,生产环境最好加protected-mode yesrequirepass,并且只 listen 127.0.0.1。很多挖矿木马最喜欢扫 Redis 端口,因为它的协议简单,未授权访问就等于直接拿 shell。这个场景我见过太多了,代价最少的一次,是业务挂了一整天,管理员在那里刷防火墙规则。

3. 系统纵深防御:补上那些"看着不大,爆了就完了"的洞

3.1 开启自动安全更新

第 9 条:启用 unattended-upgrades,只自动安装安全补丁。

很多服务器被攻破,攻击者利用的漏洞其实已经发布了官方补丁,但服务器一两个月没更新。Ubuntu 的自动更新机制默认会在安装更新时重启服务,但这会让线上业务出现不可控的中断,所以我们要做的是只开启安全更新来源,其他包更新继续手动控制。

安装并配置:

apt update apt install unattended-upgrades dpkg-reconfigure --priority=low unattended-upgrades

运行完 dpkg-reconfigure 之后会自动启用,查看配置文件确认:

cat /etc/apt/apt.conf.d/50unattended-upgrades

重点关注这几行,确保 security 相关的 origin 被取消注释:

"origin=Ubuntu,archive=jammy-security";

自动更新会在凌晨随机时间执行,对业务影响很小。个人建议在这里把"自动清理不需要的依赖"也打开,避免长期使用/var空间被撑爆。

3.2 关键文件权限与 SUID 排查

第 10 条:检查系统关键文件权限,重点排查 SUID/SGID 文件。

先看几个最核心的文件权限是否正常:

ls -l /etc/shadow /etc/passwd /etc/sudoers

正常情况应该是:

  • /etc/shadow-rw-r-----root shadow,640
  • /etc/passwd-rw-r--r--644
  • /etc/sudoers-r--r-----root root,440

如果权限被改宽了,第一时间通过 chmod 改回。接下来排查涉嫌提权的 SUID 文件:

find / -perm -4000 -type f 2>/dev/null

SUID 位的意思是普通用户执行这个文件时会以文件属主的身份运行。这是 Linux 提权的经典路径,攻击者拿到普通用户权限后,如果发现系统里有不正常的 SUID 文件,就能直接提权到 root。

排查时把系统内置的/usr/bin/sudo/usr/bin/passwd等放行,其他不认识的,特别是/tmp/var/tmp/home目录下的 SUID 文件,大概率有问题,直接删除或用chmod u-s去掉 SUID 位。

3.3 内核参数与安全模块加固

第 11 条:调整内核参数,禁用不安全的网络行为,并开启 AppArmor 强制模式。

编辑/etc/sysctl.conf,追加以下内容:

# 禁用 IP 源路由 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.default.accept_source_route = 0 # 禁用 ICMP 重定向 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 # 禁用发送重定向 net.ipv4.conf.all.send_redirects = 0 # 启用 TCP SYN cookies,防 SYN 洪泛 net.ipv4.tcp_syncookies = 1 # 启用地址空间布局随机化 kernel.randomize_va_space = 2 # 限制 dmesg 查看内核日志,只有 root 可以 kernel.dmesg_restrict = 1

保存后执行:

sysctl -p

关于禁 ping:很多人喜欢把icmp_echo_ignore_all改成 1 来隐藏服务器,我一般不会这样做。因为内网监控系统需要 ping 探活,而且禁 ping 对真正的攻击者没用,反而给运维排查增加麻烦。

Ubuntu 自带 AppArmor 而不是 SELinux,确认它是开启状态:

aa-status

如果看到一堆enforce模式的 profile 列表,说明正常的。Ubuntu 桌面版上有很多 profile 可能是 complain 模式,但服务器上尽量保持 enforce。

3.4 恶意软件与 Rootkit 扫描

第 12 条:安装 rkhunter 和 chkrootkit,定期扫描 Rootkit 和已知恶意软件。

Rootkit 是入侵之后用于隐藏踪迹的工具,一旦被种下,普通的 ps、netstat 都看不到异常。扫描工具的原理是基于已知特征和行为模式比对,不能做到 100% 检出,但有比没有强太多。

apt install rkhunter chkrootkit rkhunter --update rkhunter --check --skip-keypress chkrootkit

rkhunter 第一次扫描会看到很多 WARNING,新手经常在这里被吓到。其实很多是误报,比如 SSH 配置文件的 hash 和默认值不一致。正确的做法是确认过这些告警后,用下面的命令标记为已知状态:

rkhunter --propupd

之后再跑扫描就只关注新增的告警了。

3.5 关闭不必要的服务与端口

第 13 条:把用不上的系统服务停掉甚至 mask 掉,缩小攻击面。

很多服务器装完系统,跑着一堆和业务无关的东西。比如avahi-daemon(mDNS 广播)、cups(打印服务)、postfix(邮件服务),这些在 Web 服务器上大概率没什么用。攻击者如果通过某个服务拿到了 shell,这些多余服务很容易成为横向移动的跳板。

先看当前运行的服务:

systemctl list-units --type=service --state=running

对照业务清单,把不认识或不需要的服务逐个确认。比如:

systemctl stop cups systemctl disable cups systemctl mask cups

disable只是取消开机自启,mask更彻底,会把它和启动请求都符号链接到/dev/null,任何依赖它启动的操作都会失败。对确定没用的服务,我建议直接 mask。

4. 检测与审计:安全防线被突破后还能第一时间发现

4.1 日志体系与日志滚动

第 14 条:让系统日志持久化存储,并配置日志轮转,防止日志把磁盘写满。

Ubuntu 服务器默认用 systemd-journald 记日志,但日志默认只存在内存里,重启就没了。把日志持久化到磁盘:

mkdir -p /var/log/journal systemctl restart systemd-journald

这样/var/log/journal目录会开始积累日志。同时配置 logrotate,让日志按周期轮转:

cat > /etc/logrotate.d/syslog <<'EOF' /var/log/auth.log /var/log/syslog /var/log/kern.log { weekly rotate 4 compress missingok notifempty } EOF

这里配置的是每周轮转一次,保留 4 份,压缩存储。对业务日志量大的服务器,建议把频率改成daily,不然磁盘被日志打满,业务响应也会跟着出问题。

日志的价值在排查问题时才能体现。有一次线上服务半夜报错,就是这个/var/log/syslog里留着完整的上下文,我才快速定位到是某个依赖模块触发了 OOM。没有日志,一切排查都是盲猜。

4.2 SSH 登录审计与暴力破解封禁

第 15 条:重点监控 SSH 登录日志,做到实时发现异常登录来源。

系统日志里最值得关注的是/var/log/auth.log,里面记录了所有登录尝试。最基本的统计命令:

grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr

这个命令会按 IP 统计失败的 SSH 登录次数,排在最前面的就是要重点关注的攻击源。如果某个 IP 出现了几十次失败记录,说明它在对你做暴力破解。

真正的劳动力解放靠 fail2ban。安装配置:

apt install fail2ban

创建/etc/fail2ban/jail.local

[sshd] enabled = true port = 60231 filter = sshd logpath = /var/log/auth.log maxretry = 5 findtime = 600 bantime = 3600

配置含义:10 分钟内失败 5 次,封禁 1 小时。我建议 bantime 不要设太长,万一你自己多次输错密码被 ban 了,等太久会很烦躁。后期可以根据攻击频率逐步加大。

4.3 文件完整性监控

第 16 条:用 AIDE 对系统关键目录做文件完整性基线,定期比对。

入侵者往往会修改系统二进制文件或配置文件来维持权限,文件完整性监控可以发现这些改动。AIDE 的思路是先为指定目录生成一个哈希基线库,之后每次比对当前状态和基线库是否一致。

安装初始化:

apt install aide aideinit

第一次会把/etc/usr/sbin/bin等目录的指纹生成到/var/lib/aide/aide.db,后面的比对命令:

aide.wrapper --check

输出里所有新增、删除、修改的文件都会列出来。这个工具最大的坑是误报——你自己正常改了配置文件,下次比对也会报差异。所以每次做完合法变更,记得重新生成基线:

aideinit -y -f

如果你管了很多台机器,文件完整性监控更适合用 centralized 方案,每台机器装 agent,日志汇总到管理端统一告警。单机用 AIDE 解决不了告警无人看的问题,这个度自己把握。

4.4 定期排查开放端口与监听进程

第 17 条:把"检查监听端口"固化成周期性动作,比网络层加固更主动。

安全加固不是为了防住所有人,而是让自己对服务器状态有感知。我把每台服务器每个月执行一次端口排查写成脚本,输出所有监听端口对应的进程名,和预期清单对比:

ss -lntup

重点关注两类:

  • 没有经过 UFW 放行的监听端口。服务器上出现这种情况,通常是某个服务自己改了配置或者被入侵者留了后门。
  • 对公网网卡(不是 127.0.0.1 或内网 IP)开放的高位端口。这经常是攻击者种的远控木马在监听某个随机端口,等待回连指令。

排查时可以把输出重定向到文件,然后比对上一次的结果:

ss -lntup > /tmp/ports_now.txt diff /tmp/ports_before.txt /tmp/ports_now.txt

多出来的端口就是需要重点调查的对象。

5. 备份与应急恢复:加固的最后一块拼图没有备份就谈不上安全

5.1 核心数据自动备份

第 18 条:数据库、配置目录、上传文件必须有自动化备份,并且备份要存到其他位置。

前面 17 条都是在降低被攻破的概率,但没有任何系统能保证 100% 不被攻破。一旦被勒索病毒加密,或者自己的误操作删除了数据,备份就是最后的救命稻草。

先写一个实用的备份脚本,放到/usr/local/bin/backup.sh

#!/bin/bash BACKUP_DIR="/backup/$(date +%F)" mkdir -p "$BACKUP_DIR" mysqldump --single-transaction -u backup_user -p'password' mydb | gzip > "$BACKUP_DIR/mydb.sql.gz" tar czf "$BACKUP_DIR/etc.tar.gz" /etc find /backup -type f -mtime +7 -delete

加执行权限,再写进 crontab:

crontab -e 0 2 * * * /usr/local/bin/backup.sh

每天凌晨 2 点执行。这里的重点是把备份文件放到不是同一台机器的地方,我一般用 rsync 再同步到内网另一台存储,或者用 restic 加密后推到 S3 兼容对象存储。如果数据很重要,异地备份是必须的,光备份在同一台机器的其他目录,磁盘一坏全完。

5.2 恢复演练:光备份不恢复等于没备份

第 19 条:每个季度至少做一次备份恢复演练,确保备份数据真的能派上用场。

这句话估计大家都听过,但真正做过恢复演练的团队少得可怜。很多团队"备份了三年,从没恢复过",第一次恢复就发现备份文件损坏、加密密钥失效、恢复流程缺失关键步骤。

恢复演练不需要在生产服务器上折腾。我通常在一台全新的虚拟机里,模拟生产环境安装系统,装上数据库和业务依赖,然后把备份文件拉回来执行恢复:

gunzip -c mydb.sql.gz | mysql -u root mydb tar xzf etc.tar.gz -C /

恢复完检查几个点:数据库表数量、关键行数据、站点是否能正常响应。确认没问题后,把恢复步骤更新到文档,然后销毁演练机器。这个过程不需要很频繁,但每季度一次是值得的,否则紧急时刻你根本无法冷静地靠记忆恢复。

5.3 安全巡检与加固基线固化

第 20 条:用自动化安全检查工具做定期巡检,把加固配置固化成基线,实现新机器一键套用。

前面 19 条大多是"装一次"就完事,但服务器的安全状态是会动态变化的:新装的软件可能开了新端口,新加的账户可能权限过大,内核升级后 sysctl 配置可能被覆盖。所以加固方案必须有一个周期性巡检闭环。

我推荐用一个成熟的审计工具 Lynis:

apt install lynis lynis audit system

它会把系统层面的安全配置全部过一遍,最后输出一个 hardening index 分数,并列出每一条需要关注的项目。第一次跑完看到 scores 会很焦虑,因为很多项都是建议性的,要根据自己业务做取舍。核心思路是:把合理的加固项固化成 Ansible playbook 或 shell 脚本,对一套新环境几分钟就能完成基线配置。

我自己在团队里维护了一个 baseline 脚本仓库,把这个清单里涉及的账户配置、SSH 配置、UFW 规则、sysctl 参数、AIDE 初始化、日志持久化全部写成脚本。新机器上线先跑 baseline,再过一轮代码评审,出问题的概率大幅下降。

另外提醒一句:安全巡检发现的问题一定要进任务清单,规定整改时限。没有闭环的巡检,就是走个形式,骗骗自己而已。


最后再分享一点个人体会。安全加固这件事,真正拉开差距的不是命令用得有多花哨,而是你能不能坚持下去。我见过很多人的做法是:服务器上线当天兴致勃勃加固一遍,之后半年不管不问,直到被入侵了再来翻旧账。其实从 20 条里挑出最影响安全的几条——禁用 root 密码登录、密钥认证、UFW 白名单、自动安全更新、定期备份——先把这五条做到位,就能防住绝大多数攻击。剩下的属于锦上添花,但长期运营下来,别嫌麻烦,该做的都得做。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询