Build and release
The distro release workflow runs for version tags and manual dispatch. It builds several artifacts that have to agree on version and runtime contract. The Docker packaging step consumes already built STATIC and eBPF inputs; it does not compile them inside Alpine.
Build inputs and toolchains
- Install Node dependencies for the embedded browser runtime. The Rust build embeds the generated JS bundle.
- Build
static_proxyforx86_64-unknown-linux-muslwith Cargo. The native TLS dependency builds patched BoringSSL C/C++ sources, so CI wires Zig-backedmusl-gccandmusl-g++wrappers and a C++ runtime. - Compile
src/ebpf/ttl_editor.oseparately withclang -target bpf, Linux/libbpf headers, and LLVM tools. - Stage those two artifacts into the Alpine rootfs and write
/opt/404/distro-version.
The local build notes and build.sh describe equivalent builder prerequisites. A glibc Linux binary may fail inside Alpine; the explicit musl target matters.
Package the root filesystem
./distro/build.sh \
--static-binary ./src/STATIC_proxy/target/x86_64-unknown-linux-musl/release/static_proxy \
--ttl-object ./src/ebpf/ttl_editor.o \
--version vX.Y.Z \
--output ./dist/404-distro.tar.gz
The script builds a temporary Alpine image from Dockerfile.build, creates a container without running the application, exports its filesystem, and compresses it. The exported rootfs is what WSL later imports. The image’s CMD ["/bin/sh"] is not a WSL startup service; a launcher or desktop orchestration must start STATIC.
Manifest and signature
The workflow hashes the tarball, writes a manifest with version, sha256, artifact_path, and published_at, then signs the manifest bytes with the DISTRO_MANIFEST_SIGNING_KEY release secret. On a tagged release it publishes a stable distro/manifest.json and signature, plus versioned tarball and manifest objects in the public R2 update origin. GitHub Release assets include the tarball, manifest, signature, and Windows operator ZIP.
{
"version": "vX.Y.Z",
"sha256": "<tarball digest>",
"artifact_path": "/distro/vX.Y.Z/404-distro.tar.gz",
"published_at": "<timestamp>"
}
A SHA-256 digest in a manifest establishes a relationship only after the manifest’s signature and signing key are trusted. The desktop documentation describes an embedded public key for app verification; source confirmation of that app code remains outstanding. The operator ZIP includes a copy of the manifest and signature but its sample CLI hash check alone does not verify the signature.
What the Windows operator ZIP adds
The release workflow also packages 404-windows-x64.zip with 404-distro.tar.gz, profile JSON, a WSL runtime TOML, a control-token file, and copies of manifest/signature files. Its config uses file keystore mode inside WSL and legacy Windows roaming paths. The ZIP is a convenience layout around the rootfs, not a native Windows STATIC binary. See Provisioning and updates and the workflow source.