CI/CD¶
Workflows¶
Release (release-musl.yml)¶
Trigger: Push a tag matching v* or manual dispatch with a tag input.
Job 1: Build Tier 2 Binaries¶
Runs 4 parallel builds using stock messense/rust-musl-cross Docker images:
| Target | Docker Image |
|---|---|
| x86_64 | messense/rust-musl-cross:x86_64-musl |
| i686 | messense/rust-musl-cross:i686-musl |
| aarch64 | messense/rust-musl-cross:aarch64-musl |
| armv7 | messense/rust-musl-cross:armv7-musleabihf |
Each build:
- Sets up an 8 GB swap file for LTO linking
- Runs
cross-compile-musl.shinside the container - Produces
nym-vpnd-{arch},nym-vpnc-{arch},nym-vpn-{arch}.tar.gz, and SHA256 checksums
Job 2: Build Tier 3 Binaries¶
Runs 2 parallel builds using custom Docker images from docker/tier3-musl/:
| Target | Dockerfile |
|---|---|
| mips | Dockerfile.mips |
| mipsel | Dockerfile.mipsel |
Each build compiles the custom Docker image, then runs build-tier3.sh inside it with nightly Rust and -Z build-std.
Job 3: Package (IPK + APK)¶
Depends on both build jobs. Runs 18 parallel packaging jobs that map the 6 binary targets to 18 OpenWrt architecture variants:
| Binary Target | OpenWrt Architectures |
|---|---|
| aarch64 | aarch64_generic, aarch64_cortex-a53, aarch64_cortex-a53_neon-vfpv4, aarch64_cortex-a72 |
| x86_64 | x86_64 |
| i686 | i386_pentium4, i386_pentium-mmx |
| armv7 | arm_cortex-a5_vfpv4, arm_cortex-a7, arm_cortex-a7_neon-vfpv4, arm_cortex-a7_vfpv4, arm_cortex-a8_vfpv3, arm_cortex-a9, arm_cortex-a9_neon, arm_cortex-a9_vfpv3-d16, arm_cortex-a15_neon-vfpv4 |
| mips | mips_24kc |
| mipsel | mipsel_24kc, mips_siflower |
Each job:
- Downloads the matching binary from the build artifact
- Clones the LuCI frontend, trying the matching release tag first, falling back to main
- Builds an
.ipkviascripts/ipk/build-ipk.sh - Builds an
.apkviascripts/apk/build-apk.sh
Output naming: nym-vpn_{version}_{openwrt_arch}.ipk and .apk
Job 4: Create GitHub Release¶
Runs only on tagged commits. Collects all artifacts and:
- Generates a changelog by grouping commits since the previous tag into Features (
feat:), Bug Fixes (fix:), and Other Changes - Creates a GitHub release, marked prerelease if the tag contains
beta,alpha, orrc - Attaches all binaries, tarballs, checksums, IPKs, APKs, and the install script
Job 5: Publish Package Feed¶
Runs only on tagged commits, after the release is created.
- Generates an opkg feed index (
Packages,Packages.gz) per architecture - Generates an apk feed index (
APKINDEX.tar.gz) per architecture - Signs both feeds with an RSA key
- Uploads everything to Cloudflare R2 at
packages.dial0ut.org
Feed structure on R2:
packages.dial0ut.org/
├── opkg/
│ ├── aarch64_generic/
│ │ ├── nym-vpn_1.23.0_aarch64_generic.ipk
│ │ ├── Packages
│ │ ├── Packages.gz
│ │ └── Packages.sig
│ ├── x86_64/
│ │ └── ...
│ └── ...
└── apk/
├── aarch64_generic/
│ ├── nym-vpn_1.23.0_aarch64_generic.apk
│ └── APKINDEX.tar.gz (signed)
└── ...
Feed Signing¶
Package feeds are signed with RSA to prevent tampering. The public key (scripts/feed/dial0ut.pub) is included in the IPK/APK package and installed to /etc/opkg/keys/ or /etc/apk/keys/ during postinst.
opkg signing: The Packages index file is signed with openssl dgst -sha256, producing a detached Packages.sig.
apk signing: The APKINDEX is signed with openssl dgst -sha1, and the signature is embedded inside APKINDEX.tar.gz as .SIGN.RSA.dial0ut.pub.
Release Artifacts¶
A complete release includes:
| Artifact | Count | Example |
|---|---|---|
| Daemon binaries | 6 | nym-vpnd-aarch64 |
| CLI binaries | 6 | nym-vpnc-aarch64 |
| Tarballs | 6 | nym-vpn-aarch64.tar.gz |
| SHA256 checksums | 18 | nym-vpnd-aarch64.sha256 |
| IPK packages | 18 | nym-vpn_1.23.0_aarch64_generic.ipk |
| APK packages | 18 | nym-vpn_1.23.0_aarch64_generic.apk |
| Install script | 1 | install.sh |