The common problem for monorepo and go modules is that the following

It is really easy to miss the go.mod replace directive

In a following text we will learn more about Linux, namespaces and container technologies like Docker or Podman.

The problem

While go build is awesome tool, doing a lot of things in the background has sometimes consequences. And the typical consequences is when we build the software from an environment without network access. It should be every build environment.

Both https://opensuse and [][Fedora] disallow network access from their build workers. So that every build dependency must be correctly packaged and installed as a part of build process. And I am sure others Linux distributions have the same policy.

Similar case is a build of Docker image, where we don’t (and don’t want to) deploy SSH keys to access private git instance.

Step 4/9 : RUN go build
go: requires
        reading 403 Forbidden

There are a few ways for developer to solve it

Turn off networking

It is harsh method and I won’t be happy to have my audiostreams interrupted. Sadly it is truly multiplatform way.


Linux kernel has a concept of namespaces. They simply allow to virtualize several kernel resources and to pretend to userspace they are running on their own computer. Namespaces are key concept of all container technologies like Docker, Podman, LXC and others.

System allows you to manipulate with namespaces is via command and system call. This way one can create private network namespace, which is not configured by default and can’t connect to anything.

curl --silent | wc -l
unshare -r -n curl
curl: (7) Couldn't connect to server

Command does following

  1. -r, --map-root-user maps current user and group id to root. Not that this is fully secure, because from non-namespaced point of view is this still the same user.
  2. -n, --net create own empty network namespace

So running unshare -r -n go build will ensure that go build does not have access to network at all.


As I have mentioned namespaces are key for container technologies. And it is not surprising that both and, and most likely all others, can do the same.

$ docker run alpine:latest ping -c 1
PING ( 56 data bytes
64 bytes from seq=0 ttl=54 time=1.426 ms

--- ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 1.426/1.426/1.426 ms

With network none

$ docker run --network=none alpine:latest ping -c1
PING ( 56 data bytes
ping: sendto: Network unreachable

Logo by Clker-Free-Vector-Images-3736@Pixbay