frp穿透ssh遇到的一次问题:fail2ban的使用

公网 SSH 连接 Ubuntu 失败?fail2ban 误封 IP 的排查与解决全攻略

文章由 Grok 总结生成。

在云计算和远程开发的时代,SSH(Secure Shell)已成为开发者、运维工程师的标配工具。想象一下,你正通过 Windows 机器连接一台部署在云端的 Ubuntu 服务器,代码部署、日志查看一气呵成——但突然,一台电脑连不上,报“Connection refused”或“Timed out”,而另一台却一切正常。这不是科幻,而是许多人遇到的“典型坑”。本文基于真实案例,总结了这种公网 SSH 连接失败的成因(尤其是 Ubuntu 侧的 fail2ban 误封 IP),从使用场景到排查解决,一步步带你避坑。无论你是新手还是老鸟,都能从中获益。

使用场景:为什么 SSH 是远程工作的“命脉”?

SSH 连接远程服务器是日常运维的基石,尤其在公网环境下:

  • 开发测试:前端/后端开发者用 VS Code 的 Remote-SSH 插件,直接在本地编辑云端代码。
  • 云服务器管理:阿里云、腾讯云或 AWS 的 Ubuntu ECS 实例,用于部署 Docker 容器、监控 Nginx 日志,或运行 Python 脚本。
  • 跨设备协作:团队成员从不同 Windows 笔记本(家用/公司)连接同一服务器,处理数据库备份或 CI/CD 流水线。
  • 典型环境:Windows 10/11 作为客户端(内置 OpenSSH 或 PuTTY),Ubuntu 20.04+ 作为服务器(默认安装 OpenSSH Server),连接端口 22,公网 IP(如 47.100.x.x)。

在这些场景中,SSH 的安全性至关重要——公网暴露意味着随时可能遭暴力破解攻击。这就引出了我们的“主角”:fail2ban,一个 Ubuntu 默认的“守护神”,它监控登录失败,自动封禁可疑 IP。但好心办坏事,它有时会“误伤”合法用户。

遇到问题的情景:一台能连,一台不能的“诡异”故障

问题往往在最不经意时爆发:

  • 症状描述:你从 Windows A 轻松 ssh user@ubuntu-ip 登录,运行 sudo apt update 无压力;但从 Windows B 尝试相同命令,却卡在“Connection timed out”或“ssh: connect to host … port 22: Connection refused”。重启电脑、换 WiFi 都没用,Ubuntu 服务器日志(/var/log/auth.log)中隐约看到“Failed password”记录。
  • 触发情境
    • 公网动态 IP:两台 Windows 的公网 IP 不同(e.g., A 是 114.114.x.x,B 是 120.120.y.y),因为 ISP 动态分配或 VPN 切换。
    • 误操作积累:之前从 B 机输入错密码几次,或服务器被机器人扫描,导致 fail2ban “怒封” B 的 IP(默认禁时 10 分钟,但可累积)。
    • 环境差异:一台在公司网络(静态 IP),一台在家用 4G 热点(动态 IP),看似相同配置,却因来源 IP 被服务器“黑名单”。
  • 心理冲击:初次遇到,很多人怀疑是 Windows 防火墙、OpenSSH 未安装,或云厂商安全组问题。排查一小时后,发现真相是“服务器自卫机制”——fail2ban 已将你的 IP 扔进监狱!

这种“选择性失败”超级 frustrating,因为它不影响服务器本身,只针对特定来源,完美诠释了“公网 SSH 的隐形杀手”。

排查方案:从客户端到服务器,层层剥洋葱

别慌,系统排查能 80% 锁定问题。核心思路:用“能连机”作为基准,对比两台 Windows + 深入 Ubuntu。准备:PowerShell/CMD(Windows)、SSH 终端(Ubuntu)。时间:15-30 分钟。

步骤 1: 客户端对比(排除 Windows 侧 70% 坑)

用表格快速对比两台 Windows(A: 能连,B: 不能):

项目 检查命令/方法 预期(A 机) B 机结果? 如果差异
公网 IP 浏览器访问 whatismyipaddress.com 或 PowerShell: Invoke-RestMethod -Uri "https://api.ipify.org" 114.114.x.x 120.120.y.y? IP 不同 → 跳到服务器侧安全组检查
SSH 客户端 ssh -V OpenSSH_8.1p1 command not found? 安装 OpenSSH(设置 > 可选功能 > 添加)
端口连通 Test-NetConnection -ComputerName ubuntu-ip -Port 22 TcpTestSucceeded: True False? 添加防火墙出站规则:New-NetFirewallRule -Direction Outbound -Protocol TCP -RemotePort 22 -Action Allow
代理/VPN 设置 > 网络 > 代理 关闭 启用? 统一关闭,重启网络适配器
详细日志 ssh -v user@ubuntu-ip 连接成功 卡在 “Connecting to…”? 记录输出,检查 “No route to host”

如果全相同,继续服务器侧。

步骤 2: 服务器侧深挖(用 A 机登录 Ubuntu)

  • 安全组确认:云控制台(e.g., 阿里云 > ECS > 安全组)检查入站规则:TCP 22 是否允许你的 B 机 IP(或 0.0.0.0/0 测试)。
  • SSH 服务状态sudo systemctl status ssh(确保 Active: active);sudo ufw status(22/tcp ALLOW)。
  • 日志扫描sudo tail -n 20 /var/log/auth.log | grep "Failed"(看失败尝试的 IP)。
  • fail2ban 检查(关键一步):sudo fail2ban-client status sshd。输出中“Banned IP list”若含 B 机 IP,即中招!

排查原则:从小(客户端)到大(服务器),用 -v 详细模式记录日志,避免盲目猜。

解决措施:快速解禁 + 根治

一旦确认 fail2ban 封禁,解决超简单——从 A 机登录 Ubuntu 后执行:

核心命令:解禁 IP

1
2
3
4
5
6
7
8
# 检查状态
sudo fail2ban-client status sshd

# 解禁特定 IP(替换为 B 机 IP)
sudo fail2ban-client set sshd unbanip 120.120.y.y

# 验证(Banned IP list 应清空)
sudo fail2ban-client status sshd
  • 效果:立即生效,B 机重试 ssh user@ubuntu-ip 即可登录。默认禁时 10 分钟,若重封,等或调配置。
  • 备选:临时停用 jail:sudo fail2ban-client stop sshd(测试用,重启后恢复)。

根治 + 优化

  • 切换密钥认证:避免密码易错。Windows: ssh-keygen 生成密钥;ssh-copy-id user@ubuntu-ip 复制公钥。Ubuntu: 编辑 /etc/ssh/sshd_config 设置 PasswordAuthentication nosudo systemctl restart ssh
  • 调 fail2ban 配置sudo nano /etc/fail2ban/jail.local,添加:
    1
    2
    3
    4
    [sshd]
    enabled = true
    bantime = 300 # 禁时 5 分钟
    maxretry = 3 # 容忍 3 次失败
    然后 sudo systemctl restart fail2ban
  • 额外防护:改 SSH 端口(/etc/ssh/sshd_config: Port 2222),用 Cloudflare 等 CDN 代理;安装 denyhosts 补充。

测试后,B 机连上——问题解决!

预防建议:别让“守护神”变“绊脚石”

  • 日常习惯:用密钥 + 域名(动态 DNS 如 No-IP)连接,减少 IP 变动。
  • 监控工具:安装 Prometheus + Grafana 监控 fail2ban 日志,邮件告警封禁事件。
  • 最佳实践:公网 SSH 别裸奔——结合 VPN (WireGuard) 或 bastion 跳板机。
  • 学习资源:Ubuntu 官方 SSH 指南、fail2ban GitHub wiki。

结语:调试是运维的“浪漫”

这个 fail2ban 误封案例,表面是小故障,实则考验系统思维:对比、日志、配置。记住,SSH 连接失败 90% 是“可控的”,多练几次,你就能化“诡异”为“家常”。