Private Go Modules and GOPRIVATE
How to go get a private GitHub or GitLab repository, fix terminal prompts disabled and 410 Gone errors, and set GOPRIVATE, git credentials and CI access.
Getting a module from a private repository is one of the most searched Go problems. By default, the go command downloads modules through the public proxy at proxy.golang.org and checks them against the public checksum database. Neither can see your private repositories, so you need to tell Go to fetch them directly and give git a way to log in.
The Errors You See
Without any setup, go get github.com/acme/billing for a private repo fails with messages like these:
go: github.com/acme/billing@v1.2.0: reading https://proxy.golang.org/github.com/acme/billing/@v/v1.2.0.info: 404 Not Found
verifying github.com/acme/billing@v1.2.0: github.com/acme/billing@v1.2.0: reading https://sum.golang.org/lookup/github.com/acme/billing@v1.2.0: 410 Gone
fatal: could not read Username for 'https://github.com': terminal prompts disabled
The first two come from the public proxy and checksum database, which cannot see private code. The third comes from git: the go command runs git with prompts turned off, so it cannot ask for your password.
Step 1: Set GOPRIVATE
GOPRIVATE lists module path patterns that Go should fetch directly and never send to the public proxy or checksum database:
go env -w GOPRIVATE=github.com/acme/*
Use commas for several patterns, for example github.com/acme/*,gitlab.example.com. go env -w saves the setting for your user, so it applies to every project.
Step 2: Give git Credentials
Go uses git under the hood, so git must be able to clone the repository without asking anything. Pick one approach:
If you already push to GitHub with an SSH key, tell git to use SSH for GitHub URLs:
git config --global url."git@github.com:".insteadOf "https://github.com/"
Go asks git for https://github.com/acme/billing, and git quietly uses git@github.com:acme/billing with your key.
Then fetch again:
go get github.com/acme/billing@latest
Step 3: CI and Docker Builds
CI machines need the same two things. A typical GitHub Actions setup:
env:
GOPRIVATE: github.com/acme/*
steps:
- run: git config --global url."https://x-access-token:${{ secrets.GO_MODULES_TOKEN }}@github.com/".insteadOf "https://github.com/"
- run: go build ./...
The token comes from a repository secret, never from the code.
Never put tokens in go.mod or code:
Tokens in go.mod, Dockerfiles or committed config files leak to anyone who can read the repository or the image. Pass them through secrets and environment variables at build time only.
Related Settings
GONOSUMDBandGONOPROXYgive finer control.GOPRIVATEsets both at once, which is what most people need.- Companies sometimes run their own module proxy, such as Athens or Artifactory. Then
GOPROXYpoints to it, for exampleGOPROXY=https://goproxy.corp.example,direct. GOFLAGS=-mod=modis unrelated to private modules. Do not add it hoping to fix authentication errors.
Module path must match the repository:
The module line in the private repository's go.mod must match the path you import, including case. A mismatch fails with module declares its path as ... but was required as ..., even when authentication works.
Private modules working:
go env GOPRIVATE shows your organization's pattern, git clone https://github.com/acme/billing works in a terminal without a prompt, and go get succeeds. Once all three are true locally, repeat them with secrets in CI.
Summary
Private modules fail because the public proxy and checksum database cannot see them and git cannot prompt for a password. Set GOPRIVATE to your organization's path pattern, give git non-interactive credentials through an SSH insteadOf rule or a token in .netrc, and do the same in CI using secrets. Keep tokens out of code and make sure the module path in go.mod matches the import path.