Sign inSign up
Rust

dhi.io/rust

Rust

CIS
FIPS
STIG
linux/amd64
linux/arm64

Rust is a systems programming language focused on safety, speed, and concurrency.

How to use this image

All examples in this guide use the public image. If you’ve mirrored the repository for your own use (for example, to your Docker Hub namespace), update your commands to reference the mirrored image instead of the public one.

For example:

  • Public image: dhi.io/<repository>:<tag>
  • Mirrored image: <your-namespace>/dhi-<repository>:<tag>

For the examples, you must first use docker login dhi.io to authenticate to the registry to pull the images.

What's included in this Rust image

This Docker Hardened Rust image includes the Rust toolchain and essential build tools in a single, security-hardened package:

  • rustc: Rust compiler, and the default command the image runs
  • cargo: Rust package manager and build tool
  • sfw: Socket Firewall, which mediates network access while cargo fetches crates (sfw variants only)
  • OpenSSL development headers and pkg-config, so crates such as openssl-sys link the validated FIPS provider rather than a bundled copy (fips-dev variants only)

Start a Rust instance

Run the following command to run a Rust instance.

docker run --rm dhi.io/rust:<tag> rustc --version

Create a simple Rust program and run it directly from the container:

docker run -p 8000:8000 -v $(pwd):/app -w /app dhi.io/rust:<tag>-dev sh -c 'cat > main.rs << EOF
fn main() {
    println!("Hello from DHI Rust!");
}
EOF
rustc main.rs && ./main'

Common Rust use cases

Build and run a Rust application

The recommended way to use this image is to use a multi-stage Dockerfile with the dev variant as the build environment and the runtime variant as the runtime environment. Before writing the Dockerfile, let's create the project files:

Step 1: Create Cargo.toml
cat > Cargo.toml << EOF
[package]
name = "docker-rust-hello"
version = "0.1.0"
edition = "2024"

[dependencies]
EOF
Step 2: Create src directory and main.rs
mkdir src
cat > src/main.rs << EOF
use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};

fn main() {
    let listener = TcpListener::bind("0.0.0.0:8000").unwrap();
    println!("Server running on port 8000");

    for stream in listener.incoming() {
        let stream = stream.unwrap();
        handle_connection(stream);
    }
}

fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();

    let response = "HTTP/1.1 200 OK\r\n\r\nHello from DHI Rust!";
    stream.write(response.as_bytes()).unwrap();
    stream.flush().unwrap();
}
EOF
Step 3: Generate the lock file
docker run --rm -v $(pwd):/app -w /app dhi.io/rust:<tag>-dev cargo generate-lockfile
Step 4. Create the Dockerfile

Create a Dockerfile with the following content to compile and run the project.

################################################################################
# Create a stage for building the application.
FROM dhi.io/rust:<tag>-dev AS build
WORKDIR /build

RUN --mount=type=bind,source=src,target=src \
    --mount=type=bind,source=Cargo.toml,target=Cargo.toml \
    --mount=type=bind,source=Cargo.lock,target=Cargo.lock \
    --mount=type=cache,target=/build/target/ \
    --mount=type=cache,target=/usr/local/cargo/git/db \
    --mount=type=cache,target=/usr/local/cargo/registry/ \
    cargo build --locked --release && \
    cp /build/target/release/docker-rust-hello /build/server

################################################################################
# Create a new stage for running the application with security-hardened runtime environment

FROM dhi.io/rust:<tag> AS final

# Copy the executable from the "build" stage.
COPY --from=build /build/server ./server


# Expose the port that the application listens on.
EXPOSE 8000

# What the container should run when it is started.
CMD ["./server"]

You can then build and run the Docker image:

docker build -t my-rust-app .
docker run -d -p 8000:8000 --name my-rust-app my-rust-app

# Test endpoints
curl http://localhost:8000/

# Clean up
docker stop my-rust-app && docker rm my-rust-app

Image variants

The Rust Hardened Image is available as runtime, dev, Socket Firewall, and FIPS variants.

Docker Hardened Images come in different variants depending on their intended use. Image variants are identified by their tag.

Runtime variants are designed to run your application in production. These images are intended to be used either directly or as the FROM image in the final stage of a multi-stage build. These images typically:

  • Run as a nonroot user
  • Do not include a shell or a package manager
  • Contain only the minimal set of libraries needed to run the app

Build-time variants typically include dev in the tag name and are intended for use in the first stage of a multi-stage Dockerfile. These images typically:

  • Run as the root user

  • Include a shell and package manager

  • Are used to build or compile applications

  • FIPS variants include fips in the variant name and tag. They come in both runtime and build-time variants. These variants use cryptographic modules that have been validated under FIPS 140, a U.S. government standard for secure cryptographic operations. For example, usage of MD5 fails in FIPS variants.

Build crates against the FIPS OpenSSL provider

The Rust standard library and Cargo do not perform cryptography themselves, so a FIPS Rust image supplies the validated OpenSSL provider that your crates link against. Crates that bind to the system OpenSSL, such as openssl and openssl-sys, pick it up through pkg-config. The fips-dev variant ships the matching OpenSSL headers so those crates compile in the build stage:

FROM dhi.io/rust:<tag>-fips-dev AS build
WORKDIR /build

RUN --mount=type=bind,source=src,target=src \
    --mount=type=bind,source=Cargo.toml,target=Cargo.toml \
    --mount=type=bind,source=Cargo.lock,target=Cargo.lock \
    cargo build --locked --release && \
    cp /build/target/release/my-app /build/my-app

FROM dhi.io/rust:<tag>-fips AS final

COPY --from=build /build/my-app ./my-app

CMD ["./my-app"]

Crates that use a bundled or pure-Rust cryptographic implementation instead of the system OpenSSL — for example the openssl crate's vendored feature, or ring — are not covered by the validated module. Select an OpenSSL-backed provider, such as rustls-openssl, when the module boundary has to hold.

Docker Official Images vs Docker Hardened Images

Key differences
FeatureDocker Official RustDocker Hardened Rust
SecurityStandard base with common utilitiesAdvanced security hardening with reduced attack surface via selective tool removal
Runtime environmentFull shell and tools availableShell and Rust toolchain available, source control removed
ToolchainSame tools, same userSame tools, secure user separation
User securityRuns as root by defaultSecure non-root execution in runtime, root in dev
Attack surfaceLarger due to additional utilitiesReduced via user security + tool filtering
DebuggingTraditional shell debuggingAdvanced debugging with Docker Debug - comprehensive tools without compromising security
Base OSVarious Alpine/Debian/Ubuntu versionsSecurity-hardened Alpine or Debian base
Why selective hardening with maintained functionality?

Docker Hardened Images provide enhanced security through targeted improvements:

  • Enhanced security: Non-root user execution and source control tool removal
  • Maintained functionality: Rust toolchain and shell access preserved for operational flexibility
  • User privilege separation: Dev variants run as root for development needs, runtime variants run as nonroot
  • Selective tool removal: Source control tools removed (both dev and runtime) while preserving essential development capabilities
  • Advanced debugging capabilities: Docker Debug provides comprehensive debugging tools through an ephemeral, secure layer

Migrate to a Docker Hardened Image

To migrate your application to a Docker Hardened Image, you must update your Dockerfile. At minimum, you must update the base image in your existing Dockerfile to a Docker Hardened Image. This and a few other common changes are listed in the following table of migration notes:

ItemMigration note
Base imageReplace your base images in your Dockerfile with a Docker Hardened Image.
Nonroot userRuntime images run as a nonroot user. Ensure that necessary files and directories are accessible to that user
Multi-stage buildUtilize images with a dev tag for build stages and runtime images for runtime.
TLS certificatesDocker Hardened Images contain standard TLS certificates by default. There is no need to install TLS certificates.
PortsNon-dev hardened images run as a nonroot user by default. Configure your Rust application to use ports above 1024.
Entry pointInspect entry points for Docker Hardened Images and update your Dockerfile if necessary.
Migration process
  1. Find hardened images for your app. A hardened image may have several variants. Inspect the image tags and find the image variant that meets your needs. Rust images are available in multiple versions.

  2. Update the base image in your Dockerfile. Update the base image in your application's Dockerfile to the hardened image you found in the previous step. For Rust applications, this is typically going to be an image tagged as dev because it has the Rust toolchain needed to compile applications.

    Example:

    FROM dhi.io/rust:<version>-dev
    
  3. For multi-stage Dockerfiles, update the runtime image in your Dockerfile. To ensure that your final image is as minimal as possible, you should use a multi-stage build. Use dev images for build stages and runtime images for final runtime.

  4. Install additional packages Docker Hardened Images selectively remove certain tools while maintaining operational capabilities. You may need to install additional packages in your Dockerfile.

    Both dev and runtime variants include cargo and rustc. You should use a multi-stage Dockerfile to install the packages. Install the packages in the build stage that uses a dev image. Then copy any necessary artifacts to the runtime stage that uses a minimal image.

Troubleshoot migration

General debugging

Docker Hardened Images provide robust debugging capabilities through Docker Debug, which attaches comprehensive debugging tools to running containers while maintaining the security benefits of minimal runtime images.

Docker Debug provides a shell, common debugging tools, and lets you install additional tools in an ephemeral, writable layer that only exists during the debugging session:

docker debug <container-name>

Docker Debug advantages:

  • Full debugging environment with shells and tools
  • Temporary, secure debugging layer that doesn't modify the runtime container
  • Install additional debugging tools as needed during the session
  • Perfect for troubleshooting DHI containers while preserving security
Permissions

Runtime image variants run as the nonroot user. Ensure that necessary files and directories are accessible to that user. You may need to copy files to different directories or change permissions so your application running as a nonroot user can access them.

Privileged ports

Non-dev hardened images run as a nonroot user by default. As a result, applications in these images can't bind to privileged ports (below 1024) when running in Kubernetes or in Docker Engine versions older than 20.10. Configure your Rust applications to listen on ports 8000, 8080, or other ports above 1024.

Entry point

Docker Hardened Images may have different entry points than images such as Docker Official Images. Use docker inspect to inspect entry points for Docker Hardened Images and update your Dockerfile if necessary.