Skip to main content

nFPM (deb/rpm/apk)

Generate Linux packages using nFPM

Anodizer integrates with nFPM to generate native Linux packages.

Classification

Packager — generates deb/rpm/apk/archlinux/termux.deb/ipk packages from Linux binaries, and msix app packages from Windows binaries. Required: not a publisher; always runs unless disabled.

Minimal config

crates:
  - name: myapp
    nfpm:
      - package_name: myapp
        formats: [deb, rpm]
        vendor: "My Company"
        homepage: "https://example.com"
        maintainer: "maintainer@example.com"
        description: "My application"
        license: MIT

Full config reference

crates:
  - name: myapp
    nfpm:
      - package_name: myapp            # optional; defaults to crate name
        formats: [deb, rpm]            # REQUIRED (>= 1 entry): deb | rpm | apk | archlinux | termux.deb | ipk | msix
                                       #   with no formats entry, this config emits nothing
        vendor: ""                     # optional
        homepage: ""                   # optional
        maintainer: ""                 # optional; maintainer email
        description: ""                # optional
        license: ""                    # optional; SPDX identifier
        bindir: /usr/bin               # optional; binary installation directory
        bin_alias: ""                  # optional; rename the installed binary inside the package only
        file_name_template: ""         # optional; custom filename template
        contents: []                   # optional; additional files to include
        dependencies: {}               # optional; per-format package dependencies
        recommends: []                 # optional; soft dependencies
        suggests: []                   # optional; weaker-than-recommends dependencies
        conflicts: []                  # optional; packages this conflicts with
        replaces: []                   # optional; packages this replaces (rename upgrades)
        provides: []                   # optional; virtual packages provided
        scripts:                       # optional; install scripts
          preinstall: ""
          postinstall: ""
          preremove: ""
          postremove: ""
        overrides: {}                  # optional; per-format field overrides
        rpm: {}                        # optional; RPM-specific block (see Per-format blocks)
        deb: {}                        # optional; deb-specific block
        apk: {}                        # optional; apk-specific block
        archlinux: {}                  # optional; archlinux-specific block
        ipk: {}                        # optional; ipk (OpenWrt) block
        msix: {}                       # optional; msix (Windows) block

Authentication

Not applicable — nFPM generates package files locally. Uploading them to a package repository is handled by the cloudsmith, gemfury, or artifactory publishers.

Common gotchas

  • formats: the list must match the package types your downstream publishers expect. A mismatch (e.g., configuring cloudsmith for deb but nFPM only producing rpm) silently skips upload.
  • dependencies: per-format dependency maps allow different deps for deb vs rpm — use the overrides map for format-specific fields.
  • Platform routing: Linux (plus Android/iOS/AIX where supported) binaries feed the Linux formats; Windows binaries feed only msix. Darwin targets are ignored. A [deb, msix] config packages each target with its matching format and silently skips the rest.
  • msix needs nfpm >= 2.46.0: older nfpm binaries don't know the msix packager; anodizer surfaces the version floor in the error when packaging fails.

Republish / update behavior

Not applicable — this is a local packaging stage, not a publisher.

nFPM config fields

FieldTypeDefaultDescription
package_namestringcrate namePackage name
formatslistrequiredPackage formats: deb, rpm, apk, archlinux, termux.deb, ipk, msix. At least one entry is required — a config with no formats produces no package.
vendorstringCargo first authorDistributing entity recorded in the rpm/deb Vendor field. Auto-derives from the crate's first Cargo.toml author (with any <email> suffix stripped); set to override. See Vendor.
homepagestringnoneHomepage URL
maintainerstringnoneMaintainer email
descriptionstringnonePackage description
licensestringnoneLicense identifier
bindirstring/usr/binBinary installation directory
bin_aliasstringnoneRename the installed binary inside the package only (e.g. fdfdfind for the Debian package); the build output and archive are untouched. Templated.
file_name_templatestringautoCustom filename template
contentslistnoneAdditional files to include
dependenciesmapnonePackage dependencies keyed by format (e.g., deb: [git])
recommendslistnoneSoft (recommended) dependencies
suggestslistnoneSuggested dependencies (weaker than recommends)
conflictslistnonePackages this package conflicts with
replaceslistnonePackages this package replaces (upgrade paths from renamed packages)
provideslistnoneVirtual packages this package provides
scriptsobjectnonePre/post install/remove scripts (preinstall, postinstall, preremove, postremove)
overridesmapnonePer-format field overrides
rpmobjectnoneRPM-specific block (see Per-format blocks)
debobjectnoneDeb-specific block
apkobjectnoneAPK-specific block
archlinuxobjectnoneArchlinux-specific block
ipkobjectnoneIPK (OpenWrt) block
msixobjectnoneMSIX (Windows) block (see MSIX packages)

Vendor

The Vendor field of a deb/rpm package names the distributing entity. anodizer auto-derives it from the crate's first Cargo.toml author, stripping any <email> suffix — so a crate authored by TJ Smith <tj@jarvispro.io> produces Vendor: TJ Smith without any nfpm config. Set vendor: only to override:

# Cargo.toml
[package]
authors = ["TJ Smith <tj@jarvispro.io>"]
nfpm:
  - package_name: myapp
    formats: [deb, rpm]
    # vendor omitted -> derived as "TJ Smith"

vendor: "Some Other Org" overrides the derived value.

File contents

Include additional files in the package:

nfpm:
  - package_name: myapp
    formats: [deb, rpm]
    contents:
      - src: config.example.yaml
        dst: /etc/myapp/config.yaml
        type: config
      - src: myapp.service
        dst: /usr/lib/systemd/system/myapp.service

Install scripts

nfpm:
  - package_name: myapp
    formats: [deb]
    scripts:
      preinstall: scripts/preinstall.sh
      postinstall: scripts/postinstall.sh
      preremove: scripts/preremove.sh
      postremove: scripts/postremove.sh

Per-format blocks

Each package format has an optional dedicated block carrying settings that only apply to that format. Set the block alongside formats; anodizer emits the matching nfpm section only for the formats you list.

nfpm:
  - package_name: myapp
    formats: [rpm, deb, apk, archlinux, ipk]
    rpm:
      summary: "A fast CLI tool"        # RPM Summary tag
      compression: zstd                 # lzma | gzip | xz | zstd
      group: "System/Tools"
      packager: "Build Team <build@example.com>"
      prefixes: ["/usr"]                # relocatable RPM prefixes
      build_host: "reproducible"        # override RPM BuildHost tag
      signature:
        key_file: signing.gpg
        key_passphrase: ""              # falls back to NFPM_PASSPHRASE
      scripts:
        pretrans: scripts/pretrans.sh   # %pretrans scriptlet
        posttrans: scripts/posttrans.sh # %posttrans scriptlet
    deb:
      compression: xz                   # gzip | xz | zstd | none
      predepends: ["dpkg (>= 1.17)"]    # stronger than Depends
      breaks: ["oldpkg (<< 2.0)"]       # Breaks relationship
      lintian_overrides: ["binary-without-manpage"]
      fields:                           # extra control fields
        Built-Using: "rustc"
      signature:
        key_file: signing.gpg
        type: origin                    # origin | maint | archive
      triggers:
        activate_noawait: ["ldconfig"]
      scripts:
        rules: debian/rules
        templates: debian/templates     # debconf templates
        config: debian/config           # debconf config script
    apk:
      signature:
        key_file: signing.rsa
        key_name: "build@example.com.rsa.pub"
      scripts:
        preupgrade: scripts/preupgrade.sh
        postupgrade: scripts/postupgrade.sh
    archlinux:
      pkgbase: myapp                    # base name for split packages
      packager: "Build Team <build@example.com>"
      scripts:
        preupgrade: scripts/preupgrade.sh
        postupgrade: scripts/postupgrade.sh
    ipk:
      abi_version: "1"
      auto_installed: false
      essential: false
      predepends: ["libc"]
      tags: ["net"]
      fields:
        Maintainer: "team@example.com"
    msix:                               # only consumed by formats: [msix]
      arch: x64                         # optional; x64 | x86 | arm64 | arm | neutral (derived from the target)
      publisher: "CN=My Company, O=My Company, C=US"   # REQUIRED; must match the signing cert subject
      identity:
        resource_id: en-us              # optional
      properties:
        display_name: "My App"          # optional; defaults to the package name
        publisher_display_name: "My Company"  # optional; defaults to the package name
        logo: assets/logo.png           # REQUIRED; package logo image
      applications:                     # REQUIRED (>= 1 entry)
        - id: MyApp                     # REQUIRED
          executable: myapp.exe         # REQUIRED; path inside the package
          entry_point: Windows.FullTrustApplication  # optional; this is the default
          visual_elements:
            display_name: "My App"      # optional; defaults to the package name
            description: "A fast CLI"   # optional; defaults to the package description
            background_color: transparent          # optional; this is the default
            square150x150_logo: assets/150.png     # optional; defaults to properties.logo
            square44x44_logo: assets/44.png        # optional; defaults to properties.logo
      dependencies:
        target_device_families:         # optional; this is the default family
          - name: Windows.Desktop
            min_version: 10.0.17763.0
            max_version_tested: 10.0.22621.0
      capabilities:
        capabilities: [internetClient]  # optional
        device_capabilities: []         # optional
        restricted: []                  # optional; runFullTrust is auto-added for full-trust apps
      signature:
        pfx_file: cert.pfx              # optional; PFX certificate for signing

Termux packages

termux.deb builds a .deb for Termux's apt repository from Android binaries. Termux uses its own architecture nomenclature — anodizer stamps it into both the conventional filename and the control-file Architecture, and rewrites install paths under the Termux filesystem prefix (/data/data/com.termux/files):

Build archdeb nametermux.deb name
amd64amd64x86_64
arm64arm64aarch64
386i386i686
armv6armhfarm
nfpm:
  - package_name: myapp
    formats: [termux.deb]
    maintainer: "team@example.com"
dist/linux/myapp_1.0.0_aarch64.deb   # aarch64-linux-android, Termux arch name

MSIX packages

msix builds a Windows app package (.msix) from Windows binaries — the one format that consumes Windows targets (all other formats skip them, and msix skips non-Windows targets). Requires nfpm >= 2.46.0. The binary is placed at the package root (an MSIX is a virtual filesystem rooted at the install location, so bindir does not apply), and the artifact is registered as a Windows installer (checksummed, signed, released) under dist/windows/.

The conventional filename is {name}_{version}_{arch}.msix with a 4-part numeric version (1.2.31.2.3.0) and MSIX arch names (x64, x86, arm64, arm, neutral):

dist/windows/myapp_1.2.3.0_x64.msix   # x86_64-pc-windows-msvc

Signing uses a PFX certificate; the passphrase is never written to config — anodizer resolves it from NFPM_<ID>_MSIX_PASSPHRASE, then NFPM_<ID>_PASSPHRASE, then NFPM_PASSPHRASE, and forwards it to nfpm's environment.

Full example

crates:
  - name: myapp
    nfpm:
      - package_name: myapp
        formats: [deb, rpm, apk]
        vendor: "My Company"
        homepage: "https://github.com/myorg/myapp"
        maintainer: "team@example.com"
        description: "A fast CLI tool"
        license: MIT
        dependencies:
          deb:
            - git
          rpm:
            - git
        contents:
          - src: config.example.yaml
            dst: /etc/myapp/config.yaml
            type: config
        overrides:
          deb:
            dependencies:
              - git
              - ca-certificates