Devproxy intercepts go (and npm/npx) invocations and transparently runs them inside
ephemeral containers. Package installation code never executes on the host, isolating it from
supply-chain attacks such as malicious install scripts or post-install hooks.
curl -fsSL https://raw.githubusercontent.com/TykTechnologies/devproxy/refs/heads/main/install.sh | bashThen activate in the current shell:
source ~/.zshrc # or ~/.bashrcThe install script places a proxy script at ~/.local/bin/devproxy/go and prepends that
directory to PATH. Every go command is intercepted by the proxy, which:
- Sources
~/.devproxyfor configuration. - Runs the command inside an ephemeral container using the image defined by
GODEV_IMAGE. - Mounts the working directory and the host GOPATH at the same absolute paths so all module cache, replace directives, and IDE-generated absolute paths resolve identically inside and outside the container.
- Forwards the relevant Go environment variables (
GOPROXY,GOPRIVATE,GONOSUMDB, etc.) from the host's real Go installation.
go env and go help are always passed through to the real binary without starting a
container.
| Variable | Default | Description |
|---|---|---|
GO_BINARY |
(set by installer) | Path to the real go binary on the host |
CONTAINER_RUNTIME |
auto-detect | podman or docker |
GODEV_IMAGE |
golang:1.25 |
Container image used for all go commands |
GODEV_EXTRA_VOLUMES |
(unset) | Colon-separated list of extra host paths to mount |
GODEV_NETRC |
(unset) | Set to 1 to enable private module credentials |
DEVPROXY_UNSECURE |
(unset) | Set to 1 to bypass the container entirely |
Set GODEV_NETRC=1 in ~/.devproxy (or per-command) to mount credentials into the
container. The proxy mounts the following files read-only when the variable is set:
| File | Container path | Purpose |
|---|---|---|
~/.netrc |
/root/.netrc |
HTTPS credentials (username / PAT) |
~/.gitconfig |
/root/.gitconfig |
URL rewrites, credential helper config |
$SSH_AUTH_SOCK |
/tmp/ssh_auth.sock |
SSH agent socket for key-based auth |
The SSH agent socket is forwarded automatically if SSH_AUTH_SOCK is set in the environment,
so no private key files are ever copied into the container.
Example ~/.netrc entry:
machine github.com
login your-github-username
password ghp_yourPersonalAccessToken
Per-command override:
GODEV_NETRC=1 go get github.com/YourOrg/private-moduleIf your go.mod uses a replace directive pointing to a local path, that path must also be
visible inside the container. Add it to GODEV_EXTRA_VOLUMES in ~/.devproxy:
GODEV_EXTRA_VOLUMES=/Users/you/Dev/Go/mylib:/Users/you/Dev/Go/anotherEach path is mounted at the same absolute path in the container, so replace directives require no changes.
| Scenario | Behaviour |
|---|---|
go build with CGO disabled |
GOOS/GOARCH forwarded — cross-compiles for the host OS |
go build with CGO enabled |
GOOS/GOARCH not forwarded — produces a Linux binary |
go run |
Always builds and runs inside the Linux container |
Cross-compiling a CGO binary from a Linux container to macOS is not supported (the macOS SDK is not available in the container). To build a CGO binary for the host platform, use the real toolchain:
DEVPROXY_UNSECURE=1 go build ./...The installer downloads a ready-made Dockerfile that adds Clang and Git to the standard Go image. Build and activate it with:
devproxy build golang 1.25
devproxy go use devproxy-golang:1.25The Dockerfile is installed at ~/.local/share/devproxy/Dockerfiles/devproxy-golang.Dockerfile.
A binary compiled inside the container is a Linux ELF binary and cannot run natively on macOS.
Use devproxy go exec to run it inside the same container environment:
go build -o ./myapp .
devproxy go exec ./myapp --flag valuePass environment variables with -e:
devproxy go exec -e DB_HOST=host.docker.internal -e PORT=8080 ./myappThe container uses --network host so localhost resolves to the host network (note: on
macOS with Docker Desktop or Podman, use host.docker.internal / host.containers.internal
instead, as the container runs inside a Linux VM).
Set the GOROOT in GoLand to the synthetic GOROOT created by the installer:
Settings → Go → GOROOT → Add local → ~/.local/share/devproxy/goroot
The synthetic GOROOT symlinks the real Go standard library but replaces the go binary with
the proxy, so all GoLand-triggered go list, go mod, and module resolution calls run inside
the container automatically. Absolute paths passed by GoLand via -modfile are detected and
mounted automatically.
The install script places a single proxy script at ~/.local/bin/devproxy/npm and symlinks
~/.local/bin/devproxy/npx to it. The script detects which tool it was invoked as and routes
accordingly:
- npm — runs the npm command inside an ephemeral
node:24container.npm helpandnpm configare always passed through to the real binary without starting a container. - npx — always runs inside the container, since its purpose is to download and execute arbitrary packages.
The host npm cache directory (resolved via npm config get cache, e.g. ~/.npm) is mounted
at the same absolute path inside the container so the cache is shared across runs and persists
between invocations.
| Variable | Default | Description |
|---|---|---|
NPM_BINARY |
(set by installer) | Path to the real npm binary on the host |
NPX_BINARY |
(set by installer) | Path to the real npx binary on the host |
CONTAINER_RUNTIME |
auto-detect | podman or docker |
NODEDEV_IMAGE |
node:24 |
Container image used for all npm/npx commands |
NODEDEV_NPMRC |
(unset) | Set to 1 to enable private registry credentials |
DEVPROXY_UNSECURE |
(unset) | Set to 1 to bypass the container entirely |
Set NODEDEV_NPMRC=1 in ~/.devproxy (or per-command) to mount registry credentials into
the container. The proxy mounts the following files read-only when the variable is set:
| File | Container path | Purpose |
|---|---|---|
~/.npmrc |
/root/.npmrc |
Registry auth tokens for private/scoped packages |
~/.gitconfig |
/root/.gitconfig |
URL rewrites, credential helper config |
$SSH_AUTH_SOCK |
/tmp/ssh_auth.sock |
SSH agent socket for SSH-based git dependencies |
The SSH agent socket is forwarded automatically if SSH_AUTH_SOCK is set in the environment.
Example ~/.npmrc entry:
//registry.npmjs.org/:_authToken=npm_yourAuthToken
@yourorg:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=ghp_yourPersonalAccessToken
Per-command override:
NODEDEV_NPMRC=1 npm installDEVPROXY_UNSECURE is respected by all proxies. To run a single command on the host without
a container:
DEVPROXY_UNSECURE=1 go mod tidy
DEVPROXY_UNSECURE=1 npm installTo disable the proxy globally until re-enabled:
devproxy disable # uncomments DEVPROXY_UNSECURE in ~/.devproxy
devproxy enable # comments it back outdevproxy listShows which proxies are installed and the key variables from ~/.devproxy.
devproxy updateRe-downloads and reinstalls all proxy scripts in-place without touching ~/.devproxy.
devproxy uninstall # removes proxies and shell profile block, keeps ~/.devproxy
devproxy nuke # same as above, also deletes ~/.devproxy (prompts for confirmation)