Linux: 防火墙与安全基础——ufw / SSH 加固 / fail2ban

一台新 Linux 服务器连接到互联网后,几分钟内就会被扫描和攻击尝试。安全加固不是可选,而是必需。

📋 前置知识:需要先掌握以下内容

1. 你将学到


2. 一个被攻击的真实故事

(1) 痛点:服务器上线第二天就被暴力破解

小明买了一台云服务器部署自己的博客。第二天查看日志时吓了一跳:

BASH
grep "Failed password" /var/log/auth.log | wc -l
# 1234 次尝试!

SSH 端口 22 上有来自全世界的自动扫描程序在不断尝试登录。

(2) 三层加固

他做了三件事:

BASH
# 1. 改用密钥登录
ssh-keygen -t ed25519
ssh-copy-id user@server

# 2. 关闭密码登录
sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config

# 3. 安装 fail2ban:5 次失败封 24 小时
sudo apt install fail2ban
sudo systemctl enable fail2ban

(3) 收益:攻击归零

加固后,auth.log 中的失败尝试从每天 1000+ 降为 0。


3. 知识点讲解

(1) ufw——简单防火墙

BASH
# 基本操作
sudo ufw status                   # 查看状态
sudo ufw enable                   # 启用防火墙
sudo ufw disable                  # 禁用防火墙
sudo ufw reload                   # 重载规则

# 规则管理
sudo ufw allow 22/tcp             # 允许 SSH
sudo ufw allow 80/tcp             # 允许 HTTP
sudo ufw allow 443/tcp            # 允许 HTTPS
sudo ufw deny 23/tcp              # 拒绝 Telnet
sudo ufw deny from 10.0.0.100     # 封禁特定 IP

# 应用配置
sudo ufw app list                 # 查看应用列表
sudo ufw allow "Nginx Full"       # 允许 Nginx(80+443)
sudo ufw allow "OpenSSH"          # 允许 SSH

# 规则管理
sudo ufw status numbered          # 显示规则编号
sudo ufw delete 2                 # 删除规则 2
⚠️ 注意:ufw/iptables 规则按顺序匹配,第一条命中的规则生效。如果先写 allow from 0.0.0.0/0 再写 deny from 恶意IP,deny 永远不会生效——allow 已经先匹配了。添加规则时务必注意顺序,用 ufw status numbered 检查规则列表。

⚠️ 注意:使用 ufw allow from 指定信任 IP 时,切勿使用 0.0.0.0/0(允许所有 IP),这等同于不做限制,完全失去了防火墙意义。始终限定具体 IP 或 CIDR 段,如 ufw allow from 192.168.1.0/24

新服务器的安全策略:

⚠️ 注意ufw default deny incoming 意味着默认拒绝所有入站连接,这是一条白名单策略——只有明确 allow 的端口才能访问。这是最安全的默认策略,但启用前必须先放行 SSH(22/tcp),否则你将被自己锁在服务器外面。

BASH
# 默认拒绝所有入站
sudo ufw default deny incoming
# 默认允许所有出站
sudo ufw default allow outgoing

# 只开放需要的端口
sudo ufw allow 22/tcp    # SSH
sudo ufw allow 80/tcp    # HTTP
sudo ufw allow 443/tcp   # HTTPS

sudo ufw enable

(2) SSH 密钥认证

BASH
# 生成密钥对(推荐 Ed25519)
ssh-keygen -t ed25519 -C "your_email@example.com"

# 传统 RSA(4096 位)
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

# 拷贝公钥到服务器
ssh-copy-id user@server-ip

# 或手动添加
cat ~/.ssh/id_ed25519.pub | ssh user@server-ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

# 验证密钥登录
ssh user@server-ip

(3) SSH 安全加固

⚠️ 注意:修改 SSH 端口(如改为 2222)前,必须确保有替代访问方式。如果你的云服务商提供 VNC 控制台,可用它作为备用入口。修改端口后,记得在 ufw 中放行新端口(ufw allow 2222/tcp),否则防火墙会阻断新端口的连接。建议在修改前保持一个现有 SSH 会话不断开,作为安全回退。

编辑 /etc/ssh/sshd_config

TEXT 📖 仅展示
Port 2222                      # 改默认端口(避开自动扫描)
PermitRootLogin no             # 禁止 root 直接登录
PasswordAuthentication no      # 禁用密码登录
PubkeyAuthentication yes       # 启用密钥登录
AllowUsers alice bob           # 仅允许指定用户登录
MaxAuthTries 3                 # 最大认证尝试次数
ClientAliveInterval 60         # 客户端保活间隔(秒)
ClientAliveCountMax 3         # 保活最大失败次数

验证配置并重启:

BASH
sudo sshd -t                   # 测试配置语法
sudo systemctl restart sshd    # 重启 SSH 服务

(4) fail2ban

💡 提示:fail2ban 的 jail.conf 是软件包提供的默认配置,每次升级可能被覆盖。自定义配置应写在 jail.local/etc/fail2ban/jail.d/ 目录下,这些文件不会被升级覆盖,且优先级更高。

BASH
# 安装
sudo apt install fail2ban

# 查看状态
sudo fail2ban-client status
sudo fail2ban-client status sshd

# 默认配置(/etc/fail2ban/jail.conf),一般不需要改
# [sshd]
# enabled = true
# port = ssh
# filter = sshd
# logpath = /var/log/auth.log
# maxretry = 5
# bantime = 3600

# 创建本地覆盖
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo systemctl restart fail2ban

# 查看被封的 IP
sudo iptables -L f2b-sshd -n

▶ 示例:ufw 完整配置

BASH
# 如果 SSH 连接中,先允许 SSH
sudo ufw allow 22/tcp

# 配置默认策略
sudo ufw default deny incoming
sudo ufw default allow outgoing

# 开放服务端口
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 2222/tcp     # 如果改了 SSH 端口

# 启用
sudo ufw enable
sudo ufw status verbose

输出:

TEXT 📖 仅展示
Rule added
Rule added
Default incoming policy changed to 'deny'
Default outgoing policy changed to 'allow'
Rule added
Rule added
Rule added
Firewall is active and enabled on system startup
Status: active
Logging: on (low)
To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere
80/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere
2222/tcp                   ALLOW IN    Anywhere

▶ 示例:SSH 密钥创建和使用

BASH
# 1. 在本地机器生成密钥
ssh-keygen -t ed25519

# 2. 复制到服务器
ssh-copy-id -i ~/.ssh/id_ed25519.pub alice@192.168.1.100

# 3. 测试免密登录
ssh alice@192.168.1.100

# 4. 使用 SSH 配置文件简化登录
cat >> ~/.ssh/config << 'EOF'
Host myserver
    HostName 192.168.1.100
    User alice
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
EOF

# 现在可以简写为
ssh myserver

输出:

TEXT 📖 仅展示
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/alice/.ssh/id_ed25519):
Your identification has been saved in /home/alice/.ssh/id_ed25519
Your public key has been saved in /home/alice/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:abc123def456 alice@workstation
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/alice/.ssh/id_ed25519.pub"
Number of key(s) added: 1
Now try logging into the machine:   ssh alice@192.168.1.100
Welcome to Ubuntu 22.04.3 LTS
Last login: Tue Jul  7 10:23:45 2026

▶ 示例:SSH 加固实操

BASH
# 备份原始配置
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup

# 修改配置
sudo sed -i 's/^#Port 22/Port 2222/' /etc/ssh/sshd_config
sudo sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config

# 验证配置
sudo sshd -t

# 重启 SSH
sudo systemctl restart sshd

输出:

TEXT 📖 仅展示
(no output from sshd -t means config is valid)

▶ 示例:fail2ban 配置

BASH
# 查看 fail2ban 状态
sudo fail2ban-client status

# 查看 SSH 防护状态
sudo fail2ban-client status sshd
# Status for the jail: sshd
# |- Filter
# |  |- Currently failed: 3
# |  |- Total failed: 45
# |  `- File list: /var/log/auth.log
# `- Actions
#    |- Currently banned: 5
#    |- Total banned: 12
#    `- Banned IP list: 192.168.1.100 10.0.0.50

# 手动解封 IP
sudo fail2ban-client set sshd unbanip 192.168.1.100

# 自定义封禁时间
sudo tee /etc/fail2ban/jail.d/custom-sshd.conf << 'EOF'
[sshd]
enabled = true
maxretry = 3
bantime = 86400    # 24 小时
findtime = 600     # 10 分钟内
EOF

sudo systemctl restart fail2ban

输出:

TEXT 📖 仅展示
Status for the jail: sshd
|- Filter
|  |- Currently failed: 3
|  |- Total failed: 45
|  `- File list: /var/log/auth.log
`- Actions
   |- Currently banned: 5
   |- Total banned: 12
   `- Banned IP list: 192.168.1.100 10.0.0.50
1 unbanned

[sshd]
enabled = true
maxretry = 3
bantime = 86400
findtime = 600

▶ 示例:自动安全更新

BASH
# 安装自动更新
sudo apt install unattended-upgrades

# 配置
sudo dpkg-reconfigure --priority=low unattended-upgrades

# 或者手动编辑配置
sudo tee /etc/apt/apt.conf.d/50unattended-upgrades << 'EOF'
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
    "${distro_id}:${distro_codename}-updates";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
EOF

输出:

TEXT 📖 仅展示
Reading package lists... Done
Building dependency tree... Done
The following NEW packages will be installed:
  unattended-upgrades
0 upgraded, 1 newly installed, 0 to remove

▶ 综合示例:新服务器一键安全加固

BASH
#!/bin/bash
# secure-server.sh - 新服务器安全加固脚本
# 使用说明:首次 SSH 登录后立即运行
# 注意:确保你已经在另一个终端开启了一个 SSH 会话作为备份!

set -euo pipefail

SSH_PORT="${1:-2222}"

echo "========================================"
echo "    服务器安全加固"
echo "    时间: $(date)"
echo "========================================"

# 1. 更新系统
echo ">>> 1/6 更新系统..."
sudo apt update && sudo apt upgrade -y

# 2. 配置防火墙
echo ">>> 2/6 配置防火墙..."
sudo ufw --force disable
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow "$SSH_PORT/tcp" comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
sudo ufw --force enable
echo "防火墙配置完成 (SSH 端口: $SSH_PORT)"

# 3. 配置 SSH 密钥
echo ">>> 3/6 配置 SSH 密钥..."
mkdir -p ~/.ssh
chmod 700 ~/.ssh

# 4. SSH 加固
echo ">>> 4/6 SSH 安全加固..."
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup

sudo sed -i "s/^#Port 22/Port $SSH_PORT/" /etc/ssh/sshd_config
sudo sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sudo sed -i 's/^#MaxAuthTries 6/MaxAuthTries 3/' /etc/ssh/sshd_config

sudo sshd -t && sudo systemctl restart sshd
echo "SSH 加固完成"

# 5. 安装 fail2ban
echo ">>> 5/6 安装 fail2ban..."
sudo apt install -y fail2ban
sudo tee /etc/fail2ban/jail.d/sshd.conf << EOF
[sshd]
enabled = true
port = $SSH_PORT
maxretry = 3
bantime = 86400
findtime = 600
EOF
sudo systemctl enable --now fail2ban

# 6. 自动安全更新
echo ">>> 6/6 配置自动更新..."
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades -y

echo ""
echo "========================================"
echo "✅ 安全加固完成!"
echo ""
echo "重要提示:"
echo "  1. SSH 端口已改为 $SSH_PORT"
echo "  2. Root 登录已禁用"
echo "  3. 密码登录已禁用"
echo "  4. 请确保你的公钥已添加到 ~/.ssh/authorized_keys"
echo "  5. 在关闭当前 SSH 前,请新开终端测试连接:"
echo "     ssh -p $SSH_PORT ${USER}@$(curl -s ifconfig.me)"
echo "========================================"

❓ 常见问题

Q: ufw enable 后我会被锁在外面吗? A: \1

Q: SSH 用密码还是密钥更安全? A: 密钥认证远比密码安全。密钥是 4096 位 RSA 或 Ed25519 非对称加密,理论上不可暴力破解。密码可能会被猜测、字典攻击、钓鱼窃取。

Q: fail2ban 封禁是永久的吗? A: 默认是临时封禁(通常是 1 小时)。可以通过 bantime 配置自定义时长。永久封禁不推荐——攻击者的 IP 经常变更,封 IP 列表会无限增长。

Q: 改了 SSH 端口后怎么连接? A: ssh -p 2222 user@host。或者在 ~/.ssh/config 中配置 Port 2222

Q: 为什么还要保留密码登录一段时间? A: \1


📖 小节


📝 作业

  1. 基础题(难度⭐):检查当前 ufw 状态,开放或关闭一个端口,然后在本机生成 Ed25519 SSH 密钥对
  2. 进阶题(难度⭐⭐):配置 SSH 密钥登录到一台测试服务器(或 localhost 测试),然后安装 fail2ban 并检查 SSH jail 的状态
  3. 挑战题(难度⭐⭐⭐):编写一个安全加固脚本,包含上述所有步骤(ufw 配置、SSH 密钥、SSH 加固、fail2ban),要求每步验证成功后才继续下一步,失败时回滚
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏