Configuring gopls module proxy in an air-gapped container
In an air-gapped or restricted-network DevContainer, go build hangs trying to reach proxy.golang.org and gopls reports “could not import” for every external package. The fix is to point Go at an internal module proxy and disable the public checksum database without losing integrity guarantees. This page configures GOPROXY, GOSUMDB, and a vendoring fallback so both the compiler and the language server resolve offline. It extends the Go Development Environment with gopls & Modules cluster.
Prerequisites
- Go 1.22+ in the container
- An internal module proxy reachable from the container (Athens, JFrog, or a cache mirror)
- The proxy’s CA certificate if it terminates TLS internally
How-To Steps
-
Point Go at the internal proxy and disable the public sum database via
containerEnv:{ "image": "mcr.microsoft.com/devcontainers/go:1.22@sha256:b91a...", "containerEnv": { "GOPROXY": "https://goproxy.internal.example.com", "GOSUMDB": "off", "GOFLAGS": "-mod=mod" }, "remoteUser": "vscode" }Verify:
go env GOPROXYprints the internal URL. -
Trust the proxy’s CA if it uses an internal certificate, so TLS verification still passes:
{ "postCreateCommand": "sudo cp .devcontainer/internal-ca.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates" } -
Tell gopls to use the same environment — it inherits the Go env, but make module mode explicit:
{ "customizations": { "vscode": { "extensions": ["golang.go"], "settings": { "go.toolsManagement.autoUpdate": false, "gopls": { "build.directoryFilters": ["-node_modules"] } } } } }Disabling tool auto-update prevents gopls from trying to reach the public proxy on startup.
-
Provide a vendoring fallback for fully offline builds:
go mod vendor go build -mod=vendor ./... # builds with zero network accessVerify: disconnect the network and confirm
go build -mod=vendor ./...still succeeds.
Common Pitfalls
| Symptom | Root Cause | Remediation |
|---|---|---|
go build hangs then times out | Default GOPROXY still points to proxy.golang.org | Set GOPROXY to the internal mirror |
checksum mismatch / verification error | Public GOSUMDB unreachable | Set GOSUMDB=off and rely on the proxy’s integrity |
| TLS handshake failure to proxy | Internal CA not trusted | Install the CA and run update-ca-certificates |
| gopls re-downloads tools on start | go.toolsManagement.autoUpdate enabled | Disable it; preinstall tools in the image |
| Works in terminal, not in editor | gopls started before env applied | Reload the window after postCreateCommand |
Conclusion
The essential invariant: every Go entrypoint — compiler, go mod, and gopls — must read the same GOPROXY/GOSUMDB and trust the same CA. Set them in containerEnv so the environment is identical for all three, and keep a vendored copy as the true-offline fallback.
FAQ
Is GOSUMDB=off safe?
It disables the public checksum database, not module verification entirely. go.sum still verifies downloads against recorded hashes. Pair it with an internal proxy you trust, or set GONOSUMCHECK only for internal module prefixes via GONOSUMDB.
Why does gopls still try to reach the internet?
Tool auto-update fetches from the public proxy. Disable go.toolsManagement.autoUpdate and bake the gopls binary into the image during build.
Related
- Go Development Environment with gopls & Modules — the parent cluster.
- Caching Go module downloads with a named volume — persisting the module cache across rebuilds.
- Cross-compiling Go binaries inside containers — building for other targets offline.