Skip to content

Installing private Go modules

River Pro is distributed as a private Go module via a private Go proxy. This page describes how to configure it for an existing Go project, along with recommendations for managing GOPROXY/GONOSUMDB environment variables.


Go proxies and checksum databases

All Go modules are distributed via a module proxy. When running a Go command like go build or go get, Go's toolchain communicates to proxies controlled by the GOPROXY environment variable. Its default value is:

GOPROXY="https://proxy.golang.org,direct"

proxy.golang.org is the main Go module proxy, run by Google. Its placement as a default provides benefits for security and availability. In case of an offline third party code repository, Google's proxy is very likely to still be up, and can return a cached version of any third party module being requested so that builds don't fail.

Go proxies are augmented by a checksum database, normally served by Google from sum.golang.org. The database persists an immutable checksum for known Go modules which Go's toolchain can compare against fetched modules to verify that they haven't been tampered with, even if the modules came in by way of a third party Go proxy.

Private modules like River Pro are not publicly available to other Go module proxies and therefore cannot appear in the checksum database. For this reason, private modules prefixes must be added to the GONOSUMDB environment variable to prevent Go from attempting to verify checksums for them.

Fetching River Pro modules

River Pro is distributed via a private Go proxy hosted at riverqueue.com/goproxy. It requires a customer-specific private credential obtained during the Pro subscription process that looks like river_secret_<secret>.

export RIVER_PRO_SECRET=river_secret_...
export GOPROXY=https://proxy.golang.org,https://river:$RIVER_PRO_SECRET@riverqueue.com/goproxy,direct
export GONOSUMDB=riverqueue.com/riverpro,$GONOSUMDB

go get riverqueue.com/riverpro
go get riverqueue.com/riverpro/driver/riverpropgxv5

# install riverpro CLI:
go install riverqueue.com/riverpro/cmd/riverpro@latest

Assuming everything worked, Go will have updated the project's go.mod and go.sum files with new entries for River Pro.

Notably, the recommendation for GOPROXY above installs River's module proxy as second priority after proxy.golang.org. Module fetches will prefer Google's main proxy and only fall back to River's for modules that couldn't be found.

See also installing in CI and build environments.

Sustainably managing Go environment

Storing secrets in .netrc

The instructions above recommended a value for GOPROXY like:

GOPROXY=https://proxy.golang.org,https://river:$RIVER_PRO_SECRET@riverqueue.com/goproxy,direct

This requires the presence of the RIVER_PRO_SECRET in the environment. Keeping secrets in a shell environment is generally undesirable because there needs to be a mechanism for the secret to get there in the first place, and there's a higher likelihood that it can accidentally leak.

Go supports configuring proxy credentials in a ~/.netrc file, a standard supported by other tools like cURL and Git. Add an entry containing a River secret like the following:

machine riverqueue.com
login river
password river_secret_...

This makes it possible to use GOPROXY without an inline key:

export GOPROXY=https://proxy.golang.org,https://riverqueue.com/goproxy,direct
export GONOSUMDB=riverqueue.com/riverpro,$GONOSUMDB

go get riverqueue.com/riverpro
go get riverqueue.com/riverpro/driver/riverpropgxv5

Setting variables with go env

GOPROXY and GONOSUMDB are normal environment variables, and can be configured in a shell env/RC file like ~/.zshenv or ~/.zshrc.

Another option is to use the Go toolchain's built-in go env for managing variables that'll be scoped specifically to Go commands.

go env -w GOPROXY=https://proxy.golang.org,https://riverqueue.com/goproxy,direct
go env -w GONOSUMDB=riverqueue.com/riverpro

# or, with a secret inline instead of being read from `~/.netrc`
go env -w GOPROXY=https://proxy.golang.org,https://river:river_secret_...@riverqueue.com/goproxy,direct

go get riverqueue.com/riverpro
go get riverqueue.com/riverpro/driver/riverpropgxv5

A River secret is still required, and may be configured in ~/.netrc above, or set directly as a static string with go env -w GOPROXY=.

`go env` configuration is global

Setting configuration with go env -w will set environment variables for all go invocations, including where it's invoked in projects. Custom configuration is stored to the file returned by go env GOENV.

Using direnv for project-specific configuration

Setting GOPROXY/GONOSUMDB to either a shell RC file or with go env -w has a less-than-optimal side effect of making the new configuration global across all your Go projects. This isn't harmful, but this sort of configuration leakage is generally not considered best practice.

Projects can avoid this by using a tool like direnv to manage project-specific environment variables:

# contents of `~/.envrc` is a project directory
export GOPROXY=https://proxy.golang.org,https://riverqueue.com/goproxy,direct
export GONOSUMDB=riverqueue.com/riverpro,$GONOSUMDB

# or, with secret inline instead of being read from `~/.netrc`
export GOPROXY=https://proxy.golang.org,https://river:river_secret_...@riverqueue.com/goproxy,direct

This approach has the downside that all developers will need to have direnv installed for it to work, but the upside that especially when using a private Git repository, an .envrc file can be checked in to enable configuration-free Go builds that need only a git clone ... && cd ... && go build.

Installing in CI and build environments

GitHub Actions

If you're using River Pro, you will also need it to be available in a CI environment like GitHub Actions so it can run a test suite that uses features specific to River Pro. This can be accomplished by adding a Pro key as a GitHub repository secret, then observing the usual GOPROXY/GONOSUMDB environment variables:

- name: Setup Go
  uses: actions/setup-go@v5
  with:
    go-version: "stable"
    check-latest: true

- name: Install River Pro CLI
  run: go install riverqueue.com/riverpro/cmd/riverpro@latest
  env:
    GOPROXY: https://proxy.golang.org,https://river:${{ secrets.RIVER_PRO_SECRET }}@riverqueue.com/goproxy,direct
    GONOSUMDB: riverqueue.com/riverpro

- name: Migrate River
  run: |
    riverpro migrate-up --database-url "$DATABASE_URL"
    riverpro migrate-up --database-url "$DATABASE_URL" --line workflow

- name: Go test
  run: go test ./...
  env:
    GOPROXY: https://proxy.golang.org,https://river:${{ secrets.RIVER_PRO_SECRET }}@riverqueue.com/goproxy,direct
    GONOSUMDB: riverqueue.com/riverpro

Docker

In order to deploy a River Pro app, you may need to build it within a Docker image. Using River's module proxy in a Dockerfile is typically done by mounting a secret into the container:

COPY go.mod go.sum ./
RUN --mount=type=secret,id=river_pro_secret,dst=/etc/secrets/river_pro_secret \
  sh -c 'GOPROXY=https://proxy.golang.org,https://river:$(cat /etc/secrets/river_pro_secret)@riverqueue.com/goproxy,direct \
  go mod download'

When building the Docker image, you'll need to pass the secret to the build command with a source such as env or file:

docker build --secret id=river_pro_secret,env=RIVER_PRO_SECRET ...