Why Reproducible Builds?
Reproducible builds provide:- Transparency: Anyone can verify the APK matches the published source code
- Security: Ensures no malicious code was injected during the build process
- Trust: Users can verify the app they download is built from the exact source code
Requirements
- Docker >= 18.09
- At least 16 GB of RAM allocated to Docker
- At least 60 GB of free disk space
Docker Configuration
Allocate Resources
Ensure Docker has sufficient resources:Enable BuildKit
The build process requires Docker BuildKit for optimal performance and output handling.Building the APK
Run Docker Build
Execute the reproducible build:This process typically takes 10-20 minutes depending on your hardware.
Build Process Details
The Dockerfile uses a multi-stage build process to ensure reproducibility:Stage 1: Base Android Builder
- OpenJDK 17 (pinned digest for reproducibility)
- Android NDK version 22.0.7026061
- Android Platform version 28
- Android Build Tools version 28.0.3
- Go version 1.24.7
Stage 2: Rust Builder
- Rust nightly 2024-12-16
- Target architectures:
aarch64-linux-androidarmv7-linux-androideabii686-linux-androidx86_64-linux-android
Stage 3: librs Build
Builds Rust libraries:Stage 4: Final Build
Combines everything and builds the APK:Stage 5: Output
Extracts only the necessary artifacts using a scratch image, ensuring minimal output size.Environment Variables
The following environment variables are set during the build:| Variable | Value | Purpose |
|---|---|---|
NDK_VERSION | 22.0.7026061 | Android NDK version |
ANDROID_PLATFORM_VERSION | 28 | Target Android API level |
ANDROID_BUILD_TOOLS_VERSION | 28.0.3 | Build tools version |
GO_VERSION | 1.24.7 | Go language version |
ANDROID_HOME | /opt/android-sdk-linux | Android SDK location |
ANDROID_SDK_ROOT | /opt/android-sdk-linux | Android SDK root |
ANDROID_NDK_HOME | NDK location | |
GOPATH | /go | Go workspace |
Reproducibility Features
Pinned Dependencies
- Base Docker image uses SHA256 digest
- All tool versions are explicitly specified
- Go modules are version-locked
- Rust toolchain is pinned to specific nightly
Build Flags
The build uses flags that ensure reproducibility:-trimpath: Removes local file system paths from binaries-ldflags="-buildid=. -v": Sets consistent build ID
16KB Page Alignment
For Android targetSdk 35+ compatibility:Build Cache
Docker will cache intermediate layers. To force a clean build:Verifying Reproducibility
To verify the build is truly reproducible:- Build the APK twice on different machines
- Compare the unsigned APK files byte-by-byte:
CI/CD Integration
This Dockerfile is used by Muun’s GitHub Actions workflow (build-release.yml) to produce official builds. Any changes to the Dockerfile will affect the official build process.
Troubleshooting
Insufficient Memory
If the build fails with out-of-memory errors:Insufficient Disk Space
If the build fails due to disk space:Build Timeout
For slower machines, the build may take longer:Next Steps
- APK Verification - Verify your build against an installed APK
- Building Locally - Build without Docker for development
- Testing - Run the test suite