Skip to content

Instantly share code, notes, and snippets.

@matthewp
Created September 28, 2025 13:49
Show Gist options
  • Select an option

  • Save matthewp/431e0c89d9492ea5601ce9c01a5676af to your computer and use it in GitHub Desktop.

Select an option

Save matthewp/431e0c89d9492ea5601ce9c01a5676af to your computer and use it in GitHub Desktop.
FreeBSD Package Repository Setup Guide

FreeBSD Package Repository Setup Guide

This guide explains how to create FreeBSD packages for your projects and host them in custom repositories.

Building Packages Locally

1. Create Package Manifest

Create pkg-manifest.ucl with your package metadata:

name: "yourapp"
version: "1.0.0"
origin: "category/yourapp"
comment: "Brief description of your app"
arch: "freebsd:14:x86:64"
www: "https://your-project-url.com"
maintainer: "[email protected]"
prefix: "/usr/local"
desc: <<EOD
Longer description of your application.
Can be multiple lines.
EOD
categories: ["sysutils"]
licenselogic: "single"
licenses: ["MIT"]

2. Create Packing List

Create pkg-plist listing files to include (relative to /usr/local):

bin/yourapp
share/doc/yourapp/README.md
share/doc/yourapp/LICENSE

3. Build Script

Create build-package.sh to automate the build process:

#!/bin/sh
# Build and create FreeBSD package

set -e

echo "Building application..."
# Replace with your build command
zig build -Doptimize=ReleaseFast
# or: make
# or: cargo build --release

echo "Preparing staging area..."
rm -rf pkg-staging
mkdir -p pkg-staging/usr/local/bin
mkdir -p pkg-staging/usr/local/share/doc/yourapp

echo "Copying files..."
# Adjust paths for your project
cp zig-out/bin/yourapp pkg-staging/usr/local/bin/
cp README.md LICENSE pkg-staging/usr/local/share/doc/yourapp/

echo "Creating package..."
mkdir -p packages/All
pkg create -M ./pkg-manifest.ucl -p ./pkg-plist -r ./pkg-staging -o ./packages/All/

echo "Generating repository metadata..."
pkg repo ./packages/

echo "Package created in ./packages/"

Make it executable: chmod +x build-package.sh

4. Files to Check Into Source Control

  • pkg-manifest.ucl - Package metadata
  • pkg-plist - File list
  • build-package.sh - Build script

Don't check in:

  • pkg-staging/ - Generated during build
  • packages/ - Build output
  • *.pkg files

Testing Locally

Create Local Repository

  1. Build the package:

    ./build-package.sh
  2. Create a repo config at /usr/local/etc/pkg/repos/yourapp-local.conf:

    yourapp-local: {
      url: "file:///path/to/your/project/packages/",
      enabled: yes,
      priority: 10
    }
    
  3. Install from local repo:

    sudo pkg update
    sudo pkg install yourapp

Hosting Packages via HTTP

Repository Structure

Each project gets its own repository directory:

/var/www/
├── project1/
│   ├── All/
│   │   ├── project1-0.1.0.pkg
│   │   └── project1-0.2.0.pkg
│   ├── packagesite.pkg
│   └── meta
├── project2/
│   ├── All/
│   │   └── project2-1.0.0.pkg
│   ├── packagesite.pkg
│   └── meta

CI/CD Setup

In your CI pipeline (which must run on FreeBSD):

  1. Update version in pkg-manifest.ucl (can be automated from git tags)

  2. Build the package:

    ./build-package.sh
  3. Deploy to web server:

    rsync -av --delete ./packages/ server:/var/www/yourproject/

User Installation

Users add a repository configuration to /usr/local/etc/pkg/repos/yourproject.conf:

yourproject: {
  url: "https://example.com/yourproject/",
  enabled: yes
}

Then install:

sudo pkg update
sudo pkg install yourapp

CI Example (GitHub Actions)

name: Build Package

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    runs-on: [self-hosted, freebsd]  # Requires FreeBSD runner
    steps:
      - uses: actions/checkout@v2

      - name: Update version
        run: |
          VERSION=${GITHUB_REF#refs/tags/v}
          sed -i '' "s/version: \".*\"/version: \"$VERSION\"/" pkg-manifest.ucl

      - name: Build package
        run: ./build-package.sh

      - name: Deploy to server
        run: |
          rsync -av --delete ./packages/ user@server:/var/www/myproject/

Multiple Projects Setup

When hosting multiple projects:

  1. Each project maintains its own:

    • Package manifest and plist
    • Build script
    • CI pipeline
    • Web directory (/var/www/projectname/)
    • Repository config file
  2. Users can install from multiple repositories by adding multiple .conf files:

    /usr/local/etc/pkg/repos/project1.conf
    /usr/local/etc/pkg/repos/project2.conf
    /usr/local/etc/pkg/repos/project3.conf
  3. Benefits of separate repositories:

    • No cross-project dependencies in CI
    • No bandwidth waste copying other projects' packages
    • Each project can deploy independently
    • Simpler CI pipelines

Important Notes

  • The pkg repo command must run on FreeBSD (regenerates metadata)
  • Repository metadata files (outside All/) are regenerated each time
  • Package files in All/ accumulate (multiple versions can coexist)
  • Users can install specific versions: pkg install yourapp-1.0.0
  • The web server doesn't need to be FreeBSD, just serve static files

Security Considerations

  • Consider signing packages for production use
  • Use HTTPS for repository URLs
  • Restrict rsync/SSH access to CI systems only
  • Keep older package versions for rollback capability
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment