Files
fips/packaging
Johnathan Corgan 37196604d7 Prepare the v0.5.3 release notes, changelog and documentation corrections
Move the staged changelog entries under a 0.5.3 heading dated
2026-10-16, marked provisional in the heading itself, and leave an empty
Unreleased section above it. The topic groups follow the order the 0.5.2
section uses, and fixes that described one mechanism in several entries
now read as one: the gateway's virtual IP handling, the macOS sending
threads, the transport counters, the forged and unreadable SessionMsg3
and SessionSetup cases, and the same-epoch msg1 handling. No entry's
detail was dropped.

Add the release notes and mirror them byte for byte to RELEASE-NOTES.md,
with every link absolute and each paragraph on one line. They lead with
who should upgrade and what to do first: the SSH rule and gateway
forwarding before an OpenWrt upgrade, the farthest-first order for
routers reached over an 802.11s mesh, the Windows installer's stop on a
key left in \etc\fips, the refusal of a config that configures nothing,
the gateway's LAN-only translation and pool checks, and the changed
fips.nft, including what the systemd tarball does with an edited copy.
The upgrade steps say to restart fips after the network reload on an
OpenWrt mesh or gateway router, since a running daemon does not form
links over a recreated interface, and give the upgrade, reload and
restart as one detached command for a router reached over SSH. The
FreeBSD restart after the package upgrade is required, because pkg ends
the daemon the package starts. On Windows, a key moved out of \etc\fips
needs node.identity.persistent: true beside it and the old fips.yaml
deleted, and a service registered by hand is checked with sc.exe qc
first. On Debian, the steps cover each answer at the fips.nft prompt, an
upgrade run without a terminal, and masking fips-dns on a host that
renamed the TUN, which fips-dns does not support. A gateway on a VLAN
device on a bridge is affected only when br_netfilter passes bridged
IPv6 to the firewall, and only for clients whose traffic enters the
bridge untagged; the notes say how to check and what the workaround
costs, and that hosts off gateway.lan_interface lose .fips access.
They state the wire-format comparison and what it does not cover, the
limits that remain, the advisories accepted with the release including
RUSTSEC-2024-0449, that no crate was added to the lockfile, the
fips-mesh crate name and how a dependent names it, what was measured
and what was not, and the contributors.

The README's status badge, release-notes link and status paragraphs
follow the release, without naming a branch.

Correct documentation that no longer matches the release:

- The fips and configuration references say the Windows \etc\fips
  config probe is deprecated, that the daemon warns when it loads a
  config from there, and that from v0.6.0 the search no longer looks
  there.
- Getting started no longer says there is no cargo install path, since
  the crate is published; it says cargo install fips-mesh installs only
  the binaries and is not how to install the daemon.
- The reachability how-to names its probe placeholder as a substitution,
  and the gateway port-forward recipe marks its example mesh address as
  the one to replace.
- The mesh firewall how-to says the systemd tarball keeps an edited
  fips.nft and writes the new one as fips.nft.template.
- The gateway design document and the configuration reference state the
  bridge netfilter condition under which a VLAN device on a bridge does
  not serve its clients.
- The FreeBSD package README no longer says the package restarts the
  services on upgrade, and says to restart them by hand.
- The OpenWrt package README's mesh upgrade order adds the fips restart
  after the reload, as a detached command.
2026-10-16 07:40:38 +00:00
..

FIPS Packaging

This directory contains packaging for all supported target platforms. Most build outputs go to deploy/ at the project root; make ipk and make apk write to dist/ instead.

Quick Start

make deb        # Debian/Ubuntu .deb (built in the pinned container)
make tarball    # systemd install tarball
make ipk        # OpenWrt .ipk (opkg, OpenWrt 24.x and earlier)
make apk        # OpenWrt .apk (apk-tools, mandatory on OpenWrt 25+)
make aur        # Arch Linux AUR package (fips-git, local build + namcap)
make pkg        # macOS .pkg installer
make freebsd    # FreeBSD .pkg package (on FreeBSD; use gmake)
make zip        # Windows .zip package
make all        # deb + tarball (default)

The two Debian build paths

make deb builds in a container pinned to the oldest supported distribution, named with the glibc floor in build-floor.env, and checks the package it produced against that floor before handing it back. Its only host prerequisite is docker: the toolchain and the build dependencies live in the image. This is the path the release workflow, the integration suite and the internal builder all take, so a package that passes locally is built the way the shipped one is.

make deb-host is the old path. It builds on the host, at whatever glibc the host has, and it is checked against nothing. Use it for local iteration only. A package built on a current distribution records a version dependency that the loader refuses on Debian 12 and Ubuntu 22.04, which is what shipped in every Linux artifact from v0.3.0 through v0.5.0, so it must not produce anything anyone else installs.

Build Prerequisites

The prerequisites below apply to the host-build targets. make deb needs docker and nothing else.

These targets build FIPS from source, so the host needs a build environment in addition to a Rust toolchain (the version pinned in rust-toolchain.toml is auto-installed by rustup).

On Linux, libclang is required: the LAN gateway's nftables bindings are generated by bindgen at build time, which needs libclang.so on the build host. Without it the build fails inside the rustables crate with an "Unable to find libclang" error.

sudo apt install libclang-dev    # Debian / Ubuntu

This is a build-time prerequisite only — it is not a runtime dependency, so hosts installing a pre-built .deb do not need it.

BLE is not optional, and it is not universal either. build.rs sets ble_available for glibc Linux or Android, which is the set of platforms with a concrete backend: the transport is absent from musl Linux, macOS, FreeBSD and Windows builds entirely. On glibc Linux libdbus-1-dev and pkg-config are hard build prerequisites: there is no probe that skips BLE when they are missing. The BlueZ daemon is a runtime dependency and is not needed to build.

Directory Structure

packaging/
  aur/            Arch Linux AUR packaging (PKGBUILD, supporting files)
  common/         Shared assets (default config, hosts file)
  debian/         Debian/Ubuntu .deb packaging via cargo-deb
  freebsd/        FreeBSD .pkg packaging via pkg-create(8)
  macos/          macOS .pkg installer via pkgbuild
  nixos/          NixOS flake module (services.fips.*)
  systemd/        Generic Linux systemd tarball packaging
  openwrt-ipk/    OpenWrt .ipk packaging via cargo-zigbuild (opkg)
  openwrt-apk/    OpenWrt .apk packaging via cargo-zigbuild + apk mkpkg
  windows/        Windows .zip package with service scripts

Formats

Debian/Ubuntu (.deb)

Built with cargo-deb. Installs fips, fipsctl, fipstop, and fips-gateway to /usr/bin/, ships the fips, fips-dns, fips-firewall, and fips-gateway systemd units, and enables the fips and fips-dns services.

The default configuration ships as an example at /usr/share/fips/fips.yaml.example and is not a dpkg conf-file. (It is deliberately not under /usr/share/doc, which minimal and container installs path-exclude, since the postinst reads it at install time.) On install, postinst seeds /etc/fips/fips.yaml (mode 600) from the example only if it does not already exist, so a configuration that was rendered by configuration management or edited by an operator is never prompted for or clobbered on upgrade. To reset to defaults, remove /etc/fips/fips.yaml and reinstall, or copy the example back manually.

# Build
make deb

# Install
sudo apt install ./deploy/fips_<version>_<arch>.deb

# Remove (preserves config and keys)
sudo dpkg -r fips

# Purge (removes config and identity keys)
sudo dpkg -P fips

systemd Tarball

A self-contained tarball with binaries and an install.sh script for any systemd-based Linux distribution.

# Build
make tarball

# Install (on target host)
tar -xzf deploy/fips-<version>-linux-<arch>.tar.gz
sudo ./fips-<version>-linux-<arch>/install.sh

See systemd/README.install.md for full installation and configuration instructions.

OpenWrt (.ipk, opkg — OpenWrt 24.x and earlier)

Cross-compiled with cargo-zigbuild and assembled as a standard .ipk archive. The build script accepts aarch64, mipsel, mips, arm and x86_64; releases publish aarch64 and x86_64. The MIPS targets are not built: 32-bit MIPS has no 64-bit atomics, which fips and nostr-relay-pool both use (see the comment in .github/workflows/package-openwrt.yml).

# Build (default: aarch64)
make ipk

# Build for a specific architecture
bash packaging/openwrt-ipk/build-ipk.sh --arch x86_64

See openwrt-ipk/README.md for router-specific installation instructions.

OpenWrt (.apk, apk-tools — mandatory on OpenWrt 25+)

OpenWrt 25 makes apk-tools the mandatory package manager (it is opt-in on 24.10). Same SDK-free approach (cargo-zigbuild), but the .apk container is assembled by apk mkpkg rather than hand-rolled, so the build additionally needs an apk-tools v3 apk binary built from source. The installed-filesystem payload is shared with the .ipk package.

# Build (default: aarch64; also x86_64)
make apk

# Build for a specific architecture
bash packaging/openwrt-apk/build-apk.sh --arch x86_64

Packages are unsigned; install with apk add --allow-untrusted. See openwrt-apk/README.md for building apk-tools and router-specific installation.

macOS (.pkg)

Built with pkgbuild (included with Xcode command-line tools). Installs binaries to /usr/local/bin/, config to /usr/local/etc/fips/, sets up the /etc/resolver/fips DNS resolver for .fips domains, and loads a launchd daemon. The TUN device is named utun<N> (kernel-assigned) rather than fips0.

# Build
make pkg

# Install
sudo installer -pkg deploy/fips-<version>-macos-<arch>.pkg -target /

# Remove
sudo packaging/macos/uninstall.sh

FreeBSD (.pkg)

Built natively on a FreeBSD host with pkg create. Ships fips, fipsctl, and fipstop (fips-gateway is excluded — its NAT backend is nftables, Linux-only), rc.d services, and .fips DNS integration for local_unbound, unbound, or dnsmasq. Config installs sample-style under /usr/local/etc/fips/ (edits survive upgrades).

# Build (on FreeBSD; this Makefile needs GNU make — pkg install gmake)
gmake freebsd
# or directly, no gmake needed:
./packaging/freebsd/build-pkg.sh

# Install
pkg add ./deploy/fips-<version>-freebsd-<arch>.pkg
sysrc fips_enable=YES fips_dns_enable=YES
service fips start
service fips_dns start

See freebsd/README.md for host resolver setup and field-tested caveats.

Windows (.zip)

A ZIP archive containing binaries, default config, and PowerShell service helper scripts. Requires the wintun driver for TUN support.

# Build
make zip

# Or directly
powershell -File packaging/windows/build-zip.ps1

# Extract and install as service (requires Administrator)
Expand-Archive deploy\fips-<version>-windows-x86_64.zip -DestinationPath fips
cd fips
powershell -ExecutionPolicy Bypass -File install-service.ps1

# Uninstall (preserves config)
powershell -ExecutionPolicy Bypass -File uninstall-service.ps1

# Uninstall and remove config
powershell -ExecutionPolicy Bypass -File uninstall-service.ps1 -RemoveAll

Arch Linux (AUR)

Two AUR packages are maintained: fips (release, builds from tagged tarball) and fips-git (development, builds from latest git master).

# Build and validate locally (git variant)
make aur

# Install from AUR
yay -S fips-git    # development build from master
yay -S fips        # release build from latest tag

See aur/README.md for AUR publication instructions and maintainer guide.

Nix / NixOS (flake)

A flake at the project root builds all four binaries (fips, fipsctl, fips-gateway, fipstop) from source. It pins the exact toolchain from rust-toolchain.toml via fenix and wires up the build-time native dependencies (libclang for bindgen, plus dbus and pkg-config for BLE), so it needs no system setup beyond Nix with flakes enabled.

nix build .#fips          # build the package (all four binaries)
nix run .#fips -- --help  # run a binary directly
nix run .#fipsctl -- show status
nix develop               # dev shell with the pinned toolchain + cargo-edit
nix flake check           # build + validate the flake

The flake also exposes:

  • overlays.default — adds pkgs.fips to nixpkgs
  • nixosModules.default — a NixOS module (packaging/nixos/) that provides services.fips.enable and runs the daemon as a systemd service

As a package only (no service management):

environment.systemPackages = [ fips.packages.${system}.default ];

As a managed NixOS service (recommended — starts on boot, journalctl logs):

# flake.nix
{
  inputs.fips = {
    url = "github:jmcorgan/fips";
    inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = { self, nixpkgs, fips, ... }@inputs: {
    nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      specialArgs = { inherit inputs; };
      modules = [
        ./configuration.nix
        fips.nixosModules.default
        { services.fips.enable = true; }
      ];
    };
  };
}

See packaging/nixos/README.md for the full option reference (services.fips.enable, .package, .configFile, .openFirewall).

Shared Assets

common/ contains assets used across packaging formats:

  • fips.yaml — default configuration (ephemeral identity, UDP/TCP/TUN/DNS)
  • hosts — static hostname-to-npub mappings for .fips DNS resolution