feat: add OpenWrt cross-compilation and packaging (Phase F7)
- packaging/openwrt/: opkg Makefile, procd init script, uci config - scripts/cross-compile.sh: build for musl targets with size checks - .github/workflows/openwrt.yml: CI cross-compile + 5 MB size gate - docs/openwrt.md: installation and configuration guide - Targets: x86_64-musl, armv7-musleabihf, aarch64-musl - Uses cargo-zigbuild for Docker-free cross-compilation
This commit is contained in:
65
.github/workflows/openwrt.yml
vendored
Normal file
65
.github/workflows/openwrt.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
name: OpenWrt Cross-Compile
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
MAX_SIZE_MB: 5
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
cross-compile:
|
||||||
|
name: Cross-compile (${{ matrix.target }})
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
- x86_64-unknown-linux-musl
|
||||||
|
- armv7-unknown-linux-musleabihf
|
||||||
|
- aarch64-unknown-linux-musl
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
|
- name: Install cargo-zigbuild and zig
|
||||||
|
run: |
|
||||||
|
pip3 install ziglang
|
||||||
|
cargo install cargo-zigbuild
|
||||||
|
|
||||||
|
- name: Add target
|
||||||
|
run: rustup target add ${{ matrix.target }}
|
||||||
|
|
||||||
|
- name: Build (size-optimised)
|
||||||
|
env:
|
||||||
|
CARGO_PROFILE_RELEASE_OPT_LEVEL: s
|
||||||
|
CARGO_PROFILE_RELEASE_LTO: 'true'
|
||||||
|
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '1'
|
||||||
|
CARGO_PROFILE_RELEASE_STRIP: symbols
|
||||||
|
run: |
|
||||||
|
cargo zigbuild --release --target ${{ matrix.target }} --bin qpq-server
|
||||||
|
|
||||||
|
- name: Check binary size
|
||||||
|
run: |
|
||||||
|
BINARY="target/${{ matrix.target }}/release/qpq-server"
|
||||||
|
SIZE=$(stat -c%s "$BINARY")
|
||||||
|
SIZE_MB=$(echo "scale=2; $SIZE / 1048576" | bc)
|
||||||
|
echo "Binary size: ${SIZE_MB} MB"
|
||||||
|
MAX_BYTES=$(( ${{ env.MAX_SIZE_MB }} * 1048576 ))
|
||||||
|
if [ "$SIZE" -gt "$MAX_BYTES" ]; then
|
||||||
|
echo "::error::Binary exceeds ${MAX_SIZE_MB} MB limit (${SIZE_MB} MB)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: qpq-server-${{ matrix.target }}
|
||||||
|
path: target/${{ matrix.target }}/release/qpq-server
|
||||||
|
retention-days: 30
|
||||||
146
docs/openwrt.md
Normal file
146
docs/openwrt.md
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
# OpenWrt Deployment Guide
|
||||||
|
|
||||||
|
Run quicproquo on OpenWrt routers for mesh-capable, always-on encrypted messaging at the network edge.
|
||||||
|
|
||||||
|
## Supported Targets
|
||||||
|
|
||||||
|
| Target | Architecture | Common Devices |
|
||||||
|
|-----------------------------------|----------------|--------------------------|
|
||||||
|
| `x86_64-unknown-linux-musl` | x86_64 | PC Engines APU, VMs |
|
||||||
|
| `armv7-unknown-linux-musleabihf` | ARMv7 (hard-float) | RPi 2/3, many routers |
|
||||||
|
| `aarch64-unknown-linux-musl` | AArch64 | RPi 4/5, modern routers |
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Rust toolchain (stable)
|
||||||
|
- One of: `cargo-zigbuild` (recommended) or `cross`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install cargo-zigbuild (recommended — no Docker required)
|
||||||
|
pip3 install ziglang
|
||||||
|
cargo install cargo-zigbuild
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cross-Compilation
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build for all supported targets
|
||||||
|
./scripts/cross-compile.sh
|
||||||
|
|
||||||
|
# Build for a specific target
|
||||||
|
./scripts/cross-compile.sh aarch64-unknown-linux-musl
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Add the musl target
|
||||||
|
rustup target add x86_64-unknown-linux-musl
|
||||||
|
|
||||||
|
# Size-optimised release build
|
||||||
|
CARGO_PROFILE_RELEASE_OPT_LEVEL=s \
|
||||||
|
CARGO_PROFILE_RELEASE_LTO=true \
|
||||||
|
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1 \
|
||||||
|
CARGO_PROFILE_RELEASE_STRIP=symbols \
|
||||||
|
cargo zigbuild --release --target x86_64-unknown-linux-musl --bin qpq-server
|
||||||
|
```
|
||||||
|
|
||||||
|
The binary lands at `target/<triple>/release/qpq-server`. Target size: under 5 MB.
|
||||||
|
|
||||||
|
## OpenWrt Package Installation
|
||||||
|
|
||||||
|
### Option 1: Direct binary install (quick)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy binary to router
|
||||||
|
scp target/aarch64-unknown-linux-musl/release/qpq-server root@router:/usr/bin/
|
||||||
|
|
||||||
|
# Copy init script and config
|
||||||
|
scp packaging/openwrt/files/quicproquo.init root@router:/etc/init.d/quicproquo
|
||||||
|
scp packaging/openwrt/files/quicproquo.uci root@router:/etc/config/quicproquo
|
||||||
|
|
||||||
|
# Enable and start
|
||||||
|
ssh root@router 'chmod +x /etc/init.d/quicproquo && /etc/init.d/quicproquo enable && /etc/init.d/quicproquo start'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 2: opkg package feed
|
||||||
|
|
||||||
|
Add the feed to your OpenWrt build system:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In your OpenWrt buildroot, add to feeds.conf:
|
||||||
|
echo "src-link quicproquo /path/to/quicproquo/packaging/openwrt" >> feeds.conf
|
||||||
|
|
||||||
|
# Update and install
|
||||||
|
./scripts/feeds update quicproquo
|
||||||
|
./scripts/feeds install quicproquo
|
||||||
|
|
||||||
|
# Select in menuconfig: Network -> quicproquo
|
||||||
|
make menuconfig
|
||||||
|
make package/quicproquo/compile V=s
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The server is configured via UCI at `/etc/config/quicproquo`:
|
||||||
|
|
||||||
|
```
|
||||||
|
config server 'server'
|
||||||
|
option listen '0.0.0.0:7000'
|
||||||
|
option data_dir '/var/lib/quicproquo'
|
||||||
|
option log_level 'info'
|
||||||
|
option tls_cert '/var/lib/quicproquo/server-cert.der'
|
||||||
|
option tls_key '/var/lib/quicproquo/server-key.der'
|
||||||
|
option production '1'
|
||||||
|
```
|
||||||
|
|
||||||
|
### UCI Options
|
||||||
|
|
||||||
|
| Option | Default | Description |
|
||||||
|
|--------------|------------------------------------------|----------------------------------|
|
||||||
|
| `listen` | `0.0.0.0:7000` | QUIC listen address |
|
||||||
|
| `data_dir` | `/var/lib/quicproquo` | Persistent data directory |
|
||||||
|
| `log_level` | `info` | RUST_LOG filter |
|
||||||
|
| `tls_cert` | `<data_dir>/server-cert.der` | TLS certificate path (DER) |
|
||||||
|
| `tls_key` | `<data_dir>/server-key.der` | TLS private key path (DER) |
|
||||||
|
| `production` | `1` | Enable production hardening |
|
||||||
|
|
||||||
|
### Service Management
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start / stop / restart
|
||||||
|
/etc/init.d/quicproquo start
|
||||||
|
/etc/init.d/quicproquo stop
|
||||||
|
/etc/init.d/quicproquo restart
|
||||||
|
|
||||||
|
# Enable at boot
|
||||||
|
/etc/init.d/quicproquo enable
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
logread -e quicproquo
|
||||||
|
```
|
||||||
|
|
||||||
|
## Binary Size Optimization
|
||||||
|
|
||||||
|
The release profile is configured for minimal binary size:
|
||||||
|
|
||||||
|
| Setting | Value | Effect |
|
||||||
|
|------------------|------------|-------------------------------------|
|
||||||
|
| `opt-level` | `s` | Optimize for size over speed |
|
||||||
|
| `lto` | `true` | Full link-time optimization |
|
||||||
|
| `codegen-units` | `1` | Single codegen unit for better LTO |
|
||||||
|
| `strip` | `symbols` | Remove debug symbols |
|
||||||
|
|
||||||
|
The CI workflow enforces a 5 MB maximum binary size on every release tag.
|
||||||
|
|
||||||
|
## CI/CD
|
||||||
|
|
||||||
|
The `.github/workflows/openwrt.yml` workflow automatically:
|
||||||
|
|
||||||
|
1. Cross-compiles for all three musl targets
|
||||||
|
2. Verifies binary size stays under 5 MB
|
||||||
|
3. Uploads binaries as release artifacts
|
||||||
|
|
||||||
|
Triggered on version tags (`v*`) or manual dispatch.
|
||||||
58
packaging/openwrt/Makefile
Normal file
58
packaging/openwrt/Makefile
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# OpenWrt package feed Makefile for quicproquo server.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# 1. Add this directory as a custom feed in feeds.conf:
|
||||||
|
# src-link quicproquo /path/to/quicproquo/packaging/openwrt
|
||||||
|
# 2. ./scripts/feeds update quicproquo && ./scripts/feeds install quicproquo
|
||||||
|
# 3. make menuconfig (select Network -> quicproquo)
|
||||||
|
# 4. make package/quicproquo/compile V=s
|
||||||
|
#
|
||||||
|
# The binary is pre-built via cross-compilation (see scripts/cross-compile.sh)
|
||||||
|
# and the Makefile simply installs it into the ipkg.
|
||||||
|
|
||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
PKG_NAME:=quicproquo
|
||||||
|
PKG_VERSION:=0.1.0
|
||||||
|
PKG_RELEASE:=1
|
||||||
|
PKG_MAINTAINER:=quicproquo team
|
||||||
|
PKG_LICENSE:=MIT
|
||||||
|
|
||||||
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|
||||||
|
define Package/quicproquo
|
||||||
|
SECTION:=net
|
||||||
|
CATEGORY:=Network
|
||||||
|
TITLE:=End-to-end encrypted group messenger (server)
|
||||||
|
DEPENDS:=+libpthread +librt
|
||||||
|
URL:=https://github.com/nicholasgasior/quicproquo
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/quicproquo/description
|
||||||
|
Production-grade end-to-end encrypted group messenger using QUIC transport,
|
||||||
|
MLS (RFC 9420), ML-KEM-768 hybrid post-quantum KEM, and OPAQUE authentication.
|
||||||
|
This package installs the qpq-server daemon.
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/quicproquo/conffiles
|
||||||
|
/etc/config/quicproquo
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Skip standard build — we use pre-compiled static musl binaries.
|
||||||
|
define Build/Compile
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/quicproquo/install
|
||||||
|
$(INSTALL_DIR) $(1)/usr/bin
|
||||||
|
$(INSTALL_BIN) $(PKG_BUILD_DIR)/qpq-server $(1)/usr/bin/qpq-server
|
||||||
|
|
||||||
|
$(INSTALL_DIR) $(1)/etc/init.d
|
||||||
|
$(INSTALL_BIN) ./files/quicproquo.init $(1)/etc/init.d/quicproquo
|
||||||
|
|
||||||
|
$(INSTALL_DIR) $(1)/etc/config
|
||||||
|
$(INSTALL_CONF) ./files/quicproquo.uci $(1)/etc/config/quicproquo
|
||||||
|
|
||||||
|
$(INSTALL_DIR) $(1)/var/lib/quicproquo
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call BuildPackage,quicproquo))
|
||||||
45
packaging/openwrt/files/quicproquo.init
Executable file
45
packaging/openwrt/files/quicproquo.init
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh /etc/rc.common
|
||||||
|
# procd init script for quicproquo server.
|
||||||
|
# Reads configuration from /etc/config/quicproquo (uci).
|
||||||
|
|
||||||
|
START=95
|
||||||
|
STOP=10
|
||||||
|
USE_PROCD=1
|
||||||
|
|
||||||
|
PROG=/usr/bin/qpq-server
|
||||||
|
DATA_DIR=/var/lib/quicproquo
|
||||||
|
|
||||||
|
start_service() {
|
||||||
|
local listen data_dir log_level tls_cert tls_key production
|
||||||
|
|
||||||
|
config_load quicproquo
|
||||||
|
config_get listen server listen '0.0.0.0:7000'
|
||||||
|
config_get data_dir server data_dir "$DATA_DIR"
|
||||||
|
config_get log_level server log_level 'info'
|
||||||
|
config_get tls_cert server tls_cert "${data_dir}/server-cert.der"
|
||||||
|
config_get tls_key server tls_key "${data_dir}/server-key.der"
|
||||||
|
config_get_bool production server production 1
|
||||||
|
|
||||||
|
[ -d "$data_dir" ] || mkdir -p "$data_dir"
|
||||||
|
|
||||||
|
procd_open_instance
|
||||||
|
procd_set_param command "$PROG"
|
||||||
|
|
||||||
|
procd_set_param env \
|
||||||
|
RUST_LOG="$log_level" \
|
||||||
|
QPQ_LISTEN="$listen" \
|
||||||
|
QPQ_DATA_DIR="$data_dir" \
|
||||||
|
QPQ_TLS_CERT="$tls_cert" \
|
||||||
|
QPQ_TLS_KEY="$tls_key" \
|
||||||
|
QPQ_PRODUCTION="$production"
|
||||||
|
|
||||||
|
procd_set_param respawn 3600 5 5
|
||||||
|
procd_set_param stderr 1
|
||||||
|
procd_set_param stdout 1
|
||||||
|
procd_set_param user qpq
|
||||||
|
procd_close_instance
|
||||||
|
}
|
||||||
|
|
||||||
|
service_triggers() {
|
||||||
|
procd_add_reload_trigger "quicproquo"
|
||||||
|
}
|
||||||
7
packaging/openwrt/files/quicproquo.uci
Normal file
7
packaging/openwrt/files/quicproquo.uci
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
config server 'server'
|
||||||
|
option listen '0.0.0.0:7000'
|
||||||
|
option data_dir '/var/lib/quicproquo'
|
||||||
|
option log_level 'info'
|
||||||
|
option tls_cert '/var/lib/quicproquo/server-cert.der'
|
||||||
|
option tls_key '/var/lib/quicproquo/server-key.der'
|
||||||
|
option production '1'
|
||||||
91
scripts/cross-compile.sh
Executable file
91
scripts/cross-compile.sh
Executable file
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Cross-compile quicproquo for musl targets (OpenWrt / embedded Linux).
|
||||||
|
#
|
||||||
|
# Produces statically linked, stripped binaries optimised for size.
|
||||||
|
# Requires: cargo-zigbuild (preferred) or cross.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./scripts/cross-compile.sh # all targets
|
||||||
|
# ./scripts/cross-compile.sh x86_64-unknown-linux-musl # single target
|
||||||
|
#
|
||||||
|
# Output: target/<triple>/release/qpq-server (stripped)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
TARGETS=(
|
||||||
|
x86_64-unknown-linux-musl
|
||||||
|
armv7-unknown-linux-musleabihf
|
||||||
|
aarch64-unknown-linux-musl
|
||||||
|
)
|
||||||
|
|
||||||
|
MAX_SIZE_MB=5
|
||||||
|
|
||||||
|
# Size-optimised release profile overrides.
|
||||||
|
export CARGO_PROFILE_RELEASE_OPT_LEVEL=s
|
||||||
|
export CARGO_PROFILE_RELEASE_LTO=true
|
||||||
|
export CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1
|
||||||
|
export CARGO_PROFILE_RELEASE_STRIP=symbols
|
||||||
|
|
||||||
|
# Detect build tool.
|
||||||
|
if command -v cargo-zigbuild &>/dev/null; then
|
||||||
|
BUILD_CMD="cargo zigbuild"
|
||||||
|
elif command -v cross &>/dev/null; then
|
||||||
|
BUILD_CMD="cross build"
|
||||||
|
else
|
||||||
|
echo "ERROR: Install cargo-zigbuild or cross first:" >&2
|
||||||
|
echo " cargo install cargo-zigbuild # recommended" >&2
|
||||||
|
echo " cargo install cross # alternative" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If arguments provided, use those as targets.
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
TARGETS=("$@")
|
||||||
|
fi
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
|
||||||
|
echo "=== quicproquo cross-compilation ==="
|
||||||
|
echo "Build tool: $BUILD_CMD"
|
||||||
|
echo "Targets: ${TARGETS[*]}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
FAILED=()
|
||||||
|
for target in "${TARGETS[@]}"; do
|
||||||
|
echo "--- Building for $target ---"
|
||||||
|
if $BUILD_CMD --release --target "$target" --bin qpq-server; then
|
||||||
|
BINARY="target/$target/release/qpq-server"
|
||||||
|
if [ -f "$BINARY" ]; then
|
||||||
|
SIZE=$(stat -c%s "$BINARY" 2>/dev/null || stat -f%z "$BINARY")
|
||||||
|
SIZE_MB=$(echo "scale=2; $SIZE / 1048576" | bc)
|
||||||
|
MAX_BYTES=$((MAX_SIZE_MB * 1048576))
|
||||||
|
echo " Binary: $BINARY"
|
||||||
|
echo " Size: ${SIZE_MB} MB"
|
||||||
|
if [ "$SIZE" -gt "$MAX_BYTES" ]; then
|
||||||
|
echo " WARNING: Binary exceeds ${MAX_SIZE_MB} MB size limit!"
|
||||||
|
FAILED+=("$target (size: ${SIZE_MB} MB)")
|
||||||
|
else
|
||||||
|
echo " OK: within ${MAX_SIZE_MB} MB limit"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " ERROR: Binary not found at $BINARY"
|
||||||
|
FAILED+=("$target (binary not found)")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " ERROR: Build failed for $target"
|
||||||
|
FAILED+=("$target (build failed)")
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${#FAILED[@]} -gt 0 ]; then
|
||||||
|
echo "=== FAILURES ==="
|
||||||
|
for f in "${FAILED[@]}"; do
|
||||||
|
echo " - $f"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== All targets built successfully ==="
|
||||||
Reference in New Issue
Block a user