
1. 写在前面为什么SSH配置值得单独开一篇我最早接触云服务器的时候对SSH的理解就停留在“能用密码登录就行”。结果折腾了半年挨过暴力破解、被挖矿脚本塞满CPU、因为密钥权限不对连不上服务器才意识到SSH这套东西看着简单里面全是细节。尤其是当你的服务器开始面向公网、或者你想远程开发、想自动化部署的时候SSH配置到底是“能用”还是“好用且安全”差别非常大。这篇是“凡人修云传”系列的第七篇我会把SSH从配置到保护完整过一遍。内容包括服务端和客户端的基础配置、密钥登录的完整链路、多场景下的密钥部署Git、GitLab、VSCode远程开发都会涉及、以及面对暴力破解和异常连接时的具体应对方案。文末还会附上我自己排查过的几个高频故障包括“ssh服务器拒绝了密码”、“ubuntu ssh无法连接”、“系统时间导致的认证失败”这类问题。相比网上零散的教程我更想给你一条完整可落地的路径装好系统之后SSH这一步到底该做什么、为什么这么做、遇到问题往哪个方向查。内容偏实操命令部分我尽量给全方便直接照着敲。2. 先把服务端和客户端的“地基”打好2.1 服务端sshd_config的核心参数不管你是Ubuntu、CentOS还是Debian系的系统OpenSSH服务端的核心配置文件基本都在/etc/ssh/sshd_config。改这个文件之前建议先备份养成习惯sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak然后看几个我每次装完系统都会优先确认的参数。先说端口默认22端口是全网扫描器的最爱。我见过有朋友把端口改成22222暴力破解日志肉眼可见地减少。但要注意改端口属于“提升安全性但不绝对安全”的做法更核心的还是要靠下面要讲的密钥认证。修改方式就是去掉注释、改成你想要的端口Port 22222然后是PermitRootLogin这个建议直接设成no。我理解很多刚入门的同学图省事喜欢直接用root登录但这种做法风险真的高。root账号是系统里权限最大的账号一旦被攻破整个服务器等于裸奔。正确姿势是创建一个普通用户给它sudo权限日常操作用普通用户需要管理员权限时就加sudo。还有一个容易忽略的参数是MaxAuthTries默认值是6意思是每次连接最多允许尝试6次认证。我习惯把它调低到3能显著降低密码爆破的成功率。参数在配置文件里长这样MaxAuthTries 3改完配置之后一定要先检查语法再重载服务sudo sshd -t sudo systemctl restart sshdsshd -t这个命令很关键它只检查语法不实际重启。我有一次改配置文件写错了参数直接重启sshd导致服务器断连只能去云控制台VNC救场。有了这步检查能避免大部分人为失误。2.2 客户端配置别小看~/.ssh/config服务端配置完了客户端这边也有讲究。很多人习惯每次连接都敲完整命令ssh root192.168.1.100 -p 22222这样其实没问题但当你要管理的服务器超过三五台记忆负担就会变大。我推荐用~/.ssh/config文件来管理所有连接信息让SSH客户端帮你记住host、端口、用户名、密钥路径、甚至跳板机设置。配置文件的语法非常简单每台服务器一个Host段Host my-server HostName 192.168.1.100 Port 22222 User ubuntu IdentityFile ~/.ssh/id_ed25519配置完成后你只需要输入ssh my-server就能直接连上不用记IP也不用记端口。如果是通过跳板机访问内网机器加一行ProxyJumpHost internal-host HostName 10.0.0.5 User ubuntu ProxyJump my-server这样连上去的时候SSH会自动先连跳板机再通过跳板机转发到目标机器。对于公司里需要通过堡垒机访问内网服务器的场景非常实用。2.3 顺带一提网络设备如华为交换机的SSH配置逻辑热搜词里出现了“华为交换机ssh配置”这说明很多读者不只是管服务器也在管网络设备。交换机和Linux服务器的SSH配置思路其实一脉相承只不过设备厂商的命令风格不同。以华为交换机为例开启SSH服务的基本步骤大致是生成RSA密钥对用于SSH加密协商开启SSH服务配置VTY虚拟终端线路允许SSH协议接入创建本地用户并设置密码、服务类型为SSH命令大致是system-view rsa local-key-pair create ssh server enable user-interface vty 0 4 authentication-mode aaa protocol inbound ssh quit aaa local-user admin password irreversible-cipher YourPassword local-user admin service-type ssh local-user admin privilege level 15 quit需要注意不同版本的华为设备命令会有些差异老版本用rsa local-key-pair create新版本叫法可能略有不同。但核心逻辑不变先把SSH服务开启再配置认证用户的密码和权限。和Linux一样交换机SSH一样要禁掉telnet、限制管理VLAN道理是相通的。3. 密钥登录从“密码开门”升级到“令牌开门”3.1 生成密钥对选对算法和参数SSH安全的核心不是改端口而是把密码认证关掉、使用密钥认证。打个不严谨的比方密码认证像家门钥匙谁捡到谁就能开门密钥认证像手机验证码门禁卡私钥只存在你自己的设备里服务器只认你的公钥私钥本身不会在网络上传输。生成密钥对的命令是ssh-keygen -t ed25519 -C your_emailexample.com这里我强烈建议算法选ed25519而不是传统的rsa。ed25519密钥更短、生成更快、安全性也不逊色而且现代OpenSSH版本都原生支持。如果你需要兼容特别老的系统或设备比如某些老交换机那再退回去用rsa -b 4096。生成过程中会提示你设置私钥口令passphrase。这一步很多人会直接回车跳过但我的建议是本地设备的私钥最好加上口令。这样即使你的笔记本丢了别人拿到私钥文件也还需要再输入一层口令才能用。会觉得每次连SSH都输一遍口令很烦可以用ssh-agent帮你记住后面讲。生成之后~/.ssh/目录下会出现两个文件id_ed25519是私钥千万别外传id_ed25519.pub是公钥可以随便分发。3.2 把公钥部署到服务器ssh-copy-id最省心把公钥部署到服务器上最省心的方式是ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 22222 ubuntu192.168.1.100这个命令会自动把公钥追加到服务器上对应用户的~/.ssh/authorized_keys文件里并设置好权限。它其实是帮你省掉了手工拷贝公钥、创建.ssh目录、设置700/600权限这些琐碎操作。如果你想手动操作那需要确保服务器上chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys这个权限设置非常关键。OpenSSH对authorized_keys文件的权限要求很严格如果文件权限太宽松比如644甚至更高服务端会直接忽略这个文件里的密钥导致你明明把公钥放进去了却还是登不进去。3.3 多机多账号场景下的密钥指纹管理管理多台服务器后会遇到一个新问题每台机器用哪个密钥这时~/.ssh/config的IdentityFile参数就能帮你指定不同主机使用不同的私钥。比如一台是个人服务器一台是公司服务器分开用不同的密钥更安全。还有一个我建议养成的习惯首次连接到一台新服务器时SSH会提示你确认主机指纹。这个指纹相当于服务器的“身份证”用来防止中间人攻击。很多人这里会直接输yes回车这是可以的但最好养成先验证指纹的习惯。在你第一次连接之前通过云控制台的VNC或网页终端先执行ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub拿到服务器的主机指纹后再在本地连接时核对一下是否一致。实测下来虽然多了一步操作但能有效防止连到一个伪造的服务器上。3.4 Git、GitLab场景下的SSH密钥配置服务端密钥登录讲完了但热搜词里还有一大半是关于Git和GitLab配置SSH密钥的。这里也顺带说明一下。其实逻辑和连服务器一样把本地生成的公钥粘贴到GitHub/GitLab后台的“SSH Keys”设置页面里本地通过git clone gitgithub.com:user/repo.git这种SSH协议去拉代码。好处是不用每次提交都输密码而且比HTTPS方式更安全。我见过不少人在GitLab上配置完密钥后提交代码仍然提示要密码。大概率是因为仓库远程地址用的是HTTPS开头而不是SSH协议。检查方法git remote -v如果是https://开头的地址改成SSH格式git remote set-url origin gitgitlab.com:user/repo.git改完之后再git pull试试正常情况下就不需要输密码了。3.5 群晖这类NAS设备上的SSH密钥配置有些读者在群晖上配置SSH密钥做法也类似。群晖开启SSH功能后控制面板-终端机和SNMP-启用SSH在~/.ssh/authorized_keys里放入公钥即可实现免密登录。唯一需要注意的是群晖的home目录结构比较特殊登录用户名对应的home目录可能在/var/services/homes/用户名如果你登录后找不到.ssh目录不要慌创建即可记得权限依然要设置正确。4. 保护SSH让暴力破解和扫描器拿你没辙4.1 安检第一步禁用密码登录、限制可登录用户密钥部署完成并且验证能登录之后下一步才是真正的安全加固。最核心的一步是修改/etc/ssh/sshd_configPasswordAuthentication no PermitRootLogin no这两行的意思是禁止密码认证、禁止root直接SSH登录。做完之后理论上暴力破解ssh的脚本拿你没办法因为你根本没有密码这扇门。公钥认证不是靠猜能猜出来的扫描器跑再多次也只是浪费CPU。如果你管理的服务器有多位使用者还可以限制只有特定用户能通过SSH登录AllowUsers ubuntu deploy这个参数配合密钥认证等于在“门禁卡”之外再加了一道“人员名单”不是名单里的人就算有密钥也进不来。4.2 联动防火墙控制谁能访问你的SSH端口服务端配置只能决定“认证方式”防火墙决定的是“谁能连到SSH端口”。以Ubuntu自带的ufw为例sudo ufw allow from 203.0.113.0/24 to any port 22222 proto tcp sudo ufw enable这条规则的意思是只允许203.0.113.0/24这个网段的IP访问SSH端口其他IP一律拒绝。对于个人服务器如果你的办公网络IP固定这样配置之后服务器的SSH端口基本等于隐形状态。如果IP不固定也可以只允许某个国家的IP段不过这个操作偏进阶我会在后续章节展开。4.3 部署fail2ban让连续猜密码的IP自动进黑名单即便禁用了密码认证服务器仍然会在日志里收到大量来自扫描器的连接尝试。这些请求虽然无法成功认证但仍然会占用连接资源。应对方案是在系统层面做访问控制这里推荐fail2ban。安装和基本配置sudo apt install fail2ban sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local修改/etc/fail2ban/jail.local找到[sshd]这一段启用它[sshd] enabled true port 22222 maxretry 3 bantime 3600含义是同一个IP在短时间内认证失败3次就被封禁1小时。安装完重启服务sudo systemctl restart fail2ban我服务器上开启fail2ban之后auth.log里的失败连接请求肉眼可见地消停了下来。这个工具对网络设备、Linux服务器都适用属于低成本高回报的安全组件。4.4 服务器被大量SSH连接攻击时的应急处理流程有时候还没来得及做安全加固服务器就已经被打爆了。搜热词里有一条“网络攻击 ssh大量连接怎么办”这种场景我遇到过不止一次症状是服务器CPU飙升、负载超高、who命令能列出几十个假用户。紧急处理流程建议按这个顺序走先通过云控制台VNC登录服务器本地SSH可能已经连不上了查看/var/log/auth.log确认攻击模式tail -n 100 /var/log/auth.log临时封禁可疑IPsudo iptables -A INPUT -s 192.0.2.66 -j DROP如果不是单IP攻击而是大量IP分散攻击直接临时禁用密码登录并把SSH端口改掉sudo sed -i s/^PasswordAuthentication yes/PasswordAuthentication no/ /etc/ssh/sshd_config sudo systemctl restart sshd最后再装fail2ban进入常态化防御。注意应急时改配置比手动封IP更高效因为分散的IP是封不完的把密码认证关掉才是釜底抽薪。5. 远程开发场景下的SSH实战5.1 VSCode Remote-SSH链接远程服务器现在很多人的开发工作流已经变成“本地写代码服务器上运行”。VSCode的Remote-SSH插件就是干这个事的。安装完插件后按F1输入Remote-SSH: Connect to Host选择你~/.ssh/config里配置好的主机VSCode就会自动连接并在远程环境里打开工作区。使用过程中有几个坑我提醒一下。第一个是扩展安装慢Remote-SSH连上远程后会在远端自动安装VSCode Server如果服务器带宽小或者国内服务器访问微软源慢这个安装可能会卡住。解决办法是手动下载对应的vscode-server-linux-x64.tar.gz包放到服务器指定目录下解压。还有一种做法是用Remote-SSH: Kill VS Code Server on Host重置远端服务端很多时候就能解决。第二个坑是代码同步。Remote-SSH本质上是让你在远程环境里编码文件直接落在服务器上。本地如果没有做同步你本地看到的只是“远程文件系统”的镜像。所以务必要确认你编辑的文件在哪个环境里。5.2 remote ssh vsix离线安装有些内网环境无法访问插件市场VSCode安装Remote-SSH插件就需要用离线安装方式。去微软官方的VSCode插件市场页面下载.vsix文件然后在VSCode里“从VSIX安装”code --install-extension ms-vscode-remote.remote-ssh.vsix这样就能完全绕过插件市场联网问题。同理如果你在服务器上安装VSCode Server失败也可以手动离线部署保证内网环境一样能用Remote-SSH。5.3 SSH批量登录与自动化脚本管理多台服务器时批量登录、批量执行命令是个高频需求。基于~/.ssh/config的命名规则写个简单的循环脚本就能实现for host in web-server-01 web-server-02 web-server-03; do echo $host ssh $host uptime df -h / | tail -1 done这个脚本会依次连接三台服务器分别输出运行时间和磁盘情况。配合密钥登录整个过程无需输入密码非常适合巡检场景。如果需要更复杂的批量命令分发可以再借助pssh、ansible这类工具但它们的底层依然依赖你在SSH层做好的免密登录。6. 高频故障排查从报错倒推原因6.1 “ssh服务器拒绝了密码”的完整排查链路这个报错我几乎每周都能看到网友求助。其实“服务器拒绝了密码”这个提示原因不一定是密码真的错了。它可能由多种原因导致按频率排序大概是现象可能原因排查方向密码输错键盘布局、大小写锁定/var/log/auth.log查看记录服务端禁止密码认证PasswordAuthentication no检查sshd_config用户不存在或权限不对用户名写错、root被禁用检查PermitRootLogin和AllowUsers公网IP被防火墙拦截服务器防火墙或云安全组看是否能ping通/端口通不通客户端缓存了旧主机密钥~/.ssh/known_hosts冲突删除对应条目重试排查顺序建议从服务器日志入手。在服务器上执行sudo tail -n 50 /var/log/auth.log日志会明确告诉你连接被拒绝的原因是“invalid password”还是“user unknown”还是“Connection closed by authenticating user”。看到日志之前不要瞎猜。6.2 ubuntu ssh无法连接可能不是SSH的问题热搜词里有“ubuntu ssh无法连接”这种问题经常会被误判为SSH配置问题实际上很多时候是云服务器的安全组规则没放行端口。你本地ssh命令一直卡住不动或者提示Connection timed out大概率不是SSH服务本身的问题而是网络层面被拦截了。排查顺序ping 服务器IP # 检查主机是否在线 nc -vz 服务器IP 22222 # 检查端口是否通如果这两个都没问题再去看本地的~/.ssh/config是否写错了端口或IP。如果端口不通去云控制台检查安全组规则确认入方向是否放行了对应端口的TCP流量。6.3 系统时间偏差导致的SSH认证失败还有一个隐蔽问题系统时间不对导致SSH认证失败。这个在“CentOS ssh时间”这个热搜词里也能看出来。SSH的密钥认证和Kerberos认证都对时间敏感如果服务器和客户端的时间差超过一定阈值服务端会认为认证请求已过期直接拒绝。检验方法date如果服务器时间明显不对同步一下时间源sudo timedatectl set-ntp true sudo systemctl restart systemd-timesyncd这里多提醒一句不要只校准一次时间最好确保NTP服务常年开启服务器重启后时间也能自动同步。6.4 特殊地址格式ssh -t gitcnb.cool 这类命令的含义最后解释一个热搜词里出现的情况ssh -t gitcnb.cool。这个命令里的-t参数是强制分配伪终端。它在正常SSH登录时用于交互式会话但用在git这种用户上时实际上是某些Git托管平台用来验证SSH连通性的常见方式。执行后如果服务器返回欢迎语和“successfully authenticated”之类的信息说明你的密钥配置已经生效。如果提示权限不足检查公钥是不是正确粘贴到了平台的SSH keys设置里。7. 我的最终建议SSH配置和保护这件事没有“一劳永逸”的方案只有不断迭代的习惯。我个人经验是每次新装服务器先把密钥登录配好、密码登录关掉、fail2ban装上、防火墙规则收紧这四步做成一个固定的初始化流程。花费的时间不会超过十分钟但能帮你省掉后续无数个半夜被报警短信吵醒的夜晚。再分享一个小细节记得定期检查服务器上的authorized_keys文件把不再使用的公钥清除掉。权限这个东西给的容易收回来难。服务器里的人如果已经离职或者换了电脑旧密钥该删就删不要怕麻烦。毕竟SSH是整个服务器的入口入口守住了里面才能安稳。