从网络原理上介绍如何改善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 地址是大楼地址,端口号是具体房
间号。
常见的"知名端口":
- 22:SSH(远程登录、Git SSH 协议)
- 80:HTTP(明文网页)
- 443:HTTPS(加密网页)
- 53:DNS(域名解析)
端口号本身不影响速度
这里有一个关键认知:端口号只是一个数字标记,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 下载?不明流量? | 低 |
当国际出口拥堵时(在中国这几乎是常态),调度器会:
- 优先发送高优先级队列(443)的数据包
- 高优先级队列清空后才轮到中优先级(22)
- 如果持续拥堵,低优先级的包可能直接被丢弃
这就是为什么同一时刻,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 策略效果被放大到极致:
- 443 端口的包:排在队伍最前面,优先通过
- 22 端口的包:排在后面,拥堵时可能等很久甚至被丢弃
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 连接。技术上有两种实现方式:
- 协议多路复用(Protocol Multiplexing):服务端根据客户端发来的第一个数据包判断是 TLS 握手还是 SSH 握手,然后分发给不
同的处理程序 - ALPN 协商:在 TLS 握手阶段通过 Application-Layer Protocol Negotiation 扩展来协商上层协议
当你执行 ssh -p 443 git@ssh.github.com 时:
- TCP 三次握手(目标端口 443)
- SSH 协议握手(在 443 端口上进行,而非传统的 22)
- SSH 密钥认证
- Git 数据传输
从网络设备的视角看,这就是一个普通的 443 端口 TLS 连接。
实际体验差多少?
| 场景 | 端口 22 | 端口 443 |
|---|---|---|
| 在家(晚高峰) | 经常超时连不上 | 基本都能连上 |
| 在公司 | 大概率直接不通 | 畅通 |
| 在学校 | 大概率直接不通 | 畅通 |
| clone 速度 | 10-100 KB/s,看运气 | 200KB-1MB/s,相对稳定 |
| 大仓库克隆 | 经常中途断开要重来 | 基本能完成 |
│ 注意:443 端口不是魔法,国际出口拥堵时一样会慢。但它把体验从"碰运气"提升到了"基本可靠"。
进阶配置
如果你在公司需要走 HTTP 代理
很多公司上网必须走 HTTP 代理。22 端口在这种情况下彻底没戏——HTTP 代理只能转发 HTTP/HTTPS 流量。但 443 端口可以利用
HTTP 代理的 CONNECT 方法穿透。
CONNECT 方法的原理:
-
你的 SSH 客户端告诉代理:"请帮我建一条到 ssh.github.com:443 的隧道"
→ CONNECT ssh.github.com:443 HTTP/1.1 -
代理看到目标是 443 端口,认为这是正常的 HTTPS 请求,建立隧道
← HTTP/1.1 200 Connection Established -
隧道建立后,代理只做透明转发,你的 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 端口解决的是连通性和优先级问题。如果国际出口本身就很拥堵,可以考虑:
- 使用 git clone --depth 1 浅克隆减少数据量
- 在网络低峰期(早上)操作大仓库
- 使用 GitHub 的镜像服务或 Gitee 等国内平台做中转
总结
| 你的情况 | 建议 |
|---|---|
| 在国内用 GitHub | 必须配 443 端口 |
| 在公司有代理 | 443 + ProxyCommand |
| SSH 搞不定 | 用 HTTPS 克隆也行 |
| 在国外 | 默认 22 端口就够了 |
完整配置,复制粘贴即可:
cat >> ~/.ssh/config << 'EOF'
Host github.com
Hostname ssh.github.com
Port 443
User git
EOF
一句话总结:端口号本身不影响速度,但路上的设备会根据端口号决定你的数据包是走 VIP 通道还是被拦截