<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Kikun</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://blog.kkkkikun.dpdns.org/</id>
  <link href="https://blog.kkkkikun.dpdns.org/" rel="alternate"/>
  <link href="https://blog.kkkkikun.dpdns.org/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Kikun</rights>
  <subtitle>记录生活与技术</subtitle>
  <title>Kikunの博客</title>
  <updated>2026-10-24T08:57:25.213Z</updated>
  <entry>
    <author>
      <name>Kikun</name>
    </author>
    <category term="技术" scheme="https://blog.kkkkikun.dpdns.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <category term="博客搭建" scheme="https://blog.kkkkikun.dpdns.org/tags/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/"/>
    <category term="Cloudflare" scheme="https://blog.kkkkikun.dpdns.org/tags/Cloudflare/"/>
    <content>
      <![CDATA[<p>不少人对「自己搭博客」的印象停留在两选一：</p><ul><li>要么上 WordPress &#x2F; Typecho 这种动态博客 —— 得租一台服务器，年年掏钱，还要操心备份和安全；</li><li>要么用 Hexo &#x2F; Hugo 这种静态博客 —— 托管免费，但只能本地写 Markdown、敲命令发布，换台电脑就抓瞎，写作体验像在做运维。</li></ul><p>我最后的方案是：<strong>用静态站的成本，做出「动态站」的体验</strong>。</p><ul><li>打开网页登录后台，在 Notion 风格的编辑器里写文章，截图直接粘贴上传；</li><li>点一下「发布」，一分钟后文章就在线上出现；</li><li>图床、评论、搜索、RSS 全都有；</li><li><strong>全程 0 元</strong>——没有服务器，没有付费订阅。</li></ul><p>这篇文章把我这套东西从零到一怎么搭起来的讲清楚，希望你能照着复刻一个。</p><hr><h2 id="一、总体架构"><a href="#一、总体架构" class="headerlink" title="一、总体架构"></a>一、总体架构</h2><p>先上全景图，后面每一步都是在填这张图的一块：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">             ┌────────────────────────────────────────────┐</span><br><span class="line">             │              Cloudflare Pages              │</span><br><span class="line">git push ──▶│  hexo generate → 静态文件 → 全球 CDN 边缘节点   │──▶ 访客</span><br><span class="line">             │                                            │</span><br><span class="line">             │  Pages Functions（免费送的后端）:              │</span><br><span class="line">             │   /admin   在线后台（密码登录）                │</span><br><span class="line">             │   /api/*   发布文章 / 上传图片 / 管理图床        │</span><br><span class="line">             └───────┬──────────────────────┬─────────────┘</span><br><span class="line">                     │ GitHub API 写文件      │ 图片存取</span><br><span class="line">                     ▼                      ▼</span><br><span class="line">             ┌────────────────┐      ┌──────────────┐</span><br><span class="line">             │ GitHub 私有仓库  │      │ Cloudflare R2 │──▶ blogimg.xx 域名</span><br><span class="line">             │ (源码 = 唯一事实) │      │  (图床, 10GB)  │    返回图片外链</span><br><span class="line">             └────────────────┘      └──────────────┘</span><br></pre></td></tr></table></figure><p>核心思路就三句话：</p><ol><li><strong>Hexo 负责把 Markdown 变成静态 HTML</strong>，本地不需要常驻任何东西；</li><li><strong>GitHub 私有仓库存放源码</strong>，它是唯一事实来源——后台发布文章，本质上也是往这个仓库写文件；</li><li><strong>Cloudflare 免费托管 + 免费后端</strong>：Pages 负责静态文件和自动构建，Pages Functions 提供动态接口，R2 当图床。</li></ol><h2 id="二、成本清单：到底花了多少钱"><a href="#二、成本清单：到底花了多少钱" class="headerlink" title="二、成本清单：到底花了多少钱"></a>二、成本清单：到底花了多少钱</h2><table><thead><tr><th>组件</th><th>用的什么</th><th>花费</th></tr></thead><tbody><tr><td>静态站点生成器</td><td>Hexo + Butterfly 主题</td><td>¥0（开源）</td></tr><tr><td>代码托管</td><td>GitHub 私有仓库</td><td>¥0（Free 套餐够用）</td></tr><tr><td>托管 + CDN + HTTPS</td><td>Cloudflare Pages</td><td>¥0（免费档）</td></tr><tr><td>动态后端</td><td>Cloudflare Pages Functions</td><td>¥0（免费档，每天 10 万次请求）</td></tr><tr><td>图床</td><td>Cloudflare R2</td><td>¥0（免费 10 GB，流量不收费）</td></tr><tr><td>域名</td><td>dpdns.org 免费二级域名</td><td>¥0</td></tr><tr><td>评论系统</td><td>giscus（GitHub Discussions）</td><td>¥0</td></tr></tbody></table><p>唯一可能产生的花费：你想要一个自己买的域名（一年几十块）。我用的 <code>dpdns.org</code> 免费域名，暂时一分钱没花。</p><blockquote><p>免费额度都是「对个人博客严重过剩」级别：Pages 每月 500 次构建、R2 存 10 GB 图片、Functions 每天 10 万次请求。具体数字以 Cloudflare 官网为准，但对你我这种量级的博客，放心用。</p></blockquote><hr><h2 id="三、第一步：本地把-Hexo-站跑起来"><a href="#三、第一步：本地把-Hexo-站跑起来" class="headerlink" title="三、第一步：本地把 Hexo 站跑起来"></a>三、第一步：本地把 Hexo 站跑起来</h2><p>这步网上教程最多，我只说三个容易踩的点。</p><p><strong>1. 主题用 submodule 管理，永远别直接改主题文件。</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git submodule add https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly</span><br></pre></td></tr></table></figure><p>Butterfly 的所有定制都写在站点根目录的 <code>_config.butterfly.yml</code> 覆盖文件里。这样以后主题升级只是更新一下 submodule 指针，你的定制一行都不会丢。我后来把主题 fork 了一份做深度二开，也只是把 submodule 指向自己的 fork，原则不变。</p><p><strong>2. 配色之类的 Stylus 配置改完要 <code>hexo clean</code>。</strong></p><p>这类配置会被编译缓存进 <code>db.json</code>，不 clean 你会遇到「配置明明改了颜色就是不变」，怀疑人生的经典来源。</p><p><strong>3. <code>_posts</code> 里的文件名就是永久链接的一部分。</strong></p><p>本站永久链接格式是 <code>:year/:month/:day/:title/</code>，文件名里的中文会直接出现在 URL 里。介意外文中文 URL 的话，可以用 hexo-permalink-slug 之类的插件，或者文件名用英文、标题写中文。</p><h2 id="四、第二步：推上-GitHub，让-Cloudflare-帮你构建"><a href="#四、第二步：推上-GitHub，让-Cloudflare-帮你构建" class="headerlink" title="四、第二步：推上 GitHub，让 Cloudflare 帮你构建"></a>四、第二步：推上 GitHub，让 Cloudflare 帮你构建</h2><ol><li>在 GitHub 建一个<strong>私有</strong>仓库，把整个 Hexo 站推上去。私有仓 + 免费额度完全够，草稿和没公开的折腾不怕被人看到。</li><li>到 Cloudflare 控制台 → Workers &amp; Pages → 创建 Pages 项目 → 连接这个 GitHub 仓库。</li><li>构建配置只需要两行：</li></ol><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">构建命令:  npm run build        # 即 hexo generate</span><br><span class="line">输出目录:  public</span><br></pre></td></tr></table></figure><p>之后每次 <code>git push</code>，Cloudflare 自动拉代码、装依赖、构建、发布到全球 CDN，全程一分钟以内。HTTPS 证书自动配好，什么都不用管。</p><p><strong>域名</strong>：Pages 项目默认送一个 <code>*.pages.dev</code> 域名，嫌长的话可以在 Cloudflare 里绑自定义域。我是用 DigitalPlat 的免费域名服务（dpdns.org）申请的二级域名，解析托管在 Cloudflare，也是免费。</p><p>到这一步，你已经拥有一个免费、全球加速、自动部署的静态博客了。接下来的部分才是「别人不知道」的。</p><h2 id="五、第三步：图床——Cloudflare-R2"><a href="#五、第三步：图床——Cloudflare-R2" class="headerlink" title="五、第三步：图床——Cloudflare R2"></a>五、第三步：图床——Cloudflare R2</h2><p><strong>为什么需要图床？</strong> 文章里的截图如果直接放仓库里，仓库会越来越肥，构建越来越慢，而且 Markdown 里的相对路径离开本地就失效。正确姿势是图片放对象存储，Markdown 里只写外链。</p><p>市面上免费图床不少（imgbb、sm.ms……），但普遍的问题是：域名不可控（哪天挂了或换域名，全站图片跟着遭殃）、额度小、不知道哪天就政策收缩。所以我选了 <strong>Cloudflare R2</strong>：</p><ul><li>免费 10 GB 存储，<strong>流出流量免费</strong>（这点是 R2 最大的杀手锏，别的云对象存储流量费是大头）；</li><li>可以绑自己的域名，图片链接永远在自己的域名下，可控；</li><li>和 Pages 同在 Cloudflare，后台接口直接用 <code>env.IMAGES_BUCKET</code> 访问，不用签什么临时凭证。</li></ul><p>R2 开通后：创建一个桶 → 在设置里绑定一个自定义域（比如我的 <code>blogimg.kkkkikun.dpdns.org</code>）→ 桶里的对象就能通过这个域名直接访问了。</p><p>我的上传接口做的事很简单：收图片 → 校验类型 → 按 <code>images/年/月/时间戳-文件名</code> 存进桶 → 返回外链。有两个细节值得抄：</p><ul><li><strong>只收 png&#x2F;jpeg&#x2F;gif&#x2F;webp，拒绝 SVG</strong>。SVG 能内嵌脚本，允许上传等于在图床域名上开了一个存储型 XSS 的口子，而图床域和主站同属一个大站范围，不能不防；</li><li><strong>按年&#x2F;月分目录</strong>，后台提供图片列表和删除，清理过期截图不用进控制台。</li></ul><p>写作体验上是：后台编辑器里 <code>Ctrl+V</code> 粘贴截图 → 自动传 R2 → 编辑器里插入外链。发图文文章从此不需要「先开图床网站 → 上传 → 复制链接 → 粘贴」四连。</p><h2 id="六、第四步：在线发布后台（本文最有意思的部分）"><a href="#六、第四步：在线发布后台（本文最有意思的部分）" class="headerlink" title="六、第四步：在线发布后台（本文最有意思的部分）"></a>六、第四步：在线发布后台（本文最有意思的部分）</h2><p>很多人以为静态博客注定「只能本地发布」。其实 Cloudflare Pages 自带一个容易被忽略的能力：<strong>Pages Functions</strong>——在仓库里放一个 <code>functions/</code> 目录，它就是一个跑在 Cloudflare 边缘的 serverless 后端，免费额度每天 10 万次请求，对个人后台绰绰有余。</p><p>于是静态站就有了后端。我的后台是这么工作的：</p><p><strong>1. 登录与鉴权。</strong></p><p>后台就一个口令，存在 Cloudflare Pages 的环境变量里（不进代码仓库）。登录成功后发一个 SHA-256 派生的会话 cookie，有效期 7 天；<code>/api/*</code> 用一个中间件统一校验，所有接口不用各自写鉴权。口令未配置时所有接口直接锁死——安全默认，防止裸奔。</p><p><strong>2. 发布文章的本质：往 GitHub 仓库写一个文件。</strong></p><p>这是整套设计里我最得意的一招。后台点「发布」，Function 做的事是：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">组装 front matter（title/date/tags/categories/cover/description）</span><br><span class="line">        ↓</span><br><span class="line">调 GitHub Contents API，把 Markdown 写入 source/_posts/</span><br><span class="line">        ↓</span><br><span class="line">触发 Pages 的 Deploy Hook（一个 webhook）</span><br><span class="line">        ↓</span><br><span class="line">Cloudflare 自动重新构建，约一分钟后文章上线</span><br></pre></td></tr></table></figure><p>也就是说<strong>后台不需要任何数据库</strong>——GitHub 仓库就是数据库，git 历史就是文章的修改记录，永远可回滚。文章的增删改查全部是对同一个 GitHub API 的封装，我还做了草稿目录（<code>_drafts/</code>）：写一半的文章存草稿，不触发发布，哪天写完一键转正。</p><p>这里有个我真实踩过的坑：<strong>生成文章日期别用 <code>toISOString()</code></strong>。它是 UTC 时间，早上八点前发文，日期会被算成前一天，permalink 直接错位。要用 <code>toLocaleString</code> 转成上海时区再格式化。</p><p><strong>3. 编辑器。</strong></p><p>后台编辑器用的是 <a href="https://milkdown.dev/">Milkdown Crepe</a>，Notion 风格的所见即所得 Markdown 编辑器，用 esbuild 打包成自包含的单文件产物随仓库提交，部署时不需要额外构建步骤。粘贴图片自动走上面的 R2 上传接口。</p><p>到这一步，写作体验已经和掘金&#x2F;知乎这类在线平台没差别了：打开网页 → 登录 → 写 → 发布。但它发出来的是<strong>你自己域名下的、纯静态的、没有广告和你完全掌控数据的</strong>文章。</p><h2 id="七、第五步：评论、搜索、RSS-这些「动态功能」"><a href="#七、第五步：评论、搜索、RSS-这些「动态功能」" class="headerlink" title="七、第五步：评论、搜索、RSS 这些「动态功能」"></a>七、第五步：评论、搜索、RSS 这些「动态功能」</h2><p>剩下的动态能力，全都有成熟的免费方案：</p><ul><li><strong>评论：giscus。</strong> 借 GitHub Discussions 当评论存储，访客用 GitHub 账号登录即可评论，零服务器、零成本，数据还归你自己（我单独建了个公开仓库存评论，和源码仓解耦）。国内访客加载可能略慢，开 lazyload 后不影响首屏。</li><li><strong>站内搜索：hexo-generator-searchdb。</strong> 构建时生成一个索引 JSON，前端纯静态查询，不需要任何搜索服务。</li><li><strong>RSS：hexo-generator-feed</strong>；<strong>sitemap：hexo-generator-sitemap</strong>。都是装上就完事的插件，分别喂给 RSS 阅读器和搜索引擎。</li></ul><h2 id="八、这套东西的边界（诚实说）"><a href="#八、这套东西的边界（诚实说）" class="headerlink" title="八、这套东西的边界（诚实说）"></a>八、这套东西的边界（诚实说）</h2><p>免费方案不是没有代价，有几个点你要心里有数：</p><ol><li><strong>免费额度是「条款」不是「合同</strong>」。Cloudflare 免费档对个人博客完全够用，但如果哪天某篇文章爆了，构建次数、请求量都要留个心眼；</li><li><strong>后台是给「自己」用的，不是给「很多人」用的</strong>。它没有多用户、没有审批流，防的是陌生人和脚本，不是恶意 insider；</li><li><strong>域名是软肋</strong>。免费域名理论上有政策风险，重要内容记得定期 <code>git pull</code> 留本地备份——反正源码在 git 里，重建整个博客也就十分钟。</li></ol><h2 id="九、总结"><a href="#九、总结" class="headerlink" title="九、总结"></a>九、总结</h2><table><thead><tr><th>你以为需要</th><th>实际需要</th></tr></thead><tbody><tr><td>一台服务器</td><td>不需要</td></tr><tr><td>数据库</td><td>不需要</td></tr><tr><td>图床会员</td><td>不需要</td></tr><tr><td>每年几百块</td><td>0 元</td></tr><tr><td>本地写稿 + 命令行发布</td><td>打开网页，写完点发布</td></tr></tbody></table><p>整套东西的技术关键词就是：<strong>Hexo + GitHub 私有仓库 + Cloudflare Pages &#x2F; Functions &#x2F; R2 + giscus</strong>。没有什么高深的东西，更多是「知道这些免费件可以这么拼起来」——希望这篇能帮你把拼图凑齐。</p><p>如果你照着搭的过程中卡在哪一步，或者想看我某个环节的具体实现，欢迎在评论区（GitHub Discussions）留言交流。</p>]]>
    </content>
    <id>https://blog.kkkkikun.dpdns.org/2026/10/24/2026-10-24-%E4%B8%8D%E8%8A%B1%E4%B8%80%E5%88%86%E9%92%B1-%E6%88%91%E6%8A%8A%E9%9D%99%E6%80%81%E5%8D%9A%E5%AE%A2%E6%90%AD%E6%88%90%E4%BA%86%E5%B8%A6%E5%9C%A8%E7%BA%BF%E5%90%8E%E5%8F%B0%E7%9A%84%E5%8A%A8%E6%80%81%E7%AB%99/</id>
    <link href="https://blog.kkkkikun.dpdns.org/2026/10/24/2026-10-24-%E4%B8%8D%E8%8A%B1%E4%B8%80%E5%88%86%E9%92%B1-%E6%88%91%E6%8A%8A%E9%9D%99%E6%80%81%E5%8D%9A%E5%AE%A2%E6%90%AD%E6%88%90%E4%BA%86%E5%B8%A6%E5%9C%A8%E7%BA%BF%E5%90%8E%E5%8F%B0%E7%9A%84%E5%8A%A8%E6%80%81%E7%AB%99/"/>
    <published>2026-10-24T07:47:37.000Z</published>
    <summary>Hexo 写内容，Cloudflare Pages 免费托管，R2 当图床，Pages Functions 白嫖一个带登录的在线发布后台——从写作到上线全程 0 元，这篇文章把整条链路讲清楚。</summary>
    <title>不花一分钱，我把静态博客搭成了带在线后台的「动态站」</title>
    <updated>2026-10-24T08:57:25.213Z</updated>
  </entry>
  <entry>
    <author>
      <name>Kikun</name>
    </author>
    <category term="技术" scheme="https://blog.kkkkikun.dpdns.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <category term="问题排查" scheme="https://blog.kkkkikun.dpdns.org/tags/%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5/"/>
    <content>
      <![CDATA[<p>最近遇到了一次很典型的 SSH 网络故障：</p><p>同一台公网服务器，在手机热点下可以正常 SSH，但在校园网环境下，无论怎么尝试都连不上。</p><p>最开始看到的现象非常容易让人误判：</p><ul><li><code>ping</code> 正常，延迟约 25 ms；</li><li><code>ssh -v</code> 卡在 <code>Connecting to ... port 22</code>；</li><li><code>nc</code> 探测 22 端口同样没有立即返回结果；</li><li>服务器上的 <code>sshd</code> 正常运行；</li><li>UFW、iptables、云安全组都确认放行；</li><li>换成手机热点后，SSH 立即恢复正常。</li></ul><p>最终定位到：<strong>问题不在服务器，而是在校园网出口侧对 TCP 22 连接进行了过滤。</strong></p><p>这篇文章记录整个排查过程，也整理一下几个容易混淆的网络诊断点。</p><hr><h2 id="一、故障现象"><a href="#一、故障现象" class="headerlink" title="一、故障现象"></a>一、故障现象</h2><p>目标服务器：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">103.36.221.122</span><br></pre></td></tr></table></figure><p>在校园网环境下执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh -v -p 22 user@103.36.221.122</span><br></pre></td></tr></table></figure><p>日志停在：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">debug1: Connecting to 103.36.221.122 [103.36.221.122] port 22.</span><br></pre></td></tr></table></figure><p>之后没有任何进一步输出。</p><p>与此同时：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ping 103.36.221.122</span><br></pre></td></tr></table></figure><p>完全正常：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">64 bytes from 103.36.221.122: icmp_seq=1 ttl=52 time=27.9 ms</span><br><span class="line">64 bytes from 103.36.221.122: icmp_seq=2 ttl=52 time=26.2 ms</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">27 packets transmitted, 27 received, 0% packet loss</span><br><span class="line">rtt min/avg/max/mdev = 24.670/27.461/37.792/3.666 ms</span><br></pre></td></tr></table></figure><p>看起来网络没有问题。</p><p>于是很容易产生一个疑问：</p><blockquote><p>既然服务器能 ping 通，为什么 SSH 反而连不上？</p></blockquote><p>关键就在这里：<strong><code>ping</code> 和 SSH 根本不是同一种网络测试。</strong></p><p><code>ping</code> 使用的是 ICMP，而 SSH 建立在 TCP 之上。</p><p>所以：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ICMP 正常 ≠ TCP 正常</span><br></pre></td></tr></table></figure><p>更不能进一步推出：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ping 正常 ≠ SSH 端口一定可达</span><br></pre></td></tr></table></figure><hr><h1 id="二、第一步：确认-IP-层连通性"><a href="#二、第一步：确认-IP-层连通性" class="headerlink" title="二、第一步：确认 IP 层连通性"></a>二、第一步：确认 IP 层连通性</h1><p>先测试最基础的 IP 层：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ping 103.36.221.122</span><br></pre></td></tr></table></figure><p>结果正常，说明至少可以确认：</p><ol><li>目标主机能够对 ICMP Echo Request 做出响应；</li><li>基本 IP 路由是可达的；</li><li>当前链路不存在明显的整体断网问题。</li></ol><p>但这里能得到的结论其实非常有限。</p><p>它只能说明：</p><blockquote><p><strong>ICMP 这条路径是通的。</strong></p></blockquote><p>至于 TCP 22 是否能够建立连接，还需要单独测试。</p><hr><h1 id="三、第二步：直接测试-TCP-22"><a href="#三、第二步：直接测试-TCP-22" class="headerlink" title="三、第二步：直接测试 TCP 22"></a>三、第二步：直接测试 TCP 22</h1><p>使用 <code>nc</code>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc -zv 103.36.221.122 22</span><br></pre></td></tr></table></figure><p>结果没有立即返回：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"># 一直等待</span><br></pre></td></tr></table></figure><p>这个现象比 <code>ping</code> 更有价值，因为现在测试的已经是目标 TCP 端口。</p><p>通常可以把 TCP 连接失败粗略分成几种典型情况：</p><table><thead><tr><th>现象</th><th>常见含义</th></tr></thead><tbody><tr><td><code>succeeded</code>&#x2F;<code>open</code></td><td>TCP 三次握手成功，目标端口可以建立连接</td></tr><tr><td><code>Connection refused</code></td><td>收到了 RST，目标端口没有对应服务监听，或被主机主动拒绝</td></tr><tr><td>长时间等待后超时</td><td>在规定时间内没有得到有效响应，常见原因包括中间设备丢包、过滤或路径问题</td></tr></tbody></table><p>这里最值得注意的是第三种。</p><p><strong>“一直卡住”本身就是一个诊断信号。</strong></p><p>它至少说明：</p><blockquote><p>TCP 连接请求没有在预期时间内完成。</p></blockquote><p>一种非常常见的情况，就是防火墙直接丢弃了 SYN 包，因此客户端只能不断等待，直到 TCP 超时。</p><p>但要注意，严格来说：</p><blockquote><p><strong>仅凭客户端卡住，不能百分之百断定就是某一台设备执行了 DROP。</strong></p></blockquote><p>也可能存在其他路径异常，因此接下来还需要继续排除服务器侧。</p><hr><h1 id="四、第三步：检查服务器上的-SSH-服务"><a href="#四、第三步：检查服务器上的-SSH-服务" class="headerlink" title="四、第三步：检查服务器上的 SSH 服务"></a>四、第三步：检查服务器上的 SSH 服务</h1><p>这一步的目的很简单：</p><blockquote><p><strong>先证明服务器自己真的在正常提供 SSH。</strong></p></blockquote><p>通过服务器控制台、VNC、串口或者云厂商网页终端登录服务器。</p><h2 id="1-检查-sshd-是否监听-22"><a href="#1-检查-sshd-是否监听-22" class="headerlink" title="1. 检查 sshd 是否监听 22"></a>1. 检查 sshd 是否监听 22</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ss -tlnp | grep ssh</span><br></pre></td></tr></table></figure><p>输出：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:((&quot;sshd&quot;,pid=22310,fd=3))</span><br><span class="line">LISTEN 0 128 [::]:22 [::]:* users:((&quot;sshd&quot;,pid=22310,fd=4))</span><br></pre></td></tr></table></figure><p>这里可以看到：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">0.0.0.0:22</span><br><span class="line">[::]:22</span><br></pre></td></tr></table></figure><p>说明 SSH 服务不仅监听在 <code>127.0.0.1</code>，而是监听在 IPv4 &#x2F; IPv6 的非回环地址上，可以接受外部连接。</p><p>这一步可以排除最基础的一类问题：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sshd 根本没启动</span><br></pre></td></tr></table></figure><hr><h2 id="2-检查服务器防火墙"><a href="#2-检查服务器防火墙" class="headerlink" title="2. 检查服务器防火墙"></a>2. 检查服务器防火墙</h2><p>如果服务器使用 UFW：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ufw status</span><br></pre></td></tr></table></figure><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Status: active</span><br><span class="line"></span><br><span class="line">To                         Action      From</span><br><span class="line">--                         ------      ----</span><br><span class="line">22/tcp                     ALLOW       Anywhere</span><br><span class="line">23333/tcp                  ALLOW       Anywhere</span><br><span class="line">24444/tcp                  ALLOW       Anywhere</span><br><span class="line">25565/tcp                  ALLOW       Anywhere</span><br><span class="line">22/tcp (v6)                ALLOW       Anywhere (v6)</span><br></pre></td></tr></table></figure><p>可以看到 22&#x2F;tcp 已经明确放行。</p><p>进一步检查底层 iptables 规则：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> iptables -L -n</span><br></pre></td></tr></table></figure><p>其中可以看到类似：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22</span><br></pre></td></tr></table></figure><p>这进一步说明服务器本机没有明显的 22 端口拦截规则。</p><hr><h2 id="3-直接在服务器本机测试"><a href="#3-直接在服务器本机测试" class="headerlink" title="3. 直接在服务器本机测试"></a>3. 直接在服务器本机测试</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc -zv 127.0.0.1 22</span><br></pre></td></tr></table></figure><p>结果：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Connection to 127.0.0.1 22 port [tcp/ssh] succeeded!</span><br></pre></td></tr></table></figure><p>说明：</p><ul><li><code>sshd</code> 在运行；</li><li>SSH 服务正在监听；</li><li>本机 TCP 连接可以建立；</li><li>服务器本地配置基本正常。</li></ul><p>到这里，服务器本身的问题已经被排除了一大部分。</p><hr><h1 id="五、第四步：检查云安全组"><a href="#五、第四步：检查云安全组" class="headerlink" title="五、第四步：检查云安全组"></a>五、第四步：检查云安全组</h1><p>服务器本机正常，还不能马上断定网络没问题。</p><p>因为在很多云服务器环境中，请求实际上还需要经过云平台的安全组。</p><p>因此登录云厂商控制台，检查入站规则。</p><p>本次排查中：</p><ul><li>22&#x2F;tcp 已放行；</li><li>为了排除规则冲突，甚至临时放宽了安全组；</li><li>修改后重新测试，问题仍然存在。</li></ul><p>因此基本可以排除：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">云安全组拦截</span><br></pre></td></tr></table></figure><p>此时已经得到一个很有价值的结论：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">客户端</span><br><span class="line">   ↓</span><br><span class="line">？？？</span><br><span class="line">   ↓</span><br><span class="line">云平台安全组</span><br><span class="line">   ↓</span><br><span class="line">服务器防火墙</span><br><span class="line">   ↓</span><br><span class="line">sshd</span><br></pre></td></tr></table></figure><p>服务器这一侧从安全组到 <code>sshd</code> 基本全部正常。</p><p>那么问题就越来越像出在：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">客户端 → 校园网出口 → Internet</span><br></pre></td></tr></table></figure><p>这一段。</p><hr><h1 id="六、第五步：最关键的对照实验——换网络"><a href="#六、第五步：最关键的对照实验——换网络" class="headerlink" title="六、第五步：最关键的对照实验——换网络"></a>六、第五步：最关键的对照实验——换网络</h1><p>网络问题里有一个非常有效的方法：</p><blockquote><p><strong>不要一直猜，直接换一个网络环境。</strong></p></blockquote><p>于是切换到手机热点，再执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh -p 22 user@103.36.221.122</span><br></pre></td></tr></table></figure><p>结果：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">成功连接。</span><br></pre></td></tr></table></figure><p>这一结果非常关键。</p><p>因为目标服务器没有变化：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">服务器没变</span><br><span class="line">IP 没变</span><br><span class="line">SSH 配置没变</span><br><span class="line">云安全组没变</span><br></pre></td></tr></table></figure><p>唯一发生变化的是：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">校园网 → 手机热点</span><br></pre></td></tr></table></figure><p>因此可以把问题范围迅速缩小到：</p><blockquote><p><strong>校园网出口路径。</strong></p></blockquote><p>结合之前的现象：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">校园网</span><br><span class="line">    ping  → 正常</span><br><span class="line">    TCP 22 → 无法建立</span><br><span class="line"></span><br><span class="line">手机热点</span><br><span class="line">    ping  → 正常</span><br><span class="line">    TCP 22 → 正常</span><br></pre></td></tr></table></figure><p>最合理的解释就是：</p><blockquote><p>校园网出口侧对外发起的 TCP 22 连接存在过滤或丢弃策略。</p></blockquote><p>这也解释了最开始那个看起来很奇怪的现象：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ping 能通</span><br><span class="line">SSH 却不能用</span><br></pre></td></tr></table></figure><p>因为 ICMP 和 TCP 是完全不同的协议，网络设备可以对它们采用不同的策略。</p><hr><h1 id="七、问题到底发生在哪里？"><a href="#七、问题到底发生在哪里？" class="headerlink" title="七、问题到底发生在哪里？"></a>七、问题到底发生在哪里？</h1><p>把整个排查过程串起来，就会得到这样一条链：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">┌──────────────┐</span><br><span class="line">│  本地电脑     │</span><br><span class="line">└──────┬───────┘</span><br><span class="line">       │</span><br><span class="line">       │ ICMP</span><br><span class="line">       │ ───────────────→ 正常</span><br><span class="line">       │</span><br><span class="line">       │ TCP :22</span><br><span class="line">       │ ───────────────→ 无法建立</span><br><span class="line">       │</span><br><span class="line">┌──────▼───────┐</span><br><span class="line">│  校园网出口   │</span><br><span class="line">│   可能存在过滤│</span><br><span class="line">└──────┬───────┘</span><br><span class="line">       │</span><br><span class="line">       ▼</span><br><span class="line">    Internet</span><br><span class="line">       │</span><br><span class="line">       ▼</span><br><span class="line">┌──────────────┐</span><br><span class="line">│ 云安全组      │  已确认放行</span><br><span class="line">└──────┬───────┘</span><br><span class="line">       │</span><br><span class="line">       ▼</span><br><span class="line">┌──────────────┐</span><br><span class="line">│ 服务器防火墙   │  已确认放行</span><br><span class="line">└──────┬───────┘</span><br><span class="line">       │</span><br><span class="line">       ▼</span><br><span class="line">┌──────────────┐</span><br><span class="line">│    sshd      │  正常监听</span><br><span class="line">└──────────────┘</span><br></pre></td></tr></table></figure><p>这里需要强调一个措辞区别：</p><p>我们可以根据实验结果判断：</p><blockquote><p><strong>问题位于校园网这一侧的出口路径。</strong></p></blockquote><p>至于校园网具体是通过 ACL、端口过滤、防火墙策略还是其他网络设备实现拦截，仅凭这些测试结果无法进一步确定。</p><p>如果一定要确认具体是哪一台设备、哪条规则，可以继续使用 <code>traceroute</code>、<code>tcpdump</code> 等工具做更底层的抓包与路径分析。</p><hr><h1 id="八、最终解决方案：给-SSH-换一个端口"><a href="#八、最终解决方案：给-SSH-换一个端口" class="headerlink" title="八、最终解决方案：给 SSH 换一个端口"></a>八、最终解决方案：给 SSH 换一个端口</h1><p>既然确认问题是：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TCP 22 无法从校园网正常连接</span><br></pre></td></tr></table></figure><p>最直接的方法就是：</p><blockquote><p><strong>不要再使用 TCP 22。</strong></p></blockquote><p>可以给 SSH 增加一个其他的监听端口，例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">51832</span><br></pre></td></tr></table></figure><p>这里真正重要的不是“51832”这个数字，而是：</p><ol><li>端口没有被其他服务占用；</li><li>服务端防火墙允许该端口；</li><li>云安全组允许该端口；</li><li>当前网络环境允许访问该端口。</li></ol><p>通常选择一个较高且没有实际业务占用的端口即可。</p><p>需要特别说明：</p><blockquote><p><code>49152–65535</code> 属于 IANA 定义的动态&#x2F;私有端口范围，并不意味着这些端口天然“更安全”或者“一定不会被占用”。</p></blockquote><p>因此，<strong>检查端口是否真正空闲，比单纯选择一个大数字更加重要。</strong></p><hr><h2 id="1-先备份-SSH-配置"><a href="#1-先备份-SSH-配置" class="headerlink" title="1. 先备份 SSH 配置"></a>1. 先备份 SSH 配置</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> <span class="built_in">cp</span> /etc/ssh/sshd_config /etc/ssh/sshd_config.bak</span><br></pre></td></tr></table></figure><p>这是一个很值得养成的习惯。</p><p>服务器上的网络配置尤其如此，因为 SSH 一旦配置错误，可能直接把自己锁在服务器外面。</p><hr><h2 id="2-修改-sshd-配置"><a href="#2-修改-sshd-配置" class="headerlink" title="2. 修改 sshd 配置"></a>2. 修改 sshd 配置</h2><p>编辑：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> nano /etc/ssh/sshd_config</span><br></pre></td></tr></table></figure><p>增加：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Port 51832</span><br></pre></td></tr></table></figure><p>这次不要急着删除原来的：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Port 22</span><br></pre></td></tr></table></figure><p>而是暂时保留：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Port 22</span><br><span class="line">Port 51832</span><br></pre></td></tr></table></figure><p>这样做的目的非常简单：</p><blockquote><p><strong>先让新端口和旧端口同时工作，确认新连接正常之后，再决定是否关闭 22。</strong></p></blockquote><hr><h2 id="3-修改后先检查语法"><a href="#3-修改后先检查语法" class="headerlink" title="3. 修改后先检查语法"></a>3. 修改后先检查语法</h2><p>不要直接重启。</p><p>先执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> sshd -t</span><br></pre></td></tr></table></figure><p>如果没有任何输出，通常表示配置语法检查通过。</p><p>如果出现报错，先修复配置，不要继续重启 SSH 服务。</p><hr><h2 id="4-放行防火墙"><a href="#4-放行防火墙" class="headerlink" title="4. 放行防火墙"></a>4. 放行防火墙</h2><p>如果使用 UFW：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ufw allow 51832/tcp</span><br></pre></td></tr></table></figure><p>这一步很容易被忘记。</p><p><code>sshd</code> 监听新端口，并不代表防火墙一定允许这个端口。</p><hr><h2 id="5-重启-SSH"><a href="#5-重启-SSH" class="headerlink" title="5. 重启 SSH"></a>5. 重启 SSH</h2><p>不同发行版的服务名称可能不同，例如有的系统使用 <code>ssh</code>，有的环境会使用 <code>sshd</code>。</p><p>例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart ssh</span><br></pre></td></tr></table></figure><p>或者：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart sshd</span><br></pre></td></tr></table></figure><p>以当前系统实际存在的服务名为准。</p><hr><h2 id="6-确认新端口真的在监听"><a href="#6-确认新端口真的在监听" class="headerlink" title="6. 确认新端口真的在监听"></a>6. 确认新端口真的在监听</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ss -tlnp | grep 51832</span><br></pre></td></tr></table></figure><p>例如看到：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LISTEN 0 128 0.0.0.0:51832 0.0.0.0:* users:((&quot;sshd&quot;,pid=...,fd=...))</span><br></pre></td></tr></table></figure><p>说明 sshd 已经成功监听新端口。</p><hr><h2 id="7-从校园网重新测试"><a href="#7-从校园网重新测试" class="headerlink" title="7. 从校园网重新测试"></a>7. 从校园网重新测试</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh -p 51832 user@103.36.221.122</span><br></pre></td></tr></table></figure><p>这次连接成功进入认证阶段，说明 TCP 连接已经建立。</p><p>至此，问题得到解决。</p><hr><h1 id="九、过程中踩到的几个坑"><a href="#九、过程中踩到的几个坑" class="headerlink" title="九、过程中踩到的几个坑"></a>九、过程中踩到的几个坑</h1><p>这次排查过程中，还有几个非常典型的问题值得单独记录。</p><h2 id="坑-1：防火墙放行-≠-端口空闲"><a href="#坑-1：防火墙放行-≠-端口空闲" class="headerlink" title="坑 1：防火墙放行 ≠ 端口空闲"></a>坑 1：防火墙放行 ≠ 端口空闲</h2><p>一开始曾经考虑使用：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">23333</span><br></pre></td></tr></table></figure><p>因为服务器的 UFW 中已经允许这个端口。</p><p>但实际测试时：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kex_exchange_identification: Connection closed by remote host</span><br><span class="line">Connection closed by 103.36.221.122 port 23333</span><br></pre></td></tr></table></figure><p>进一步检查：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ss -tlnp | grep -E <span class="string">&#x27;23333|24444|25565&#x27;</span></span><br></pre></td></tr></table></figure><p>发现：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">LISTEN 0 4096 0.0.0.0:25565 0.0.0.0:* users:((&quot;java&quot;,pid=348140,fd=68))</span><br><span class="line">LISTEN 0 511 *:24444 *:* users:((&quot;node&quot;,pid=19234,fd=18))</span><br><span class="line">LISTEN 0 511 *:23333 *:* users:((&quot;node&quot;,pid=19273,fd=19))</span><br></pre></td></tr></table></figure><p>也就是说：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">23333 → Node 服务</span><br><span class="line">24444 → Node 服务</span><br><span class="line">25565 → Java 服务</span><br></pre></td></tr></table></figure><p>这些端口根本不是 SSH。</p><p>这也解释了为什么会出现：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Connection closed by remote host</span><br></pre></td></tr></table></figure><p>TCP 连接可能已经建立，但连接到该端口的实际上是另一个应用，而不是 <code>sshd</code>。</p><p>因此选端口时一定要检查：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ss -tlnp | grep &lt;port&gt;</span><br></pre></td></tr></table></figure><p><strong>“防火墙允许这个端口”与“这个端口可以拿来运行 SSH”是两件完全不同的事情。</strong></p><hr><h2 id="坑-2：不要把-Connection-closed、refused-和-timeout-混为一谈"><a href="#坑-2：不要把-Connection-closed、refused-和-timeout-混为一谈" class="headerlink" title="坑 2：不要把 Connection closed、refused 和 timeout 混为一谈"></a>坑 2：不要把 <code>Connection closed</code>、<code>refused</code> 和 <code>timeout</code> 混为一谈</h2><p>这几个错误背后的网络阶段并不一样。</p><h3 id="Connection-refused"><a href="#Connection-refused" class="headerlink" title="Connection refused"></a><code>Connection refused</code></h3><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh: connect to host 103.36.221.122 port 22: Connection refused</span><br></pre></td></tr></table></figure><p>通常意味着 TCP 层已经收到对方的拒绝响应，例如 RST。</p><p>常见原因：</p><ul><li>端口没有服务监听；</li><li>主机侧规则主动拒绝连接。</li></ul><hr><h3 id="Connection-closed-by-remote-host"><a href="#Connection-closed-by-remote-host" class="headerlink" title="Connection closed by remote host"></a><code>Connection closed by remote host</code></h3><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kex_exchange_identification: Connection closed by remote host</span><br></pre></td></tr></table></figure><p>这意味着 TCP 连接至少已经进入建立后的阶段，然后连接被关闭。</p><p>如果目标端口实际上运行着 Node、Java 等其他服务，就可能出现这种情况。</p><hr><h3 id="长时间等待后超时"><a href="#长时间等待后超时" class="headerlink" title="长时间等待后超时"></a>长时间等待后超时</h3><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Connection timed out</span><br></pre></td></tr></table></figure><p>说明客户端一直没有得到足够的响应来完成连接。</p><p>常见原因包括：</p><ul><li>防火墙丢弃数据包；</li><li>中间设备进行过滤；</li><li>路由异常；</li><li>目标侧无响应。</li></ul><p>所以：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">refused</span><br><span class="line">closed</span><br><span class="line">timeout</span><br></pre></td></tr></table></figure><p>并不是三个“差不多”的错误，它们对应的是不同阶段的问题。</p><hr><h1 id="十、另一个容易误判的地方：nc-卡住到底说明什么？"><a href="#十、另一个容易误判的地方：nc-卡住到底说明什么？" class="headerlink" title="十、另一个容易误判的地方：nc 卡住到底说明什么？"></a>十、另一个容易误判的地方：<code>nc</code> 卡住到底说明什么？</h1><p>之前我一度把：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc -zv 103.36.221.122 22</span><br></pre></td></tr></table></figure><p>卡住直接理解成：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DROP</span><br></pre></td></tr></table></figure><p>严格来说，这个结论太绝对了。</p><p>更加严谨的判断应该是：</p><blockquote><p>TCP 连接在指定时间内没有完成，也没有立即收到拒绝响应。</p></blockquote><p>其中一种典型原因确实是：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SYN → 防火墙直接 DROP → 客户端一直等待 → 最终 timeout</span><br></pre></td></tr></table></figure><p>但还可能存在其他原因。</p><p>如果需要进一步确定，可以使用：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> tcpdump -i any -n port 22</span><br></pre></td></tr></table></figure><p>观察 SYN 是否发出、有没有 SYN-ACK 返回。</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">客户端 → SYN →</span><br><span class="line">客户端 ← SYN-ACK ←</span><br></pre></td></tr></table></figure><p>说明服务器侧至少有返回。</p><p>如果只有：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">客户端 → SYN →</span><br><span class="line">客户端 → SYN →</span><br><span class="line">客户端 → SYN →</span><br></pre></td></tr></table></figure><p>始终没有收到对应响应，那么就可以进一步怀疑中间路径存在丢弃或过滤。</p><p>这时候排障就从：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">“感觉端口有问题”</span><br></pre></td></tr></table></figure><p>进入了：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">“观察实际 TCP 报文”</span><br></pre></td></tr></table></figure><p>的阶段。</p><hr><h1 id="十一、为什么换网络是一个非常有效的排障方法？"><a href="#十一、为什么换网络是一个非常有效的排障方法？" class="headerlink" title="十一、为什么换网络是一个非常有效的排障方法？"></a>十一、为什么换网络是一个非常有效的排障方法？</h1><p>这次真正让我快速定位问题的，其实不是某条命令，而是：</p><blockquote><p><strong>手机热点对照实验。</strong></p></blockquote><p>网络故障最怕的是同时存在太多变量。</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">客户端</span><br><span class="line">↓</span><br><span class="line">校园网</span><br><span class="line">↓</span><br><span class="line">出口网关</span><br><span class="line">↓</span><br><span class="line">运营商</span><br><span class="line">↓</span><br><span class="line">Internet</span><br><span class="line">↓</span><br><span class="line">云平台</span><br><span class="line">↓</span><br><span class="line">安全组</span><br><span class="line">↓</span><br><span class="line">服务器防火墙</span><br><span class="line">↓</span><br><span class="line">sshd</span><br></pre></td></tr></table></figure><p>如果只盯着服务器排查，就可能在 <code>ufw</code>、iptables、sshd、云安全组里来回折腾很久。</p><p>而一旦换成：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">客户端</span><br><span class="line">↓</span><br><span class="line">手机热点</span><br><span class="line">↓</span><br><span class="line">运营商</span><br><span class="line">↓</span><br><span class="line">Internet</span><br><span class="line">↓</span><br><span class="line">云平台</span><br><span class="line">↓</span><br><span class="line">服务器</span><br></pre></td></tr></table></figure><p>服务器完全没变。</p><p>所以：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">校园网失败</span><br><span class="line">+</span><br><span class="line">手机热点成功</span><br></pre></td></tr></table></figure><p>本身就是一次非常强的“隔离变量”实验。</p><p>它直接把问题从：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">服务器 / 云平台 / 网络路径</span><br></pre></td></tr></table></figure><p>缩小到了：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">校园网出口及其路径</span><br></pre></td></tr></table></figure><p>这比不停修改服务器配置有效得多。</p><hr><h1 id="十二、以后遇到-SSH-连接问题，我会这样排查"><a href="#十二、以后遇到-SSH-连接问题，我会这样排查" class="headerlink" title="十二、以后遇到 SSH 连接问题，我会这样排查"></a>十二、以后遇到 SSH 连接问题，我会这样排查</h1><p>现在回头看，这类问题其实可以形成一套比较固定的排查顺序。</p><h2 id="第-1-层：IP-是否可达"><a href="#第-1-层：IP-是否可达" class="headerlink" title="第 1 层：IP 是否可达"></a>第 1 层：IP 是否可达</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ping &lt;ip&gt;</span><br></pre></td></tr></table></figure><p>确认是不是连最基础的 IP 通信都不存在。</p><p>但注意：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ping 通 ≠ TCP 一定通</span><br></pre></td></tr></table></figure><hr><h2 id="第-2-层：目标-TCP-端口是否可建立"><a href="#第-2-层：目标-TCP-端口是否可建立" class="headerlink" title="第 2 层：目标 TCP 端口是否可建立"></a>第 2 层：目标 TCP 端口是否可建立</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc -zv &lt;ip&gt; &lt;port&gt;</span><br></pre></td></tr></table></figure><p>重点观察：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">succeeded</span><br><span class="line">refused</span><br><span class="line">timeout</span><br></pre></td></tr></table></figure><p>分别对应不同方向的排查。</p><hr><h2 id="第-3-层：服务器有没有服务监听"><a href="#第-3-层：服务器有没有服务监听" class="headerlink" title="第 3 层：服务器有没有服务监听"></a>第 3 层：服务器有没有服务监听</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ss -tlnp | grep &lt;port&gt;</span><br></pre></td></tr></table></figure><p>确认：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">端口存在吗？</span><br><span class="line">是哪个进程占用？</span><br><span class="line">真的是 sshd 吗？</span><br><span class="line">监听地址正确吗？</span><br></pre></td></tr></table></figure><hr><h2 id="第-4-层：服务器本机测试"><a href="#第-4-层：服务器本机测试" class="headerlink" title="第 4 层：服务器本机测试"></a>第 4 层：服务器本机测试</h2><p>例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc -zv 127.0.0.1 22</span><br></pre></td></tr></table></figure><p>证明服务本身至少能够接受本机连接。</p><hr><h2 id="第-5-层：检查服务器防火墙"><a href="#第-5-层：检查服务器防火墙" class="headerlink" title="第 5 层：检查服务器防火墙"></a>第 5 层：检查服务器防火墙</h2><p>例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ufw status</span><br><span class="line"><span class="built_in">sudo</span> iptables -L -n</span><br></pre></td></tr></table></figure><p>或者其他发行版对应的防火墙工具。</p><hr><h2 id="第-6-层：检查云安全组"><a href="#第-6-层：检查云安全组" class="headerlink" title="第 6 层：检查云安全组"></a>第 6 层：检查云安全组</h2><p>特别是云服务器，不要只看操作系统里的防火墙。</p><hr><h2 id="第-7-层：更换网络"><a href="#第-7-层：更换网络" class="headerlink" title="第 7 层：更换网络"></a>第 7 层：更换网络</h2><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">校园网 → 手机热点</span><br><span class="line">公司网络 → 家庭网络</span><br><span class="line">Wi-Fi → 手机流量</span><br></pre></td></tr></table></figure><p>这是非常高性价比的排查手段。</p><hr><h2 id="第-8-层：必要时抓包"><a href="#第-8-层：必要时抓包" class="headerlink" title="第 8 层：必要时抓包"></a>第 8 层：必要时抓包</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> tcpdump -i any -n port 22</span><br></pre></td></tr></table></figure><p>进一步观察：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">SYN 有没有出去？</span><br><span class="line">SYN-ACK 有没有回来？</span><br><span class="line">RST 是谁发的？</span><br></pre></td></tr></table></figure><p>到了这个层面，基本就是在直接观察 TCP 的实际行为，而不是仅凭客户端错误信息猜测。</p><hr><h1 id="十三、最终结论"><a href="#十三、最终结论" class="headerlink" title="十三、最终结论"></a>十三、最终结论</h1><p>这次问题最后可以归纳成一句话：</p><blockquote><p><strong>服务器本身没有故障，SSH 服务、防火墙和云安全组均正常；真正的问题是校园网出口路径对 TCP 22 连接进行了过滤，使 SSH 无法完成 TCP 建连。</strong></p></blockquote><p>整个过程最值得记录的并不是“SSH 改成了 51832”，而是排障思路：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">ping 正常</span><br><span class="line">    ↓</span><br><span class="line">不要急着认为网络正常</span><br><span class="line">    ↓</span><br><span class="line">单独测试 TCP 端口</span><br><span class="line">    ↓</span><br><span class="line">排除服务器 sshd</span><br><span class="line">    ↓</span><br><span class="line">排除服务器防火墙</span><br><span class="line">    ↓</span><br><span class="line">排除云安全组</span><br><span class="line">    ↓</span><br><span class="line">更换网络做对照实验</span><br><span class="line">    ↓</span><br><span class="line">定位到本地网络出口</span><br><span class="line">    ↓</span><br><span class="line">更换 SSH 监听端口</span><br></pre></td></tr></table></figure><p>而这次经历里，我觉得最值得记住的其实是三个判断：</p><h3 id="1-ping-通，不代表-TCP-服务可达"><a href="#1-ping-通，不代表-TCP-服务可达" class="headerlink" title="1. ping 通，不代表 TCP 服务可达"></a>1. <code>ping</code> 通，不代表 TCP 服务可达</h3><p>ICMP 和 TCP 是不同协议，网络设备完全可以对它们采用不同的策略。</p><h3 id="2-网络故障不要只盯着服务器"><a href="#2-网络故障不要只盯着服务器" class="headerlink" title="2. 网络故障不要只盯着服务器"></a>2. 网络故障不要只盯着服务器</h3><p>当服务器配置全部正常时，<strong>换一个网络环境做对照实验</strong>，往往比继续改服务器配置更有效。</p><h3 id="3-SSH-换端口时，先确认端口真的空闲"><a href="#3-SSH-换端口时，先确认端口真的空闲" class="headerlink" title="3. SSH 换端口时，先确认端口真的空闲"></a>3. SSH 换端口时，先确认端口真的空闲</h3><p>不要因为：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">UFW 允许</span><br></pre></td></tr></table></figure><p>就认为：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">这个端口可以直接拿来跑 SSH</span><br></pre></td></tr></table></figure><p>一定要先检查：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ss -tlnp | grep &lt;port&gt;</span><br></pre></td></tr></table></figure><p>确认没有其他服务占用。</p><hr><h2 id="附：常用排障命令"><a href="#附：常用排障命令" class="headerlink" title="附：常用排障命令"></a>附：常用排障命令</h2><h3 id="测试-IP-连通性"><a href="#测试-IP-连通性" class="headerlink" title="测试 IP 连通性"></a>测试 IP 连通性</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ping &lt;ip&gt;</span><br></pre></td></tr></table></figure><h3 id="测试-TCP-端口"><a href="#测试-TCP-端口" class="headerlink" title="测试 TCP 端口"></a>测试 TCP 端口</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc -zv &lt;ip&gt; &lt;port&gt;</span><br></pre></td></tr></table></figure><p>也可以使用：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">timeout</span> 5 bash -c <span class="string">&#x27;cat &lt; /dev/null &gt; /dev/tcp/&lt;ip&gt;/&lt;port&gt;&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="查看监听端口和进程"><a href="#查看监听端口和进程" class="headerlink" title="查看监听端口和进程"></a>查看监听端口和进程</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ss -tlnp</span><br></pre></td></tr></table></figure><p>或者：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ss -tlnp | grep &lt;port&gt;</span><br></pre></td></tr></table></figure><h3 id="查看-UFW"><a href="#查看-UFW" class="headerlink" title="查看 UFW"></a>查看 UFW</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ufw status</span><br></pre></td></tr></table></figure><h3 id="查看-iptables"><a href="#查看-iptables" class="headerlink" title="查看 iptables"></a>查看 iptables</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> iptables -L -n</span><br></pre></td></tr></table></figure><h3 id="查看-SSH-配置"><a href="#查看-SSH-配置" class="headerlink" title="查看 SSH 配置"></a>查看 SSH 配置</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">grep -i <span class="string">&#x27;^Port&#x27;</span> /etc/ssh/sshd_config</span><br><span class="line"><span class="built_in">sudo</span> sshd -T | grep -i <span class="string">&#x27;^port&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="检查-SSH-配置语法"><a href="#检查-SSH-配置语法" class="headerlink" title="检查 SSH 配置语法"></a>检查 SSH 配置语法</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> sshd -t</span><br></pre></td></tr></table></figure><h3 id="重启-SSH-服务"><a href="#重启-SSH-服务" class="headerlink" title="重启 SSH 服务"></a>重启 SSH 服务</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart ssh</span><br></pre></td></tr></table></figure><p>或：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart sshd</span><br></pre></td></tr></table></figure><p>具体取决于发行版的服务名称。</p><h3 id="抓包观察-TCP-连接"><a href="#抓包观察-TCP-连接" class="headerlink" title="抓包观察 TCP 连接"></a>抓包观察 TCP 连接</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> tcpdump -i any -n port 22</span><br></pre></td></tr></table></figure><p>也可以进一步限定来源：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> tcpdump -i any -n host &lt;你的IP&gt; and port &lt;端口&gt;</span><br></pre></td></tr></table></figure><hr><p>这次排障让我比较直观地体会到一件事：</p><p><strong>网络问题最重要的不是“多试几个命令”，而是不断缩小故障范围。</strong></p><p>从 ICMP 到 TCP，从客户端到服务器，再从服务器切换到网络出口；每进行一次测试，实际上都应该是在排除一部分可能性。</p><p>当最后只剩下一个变量时，问题通常也就不难解决了。</p>]]>
    </content>
    <id>https://blog.kkkkikun.dpdns.org/2026/09/24/2026-09-24-%E6%A0%A1%E5%9B%AD%E7%BD%91%E5%B0%81%E4%BA%86-22-%E7%AB%AF%E5%8F%A3-%E4%B8%80%E6%AC%A1%E5%AE%8C%E6%95%B4%E7%9A%84-SSH-%E6%8E%92%E9%9A%9C%E8%AE%B0%E5%BD%95/</id>
    <link href="https://blog.kkkkikun.dpdns.org/2026/09/24/2026-09-24-%E6%A0%A1%E5%9B%AD%E7%BD%91%E5%B0%81%E4%BA%86-22-%E7%AB%AF%E5%8F%A3-%E4%B8%80%E6%AC%A1%E5%AE%8C%E6%95%B4%E7%9A%84-SSH-%E6%8E%92%E9%9A%9C%E8%AE%B0%E5%BD%95/"/>
    <published>2026-09-24T00:37:49.000Z</published>
    <summary>
      <![CDATA[<p>最近遇到了一次很典型的 SSH 网络故障：</p>
<p>同一台公网服务器，在手机热点下可以正常 SSH，但在校园网环境下，无论怎么尝试都连不上。</p>
<p>最开始看到的现象非常容易让人误判：</p>
<ul>
<li><code>ping</code> 正常，延迟约]]>
    </summary>
    <title>校园网封了 22 端口？一次完整的 SSH 排障记录</title>
    <updated>2026-10-24T08:57:25.213Z</updated>
  </entry>
</feed>
