
A fresh Ubuntu 26.04 LTS server is easy to set up, and then someone asks for a Rust toolchain. It looks like a two-minute job. Then cargo build stops with “linker cc not found”, or a crate wants OpenSSL headers that aren’t there. The CI runner works, but the production box compiles a different Rust version from the one on your laptop. Each of these problems is small, but together they can eat an afternoon.
Ubuntu 26.04 LTS “Resolute Raccoon” was released on April 23, 2026. It leans on Rust more than any Ubuntu release before it. The default sudo is now sudo-rs, and a large share of the core utilities come from the Rust-based rust-coreutils project. Installing a Rust toolchain on this release is a very normal thing to do.
There are two sensible ways to do it. You can use the compiler packaged by Ubuntu through APT, or you can use rustup, the toolchain manager maintained by the Rust project. They suit different jobs, and mixing them carelessly causes confusing behavior. This guide covers both methods and explains when each fits. It also covers the build dependencies people forget, the PATH and permission problems that catch people out, and the settings that matter on a real server.
The commands below were written for Ubuntu 26.04. Where Debian or AlmaLinux differ, a note says so.
Which Install Method Should You Pick?
The choice depends on what the machine does.
Ubuntu 26.04 ships Rust 1.93.x in its default repositories. LinuxCapable’s install guide confirms that the default APT packages resolve to Rust and Cargo 1.93.x on 26.04. Ubuntu’s own developer documentation lists the same 1.93 version for 26.04. That version is stable and patched by Canonical, and it stays fixed for the life of the release.
The official rustup installer tracks the newest stable release. The Rust project’s own documentation describes it as the recommended way to get Rust, and it installs to ~/.cargo/bin.
| Scenario | Best method | Why |
|---|---|---|
| Developer workstation | rustup | Newest stable, easy beta and nightly switching |
| CI runner or build server | rustup, pinned version | Reproducible builds across machines |
| Building one tool from source | APT | Quick, no extra files in home directory |
| Packaging for .deb distribution | APT toolchain | Matches the distro’s own build environment |
| Locked-down production host | APT, or no compiler at all | Smaller attack surface, vendor-patched |
| Cross-compiling (musl, ARM, WASM) | rustup | Targets are one command away |
My own rule is simple. Production hosts should rarely have a compiler on them at all. Build in CI, ship the binary. A compiler on a public-facing server is a convenience for an attacker and a drift risk for you. Developer boxes and build runners are different, and rustup is the better choice for them.
Prerequisites and System Preparation
Start by checking what you have. The commands are short, and they save time later.
lsb_release -a
uname -m
df -h /home
free -h
You want Ubuntu 26.04 on x86_64 or aarch64. Both are well supported. On disk, a rustup install with the default profile uses somewhere around 1 to 1.5 GB under ~/.rustup. Plan for several more gigabytes if you build large projects, because the target/ directory grows quickly. RAM matters more than people expect. Linking big binaries can spike memory use, so a 1 GB VPS will struggle with heavy crates.
Update the system first
sudo apt update
sudo apt full-upgrade -y
On a server that has been running a while, reboot afterward if the kernel changed. Then confirm sudo works as expected. Ubuntu 26.04 uses sudo-rs by default, and traditional sudo remains available as the sudo.ws package. For installing Rust, the difference rarely matters. It can matter if you have old scripts that depend on unusual sudoers syntax or on sudo -E behavior, so test them.
Install the build dependencies
This is the step most tutorials skip, and it causes most “Rust is broken” complaints. Rust needs a C linker, and many popular crates compile C code or link against system libraries. The Rust book says that Linux users should generally install GCC or Clang, and on Ubuntu that means the build-essential package.
sudo apt install -y build-essential pkg-config libssl-dev curl ca-certificates git
Each package has a job:
build-essentialprovidesgcc,g++,makeand the linker thatrustccalls.pkg-configlets build scripts find system libraries.libssl-devsatisfies theopenssl-syscrate, which a surprising number of projects pull in.curlandca-certificateslet you download the installer over verified TLS.gitis needed for crates fetched from Git repositories.
On Debian the same command works. On AlmaLinux or Rocky, use this instead:
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y openssl-devel pkgconf-pkg-config curl git
Method 1: Install Rust with rustup (Recommended)
This is the route for most people. It gives you rustc, cargo, rustup and the standard tools in your home directory, with no root access needed beyond the build dependencies.
Step 1: Download and run the installer
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
The flags are worth understanding. --proto '=https' refuses any redirect to plain HTTP. --tlsv1.2 sets a minimum TLS version. -sSf keeps curl quiet but still shows errors, and it fails on HTTP errors instead of piping an error page into your shell. This is the command the Rust project publishes.
Piping a script straight into sh makes some admins uneasy, and that instinct is healthy. A more careful approach is to download first, read it, then run it:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup-init.sh
less rustup-init.sh
sh rustup-init.sh
The Arch Wiki recommends the same download, inspect and run pattern. On a regulated server, add a checksum comparison against the standalone rustup-init binaries published by the project.
Step 2: Choose the installation option
The installer shows a menu. You will see options for the default installation, customization, and cancel. Option 1 is right for most people. Choose option 2 when you need something specific:
- A minimal profile, which skips documentation and saves disk space on CI runners.
- A specific default toolchain, such as a pinned version.
- Skipping PATH modification, if you manage shell profiles through configuration management.
A non-interactive install is better for automation:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable
The -y flag accepts defaults, and --profile minimal installs just rustc, rust-std and cargo. Add clippy and rustfmt later if you want them.
Step 3: Load Cargo into your current shell
The installer appends a line to your shell profile. That change only applies to new sessions, so load it manually this time:
. "$HOME/.cargo/env"
The Arch Wiki makes the same point about sourcing the environment file until you log out and back in. The rustup book also says to open a new shell before checking the version.
Step 4: Verify the installation
rustc --version
cargo --version
rustup --version
rustup show
You should see a stable version number. Rust releases a new stable roughly every six weeks, so what you see depends on the date. Today is October 2, 2026, and the number will be well ahead of the 1.93 that Ubuntu packages.
Step 5: Compile something real
A hello world test proves the whole chain works, linker included.
cargo new hello_rust
cd hello_rust
cargo run
Expected output is Hello, world! after a short compile. If this works, the compiler, Cargo, the linker and the crate registry connection are all fine. Now try a dependency that touches native code. Add reqwest to Cargo.toml and build. If OpenSSL headers are missing, you will find out now instead of during a deploy.
Method 2: Install Rust from Ubuntu’s APT Repository
This approach is simple and conservative. You get a distribution-tested compiler, updated through normal apt upgrade cycles.
sudo apt update
sudo apt install -y rustc cargo
rustc --version
cargo --version
On Ubuntu 26.04 this installs the 1.93 series. A computingforgeeks walkthrough recorded 1.93.1 from the default repositories for this release.
Versioned packages
Ubuntu also offers versioned Rust packages, so you can install a specific toolchain beside the default one. Ubuntu’s availability table lists several available 26.04 versions and a naming scheme like rustc-1.97. Check what exists before assuming a name:
apt-cache search --names-only '^rustc-[0-9]'
apt policy rustc
Versioned packages install binaries such as rustc-1.93 and cargo-1.93. That is useful when a Debian packaging workflow needs a known compiler version.
The rustup package and the snap
Ubuntu 26.04 also packages rustup itself, though the repository version trails the upstream release. Ubuntu additionally offers a rustup snap with stable, beta and nightly channels. They work, but on servers the official script is the most predictable choice, because its behavior is the same on every distribution you manage.
Don’t Mix APT Rust and rustup Rust
This mistake shows up on real machines all the time. Someone installs rustc from APT months ago, then runs the rustup installer. Now /usr/bin/rustc and ~/.cargo/bin/rustc both exist. Which one runs depends on PATH order, and different users, cron jobs and systemd units see different results.
Diagnose it with:
type -a rustc
which -a cargo
echo "$PATH"
If you see two entries, pick one. For a rustup setup, remove the APT packages:
sudo apt remove --purge rustc cargo
sudo apt autoremove -y
hash -r
The hash -r command clears bash’s cached command locations. Without it, your shell may keep looking for the deleted binary. This matters for scripts too. A deploy script that runs under a non-login shell will not read ~/.bashrc, so it may not find ~/.cargo/bin at all. Set the PATH explicitly in such scripts:
export PATH="$HOME/.cargo/bin:$PATH"
Managing Toolchains, Components and Targets
Installing Rust is the easy part. Running it well over months is where rustup earns its place.
Update and switch channels
rustup update
rustup self update
rustup toolchain list
rustup default stable
rustup toolchain install nightly
rustup toolchain install 1.93.0
rustup update refreshes installed toolchains. The Rust documentation points to it for getting the latest version. rustup self update upgrades rustup itself, which is a separate step.
Pin a version per project
Teams with more than one developer should commit a rust-toolchain.toml file at the project root:
[toolchain]
channel = "1.93.0"
components = ["rustfmt", "clippy"]
targets = ["x86_64-unknown-linux-musl"]
profile = "minimal"
When someone runs cargo build in that directory, rustup fetches the right toolchain automatically. This removes the classic “works on my machine” problem. It also keeps CI and production builds identical, which is the whole point of reproducibility.
Add components
rustup component add rustfmt clippy rust-analyzer
rustup component list --installed
rustfmt formats code, clippy is the linter, and rust-analyzer powers editor features. On a headless build runner, clippy and rustfmt are usually all you need.
Cross-compilation targets
rustup target add x86_64-unknown-linux-musl
rustup target add aarch64-unknown-linux-gnu
rustup target add wasm32-unknown-unknown
The musl target produces statically linked binaries that run on nearly any Linux distribution, which makes deployment much simpler. You may also need a musl cross compiler:
sudo apt install -y musl-tools
cargo build --release --target x86_64-unknown-linux-musl
For ARM targets, install the cross linker (gcc-aarch64-linux-gnu) and point Cargo at it in ~/.cargo/config.toml:
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
Performance Tuning for Rust Builds
Rust compiles slowly compared with many languages, and the cost grows with project size. A few adjustments make a large difference.
CPU
Cargo uses all cores by default. On shared hosts, cap it with -j or the CARGO_BUILD_JOBS variable. For release builds, link-time optimization produces smaller, faster binaries but takes longer. Tune it in Cargo.toml:
[profile.release]
opt-level = 3
lto = "thin"
codegen-units = 16
strip = true
Lowering codegen-units to 1 gives the best runtime performance and the slowest build. For everyday work, thin LTO with the default units is a reasonable middle ground.
Linker
The default linker can be the slowest phase on big projects. Faster linkers such as lld or mold cut link times noticeably. Install one and tell Cargo to use it:
sudo apt install -y lld clang
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
Put that in ~/.cargo/config.toml or the project’s .cargo/config.toml. Test that it works before rolling it out to a team, since a few crates behave badly with alternative linkers.
RAM and swap
A linker plus several rustc processes can use several gigabytes at once. On small VPS instances, the out-of-memory killer ends builds with a cryptic “signal: 9, SIGKILL” message. Reduce parallelism with -j 1, or add swap:
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
Swap is a safety net, not a performance feature. Builds that depend on it will be slow, but they will finish.
Disk I/O
The target/ directory generates a huge number of small files. Put it on fast storage, ideally NVMe. On a machine with a slow disk, you can point Cargo at a tmpfs directory for throwaway builds:
export CARGO_TARGET_DIR=/dev/shm/target
Remember that tmpfs lives in RAM and disappears on reboot. For long-term hygiene, install cargo-sweep or periodically run cargo clean on old projects. A forgotten target/ folder can fill a disk without warning.
Compile caching
sccache caches compiler output and helps most on CI systems:
cargo install sccache --locked
export RUSTC_WRAPPER=sccache
sccache --show-stats
Installing it with cargo install compiles it from source, which takes a few minutes the first time.
Network
Cargo downloads crates from the registry over HTTPS. Behind a corporate proxy, set HTTPS_PROXY. On flaky connections, raise retries in ~/.cargo/config.toml:
[net]
retry = 5
[registries.crates-io]
protocol = "sparse"
Sparse is already the default in recent Cargo, so the second entry is only a safeguard for older setups. For offline or air-gapped hosts, use cargo vendor to bundle dependencies into the repository.
Security Considerations
A toolchain executes arbitrary code at build time. Every crate can run a build.rs script with your privileges. That is the main risk, so treat it as one.
Do not build as root
Never run cargo build or rustup as root unless you have a specific reason. Create a dedicated user for builds:
sudo adduser --disabled-password --gecos "" builder
Running as an unprivileged user limits the damage from a malicious or buggy build script.
Audit your dependencies
cargo install cargo-audit --locked
cargo audit
cargo install cargo-deny --locked
cargo deny check
cargo-audit checks your lock file against the RustSec advisory database. cargo-deny adds license and source policies. Run both in CI. Commit Cargo.lock for applications so builds use the same versions every time, and use --locked in build commands to fail when the lock file is out of date.
Firewall and network exposure
A build box rarely needs inbound access beyond SSH. Keep UFW tight:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status verbose
Outbound access is needed for static.rust-lang.org and the crates registry. If you restrict egress, allow those hosts. Keep the OS patched with unattended-upgrades, and keep Rust updated as well, since compiler and standard library fixes ship regularly.
File permissions
chmod 700 ~/.cargo
chmod 600 ~/.cargo/credentials.toml 2>/dev/null
The credentials.toml file holds registry API tokens if you publish crates. Treat it like an SSH key. Never commit it, and never bake it into container images. Use short-lived CI secrets instead.
Troubleshooting Common Errors
These are the problems that show up most often on Ubuntu servers, with the fix for each.
error: linker `cc` not found
The C toolchain is missing. Install it:
sudo apt install -y build-essential
failed to run custom build command for `openssl-sys`
OpenSSL development headers or pkg-config are absent:
sudo apt install -y libssl-dev pkg-config
If you would rather avoid system OpenSSL, many crates offer a rustls feature. Switching to it removes the dependency completely and simplifies static builds.
cargo: command not found
PATH does not include ~/.cargo/bin. Run . "$HOME/.cargo/env" or open a new shell. For cron and systemd, set PATH explicitly. In a systemd unit:
[Service]
Environment="PATH=/home/builder/.cargo/bin:/usr/local/bin:/usr/bin:/bin"
curl: (60) SSL certificate problem
The CA bundle is missing or the clock is wrong. Fix both:
sudo apt install -y ca-certificates
sudo update-ca-certificates
timedatectl status
On a minimal container, missing certificates are the usual cause. Do not “fix” it with curl -k, because that disables verification.
error: could not compile … signal: 9, SIGKILL
The kernel’s out-of-memory killer ended the process. Confirm it:
dmesg | grep -i -E 'killed process|out of memory'
Then reduce -j, add swap, or use a bigger instance.
Two different rustc versions
See the earlier section on mixing APT and rustup. Run type -a rustc, remove the one you do not want, and clear the shell hash.
rustup: unable to write to the home directory, or permission denied on ~/.cargo
This often happens after someone ran sudo cargo or sudo rustup once, leaving root-owned files in a user’s directory:
sudo chown -R "$USER":"$USER" ~/.cargo ~/.rustup
Slow or stalled crate downloads
Try a different network path, check DNS, and raise net.retry. If your provider throttles connections, a local mirror or vendored dependencies will make builds more reliable.
sudo behaves differently than expected
Since Ubuntu 26.04 uses sudo-rs by default, some old environment-handling habits may not carry over exactly. If a legacy script breaks, check the Ubuntu Server documentation on sudo-rs, which notes that sudo.ws remains available as an alternative provider. Cases like this are rare for Rust installs, but they are worth knowing about when you run automation on a new LTS.