Go Modules Guide
Artifact Keeper provides a Go module proxy compatible with the GOPROXY protocol for hosting Go modules.
Endpoint
Go module operations use the /go/{repo} endpoint:
http://localhost:8080/go/myrepoThis implements the Go module proxy protocol.
Configuration
GOPROXY Environment Variable
Configure Go to use Artifact Keeper as a module proxy:
export GOPROXY="http://localhost:8080/go/myrepo,direct"For production use with HTTPS:
export GOPROXY="https://registry.example.com/go/myrepo,direct"The direct fallback allows Go to fetch modules directly from version control if not found in the proxy.
Multiple Proxies
Chain multiple proxies with fallback behavior:
export GOPROXY="https://registry.example.com/go/private,https://proxy.golang.org,direct"Go will try each proxy in order until one succeeds.
Private Modules
For private modules that should skip checksum verification:
export GOPRIVATE="github.com/yourcompany/*,gitlab.yourcompany.com/*"This automatically sets both GONOPROXY and GONOSUMDB for the specified patterns.
Alternatively, configure individually:
# Skip proxy for these modules (fetch directly)export GONOPROXY="github.com/yourcompany/*"
# Skip checksum database verificationexport GONOSUMDB="github.com/yourcompany/*"go env Settings
Make configuration permanent:
go env -w GOPROXY="https://registry.example.com/go/myrepo,direct"go env -w GOPRIVATE="github.com/yourcompany/*"View current settings:
go env GOPROXYgo env GOPRIVATEReset to defaults:
go env -u GOPROXYgo env -u GOPRIVATEDownloading Modules
go get
Download and add a module to your project:
go get github.com/yourcompany/mymodule@latestGet a specific version:
go get github.com/yourcompany/mymodule@v1.2.3go get github.com/yourcompany/mymodule@v1.2.0Get a specific commit:
go get github.com/yourcompany/mymodule@abc1234go mod download
Download modules without adding to go.mod:
go mod download github.com/yourcompany/mymodule@v1.2.3Download all dependencies:
go mod downloadUsing Modules
Add to your go.mod:
module github.com/yourcompany/myapp
go 1.21
require ( github.com/yourcompany/mymodule v1.2.3)Import in your code:
package main
import ( "github.com/yourcompany/mymodule")
func main() { mymodule.DoSomething()}Publishing Modules
Prepare Your Module
Create a go.mod file:
go mod init github.com/yourcompany/mymoduleExample go.mod:
module github.com/yourcompany/mymodule
go 1.21
require ( github.com/sirupsen/logrus v1.9.3)Tag a Release
Go modules use Git tags for versioning:
git tag v1.0.0git push origin v1.0.0For pre-release versions:
git tag v1.0.0-beta.1git push origin v1.0.0-beta.1Upload to Artifact Keeper
Use the HTTP API to publish your module:
# Create a zip archive of your modulegit archive --format=zip --prefix=mymodule@v1.0.0/ v1.0.0 -o mymodule-v1.0.0.zip
# Upload to Artifact Keepercurl -X POST \ -H "Authorization: Bearer your-auth-token" \ -F "file=@mymodule-v1.0.0.zip" \ -F "format=go" \ -F "name=github.com/yourcompany/mymodule" \ -F "version=v1.0.0" \ https://registry.example.com/api/artifactsAutomated Publishing Script
#!/bin/bashset -e
MODULE_NAME="github.com/yourcompany/mymodule"VERSION=${1:-$(git describe --tags --abbrev=0)}REGISTRY="https://registry.example.com"TOKEN="${ARTIFACT_KEEPER_TOKEN}"
echo "Publishing ${MODULE_NAME}@${VERSION} to ${REGISTRY}"
# Create zip archivegit archive --format=zip --prefix="${MODULE_NAME}@${VERSION}/" "${VERSION}" -o "/tmp/${MODULE_NAME##*/}-${VERSION}.zip"
# Upload to registrycurl -X POST \ -H "Authorization: Bearer ${TOKEN}" \ -F "file=@/tmp/${MODULE_NAME##*/}-${VERSION}.zip" \ -F "format=go" \ -F "name=${MODULE_NAME}" \ -F "version=${VERSION}" \ "${REGISTRY}/api/artifacts"
# Cleanuprm "/tmp/${MODULE_NAME##*/}-${VERSION}.zip"
echo "Successfully published ${MODULE_NAME}@${VERSION}"Private Modules Workflow
Setup for Private Modules
Configure GOPRIVATE to bypass public proxies:
# Set for all company modulesexport GOPRIVATE="github.com/yourcompany/*,gitlab.yourcompany.com/*"
# Use only your private registryexport GOPROXY="https://registry.example.com/go/private,direct"Authentication
For authenticated access to private modules:
# Using .netrc for HTTP basic authcat >> ~/.netrc <<EOFmachine registry.example.comlogin your-usernamepassword your-tokenEOF
chmod 600 ~/.netrcOr use Git credential helpers:
git config --global credential.helper storePrivate Module Example
module github.com/yourcompany/myapp
go 1.21
require ( github.com/yourcompany/private-lib v1.0.0 github.com/yourcompany/internal-pkg v2.3.1)# Download private modulesgo mod download
# Build with private dependenciesgo buildVersion Management
Semantic Versioning
Go modules use semantic versioning:
v1.2.3 │ │ │ │ │ └─ Patch: Bug fixes │ └─── Minor: New features, backward compatible └───── Major: Breaking changesVersion Selection
In go.mod:
require ( github.com/yourcompany/mymodule v1.2.3 // Exact version github.com/yourcompany/other v1.2.0 // Minimum version)Update Modules
Update to latest compatible version:
go get -u github.com/yourcompany/mymoduleUpdate to latest patch release:
go get -u=patch github.com/yourcompany/mymoduleUpdate all dependencies:
go get -u ./...List Available Versions
go list -m -versions github.com/yourcompany/mymoduleView Module Information
# Show module detailsgo list -m github.com/yourcompany/mymodule
# Show all dependenciesgo list -m all
# Show dependency graphgo mod graphTidy Dependencies
Remove unused dependencies and add missing ones:
go mod tidyReplace Directive
For local development or forked modules:
module github.com/yourcompany/myapp
go 1.21
require ( github.com/yourcompany/mymodule v1.2.3)
// Use local version for developmentreplace github.com/yourcompany/mymodule => ../mymodule
// Or use a forkreplace github.com/yourcompany/mymodule => github.com/yourname/mymodule v1.2.4Remove replace directives for production:
# Temporarily remove replace directivesgo mod edit -dropreplace=github.com/yourcompany/mymoduleIntegration with CI/CD
GitHub Actions
name: Publish Go Moduleon: push: tags: - 'v*'
jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- uses: actions/setup-go@v5 with: go-version: '1.21'
- name: Run tests run: go test ./...
- name: Extract version id: version run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Create module archive run: | MODULE_NAME=$(go list -m) git archive --format=zip --prefix="${MODULE_NAME}@${{ steps.version.outputs.VERSION }}/" \ ${{ steps.version.outputs.VERSION }} -o module.zip
- name: Publish to Artifact Keeper env: ARTIFACT_KEEPER_TOKEN: ${{ secrets.ARTIFACT_KEEPER_TOKEN }} run: | MODULE_NAME=$(go list -m) curl -X POST \ -H "Authorization: Bearer ${ARTIFACT_KEEPER_TOKEN}" \ -F "file=@module.zip" \ -F "format=go" \ -F "name=${MODULE_NAME}" \ -F "version=${{ steps.version.outputs.VERSION }}" \ https://registry.example.com/api/artifactsGitLab CI
publish: image: golang:1.21 stage: deploy script: - MODULE_NAME=$(go list -m) - VERSION=${CI_COMMIT_TAG} - git archive --format=zip --prefix="${MODULE_NAME}@${VERSION}/" ${VERSION} -o module.zip - | curl -X POST \ -H "Authorization: Bearer ${ARTIFACT_KEEPER_TOKEN}" \ -F "file=@module.zip" \ -F "format=go" \ -F "name=${MODULE_NAME}" \ -F "version=${VERSION}" \ https://registry.example.com/api/artifacts only: - tagsJenkins Pipeline
pipeline { agent any
tools { go 'Go 1.21' }
environment { MODULE_NAME = sh(script: 'go list -m', returnStdout: true).trim() REGISTRY = 'https://registry.example.com' }
stages { stage('Test') { steps { sh 'go test ./...' } }
stage('Publish') { when { tag pattern: 'v\\d+\\.\\d+\\.\\d+', comparator: 'REGEXP' } steps { withCredentials([ string(credentialsId: 'artifact-keeper-token', variable: 'TOKEN') ]) { sh ''' VERSION=${TAG_NAME} git archive --format=zip --prefix="${MODULE_NAME}@${VERSION}/" ${VERSION} -o module.zip
curl -X POST \ -H "Authorization: Bearer ${TOKEN}" \ -F "file=@module.zip" \ -F "format=go" \ -F "name=${MODULE_NAME}" \ -F "version=${VERSION}" \ ${REGISTRY}/api/artifacts ''' } } } }}Docker Build with Private Modules
FROM golang:1.21 AS builder
WORKDIR /app
# Configure Go to use private registryENV GOPROXY="https://registry.example.com/go/myrepo,direct"ENV GOPRIVATE="github.com/yourcompany/*"
# Copy go.mod and go.sumCOPY go.mod go.sum ./
# Download dependenciesRUN --mount=type=secret,id=netrc,target=/root/.netrc \ go mod download
# Copy source codeCOPY . .
# Build applicationRUN go build -o app .
FROM alpine:latestCOPY --from=builder /app/app /appENTRYPOINT ["/app"]Build with secrets:
docker build --secret id=netrc,src=$HOME/.netrc -t myapp .Troubleshooting
Authentication Failures
Verify GOPROXY is set correctly:
go env GOPROXYTest proxy access:
curl https://registry.example.com/go/myrepo/github.com/yourcompany/mymodule/@v/listCheck .netrc permissions:
ls -la ~/.netrc # Should be 600Module Not Found
Clear module cache:
go clean -modcacheVerify module exists in proxy:
curl https://registry.example.com/go/myrepo/github.com/yourcompany/mymodule/@v/listEnable verbose output:
go get -v github.com/yourcompany/mymodule@v1.2.3Checksum Mismatch
For private modules, ensure GOPRIVATE is set:
go env -w GOPRIVATE="github.com/yourcompany/*"Or disable checksum verification:
export GONOSUMDB="github.com/yourcompany/*"Clear checksum database:
rm -rf $GOPATH/pkg/sumdbVersion Not Available
List available versions:
go list -m -versions github.com/yourcompany/mymoduleRefresh module cache:
GOPROXY=direct go get github.com/yourcompany/mymodule@v1.2.3Proxy Timeout
Increase timeout:
export GOPROXY_TIMEOUT=30 # Default is 10 secondsCheck proxy health:
curl -I https://registry.example.com/go/myrepoBest Practices
Module Structure
Organize your module properly:
mymodule/├── go.mod├── go.sum├── README.md├── LICENSE├── pkg/│ └── public/ # Public API│ └── api.go└── internal/ # Internal implementation └── impl.goVersioning Strategy
- Use semantic versioning strictly
- Tag releases with
vprefix:v1.2.3 - Major version ≥2 requires
/vNsuffix in module path:
module github.com/yourcompany/mymodule/v2
go 1.21Documentation
Include comprehensive documentation:
// Package mymodule provides utilities for doing X.//// Basic usage://// client := mymodule.New()// result, err := client.DoSomething()//// For advanced usage, see the examples.package mymoduleTesting Before Publishing
# Run all testsgo test ./...
# Check for race conditionsgo test -race ./...
# Verify module integritygo mod verify
# Check for vulnerabilitiesgo list -json -m all | go run golang.org/x/vuln/cmd/govulncheck@latest -mode=binary
# Vet codego vet ./...
# Run lintergolangci-lint runMinimal Version Selection
Go uses minimal version selection. Specify minimum required versions:
require ( github.com/yourcompany/mymodule v1.2.0 // Requires at least v1.2.0)Vendor Dependencies
For reproducible builds:
# Create vendor directorygo mod vendor
# Build using vendorgo build -mod=vendorCommit vendor directory for air-gapped environments.
Module Proxy Caching
Go caches module downloads. To serve from cache:
# Check cache locationgo env GOMODCACHE
Retract Versions
Mark versions as retracted in go.mod:
retract ( v1.0.0 // Published accidentally v1.0.1 // Contains critical bug)See Also
- Security Scanning - Automatic vulnerability scanning for Go modules
- Security Policies - Configure policies to block vulnerable modules