This project demonstrates how to create a minimal, security-focused Docker container for a Java application by replacing busybox with custom static binaries built using Nix.
Traditional Alpine-based containers include busybox, which provides many shell utilities but also increases the attack surface. This project shows how to:
- Remove busybox from the container
- Use Nix to build only the minimal static binaries you actually need
- Create a more secure container with a reduced attack surface
The Dockerfile includes two build targets:
Minimal secure image (default):
# Build with reduced attack surface (no busybox)
docker build -t minimal-java .
# Run the container
docker run minimal-javaStandard Alpine image:
# Build standard Alpine with busybox utilities
docker build --target prod-alpine -t minimal-java-standard .
# Run the container
docker run minimal-java-standardBoth images output: Hello World from Java 21!
# Compile the Java application
mvn clean package
# Run locally
java -jar target/hello-world-1.0.0.jarTo update the Nix dependencies to the latest versions:
# Update flake.lock to latest nixpkgs
nix flake update
# Or using Docker if you don't have Nix installed locally
docker run --rm -v $(pwd):/workspace -w /workspace nixos/nix:latest nix --extra-experimental-features 'nix-command flakes' flake updateThe Dockerfile uses multi-stage builds with two final production targets:
prod-minimal(default): Removes busybox and uses Nix-built static binaries for minimal attack surfaceprod-alpine: Standard Alpine Linux with busybox utilities for broader compatibility
Use --target prod-alpine to build without the security hardening if you need standard shell utilities.
- Reduced attack surface: Only includes
sh,su-exec, andchmodbinaries - Static binaries: No dynamic library dependencies
- Non-root execution: Runs as
appuserwith minimal privileges - Minimal base: Uses
scratchfor the Nix-built binaries layer