从网络原理上介绍如何改善github访问

在中国访问 GitHub 慢?一个配置改变一切

│ 如果你在国内用 Git 推拉代码时经常遇到超时、龟速、断连,这篇文章能帮你解决 90% 的问题。只需要改一行配置。文章还会深
入解释背后的网络原理,让你知其然也知其所以然。

你是不是经常遇到这些情况?

$ git clone git@github.com:torvalds/linux.git
Cloning into 'linux'...
ssh: connect to host github.com port 22: Connection timed out
fatal: Could not read from remote repository.

或者连上了,但速度感人:

Receiving objects:  3% (1024/34567), 256.00 KiB | 12.00 KiB/s

甚至克隆到一半突然断掉:

fatal: the remote end hung up unexpectedly

如果你在中国大陆,这些场景大概率天天发生。但问题可能不在 GitHub,而在你用的端口

先说结论

把 GitHub 的 SSH 连接从默认的 22 端口切换到 443 端口,体验会有质的飞跃。

三步搞定:

# 第一步:测试 443 端口能不能通
ssh -T -p 443 git@ssh.github.com
# 看到 "Hi xxx! You've successfully authenticated" 就说明没问题

# 第二步:写入配置文件
echo '
Host github.com
    Hostname ssh.github.com
    Port 443
    User git
' >> ~/.ssh/config

# 第三步:没有第三步,正常用就行
git clone git@github.com:user/repo.git   # 自动走 443 端口了

仓库地址不用改,工作流不用变,密钥不用重新配。

原理篇:TCP 端口到底是什么?

在讲为什么换端口有用之前,先搞清楚几个基础概念。

TCP 连接的本质

当你执行 git push 时,你的电脑和 GitHub 服务器之间会建立一条 TCP 连接。一条 TCP 连接由四个要素唯一确定:

源 IP : 源端口 ←→ 目标 IP : 目标端口
192.168.1.100:52431 ←→ 20.205.243.166:22

端口号是一个 0-65535 的数字,用来区分同一台机器上的不同服务。就像一栋大楼的门牌号——IP 地址是大楼地址,端口号是具体房
间号。

常见的"知名端口":

端口号本身不影响速度

这里有一个关键认知:端口号只是一个数字标记,TCP 协议本身不会因为端口号不同而改变传输速度。 从纯协议层面看,22 端
口和 443 端口的数据包格式完全一样,走的是同一条物理线路。

那为什么换端口就能变快?因为路上的设备会根据端口号区别对待你的数据包

原理篇:你的数据包经历了什么

当你在北京 git push 到 GitHub 时,数据包大致走这条路:

你的电脑

家庭路由器 / 公司防火墙 ← 第一关:本地网络

运营商接入网(小区/写字楼) ← 第二关:接入层

运营商城域网 ← 第三关:城市级网络

省级/国家级骨干网 ← 第四关:骨干网

国际出口(北上广等少数节点) ← 第五关:最大瓶颈

海底光缆 / 跨境链路

GitHub 服务器(美国/新加坡)

每一关都有设备在检查和处理你的数据包,而它们做决策的重要依据之一就是目标端口号

原理篇:每一关发生了什么

第一关:本地网络(防火墙/路由器)

原理:端口级访问控制(ACL)

企业和校园网络的防火墙通常配置了访问控制列表(ACL),规则类似:

典型的企业防火墙规则(伪代码)

ALLOW TCP * → *:80 # 放行 HTTP
ALLOW TCP * → *:443 # 放行 HTTPS
DENY TCP * → : # 其他全部拦截

这意味着 22 端口的流量在离开你的公司/学校之前就被丢弃了。你的 git push 数据包根本没有机会到达 GitHub。

而 443 端口?它在任何 ACL 白名单里都一定存在,因为没有它就没有互联网。

第二关 & 第三关:运营商网络(QoS 流量调度)

原理:QoS(Quality of Service,服务质量)

运营商的网络带宽是有限的,尤其是国际出口。当带宽不够用时,运营商需要决定先传谁的数据包、丢谁的数据包。这就是 QoS

QoS 的核心机制是分类 + 排队

                    ┌─────────────────┐
所有数据包 ──────→  │  分类器(Classifier)│
                    └────┬───┬───┬────┘
                         │   │   │
                    ┌────▼┐ ┌▼──┐ ┌▼────┐
                    │ 高优 │ │中优│ │低优  │   ← 不同优先级的队列
                    │ 先级 │ │先级│ │先级  │
                    └──┬──┘ └─┬─┘ └──┬──┘
                       │      │      │
                    ┌──▼──────▼──────▼──┐
                    │   调度器(Scheduler) │   ← 高优先级队列优先发送
                    └───────┬───────────┘
                            ↓
                        出口链路

分类器怎么分类?最简单直接的依据就是端口号

端口 运营商眼中的身份 优先级
443 HTTPS — 电商、支付、视频会议,高商业价值 最高
80 HTTP — 普通网页
22 SSH — 可能是正常运维,也可能是隧道代理 中低
随机高位端口 P2P 下载?不明流量?

当国际出口拥堵时(在中国这几乎是常态),调度器会:

  1. 优先发送高优先级队列(443)的数据包
  2. 高优先级队列清空后才轮到中优先级(22)
  3. 如果持续拥堵,低优先级的包可能直接被丢弃

这就是为什么同一时刻,443 端口能跑到几百 KB/s,而 22 端口只有几十 KB/s。不是线路不同,是排队的位置不同。

第四关:骨干网(DPI 深度包检测)

原理:DPI(Deep Packet Inspection)

普通防火墙只看数据包的"信封"(IP 头 + TCP 头),DPI 则会拆开"信封"看里面的"信件内容"。

SSH 协议有一个非常明显的特征——连接建立时,服务端会发送一个明文的版本标识:

SSH-2.0-OpenSSH_8.9

DPI 设备看到这个特征后,就知道这是一条 SSH 连接。然后可能:

if (protocol == SSH && destination == 境外IP) {
    mark_as_suspicious();
    apply_bandwidth_limit(low);    // 限速
    increase_inspection_level();   // 加强检查
}

但当 SSH 走 443 端口时,情况完全不同。GitHub 的 ssh.github.com:443 实际上是在 TLS 层之上承载 SSH 协议。DPI 设备看到的
是:

TLS 1.3 Client Hello → Server Hello → [加密数据]

这和你打开淘宝、刷抖音的流量特征完全一样。DPI 无法区分这是 SSH 还是普通 HTTPS 浏览,自然也不会做特殊处理。

第五关:国际出口(最大瓶颈)

原理:出口带宽争抢

中国的国际互联网出口总带宽是有限的(虽然逐年增加,但增速赶不上需求)。所有访问境外网站的流量都要挤这几个出口。

在这个最拥挤的瓶颈处,前面所有的 QoS 策略效果被放大到极致:

TCP 协议有重传机制——丢了的包会重新发送。但重传意味着额外的延迟和带宽浪费,而且重传的包到了出口可能又被丢弃,形成恶性
循环。这就是为什么 22 端口不只是"慢",而是"慢到不可用"。

原理篇:一张图看懂全过程

端口 22 的旅程:
你的电脑 ──22──→ 公司防火墙 ──✖ 被拦截(不通)
你的电脑 ──22──→ 家庭路由器 ──→ 运营商 DPI ──⚠ 识别为 SSH,标记低优先级
──→ 骨干网 QoS ──⚠ 排在低优先级队列 ──→ 国际出口 ──⚠ 拥堵时优先丢弃
──→ GitHub(如果包还活着的话)

端口 443 的旅程:
你的电脑 ──443──→ 公司防火墙 ──✓ 白名单放行
──→ 运营商 DPI ──✓ 看起来是普通 HTTPS,不做特殊处理
──→ 骨干网 QoS ──✓ 最高优先级队列 ──→ 国际出口 ──✓ 优先通过
──→ GitHub ✓

原理篇:GitHub 是怎么做到让 SSH 走 443 的?

你可能会好奇:SSH 不是只能走 22 端口吗?GitHub 怎么在 443 端口上跑 SSH?

GitHub 专门部署了一个服务 ssh.github.com,在 443 端口上同时监听 TLS 和 SSH 连接。技术上有两种实现方式:

  1. 协议多路复用(Protocol Multiplexing):服务端根据客户端发来的第一个数据包判断是 TLS 握手还是 SSH 握手,然后分发给不
    同的处理程序
  2. ALPN 协商:在 TLS 握手阶段通过 Application-Layer Protocol Negotiation 扩展来协商上层协议

当你执行 ssh -p 443 git@ssh.github.com 时:

  1. TCP 三次握手(目标端口 443)
  2. SSH 协议握手(在 443 端口上进行,而非传统的 22)
  3. SSH 密钥认证
  4. Git 数据传输

从网络设备的视角看,这就是一个普通的 443 端口 TLS 连接。

实际体验差多少?

场景 端口 22 端口 443
在家(晚高峰) 经常超时连不上 基本都能连上
在公司 大概率直接不通 畅通
在学校 大概率直接不通 畅通
clone 速度 10-100 KB/s,看运气 200KB-1MB/s,相对稳定
大仓库克隆 经常中途断开要重来 基本能完成

│ 注意:443 端口不是魔法,国际出口拥堵时一样会慢。但它把体验从"碰运气"提升到了"基本可靠"。

进阶配置

如果你在公司需要走 HTTP 代理

很多公司上网必须走 HTTP 代理。22 端口在这种情况下彻底没戏——HTTP 代理只能转发 HTTP/HTTPS 流量。但 443 端口可以利用
HTTP 代理的 CONNECT 方法穿透。

CONNECT 方法的原理:

  1. 你的 SSH 客户端告诉代理:"请帮我建一条到 ssh.github.com:443 的隧道"
    → CONNECT ssh.github.com:443 HTTP/1.1

  2. 代理看到目标是 443 端口,认为这是正常的 HTTPS 请求,建立隧道
    ← HTTP/1.1 200 Connection Established

  3. 隧道建立后,代理只做透明转发,你的 SSH 数据在隧道里自由传输
    [SSH 握手和数据传输,代理看不到内容]

配置方法:

# ~/.ssh/config
Host github.com
    Hostname ssh.github.com
    Port 443
    User git
    ProxyCommand nc -X connect -x proxy.yourcompany.com:8080 %h %p

macOS 上如果 nc 不支持 -X 参数:

brew install connect

# 然后改成:
ProxyCommand connect -H proxy.yourcompany.com:8080 %h %p

SSH over 443 vs HTTPS 克隆

对比项 SSH over 443 HTTPS 克隆
认证方式 SSH Key,一次配置永久免密 Token,需要 credential 管理
安全性 密钥对认证,私钥不离开本机 Token 是字符串,可能泄露
改动成本 加一段配置,仓库地址不用改 所有仓库 remote 要改成 https
推送体验 完全无感 可能弹认证框

常见问题

Q:改成 443 端口后,原来的 SSH Key 还能用吗?
A:能。端口只影响传输通道,认证用的还是你 ~/.ssh/ 下的密钥对,完全不受影响。

Q:会不会影响访问其他 SSH 服务器?
A:不会。配置文件里的 Host github.com 是精确匹配,只对 GitHub 生效,其他 SSH 连接不受影响。

Q:443 端口不是 HTTPS 用的吗?跑 SSH 不会冲突吗?
A:不会。GitHub 在 ssh.github.com 这个专门的域名上做了协议识别,443 端口同时支持 HTTPS 和 SSH。你的 SSH 客户端连上去
后会进行 SSH 握手,服务端识别后走 SSH 处理流程。

Q:速度还是不理想怎么办?
A:443 端口解决的是连通性和优先级问题。如果国际出口本身就很拥堵,可以考虑:

总结

你的情况 建议
在国内用 GitHub 必须配 443 端口
在公司有代理 443 + ProxyCommand
SSH 搞不定 用 HTTPS 克隆也行
在国外 默认 22 端口就够了

完整配置,复制粘贴即可:

cat >> ~/.ssh/config << 'EOF'
Host github.com
    Hostname ssh.github.com
    Port 443
    User git
EOF

一句话总结:端口号本身不影响速度,但路上的设备会根据端口号决定你的数据包是走 VIP 通道还是被拦截