Short answer: download the archive for your system from go.dev/dl, delete any old /usr/local/go, unpack the new one with sudo tar -C /usr/local -xzf and add /usr/local/go/bin to your PATH. go version confirms it. On Windows, run the MSI from the same page. As of October 2026 the current release is Go 1.27.3.
curl -LO https://go.dev/dl/go1.27.3.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.27.3.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile
source ~/.profile
go version
go version go1.27.3 linux/amd64The builds, go install, cross-compiling and error messages on this page were run on Debian 12 with Go 1.26.0 (linux/amd64) in a scratch directory on 21 October 2026, with downloads switched off. The install steps follow go.dev/doc/install; version numbers come from go.dev/dl and the Go release history, read the same day.
Which way should you install Go?
| Method | Version you get | Updates | Good for |
|---|---|---|---|
| Official archive from go.dev/dl | 1.27.3 (or 1.26.10) | By hand, same steps again | Servers and development machines: the default |
| apt: golang-go | Debian 12: 1.19 (1.23 in backports) · Debian 13: 1.24 · Ubuntu 22.04: 1.18 · Ubuntu 24.04: 1.22 | With apt, within that version | Building Debian or Ubuntu packages, old projects |
| snap: go --classic | 1.27.3, published by Canonical | Automatic | Ubuntu machines that already use snaps |
| Windows MSI from go.dev/dl | 1.27.3 | Run the newer MSI | Windows 10, 11 and Windows Server |
| winget: GoLang.Go | Whatever the manifest holds | winget upgrade | Windows with winget |
Go ships two major releases a year: 1.25 in August 2025, 1.26 in February 2026 and 1.27 in August 2026. Each is supported until two newer ones exist, so as of October 2026 only 1.27 and 1.26 get fixes from the Go team, and every distribution package in the table is older than that (distributions may backport security fixes on their own). To get the newest version number in a script:
curl -s 'https://go.dev/VERSION?m=text' | head -n 1
go1.27.3How do I install Go on Linux?
- 1Pick the right archive
uname -mprintsx86_64forlinux-amd64archives andaarch64forlinux-arm64. The download page on go.dev lists a SHA-256 checksum next to each file; compare it withsha256sum go1.27.3.linux-amd64.tar.gz. - 2Remove the old tree, unpack the new one
shell sudo rm -rf /usr/local/go sudo tar -C /usr/local -xzf go1.27.3.linux-amd64.tar.gzThe Go documentation is explicit: do not unpack a new archive into an existing
/usr/local/go, it is known to produce broken installations. Updating later means repeating exactly this step with the newer file. - 3Put Go on your PATH
~/.profile (one user) or /etc/profile.d/go.sh (everyone) export PATH=$PATH:/usr/local/go/bin export PATH="$PATH:$(go env GOPATH)/bin" # tools from go install, ~/go/bin by defaultThe profile is read at login, so run
source ~/.profileor log in again. How the different startup files relate is in setting environment variables on Linux. - 4Check it
shell go version go env GOROOT GOPATH
One trap on servers: sudo go build fails with sudo: go: command not found, because sudo replaces your PATH with its own secure_path, which does not contain /usr/local/go/bin; in our test a shell with Debian’s default sudo path could not find go either. Build as your normal user instead; only installing the result needs root.
apt and snap: quicker, but older or different
sudo apt install golang-go # the distribution's Go
sudo apt install -t bookworm-backports golang-go # Debian 12, backports enabled: 1.23
sudo snap install go --classic # Ubuntu, current GoAn old Go matters more than it seems. Since Go 1.21, go.mod files can carry a three-part version such as go 1.25.0, and new ones written by a recent Go do. Go 1.19 or 1.18 cannot even parse that:
go: errors parsing go.mod:
/home/you/app/go.mod:3: invalid go version '1.25.0': must match format 1.23Go 1.21 and later handle it differently: when a module asks for a newer Go, the go command downloads that toolchain into the module cache and uses it. That is convenient, but it means your installed Go quietly runs another version. Some distribution builds change that default, so check with go env GOTOOLCHAIN. With GOTOOLCHAIN=local it refuses instead, which is what we got on Go 1.26.0 with a go.mod asking for 1.27.0:
go: go.mod requires go >= 1.27.0 (running go 1.26.0; GOTOOLCHAIN=local)How do I install Go on Windows?
Download go1.27.3.windows-amd64.msi from go.dev/dl and run it. By default it installs into Program Files and adds Go to the PATH; close and reopen every terminal, then check:
go version
go version go1.27.3 windows/amd64
# unattended, as Administrator
msiexec /i go1.27.3.windows-amd64.msi /qn
# or with winget
winget install --id GoLang.Go -eWindows Server 2022 and 2019 have no winget out of the box; see winget on Windows Server, or simply use the MSI.
Your first program: go mod init, go run, go build
$ mkdir hello && cd hello
$ go mod init example.com/hello
go: creating new go.mod: module example.com/hello
$ cat go.mod
module example.com/hello
go 1.25.0Every Go project is a module, and go mod init starts one. The module path is a name, not a download: example.com/hello is fine locally, a repository path such as github.com/you/hello is the convention for published code. Note the go 1.25.0 line: Go 1.26 writes the previous release into new modules. Now the program:
package main
import "fmt"
func main() {
fmt.Println("Hello from Go")
}$ go run .
Hello from Go
$ go build -o hello .
$ ls -l hello
-rwxr-xr-x 1 root root 2392561 Oct 21 22:54 hello
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=…, with debug_info, not strippedgo run compiles into a temporary directory and runs the result; go build leaves a single 2.4 MB executable that needs no Go installation on the machine that runs it. go vet ./... and gofmt -l . both came back clean on this program. Dependencies are added with go get example.org/pkg@latest, and go mod tidy prunes what the code no longer imports. The shell tools used here (file, ls -l, uname) are covered in the Linux commands cheat sheet.
go install, GOPATH and GOBIN
go install builds a program and puts the binary into a bin directory instead of the current one. For a tool from the internet, name a version:
go install golang.org/x/tools/gopls@latest
go env GOPATH GOBIN
ls "$(go env GOPATH)/bin"- Where the binary goes:
$GOBINif it is set, otherwise$(go env GOPATH)/bin, which is~/go/binby default. In our test,go install .puthellointoGOPATH/bin, and withGOBINset it went there instead. - Make it permanent:
go env -w GOBIN=$HOME/.local/binwrites the setting to Go’s own environment file (go env GOENVshows where). - go get no longer installs programs. It only edits
go.mod.
$ go install golang.org/x/tools/gopls
go: 'go install' requires a version when current directory is not in a module
Try 'go install golang.org/x/tools/gopls@latest' to install the latest version
$ go get golang.org/x/tools/gopls@latest
go: go.mod file not found in current directory or any parent directory.
'go get' is no longer supported outside a module.
To build and install a command, use 'go install' with a version,
like 'go install example.com/cmd@latest'Cross-compiling with GOOS and GOARCH
Go builds for another system with two environment variables and no extra toolchain:
$ GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o web-arm64 .
$ file web-arm64
web-arm64: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, …
$ GOOS=windows GOARCH=amd64 go build -o web.exe .
$ file web.exe
web.exe: PE32+ executable (console) x86-64, for MS Windows, 16 sections
$ go tool dist list | wc -l
47| Target | GOOS | GOARCH |
|---|---|---|
| Linux server, Intel or AMD | linux | amd64 |
| Linux on 64-bit ARM (ARM servers, Raspberry Pi 4 and 5 with a 64-bit OS) | linux | arm64 |
| Windows Server or Windows 10/11 | windows | amd64 |
| Apple silicon Mac | darwin | arm64 |
| FreeBSD | freebsd | amd64 |
Cross-compiling switches cgo off by default, so code that needs C (for example the mattn/go-sqlite3 driver) needs a C cross-compiler as well. Run a binary built for the wrong architecture and the shell answers cannot execute binary file: Exec format error, which is what our arm64 build did on the x86-64 host.
A static binary for your server
A small web service shows why CGO_ENABLED=0 matters. It reads its address from an environment variable:
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func main() {
addr := os.Getenv("ADDR")
if addr == "" {
addr = "127.0.0.1:8080"
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "ok")
})
log.Printf("listening on %s", addr)
log.Fatal(http.ListenAndServe(addr, nil))
}$ go build -o web-default .
$ ldd web-default
linux-vdso.so.1 (0x…)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x…)
/lib64/ld-linux-x86-64.so.2 (0x…)
$ CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o web .
$ file web
web: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, …
$ ls -l web-default web
-rwxr-xr-x 1 root root 5755042 Oct 21 22:55 web
-rwxr-xr-x 1 root root 8423646 Oct 21 22:55 web-defaultWith a C compiler present, the net package uses cgo and the binary links against the system’s glibc. Copy that to an older distribution and it can fail with version 'GLIBC_2.34' not found, a case covered in error while loading shared libraries. CGO_ENABLED=0 gives a static binary that runs on any Linux of the same architecture. -trimpath removes your local paths, and -s -w drops the symbol table and debug data; together they took this binary from 8.4 to 5.8 MB. Panics still print function names and line numbers: a test program built this way showed main.boom(...) with its file and line in the trace. go version -m ./web lists the settings a binary was built with, CGO_ENABLED=0 included.
Run it as a systemd service
- 1Copy the binary and create a user
shell scp web you@203.0.113.10:/tmp/web # from your machine # on the server sudo useradd --system --no-create-home --shell /usr/sbin/nologin web sudo install -m 755 /tmp/web /usr/local/bin/webUse
install, notcp, when you later replace the binary of a running service: on our Debian 12 test,cpover a running executable failed withText file busy, whileinstall(GNU coreutils 9.1) replaced it. More ways to move files are in transferring files to a VPS. - 2Write the unit
/etc/systemd/system/web.service [Unit] Description=Small web service written in Go After=network-online.target Wants=network-online.target [Service] User=web Group=web Environment=ADDR=127.0.0.1:8080 ExecStart=/usr/local/bin/web Restart=on-failure RestartSec=2 NoNewPrivileges=yes ProtectSystem=strict ProtectHome=yes PrivateTmp=yes [Install] WantedBy=multi-user.target - 3Start it and follow the log
shell sudo systemctl daemon-reload sudo systemctl enable --now web journalctl -u web -f curl http://127.0.0.1:8080/The
log.Printfline appears in the journal, and thecurlshould printok. Every directive in the unit is explained in creating a systemd service.
Common Go install errors
| Message | Cause | Fix |
|---|---|---|
go: command not found | /usr/local/go/bin is not on the PATH of this shell | Add it to ~/.profile, then source it or log in again |
sudo: go: command not found | sudo uses secure_path | Build without sudo, or call /usr/local/go/bin/go |
go: go.mod file not found in current directory or any parent directory | Not inside a module | go mod init example.com/app |
invalid go version '1.25.0': must match format 1.23 | Go older than 1.21, usually from apt | Install from go.dev/dl |
go.mod requires go >= 1.27.0 (running go 1.26.0; GOTOOLCHAIN=local) | The module needs a newer Go and downloads are off | Update Go, or allow GOTOOLCHAIN=auto |
cannot execute binary file: Exec format error | Built for another architecture | Rebuild with the right GOARCH |
version 'GLIBC_2.34' not found | cgo binary built on a newer glibc | CGO_ENABLED=0, or build on the oldest target |
Go on a VPS
Because a Go program is one file, the easiest deployment is to build on your own machine or in CI with the right GOOS and GOARCH, copy the binary and restart the service. If you do build on the server, keep an eye on the disk: in our test, building two small programs for three targets left 340 MB in the build cache. Check it with du -sh $(go env GOCACHE) and clear it with go clean -cache; go clean -modcache removes downloaded modules. Builds use every core you give them, and our Standard KVM line puts more cores on each price step than Hi-CPU KVM, whose EPYC cores suit programs that lean on one or two threads. The finished binary of a typical API is happy on the smallest Standard KVM plan with 2 cores and 4 GB of RAM. The Linux VPS images for Ubuntu and Debian take the Linux commands on this page as written.
Frequently asked
Which Go version should I install?
The newest release from go.dev/dl, which was Go 1.27.3 as of October 2026. Each major Go release is supported until two newer majors exist, so 1.27 and 1.26 get fixes and older ones do not. Distribution packages lag behind: Ubuntu 24.04 ships Go 1.22 and Debian 12 ships 1.19, too old for many current projects.
Where does go install put the binary?
Into the directory in GOBIN if that is set, otherwise into the bin folder under GOPATH, which is ~/go/bin on Linux by default. Add that folder to your PATH, or set GOBIN permanently with 'go env -w GOBIN=$HOME/.local/bin'. Outside a module, go install needs a version, for example 'go install golang.org/x/tools/gopls@latest'.
How do I update Go on Linux?
Download the new archive from go.dev/dl, then run 'sudo rm -rf /usr/local/go' and 'sudo tar -C /usr/local -xzf' with the new file. Never unpack a new archive over an existing /usr/local/go, which the Go documentation says produces broken installations. 'go version' confirms the update; your PATH stays the same.
How do I uninstall Go?
Run 'go clean -cache -modcache' first to remove the build and module caches, then delete /usr/local/go with 'sudo rm -rf /usr/local/go', remove the PATH line from ~/.profile or /etc/profile.d/go.sh, and delete ~/go if you no longer need its tools. On Windows, uninstall Go under Settings, Apps.