先说结论:GitHub镜像站这事儿,绝大多数人一听就觉得是“大佬专属技能”,实际上只要搞清楚原理,一台低配服务器加Nginx就能把八成需求跑起来。我前后帮三个团队搭过同类服务,从最初的网页能打开,到release文件稳定下载,再到git clone不再断流,每一步都踩过不少坑。这篇文章就把我这套完整的搭建流程、配置文件和排障思路直接摊开写出来,你照着一步步做就能从零跑起来。
这套方案适合谁?适合那些GitHub网页经常打不开、clone仓库要等半天、release包下载总在中途断掉的人,也适合公司内部需要给研发团队共享一个稳定入口的运维同学。核心思路很简单:用一台网络质量较好的服务器作为中转,把GitHub的页面流量和下载流量“原样搬”到你自己域名下,再用Nginx做缓存和超时优化,让原本走不动的链路变得顺畅。全程不涉及那些灰色手段,所有技术点都是标准的Web反向代理与缓存,合规也干净。
1. 镜像站到底在解决什么问题
1.1 为什么直接访问GitHub经常掉链子
大家口中“打不开”的GitHub,本质是一组分布在全球的域名系统,包括网页端github.com、文件下载端codeload.github.com、对象存储端objects.githubusercontent.com、用户头像avatars.githubusercontent.com等。这些域名背后的服务器有些在海外,有些在CDN节点上,国内网络访问时容易受跨境链路质量影响,高峰期丢包率会明显上升。
这不是GitHub本身挂了,而是网络链路不稳定。表现就是网页转圈圈、clone卡在“Receiving objects”、release压缩包下载到一半连接重置。镜像站就是绕开这条糟糕链路:你访问自己服务器上搭的反代服务,由这台网络质量更可控的服务器代替你去和GitHub“对话”,再把结果原样回传给你。对用户来说,域名变了,体验却接近直连顺畅的状态。
1.2 镜像站的本质:反向代理加缓存
很多非技术朋友听到“镜像”就以为是“复制了GitHub所有代码”,其实完全不是。绝大多数GitHub镜像站,尤其咱们自己搭的这种,做的是反向代理:客户端的请求打到你的Nginx上,Nginx作为中间人转发到GitHub官方服务器,拿到响应后再返回给客户端。
为什么用反向代理而不是同步仓库?同步镜像(比如代码托管平台那种自动import仓库)只能解决“仓库里默认分支的代码”这一个场景,而日常开发中更重要的问题是:网页跳转、Issue渲染、Release下载、raw文件直链、git协议交互。这些都要求“实时数据”,同步方案处理不了。反向代理则什么都不用存,来一个请求转发一个请求,最简单也最接近原始体验。
缓存则是锦上添花。release压缩包、npm包、release-assets这类不常变化的文件,Nginx可以在中转时留一份本地副本,下次有人再下载同版本,直接由你服务器发出去,速度快且省流量。但要注意,html页面和API结果不建议开长效缓存,否则你会看到各种灵异问题。
1.3 几种主流架构对比,选错方向会事倍功半
在自己动手之前,我建议先把方案选型搞清楚。网上流传的有这么几类路子,各有优劣:
| 方案类型 | 代表实现 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|---|
| Nginx反代全站 | 自己配Nginx | 可控性最强,能精确处理每个域名和路径 | 配置量大,需要自己维护 | 有服务器、想长期自用 |
| Cloudflare Worker反代 | 改版ghproxy类项目 | 部署快,全球CDN节点多,免费额度够用 | 免费版限流,下载大文件不稳 | 临时用、请求量不大 |
| 基于Cloudflare Pages/Tunnel | 借助CF edge | 不用买服务器,绑定自定义域名方便 | 免费频率限制严格,重负载会429 | 个人学习、轻量访问 |
| 公网仓库同步 | Gitee导入等 | 全站可访问镜像仓库 | 只能同步仓库,不是全站,release和Issue缺失 | 代码浏览与下载release替代 |
| 自建下载加速器容器 | 跑一个gh-proxy容器 | 专门针对github.com和raw.githubusercontent.com下载加速 | 网页浏览体验弱,跳转逻辑不完整 | 只想要clone和下载提速 |
我自己最终选了Nginx自建,原因很实际:Cloudflare免费版对单IP的限速非常严格,测下来下载大文件时经常跑到一半被断;而Caddy虽然配置简单,但我想用sub_filter对HTML内容里的各种github.com链接做替换,Nginx配合编译好的http_sub_module最顺手。另外Nginx的proxy_cache缓存大文件时表现也比Caddy更稳。如果你只是临时给朋友开几天,那Worker方案确实快;但想长期、安静、稳定地用,还是得自己掌握Nginx那套。
2. 动手前的基础准备与选型
2.1 服务器怎么选,带宽和区域是硬指标
镜像站最耗资源的地方不在CPU,而在出网带宽。买服务器前先想清楚:你是自己一个人用,还是给一个研发小组用?一个人用,1核1G内存、带宽5Mbps可能都够;如果十几个人同时clone大仓库,那带宽反而是第一瓶颈。
区域的优先级高于一切。我这里不方便评价具体地区的网络环境,但可以给你一个选型方法:在目标服务器上执行三次curl -o /dev/null -s -w '%{speed_download}' https://codeload.github.com/,测一下从这台服务器到GitHub官方下载端的实际速度。我实测过几个区域,差异非常大,有的能稳定跑到几十MB/s,有的只有几百KB/s。建议你买服务器前先借用同区域的测试IP试一下,或者买那种支持24小时无理由退款的产品,开机后先测速,速度不行马上退款换区域。
存储推荐SSD,且容量至少留50GB以上空间来做缓存。Nginx缓存release文件时,一个大仓库的tag包可能有几百MB,容量太小的机器缓存一会儿就满了,命中率上不来。
2.2 域名、证书与DNS,三个环节缺一不可
域名是必须的。用IP直接访问会带来几个麻烦:HTTPS证书不好签、浏览器直接标“不安全”、后续子域名拆分(比如raw.你的域名.com)也做不了。域名不贵,买个便宜后缀就够用。
证书我用Let‘s Encrypt,配合acme.sh自动续期,三个月一续,配置一次就不用管了。域名解析选哪家不重要,阿里云、腾讯云、Cloudflare都行。但有两个操作细节要提一下:
- 如果你域名在国内备案的机器上使用,A记录解析到国内IP可能会有备案核查问题,具体按你的实际情况操作;
- 解析记录建议设置一个泛解析(
*),这样后面想加raw、codeload、objects这些二级子域名时不用每次都去控制台新增记录。
Nginx里我会按二级域名拆分不同location,一个主域名github.example.com用来跑网页反代,另外用raw.example.com和dl.example.com分别处理raw文件与release下载。这样职责清晰,也方便针对不同流量配置不同的缓存策略。
2.3 先列一份需求清单,再决定要代理哪些域名
这一步特别关键,很多人搭完发现“网页能开了但clone还是慢”,就是因为没搞清楚GitHub的下载流量不在网页域名上。我建议把自己的需求列成清单:
| 使用场景 | 对应的GitHub域名 | 你的镜像站怎么处理 |
|---|---|---|
| 浏览仓库、Issue、PR | github.com | 主域名反代,并替换页面内链接 |
| git clone / push | github.com | 走主域名/git路径,Nginx透传Smart HTTP协议 |
| 下载release压缩包 | codeload.github.com | 单独子域名反代,开缓存 |
| 下载release内的assets | objects.githubusercontent.com | 跟随跳转,或单独反代 |
| 下载raw文件 | raw.githubusercontent.com | 单独子域名反代,开缓存 |
| 请求REST API | api.github.com | 如需使用,单独子域名,谨慎缓存 |
| 用户头像资源 | avatars.githubusercontent.com | 建议回源,不缓存或短缓存 |
我见过有人只反代了github.com,结果页面里所有clone链接都变成github.com/xxx/xxx.git,点开还是要走原来的烂网络,这就是典型的“拆东墙补西墙”。正确做法是页面里的所有链接都用sub_filter替换成你的镜像域名,用户点到的所有资源都走你的服务器中转,才叫真正的镜像。
3. Nginx反向代理镜像核心配置
3.1 安装Nginx时提前编译好两个关键模块
如果你直接用系统自带的nginx(比如apt install nginx),大概率缺少http_sub_module和http_proxy_module的部分高级特性。尤其是sub_filter,GitHub页面里的链接替换全靠它,没这个模块你就没法做透明的“换链”操作。
我在Ubuntu 20.04/22.04上推荐编译安装。先装依赖:
apt update apt install build-essential libpcre3-dev libssl-dev zlib1g-dev -y wget https://nginx.org/download/nginx-1.24.0.tar.gz tar zxvf nginx-1.24.0.tar.gz cd nginx-1.24.0编译参数里一定要带这几个模块:
./configure \ --prefix=/etc/nginx \ --sbin-path=/usr/sbin/nginx \ --modules-path=/usr/lib/nginx/modules \ --conf-path=/etc/nginx/nginx.conf \ --with-http_ssl_module \ --with-http_sub_module \ --with-http_gzip_static_module \ --with-http_v2_module \ --with-stream \ --with-stream_ssl_module make && make install这里多说一句为什么我要--with-stream。后面如果要给git的SSH协议(22端口)也做镜像跳转,stream模块可以做四层透明转发。虽然平时git用HTTPS就够,但总有同事习惯用SSH协议拉代码,有备无患。
3.2 网页反代主配置:换链是灵魂
网页反代的难点不在“转发”,而在“让用户看起来没离开GitHub”。GitHub页面会动态生成大量绝对链接,图片、CSS、JS、仓库地址全指向github.com或avatars.githubusercontent.com等。你需要在返回给用户前把响应内容里的这些域名全部替换成你的镜像域名。
关于换链,核心配置如下:
server { listen 443 ssl http2; server_name github.example.com; ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/privkey.pem; # 关键:替换HTML响应中的域名链接 sub_filter_once off; sub_filter 'https://github.com' 'https://github.example.com'; sub_filter 'https://codeload.github.com' 'https://dl.example.com'; sub_filter 'https://raw.githubusercontent.com' 'https://raw.example.com'; sub_filter 'https://objects.githubusercontent.com' 'https://objects.example.com'; sub_filter 'https://avatars.githubusercontent.com' 'https://avatars.example.com'; sub_filter_types text/html text/css application/javascript application/json; location / { proxy_pass https://github.com; proxy_set_header Host github.com; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; # 防断连核心参数 proxy_connect_timeout 10s; proxy_send_timeout 60s; proxy_read_timeout 60s; proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; # 关闭缓存,保证页面实时性 proxy_no_cache 1; proxy_cache_bypass 1; } }proxy_pass https://github.com;这里有个细节,不要在URI末尾加斜杠,也不要带变量。否则Nginx可能把请求路径处理逻辑搞乱,Git登录后的回调地址会错乱。保留默认的”把完整URI透传给上游“行为是最稳的。
proxy_set_header Host github.com这行也容易被忽略。GitHub是根据Host头来识别你想访问哪个站点的,如果你把Host留成你自己的域名,GitHub会返回404或者跳转。
那github.com的IP是怎么解析的?Nginx默认用系统DNS解析,但系统DNS有时候给出的不是最优IP。我建议在nginx.conf的http块里显式配置:
resolver 8.8.8.8 1.1.1.1 valid=300s ipv6=off; resolver_timeout 5s;再加一条:proxy_ssl_server_name on; proxy_ssl_name github.com;。这是因为GitHub的SSL证书是针对github.com域名的,Nginx和上游建立TLS连接时必须发送正确的SNI,否则证书校验失败,报SSL: certificate verify failed。
3.3 release下载与raw文件子域名配置
GitHub的release下载链路比较特殊:浏览器请求codeload.github.com/owner/repo/tar.gz/refs/tags/v1.0.0,会先返回302跳转到objects.githubusercontent.com/...。反代时如果你直接把proxy_pass指向https://codeload.github.com,Nginx会原样把302回给客户端,客户端再去请求objects.githubusercontent.com,但前面又说这个域名没被镜像,等于白干。
所以我的做法是:在处理dl.example.com时,把上游域名的跳转也一起“劫持”过来。两个方案:
方案一:直接用Nginx跟随重定向。在location里加proxy_intercept_errors off;,然后额外加一层location匹配objects.example.com,把这一层也反代到objects.githubusercontent.com。这要求你在页面换链时已经把对象域名换成objects.example.com,用户点击下载后,实际请求落到你的服务器上。
方案二:顺手在nginx里直接改写Location头:
server { listen 443 ssl http2; server_name dl.example.com objects.example.com; location / { proxy_pass https://codeload.github.com; proxy_set_header Host codeload.github.com; proxy_ssl_server_name on; proxy_ssl_name codeload.github.com; proxy_redirect https://objects.githubusercontent.com/ https://objects.example.com/; proxy_redirect https://codeload.github.com/ https://dl.example.com/; proxy_intercept_errors on; error_page 301 302 307 = @handle_redirect; } location @handle_redirect { proxy_pass https://objects.githubusercontent.com$request_uri; proxy_set_header Host objects.githubusercontent.com; proxy_ssl_server_name on; proxy_ssl_name objects.githubusercontent.com; proxy_redirect https://objects.githubusercontent.com/ https://objects.example.com/; } }proxy_redirect这条配置的作用是:上游返回302时,Nginx会把响应头里的Location也按规则改写。这样用户即使看到302,浏览器地址栏也不会跳成GitHub官方域名,而是一直停留在你的镜像域名上。
raw文件子域名相对单纯一点:
server { listen 443 ssl http2; server_name raw.example.com; location / { proxy_pass https://raw.githubusercontent.com; proxy_set_header Host raw.githubusercontent.com; proxy_ssl_server_name on; proxy_ssl_name raw.githubusercontent.com; proxy_redirect https://raw.githubusercontent.com/ https://raw.example.com/; proxy_cache github_raw_cache; proxy_cache_key "$uri$is_args$args"; proxy_cache_valid 200 6h; proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; add_header X-Cache-Status $upstream_cache_status; } }raw文件绝大多数是源码文件,不经常变化,6小时缓存完全没问题。add_header X-Cache-Status是为了方便自己调试,每次请求看响应头就能判断是HIT还是MISS,排查问题时特别有用。
3.4 git clone加速原理与配置优化
镜像站的最终考验是git clone。Git的HTTP协议不是简单的GET,它需要先请求一个info/refs的端点获取分支引用,然后通过git-upload-pack和git-receive-pack两个端点传输对象数据。Nginx反代需要把这类POST请求原样透传。
在刚才的主域名配置里,location /就已经覆盖了这些路径。但有几个坑必须填:
第一个坑是URL转换。用户使用镜像域名clone时,他把原始URL里的github.com/owner/repo.git换成github.example.com/owner/repo.git即可,Nginx会把请求完整转发到https://github.com/owner/repo.git。这没问题。但很多用户会直接在页面里看到GitHub帮我们生成好的一行命令,比如git clone https://github.com/owner/repo.git,这个原始URL已经被sub_filter替换成了镜像域名,所以页面里复制的命令直接可用。
第二个坑是大仓库的POST body限制。git push时要上传大量数据,Nginx默认的client_max_body_size是1m,你push几百MB的提交时一定会报413 Request Entity Too Large。我在主站配置里统一加一行:
client_max_body_size 2048m; proxy_request_buffering off;这里proxy_request_buffering off是让Nginx把客户端数据边收边发给上游,而不是攒满整个请求体再转发。不然既占内存,对大文件push也不友好。
第三个坑是超时时间不要太短。Git clone空仓库时,服务器端可能长时间没有数据输出,如果proxy_read_timeout只有60秒,拉一个1GB大仓库时很容易在某个节点触发上游超时。我自己一般给到600s:
proxy_connect_timeout 15s; proxy_send_timeout 600s; proxy_read_timeout 600s;还有一个很大的提速点:浅克隆。很多场景下我们根本不需要仓库的全部分支历史,只要默认分支最新代码。可以跟团队明确一下,用git clone --depth=1替代完整克隆,镜像站压力小一大截,下载速度也快好几倍。我这边在内部文档里直接把浅克隆设为推荐操作。
3.5 大文件缓存:让重复下载走上快车道
release下载场景里,重复下载相同版本是非常普遍的。比如一个新版本发布,团队10个人先后都要下载,如果每次都回源,你服务器和GitHub之间的带宽完全不够用。加一块Nginx缓存能有效解决。
缓存配置可以放在http块:
proxy_cache_path /data/nginx_cache levels=1:2 keys_zone=github_dl_cache:10m max_size=80g inactive=14d use_temp_path=off;重点是levels=1:2的目录分级、max_size上限和inactive清理时间。我建议max_size设置成你磁盘容量的60%左右,留出余量给系统日志和临时文件;inactive选14天比较合适,release包生命周期也就这一两周。
然后在dl.example.com的server块里启用:
location ~* \.(tar\.gz|zip|tgz|bz2|exe|dmg|deb|rpm)$ { proxy_pass https://codeload.github.com; proxy_set_header Host codeload.github.com; proxy_cache github_dl_cache; proxy_cache_valid 200 14d; proxy_cache_lock on; proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; add_header X-Cache-Status $upstream_cache_status; }proxy_cache_lock on这行太重要了。不加它,当10个人同时请求同一个大文件时,Nginx会同时回源10次,把上游带宽打满不说,你服务器的CPU也会被白白耗掉。加了这个参数,同一时刻只有一个回源请求,其他人排队等待第一个结果写进缓存后再直接命中。
我实测过,缓存命中之后,大文件的下载速度基本取决于你服务器到用户之间的带宽,和GitHub官方链路完全无关了。如果你用的是带BGP线路的机器,体验会非常接近本地下载。
4. 上线后的维护与提速技巧
4.1 缓存命中率观测与预热
搭好之后别急着甩给同事用,先用你自己账号把常用的仓库、release包访问一遍,让缓存预热。看缓存命中率最直接的方式是看响应头的X-Cache-Status:
MISS:这一次走了上游GitHub,还没缓存;HIT:这次是你本地缓存直接返回,速度快;UPDATING:缓存正在后台刷新,当前请求用了旧缓存;EXPIRED:缓存过期,需要回源。
我这边的经验是,发布新版本时自己先手动下载一次release包,让缓存先热起来。不然同事同时抢着下载,第一次全MISS,体验还是卡。
对于页面HTML,我不建议开缓存。GitHub的页面包含大量动态内容(README渲染、文件列表、star数),缓存容易造成页面过时。但你可以在Nginx层面把静态资源(.css、.js、.png)单独设一条location,给静态资源做缓存,这个提升很明显。
4.2 再提速:调整TCP与HTTP参数
Nginx默认的内核参数不是为镜像站这种“高并发长连接”场景设计的。我调过几个参数后,页面加载速度和下载稳定性都有改善,在nginx.conf的http块里加:
keepalive_timeout 20s; keepalive_requests 1000; tcp_nopush on; tcp_nodelay on; sendfile on;tcp_nopush与tcp_nodelay看起来矛盾,但配合使用其实效果很好:前者优化大文件发送,后者优化小数据包低延迟。在高带宽机器上,sendfile能直接把文件从磁盘读到网卡,走内核零拷贝,CPU占用明显下降。
系统层面可以加大连接队列长度:
sysctl -w net.core.somaxconn=65535 sysctl -w net.ipv4.tcp_max_syn_backlog=65535有朋友问我需不需要上CDN,我的看法是:如果你的用户群体和你服务器所在区域比较集中,CDN的意义不大,反而多一层回源增加延迟;但用户分布在全国各地的话,靠一台服务器很难保证所有人快,套一层CDN、把缓存命中率做上去,确实能解决跨区域延迟问题。CDN配置时记得把缓存规则针对大文件做特殊调整,否则CDN节点全回源到你服务器,你还得再买带宽。
4.3 防止镜像站被滥用:限流与安全加固
镜像站一搭好,如果你把域名公开出去,很快就会被全网扫描到,然后被当成免费代理乱用。我最开始吃过这个亏,一个晚上跑掉几十GB流量,原因就是有人在用我这个镜像下大文件。几个实用手段:
第一,请求限流。对每个IP限制请求速率:
limit_req_zone $binary_remote_addr zone=github_limit:10m rate=5r/s; location / { limit_req zone=github_limit burst=20 nodelay; }这个rate=5r/s表示平均每秒最多5个请求,burst=20是允许瞬时突发20个,对正常浏览完全够用,但机器脚本会被拦下来。
第二,限制单IP的并发连接数:
limit_conn_zone $binary_remote_addr zone=perip:10m; limit_conn perip 10;防止有人开几十个线程同时从你这里拉文件。
第三,更保险的做法是启用Basic Auth,只有团队内部分享用户名密码的人能用。这个看需求,如果只是自己用,我建议直接开:
location / { auth_basic "GitHub Mirror"; auth_basic_user_file /etc/nginx/.htpasswd; }用openssl passwd -apr1生成密码放到.htpasswd即可。公开镜像站的流量控制难度指数级上升,不如一开始就限制使用范围。
5. 常见问题排查实录与避坑清单
5.1 现象一:网页打开白屏或样式丢失
这个八成是sub_filter没生效。很多人编译Nginx时没带http_sub_module,或者用了系统默认的nginx包,配置里写了sub_filter但Nginx启动时直接报错,根本没加载。先确认模块:
nginx -V 2>&1 | grep sub看到--with-http_sub_module才算OK。还有一个坑是sub_filter_types没加application/javascript,现在GitHub的JS都是text/javascript、application/javascript混合类型,漏掉就只替换HTML不替换JS,页面里很多功能按钮点起来会404。
5.2 现象二:能打开网页但git clone还是直连github.com
排查思路很简单——打开页面,右键查看源码,搜索一下github.com。如果还能搜到原始域名,说明sub_filter没生效或没匹配到。常见原因有二:一是页面某些响应是gzip压缩的,Nginx的sub_filter默认只对未经压缩的响应做替换,需要在http块里加proxy_set_header Accept-Encoding identity;禁用上游压缩;二是你设置的sub_filter_types不够全,漏了JSON类型。
GitHub的部分接口返回是JSON格式,原始内容里也有仓库地址,这种不替换的话,依赖接口路径的前端交互组件会继续指回官方域名。加上后基本能根治。
5.3 现象三:release下载到一半断了
这种问题首先看是不是缓存目录满了。Nginx写缓存失败时会回源,但本身传输也会受影响。我遇到过/data/nginx_cache这个目录所在的磁盘满了,Nginx报cache lock错误,下载直接404。
另外注意proxy_cache_lock和proxy_cache_use_stale的配合。如果上游网络抖动导致回源失败,默认配置会把错误直接抛给用户;我加了proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504后,Nginx会在回源失败时尝试用旧缓存兜底,至少用户还能拿到文件,只是可能不是最新版本。对release包来说,旧版本其实也能用。
5.4 快速排查速查表
| 异常现象 | 优先排查项 | 避坑操作 |
|---|---|---|
| HTTPS证书报错 | SSL证书文件路径、有效期 | 加定时任务自动续期,或用acme.sh hook重载nginx |
| 页面能开但图片裂 | sub_filter未替换avatars域名 | 确认配置了avatars.example.com反代 |
| clone提示401/403 | Host头没有透传 | proxy_set_header Host github.com;不可省 |
| push超过1MB报413 | client_max_body_size太小 | 设为2048m并关掉request_buffering |
| 间歇性502 | 上游超时参数太短 | proxy_read_timeout调大到600s |
| 502频繁出现在缓存场景 | proxy_cache_lock并发 | 确认use_temp_path=off,避免缓存写临时目录 |
| sub_filter部分生效 | 上游gzip未禁用 | 加proxy_set_header Accept-Encoding identity; |
| 下载速度无法跑满 | 本地vCPU/磁盘瓶颈 | 大文件走sendfile on;,确保磁盘IO够 |
5.5 一个容易被忽略的坑:API与登录场景
镜像站做反代时,GitHub的登录功能是没法直接用的。GitHub登录涉及cookie、CSRF token、OAuth回调,全部绑定官方域名,单纯用Nginx反代和换链没法把整套登录逻辑搬到你的域名下面。所以镜像站通常只能服务公开仓库的浏览、clone、下载这些场景,fork、star、issue评论、登录后操作都会有各种异常。
我建议你在使用文档里写清楚:“本镜像站仅用于公开仓库的浏览与下载,登录与写操作请使用官方地址。”这样能避免团队里有同事踩到“发现自己登不上镜像站”的坑。
如果你确实想给团队提供稳定的代码拉取渠道,比反代更稳的思路是我上面提过的方案组合:网页浏览走镜像站,代码下载优先用release缓存,clone时推荐git clone --depth=1,遇到私有仓库就仍然走官方客户端配合认证。把这个组合写进团队开发规范里,避免大家遇到问题再来问你。
5.6 我的几点实操心得
最后分享几个我自己摸出来的小技巧。
第一个,Nginx配置改完先做语法检查和reload,这已经成了肌肉记忆:
nginx -t && nginx -s reload但reload只对新连接生效,旧的长连接还会保留一会儿,如果改的是缓存或限流参数,建议直接systemctl restart nginx,别省这个事。
第二个,日志一定不要省。我在nginx.conf里单独给镜像站配了一份访问日志,字段带上$upstream_cache_status、$upstream_response_time和$request_time。排障时一眼能看出是上游慢还是本地慢。
log_format mirror '$remote_addr [$time_local] "$request" ' '$status $body_bytes_sent $request_time ' '$upstream_response_time $upstream_cache_status'; access_log /var/log/nginx/mirror_access.log mirror;第三个,别忘了监控磁盘和流量。我写过一个简单的cron脚本,每天检查缓存目录占用率,超过阈值自动清掉inactive时间最长的文件:
find /data/nginx_cache -type f -atime +14 -delete比自己盯着磁盘容量踏实多了。
镜像站这个东西,说到底是给“链路质量不理想环境下的开发工作”提供一个工程化兜底。你把这套流程跑通后,再遇到GitHub访问问题,心里就有底了:不用到处找别人搭的公共镜像,自己手里的这套随时能用、能调、能修。后续如果你想加raw文件加速、release大文件缓存甚至团队内部分发,都是一样的思路往下扩展就行。