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

  1. 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 GOPROXY prints the internal URL.

  2. 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"
    }
    
  3. 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.

  4. Provide a vendoring fallback for fully offline builds:

    go mod vendor
    go build -mod=vendor ./...   # builds with zero network access
    

    Verify: disconnect the network and confirm go build -mod=vendor ./... still succeeds.

Common Pitfalls

SymptomRoot CauseRemediation
go build hangs then times outDefault GOPROXY still points to proxy.golang.orgSet GOPROXY to the internal mirror
checksum mismatch / verification errorPublic GOSUMDB unreachableSet GOSUMDB=off and rely on the proxy’s integrity
TLS handshake failure to proxyInternal CA not trustedInstall the CA and run update-ca-certificates
gopls re-downloads tools on startgo.toolsManagement.autoUpdate enabledDisable it; preinstall tools in the image
Works in terminal, not in editorgopls started before env appliedReload 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.