当前位置: 首页 > news >正文

Ubuntu 22.04 SSH默认关闭原因与安全配置全指南

1. 为什么默认不开启SSH?——从安全设计逻辑讲清Ubuntu的“保守哲学”

刚装好Ubuntu 22.04 LTS,想用另一台电脑ssh连过去,敲完ssh user@192.168.1.100却卡在Connection refused,反复确认IP、用户名、密码都没错,最后发现:系统压根没装OpenSSH服务端。这不是你操作失误,而是Ubuntu官方刻意为之的设计选择。

Ubuntu 22.04 LTS(代号Jammy Jellyfish)延续了Debian系“最小化默认安装”的安全哲学:不启用任何非必要网络服务,哪怕它再常用。SSH虽然对运维和开发者是刚需,但它本质上是一扇直接通向系统内核权限的“数字大门”。一旦配置不当、版本存在漏洞、或密码过于简单,攻击者就能绕过所有图形界面防护,直抵root权限。所以Ubuntu安装程序默认只装openssh-client(让你能ssh出去),而openssh-server必须手动显式安装并启动——这个动作本身就是一个安全确认信号:你清楚自己正在暴露一个高危端口。

我第一次在客户现场部署时就栽在这儿。客户要求“开个SSH方便后续维护”,我习惯性以为已预装,结果远程调试全靠VNC硬扛了三天。后来翻遍Ubuntu Server安装日志才发现,openssh-server包根本不在默认任务列表里,连apt list --installed | grep openssh都查不到。这背后是Canonical团队对“零信任”原则的落地:默认拒绝,显式授权。不是Ubuntu懒,而是它把安全责任前置到了安装后的第一分钟。

这种设计也直接影响了防火墙策略。UFW(Uncomplicated Firewall)作为Ubuntu默认的iptables前端,在openssh-server未安装时,其规则集里压根没有针对22端口的放行条目——因为“不存在的服务不需要被保护”。只有当你真正安装并启用服务后,UFW才需要介入管理访问控制。这就引出了一个关键认知:SSH开启 ≠ 远程可登录。它实际包含三个独立环节:服务进程存在(sshd)、服务处于运行状态(systemctl status ssh)、网络层允许流量抵达(UFW/iptables规则)。三者缺一不可,而绝大多数新手只卡在第一个环节。

更值得深思的是版本差异。Ubuntu 22.04基于Linux 5.15内核,其sshd默认启用了UsePrivilegeSeparation sandboxPermitRootLogin prohibit-password等加固选项,这些在旧版中可能只是注释掉的配置项。这意味着,即使你成功启用了SSH,直接用root密码登录也会失败——系统强制要求密钥认证或普通用户提权。这不是bug,是22.04对现代攻击面的主动收缩。所以当你看到Permission denied (publickey)时,别急着骂配置文件,先确认你是否在用root账户尝试密码登录。

提示:Ubuntu桌面版(GNOME)和服务器版在SSH策略上完全一致。很多用户误以为“桌面版默认开SSH”,其实只是某些第三方ISO(如Ubuntu Studio)或OEM预装版本做了定制,官方标准镜像一律遵循最小化原则。

2. 从零安装到首次连接:分步拆解每个命令背后的意图

现在我们进入实操阶段。整个过程看似只需几条命令,但每一步都有明确的安全意图和依赖关系,跳过任何一环都可能导致后续故障。我会用“命令+原理+验证”三段式说明,确保你不仅知道怎么做,更明白为什么必须这么做。

2.1 安装OpenSSH服务端:为什么必须用sudo apt install openssh-server而非apt-get

sudo apt update && sudo apt install openssh-server -y

这条命令表面是安装软件,实则触发了三重系统级变更:

  1. 包依赖解析openssh-server会自动拉取openssh-client(确保本机也能发起连接)、libssl3(TLS加密基础库)、procps(进程监控工具)等核心依赖。如果你之前手动删过openssh-client,这里会一并恢复,避免因客户端缺失导致ssh-keygen等工具不可用。

  2. 服务单元注册:安装完成后,/lib/systemd/system/ssh.service文件被写入系统。这是systemd管理sshd进程的“身份证”,定义了启动顺序(After=network.target)、重启策略(Restart=on-failure)和环境变量(EnvironmentFile=-/etc/default/ssh)。注意那个-符号——它表示“如果/etc/default/ssh不存在则忽略”,这是Ubuntu为兼容旧配置留的后门。

  3. 初始密钥生成:安装脚本会自动执行/usr/bin/ssh-keygen -A,为RSA、ECDSA、Ed25519三种算法各生成一对主机密钥,存于/etc/ssh/ssh_host_*_key。这些密钥是SSH握手时证明服务器身份的“数字指纹”,绝不能删除或替换为自定义密钥(除非你懂密钥轮换机制),否则客户端会因Host key verification failed报错而拒绝连接。

验证是否成功?别只看apt输出的Setting up openssh-server,执行:

ls -l /etc/ssh/ssh_host_*_key # 应看到4个文件:rsa ecdsa ed25519的私钥+公钥 sudo systemctl is-active ssh # 返回"active"而非"inactive"或"failed"

2.2 启动并设为开机自启:systemctl enable --now ssh的深层含义

sudo systemctl enable --now ssh

--now参数是22.04的关键改进。在旧版Ubuntu中,你需要分两步:systemctl enable ssh(写入开机启动)+systemctl start ssh(立即启动)。而--now将二者原子化,避免了“已设置开机启动但当前未运行”的中间态——这种状态在远程部署时极其危险:你以为服务开着,实际只能本地连。

更隐蔽的细节在于enable操作本身。它会在/etc/systemd/system/multi-user.target.wants/下创建指向/lib/systemd/system/ssh.service的软链接。这个目录名multi-user.target揭示了本质:SSH服务被归类为“多用户模式”的基础设施,意味着它依赖于网络就绪(network.target)、本地文件系统挂载(local-fs.target)等基础服务。如果你在/etc/fstab里配了NFS共享且挂载失败,sshd可能因依赖链中断而无法启动——此时systemctl status ssh会显示Dependency failed,而非简单的inactive

验证启动状态时,务必用:

sudo systemctl status ssh --no-pager -l # --no-pager 避免less分页干扰,-l 显示完整日志

重点关注Active:行后的状态(active (running)),以及Main PID:后的进程号。如果看到Failed to start OpenBSD Secure Shell server,立刻按q退出,然后执行:

sudo journalctl -u ssh --since "1 hour ago" | grep -i "error\|fail\|denied"

这比盲目重启服务高效十倍。

2.3 获取本机IP地址:ip avshostname -I的适用场景

ip a | grep "inet " | grep -v "127.0.0.1" # 或更简洁的 hostname -I

hostname -I返回所有IPv4地址(空格分隔),适合脚本调用;ip a则显示完整网络接口详情,包括子网掩码、广播地址、MTU值。为什么强调“排除127.0.0.1”?因为很多用户复制粘贴时会误选lo回环地址,导致ssh user@127.0.0.1看似成功,实则只是本地登录,完全没测试到网络连通性。

真实案例:某次在VMware虚拟机中,hostname -I返回两个IP:192.168.1.100(NAT模式)和172.16.10.100(仅主机模式)。用户用后者连接宿主机失败,却以为SSH没开——其实是因为仅主机模式下宿主机根本无法路由到该网段。此时必须用ip route show确认默认网关,再用ping测试双向连通性。

2.4 从客户端首次连接:ssh -o ConnectTimeout=5 user@ip的实战价值

在另一台机器执行:

ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no user@192.168.1.100

ConnectTimeout=5将超时从默认的120秒缩短至5秒,避免因网络问题长时间卡住;StrictHostKeyChecking=no跳过首次连接的密钥确认提示(Are you sure you want to continue connecting (yes/no/[fingerprint])?),适合自动化脚本。但请注意:生产环境严禁使用此参数,它会削弱MITM(中间人)攻击防护。

首次连接时,客户端会将服务器公钥存入~/.ssh/known_hosts。如果之后服务器重装系统导致密钥变更,再次连接会报错:

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!

此时需手动清理:

ssh-keygen -R 192.168.1.100 # 或更精准地删除指定行 sed -i '/192.168.1.100/d' ~/.ssh/known_hosts

3. UFW防火墙配置:为什么ufw allow OpenSSHufw allow 22更安全

很多人认为“开放22端口”就是加一条ufw allow 22,但Ubuntu官方文档明确推荐ufw allow OpenSSH。这背后是UFW的“应用配置文件”(application profile)机制,它比端口号映射更智能、更安全。

3.1 UFW应用配置文件的本质:预定义的策略模板

UFW的/etc/ufw/applications.d/目录下存放着.ini格式的应用配置文件。OpenSSH对应/etc/ufw/applications.d/openssh-server,内容如下:

[OpenSSH] title=Secure shell server, an rshd replacement description=OpenSSH is a free implementation of the Secure Shell protocol. ports=22/tcp

关键点在于ports=22/tcp——它明确指定了TCP协议。而ufw allow 22会同时开放TCP和UDP的22端口(尽管SSH协议本身不使用UDP)。攻击者可能利用UDP 22端口进行端口扫描探测或伪造ICMP错误响应,增加攻击面。应用配置文件通过限定协议类型,实现了最小权限原则。

更进一步,UFW还支持多端口绑定。比如你的sshd_config修改了端口为2222,只需创建新配置文件:

echo -e "[CustomSSH]\ntitle=Custom SSH port\nports=2222/tcp" | sudo tee /etc/ufw/applications.d/custom-ssh sudo ufw allow CustomSSH

这样既保持策略清晰,又避免了ufw allow 2222可能误开UDP的风险。

3.2 配置UFW前的必做检查:ufw status verbose的隐藏信息

执行sudo ufw status verbose前,先确认UFW状态:

sudo ufw status numbered # 查看当前规则编号,便于删除 sudo ufw status verbose # 输出含日志级别、默认策略、规则计数器

重点观察Default: deny (incoming), allow (outgoing), disabled (routed)这一行。disabled (routed)表示UFW不处理路由转发流量(即不干预VM或容器网络),这是Ubuntu 22.04的默认行为,符合单机防火墙定位。如果此处显示enabled,说明你可能启用了IP转发,需额外检查/etc/ufw/sysctl.conf

Status: inactive是常见陷阱。很多用户执行ufw allow OpenSSH后仍连不上,却没意识到UFW根本没启用。正确流程是:

sudo ufw enable # 启用防火墙(会提示确认) sudo ufw allow OpenSSH sudo ufw status verbose # 确认状态为active且有OpenSSH规则

ufw enable会自动加载内核模块(nf_tables,nf_nat等),并写入/etc/ufw/ufw.confENABLED=yes。如果/etc/default/ufwIPV6=yes,UFW还会自动添加IPv6规则——这点常被忽略,导致IPv6网络下SSH失效。

3.3 高级场景:限制特定IP段访问(白名单模式)

企业环境中,绝不应让SSH暴露给全网。UFW支持基于源IP的精细控制:

# 只允许公司内网192.168.10.0/24访问 sudo ufw allow from 192.168.10.0/24 to any port 22 proto tcp # 拒绝所有其他IP(需在allow规则后执行) sudo ufw deny 22 # 或更安全的写法:先设默认拒绝,再精确放行 sudo ufw default deny incoming sudo ufw allow from 192.168.10.0/24 to any port 22

注意to any port 22中的any——它表示目标端口为22,不限制目标IP(即本机所有IP)。如果服务器有多个IP(如192.168.1.10010.0.0.100),此规则对两者均生效。若只想限制访问192.168.1.100:22,需写成:

sudo ufw allow from 192.168.10.0/24 to 192.168.1.100 port 22 proto tcp

实测中发现一个坑:当使用ufw allow from x.x.x.x时,UFW会自动生成两条iptables规则——一条ACCEPT,一条LOG(如果启用了日志)。如果规则过多,可能触发iptables链长度限制。此时可用sudo ufw logging off关闭日志,或改用iptables -I INPUT 1 ...手动添加精简规则。

4. 深度排错与加固:从Connection refusedToo many authentication failures的全链路分析

即使严格按前述步骤操作,仍可能遇到各种连接异常。下面我以真实排错日志为线索,还原完整的诊断链条。这些经验来自处理过200+台Ubuntu 22.04服务器的实战总结,每一步都经过反复验证。

4.1Connection refused:三层网络模型的逐层剥离法

ssh user@ip返回Connection refused,这不是SSH配置问题,而是TCP连接根本未建立。按OSI模型自底向上排查:

物理层/数据链路层

  • ping ip是否通?不通则检查网线、Wi-Fi、虚拟交换机配置
  • arp -a | grep ip是否有MAC地址?无则说明ARP请求未响应,可能是防火墙拦截或网关故障

网络层

  • sudo ss -tlnp | grep ':22'查看sshd是否监听22端口
    • 若无输出:sshd未运行或配置了Port非22
    • 若显示127.0.0.1:22:sshd只监听回环,需改/etc/ssh/sshd_configListenAddress0.0.0.0或本机IP
    • 若显示*:22:正常,监听所有接口

传输层

  • sudo ufw status verbose确认UFW状态及规则
  • sudo iptables -L INPUT -n -v直接查看iptables原始规则(UFW底层)
    • Chain INPUTpkts列有增长但sshd无日志:UFW规则被其他规则拦截
    • pkts为0:流量未到达INPUT链,可能是云平台安全组或路由器防火墙阻断

注意:ufw status可能显示active,但iptables -L看不到规则——这说明UFW服务崩溃。此时执行sudo systemctl restart ufw并检查journalctl -u ufw

4.2Permission denied (publickey):密钥认证失败的七种可能

这是22.04最典型的报错。根源在于/etc/ssh/sshd_configPubkeyAuthentication yes虽默认开启,但以下任一条件不满足都会失败:

  1. 客户端密钥未发送ssh -v user@ip查看debug日志,若无Offering public key行,说明客户端未找到私钥。解决:ssh-add ~/.ssh/id_rsa或指定密钥ssh -i ~/.ssh/mykey user@ip

  2. 服务端未授权公钥~/.ssh/authorized_keys权限必须为600,目录权限为700。chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys

  3. SELinux/AppArmor干扰:Ubuntu默认用AppArmor。检查sudo aa-status | grep ssh,若/usr/sbin/sshdenforce模式,执行sudo aa-disable /usr/sbin/sshd临时禁用测试

  4. AuthorizedKeysCommand未配置:若使用LDAP或数据库存储密钥,需配置AuthorizedKeysCommand路径及权限

  5. Chroot环境限制Match User xxx块中若设ChrootDirectory,则authorized_keys必须放在chroot路径内(如/var/chroot/user/.ssh/authorized_keys

  6. PAM模块拒绝/etc/pam.d/sshd中若含auth [default=ignore] pam_succeed_if.so user ingroup nopasswdlogin,需确保用户在nopasswdlogin

  7. sshd_config语法错误sudo sshd -t验证配置文件语法,sudo systemctl reload ssh重载(非restart)

4.3Too many authentication failures:暴力破解防护的双刃剑

当连续输错密码3次,sshd会断开连接并报此错。这是MaxAuthTries 3(默认值)的防护机制。但有时合法用户也会触发,原因有二:

  • 客户端发送了过多密钥ssh -v日志中可见Trying private key多次。解决:在~/.ssh/config中为该主机指定密钥:

    Host myserver HostName 192.168.1.100 User ubuntu IdentityFile ~/.ssh/id_rsa_prod
  • PAM faillock模块启用:Ubuntu 22.04默认启用pam_faillock.so。查看/etc/pam.d/common-auth是否有:
    auth [default=bad success=ok user_unknown=ignore] pam_faillock.so preauth silent deny=3 unlock_time=600
    此时需等待10分钟或手动解锁:sudo faillock --user ubuntu --reset

4.4 日志分析黄金组合:journalctl+grep的精准定位

不要盲目翻/var/log/auth.log,用以下命令直击要害:

# 查看最近10分钟所有SSH相关事件 sudo journalctl -u ssh --since "10 minutes ago" | grep -E "(Accepted|Failed|Connection|Disconnect)" # 筛选特定IP的失败记录(替换xxx.xxx.xxx.xxx) sudo journalctl -u ssh | grep "xxx\.xxx\.xxx\.xxx" | grep "Failed password" # 统计各IP失败次数(防暴力破解) sudo journalctl -u ssh | grep "Failed password" | awk '{print $11}' | sort | uniq -c | sort -nr | head -10

journalctl比传统日志更可靠,因为它不依赖rsyslog服务状态,且能关联systemd单元。$11是日志中IP字段的位置(不同版本可能变化),用sudo journalctl -u ssh | head -5可确认实际位置。

5. 生产环境加固实践:从“能连上”到“安全可靠”的五步跃迁

完成基础配置只是起点。在真实业务场景中,还需叠加多层防护。以下是我在金融、政务类项目中验证过的加固方案,每一步都附带实施成本与收益评估。

5.1 修改默认端口:性价比最高的第一道防线

sudo nano /etc/ssh/sshd_config # 修改 Port 22 为 Port 2222(或其他1024-65535间未占用端口) sudo systemctl restart ssh sudo ufw allow 2222/tcp sudo ufw delete allow OpenSSH # 删除旧规则

收益:过滤90%以上的自动化扫描(Shodan、Zoomeye等工具默认只扫22端口)
成本:客户端需指定端口ssh -p 2222 user@ip,或配置~/.ssh/config
风险:若忘记更新UFW规则,会导致连接中断。建议用sudo ufw status numbered确认规则编号后删除

5.2 禁用密码登录,强制密钥认证

sudo nano /etc/ssh/sshd_config # 设置 PermitRootLogin no # 设置 PasswordAuthentication no # 设置 PubkeyAuthentication yes sudo systemctl restart ssh

收益:彻底杜绝暴力破解,密钥强度远超人类记忆的密码
成本:需提前分发公钥到所有管理员机器,ssh-copy-id -i ~/.ssh/id_rsa.pub user@ip
风险:若私钥丢失且无备用密钥,将永久锁死。必须配置至少2个管理员账户的密钥,并将私钥离线备份

5.3 限制登录用户与组:最小权限原则落地

# 只允许admin组用户登录 echo "AllowGroups admin" | sudo tee -a /etc/ssh/sshd_config # 或只允许特定用户 echo "AllowUsers deploy@192.168.1.* ubuntu@10.0.0.*" | sudo tee -a /etc/ssh/sshd_config sudo systemctl restart ssh

AllowUsers支持user@host语法,可精确到IP段。deploy@192.168.1.*表示deploy用户只能从192.168.1网段登录,极大缩小攻击面。

5.4 启用Fail2ban:自动封禁恶意IP

sudo apt install fail2ban -y sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local sudo nano /etc/fail2ban/jail.local # 修改 [sshd] 段: # enabled = true # maxretry = 3 # bantime = 1h sudo systemctl enable fail2ban && sudo systemctl start fail2ban

Fail2ban通过分析/var/log/auth.log,自动将多次失败的IP加入iptables黑名单。bantime = 1h比默认的10分钟更有效,因为自动化扫描通常在1小时内重试。

5.5 配置SSH会话超时:防止闲置连接泄露

sudo nano /etc/ssh/sshd_config # ClientAliveInterval 300 # 服务器每5分钟发心跳 # ClientAliveCountMax 2 # 连续2次心跳无响应则断开 # LoginGraceTime 30 # 登录超时30秒(防暴力破解) sudo systemctl restart ssh

ClientAliveInterval配合ClientAliveCountMax,可确保网络中断时连接及时释放,避免ss -tnp | grep :22中堆积大量ESTABLISHED僵尸连接。

最后分享一个血泪教训:某次在Kubernetes节点上加固SSH,我执行了sudo ufw enable后忘记检查UFW默认策略,结果ufw default deny incoming导致kubelet无法与API Server通信,整个集群失联。从此我养成了固定习惯:任何防火墙变更后,必执行sudo ufw status verbose并确认Default: deny (incoming)旁标注# OK for SSH only。安全加固不是一劳永逸,而是持续校验的过程。

http://www.jsqmd.com/news/888212/

相关文章:

  • Tableau环形图设计原理与实战:从视觉编码到业务决策
  • Excel求和的5种方式:从快捷键到动态数组的实战选择指南
  • NGUI锚点原理与计算公式详解:从漂移问题到精准布局
  • Hyper-V第一代和第二代虚拟机怎么选?迁移CentOS避坑指南(附SCSI启动和Secure Boot设置)
  • 从感官实验到正念实践:如何通过系统化觉察重塑你的清晨体验
  • taoCMS文件上传漏洞CVE-2022-23880深度解析与七层加固
  • 嵌入式实时紧急车辆警笛检测系统设计与优化
  • 保姆级教程:用Davinci配置RH850(F1KM)的PWM,从原理图到波形输出(附避坑点)
  • 2026年热门的管道防冻电伴热带/MI铠装电伴热带/防爆电伴热带/电伴热带厂家选择推荐 - 品牌宣传支持者
  • Seedance 2.0全栈AI舞蹈生成:C++17引擎+HDRP实时渲染工作流
  • MicroBlaze软核在DDR3里跑,你的sleep函数为啥‘睡过头’了?Vitis 2020.1实测避坑
  • UE5 BaseEditorSettings.ini 源码级配置解析与生产避坑指南
  • 构建AI代码审查自动化管道:从原理到工程实践
  • Unity Tilemap高性能优化:多线程加速与区块快照机制
  • Win10家庭版别再乱搜了!手把手教你正确启用gpedit.msc组策略(附路径避坑)
  • GitHub Actions 自定义 Runner 镜像实战:把初始化环境提前做好
  • 音频运放与电阻测试平台:标准化设计与实测指南
  • 2026年知名的冷库板/冷库工程/冷库安装/冷库维修优质厂家汇总推荐 - 行业平台推荐
  • 创建了安卓模拟器却运行不了,改GVM为aehd成功了
  • 2026年质量好的济南生物质壁炉/嵌入壁炉/燃木壁炉/颗粒取暖壁炉厂家综合对比分析 - 品牌宣传支持者
  • A/B测试与Split平台:数据驱动决策的实践指南
  • 七天掌握全栈开发:Next.js + TypeScript + tRPC 实战学习系统
  • 嵌入式通信连接器(ECC)设计:统一接口规范与旋转连接技术
  • 手把手教你用Python解析GY-95T IMU原始数据包:从十六进制流到ROS2 sensor_msgs/Imu消息
  • IDEA Diagrams保姆级教程:5分钟看懂Java类图,还能一键定位源码
  • 构建分布式Saga智能体:从状态机到可观测性的工程实践
  • 5分钟配置GitHub汉化插件:让英文界面秒变中文的实战应用指南
  • Docker 部署 MongoDB 的可重现性实践与生产就绪指南
  • 2026年比较好的别墅电梯/曳引别墅电梯/无障碍别墅电梯推荐厂家精选 - 品牌宣传支持者
  • 60项核心功能深度解析:HsMod如何彻底改变炉石传说游戏体验