Build macOS packages on Linux
apepkg is a Linux port of munki-pkg by Greg Neagle, designed for building macOS installer packages (.pkg files) on Linux systems.
⚠️ Important: If you're on macOS, use munki-pkg instead. apepkg is specifically designed for Linux environments where munki-pkg's native Apple tools aren't available.
APE = Apple Package Engineer
Just like how munki-pkg helps you build packages on macOS, apepkg engineers your Apple packages on Linux!
apepkg is a Linux-compatible implementation of munki-pkg's functionality. All credit for the project structure, build-info format, and workflow design goes to Greg Neagle and the munki-pkg project.
Key differences:
- munki-pkg: Uses Apple's native tools (pkgbuild, productbuild) on macOS
- apepkg: Uses open-source tools (bomutils, xar) on Linux
Both tools maintain 100% project compatibility - you can use the same project directories with either tool.
./INSTALL.sh./apepkg --create MyPackage# Add files to install
mkdir -p MyPackage/payload/usr/local/bin
cp myapp MyPackage/payload/usr/local/bin/
# Add installation scripts (optional)
cat > MyPackage/scripts/postinstall << 'EOF'
#!/bin/bash
echo "Installation complete!"
exit 0
EOF
chmod +x MyPackage/scripts/postinstall./apepkg MyPackageYour package is now at MyPackage/build/MyPackage-1.0.pkg!
✅ Linux-based CI/CD - Build macOS packages in GitHub Actions, GitLab CI, etc. ✅ Code signing & notarization - Sign and notarize packages on Linux with rcodesign ✅ munki-pkg compatible - Use the same project structure ✅ Open source tools - Uses bomutils and xar instead of proprietary Apple tools ✅ Git-friendly - Export/sync BOM for version control ✅ Distribution packages - Ready for deployment via MDM, Munki, Jamf, etc.
- Build standard macOS installer packages (.pkg files)
- Distribution-style packages
- Pre/post installation scripts
- Custom install locations
- Payload and payload-free packages
- Package importing - Convert existing packages to projects
- BOM export/sync for git workflows
- Supports plist, JSON, and YAML build-info formats
- Code signing with Developer ID certificates (via rcodesign)
- Apple notarization and ticket stapling (via rcodesign)
- Advanced build options (compression, min-os-version, large-payload, etc.)
apepkg supports signing and notarizing packages on Linux using rcodesign:
# Using cargo
cargo install apple-codesign
# Or download pre-built binaries from:
# https://github.com/indygreg/apple-platform-rs/releases# Sign with Developer ID Installer certificate
./apepkg MyPackage \
--sign \
--p12-file ~/certs/developer-id-installer.p12 \
--p12-password-env CERT_PASSWORD# Build, sign, and submit for notarization
./apepkg MyPackage \
--sign \
--p12-file ~/certs/developer-id-installer.p12 \
--p12-password-env CERT_PASSWORD \
--notarize \
--api-issuer YOUR_TEAM_ID \
--api-key YOUR_API_KEY_IDPrerequisites for signing:
- Apple Developer ID Installer certificate (.p12 file)
- Export from macOS Keychain or obtain from Apple Developer portal
Prerequisites for notarization:
- App Store Connect API Key (not Apple ID password)
- API Issuer ID (your Team ID, a UUID like
12345678-abcd-1234-abcd-123456789012) - API Key ID (from App Store Connect, like
ABC123XYZ) .p8file (AuthKey_.p8) in a standard location:~/.appstoreconnect/private_keys/~/.private_keys/~/private_keys/./private_keys/
To get an App Store Connect API Key:
- Go to https://appstoreconnect.apple.com/access/api
- Create a new API Key (select "App Manager" role or higher)
- Note the Issuer ID and Key ID
- Download the
.p8file (e.g.,AuthKey_ABC123XYZ.p8) - Place it in
~/.appstoreconnect/private_keys/
On macOS, export your certificate from Keychain:
# Open Keychain Access, find your "Developer ID Installer" certificate
# Right-click → Export → Save as .p12 file with passwordapepkg can import existing flat packages and convert them into apepkg projects:
# Import a package
./apepkg --import /path/to/existing.pkg MyProject
# The package will be extracted and converted to a project directory:
MyProject/
├── build-info.plist # Metadata extracted from PackageInfo
├── payload/ # Installed files
├── scripts/ # Pre/post installation scripts
├── Bom.txt # Bill of Materials
└── build/ # Output directorySupported:
- ✅ Distribution-style flat packages (xar archives)
- ✅ Payload extraction
- ✅ Scripts extraction
- ✅ BOM export
- ✅ Metadata preservation (identifier, version, install location, etc.)
Not Supported:
- ❌ Bundle-style packages (directory format)
Note: Signing and notarization require valid Apple Developer certificates and credentials.
- Full Documentation - Complete guide with all features
- Quick Start Guide - Step-by-step tutorial
- Comparison Table - munki-pkg vs apepkg feature comparison
- Example Project - Working example to learn from
MyPackage/
├── build-info.plist # Package metadata (or .json/.yaml)
├── payload/ # Files to install
│ └── usr/
│ └── local/
│ └── bin/
│ └── myapp
├── scripts/ # Installation scripts (optional)
│ ├── preinstall
│ └── postinstall
└── build/ # Output directory (auto-created)
└── MyPackage-1.0.pkg
name: Build Package
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install apepkg dependencies
run: ./INSTALL.sh
- name: Build package
run: ./apepkg MyPackage
- name: Upload artifact
uses: actions/upload-artifact@v2
with:
name: package
path: MyPackage/build/*.pkgname: Build and Sign Package
on: [push]
jobs:
build-and-sign:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install apepkg dependencies
run: ./INSTALL.sh
- name: Install rcodesign
run: cargo install apple-codesign
- name: Decode certificate
env:
CERTIFICATE_BASE64: ${{ secrets.DEVELOPER_ID_INSTALLER_P12_BASE64 }}
run: |
echo "$CERTIFICATE_BASE64" | base64 --decode > cert.p12
- name: Setup App Store Connect API Key
env:
API_KEY_P8_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_P8_BASE64 }}
API_KEY_ID: ${{ secrets.API_KEY_ID }}
run: |
mkdir -p ~/.appstoreconnect/private_keys
echo "$API_KEY_P8_BASE64" | base64 --decode > ~/.appstoreconnect/private_keys/AuthKey_${API_KEY_ID}.p8
- name: Build, sign, and notarize package
env:
CERT_PASSWORD: ${{ secrets.P12_PASSWORD }}
run: |
./apepkg MyPackage \
--sign \
--p12-file cert.p12 \
--p12-password-env CERT_PASSWORD \
--notarize \
--api-issuer ${{ secrets.API_ISSUER }} \
--api-key ${{ secrets.API_KEY_ID }}
- name: Upload signed package
uses: actions/upload-artifact@v2
with:
name: signed-package
path: MyPackage/build/*.pkgRequired GitHub Secrets:
DEVELOPER_ID_INSTALLER_P12_BASE64- Your .p12 certificate (base64 encoded)P12_PASSWORD- Certificate passwordAPI_ISSUER- App Store Connect API Issuer ID (Team ID UUID)API_KEY_ID- App Store Connect API Key IDAPP_STORE_CONNECT_API_KEY_P8_BASE64- Your .p8 API key file (base64 encoded)
- Python 3
- bomutils (mkbom/lsbom)
- xar
- cpio, gzip (usually pre-installed)
Install with:
./INSTALL.shSupported distributions:
- Debian/Ubuntu
- Red Hat/Fedora/CentOS
- Other Linux distributions (manual install)
apepkg [options] pkg_project_directory
Options:
--create Create new empty project
--import <pkg> Import existing package and create project
--json Use JSON format for build-info
--yaml Use YAML format for build-info
--export-bom-info Export BOM to Bom.txt
--sync Sync permissions from Bom.txt
--quiet Suppress status messages
-f, --force Force creation if directory exists
Signing & Notarization:
--sign Sign the package (requires rcodesign)
--p12-file <path> Path to .p12 certificate file
--p12-password <pass> Certificate password (use --p12-password-env instead)
--p12-password-env <var> Environment variable with certificate password
--notarize Submit for notarization (requires --sign)
--api-issuer <uuid> App Store Connect API Issuer ID (Team ID UUID)
--api-key <id> App Store Connect API Key ID (requires .p8 file)
--notarize-wait Wait for notarization to complete and staple (default)
--notarize-no-wait Don't wait for notarization completionYou can use both apepkg and munki-pkg with the same project:
# On Linux (use apepkg)
./apepkg MyPackage
# On macOS (use munki-pkg)
munkipkg MyPackageBoth produce identical packages. Recommendation: Use munki-pkg on macOS (native Apple tools), and apepkg on Linux (CI/CD pipelines).
Licensed under the Apache License, Version 2.0
apepkg is a Linux port of munki-pkg. All credit for the original concept, project structure, and workflow goes to:
- munki-pkg by Greg Neagle - The original macOS package building tool that this project is based on
Additional tools and inspiration:
- bomutils by Joseph Coffland - BOM creation on Linux
- xar - Package archive format
- rcodesign by Gregory Szorc - Cross-platform code signing
- GytPol's blog post - Initial inspiration for Linux package building
Issues and pull requests welcome.
🦍📦
