This project generates Docker images to build static musl binaries using the Rust language. It has several pre-build C/C++ libraries to either speedup the compile time of the Rust project or make it possible to build a project at all like Diesel with MySQL.
These container images are based upon Ubuntu 26.04 and use GCC v15.2.0 to build the toolchains and GCC v15.3.0 for the libraries.
Since 2026-06 all images are built using musl v1.2.6 using https://github.com/crosstool-ng/crosstool-ng.
And since 2025-02-15 all images are available for amd64 and arm64 host platforms.
The following libraries are pre-built and marked as STATIC already via ENV variables so that the Rust Crates know there are static libraries available already.
- ZLib (
v1.3.2) - OpenSSL (
v3.5.8) - cURL (
v8.22.0) - sccache (
0.18.0) - PostgreSQL lib (
v17.11) + (v18.6), (v16.15) and (v15.19) - SQLite (
v3.53.4) - MariaDB Connector/C (
v3.4.8) (MySQL Compatible) - libxml2 (
v2.15.4)
To see the changes, check out the Changelog
Both stable and nightly builds are available.
The latest nightly's are always suffixed with -nightly, if you want to use a specific date, check whether the image exists then use the -nightly-YYYY-MM-DD tag.
Nightly's are built every morning around 9:30 UTC (If GitHub Allows it).
For stable you can just use the tags listed below, or add -stable to it.
If you want to be sure that you are using a specific stable version you can use -X.Y.Z or -stable-X.Y.Z.
Stables builds are triggered automatically when a new version is available.
Tip
2025-02-15:
Created aarch64 (arm64) images as base containers!
From this day on you can also build on aarch64 (arm64) architectures like on a Raspberry Pi 4 or 5.
Or even use the GitHub arm64 runners (which are also used to build the containers for this repo).
This means that you can build x86_64 (amd64) binaries on an aarch64 (arm64) host.
The OCI images are multi-platform containers and all should work the same for both platforms.
The default PostgreSQL lib used is v17.
If you want to use v18 or v15 you need to overwrite an environment variable so that the pq-sys crate will look at the right directory.
Adding -e PQ_LIB_DIR="/usr/local/musl/pq18/lib" at the cli or ENV PQ_LIB_DIR="/usr/local/musl/pq18/lib" to your custom build image will trigger the v18 version to be used during the build.
| Cross Target | Container Tag |
|---|---|
| x86_64-unknown-linux-musl | x86_64-musl |
| armv7-unknown-linux-musleabihf | armv7-musleabihf |
| aarch64-unknown-linux-musl | aarch64-musl |
| arm-unknown-linux-musleabi | arm-musleabi |
To make use of these images you can either use them as your main FROM in your Dockerfile.
The images are pushed to multiple container registries.
| Container Registry |
|---|
| https://github.com/BlackDex/rust-musl/pkgs/container/rust-musl |
| https://hub.docker.com/r/blackdex/rust-musl |
| https://quay.io/repository/blackdex/rust-musl |
FROM ghcr.io/blackdex/rust-musl:aarch64-musl AS build
COPY . /home/rust/src
# If you want to use PostgreSQL v18 add and uncomment the following ENV
# ENV PQ_LIB_DIR="/usr/local/musl/pq18/lib"
RUN cargo build --release
FROM scratch
WORKDIR /
COPY --from=build /home/rust/src/target/aarch64-unknown-linux-musl/release/my-application-name .
CMD ["/my-application-name"]If you want to use the PostgreSQL v18 client library add -e PQ_LIB_DIR="/usr/local/musl/pq18/lib" before the -v "$(pwd)" argument.
# First pull the image:
docker pull ghcr.io/blackdex/rust-musl:aarch64-musl
# Then you could either create an alias
alias rust-musl-builder='docker run --rm -it -v "$(pwd)":/home/rust/src ghcr.io/blackdex/rust-musl:aarch64-musl'
rust-musl-builder cargo build --release
# Or use it directly
docker run --rm -it -v "$(pwd)":/home/rust/src ghcr.io/blackdex/rust-musl:aarch64-musl cargo build --releaseYou can also use these images as a GitHub Actions container.
A simple workflow to build aarch64 binaries looks like this.
name: "Build container"
on:
push:
branches:
- main
jobs:
build_container:
runs-on: ubuntu-latest
container: ghcr.io/blackdex/rust-musl:aarch64-musl-stable
steps:
- uses: actions/checkout@v4
- name: Build
run: |
cargo build --releaseYou can verify all my images using the gh client.
For example, to verify the aarch64 v1.96.0 image.
gh attestation verify --owner BlackDex oci://ghcr.io/blackdex/rust-musl:aarch64-musl-stable-1.96.0Sometimes musl based binaries are slower than glibc based binaries.
This is mostly because of the memory allocator (malloc) which is not that fast.
One way to improve the performance is to use a different allocator within your Rust project.
For example, Vaultwarden uses MiMalloc via mimalloc_rust.
Other memory allocators exists too, just see which one fits your application the best.
The tests that run after building also test the MiMalloc crate.
If you want to build the bundled/vendored Oracle MySQL Client Library provided by the mysqlclient-sys crate, you need to add a special file to the container so that the cmake build script thinks the host runs Alpine. This enables special handling that is done for musl based compilers. It is as simple as just run touch /etc/alpine-release before you run any cargo build action.
In the test.sh script this is done automatically when the vendored_mysql feature is used for testing.
Note that Oracle MySQL can only be built on 64bit architectures, and thus will only work on amd64/x86_64 or arm64/aarch64 builds.
During the automatic build workflow the images are first tested with Rust projects that test all built C/C++ Libraries using Diesel for the database libraries, and openssl, zlib and curl for the other pre-built libraries.
If the test fails, the image will not be pushed to Docker Hub.
Because of some strange bugs/quirks it sometimes happens that on some platforms the linker reports missing __atomic* symbols. The strange thing is, these are available, but for some reason ignored by the linker or rustc (if someone knows a good solution here, please share).
Because of this some platforms need an extra RUSTFLAGS which provides the correct location of the c archive .a file.
| Cross Target | RUSTFLAG |
|---|---|
| arm-unknown-linux-musleabi | -Clink-arg=-latomic |
I started this project to make it possible for Vaultwarden to be built statically with all supported databases. SQLite is not really an issue, since that has a bundled option. But PostgreSQL and MariaDB/MySQL do not have a bundled/vendored feature available or not for all architectures.
I also wanted to get a better understanding of the whole musl toolchain and Github Actions, which I did.
Some projects I got my inspiration from:
- https://github.com/messense/rust-musl-cross
- https://github.com/clux/muslrust
- https://github.com/emk/rust-musl-builder
Projects used to get this working:
Other links for projects used in the past: