Skip to content

A minimalist, POSIX‑oriented, non‑root installer for the Go programming language on Linux.

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

jcsxdev/letsgolang

letsgolang: The Go Installer

OpenSSF Best Practices OpenSSF Scorecard Shell Script Quality Checks Security Audit License

letsgolang is a minimalist, POSIX-oriented, non-root installer for the Go programming language on Linux. It focuses on security, auditability, and simplicity, ensuring your development environment is set up correctly with minimal fuss.

Table of Contents

Overview

letsgolang automates the process of fetching, verifying, and installing the latest official Go distribution directly into your user environment.

  • Non-root: Installs to $HOME/.local/opt/go by default, requiring no sudo privileges.
  • Auditable: Written in standard /bin/sh with a small set of widely supported extensions. No opaque binaries or hidden runtime dependencies.
  • Reliable: Enforces SHA256 checksum verification and handles environment configuration automatically.

⚠️ WARNING!

letsgolang is an early‑stage, experimental project. While it aims to be safe and predictable, it may still contain bugs or edge cases. Use it at your own discretion and review the installer script before execution.

Installation

To install Go using letsgolang, run:

curl --proto '=https' --tlsv1.2 -sSLf https://github.com/jcsxdev/letsgolang/releases/latest/download/letsgolang.sh | sh

Note on curl | sh
This installer uses the curl | sh pattern for convenience, but the script is fully transparent and can be downloaded, reviewed, and signature‑verified before execution. HTTPS is enforced, redirects are restricted, and checksum validation is performed to mitigate common risks associated with this installation method.

About the curl flags
The installer uses a hardened curl invocation to reduce common risks associated with remote script execution:

  • --proto '=https' — refuses any protocol other than HTTPS, preventing downgrade attacks. [docs]
  • --tlsv1.2 — enforces a minimum TLS version to avoid insecure cipher suites. [docs]
  • -sS — silent mode but still shows errors. [docs]
  • -f — fails on HTTP errors instead of piping HTML error pages into the shell. [docs]
  • -L — follows HTTPS redirects required by GitHub Releases. [docs]

More info: https://curl.se/docs/manpage.html

Verify installer signature (optional)

curl --proto '=https' --tlsv1.2 -sSLfO "https://github.com/jcsxdev/letsgolang/releases/latest/download/letsgolang.sh{,.asc}"
gpg --keyserver hkps://keys.openpgp.org --recv-keys DD7C87C3FEACEFF03CD1B93D00073B0954092B26
gpg --verify letsgolang.sh.asc

Why use letsgolang?

  • Zero Dependencies: No need to install Python, Node.js, or complex version managers. Just a shell and standard utilities (curl, tar).
  • POSIX-oriented: Runs on standard /bin/sh, prioritizing portability across minimal environments.

Note on POSIX orientation
letsgolang aims to be portable across standard /bin/sh implementations and follows POSIX principles wherever practical. It is described as POSIX‑oriented rather than POSIX‑compliant because it intentionally avoids strict formal compliance in favor of real‑world portability and maintainability. This keeps the script simple, auditable, and compatible with the minimal shells commonly found on Linux systems.

  • Non-Root Installation: Installs to your home directory, keeping your system partitions clean and secure.
  • Auditable: The entire logic is in a single, readable shell script. No hidden binaries or black boxes.
  • Predictable: Enforces official checksums and handles GOROOT/PATH configuration automatically, preventing common "it works on my machine" issues.

Note on auditability
While the script is fully transparent and contains no opaque binaries or generated code, it is not small. “Auditable” here means that all logic is visible, deterministic, and self‑contained — not that the script is trivial to read in its entirety.

Supported Platforms

  • Linux (glibc): First-class target (Debian, Ubuntu, Fedora, CentOS, etc.).
  • Alpine Linux (musl): Supported, but relies on Go's upstream musl compatibility.
  • WSL2: First-class target.
  • WSL1: Supported (best effort).
  • NixOS: Partially supported (installation works, but environment configuration may require manual tweaks due to NixOS's unique structure).
  • macOS: Not supported (use the official pkg installer or Homebrew).

Support for the platforms listed above is based on expected compatibility; only the environments listed in the “Tested Environments” section have been validated directly.

Tested Environments

The installer has been tested directly on the following environments:

Manually tested:

  • WSL2 (Ubuntu 24.04 LTS)
  • Debian 12 (Bookworm)
  • Debian 13 (Trixie)

Not yet tested:

  • Alpine Linux (musl)
  • Fedora, CentOS, RHEL
  • NixOS
  • Other glibc-based distributions

These platforms are expected to work based on POSIX compatibility, but they have not been validated yet.

Usage

Interactive

Run the installed script (or the one-liner) and follow the prompts. The installer will guide you through the process.

Non-interactive Usage

For automation or CI environments, use the --assume-yes flag to skip prompts:

./letsgolang.sh --assume-yes

CLI Options

The installer supports the following flags:

Option Description
-u, --uninstall Uninstall Go (removes binary and environment config)
-v, --verbose Enable verbose mode for detailed logging
-q, --quiet Enable quiet mode (suppress non-essential output)
-y, --assume-yes Run in non-interactive mode (auto-confirm prompts)
--pinned-cert <path> Use a user‑supplied PEM certificate for TLS pinning
--cert-fingerprint <sha256> Use a user‑supplied SHA‑256 fingerprint for TLS pinning
--checksum <sha256> Verify the downloaded file against a specific checksum
-h, --help Print help message
-V, --version Print installer version
--license Print license information

Updating Go

To update Go, simply run the installation command again. letsgolang will detect the new version (if available upstream), verify it, and replace the existing installation in $HOME/.local/opt/go. Your GOPATH and projects remain untouched.

Uninstallation

To uninstall Go, run the script with the --uninstall (or -u) flag:

./src/letsgolang.sh --uninstall

Or using the remote one-liner:

curl --proto '=https' --tlsv1.2 -sSLf https://github.com/jcsxdev/letsgolang/releases/latest/download/letsgolang.sh | sh -s -- --uninstall

This command will:

  1. Remove the Go installation directory ($HOME/.local/opt/go).
  2. Check your shell configuration file for Go-related environment variables and advise you if manual cleanup is needed.

Installation Details

  • Location: Go is installed into $HOME/.local/opt/go.
  • Symlinks: The installer manages GOROOT and PATH settings.
  • Shell Config: It automatically updates your shell profile (e.g., .bashrc, .zshrc, config.fish, or .profile) to include:
    export GOROOT="$HOME/.local/opt/go"
    export PATH="$GOROOT/bin:$HOME/go/bin:$PATH"

Security Model

Go is distributed via HTTPS from https://go.dev/dl/. The Go project publishes checksums (currently only SHA‑256) on that page. There are no official GPG signatures, no transparency log, and no independent authenticated checksum channel.

Although some .asc files exist on the Go download servers and contain valid PGP signatures — for example:

https://go.dev/dl/go1.25.5.linux-amd64.tar.gz.asc

$ file ~/Downloads/go1.25.5.linux-amd64.tar.gz.asc
/home/user/Downloads/go1.25.5.linux-amd64.tar.gz.asc: PGP signature Signature (old)

However, the Go project does not document, support, or guarantee GPG signatures as part of its release process. No official public key, fingerprint, or verification procedure is provided. These signatures appear to be artifacts of Google’s internal infrastructure rather than an official security mechanism. For this reason, letsgolang does not rely on GPG verification.

The Go Authors. (n.d.). Downloads. Retrieved January 11, 2026, from https://go.dev/dl/

What letsgolang currently does

  • Enforces HTTPS security: Uses curl --fail --proto '=https' --tlsv1.2 for all network access to avoid protocol downgrade and enforce TLS 1.2+.
  • Computes local checksums (SHA‑256 and SHA‑512): After downloading the tarball, it computes both SHA‑256 and SHA‑512 for the local file.
  • Uses only SHA‑256 for official verification:
    • The Go download page currently publishes only SHA‑256 checksums.
    • letsgolang matches the local SHA‑256 against the checksums found on https://go.dev/dl/.
    • SHA‑512 is computed for diagnostic/future use, but there is no official SHA‑512 reference to compare against.
  • Aborts on mismatch or failure: If the SHA‑256 hash is not found in the official checksum list, or if checksum calculation or download integrity checks fail, the installer aborts.

Double Checksum Verification

letsgolang implements a robust dual-verification strategy for checksums:

  1. Primary Source (HTML): Parses the official download page (https://go.dev/dl/). This remains the primary source because it is the only officially documented interface for verifying releases. The checksums are visible directly in the page body.
  2. Secondary Source (JSON): Fetches metadata from the undocumented JSON endpoint (https://go.dev/dl/?mode=json). Although not officially advertised on the main Go website, this endpoint is widely used by tools and was referenced by Go maintainers in GitHub Issue #41172.

Note on JSON Endpoint: The JSON API (?mode=json) is undocumented and treated as a best-effort secondary signal, not a source of trust. Its structure may change without notice. If verification against the HTML source succeeds but the JSON check fails (e.g., due to API changes), the installer will still report the failure and abort, adhering to a "secure by default" philosophy.

The installer cross-validates the checksums from both sources. If either fails or if they disagree, the installation aborts. This provides redundancy and protects against interface changes or targeted content manipulation on a single endpoint.

Future roadmap and trade-offs

  • Cross-checking SHA‑256 against independent sources Concept: Verify the hash against Repology, Homebrew, or distro packaging metadata. Trade-off: Increases assurance but adds latency and fragility. Third‑party ecosystems often lag hours or days behind go.dev, which can cause false failures right after a new Go release.

  • Certificate pinning Concept: Hardcode the TLS certificate (or fingerprint) for go.dev to reduce the impact of some MITM attacks. Trade-off: High operational maintenance cost. When Google rotates certificates (which happens regularly), the installer may break until letsgolang is updated.

  • Trust‑on‑First‑Use (TOFU) Concept: Store the verified checksum locally on first run and warn if future downloads of the same version differ. Trade-off: Great for detecting tampering over time, but offers no protection for the very first installation, which still relies on the upstream infrastructure.

  • Heuristic validation Concept: Inspect the tarball structure (e.g., existence of go/bin/go, go/src, etc.) before or after extraction. Trade-off: Helps catch obviously corrupted or malformed archives, but provides no cryptographic guarantee against targeted binary modification.

What letsgolang cannot do (limitations of Go’s distribution model)

  • GPG verification: No official signed release artifacts or public keys are provided by the Go project.
  • Transparency logs: There is no official log (like Sigstore/Rekor) of artifacts to verify against.
  • Independent authenticated checksum channel: Checksums are only available on the same site that serves the binaries, over the same HTTPS connection.
  • Dedicated, authenticated metadata API: All metadata is scraped from the HTML of the download page.

letsgolang cannot provide cryptographic guarantees stronger than those offered by Go’s own distribution model. This is a limitation of Go’s current distribution model, not a design choice made by letsgolang. It focuses on enforcing HTTPS, verifying the downloaded file’s SHA‑256 against the official checksum, and failing fast when something doesn’t match expectations.

Optional: Certificate Pinning

letsgolang supports optional TLS certificate pinning for users who want an additional layer of transport security.
This feature is opt‑in and intended for advanced users. It does not replace checksum verification and may break when upstream certificates rotate.

Two pinning methods are available:

  • --pinned-cert <path>
    Validates the TLS certificate chain using a user‑supplied PEM file (e.g., a custom CA bundle or specific root). Uses curl --cacert.

  • --cert-fingerprint <sha256>
    Validates that the server’s public key matches the provided fingerprint. Uses curl --pinnedpubkey.
    Note: Requires the format sha256//<base64>. See [docs] for details.

Advanced: Extracting Certificate Data for Pinning

To use pinning effectively, you must first extract the valid certificate data from go.dev.

1. Extracting the Public Key Fingerprint

To get the sha256//<base64> hash expected by --cert-fingerprint, run:

# Extract and format the fingerprint
HASH=$(openssl s_client -connect go.dev:443 -servername go.dev </dev/null 2>/dev/null \
| openssl x509 -pubkey -noout \
| openssl pkey -pubin -outform der \
| openssl dgst -sha256 -binary \
| openssl enc -base64)

echo "Fingerprint: sha256//$HASH"

Usage:

# Successful run (matches)
./letsgolang.sh --cert-fingerprint "sha256//$HASH"

# Failing run (mismatch test)
./letsgolang.sh --cert-fingerprint "sha256//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="

2. Extracting the Certificate Chain

To get the PEM file for --pinned-cert, download the chain presented by the server:

openssl s_client -connect go.dev:443 -servername go.dev -showcerts </dev/null 2>/dev/null \
| sed -n '/^-*BEGIN CERTIFICATE-*$/,/^-*END CERTIFICATE-*$/p' \
> go-dev-chain.pem

Usage:

./letsgolang.sh --pinned-cert ./go-dev-chain.pem

Security Note

⚠️ WARNING!

Certificate extraction must be performed on a trusted network. If you extract certificates while under a Man-in-the-Middle (MITM) attack, you will pin the attacker’s certificate, rendering the protection useless. Always verify the extracted data via a secondary channel if possible.

Manual Checksum Verification

For environments requiring strict immutability (like CI/CD pipelines) or where you do not trust the live metadata on go.dev, you can bypass the remote verification entirely by providing the expected SHA-256 hash directly via --checksum.

When this option is used:

  1. The installer downloads the file (using TLS pinning if configured).
  2. It calculates the local SHA-256 hash.
  3. It compares the local hash only against the user-provided value.
  4. Remote metadata (HTML/JSON) is ignored.
./letsgolang.sh --checksum "f022b6aad78e362bcba9b0b94d09ad58c5a70c6ba3b7582905fababf5fe0181a"

Maximum Security Configuration

You can combine Transport Security (TLS Pinning) with Content Integrity (Manual Checksum) for the highest level of assurance. This ensures that you are connecting to the legitimate server and receiving exactly the expected content.

./letsgolang.sh \
  --cert-fingerprint "sha256//<known_fingerprint>" \
  --checksum "<known_file_hash>"

This configuration protects against:

  • MitM Attacks: The connection will fail if the certificate does not match.
  • Compromised Server/Content: The installation will fail if the file hash does not match your expectation.

Design Goals

  • Minimalism: Do one thing well—install Go.
  • Predictability: The script should behave exactly the same way on a fresh container as it does on a developer's workstation.
  • Auditability: Security-conscious users should be able to understand the structure and trust boundaries in minutes.
  • Fail-Fast: If a checksum fails or a dependency is missing, stop immediately.

Non-Goals

  • Multi-version Management: This tool installs the latest stable Go version. For switching between multiple versions, consider tools like asdf or gvm.
  • macOS/Windows Support: Focused strictly on Linux/POSIX environments.
  • Plugin Ecosystem: No plugins, no extensions.
  • GPG Verification: We do not enforce GPG because the Go project does not officially support it for releases.

Requirements

To run the installer, your system needs standard POSIX tools:

  • A standard /bin/sh implementation
  • curl or wget (for downloading)
  • tar (for extraction)
  • sha256sum or shasum (for verification)
  • awk, sed, and grep (for text processing)

Troubleshooting

  • Command not found: If go is not found after installation, try reloading your shell configuration:
    source ~/.bashrc  # or ~/.zshrc, ~/.profile, etc.
  • Permission denied: Ensure the script is executable (chmod +x src/letsgolang.sh).
  • Checksum mismatch: This indicates a corrupted download or a security issue. The installer will abort automatically to protect your system.

FAQ

Why not just extract the Go tarball manually?
Manual installation works, but it is repetitive and error‑prone across machines. letsgolang automates verification, cleanup, and environment configuration in a predictable, auditable way.

Why not use asdf, mise, or gvm?
Those tools are excellent for multi‑version workflows. letsgolang intentionally focuses on a single task: installing the latest stable Go with zero dependencies.

Why no GPG verification?
The Go project does not officially publish signed release artifacts or document a supported GPG verification process. See the Security Model section for details.

Does it work on Alpine, NixOS, or other distros?
These platforms are expected to work based on POSIX compatibility, but they have not been tested yet. See the “Tested Environments” section for details.

Development

To contribute to letsgolang, clone the repository:

git clone https://github.com/jcsxdev/letsgolang
cd letsgolang
./src/letsgolang.sh # Run from source

See CONTRIBUTING.md for more details.

Documentation

License

This project is licensed under either of:

at your option.

About

A minimalist, POSIX‑oriented, non‑root installer for the Go programming language on Linux.

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Contributing

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •