1. 首页
  2. GoLang

用 Nginx 搭建 Go Module Vanity Import 服务(内部模块统一分发方案)

一、为什么需要 Vanity Import

在 Go 项目中,我们通常会引用公司内部 Git 仓库的模块:

import "code.example.com/common/util"

但 Go 在拉取模块时,必须知道这个 import path 对应的真实仓库地址

如果不做任何处理,go get 会直接访问该域名,却拿不到仓库信息。

通过 Nginx + Go Vanity Import​ 机制,我们可以:

  • 隐藏真实 Git 仓库地址

  • 统一公司内部 Go 模块命名规范

  • 让其他项目组透明引用,无需关心底层 Git 地址

二、服务端原理简述

Go 工具链在拉取模块时,会访问:

https://code.example.com/common/util?go-get=1

如果返回的 HTML 中包含如下 <meta> 标签:

<meta name="go-import"
      content="code.example.com/common/util git https://git.example.com/team/util.git">

Go 就会自动执行:

git clone https://git.example.com/team/util.git

三、服务端 Nginx 完整配置(可直接复制)

HTTP → HTTPS 强制跳转

# ============================================================
# HTTP → HTTPS
# ============================================================
server {
    listen 80;
    server_name code.example.com;
    return 301 https://$host$request_uri;
}

模块映射表

# ============================================================
# 模块映射表 —— 用 $uri(不含查询参数)
# ============================================================
map $uri $go_vcs_prefix {
    /common/util    "code.example.com/common/util git https://git.example.com/team/util.git";
    /sdk/logger    "code.example.com/sdk/logger git https://git.example.com/team/logger.git";
}

HTTPS 主服务

# ============================================================
# HTTPS 主服务
# ============================================================
server {
    listen 443 ssl;
    server_name code.example.com;

    # 证书路径
    ssl_certificate     /etc/nginx/cert/example.com/cert.crt;
    ssl_certificate_key /etc/nginx/cert/example.com/cert.key;

    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # ---- Go Vanity Import(核心) ----
    location ~ ^/(common|sdk)/[^/]+$ {
        if ($go_vcs_prefix = "") {
            return 404;
        }

        default_type text/html;
        return 200 '<!DOCTYPE html>
<html>
<head>
<meta name="go-import" content="$go_vcs_prefix">
</head>
<body>Go Module Redirect</body>
</html>';
    }

    # ---- 根路径健康检查 ----
    location = / {
        return 200 'Go module vanity import server\n';
    }

    # ---- 其他全部 404 ----
    location / {
        return 404;
    }
}

四、客户端需要哪些配置(重点)

告诉 Go 这是私有模块(必须)

如果不配置,Go 会尝试走公共代理(如 proxy.golang.org),导致拉取失败。

go env -w GOPRIVATE="code.example.com"

效果:

  • 不走公共 proxy

  • 不走 checksum 校验(避免 sum.golang.org 报错)

确保 Git 能访问真实仓库

Vanity Import 只负责“指路”,最终仍然由 Git 拉取代码。

方式一:SSH(推荐)

git config --global url."git@example.com:team/".insteadOf "https://git.example.com/team/"

方式二:HTTPS + Token

git config --global url."https://<token>@git.example.com/team/".insteadOf "https://git.example.com/team/"

在项目中引用模块

import "code.example.com/common/util"
go get code.example.com/common/util

五、验证是否生效

curl https://code.example.com/common/util?go-get=1

应返回:

<meta name="go-import"
      content="code.example.com/common/util git https://git.example.com/team/util.git">

六、常见问题

为什么一定要配置 GOPRIVATE

因为 Go 默认会尝试通过公共代理拉取模块,私有模块必须显式声明。

能否支持子模块?

支持,只要仓库结构一致即可:

import "code.example.com/common/util/subpkg"

一个 import path 能对应多个仓库吗?

不建议,Go 以模块根路径为准。

七、完整配置如下

# ============================================================
# HTTP → HTTPS
# ============================================================
server {
    listen 80;
    server_name code.example.com;
    return 301 https://$host$request_uri;
}

# ============================================================
# 模块映射表 —— 用 $uri(不含查询参数)
# ============================================================
map $uri $go_vcs_prefix {
    /common/util    "code.example.com/common/util git https://codeup.aliyun.com/697822a7cf8993734af2c8c3/util.git";
}

# ============================================================
# HTTPS 主服务
# ============================================================
server {
    listen 443 ssl;
    server_name code.example.com;

    #证书路径
    ssl_certificate /usr/local/nginx/cert/example.com/cert.crt;
    #私钥路径
    ssl_certificate_key /usr/local/nginx/cert/example.com/cert.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # ---- Go Vanity Import(核心) ----
    # 匹配 /common/xxx 和 /sdk/xxx(不含子路径)
    location ~ ^/(common|sdk)/[^/]+$ {
        # 没匹配到映射表的,直接 404
        if ($go_vcs_prefix = "") {
            return 404;
        }

        default_type text/html;
        return 200 '<!DOCTYPE html>
<html>
<head>
<meta name="go-import" content="$go_vcs_prefix">
</head>
<body>Go Module Redirect</body>
</html>';
    }

    # ---- 根路径 ----
    location = / {
        return 200 'Go module vanity import server\n';
    }

    # ---- 其他全部 404 ----
    location / {
        return 404;
    }
}

八、总结

通过这套方案,你可以:

用 Nginx 实现一个轻量级 Go Module 路由层

统一内部模块命名

让多个项目组无感知引用

服务端集中维护,客户端配置简单


TOP