Dev

Install Go (Golang) on Fedora 45 / 44: dnf or go.dev Tarball

Fedora’s Go package behaves differently from upstream Go in two ways that matter. It ships with GOTOOLCHAIN=local, so a go.mod that asks for a newer release stops the build instead of downloading that release. And its version string ends in -X:nodwarf5, which govulncheck can’t parse, so on our Fedora 45 machine the scanner reported “No vulnerabilities found” for an HTTP server exposed to five standard library vulnerabilities.

Original content from computingforgeeks.com - post 22411

Below you’ll install Go (Golang) on Fedora with dnf, see what Fedora changes in go env, build and cross-compile a first program, and fix both problems. The upstream go.dev tarball closes the guide for when you want Go’s own defaults. We ran everything on Fedora 45 with Go 1.27 and checked the dnf install and the toolchain behaviour on Fedora 44, which ships Go 1.26, in October 2026.

Install Go on Fedora with dnf

Go is packaged as golang in the main Fedora repository. On the day we tested, Fedora 45 carried the 1.27 series and Fedora 44 the newest 1.26.x release, so each gets a current, supported Go from dnf. Check what your release offers before installing:

dnf repoquery --qf "%{name} %{version}-%{release} %{repoid}\n" golang golang-bin

On our Fedora 45 machine the stable repository held 1.27.1 and updates-testing already had 1.27.2, the same release go.dev listed as current that day:

golang 1.27.1-2.fc45 fedora
golang 1.27.2-1.fc45 updates-testing
golang-bin 1.27.1-2.fc45 fedora
golang-bin 1.27.2-1.fc45 updates-testing

If updates-testing is enabled on your machine, dnf takes the newer build from it, and if it isn’t, you get the stable one. The difference matters more than it looks. The 1.27.2 build fixes five net/http vulnerabilities, as the govulncheck section below shows, and the exact patch release also ends up in every go.mod you create. Install the toolchain:

sudo dnf install golang

Installing golang pulls in the compiler and the standard library sources, plus gcc, binutils and the glibc headers that cgo needs. That came to 13 packages with updates-testing enabled, a 108 MiB download and 394 MiB on disk. The output below is trimmed to the Go packages; the rest are those C dependencies:

Installing:
 golang          x86_64 0:1.27.2-1.fc45   updates-testing  10.3 MiB
 golang-bin      x86_64 0:1.27.2-1.fc45   updates-testing  88.5 MiB
 golang-src      noarch 0:1.27.2-1.fc45   updates-testing  90.8 MiB
 Installing:        13 packages
Total size of inbound packages is 108 MiB. Need to download 108 MiB.
After this operation, 394 MiB extra will be used (install 394 MiB, remove 0 B).
Complete!

Check the version and the four settings that matter most. GOROOT tells you which install answered, and that matters once a second Go lands on the machine.

go version
go env GOROOT GOPATH GOTOOLCHAIN GOPROXY

Two details give away a Fedora build. The version carries an -X:nodwarf5 suffix, and GOTOOLCHAIN reads local where an upstream install says auto. This screenshot comes from the stable 1.27.1 build:

Go installed from Fedora 45 repositories showing go version, GOTOOLCHAIN local and go run output

Your workspace lives in ~/go, which Go creates the first time it downloads a module, so don’t be surprised that it is missing right after the install. Go spreads what it writes for your user over three places:

  • ~/go/bin and ~/go/pkg/mod: tools, modules and downloaded toolchains
  • ~/.cache/go-build: the build cache (GOCACHE)
  • ~/.config/go/env: settings written by go env -w

The module cache grows with every project and every downloaded toolchain, and ours reached 344 MiB during these tests. Go writes it read-only, so rm -rf ~/go/pkg/mod fails with “Permission denied” on every file. Clear it with go clean -modcache instead, which removed the whole directory on our VM. Fedora 44 behaves the same way with Go 1.26 from its updates repository.

Review what Fedora changes in go env

Fedora sets its defaults in go.env inside GOROOT, and the file explains each change in its comments, so read it once with cat $(go env GOROOT)/go.env. Three settings decide how the toolchain behaves:

  • GOPROXY=https://proxy.golang.org,direct: the upstream default
  • GOTOOLCHAIN=local: never download another toolchain
  • GOEXPERIMENT=nodwarf5: older DWARF debug info in binaries

If you remember older Fedora advice, the proxy line matters. Fedora used to set GOPROXY=direct and turn off the checksum database for historical and privacy reasons, then reverted to upstream’s proxy and sum.golang.org with the Go 1.25 change in Fedora 43. The comment in go.env says the old setting caused severe performance degradations. Old blog posts telling you to “fix” the proxy on Fedora are now fixing something that is no longer there. The DWARF setting works around a debugedit incompatibility in Fedora’s RPM builds. It looks harmless, but it adds the -X:nodwarf5 suffix to the version string, and that suffix breaks govulncheck’s standard library checks, covered in its own section below.

GOTOOLCHAIN=local is the one that changes your day. Fedora wants the distribution-packaged compiler used for everything, so the go command never fetches a pre-built toolchain the way upstream Go does when a module asks for a newer release. That is a reasonable policy for a distribution, and it is the cause of the error covered further down. Your own setting overrides it, as that section shows.

Build your first Go program

Every Go program now lives in a module, so start with go mod init. The module path only has to be unique if you publish the code, and example.com/hello is fine for a test:

mkdir -p ~/hello && cd ~/hello
go mod init example.com/hello

Then create the program file. The vim command comes from vim-enhanced, so run sudo dnf install vim-enhanced first if your machine only has vi, or use nano, Fedora’s default editor.

vim ~/hello/main.go

Print the toolchain version and the target platform, which makes the cross-compile and toolchain tests below easy to read. If you are coming from Ubuntu, the program is identical to the one in our Go on Ubuntu 26.04 guide; only the packaging around it differs:

package main

import (
	"fmt"
	"runtime"
)

func main() {
	fmt.Printf("Hello from %s on %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
}

Run it straight from source first, then build a binary and inspect it.

go run .
go build -o hello .
./hello
ls -lh hello
file hello

You get one self-contained file, which is the reason Go is so pleasant to ship. Look at the last line of the file output in particular.

Hello from go1.27.2-X:nodwarf5 on linux/amd64
Hello from go1.27.2-X:nodwarf5 on linux/amd64
-rwxr-xr-x. 1 josphat josphat 2.4M Oct 15 08:53 hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=5FeEXw4AOe7bKqe3GVS_/A2xsaKYg01Ed-iKW5F2J/AyoZ-qXnuZH3Dhl9Z0Ef/-8LTUzPg6V5LlQj6GFTs, BuildID[sha1]=b5ebfdd17a62cc1203e032755fcb31cbfe081c6b, with debug_info, not stripped

Our binary came out statically linked even though CGO_ENABLED defaults to 1 on Fedora, because this program imports nothing that needs C. That changes as soon as the code imports net. A five-line net/http server built the same way came out “dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2”, and the same server built with CGO_ENABLED=0 came out statically linked. Build release binaries with cgo off when you want them to run on any Linux. Stripping the symbol table at the same time took the hello program from 2.4 MiB to 1.5 MiB:

CGO_ENABLED=0 go build -ldflags="-s -w" -o hello-small .
ls -lh hello-small

Cross-compiling needs no extra packages on Fedora, since the Go toolchain carries every target itself. Set GOOS and GOARCH for the platform you want:

GOOS=linux GOARCH=arm64 go build -o hello-arm64 .
GOOS=windows GOARCH=amd64 go build -o hello.exe .
file hello-arm64 hello.exe

Both targets came out of the same x86_64 machine, an ARM64 Linux binary for a 64-bit Raspberry Pi OS or Graviton host and a Windows executable. A 32-bit Raspberry Pi OS needs GOARCH=arm instead:

hello-arm64: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, Go BuildID=GjkFKRayFqMkG8che1En/24StaL7-xJ01DPYDoUet/5FBnN0mCBoBnGdI0Begz/2JIS5bKERYAL2i3msBGb, BuildID[sha1]=cfdbe8db540f9354e5169a68655b0805b4435ba8, with debug_info, not stripped
hello.exe: PE32+ executable for MS Windows 10.00 (console), x86-64, 15 sections

Add GOPATH/bin to your PATH for go install

go install builds a tool and drops it in ~/go/bin, but Fedora doesn’t put that directory on your PATH. The install looks successful and the command then isn’t found. We hit exactly that with govulncheck, Go’s own vulnerability scanner, which the next section needs anyway:

go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck -version

Go put the binary in ~/go/bin, yet the shell couldn’t find it.

bash: govulncheck: command not found

Add the directory to your PATH in ~/.bashrc. Use the literal $HOME/go/bin rather than $(go env GOPATH)/bin, which you’ll see in many guides. We tried that form first, and once Fedora’s go was gone (switching to the tarball below), every new shell printed go: command not found from .bashrc because the line ran before Go was on the PATH:

echo "export PATH=\$PATH:\$HOME/go/bin" >> ~/.bashrc
source ~/.bashrc
govulncheck -version

Now the scanner runs, and it reports the toolchain it will check against. Look at the first line, because it is the reason for the next section.

Go: go1.27.1-X:nodwarf5
Scanner: [email protected]
DB: https://vuln.go.dev
DB updated: 2026-10-08 22:31:09 +0000 UTC

We captured that on the stable 1.27.1 build, which is what a Fedora 45 machine without updates-testing runs.

Fix govulncheck missing standard library vulnerabilities

On Fedora’s Go, govulncheck never reports a vulnerability in the standard library. It reads the Go version from go env GOVERSION and converts it to a semantic version, and go1.27.1-X:nodwarf5 doesn’t match the pattern it expects. With no usable version it skips every standard library entry rather than risk false alarms. To see it yourself, create a module whose whole program is a bare HTTP server:

mkdir -p ~/vulndemo && cd ~/vulndemo
go mod init example.com/vulndemo
vim main.go

Five lines are enough, because ListenAndServe pulls in the whole HTTP and HTTP/2 server:

package main

import "net/http"

func main() {
	http.ListenAndServe(":8080", nil)
}

Scan it inside ~/vulndemo. We ran this on the stable 1.27.1 build, and on 1.27.2 both scans below come back clean because the flaws are fixed there:

govulncheck ./...

The scan comes back clean:

No vulnerabilities found.

govulncheck reads GOVERSION from the environment before asking the toolchain, so hand it the version without Fedora’s suffix and scan again. We trimmed the output to the findings:

GOVERSION=$(go env GOVERSION | sed "s/-X:.*//") govulncheck ./...

The same code is now affected by five vulnerabilities, all fixed one point release later:

Vulnerability #1: GO-2026-6617
    Found in: net/http/internal/[email protected]
    Fixed in: net/http/internal/[email protected]
Vulnerability #2: GO-2026-6613
    Found in: net/[email protected]
    Fixed in: net/[email protected]
Vulnerability #3: GO-2026-6612
    Found in: net/http/internal/[email protected]
    Fixed in: net/http/internal/[email protected]
Vulnerability #4: GO-2026-6611
    Found in: net/http/internal/[email protected]
    Fixed in: net/http/internal/[email protected]
Vulnerability #5: GO-2026-6603
    Found in: net/http/internal/[email protected]
    Fixed in: net/http/internal/[email protected]
Your code is affected by 5 vulnerabilities from the Go standard library.

That is a clean bill of health for a server with five reachable HTTP and HTTP/2 flaws, and nothing in the first scan hints at it. Upgrading the toolchain is the real fix. With updates-testing enabled on our VM, sudo dnf upgrade golang moved it to 1.27.2, and the corrected scan then reported “No vulnerabilities found.” too. On a machine without updates-testing, the fixed build arrives once it reaches the stable updates repository. Until Fedora’s version string parses, put the GOVERSION prefix in every shell script and CI step that runs govulncheck. It only covers source scans like govulncheck ./.... A -mode=binary scan reads the version recorded inside the binary, which also carries the suffix, so for binaries built with Fedora’s Go the toolchain upgrade is the only fix. We read that in the scanner’s source rather than testing it.

Fix “go.mod requires go” with GOTOOLCHAIN=local

Fedora users hit this error, and upstream users rarely see it, because upstream Go only stops here when the toolchain download is turned off or fails. We created the test module with Go 1.27.2 from updates-testing, then moved the machine back to the stable 1.27.1 build, which is what most Fedora 45 users have. The go.mod written by go mod init said go 1.27.2, and the build failed:

go: go.mod requires go >= 1.27.2 (running go 1.27.1; GOTOOLCHAIN=local)

Across releases it gets worse. A module marked go 1.27 fails on Fedora 44, whose packaged Go is 1.26.9, with go: go.mod requires go >= 1.27 (running go 1.26.9; GOTOOLCHAIN=local). A teammate who clones your repository onto an older Fedora sees this before compiling a single file. You have three ways out, and the right one depends on whether the code needs the newer release and on which Fedora is building it:

  1. Lower the requirement with go mod edit -go=1.27 (or 1.26 for Fedora 44)
  2. Allow a download for one build with GOTOOLCHAIN=auto
  3. Allow downloads permanently with go env -w GOTOOLCHAIN=auto

Start with the first. go mod init pins the exact patch release even though almost no code depends on one, so go 1.27 is the honest requirement for a new module, and it builds with any 1.27.x toolchain. It does not help on Fedora 44, though. A go 1.27 line still fails there against Go 1.26.9, so for that machine you either lower the line to go 1.26, if the code builds on 1.26, or use one of the other two options:

Go GOTOOLCHAIN=local go.mod requires newer go error on Fedora 45 and the fix

When the code really needs the newer release, let Go fetch it. With go.mod still saying go 1.27.2 and the stable 1.27.1 toolchain installed, prefixing a single command with GOTOOLCHAIN=auto downloaded the requested toolchain into the module cache and built with it. If your local Go already satisfies go.mod, nothing is downloaded:

GOTOOLCHAIN=auto go build -o hello .
./hello

Notice that the binary reports the downloaded upstream release, without Fedora’s suffix.

go: downloading go1.27.2 (linux/amd64)
Hello from go1.27.2 on linux/amd64

Each such download takes 247 MiB under ~/go/pkg/mod/golang.org/, and it’s an upstream build rather than Fedora’s. Go fetches the minimum release that satisfies go.mod, not the newest: on Fedora 44 a module marked go 1.27 pulled go1.27.0, while go.dev already offered 1.27.2. To make the override permanent for your user, write it to Go’s own config file:

go env -w GOTOOLCHAIN=auto
cat $(go env GOENV)

Your user config now holds the setting, and it overrides Fedora’s go.env for every build.

GOTOOLCHAIN=auto

To return to Fedora’s default later, run go env -u GOTOOLCHAIN, after which go env GOTOOLCHAIN reads local again. We’d keep the permanent override for developer laptops and leave CI on local. A build server that silently downloads toolchains is harder to reproduce, while one that fails loudly tells you to fix go.mod. The Go toolchain documentation covers the toolchain line and the other values GOTOOLCHAIN accepts.

Install Go from the go.dev tarball instead

Choose the upstream tarball if you want Go’s own defaults (GOTOOLCHAIN=auto, no Fedora patches) or a new release the day it ships. It installs into /usr/local/go and dnf never updates it, so upgrades become your job. Detect the current release from go.dev, so the commands keep working when the next version ships:

GO_VER=$(curl -fsSL "https://go.dev/VERSION?m=text" | head -1)
ARCH=$(uname -m | sed "s/x86_64/amd64/;s/aarch64/arm64/")
echo "$GO_VER $ARCH"

On our VM that printed go1.27.2 and amd64, and the ARCH line makes the same commands work on an aarch64 Fedora box. If the version is empty, the curl call failed, so stop before downloading anything. Download the archive and verify its checksum before you extract anything as root. The .sha256 file has to come from dl.google.com, because the same path on go.dev returns an HTML redirect page and the check then fails with “no properly formatted checksum lines found”:

cd /tmp
curl -fsSLO "https://go.dev/dl/${GO_VER}.linux-${ARCH}.tar.gz"
curl -fsSL "https://dl.google.com/go/${GO_VER}.linux-${ARCH}.tar.gz.sha256" -o go.sha256

The .sha256 file holds only the hash, so pair it with the file name and let sha256sum compare them:

echo "$(cat go.sha256)  ${GO_VER}.linux-${ARCH}.tar.gz" | sha256sum -c -

A matching archive prints go1.27.2.linux-amd64.tar.gz: OK. Replace any older copy completely rather than extracting over it, since stale files in /usr/local/go break builds in confusing ways, then put the new bin directory first on your PATH:

sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "/tmp/${GO_VER}.linux-${ARCH}.tar.gz"
echo "export PATH=/usr/local/go/bin:\$PATH" >> ~/.bashrc
source ~/.bashrc
command -v go
go version

Your shell now finds the upstream toolchain first. If command -v go still prints /usr/bin/go, the shell has not reread ~/.bashrc, so open a new terminal.

/usr/local/go/bin/go
go version go1.27.2 linux/amd64

Both installs ran on the same Fedora 45 VM, and they differ in more than the version string:

Fedora golang packagego.dev tarball
Location/usr/lib/golang/usr/local/go
GOTOOLCHAINlocalauto
Version stringgo1.27.2-X:nodwarf5go1.27.2
Disk used394 MiB (13 packages)276 MiB
Updatesdnf upgradeRepeat the download by hand

Pick one per machine. With both installed, whichever directory comes first in PATH wins, and a script that calls /usr/bin/go by its full path still gets Fedora’s build, which is how two people on the same box end up with different results. We’d use the dnf package on Fedora and only switch to the tarball when a project needs a release the day it ships. If you go the tarball route, remove the package with sudo dnf remove golang so there is only one Go left. dnf takes the 12 dependencies with it, gcc included. To keep the C toolchain for cgo, run sudo dnf mark user gcc first, which cut the removal on our VM from 13 packages to 4. The tarball build reports a plain version string, so govulncheck checks the standard library correctly there without the GOVERSION prefix.

Language runtimes on Fedora tend to follow this split between distro package and upstream build, and the Node.js guide for Fedora makes the same call for Node. To containerise what you build, Podman on Fedora runs a static Go binary in a scratch image, and the polyglot Fedora dev environment sets up Python, Node.js and Rust alongside it.

Keep reading

How to Upgrade Fedora 44 to Fedora 45 (GUI, CLI and Rollback) Fedora How to Upgrade Fedora 44 to Fedora 45 (GUI, CLI and Rollback) Enable RPM Fusion and Install Multimedia Codecs on Fedora 45 / 44 / 43 Fedora Enable RPM Fusion and Install Multimedia Codecs on Fedora 45 / 44 / 43 Harden Fedora 45 / 44 for Desktop and Server: Complete Guide Fedora Harden Fedora 45 / 44 for Desktop and Server: Complete Guide Best Monitor Arms for a Multi-Monitor Developer Desk Programming Best Monitor Arms for a Multi-Monitor Developer Desk Best Mouse and Keyboard for Programming Programming Best Mouse and Keyboard for Programming Install and Use Node.js on Windows 11 / Windows 10 Programming Install and Use Node.js on Windows 11 / Windows 10

Leave a Comment

Press ESC to close