Substrate is a minimal base Docker container designed for deploying statically linked applications. It provides an extremely small, immutable, and secure environment with no unnecessary files, libraries, or utilities—just enough to run your statically compiled binary.
- Security: Minimal surface area—no shells, package managers, or extra binaries to exploit.
- Immutability: The container is designed to be read-only and unchanging at runtime.
- Reproducibility: Builds are simple and predictable, with no hidden dependencies.
- Simplicity: No clutter—just your statically linked app and the bare minimum to run it.
- If your application requires dynamic linking or external dependencies, Substrate is not suitable.
- If you need a shell, package manager, or standard Linux utilities, consider using a different base image.
- If you need to run scripts or commands inside the container, Substrate does not provide that capability.
/etc/passwdand/etc/groupfiles with a single user (nobody) for basic user management./bin/falseto provide POSIX compliance for the/etc/passwdentry fornobody.- This is just a shell script that returns false; it does not provide shell access.
/etc/ssl/certs/ca-certificates.crtfor SSL/TLS support in applications that require it.- Many languages and frameworks rely on this file for secure connections, like Go, Python, and Node.js.
- This file is generated at build time by downloading the latest Mozilla CA certificates from the CCADB.
- Certificates are normalized, deduplicated, and combined into the concatenated PEM format expected by most applications.
/etc/os-releasefile identifying the OS as "substrate" for compatibility with software that checks this file.
- Timezone data (e.g.,
/etc/localtime). - Any package manager (e.g.,
apt,yum,apk). - Any shell (e.g.,
sh,bash,zsh). - Any standard Linux utilities (e.g.,
ls,cat,curl). - Any programming languages or runtimes (e.g.,
python,node,java). - Any libraries (e.g.,
libc,libssl). - Any init systems or process managers (e.g.,
systemd,supervisord). - Literally anything else.
To use Substrate, your application must be compiled as a fully static binary (no dynamic linking, no external runtime dependencies).
Example Dockerfile:
FROM ghcr.io/haukened/substrate:latest
COPY my-static-app /app
USER 1000:1000 # Optional: run as non-root user
ENTRYPOINT ["/app"]Build and run your image:
docker build -t my-app .
docker run --rm my-appTo build the Substrate image locally:
docker build -t substrate .You can then use FROM substrate in your own Dockerfiles.
If you are building substrate for youself, you may optionally add custom CA certificates to be trusted by your applications or enterprise. To do so, place your PEM-encoded CA certificates in the directory named user-roots/ at the root of the build context before building the image. The build process will include these certificates in addition to the default Mozilla CA bundle.
- Static Binaries Only: Substrate is intentionally empty. Your app must be a statically linked binary, with no external library or runtime dependencies.
- No Shell or Utilities: There is no shell, package manager, or standard Linux utilities included.
- UID/GID Configurability: You may specify a non-root user with
USERin your Dockerfile (default is root). This is recommended for security. - Default User: If you leave the default configuration unchanged, the container will run as the
nobodyuser (UID:GID 65534:65534). This is safe by default but may restrict filesystem permissions and access to mounted volumes, sincenobodytypically has minimal privileges and ownership of files is rare. You can customize the UID/GID at build time using Docker build arguments or override them at runtime with the--userflag if necessary. - Minimalism Philosophy: The goal is a clean, auditable container with nothing but your app.
When choosing a minimal base image for statically linked applications, it's useful to understand how Substrate compares with other popular minimal images such as Alpine, Google Distroless (especially distroless:static), and Chainguard static.
-
Alpine Linux
- Provides a small, musl-based Linux distribution with a package manager (
apk) and a shell. - Trade-offs:
- Includes many standard utilities and libraries by default, increasing image size and attack surface.
- Requires careful management to avoid unnecessary packages and dependencies.
- When to choose alpine:
- If you need a lightweight Linux environment with package management and shell access.
- If your application requires dynamic linking or additional runtime dependencies.
- Why choose Substrate instead:
- Substrate offers a far more minimal and immutable environment with no shells or package managers.
- Better suited for fully static binaries where no runtime dependencies or utilities are needed.
- Provides a small, musl-based Linux distribution with a package manager (
-
Google Distroless (
distroless:static)- Provides minimal images focused on security and smaller size, with no package manager or shell.
- Includes some essential files and libraries required to run applications.
- Trade-offs:
- While minimal, it still includes certain runtime dependencies and libraries, which might increase complexity.
- Less transparent build process compared to a fully open and auditable minimal image.
- When to choose Distroless:
- If you want a minimal image with some built-in runtime support and are okay with less transparency.
- If you need a balance between minimalism and convenience for certain application types.
- Why choose Substrate instead:
- Substrate is fully transparent and auditable, containing only what is absolutely necessary.
- It avoids any runtime dependencies or libraries, making it ideal for strict static binaries.
-
Chainguard
static- Offers minimal base images with a focus on security, supply chain transparency, and reproducibility.
- Includes signed and verified components and supports various Linux distributions.
- Trade-offs:
- Includes some tooling and libraries to support a broader range of applications and use cases.
- Slightly larger and more complex than Substrate due to additional features.
- When to choose Chainguard:
- If you need a secure, verified base image with supply chain attestation and some runtime support.
- If your application benefits from the additional tooling and libraries provided.
- Why choose Substrate instead:
- Substrate emphasizes absolute minimalism and simplicity, with no additional tooling or libraries.
- It is ideal when you want complete control over the environment and minimal attack surface.
- We do not need supply chain attestation or signed components for our use case, since we ship no software, we require no provenance.
Substrate embraces a philosophy of complete control, transparency, and simplicity by providing an extremely minimal, immutable base container that contains nothing but what your statically linked application needs to run. In contrast, managed minimal distributions like Alpine, Distroless, and Chainguard offer varying degrees of convenience, attestation, and automated updates, which come at the cost of additional complexity, size, and less transparency. Choosing Substrate means opting for a clean slate where you manage dependencies explicitly, ensuring a small and secure runtime environment tailored exactly to your application's needs.
