离线终端执行 go mod download 必然失败,需在有网机器用相同 go 版本执行 go mod download 完整拉取依赖至 $gopath/pkg/mod/cache,并设 goproxy=direct 后离线构建。

离线终端执行 go mod download 必然失败,必须提前预拉取
在限制外网的终端上直接运行 go mod download 或 go build 会立刻报错,典型错误如:proxy.golang.org: no such host、timeout 或 failed to fetch。Go 工具链默认所有模块解析和下载都走网络,不提供“断网回退”机制。核心解法不是在离线机上想办法联网,而是在有网机器上把整个依赖树完整落盘——包括模块源码、校验和、元信息,全部塞进 $GOPATH/pkg/mod/cache 目录结构里。
关键动作顺序不能错:
- 先确保目标项目
go.mod和go.sum已提交且无未暂存修改(否则go mod download可能引入非预期版本) - 在有网机器上,用与离线机**完全一致的 Go 版本**(如
go1.21.6)执行go mod download - 执行
go mod download -x查看实际下载路径,确认所有模块都写入$GOPATH/pkg/mod/cache/download/子目录 - 打包时必须保留完整目录结构,例如
github.com/gorilla/mux@v1.8.0对应路径是github.com/gorilla/mux/@v/v1.8.0.info等多个文件,不能只拷源码
GOPROXY=direct 是离线构建的前提,不是可选项
离线机上若不设 GOPROXY=direct,Go 仍会尝试连接默认代理(如 https://proxy.golang.org)或你之前配置过的国内镜像(如 https://goproxy.cn),哪怕缓存已齐全,也会卡在网络超时上。这个环境变量必须显式设置,且优先级高于任何全局配置。
常见误区:
- 以为设了
GOPROXY=off就行——不对,off会禁用所有代理逻辑但不跳过远程校验,仍可能触发 DNS 查询;direct才表示“本地缓存即权威”,完全绕过网络请求 - 只在当前 shell 设置,忘了写入
~/.bashrc或~/.zshrc,导致 CI 脚本或新终端失效 - 用 Docker 构建时,在
Dockerfile里漏掉ENV GOPROXY=direct,结果构建阶段仍尝试联网
私有模块和 replace 依赖需单独处理
如果 go.mod 里有 replace 指向公司内网 Git 地址(如 replace git.mycompany.com/lib/foo => ./local-foo),或依赖未打 tag 的私有分支,go mod download 不会拉取这些内容——它只处理远程模块索引能解析的部分。这类依赖必须手动同步。
操作要点:
- 对每个
replace条目,在有网机器上 clone 对应仓库到本地路径,确保 commit ID 与go.mod中标注一致 - 打包时把
./local-foo整个目录一起拷到离线机相同相对位置 - 离线机上运行
go mod edit -replace=git.mycompany.com/lib/foo=./local-foo(注意路径是相对于项目根目录) - 验证:执行
go list -m all | grep foo,输出应显示git.mycompany.com/lib/foo v0.0.0-20240101000000-abcdef123456 => ./local-foo
交叉编译和 cgo 依赖容易被忽略
离线构建常用于国产 OS(麒麟、统信)或嵌入式设备,此时仅复制 Go 模块远远不够。若项目启用 cgo(默认开启),net、os/user 等包会调用系统 C 库,编译时需目标机器已安装对应头文件和静态库(如 libc6-dev、libpthread.a)。纯 Go 编译(CGO_ENABLED=0)虽可绕过,但会导致 DNS 解析降级,可能无法读取 /etc/resolv.conf。
检查方式:
- 运行
go list -f '{{.CgoFiles}}' ./...,非空输出即含 cgo 文件 - 对关键第三方包(如
github.com/mattn/go-sqlite3),提前在目标系统上编译好静态链接版本并replace进来 - 若用 Alpine 镜像构建,记得
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/,否则 HTTPS 请求会因证书缺失失败
最易被跳过的点:离线机 go.sum 哈希不匹配。哪怕所有文件都拷对了,只要 go.sum 里某条记录的 checksum 和缓存中实际文件不一致,go build 就会拒绝构建。务必核对 go.sum 是否与有网机器生成的一致,不要手动编辑或删减。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











