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.
- Overview
- Installation
- Why use letsgolang?
- Supported Platforms
- Usage
- Updating Go
- Uninstallation
- Installation Details
- Security Model
- Optional: Certificate Pinning
- Design Goals
- Non-Goals
- Requirements
- Troubleshooting
- FAQ
- Development
- Documentation
- License
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/goby default, requiring nosudoprivileges. - Auditable: Written in standard
/bin/shwith 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!
letsgolangis 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.
To install Go using letsgolang, run:
curl --proto '=https' --tlsv1.2 -sSLf https://github.com/jcsxdev/letsgolang/releases/latest/download/letsgolang.sh | shNote on curl | sh
This installer uses thecurl | shpattern 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
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- 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
letsgolangaims to be portable across standard/bin/shimplementations 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/PATHconfiguration 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.
- 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.
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.
Run the installed script (or the one-liner) and follow the prompts. The installer will guide you through the process.
For automation or CI environments, use the --assume-yes flag to skip prompts:
./letsgolang.sh --assume-yesThe 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 |
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.
To uninstall Go, run the script with the --uninstall (or -u) flag:
./src/letsgolang.sh --uninstallOr using the remote one-liner:
curl --proto '=https' --tlsv1.2 -sSLf https://github.com/jcsxdev/letsgolang/releases/latest/download/letsgolang.sh | sh -s -- --uninstallThis command will:
- Remove the Go installation directory (
$HOME/.local/opt/go). - Check your shell configuration file for Go-related environment variables and advise you if manual cleanup is needed.
- Location: Go is installed into
$HOME/.local/opt/go. - Symlinks: The installer manages
GOROOTandPATHsettings. - 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"
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/
- Enforces HTTPS security: Uses
curl --fail --proto '=https' --tlsv1.2for 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.
letsgolangmatches the local SHA‑256 against the checksums found onhttps://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.
letsgolang implements a robust dual-verification strategy for checksums:
- 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. - 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.
-
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.devto reduce the impact of some MITM attacks. Trade-off: High operational maintenance cost. When Google rotates certificates (which happens regularly), the installer may break untilletsgolangis 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.
- 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.
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). Usescurl --cacert. -
--cert-fingerprint <sha256>
Validates that the server’s public key matches the provided fingerprint. Usescurl --pinnedpubkey.
Note: Requires the formatsha256//<base64>. See [docs] for details.
To use pinning effectively, you must first extract the valid certificate data from go.dev.
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="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.pemUsage:
./letsgolang.sh --pinned-cert ./go-dev-chain.pem
⚠️ 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.
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:
- The installer downloads the file (using TLS pinning if configured).
- It calculates the local SHA-256 hash.
- It compares the local hash only against the user-provided value.
- Remote metadata (HTML/JSON) is ignored.
./letsgolang.sh --checksum "f022b6aad78e362bcba9b0b94d09ad58c5a70c6ba3b7582905fababf5fe0181a"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.
- 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.
- Multi-version Management: This tool installs the latest stable Go version. For switching between multiple versions, consider tools like
asdforgvm. - 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.
To run the installer, your system needs standard POSIX tools:
- A standard
/bin/shimplementation curlorwget(for downloading)tar(for extraction)sha256sumorshasum(for verification)awk,sed, andgrep(for text processing)
- Command not found: If
gois 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.
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.
To contribute to letsgolang, clone the repository:
git clone https://github.com/jcsxdev/letsgolang
cd letsgolang
./src/letsgolang.sh # Run from sourceSee CONTRIBUTING.md for more details.
This project is licensed under either of:
at your option.