惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

阮一峰的网络日志
阮一峰的网络日志
P
Proofpoint News Feed
Hacker News: Ask HN
Hacker News: Ask HN
T
Threatpost
WordPress大学
WordPress大学
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 【当耐特】
Know Your Adversary
Know Your Adversary
P
Palo Alto Networks Blog
S
SegmentFault 最新的问题
月光博客
月光博客
Latest news
Latest news
博客园 - Franky
T
Threat Research - Cisco Blogs
有赞技术团队
有赞技术团队
博客园_首页
T
The Exploit Database - CXSecurity.com
The Cloudflare Blog
人人都是产品经理
人人都是产品经理
C
Cybersecurity and Infrastructure Security Agency CISA
S
Schneier on Security
Simon Willison's Weblog
Simon Willison's Weblog
爱范儿
爱范儿
Security Latest
Security Latest
Scott Helme
Scott Helme
博客园 - 聂微东
T
Tor Project blog
美团技术团队
IT之家
IT之家
Stack Overflow Blog
Stack Overflow Blog
B
Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Cisco Blogs
Cisco Talos Blog
Cisco Talos Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
G
Google Developers Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
AWS News Blog
AWS News Blog
Jina AI
Jina AI
Vercel News
Vercel News
小众软件
小众软件
T
Tenable Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Forbes - Security
Forbes - Security
aimingoo的专栏
aimingoo的专栏
O
OpenAI News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The Last Watchdog
The Last Watchdog
Cloudbric
Cloudbric
AI
AI

Tony Bai

Twitter之父再出手:Block开源Buzz,要让人类和AI Agent「同工同权」 Go 密码学维护者放大招:把 Passkey 存成一行字符串,还顺手为 Go 1.28 写好了 API Loop Engineering才火两个月,硅谷已经卷出“Graph Engineering”了 我开源了 cc-session-migrate :让 Claude Code 会话在多台机器之间自由迁移 从掌上设备的失败到AI时代的基石:Java官方纪录片,揭开一门语言30年的生死赌局 “皇帝的新衣”一年后:对话Thorsten Ball谈Agentic编程 告别标签页焦虑:我让 AI 帮我做了个浏览器插件 TabQueue Bun刚把Zig重写成Rust,这个团队却用487天反向重写 为了一个函数名,Go官方吵了两个月:maps.Same提案近日正式通过 Go 1.28 路线图首度曝光:Cgo 告别C工具链?泛型容器将入标准库? 掌控外环:为什么“循环工程”的边界必须由人类死守? 171个“已批准”却迟迟未实现的提案:Go语言的十年“欠账清单” 别再往 Go 里塞 Java 了:拆解 spf13 的 Idiomatic Go 信仰 AI 不在乎代码烂不烂,但你的Token账单在乎:一项660次实验揭示的编程新常识 10倍速 TypeScript 7.0 正式发布,前Go产品经理:Go才是AI智能体时代的“天选语言” Bun 重写为 Rust 后,Zig 之父罕见开炮:“我们早就等着看你重写” 全新 AI 技术栈:模型、Harness、Loop 与自我进化的智能体 AI 重写 Bun 为Rust全过程揭秘:101万行代码、11天、64个Claude并行开工 MCP Server 架构模式全解析:5 种模式、4 个反模式,与那条不能越过的“工具数量红线” Go 私有模块拉取全解:凭据配置 + Vanity URL,个人与组织全覆盖 从“切歌小工具”到“零人工代码”:Claude Code 的诞生史,比科幻还科幻 如何使用 Claude Code 构建 AI 循环系统(Loops) 5 分钟上手 gvu:把 vanity import path 这件事,从“半天运维”变成一条命令 Go 对语言演化的保守态度,在未来 5 年是否仍然正确呢? 五年,三篇文章,一个我一直没真正解决的问题 别把“容易”当“简单”:Gin 框架作者撰文揭秘 88k Star 背后的架构哲学 每个 AI 工程师都应该知道的 20 个循环设计模式 cc-switch-cli:专为终端控与远程开发打造的 Claude Code 多模型切换工具! Andrej Karpathy 解析 Loop Engineering:构建“数日级”长程 Agent 的 9 条黄金法则 HashiCorp 创始人:AI 时代,我们为什么越来越需要有“品味”的程序员? HashiCorp 创始人:AI 时代,我们为什么越来越需要有“品味”的程序员? 一个 Rust 项目吃掉 75GB 硬盘?聊聊 Go 与 Rust 的“缓存焦虑”与拯救指南 折腾过各种语言后,我为什么总是回到 Go 语言? YC 揭秘 AI 原生组织:打造一家在睡梦中自我进化的公司 从 WordPress 到 Hugo:一个 20 年技术博客的迁移实录 偿还十年技术债:深度拆解 Go 1.27 的 GODEBUG 强力清理计划 浏览器里的“安全阴谋”:为什么 Go 1.27 的 UUIDv7 会离奇丧失随机性? Go 1.27新特性前瞻:泛型方法落地,标准库内建 UUID - Tony Bai AI 正在撕裂研发团队:狂欢的“托管派”与心碎的“守夜人” - Tony Bai 屠榜 CNCF!为什么在云原生时代,Go 语言能把 Java、C++ 和 Rust 堵在门外? 上千程序员自爆 AI 的“卧槽时刻”:是推开神界大门,还是跌入黑盒地狱? - Tony Bai 大模型正在见顶!传奇架构师:欢迎来到“平坦曲线时代” - Tony Bai Anthropic 40万大样本揭秘:AI 时代为什么“专家”身价暴涨? - Tony Bai 在 AI 编码时代,为什么我们依然选择 Go 而不是 Rust? DeepMind 亮出王炸:别再手写 Agent Harness 了,AI 已经学会自己写了! 为什么说“编译通过,就能运行”?Google 专家 Alice 揭秘 Rust 的工程美学与底层逻辑 谷歌 SRE 重磅白皮书:当 AI 自动写出 10 倍代码,谁来阻止系统崩溃? 别再省 Token 了!硅谷新共识:浪费算力才是唯一捷径 - Tony Bai Linux 内核顶级维护者:写了 35 年 C,是 Rust 让我重新找回了编程的乐趣 拒领上亿、封杀 AI:Zig 之父为什么 10 年不发 1.0? 写地道的 Go 语言,是否能让你成为了一个更好的开发者? - Tony Bai RSA 将死?Let’s Encrypt 押注 MTCs 迎战后量子时代 C++ 的权力游戏:一部关于妥协、背叛与重生的“史诗神剧” - Tony Bai 终结十年纠结:Go 新提案允许 Example 支持任意函数签名 - Tony Bai 2026年,大厂重构核心系统为何集体投向 Go? - Tony Bai “辛辛苦苦考上985,却发现AI能替代我90%的工作”:今天的高考,我们还在为什么而战? - Tony Bai 传奇黑客 Geohot 炮轰 AI Agent:这是软件工程史上代价最昂贵的灾难! 别把 Go 写成 Java:毁掉项目从过度架构开始 - Tony Bai 开源维护者的困境 - Tony Bai AI 时代如何真正掌握一门新技术?这份非主流学习指南建议永久收藏 - Tony Bai Go 生态17年大浪淘沙:2026年最值得引入的10个“神仙级”QoL工具包 - Tony Bai 再见样板代码!Go 官方新提案:函数一键转接口 - Tony Bai 写代码快 10 倍,不等于研发快 10 倍!Google 揭秘 AI 系统级瓶颈 Google I/O 2026:Jeff Dean 携 DeepMind 众神宣告,AI Agent 正在终结“标准化软件”时代 AI 优化 1.5ms,手写 0.02ms!Ghostty 作者痛批 AI 编程“平庸陷阱” Redis 之父吐槽现代前端的复杂性:我们到底是在解决问题,还是在制造问题? - Tony Bai 无痛消灭技术债:Google I/O 2026 开启 Go 自动重构时代 省下 10% CPU!Uber 揭秘 Go 栈扩容的隐秘代价 从 Go 迁移到 Rust - Tony Bai 悄悄用 Go 重写 AI 基础设施:NVIDIA 的 GPU 云平台为何选择 Go? Shopify 23,000 名工程师背后的 Claude Code 配置方案(你可以直接复刻的完整配置) Google 开源 AX 与 Agent Substrate:构建以 Agent 为核心的云原生计算底座 十年难题终获突破:揭秘 Go 1.27 接口逃逸分析优化 - Tony Bai
从手动 govanityurls + Nginx 迁移到 gvu:一次真实迁移记录
Tony Bai · 2026-07-08 · via Tony Bai

题图

本文永久链接https://tonybai.com/2026/07/08/migrate-from-govanityurls-to-gvu

大家好,我是Tony Bai。

上一篇《5 分钟上手 gvu》带大家跑通了一个全新项目从 0 到 1 接入 gvu 的过程。

但对于已经在生产环境跑了好几年 govanityurls 或其他私有Go模块拉取方案的团队(比如五年前的我们自己),更现实的问题是:已有的这套方案,要不要迁、怎么迁。

这篇文章就是要把这件事儿讲清楚,并且给出我们团队真实迁移的完整记录。

先把一件事说清楚:goproxy 和 gvu 不是一回事

这是我在写这篇文章之前,觉得最有必要单独拎出来讲的一点,因为这个误解我自己五年前也有过。

go getgo mod tidy 背后其实有两层完全不同的机制在起作用:

第一层:vanity import path 解析(govanityurls / gvu 解决的问题)

当你执行 go get mycompany.com/go/common 时,Go 工具链第一步要做的是搞清楚这个 import path 背后到底是哪个仓库、用什么版本控制系统。

它会去请求 https://mycompany.com/go/common?go-get=1,期待拿到一个包含 go-import meta 标签的 HTML 页面,告诉它"真正的仓库在这里"。

govanityurls 和 gvu 干的就是这一件事—— 提供这个"翻译层",把好看的、语义化的 import path 映射到真实仓库地址。它本身不存代码,不存版本,不存访问私有仓库的凭据,只是一次 HTTP 重定向式的元信息响应。

第二层:module 内容的拉取与缓存(GOPROXY 解决的问题)

搞清楚真实仓库地址之后,Go 工具链还需要实际拉取这个 module 的具体版本内容(代码、go.sum 校验信息)。

这一层默认走的是 proxy.golang.org,也可以是你自己搭的私有代理(Athens、GoProxy.io 私有化版本等),负责缓存、加速、以及对私有仓库做鉴权拉取。

两者的关系是:

vanity URL 解析发生在前,GOPROXY 拉取发生在后,一前一后,缺一不可,但解决的是完全不同的问题。

迁移到 gvu 之后,你的私有 module 依然需要一个 GOPROXY(或者用 GOPRIVATE/GONOSUMCHECK 让 Go 工具链直接绕过公共代理走直连)——gvu 只是替你省掉了手动维护 vanity 映射这一层,它不会、也不打算替代你现有的 GOPROXY。

五年前那几篇文章里,我们的架构其实一直是"govanityurls(第一层)+ 内部 GOPROXY(第二层)“的组合,这次迁移改动的只是第一层。

迁移前:五年前的架构长什么样

回顾一下五年积累下来的这套东西,大致是这样:

  • 一台机器上跑着 govanityurls 进程,读取一份手写的 vanity.yml,每新增一个私有仓库就要手动加一条映射
  • 前面挂一层 Nginx,做 HTTPS 终止、反代到 govanityurls 的端口
  • TLS 证书自己申请、自己续期
  • 内部 GOPROXY 单独部署,负责真正的 module 内容拉取和缓存

这套东西五年里总体稳定,但"新增一个仓库 = 改配置 + 重载 govanityurls"这个流程,一直是团队里被吐槽最多的一环,也是这次迁移最想解决的核心痛点。

迁移步骤

第一步:盘点现有的 vanity.yml

把所有存量映射列出来。我们当时 vanity.yml 大概是这样的结构(简化版):

paths:
  go/common:
    repo: https://internal-git.mycompany.com/go/common
    vcs: git
  go/authsdk:
    repo: https://internal-git.mycompany.com/go/authsdk
    vcs: git
  # ... 还有几十条

这一步的目的很简单:确认清楚现存映射一共有多少条,后面要在 gvu 里一一重建,同时顺手看一眼这些仓库的命名规律——这会决定下一步走哪条路径。

第二步:决定重建方式——逐条添加,还是用 wildcard routing 批量覆盖

盘点完存量映射之后,我们发现几十条里大多都遵循同一个规律:仓库地址都是 https://internal-git.mycompany.com/go/<repo>,vanity path 也都是 mycompany.com/go/<repo>,只有仓库名不同。这种情况正好是 gvu 新上线的 wildcard routing(通配符路由)想解决的场景。

不过用之前要先说明两个前提:

  • wildcard routing 是 Pro 账号的能力,免费账号(不管是匿名还是 Verified)都用不了,需要执行 gvu subscribe 升级;
  • wildcard routing 只能用在自定义域名下,默认的 gomod.io 不支持。也就是说,如果你打算用这个能力,第四步"配置自定义域名"要提到这一步之前先做完。

确认这两个前提之后,wildcard routing 分两种:

repo wildcard(覆盖同一个组织 / 路径前缀下的多个仓库)

gvu add 'go.mycompany.com/go/*' 'https://internal-git.mycompany.com/go/*.git'

注意命令里的单引号不是可有可无的——* 在 shell 里会被当成通配符展开,必须用单引号把带 * 的参数包起来,避免被 shell 提前解释掉。这条规则建立之后,go.mycompany.com/go/ 前缀下的任意仓库都会自动解析,不需要逐条添加:

import "go.mycompany.com/go/common"    // → internal-git.mycompany.com/go/common
import "go.mycompany.com/go/authsdk"   // → internal-git.mycompany.com/go/authsdk

以后团队新开一个仓库,只要命名遵循这个规律,直接就能用,不需要再执行任何 gvu add

subdir wildcard(覆盖 monorepo 里的多个子模块)

如果你的私有代码是放在一个 monorepo 里、每个子目录一个独立 Go module(需要 Go 1.25+),可以用另一种通配符:

gvu add go.mycompany.com/go/mono https://internal-git.mycompany.com/go/mono.git '--subdir=*'

--subdir=* 里的 * 会被请求路径里对应的子目录名替换,一条规则覆盖 monorepo 里所有子模块,同样不需要逐条声明。

两种通配符不能混用:一条路由要么是 repo wildcard,要么是 subdir wildcard,二选一;而且仓库 URL 里只允许出现一个 *

剩下命名不规律的几条,用 exact route 单独声明,并且优先级更高。

我们盘点出来的几十条里,有一条是历史遗留的老库,仓库地址和其余的不在一个路径下,这种直接用普通的精确路由声明即可:

gvu add go.mycompany.com/go/legacy https://internal-git.mycompany.com/legacy-repo/oldname.git

gvu 的路由匹配优先级是"精确匹配 > subdir wildcard > repo wildcard”,也就是说,即便这条 legacy 恰好也落在前面那条 repo wildcard 规则的覆盖范围内,精确路由也会优先生效,不用担心两条规则打架。

如果你的仓库命名不规整,或者分散在不同 Git 服务器 / 不同组织路径下,没办法用一条通配符规则覆盖,那就还是老老实实逐条添加:

gvu add gomod.io/common https://internal-git.mycompany.com/go/common
gvu add gomod.io/authsdk https://internal-git.mycompany.com/go/authsdk

第三步:配额是怎么算的

值得一提的是配额规则:一条 wildcard 路由,不管它实际覆盖了多少个仓库,只占用 Pro 账号配额里的 1 个路由名额(Pro 账号总配额 50 条)。也就是说,前面那条覆盖了十个仓库的 repo wildcard 规则,只算 1 条,这也是这次迁移里省下配额最明显的一处。

第四步:如果你要保留自己的域名

如果你不想让 go.mod 里的 module path 从 mycompany.com/go/common 变成 gomod.io/common(多数团队会希望保留自己的域名语义),或者像上一步那样打算用 wildcard routing,都需要先走自定义域名这条路:

  1. 用邮箱把匿名账号升级成 Verified 账号(gvu auth bind your@email.com),这一步是免费的,解锁自定义域名能力
  2. 在你的 DNS 服务商那里,给 go.mycompany.com 加一条指向 gvu 的 CNAME 记录
  3. 在 gvu 里把域名和这条 CNAME 绑定验证通过
  4. 如果要用 wildcard routing,还需要额外执行 gvu subscribe 升级到 Pro 账号(自定义域名本身免费账号就能用,但 wildcard routing 是 Pro 专属能力)

这一步本质上是把原来 Nginx 承担的"域名 + TLS"职责,转交给了 gvu。证书签发、续期这些事情,也就不用自己操心了。

第五步:验证

找几个存量项目,重新跑一遍 go mod tidy / go build,确认能正常解析到内部仓库。用了 wildcard routing 的话,记得确认一下 GOPRIVATE 里包含的是整个自定义域名前缀,而不是某一个具体仓库路径:

go env -w GOPRIVATE=go.mycompany.com

否则会出现"路由规则本身没问题,但个别 sub-package 解析不出来"这种容易让人摸不着头脑的情况。

另外建议多挑几个不同仓库名分别验证,而不是测一个就当全部通过——尤其是 repo wildcard,如果某个仓库名在目标 Git 服务器上其实不存在,go get 会报"repository not found",这种情况下用 git ls-remote* 换成实际仓库名单独测一下就能定位。

第六步:下线旧组件

确认所有存量 module 都迁移验证完毕之后,就可以把 govanityurls 进程和对应的 Nginx 配置下线了。注意,这里下线的只是"第一层",你的内部 GOPROXY(第二层)该怎么跑还怎么跑,不要连它一起下线。

迁移前后对比

迁移前(手动 govanityurls + Nginx) 迁移后(gvu)
需要自己运维的组件 govanityurls 进程、Nginx、TLS 证书 0
新增一个私有仓库的操作 vanity.yml → 重载 Nginx 命名规整的一批仓库:新增仓库时不需要任何操作;命名不规律的:一条 gvu add
覆盖 10 个命名规整仓库所需的路由数 10 条 vanity.yml 条目 1 条 repo wildcard 规则,只占 1 个配额名额(需要 Pro 账号 + 自定义域名)
域名迁移代价(仓库从一个平台挪到另一个平台) vanity.yml 对应条目,无需下游改动 gvu 里改一下映射,无需下游改动(两者在这一点上其实是一样的,这是 vanity URL 机制本身的优势,不是 gvu 独有)
TLS 证书 自己签、自己续期 gvu 托管
GOPROXY(module 拉取层) 不变 不变,依然需要

最后一行故意留在这里,是想再强调一次:这次迁移动的只是"翻译层",“拉取层"从头到尾没有变过,这也是我在文章开头要先把两者区分清楚的原因——如果团队里有人指望"上了 gvu 就不用管 GOPROXY 了”,迁移过程中大概率会踩这个认知上的坑。

小结

这次迁移前后花了不到半个小时,大部分时间花在盘点存量映射上,实际的重建操作本身很快——尤其是这次用上了 wildcard routing 之后,原本要逐条敲的十几条 gvu add,命名规整的十条合并成了一条 repo wildcard 规则就解决了,剩下一条历史遗留的老库单独用精确路由声明,优先级还能保证不会被 wildcard 规则误覆盖。

需要提醒一句:wildcard routing 是 Pro 账号才有的能力,而且必须搭配自定义域名使用,如果你的团队规模不大、存量仓库也没几个,逐条 gvu add 完全够用,不必为了这个能力专门升级付费账号——这个功能真正划算的场景,是仓库数量比较多、且命名规律统一的团队。

更重要的是想清楚了一件事:私有 module 拉取这件事,从来不是一个单一问题,而是"vanity 解析"和"内容拉取"两层问题叠在一起。gvu 解决的是前一层,这一层解决好之后,剩下的路由和证书维护成本基本归零。

下一篇,我会回到起源那篇文章埋的那个坑——白盒交付给客户时,怎么用 gvu 在客户组织内部 10 分钟重建一套私有 module 拉取方案。


还在为写 Agent 框架频频死循环、上下文爆炸而束手无策?我的新专栏 从0 开始构建 Agent Harness 将带你:

  • 抛弃臃肿框架,回归“驾驭工程 (Harness Engineering)”的第一性原理
  • 用 Go 语言手写 ReAct 循环、并发拦截与上下文压缩引擎等,复刻极简OpenClaw
  • 构建坚不可摧的 Safety Middleware 与飞书人工审批防线
  • 在底层实现 Token 成本审计、链路追踪与自动化跑分评估
  • 从“调包侠”进化为掌控大模型边界的“AI 操作系统架构师”

扫描下方二维码,开启从 0 开始构建Agent Harness 的实战之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。