中国大陆网络环境下让 GitHub 恢复可用:跑在本机
127.0.0.1:443上的透明 TLS 反向代理。
GFW 对 GitHub 的阻断按 TLS 握手里的 SNI 字段精确匹配 —— 这解释了两件事:
- 换 IP、改 hosts、换 DNS 全都无效(阻断不认 IP);
- 同一 IP、同一时刻,发 SNI 就超时,不发 SNI 就能拿到完整内容。
所以思路很直接:浏览器照常访问 https://github.com,由 hosts 把域名指到本机,
反代完成 TLS 中间人,在转发时不发送 SNI,阻断就失效了。
与 FastGithub / Watt Toolkit 同源思路,区别是这里纯 Python 标准库实现: 不需要内核驱动,不改系统代理,不与其他代理软件争夺流量。
- 零第三方依赖 —— 只用 Python 标准库,Python 3.11+ 直接跑
- 并发竞速选路 ——
4 个 IP × (正常 SNI / 无 SNI) × 2 轮,谁先握手成功用谁 - 连接池复用 —— 避免每个请求都重吃一遍「握手成功但请求被吞」的十几秒
- 故障分级处理
- 通道级(体传输中断 / 刚建连接等不到响应头)→ 惩罚该 SNI 模式 180s,换另一条
- 虚拟主机级(IP 真实但不属于该域名)→ 拉黑该 IP 600s
- 流式转发 —— 响应体不落内存,几百 MB 的仓库打包也不会撑爆
- 分帧严格按类型收尾 ——
chunked必须读到收尾块、length必须读满、 只有eof才是「上游关连接 = 正常结束」 - 白名单收口 —— 只有 GitHub 相关域名会转发,其余一律 403
- 自带 CRL 分发 —— 证书声明 CRL 分发点、反代顺手把它喂出去, 于是 curl / git 在 Windows 上不需要任何开关(见下)
- 内置自测 —— 147+ 项离线单测 + 真
git push端到端,不联网约 12s 跑完
gh-proxy.py 反代主体(唯一的网络核心)
deploy.py 一键部署:备份 hosts → 装 CA → 写映射 → 起反代
undeploy.py 一键卸载:摘映射 → 删 CA → 删自启(可逆,带快照)
status_gui.py 状态监控窗口(纯 tkinter)
restart_proxy.py 重启逻辑(停旧起新)
stop_proxy.py 停进程逻辑(带防误杀核对)
gen_certs.py 生成私有 CA + 服务器证书
selftest.py 离线自测(A 段单测 + C 段真 git push 端到端)
certs/ openssl 配置 + 运行时生成的证书(证书本体不入库)
使用说明.txt 详细中文文档
- Windows 10 / 11
- Python 3.11 或更高(下载,安装时勾选 Add python.exe to PATH)
- 管理员权限(写 hosts、监听 443、装根证书都需要)
- openssl(Git for Windows 自带,装 Git 即可)
1. 生成证书(每人必须自建,仓库内不含任何私钥)
python gen_certs.py2. 部署
双击 一键部署.bat(会自动申请管理员权限)。
它会:备份 hosts → 把私有 CA 装进系统信任区 → 写入 36 条域名映射 → 启动反代。
3. 验证
双击 状态监控.bat,点「立即全链路测试」。
六行全部变绿 = 通了。
| 项 | 做法 |
|---|---|
| CA 私钥 | 每人自建,仓库永不包含 |
| 上游证书链 | 一律验证;「正常 SNI」模式连主机名一起核 |
| 「无 SNI」模式 | 没有主机名可核 → 用根证书 SHA-256 钉扎,链根不在白名单就拒 |
| 转发范围 | 域名白名单,非 GitHub 域名返回 403 |
alt-svc 响应头 |
剥掉,否则浏览器记住 HTTP/3 地址后会绕过本代理 |
⚠️ 这是 TLS 中间人。私有 CA 私钥等同于你所有 HTTPS 流量的伪造能力, 请勿外泄,也不要把certs/*.key提交到任何仓库(.gitignore已排除)。
这个工具的存在理由只有一条:到 GitHub 的链路存在概率性、时变的干扰。 从这条事实出发,每个机制都对应一条环境约束——没有为炫技而生的部件:
| 环境约束 | 必然需求 | 对应机制 |
|---|---|---|
| 失效是概率性的(同时刻部分 IP 通、部分不通) | 静态白名单必然失效 → 探索 + 记忆 | 4 IP × 2 模式竞速、GOOD_PEER 直连、模式提升/惩罚 |
| 干扰会适应(今天通的通道明天被盯上) | 单一机制会被磨掉 → 在线轮换 | 模式惩罚、IP 拉黑、预算过期回收 |
| 效率瓶颈在握手(每页几十次请求) | 复用是唯一根本杠杆 | 连接池 keep-alive + 流式搬运(内存与文件大小无关) |
| 无 SNI 是根本反制,但丢名字=丢认证 | 认证缺口只能补偿 | 链验证 + 根证书钉扎(预共享秘密) |
- 专注(满分):白名单 + 纯标准库 + 单文件 + 不碰内核。每个「没有」 (不做通用代理、无第三方依赖、无驱动)都是主动的范围收缩—— 专注换来了一个人就能完成全量审计的可维护性。
- 高效(热路径达标):记忆命中时延迟由链路主导(API/静态资源亚秒级); 记忆失效时的重新探索以秒计,这是对抗环境的必然成本,设计只在必要时支付 (热路径直达、付过就记住、同一条税不重复交)。
- 稳定(逻辑层达标):所有失败被分类并映射到恰好一个纠正动作; 预算体系保证「重试在结构上永远可能」;全部超时锚定实测分布并留 15 倍以上裕度。
- 「无 SNI」模式的认证缺口是信息论层面的。「不透露名字」与「用名字做 TLS 认证」不可兼得;在没有预分发秘密的现实中,根证书钉扎就是那个秘密。 残余风险:持有任意受信 CA 证书的在路者可在此模式下伪造响应——这是 该选择的下界,不是瑕疵。缓解靠 SNI 优先 + 钉扎 + 错误虚拟主机检测三层。
- MITM 架构意味着永远握着信任根。所有效率与稳定收益,都以「永久维护 CA 私钥卫生」为对价。私钥一旦泄露等同于全部 HTTPS 流量可被伪造—— 这是架构内生负债,需要永久警觉(文件权限 + 不入库 + 每人自建)。
代码有预算与自愈,但进程本身没有守护:无看门狗、无崩溃自启。
若系统策略阻止注册自启任务,可用手动方式创建(见
手动添加开机自启-GUI教程),
或退回「双击 启动反代.bat」的最低保障。
190+ 条离线断言(含真 git push 端到端)+ 27 项沙盒对抗矩阵 (慢握手/慢滴灌/请求夹带/上游投毒/并发洪水,全部按预算精确收敛)。 对抗性验证与静态审计的报告随仓库演进持续更新。
这是本项目踩过的最隐蔽的一个坑,值得单独说明。
Windows 上 curl / git 走的是 schannel(系统原生 TLS),它会强制做 证书吊销检查(CRL / OCSP)。而本方案出示的证书由你自己的私有 CA 签发 —— 如果那张证书没声明任何吊销源,schannel 就找不到东西可查,直接报:
curl: (35) schannel: next InitializeSecurityContext failed:
CRYPT_E_NO_REVOCATION_CHECK (0x80092012) - 吊销功能无法检查证书是否吊销。
注意错误信息的误导性:它读起来像「CRL 服务器连不上」,实际是 「证书里压根没写 CRL 地址」。两者修法完全不同。
而且只有 curl 会中招 —— Git for Windows 对吊销失败的处理宽松得多,
git clone 默认就能过。所以排查时务必把 git 和 curl 分开实测,
不要假设「两个都坏了」。
本项目的做法(gen_certs.py + gh-proxy.py 配合):
- 给服务器证书加
crlDistributionPoints = http://127.0.0.1:<端口>/ca.crl - 生成对应的 CRL 文件
- 反代在同端口起一个只服务该 CRL 的极小 HTTP 监听
schannel 取到 CRL → 吊销检查真正成功 → 放行。 于是 curl / git / 任何 schannel 工具都不需要任何开关。
实测(2026-09-21,ctypes 直调
crypt32读链的TrustStatus):file://形式的 CRL 分发点Windows 链引擎不读,吊销状态仍是 UNKNOWN, 只有http://才真正被取回。所以别图省事改成file://。
若该监听因故未起来,反代会在启动横幅里明确报警,此时回退方案是给 curl 加
--ssl-revoke-best-effort(仍尝试检查,只是不硬失败),
写进 %USERPROFILE%\.curlrc 即全局生效。
只有三处,且都可逆:
- hosts 的标记块 —— 36 条
127.0.0.1 <域名>,夹在# === gh-proxy BEGIN ===/# === gh-proxy END ===之间。 卸载时只摘这一段,其余条目原样保留。 - 系统 Root 存储里的私有 CA —— 卸载时移除。
127.0.0.1:443监听 —— 关掉进程即释放。
不改:系统代理设置(ProxyEnable / ProxyServer 原样)、
不碰 v2rayN / Watt Toolkit / Clash 等其它代理软件、不注册常驻服务(除非你主动运行 开机自启.bat)。
| 想做什么 | 双击 |
|---|---|
| 启动反代(前台,能看输出) | 启动反代.bat |
| 改完代码后让它生效 | 重启反代.bat |
| 体检 | 状态监控.bat |
| 开机自动跑 | 开机自启.bat |
| 恢复原样 | 一键卸载.bat |
⚠️ 改完gh-proxy.py必须重启才生效 —— 反代是常驻进程, 加载的是它启动那一刻的代码。
python selftest.py -A-A 跑 A 段(离线单测)+ C 段(真 git push 端到端),不联网,约 12 秒。
改代码后建议先跑这个 —— 联机试验会被网络波动掩盖真正的 bug。
跑全量(含联网链路):
python selftest.py| 症状 | 原因 | 处理 |
|---|---|---|
| 浏览器报「连接被拒绝」 | hosts 还在拦截,但 443 没进程监听 | 双击 启动反代.bat |
| 反代在跑,但某些域名 502 | 链路抖动,或某个 SNI 模式被针对 | 等 3 分钟(模式惩罚自动过期),看监控窗口是哪条 |
| 面板显示「pid 文件过期」但端口在听 | 面板判活异常 | 新版已改用端口属主核对,不会再误报 |
重启反代.bat 报「拒绝访问」 |
旧进程在更高完整性等级下运行 | 注销重登后再试 |
- 只支持 Windows —— hosts 路径、
certutil、schtasks都绑定了 Windows - 只代理 GitHub 域名 —— 白名单机制,不做通用代理
- 不支持 WebSocket(收到
Upgrade请求会按 RFC 剥掉Connection: Upgrade等头再转发) - 反代进程本身不监听公网,仅
127.0.0.1
本项目用于恢复对 GitHub 的正常访问,不提供任何绕过付费/授权的手段。 请遵守当地法律法规与 GitHub 服务条款。使用者自行承担风险。
MIT,见 LICENSE。