Docker environment for building musl based static rust binaries
Switch branches/tags
Nothing to show
Clone or download


build status docker pulls docker image info docker tag

A plain docker environment for building static binaries compiled with rust and linked against musl instead of glibc. Built nightly on travis.

This is only useful if you require external C dependencies, because otherwise you could do rustup target add x86_64-unknown-linux-musl.

This container comes with a bunch of statically compiled C libraries using musl-gcc so that we can statically link against these as well.

If you already have rustup installed on the machine that should compile, you might consider cross as a more general solution for cross compiling rust binaries.


Pull and run from a rust project root:

docker pull clux/muslrust
docker run -v $PWD:/volume --rm -t clux/muslrust cargo build

You should have a static executable in the target folder:

ldd target/x86_64-unknown-linux-musl/debug/EXECUTABLE
        not a dynamic executable

From there on, you can include it in a blank docker image (because everything you need is included in the binary) and perhaps end up with a 5MB docker blog image.

Docker builds

Latest is always the last built nightly pushed by travis. To pin against specific builds, see the available tags on the docker hub.

C Libraries

The following system libraries are compiled against musl-gcc:

We try to keep these up to date.

If it weren't for pq, we could ditch zlib as the flate2 crate bundles miniz.c as the default implementation, and this just works. Similarly, curl is only needed for people using the C bindings to curl over hyper.

If you need extra dependencies, you can follow the builder pattern approach by portier-broker


Clone, tweak, build, and run tests:

git clone && cd muslrust
make build
make test

Before we push a new version of muslrust we ensure that we can use and statically link:

  • serde
  • diesel (postgres and sqlite - see note below for postgres)
  • hyper
  • curl
  • openssl
  • flate2
  • rand
  • rocket (nightly only - some gaps)

SSL Verification

You need to point openssl at the location of your certificates explicitly to have https requests not return certificate errors.

export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
export SSL_CERT_DIR=/etc/ssl/certs

You can also hardcode this in your binary, or, more sensibly set it in your running docker image. The openssl-probe crate can be also be used to detect where these reside.

Diesel and PQ builds

Works without fork now. See the test/dieselpgcrate for how to get this working.

For stuff like infer_schema! to work you need to explicitly pass on -e DATABASE_URL=$DATABASE_URL to the docker run. It's probably easier to just make diesel print-schema > src/ part of your migration setup though.

Caching Cargo Locally

Repeat builds locally are always from scratch (thus slow) without a cached cargo directory. You can set up a docker volume by just adding -v cargo-cache:/root/.cargo to the docker run command.

You'll have an extra volume that you can inspect with docker volume inspect cargo-cache.

Suggested developer usage is to add the following function to your ~/.bashrc:

musl-build() {
  docker run \
    -v cargo-cache:/root/.cargo \
    -v "$PWD:/volume" \
    --rm -it clux/muslrust cargo build --release

Then use in your project:

$ cd myproject
$ musl-build
    Finished release [optimized] target(s) in 0.0 secs

Second time around this will be quick, and you can even mix it with native cargo build calls without screwing with your cache.

Debugging on alpine

If you are running a plain alpine/scratch container with your musl binary in there, then even if you add ENV RUST_BACKTRACE=full to your Dockerfile, your stacktraces will look like a longer version of this:

app_1  | stack backtrace:
app_1  |    0:           0x870b03 - <unknown>
app_1  |    1:           0x86ca10 - <unknown>
app_1  |    2:           0x875623 - <unknown>
app_1  |    3:           0x875392 - <unknown>

To debug in the container, you seem to need to have the rust package installed (from apk), as well as debug symbols compiled in (to get line numbers).

Using muslrust on CI

Due to the current best compatibility with docker caching strategies, recommended CI is Circle. See webapp-rs for a complete life-cycle example of a rust cloud application on alpine built on CI.


If you need to install clippy on a CI build image, you need to build it against the GNU toolchain (see #37):

CARGO_BUILD_TARGET=x86_64-unknown-linux-gnu cargo install clippy


On SELinux enabled systems like Fedora, you will need to configure selinux labes. E.g. adding the :Z or :z flags where appropriate: -v $PWD:/volume:Z.