Tag Archives: build

FreeBSD and Poudriere in High Security Environments

Most of the time FreeBSD systems are used with wide open connection to the Internet along with fully working DNS that resolves anything the Root Servers resolve … but FreeBSD – besides being used as SONY PlayStation gaming systems or Netflix storage layer.

Its also used in high security environments without any external DNS access or direct Internet connection to the outside World … yet the security patches are fetched and applied and custom PKGBASE and/or Poudriere systems build base system/packages while fetching them from the Internet over some dedicated proxy.

Many people will not read entire article so I will point that in the beginning – that I am really grateful to Mariusz Zaborski (oshogbo) for his help with this one – without his help – it just would not happen.

By default FreeBSD does not work well in such environments … in this article we will configure FreeBSD to make everything work as needed.

The Table of Contents is as follows.

  • FreeBSD and Poudriere in High Security Environments
  • Example Proxy Configuration
  • Physical (or Virtual) FreeBSD Host
    • pkg(8)
    • FreeBSD Ports Tree
    • Proxy on the Fly
    • Back to the PKGBASE
  • Poudriere in Proxy World
    • Basic Poudriere Setup
    • Important Poudriere Config Part

Example Proxy Configuration

For completeness I will add Squid configuration used here – so that all information will be available.

proxy # grep '^[^#]' /usr/local/etc/squid/squid.conf
http_port 127.0.0.1:3128
http_port 10.0.0.41:3128
acl SSL_ports port 443
acl Safe_ports port 80          # http
acl Safe_ports port 21          # ftp
acl Safe_ports port 443         # https
acl Safe_ports port 70          # gopher
acl Safe_ports port 210         # wais
acl Safe_ports port 1025-65535  # unregistered ports
acl Safe_ports port 280         # http-mgmt
acl Safe_ports port 488         # gss-http
acl Safe_ports port 591         # filemaker
acl Safe_ports port 777         # multiling http
acl CONNECT method CONNECT
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost manager
http_access deny manager
acl localnet src 127.0.0.1
acl localnet src 10.0.0.0/8     # RFC 1918 local private network (LAN)
acl localnet src 172.16.0.0/12  # RFC 1918 local private network (LAN)
acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
http_access allow localnet
http_access allow localhost
http_access deny all
visible_hostname proxy.xyz
acl custom-local dstdomain .custom.xyz
cache_peer 10.0.0.42 parent 3128 0 no-query default name=weathertop
cache_peer_domain 10.0.0.43 !.xyz
never_direct deny custom-local
never_direct allow all
cache_dir ufs /var/local/squid/cache 50 16 256
coredump_dir /var/local/squid/cache
access_log stdio:/var/local/log/squid/access.log
cache_store_log stdio:/var/local/log/squid/store.log
cache_log /var/local/log/squid/cache.log
refresh_pattern ^ftp:          1440 20% 10080
refresh_pattern ^gopher:       1440  0%  1440
refresh_pattern -i (/cgi-bin/|\?) 0  0%     0
refresh_pattern .                 0 20%  4320
email_err_data off

Now we will configure a FreeBSD host to use it properly.

Physical (or Virtual) FreeBSD Host

For a start we will make pkg(8) work with our proxy system.

pkg(8)

I installed that FreeBSD 15.0-RELEASE system with PKGBASE way – Brave New PKGBASE World – described in details here. With offline install using PKGBASE packages from the install disc1.iso medium.

That means the pkg(8) is already bootstrapped … we will turn that ‘OFF’ for a moment.

test # pkg info
FreeBSD-acct-15.0              System resource accounting
FreeBSD-acpi-15.0              Advanced Configuration and Power Interface (ACPI) utilities
FreeBSD-apm-15.0               Intel / Microsoft APM BIOS utility
(...)
FreeBSD-zlib-lib32-15.0        DEFLATE (gzip) data compression library (32-bit libraries)
FreeBSD-zoneinfo-15.0          Timezone database
pkg-2.4.2                      Package manager

test # mv /var/db/pkg /var/db/pkg.BCK
test # mv /usr/local  /usr/local.BCK

Now if you would like to bootstrap pkg(8) it will fail.

test # pkg
The package management tool is not yet installed on your system.
Do you want to fetch and install it now? [y/N]: y
Bootstrapping pkg from pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/quarterly, please wait...
pkg: Error fetching https://pkg.FreeBSD.org/FreeBSD:15:amd64/quarterly/Latest/pkg.pkg: Transient resolver failure
A pre-built version of pkg could not be found for your system.
Bootstrapping pkg from pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/kmods_quarterly_0, please wait...
pkg: Error fetching https://pkg.FreeBSD.org/FreeBSD:15:amd64/kmods_quarterly_0/Latest/pkg.pkg: Transient resolver failure
A pre-built version of pkg could not be found for your system.

Now we will export(1) needed proxy setting into environment.

test # export HTTP_PROXY="http://10.0.0.41:3128" 

test # export HTTPS_PROXY="http://10.0.0.41:3128"

test # export FTP_PROXY="http://10.0.0.41:3128"

test # env | grep -i proxy
HTTP_PROXY=http://10.0.0.41:3128
HTTPS_PROXY=http://10.0.0.41:3128
FTP_PROXY=http://10.0.0.41:3128

If you want to make it permanent for the default sh(1) shell then do this.

test # cat < /etc/profile.d/proxy.sh
export HTTP_PROXY=http://10.0.0.41:3128
export HTTPS_PROXY=http://10.0.0.41:3128
export FTP_PROXY=http://10.0.0.41:3128
EOF

Now with each new login these proxy settings will be available.

Lets try with pkg(8) again.

test # pkg info
The package management tool is not yet installed on your system.
Do you want to fetch and install it now? [y/N]: y
Bootstrapping pkg from pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/quarterly, please wait...
Verifying signature with trusted certificate pkg.freebsd.org.2013102301... done
Installing pkg-2.4.2...
Extracting pkg-2.4.2: 100%
pkg-2.4.2                      Package manager

The pkg(8) has now bootstrap completed and will work, right? Right?

test # pkg update
Updating FreeBSD-ports repository catalogue...
pkg: No SRV record found for the repo 'FreeBSD-ports'
Fetching meta.conf: 100%    179 B   0.2kB/s    00:01    
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/quarterly/data.pkg -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/quarterly/data.tzst -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/quarterly/packagesite.pkg -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/quarterly/packagesite.tzst -- pkg+:// implies SRV mirror type
Unable to update repository FreeBSD-ports
Updating FreeBSD-ports-kmods repository catalogue...
pkg: No SRV record found for the repo 'FreeBSD-ports-kmods'
Fetching meta.conf: 100%    179 B   0.2kB/s    00:01    
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/kmods_quarterly_0/data.pkg -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/kmods_quarterly_0/data.tzst -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/kmods_quarterly_0/packagesite.pkg -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/kmods_quarterly_0/packagesite.tzst -- pkg+:// implies SRV mirror type
Unable to update repository FreeBSD-ports-kmods
Error updating repositories!

Small modification is needed. One need to remove pkg+ prefix from all url: paths and to switch mirror_type: from srv to none. Then it will work.

Now … the reason why FreeBSD uses the pkg+ prefix is this:

  • pkg+https:// tells pkg(8) to use libpkg internal HTTP/HTTPS fetcher.
  • https:// tells pkg(8) to use external fetcher – usually with FreeBSD fetch(1) tool.

Now … the needed changes.

test # \
  grep '^[^#]' /etc/pkg/FreeBSD.conf \
    | sed -e 's.pkg+..g' \
          -e 's."srv"."none".g' \
          -e 's.enabled: no.enabled: yes.g' \
    > /root/FreeBSD.conf 

The diff(1) for that change is below.

root # diff -u /etc/pkg/FreeBSD.conf /root/FreeBSD.conf 
--- /etc/pkg/FreeBSD.conf  2025-11-28 00:00:00.000000000 +0000
+++ /root/FreeBSD.conf     2026-01-07 00:11:41.534051000 +0000
@@ -10,23 +10,23 @@
 #
 
 FreeBSD-ports: {
-  url: "pkg+https://pkg.FreeBSD.org/${ABI}/quarterly",
-  mirror_type: "srv",
+  url: "https://pkg.FreeBSD.org/${ABI}/quarterly",
+  mirror_type: "none",
   signature_type: "fingerprints",
   fingerprints: "/usr/share/keys/pkg",
   enabled: yes
 }
 FreeBSD-ports-kmods: {
-  url: "pkg+https://pkg.FreeBSD.org/${ABI}/kmods_quarterly_${VERSION_MINOR}",
-  mirror_type: "srv",
+  url: "https://pkg.FreeBSD.org/${ABI}/kmods_quarterly_${VERSION_MINOR}",
+  mirror_type: "none",
   signature_type: "fingerprints",
   fingerprints: "/usr/share/keys/pkg",
   enabled: yes
 }
 FreeBSD-base: {
-  url: "pkg+https://pkg.FreeBSD.org/${ABI}/base_release_${VERSION_MINOR}",
-  mirror_type: "srv",
+  url: "https://pkg.FreeBSD.org/${ABI}/base_release_${VERSION_MINOR}",
+  mirror_type: "none",
   signature_type: "fingerprints",
   fingerprints: "/usr/share/keys/pkgbase-${VERSION_MAJOR}",
-  enabled: no
+  enabled: yes
 }

Now – lets leave the original /etc/pkg/FreeBSD.conf unmodified and create /usr/local/etc/pkg/repos/FreeBSD.conf that will override the defaults.

test # mkdir -pv /usr/local/etc/pkg/repos
/usr/local/etc/pkg
/usr/local/etc/pkg/repos

test # cp /root/FreeBSD.conf /usr/local/etc/pkg/repos/

Now that pkg(8) should work well over proxy.

test # pkg update 
Updating FreeBSD-ports repository catalogue...
Fetching meta.conf: 100%    179 B   0.2kB/s    00:01    
Fetching data.pkg: 100%   10 MiB   3.6MB/s    00:03    
Processing entries: 100%
FreeBSD-ports repository update completed. 36390 packages processed.
Updating FreeBSD-ports-kmods repository catalogue...
Fetching meta.conf: 100%    179 B   0.2kB/s    00:01    
Fetching data.pkg: 100%   31 KiB  31.3kB/s    00:01    
Processing entries: 100%
FreeBSD-ports-kmods repository update completed. 204 packages processed.
Updating FreeBSD-base repository catalogue...
Fetching meta.conf: 100%    179 B   0.2kB/s    00:01    
Fetching data.pkg: 100%   80 KiB  81.5kB/s    00:01    
Processing entries: 100%
FreeBSD-base repository update completed. 496 packages processed.

Lets try to actually install any software.

test # pkg install lsblk beadm 
Updating FreeBSD-ports repository catalogue...
FreeBSD-ports repository is up to date.
Updating FreeBSD-ports-kmods repository catalogue...
FreeBSD-ports-kmods repository is up to date.
Updating FreeBSD-base repository catalogue...
FreeBSD-base repository is up to date.
All repositories are up to date.
The following 2 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        beadm: 1.3.5_1 [FreeBSD-ports]
        lsblk: 4.0 [FreeBSD-ports]
        gitup: 1.0 [FreeBSD-ports]

Number of packages to be installed: 3

18 KiB to be downloaded.

Proceed with this action? [y/N]: y
[1/3] Fetching lsblk-4.0~3110a4bb46.pkg: 100%    7 KiB   7.2kB/s    00:01    
[2/3] Fetching beadm-1.3.5_1~53f06720d4.pkg: 100%   11 KiB  11.0kB/s    00:01    
[3/3] Fetching gitup-1.0~2c88a1f1f1.pkg: 100%   36 KiB  37.0kB/s    00:01    
Checking integrity... done (0 conflicting)
[1/3] Installing beadm-1.3.5_1...
[1/3] Extracting beadm-1.3.5_1: 100%
[2/3] Installing lsblk-4.0...
[2/3] Extracting lsblk-4.0: 100%
[3/3] Installing gitup-1.0...
[3/3] Extracting gitup-1.0: 100%

test # lsblk -d
DEVICE SIZE MODEL
nda0    10G bhyve-NVMe
-       10G TOTAL SYSTEM STORAGE

Works.

If for some reason the above method will not work – you may also configure proxy server within the pkg(8) config /usr/local/etc/pkg.conf file.

test # tail -5 /usr/local/etc/pkg.conf
PKG_ENV {
  HTTP_PROXY: "http://10.0.0.41:3128"
  HTTPS_PROXY: "https://10.0.0.41:3128"
  FTP_PROXY: "http://10.0.0.41:3128"
}

These settings will also override any ‘system’ settings we set previously in the /etc/profile.d/proxy.sh file.

FreeBSD Ports Tree

We already installed gitup tool that will allow us to update the FreeBSD Ports tree easily.

Its default config is more then enought.

test # grep -m 1 -A 6 ports /usr/local/etc/gitup.conf
        "ports" : {
                "repository_path"  : "/ports.git",
                "branch"           : "main",
                "target_directory" : "/usr/ports",
                "ignores"          : [],
        },

Lets try fetching the FreeBSD Ports tree now.

test # gitup ports
# Host: git.freebsd.org
# Port: 443
# Proxy Host: 10.0.0.41
# Proxy Port: 3128
# Repository Path: /ports.git
# Target Directory: /usr/ports
# Want: 284813ec0382a2bfe5b2e74a3081a67599d3155d
# Branch: main
# Action: clone
  75 MB in 0m25s, 4614 kB/s now 
 + /usr/ports/.arcconfig
 + /usr/ports/.gitignore
 + /usr/ports/.hooks/pre-commit
(...)
 + /usr/ports/x11/zutty/Makefile
 + /usr/ports/x11/zutty/distinfo
 + /usr/ports/x11/zutty/pkg-descr
#
# Please review the following file(s) for important changes.
#       /usr/ports/UPDATING
#       /usr/ports/mail/dspam/files/UPDATING
#
# Done.

Seems to work.

To now update the FreeBSD Ports tree run gitup(1) command again.

test # gitup ports
# Scanning local repository...
# Host: git.freebsd.org
# Port: 443
# Proxy Host: 10.0.0.41
# Proxy Port: 3128
# Repository Path: /ports.git
# Target Directory: /usr/ports
# Have: 284813ec0382a2bfe5b2e74a3081a67599d3155d
# Want: 7b2f3c4f484b1634066997a91836554608c72c48
# Branch: main
# Action: pull
 * /usr/ports/lang/spidermonkey115/Makefile
 * /usr/ports/lang/spidermonkey115/distinfo
 * /usr/ports/lang/spidermonkey140/Makefile
 * /usr/ports/lang/spidermonkey140/distinfo
# Done.

If for some reason You will find gitup(1) or git(1) does not work – you may always configure system wide proxy as follows.

test # git config --system http.proxy http://10.0.0.41:3128

That would help.

Proxy on the Fly

If for some reason You will need to force the proxy settings for a single command – then use something like that below.

test # \
  env HTTP_PROXY="http://10.0.0.41:3128"  \
      HTTPS_PROXY="http://10.0.0.41:3128" \
      FTP_PROXY="http://10.0.0.41:3128" 
    command ...

Back to the PKGBASE

Now – lets bring back our original pkg(8) config – we may ‘keep’ the current ‘test’ bootstrap if needed with .CUSTOM suffix.

test # mv /usr/local  /usr/local.CUSTOM
test # mv /var/db/pkg /var/db/pkg.CUSTOM

test # mv /usr/local.BCK  /usr/local
test # mv /var/db/pkg.BCK /var/db/pkg

Now the ‘original’ pkg(8) config that keeps PKGBASE information works again.

test # pkg info | (head -3 ;echo '(...)'; tail -3)
FreeBSD-acct-15.0              System resource accounting
FreeBSD-acpi-15.0              Advanced Configuration and Power Interface (ACPI) utilities
FreeBSD-apm-15.0               Intel / Microsoft APM BIOS utility
(...)
FreeBSD-zlib-lib32-15.0        DEFLATE (gzip) data compression library (32-bit libraries)
FreeBSD-zoneinfo-15.0          Timezone database
pkg-2.4.2                      Package manager

But when we will now try to update the pkg(8) repositories it will fail … why?

test # pkg update
Updating FreeBSD-ports repository catalogue...
pkg: No SRV record found for the repo 'FreeBSD-ports'
Fetching meta.conf: 100%    179 B   0.2kB/s    00:01    
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/quarterly/data.pkg -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/quarterly/data.tzst -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/quarterly/packagesite.pkg -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/quarterly/packagesite.tzst -- pkg+:// implies SRV mirror type
Unable to update repository FreeBSD-ports
Updating FreeBSD-ports-kmods repository catalogue...
pkg: No SRV record found for the repo 'FreeBSD-ports-kmods'
Fetching meta.conf: 100%    179 B   0.2kB/s    00:01    
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/kmods_quarterly_0/data.pkg -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/kmods_quarterly_0/data.tzst -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/kmods_quarterly_0/packagesite.pkg -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/kmods_quarterly_0/packagesite.tzst -- pkg+:// implies SRV mirror type
Unable to update repository FreeBSD-ports-kmods
Error updating repositories!

Its because our config override was placed in /usr/local path … and we just wiped that away.

Copy working proxy config again then.

test # mkdir -pv /usr/local/etc/pkg/repos
/usr/local/etc/pkg
/usr/local/etc/pkg/repos

test # cp /root/FreeBSD.conf /usr/local/etc/pkg/repos/

Now update will work again.

test # pkg update
Updating FreeBSD-ports repository catalogue...
Fetching meta.conf: 100%    179 B   0.2kB/s    00:01    
Fetching data.pkg: 100%   10 MiB   5.4MB/s    00:02    
Processing entries: 100%
FreeBSD-ports repository update completed. 36390 packages processed.
Updating FreeBSD-ports-kmods repository catalogue...
Fetching meta.conf: 100%    179 B   0.2kB/s    00:01    
Fetching data.pkg: 100%   31 KiB  31.3kB/s    00:01    
Processing entries: 100%
FreeBSD-ports-kmods repository update completed. 204 packages processed.
Updating FreeBSD-base repository catalogue...
pkg: Repository FreeBSD-base has a wrong packagesite, need to re-create database
Fetching meta.conf: 100%    179 B   0.2kB/s    00:01    
Fetching data.pkg: 100%   80 KiB  81.5kB/s    00:01    
Processing entries: 100%
FreeBSD-base repository update completed. 496 packages processed.
All repositories are up to date.

You can even do PKGBASE upgrade if wanted.

test # pkg upgrade
Updating FreeBSD-ports repository catalogue...
FreeBSD-ports repository is up to date.
Updating FreeBSD-ports-kmods repository catalogue...
FreeBSD-ports-kmods repository is up to date.
Updating FreeBSD-base repository catalogue...
FreeBSD-base repository is up to date.
All repositories are up to date.
Checking for upgrades (4 candidates): 100%
Processing candidates (4 candidates): 100%
The following 4 package(s) will be affected (of 0 checked):

Installed packages to be UPGRADED:
        FreeBSD-kernel-generic: 15.0 -> 15.0p1 [FreeBSD-base]
        FreeBSD-rescue: 15.0 -> 15.0p1 [FreeBSD-base]
        FreeBSD-runtime: 15.0 -> 15.0p1 [FreeBSD-base]
        FreeBSD-utilities: 15.0 -> 15.0p1 [FreeBSD-base]

Number of packages to be upgraded: 4

62 MiB to be downloaded.

Proceed with this action? [y/N]: 

Poudriere in Proxy World

Now to another deeper level – like in Inception (2010) movie – the Poudriere package building harvester.

If you want to check more on the Poudriere itself you can check these:

Now – first we need to install poudriere-devel package as it has the latest features.

test # pkg install poudriere-devel ccache4 git nginx
Updating FreeBSD-ports repository catalogue...
FreeBSD-ports repository is up to date.
Updating FreeBSD-ports-kmods repository catalogue...
FreeBSD-ports-kmods repository is up to date.
Updating FreeBSD-base repository catalogue...
FreeBSD-base repository is up to date.
All repositories are up to date.
The following 28 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        brotli: 1.1.0,1 [FreeBSD-ports]
        ccache4: 4.10.2_1 [FreeBSD-ports]
        curl: 8.16.0 [FreeBSD-ports]
        expat: 2.7.3 [FreeBSD-ports]
        gettext-runtime: 0.23.1 [FreeBSD-ports]
        git: 2.51.0 [FreeBSD-ports]
        indexinfo: 0.3.1_1 [FreeBSD-ports]
        libffi: 3.5.1 [FreeBSD-ports]
        libidn2: 2.3.8 [FreeBSD-ports]
        libnghttp2: 1.67.0 [FreeBSD-ports]
        libpsl: 0.21.5_2 [FreeBSD-ports]
        libssh2: 1.11.1,3 [FreeBSD-ports]
        libunistring: 1.4.1 [FreeBSD-ports]
        mpdecimal: 4.0.1 [FreeBSD-ports]
        nginx: 1.28.0_3,3 [FreeBSD-ports]
        p5-Authen-SASL: 2.1900 [FreeBSD-ports]
        p5-Crypt-URandom: 0.54 [FreeBSD-ports]
        p5-Digest-HMAC: 1.05 [FreeBSD-ports]
        p5-Error: 0.17030 [FreeBSD-ports]
        p5-IO-Socket-SSL: 2.095 [FreeBSD-ports]
        p5-MIME-Base32: 1.303 [FreeBSD-ports]
        p5-MIME-Base64: 3.16 [FreeBSD-ports]
        p5-Mozilla-CA: 20250602 [FreeBSD-ports]
        p5-Net-SSLeay: 1.94 [FreeBSD-ports]
        p5-URI: 5.32_1 [FreeBSD-ports]
        poudriere-devel: 3.4.99.20251213 [FreeBSD-ports]
        python311: 3.11.14 [FreeBSD-ports]
        readline: 8.2.13_2 [FreeBSD-ports]

Number of packages to be installed: 28

The process will require 283 MiB more space.
41 MiB to be downloaded.

Proceed with this action? [y/N]: y
[1/25] Fetching mpdecimal-4.0.1~f774e949d8.pkg: 100%  157 KiB 160.5kB/s    00:01    
(...)
[28/28] Installing git-2.51.0...
===> Creating groups
Creating group 'git_daemon' with gid '964'
===> Creating users
Creating user 'git_daemon' with uid '964'
[28/28] Extracting git-2.51.0: 100%

Basic Poudriere Setup

We will now setup some basic Poudriere setup.

test # export SSL=/usr/local/etc/ssl

test # mkdir -p \
              /usr/ports/distfiles \
              ${SSL}/keys \
              ${SSL}/certs

test # chmod 0600 ${SSL}/keys

test # openssl genrsa -out ${SSL}/keys/poudriere.key 4096

test # openssl rsa \
              -in  ${SSL}/keys/poudriere.key -pubout \
              -out ${SSL}/certs/poudriere.cert

test # mkdir /var/ccache

test # cat < /usr/local/etc/poudriere.conf
ZPOOL=zroot
FREEBSD_HOST=ftp://ftp.freebsd.org
BASEFS=/usr/local/poudriere
POUDRIERE_DATA=/usr/local/poudriere/data
DISTFILES_CACHE=/usr/ports/distfiles
CCACHE_DIR=/var/ccache
CHECK_CHANGED_OPTIONS=verbose
CHECK_CHANGED_DEPS=yes
PKG_REPO_SIGNING_KEY=/usr/local/etc/ssl/keys/poudriere.key
URL_BASE=http://0.0.0.0/
USE_TMPFS=no
TMPFS_LIMIT=12
MAX_MEMORY=12
PARALLEL_JOBS=4
PREPARE_PARALLEL_JOBS=4
MAX_FILES=4096
KEEP_OLD_PACKAGES=yes
KEEP_OLD_PACKAGES_COUNT=3
CHECK_CHANGED_OPTIONS=verbose
CHECK_CHANGED_DEPS=yes
RESTRICT_NETWORKING=no
PACKAGE_FETCH_URL="http://pkg.FreeBSD.org/\${ABI}"
PACKAGE_FETCH_BRANCH="latest"
export HTTP_PROXY="http://10.0.0.41:3128"
export HTTPS_PROXY="http://10.0.0.41:3128"
export FTP_PROXY="http://10.0.0.41:3128"
EOF

test # mkdir -p /usr/local/poudriere/data/logs/bulk

test # ln -s \
              /usr/local/etc/ssl/certs/poudriere.cert \
              /usr/local/poudriere/data/logs/bulk/poudriere.cert

test # cat < /usr/local/etc/poudriere.d/make.conf
# general
ALLOW_UNSUPPORTED_SYSTEM=yes
DISABLE_LICENSES=yes

# ccache(1)
WITH_CCACHE_BUILD=yes

# ports options
FORCE_MAKE_JOBS=yes
MAKE_JOBS_UNSAFE=yes
MAKE_JOBS_NUMBER=8
EOF

test # sed -i '' -E 's|text/plain[\t\ ]*txt|text/plain txt log|g' /usr/local/etc/nginx/mime.types

test # cat < /usr/local/etc/nginx/nginx.conf
events {
  worker_connections 1024;
}

http {
  include      mime.types;
  default_type application/octet-stream;

  server {
    listen 80 default;
    server_name 0.0.0.0;
    root /usr/local/share/poudriere/html;

    location /data {
      alias /usr/local/poudriere/data/logs/bulk;
      autoindex on;
    }

    location /packages {
      root /usr/local/poudriere/data;
      autoindex on;
    }
  }
}
EOF

test # mkdir /root/.cache

test # ln -sf /var/ccache /root/.cache/ccache

test # cat < /var/ccache/ccache.conf
max_size = 0
cache_dir = /var/ccache
base_dir = /var/ccache
hash_dir = false
EOF

Important Poudriere Config Part

The IMPORTANT settings here – to allow Poudriere function properly within proxy environment – are these five lines in the /usr/local/etc/poudriere.conf file.

export HTTP_PROXY="http://10.0.0.41:3128"
export HTTPS_PROXY="http://10.0.0.41:3128"
export FTP_PROXY="http://10.0.0.41:3128"
PACKAGE_FETCH_URL="http://pkg.FreeBSD.org/\${ABI}"
PACKAGE_FETCH_BRANCH="latest"

The first three are obvious – and YES – they need the export prefix to work.

The other two are less obvious … and I will show You why in a moment.

We need to create some FreeBSD jail – we will use 14.3-RELEASE as example. Use any version that you will be building packages for.

test # poudriere jail -c -j 14-3-R-amd64 -v 14.3-RELEASE
[00:00:00] Creating 14-3-R-amd64 fs at /usr/local/poudriere/jails/14-3-R-amd64... done
[00:00:00] Using pre-distributed MANIFEST for FreeBSD 14.3-RELEASE amd64
[00:00:00] Fetching base for FreeBSD 14.3-RELEASE amd64
base.txz                                               200 MB 5128 kBps    41s
[00:00:41] Extracting base... done
[00:00:49] Fetching src for FreeBSD 14.3-RELEASE amd64
src.txz                                                206 MB 4828 kBps    44s
[00:01:34] Extracting src... done
[00:01:46] Fetching lib32 for FreeBSD 14.3-RELEASE amd64
lib32.txz                                               60 MB   11 MBps    05s
[00:01:52] Extracting lib32... done
[00:01:54] Cleaning up... done
[00:01:54] Recording filesystem state for clean... done
[00:01:54] Upgrading using http
Looking up update.FreeBSD.org mirrors... none found.
Fetching public key from update.FreeBSD.org... done.
Fetching metadata signature for 14.3-RELEASE from update.FreeBSD.org... done.
Fetching metadata index... done.
Fetching 2 metadata files... done.
Inspecting system... done.
Preparing to download files... done.
Fetching 196 patches.....10....20....30....40....50....60....70....80....90....100....110....120....130....140....150....160....170....180....190... done.
Applying patches... done.
Fetching 40 files... ....10....20....30....40 done.
The following files will be removed as part of updating to
14.3-RELEASE-p7:
/usr/src/contrib/libarchive/libarchive/archive_getdate.c
/usr/src/contrib/libarchive/libarchive/archive_getdate.h
/usr/src/contrib/libarchive/libarchive/test/test_archive_getdate.c
(...)
/usr/src/usr.bin/tar/tests/Makefile
/usr/src/usr.sbin/freebsd-update/freebsd-update.sh
/usr/src/usr.sbin/rtsold/rtsol.c
Installing updates... done.
14.3-RELEASE-p7
[00:03:25] Recording filesystem state for clean... done
[00:03:25] Jail 14-3-R-amd64 14.3-RELEASE-p7 amd64 is ready to be used

test # poudriere jail -l
JAILNAME     VERSION         OSVERSION ARCH  METHOD TIMESTAMP           PATH
14-3-R-amd64 14.3-RELEASE-p7 1403000   amd64 http   2026-01-07 01:33:45 /usr/local/poudriere/jails/14-3-R-amd64

We also need FreeBSD Ports tree … just in a Poudriere way.

test # poudriere ports -c
[00:00:00] Creating default fs at /usr/local/poudriere/ports/default... done
[00:00:00] Cloning the ports tree...
fatal: unable to access 'https://git.FreeBSD.org/ports.git/': Could not resolve host: git.FreeBSD.org
[00:00:45] Error: /usr/local/share/poudriere/ports.sh:303: fail
[00:00:45] Error while creating ports tree, cleaning up.

This is where the dedicated git(1) config is needed as its a bitch and ignores *_PROXY variables πŸ™‚

test # git config --system http.proxy http://10.0.0.41:3128

test # poudriere ports -c
[00:00:00] Creating default fs at /usr/local/poudriere/ports/default... done
[00:00:00] Cloning the ports tree... done

test # poudriere ports -l
PORTSTREE METHOD    TIMESTAMP           PATH
default   git+https 2026-01-07 01:49:46 /usr/local/poudriere/ports/default

Works.

Now – lets try to actually build something with Poudriere.

We will try two ports that one needs to be actually build (dosunix) and one that is in POSIX sh(1) and does not need building (lsblk).

I will intentionally run first building process with proxy variables disabled like this in the /usr/local/etc/poudriere.conf file:

# PACKAGE_FETCH_URL="http://pkg.FreeBSD.org/\${ABI}"
# PACKAGE_FETCH_BRANCH="latest"
# export HTTP_PROXY="http://10.0.0.41:3128"
# export HTTPS_PROXY="http://10.0.0.41:3128"
# export FTP_PROXY="http://10.0.0.41:3128"

Here.

test # poudriere bulk -c -C -j 14-3-R-amd64 -b latest -p default sysutils/lsblk converters/dosunix

Result is below … and as expected it failed.

test # poudriere bulk -c -C -j 14-3-R-amd64 -b latest -p default sysutils/lsblk converters/dosunix
[00:00:00] Creating the reference jail... done
[00:00:00] Mounting system devices for 14-3-R-amd64-default
[00:00:00] Stashing existing package repository
[00:00:00] Mounting ccache from: /var/ccache
[00:00:00] Mounting ports from: /usr/local/poudriere/ports/default
[00:00:00] Mounting packages from: /usr/local/poudriere/data/packages/14-3-R-amd64-default
[00:00:00] Mounting distfiles from: /usr/ports/distfiles
[00:00:00] Appending to make.conf: /usr/local/etc/poudriere.d/make.conf
/etc/resolv.conf -> /usr/local/poudriere/data/.m/14-3-R-amd64-default/ref/etc/resolv.conf
[00:00:00] Starting jail 14-3-R-amd64-default
Updating /var/run/os-release done.
[00:00:00] Will build as root:wheel (0:0)
[00:00:00] Ports supports: FLAVORS SUBPACKAGES SELECTED_OPTIONS
[00:00:00] Inspecting /usr/local/poudriere/data/.m/14-3-R-amd64-default/ref//usr/ports for modifications to git checkout... no
[00:00:03] Ports top-level git hash: 284813ec0382a2bfe5b2e74a3081a67599d3155d
[00:00:03] Acquiring build logs lock for 14-3-R-amd64-default... done
[00:00:03] Logs: /usr/local/poudriere/data/logs/bulk/14-3-R-amd64-default/2026-01-07_01h58m23s
[00:00:03] WWW: http://0.0.0.0//build.html?mastername=14-3-R-amd64-default&build=2026-01-07_01h58m23s
[00:00:03] Loading MOVED for /usr/local/poudriere/data/.m/14-3-R-amd64-default/ref/usr/ports
[00:00:04] Gathering ports metadata
[00:00:04] Calculating ports order and dependencies
[00:00:04] Sanity checking the repository
[00:00:04] -c specified, cleaning all packages... done
[00:00:04] -C specified, cleaning listed packages
[00:00:04] (-C) Flushing package deletions
[00:00:04] Trimming IGNORED and blacklisted ports
[00:00:04] Package fetch: Looking for missing packages to fetch from pkg+http://pkg.FreeBSD.org/${ABI}/latest
[00:00:04] Package fetch: bootstrapping pkg
Bootstrapping pkg from pkg+http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest, please wait...
pkg: Attempted to fetch pkg+http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest/Latest/pkg.pkg
pkg: Attempted to fetch pkg+http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest/Latest/pkg.txz
pkg: Error: Address family for host not supported
Address resolution failed for http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest.
[00:08:58] Package fetch: Not fetching as remote repository is unavailable.
[00:08:58] pkg bootstrap missing: unable to inspect existing packages, cleaning all packages... done
[00:08:58] Deleting stale symlinks... done
[00:08:58] Deleting empty directories... done
[00:08:58] Unqueueing existing packages
[00:08:58] Unqueueing orphaned build dependencies
[00:08:58] Sanity checking build queue
[00:08:58] [14-3-R-amd64-default] [2026-01-07_01h58m23s] [pkgqueue_sanity_check] Time: 00:08:54
           Queued: 4 Inspected: 0 Ignored: 0 Built: 0 Failed: 0 Skipped: 0 Fetched: 0 Remaining: 4
[00:08:58] Recording filesystem state for prepkg... done
[00:08:58] Processing PRIORITY_BOOST
[00:08:58] Building 4 packages using up to 4 builders
[00:08:58] Hit CTRL+t at any time to see build progress and stats
[00:08:58] [01] [00:00:00] Builder starting
[00:08:58] [01] [00:00:00] Builder started
[00:08:58] [01] [00:00:00] Building   ports-mgmt/pkg | pkg-2.5.1
[00:11:56] [01] [00:02:58] Finished   ports-mgmt/pkg | pkg-2.5.1: Failed: fetch
[00:11:56] [01] [00:02:58] Skipping   devel/ccache | ccache-3.7.12_8: Dependent port ports-mgmt/pkg | pkg-2.5.1 failed
[00:11:56] [01] [00:02:58] Skipping   converters/dosunix | dosunix-1.0.14: Dependent port ports-mgmt/pkg | pkg-2.5.1 failed
[00:11:56] [01] [00:02:58] Skipping   sysutils/lsblk | lsblk-4.0: Dependent port ports-mgmt/pkg | pkg-2.5.1 failed
[00:11:57] Stopping up to 4 builders
[00:11:57] Creating pkg repository
[00:11:57] No packages present
[00:11:57] Committing packages to repository: /usr/local/poudriere/data/packages/14-3-R-amd64-default/.real_1767751820 via .latest symlink
[00:11:57] Removing old packages
[00:11:57] Failed ports: ports-mgmt/pkg:fetch
[00:11:57] Skipped ports: converters/dosunix devel/ccache sysutils/lsblk
[00:11:57] [14-3-R-amd64-default] [2026-01-07_01h58m23s] [committing] Time: 00:11:53
           Queued: 4 Inspected: 0 Ignored: 0 Built: 0 Failed: 1 Skipped: 3 Fetched: 0 Remaining: 0
[00:11:57] Logs: /usr/local/poudriere/data/logs/bulk/14-3-R-amd64-default/2026-01-07_01h58m23s
[00:11:57] WWW: http://0.0.0.0//build.html?mastername=14-3-R-amd64-default&build=2026-01-07_01h58m23s
[00:11:57] Cleaning up
[00:11:57] Stopping up to 4 builders
[00:11:57] Unmounting file systems
test # 

Now I will run it again but with proxy setting enabled in the /usr/local/etc/poudriere.conf file like that.

# PACKAGE_FETCH_URL="http://pkg.FreeBSD.org/\${ABI}"
# PACKAGE_FETCH_BRANCH="latest"
export HTTP_PROXY="http://10.0.0.41:3128"
export HTTPS_PROXY="http://10.0.0.41:3128"
export FTP_PROXY="http://10.0.0.41:3128"

It should work with one small caveat.

test # poudriere bulk -c -C -j 14-3-R-amd64 -b latest -p default sysutils/lsblk converters/dosunix
[00:00:00] Creating the reference jail... done
[00:00:00] Mounting system devices for 14-3-R-amd64-default
[00:00:00] Stashing existing package repository
[00:00:00] Mounting ccache from: /var/ccache
[00:00:00] Mounting ports from: /usr/local/poudriere/ports/default
[00:00:00] Mounting packages from: /usr/local/poudriere/data/packages/14-3-R-amd64-default
[00:00:00] Mounting distfiles from: /usr/ports/distfiles
[00:00:00] Appending to make.conf: /usr/local/etc/poudriere.d/make.conf
/etc/resolv.conf -> /usr/local/poudriere/data/.m/14-3-R-amd64-default/ref/etc/resolv.conf
[00:00:00] Starting jail 14-3-R-amd64-default
Updating /var/run/os-release done.
[00:00:00] Will build as root:wheel (0:0)
[00:00:01] Ports supports: FLAVORS SUBPACKAGES SELECTED_OPTIONS
[00:00:01] Inspecting /usr/local/poudriere/data/.m/14-3-R-amd64-default/ref//usr/ports for modifications to git checkout... no
[00:00:04] Ports top-level git hash: 284813ec0382a2bfe5b2e74a3081a67599d3155d 
[00:00:04] Acquiring build logs lock for 14-3-R-amd64-default... done
[00:00:04] Logs: /usr/local/poudriere/data/logs/bulk/14-3-R-amd64-default/2026-01-07_02h13m56s
[00:00:04] WWW: http://0.0.0.0//build.html?mastername=14-3-R-amd64-default&build=2026-01-07_02h13m56s
[00:00:04] Loading MOVED for /usr/local/poudriere/data/.m/14-3-R-amd64-default/ref/usr/ports
[00:00:04] Gathering ports metadata
[00:00:04] Calculating ports order and dependencies
[00:00:04] Sanity checking the repository
[00:00:04] -c specified, cleaning all packages... done
[00:00:04] -C specified, cleaning listed packages
[00:00:04] (-C) Flushing package deletions
[00:00:04] Trimming IGNORED and blacklisted ports
[00:00:04] Package fetch: Looking for missing packages to fetch from pkg+http://pkg.FreeBSD.org/${ABI}/latest
[00:00:04] Package fetch: bootstrapping pkg
Bootstrapping pkg from pkg+http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest, please wait...
[14-3-R-amd64-default] Installing pkg-2.5.1...
[14-3-R-amd64-default] Extracting pkg-2.5.1: 100%
Updating Poudriere repository catalogue...
pkg: No SRV record found for the repo 'Poudriere'
[14-3-R-amd64-default] Fetching meta.conf: 100%    179 B   0.2 k/s    00:01    
pkg: packagesite URL error for pkg+http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest/data.pkg -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest/data.tzst -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest/packagesite.pkg -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest/packagesite.tzst -- pkg+:// implies SRV mirror type
Unable to update repository Poudriere
Error updating repositories!
[00:00:29] Package fetch: Not fetching as remote repository is unavailable.
[00:00:29] pkg bootstrap missing: unable to inspect existing packages, cleaning all packages... done
[00:00:29] Deleting stale symlinks... done
[00:00:29] Deleting empty directories... done
[00:00:29] Unqueueing existing packages
[00:00:29] Unqueueing orphaned build dependencies
[00:00:29] Sanity checking build queue
[00:00:29] [14-3-R-amd64-default] [2026-01-07_02h13m56s] [pkgqueue_sanity_check] Time: 00:00:26
           Queued: 4 Inspected: 0 Ignored: 0 Built: 0 Failed: 0 Skipped: 0 Fetched: 0 Remaining: 4
[00:00:29] Recording filesystem state for prepkg... done
[00:00:29] Processing PRIORITY_BOOST
[00:00:30] Building 4 packages using up to 4 builders
[00:00:30] Hit CTRL+t at any time to see build progress and stats
[00:00:30] [01] [00:00:00] Builder starting
[00:00:30] [01] [00:00:00] Builder started
[00:00:30] [01] [00:00:00] Building   ports-mgmt/pkg | pkg-2.5.1
[00:02:34] [01] [00:02:04] Finished   ports-mgmt/pkg | pkg-2.5.1: Success
[00:02:34] [02] [00:00:00] Builder starting
[00:02:34] [01] [00:00:00] Building   devel/ccache | ccache-3.7.12_8
[00:02:35] [02] [00:00:01] Builder started
[00:02:35] [02] [00:00:00] Building   sysutils/lsblk | lsblk-4.0
[00:02:36] [02] [00:00:01] Finished   sysutils/lsblk | lsblk-4.0: Success
[00:02:39] [01] [00:00:05] Finished   devel/ccache | ccache-3.7.12_8: Success
[00:02:39] [01] [00:00:00] Building   converters/dosunix | dosunix-1.0.14
[00:02:42] [01] [00:00:03] Finished   converters/dosunix | dosunix-1.0.14: Success
[00:02:42] Stopping up to 4 builders
[00:02:42] Creating pkg repository
[00:02:42] Signing repository with key: /usr/local/etc/ssl/keys/poudriere.key
Creating repository in /tmp/packages: 100%
Packing files for repository: 100%
[00:02:43] Signing pkg bootstrap with method: pubkey
[00:02:43] Committing packages to repository: /usr/local/poudriere/data/packages/14-3-R-amd64-default/.real_1767752199 via .latest symlink
[00:02:43] Removing old packages
[00:02:43] Built ports: ports-mgmt/pkg sysutils/lsblk devel/ccache converters/dosunix
[00:02:43] [14-3-R-amd64-default] [2026-01-07_02h13m56s] [committing] Time: 00:02:39
           Queued: 4 Inspected: 0 Ignored: 0 Built: 4 Failed: 0 Skipped: 0 Fetched: 0 Remaining: 0
[00:02:43] Logs: /usr/local/poudriere/data/logs/bulk/14-3-R-amd64-default/2026-01-07_02h13m56s
[00:02:43] WWW: http://0.0.0.0//build.html?mastername=14-3-R-amd64-default&build=2026-01-07_02h13m56s
[00:02:43] Cleaning up
[00:02:43] Stopping up to 4 builders
[00:02:43] Unmounting file systems

Also in nice graphical colored form.

The build generally ended successfully – we have our packages available.

test # ls -l /usr/local/poudriere/data/packages/14-3-R-amd64-default/All/
total 6294
-rw-r--r--  1 root wheel  126041 Jan  7 02:16 ccache-3.7.12_8.pkg
-rw-r--r--  1 root wheel    5963 Jan  7 02:16 dosunix-1.0.14.pkg
-rw-r--r--  1 root wheel    6544 Jan  7 02:16 lsblk-4.0.pkg
-rw-r--r--  1 root wheel 6290261 Jan  7 02:16 pkg-2.5.1.pkg

The only errors were these below and they did not broken our build:

(...)
Updating Poudriere repository catalogue...
pkg: No SRV record found for the repo 'Poudriere'
[14-3-R-amd64-default] Fetching meta.conf: 100%    179 B   0.2 k/s    00:01    
pkg: packagesite URL error for pkg+http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest/data.pkg -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest/data.tzst -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest/packagesite.pkg -- pkg+:// implies SRV mirror type
pkg: packagesite URL error for pkg+http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest/packagesite.tzst -- pkg+:// implies SRV mirror type
Unable to update repository Poudriere
Error updating repositories!
[00:00:29] Package fetch: Not fetching as remote repository is unavailable.
(...)

To get the idea what is wrong here we need to level up our debugging skill and get our hands dirty with FreeBSD tools like ktrace(8) and kdump(8) to know what is missing.

test # ktrace -di poudriere bulk -c -C -j 14-3-R-amd64 -b latest -p default sysutils/lsblk converters/dosunix
(...)
[00:00:32] [01] [00:00:00] Builder starting
[00:00:33] [01] [00:00:01] Builder started
[00:00:33] [01] [00:00:00] Building   ports-mgmt/pkg | pkg-2.5.1

When You reach this place – just hit [CTRL]+[C] to stop it – its not needed to wait for it.

Now check with kdump(8) the gathered data.

test # kdump | grep -m 5 -C 2 'pkg+' | tail -4
        Poudriere: {
        url: pkg+http://pkg.FreeBSD.org/${ABI}/latest,
        mirror_type: srv
        }

I wanted to show only the part that was important – Of course I did not guessed it like that … just find it with a help of a friend.

Poudriere – on the fly – defines additional repository … and if you did not override it – yes – it will use both pkg+ and srv things that hurt our proxy environment.

This is part of the Poudriere code that is responsible for its generation.

cat >> "${MASTERMNT:?}/etc/pkg/poudriere.conf" <<-EOF
FreeBSD: {
        enabled: no,
        priority: 100
}
FreeBSD-kmods: {
        enabled: no,
        priority: 100
}
FreeBSD-ports: {
        enabled: no,
        priority: 100
}
FreeBSD-ports-kmods: {
        enabled: no,
        priority: 100
}
FreeBSD-base: {
        enabled: no,
        priority: 100
}

Poudriere: {
        url: ${packagesite},
        mirror_type: $(if [ "${packagesite#pkg+}" = "${packagesite}" ]; then echo "none"; else echo "srv"; fi)
}
EOF

So it will generate the ‘broken for proxy’ config like that:

Poudriere: {
        url: pkg+http://pkg.FreeBSD.org/${ABI}/latest,
        mirror_type: srv
}

Looking at the code above you can see the if that checks how the packagesite is defined.

Lets see how Poudriere figures that one out in the code.

test # grep -m 1 packagesite= common.sh
        packagesite="${PACKAGE_FETCH_URL:+${PACKAGE_FETCH_URL}/}${PACKAGE_FETCH_BRANCH}"

So the answer is that we need to set PACKAGE_FETCH_URL and PACKAGE_FETCH_BRANCH in the /usr/local/etc/poudriere.conf file … the ones I commented out to explain all that in details.

So now – with all needed settings enabled at /usr/local/etc/poudriere.conf file … fully working Poudriere build in proxy environment.

PACKAGE_FETCH_URL="http://pkg.FreeBSD.org/\${ABI}"
PACKAGE_FETCH_BRANCH="latest"
export HTTP_PROXY="http://10.0.0.41:3128"
export HTTPS_PROXY="http://10.0.0.41:3128"
export FTP_PROXY="http://10.0.0.41:3128"

Remember to have the \$ as backslashed as Poudriere is written in POSIX sh(1).

Now the fully working run.

test # poudriere bulk -c -C -j 14-3-R-amd64 -b latest -p default sysutils/lsblk converters/dosunix
[00:00:00] Creating the reference jail... done
[00:00:00] Mounting system devices for 14-3-R-amd64-default
[00:00:00] Stashing existing package repository
[00:00:00] Mounting ccache from: /var/ccache
[00:00:00] Mounting ports from: /usr/local/poudriere/ports/default
[00:00:00] Mounting packages from: /usr/local/poudriere/data/packages/14-3-R-amd64-default
[00:00:00] Mounting distfiles from: /usr/ports/distfiles
[00:00:00] Appending to make.conf: /usr/local/etc/poudriere.d/make.conf
/etc/resolv.conf -> /usr/local/poudriere/data/.m/14-3-R-amd64-default/ref/etc/resolv.conf
[00:00:00] Starting jail 14-3-R-amd64-default
Updating /var/run/os-release done.
[00:00:00] Will build as root:wheel (0:0)
[00:00:00] Ports supports: FLAVORS SUBPACKAGES SELECTED_OPTIONS
[00:00:00] Inspecting /usr/local/poudriere/data/.m/14-3-R-amd64-default/ref//usr/ports for modifications to git checkout... no
[00:00:03] Ports top-level git hash: 284813ec0382a2bfe5b2e74a3081a67599d3155d 
[00:00:03] Acquiring build logs lock for 14-3-R-amd64-default... done
[00:00:03] Logs: /usr/local/poudriere/data/logs/bulk/14-3-R-amd64-default/2026-01-07_03h52m21s
[00:00:03] WWW: http://0.0.0.0//build.html?mastername=14-3-R-amd64-default&build=2026-01-07_03h52m21s
[00:00:03] Loading MOVED for /usr/local/poudriere/data/.m/14-3-R-amd64-default/ref/usr/ports
[00:00:04] Gathering ports metadata
[00:00:04] Calculating ports order and dependencies
[00:00:04] Sanity checking the repository
[00:00:04] -c specified, cleaning all packages... done
[00:00:04] -C specified, cleaning listed packages
[00:00:04] (-C) Flushing package deletions
[00:00:04] Trimming IGNORED and blacklisted ports
[00:00:04] Package fetch: Looking for missing packages to fetch from http://pkg.FreeBSD.org/${ABI}/latest
[00:00:04] Package fetch: bootstrapping pkg
Bootstrapping pkg from http://pkg.FreeBSD.org/FreeBSD:14:amd64/latest, please wait...
[14-3-R-amd64-default] Installing pkg-2.5.1...
[14-3-R-amd64-default] Extracting pkg-2.5.1: 100%
Updating Poudriere repository catalogue...
[14-3-R-amd64-default] Fetching meta.conf: 100%    179 B   0.2 k/s    00:01    
[14-3-R-amd64-default] Fetching data: 100%   11 MiB   3.7 M/s    00:03    
Processing entries: 100%
Poudriere repository update completed. 36661 packages processed.
All repositories are up to date.
[00:00:20] Package fetch: Will fetch 3 packages from remote or local pkg cache
Updating database digests format: 100%
The following packages will be fetched:

New packages to be FETCHED:
        ccache: 3.7.12_8 (134 KiB: 91.17% of the 147 KiB to download)
        dosunix: 1.0.14 (6 KiB: 4.04% of the 147 KiB to download)
        lsblk: 4.0 (7 KiB: 4.79% of the 147 KiB to download)

Number of packages to be fetched: 3

147 KiB to be downloaded.
[14-3-R-amd64-default] Fetching ccache-3.7.12_8: 100%  134 KiB 137.3 k/s    00:01    
[14-3-R-amd64-default] Fetching lsblk-4.0: 100%    7 KiB   7.2 k/s    00:01    
[14-3-R-amd64-default] Fetching dosunix-1.0.14: 100%    6 KiB   6.1 k/s    00:01    
[00:00:21] Package fetch: Using cached copy of ccache-3.7.12_8
[00:00:21] Package fetch: Using cached copy of dosunix-1.0.14
[00:00:21] Package fetch: Using cached copy of lsblk-4.0
[00:00:21] Checking packages for incremental rebuild needs
[00:00:21] Deleting stale symlinks... done
[00:00:21] Deleting empty directories... done
[00:00:21] Package fetch: Generating logs for fetched packages
[00:00:21] Unqueueing existing packages
[00:00:21] Unqueueing orphaned build dependencies
[00:00:21] Sanity checking build queue
[00:00:21] [14-3-R-amd64-default] [2026-01-07_03h52m21s] [pkgqueue_sanity_check] Time: 00:00:18
           Queued: 4 Inspected: 0 Ignored: 0 Built: 0 Failed: 0 Skipped: 0 Fetched: 3 Remaining: 1
[00:00:21] Recording filesystem state for prepkg... done
[00:00:21] Processing PRIORITY_BOOST
[00:00:21] Building 1 packages using up to 1 builders
[00:00:21] Hit CTRL+t at any time to see build progress and stats
[00:00:21] [01] [00:00:00] Builder starting
[00:00:21] [01] [00:00:00] Builder started
[00:00:21] [01] [00:00:00] Building   ports-mgmt/pkg | pkg-2.5.1
[00:02:25] [01] [00:02:04] Finished   ports-mgmt/pkg | pkg-2.5.1: Success
[00:02:25] Stopping up to 1 builders
[00:02:25] Creating pkg repository
[00:02:25] Signing repository with key: /usr/local/etc/ssl/keys/poudriere.key
Creating repository in /tmp/packages: 100%
Packing files for repository: 100%
[00:02:25] Signing pkg bootstrap with method: pubkey
[00:02:25] Committing packages to repository: /usr/local/poudriere/data/packages/14-3-R-amd64-default/.real_1767758087 via .latest symlink
[00:02:25] Removing old packages
[00:02:25] Built ports: ports-mgmt/pkg
[00:02:25] Fetched ports: sysutils/lsblk converters/dosunix devel/ccache
[00:02:25] [14-3-R-amd64-default] [2026-01-07_03h52m21s] [committing] Time: 00:02:23
           Queued: 4 Inspected: 0 Ignored: 0 Built: 1 Failed: 0 Skipped: 0 Fetched: 3 Remaining: 0
[00:02:25] Logs: /usr/local/poudriere/data/logs/bulk/14-3-R-amd64-default/2026-01-07_03h52m21s
[00:02:25] WWW: http://0.0.0.0//build.html?mastername=14-3-R-amd64-default&build=2026-01-07_03h52m21s
[00:02:25] Cleaning up
[00:02:25] Stopping up to 4 builders
[00:02:25] Unmounting file systems
test # 

… and in the TECHNICOLOR form πŸ™‚

The part that was broken earlier is now fine.

Updating Poudriere repository catalogue...
[14-3-R-amd64-default] Fetching meta.conf: 100%    179 B   0.2 k/s    00:01    
[14-3-R-amd64-default] Fetching data: 100%   11 MiB   3.7 M/s    00:03    
Processing entries: 100%

I believe that concludes this article – let me know if I missed anything.

EOF

Simple FreeBSD Poudriere Harvester Guide

The Poudriere is one of the topics I kinda omitted. I thought that official pkg(8) packages are more then enough and that occasional needed package recompilations are not the reasons to use a harvester such as Poudriere for that task. What was my needed recompilations? Usually the audio/lame because FreeBSD did not provided package for it for more then a decade while OpenBSD did … and multimedia/ffmpeg just to include that lame(1) support. Also at the beginning of exFAT format the sysutils/exfat-utils and sysutils/fusefs-exfat needed to be built by hand because of additional license agreement.

This guide will be about running Poudriere on a bare metal or virtual machine. If you would like to run Poudriere inside FreeBSD Jail instead – then check the Poudriere Inside FreeBSD VNET Jail article.

logo-freebsd

The Table of Contents for this article:

  • Poudriere Name
  • Poudriere Features
  • FreeBSD Host Setup
  • Poudriere Setup
  • Poudriere Jails
  • Poudriere Ports Tree
  • Poudriere Packages to Build List
  • Poudriere Options
  • Nginx
  • Memcached
  • Ccache
  • Poudriere Packages Build Process
  • Our Repository Client Setup
  • Next Builds
  • Summary

There was as time when I had a dedicated script that would do just that – rebuild several ports as packages after the pkg upgrade cycle.

% cat pkg-recompile.sh
#! /bin/sh

# OPTIONS
  PORTS='audio/lame multimedia/ffmpeg sysutils/exfat-utils sysutils/fusefs-exfat'

# ONLY root CAN BUILD PACKAGES/PORTS
if [ "$( whoami )" != "root" ]
then
  echo "ER: only 'root' may use this script"
  exit 1
fi

# BUILD PACKAGES
case ${1} in
  # REBUILD PACKAGES
  (b|build)
    for PORT in ${PORTS}
    do
      pkg unlock -y ${PORT} 1> /dev/null 2> /dev/null
      env BATCH=yes DISABLE_VULNERABILITIES=yes \
        make -C /usr/ports/${PORT} build deinstall install clean &
      MAKE=${!}
      rctl -a process:${MAKE}:pcpu:deny=40
      wait ${MAKE}
      pkg lock -y ${PORT}
    done
    ;;

  # CLEAN
  (c|clean)
    for PORT in ${PORTS}
    do
      make -C /usr/ports/${PORT} clean
    done
    ;;

  # USAGE
  (*)
    echo "usage: ${0##*/} b|c|build|clean"
    exit 1
    ;;

esac

Now none of that is needed anymore … unless you want to Connect FreeBSD to FreeIPA/IDM server … this is the case where Poudriere comes pretty handy. Here you may find my latest attempt with FreeBSD on FreeIPA/IDM with Poudriere Repo guide. You may configure/rebuild needed packages by hand or use a tool that will do that for you and you will then just use its custom build packages repository to install them on multiple systems. Scale often changes many things and this is not different with Poudriere tool.

Poudriere Name

… its quite unfortunate to say the least. I needed some time to actually learn to remember that name properly. Not sure I have any useful tips here – I just split it in half to make it easier to remember – as poud and riere parts. In the beginning I interpreted the pond part as British Pound … uncorrected of course. I really wish the author would name it simpler – like Rebuild or Bob the Builder for example πŸ™‚

So what does Poudriere really means? Its a French translation of Powder Keg – which means a place where gunpowder was stored. There is some logic in that … as all the power (gun power) is in the packages … and Poudriere creates that place.

UPDATE: Dan Langille just reminded me that Poudriere replaced Powder Keg which was a similar tool – that explains the French translation for the name πŸ™‚

Poudriere Features

The Poudriere is a bulk package builder and port tester. It uses a ‘clean’ FreeBSD Jails containers to build packages for defined FreeBSD version (supported or not) and a ‘snapshot’ of a FreeBSD Ports tree. Most of the time it will be the latest FreeBSD Ports tree ‘snapshot’ but nothing prevents you from using older ‘snapshots’ with older packages versions when needed.

Then the results (and logs) of these builds are available as HTML pages and you can (and probably should) host them as some WWW server.

All of this seems scary, complicated and pointless bloat to some … but it gets simple and obvious once you try it. You know me – I have an allergy for bullshit and bloat and Poudriere is really far from both of them.

Its kinda like with the famous UNIX co-creator Dennis Ritchie quote – “UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity.” – just kidding – Poudriere actually is quite simple once you start using it – and that is probably the biggest obstacle to knowing it better. Just start using it (in a VM or in a Jail) to get to know it better and once you know it better – setup it properly and just use. Its far from over-complicated solutions such as SELinux, systemd(1) or Kubernetes.

FreeBSD Host Setup

First things first. The ‘three kings’ of and FreeBSD system configuration:

  • /boot/loader.conf
  • /etc/rc.conf
  • /etc/sysctl.conf

Here they are:

The /boot/loader.conf file.

# cat /boot/loader.conf
security.bsd.allow_destructive_dtrace=0
kern.geom.label.disk_ident.enable=0
kern.geom.label.gptid.enable=0
cryptodev_load=YES
zfs_load=YES

The /etc/rc.conf file.

# cat /etc/rc.conf
  clear_tmp_enable=YES
  syslogd_flags="-ss"
  sendmail_enable=NONE
  hostname=fbsdpr
  ifconfig_em0="inet 10.0.10.123/24"
  defaultrouter="10.0.10.1"
  sshd_enable=YES
  dumpdev=AUTO
  zfs_enable=YES
  nginx_enable=YES
  memcached_enable=YES
  memcached_flags="-l localhost -m 8192"

The /etc/sysctl.conf file.

# cat /etc/sysctl.conf
vfs.zfs.min_auto_ashift=12

From the three above only the /etc/rc.conf is important as the other two only have settings from the bsdinstall(8) installer – as used with the Auto ZFS option.

We will also need to populate /etc/resolv.conf file to have DNS configured.

# echo nameserver 1.1.1.1 > /etc/resolv.conf

Pick your personal DNS server favorite here if the Cloudflare one does not suit your needs.

Poudriere Setup

First we need to install some packages – especially the Poudriere package – to make them more up-to-date we would prefer the latest branch of pkg(8) packages.

# sed -i '' -e 's|quarterly|latest|g' /etc/pkg/FreeBSD.conf

# grep latest /etc/pkg/FreeBSD.conf
  url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest",

Now we can add needed packages.

# env ASSUME_ALWAYS_YES=yes \
    pkg install -y \
      poudriere \
      portmaster \
      screen \
      tmux \
      zsh \
      beadm \
      lsblk \
      nginx \
      git-lite \
      htop \
      tree \
      ccache-memcached \
      memcached \
      groff

Some of them are less needed but they definitely does not hurt for workflow. Absolute minimum are:

  • poudriere
  • nginx
  • git-lite
  • ccache-memcached
  • groff

[ CAUTION: BEGIN ]

The devel/ccache-memcached port seems to be removed now – so as showed in one of the later guides – Connect FreeBSD 14.0-STABLE to FreeIPA/IDM – please useΒ devel/ccache4 instead. Thanks.

[ CAUTION: END ]

Now … lets prepare some dirs and certs to make our packages signed.

# SSL=/usr/local/etc/ssl
# mkdir -p   ${SSL}/keys ${SSL}/certs /usr/ports/distfiles
# chmod 0600 ${SSL}/keys
# openssl genrsa -out ${SSL}/keys/poudriere.key 4096
# openssl rsa -in ${SSL}/keys/poudriere.key -pubout -out ${SSL}/certs/poudriere.cert

As we will be using ZFS for Poudriere we will now create dedicated dataset for it.

# zfs create -o mountpoint=/usr/local/poudriere zroot/poudriere

[ CAUTION: BEGIN ]

Because of the ZROOTFS /usr/local bug I have switched the ZROOTFS variable to /dev/null and Poudriere still works well.

[ CAUTION: END ]

Now we will create the Poudriere config file.

# cat << EOF > /usr/local/etc/poudriere.conf
ZPOOL=zroot
BASEFS=/usr/local/poudriere
ZROOTFS=/dev/null
FREEBSD_HOST=ftp://ftp.freebsd.org
POUDRIERE_DATA=/usr/local/poudriere/data
CHECK_CHANGED_OPTIONS=verbose
CHECK_CHANGED_DEPS=yes
PKG_REPO_SIGNING_KEY=/usr/local/etc/ssl/keys/poudriere.key
URL_BASE=http://10.0.10.123/
USE_TMPFS=yes
TMPFS_LIMIT=8
MAX_MEMORY=8
MAX_FILES=2048
DISTFILES_CACHE=/usr/ports/distfiles
KEEP_OLD_PACKAGES=yes
KEEP_OLD_PACKAGES_COUNT=3
CHECK_CHANGED_OPTIONS=verbose
CHECK_CHANGED_DEPS=yes
CCACHE_DIR=/var/ccache
RESTRICT_NETWORKING=no
EOF

Its quite basic – yet it will do the job.

Poudriere Jails

Next we will create Poudriere Jails for each FreeBSD version we want to create pkg(8) repositories with packages.

I will create Jails for all FreeBSD 13.x versions – supported or not.

# poudriere jail -c -j 13-2-R-amd64 -v 13.2-RELEASE
# poudriere jail -c -j 13-1-R-amd64 -v 13.1-RELEASE
# poudriere jail -c -j 13-0-R-amd64 -v 13.0-RELEASE -m ftp-archive

Keep in mind that you need to specify additional -m ftp-archive argument for unsupported FreeBSD versions.

After some time you will end up with ready to use Poudriere FreeBSD Jails containers as shown below.

# poudriere jail -l
13-0-R-amd64 13.0-RELEASE-p13 amd64 ftp-archive 2023-04-28 03:22:05 /usr/local/poudriere/jails/13-0-R-amd64
13-1-R-amd64 13.1-RELEASE-p7  amd64 http        2023-04-27 23:17:13 /usr/local/poudriere/jails/13-1-R-amd64
13-2-R-amd64 13.2-RELEASE     amd64 http        2023-04-27 23:15:30 /usr/local/poudriere/jails/13-2-R-amd64

Poudriere Ports Tree

You may already have an up-to-date FreeBSD Ports tree on your disk at usual /usr/ports location – but we need Poudriere to get its own one too.

# poudriere ports -c

After fetching one you can list it like that.

# poudriere ports -l
default   git+https 2023-04-27 06:16:42 /usr/local/poudriere/ports/default

Poudriere Packages to Build List

Here is the best part – you do not need to build all 33000+ ports – you may specify just several of them. This is what we would do now.

# cat << EOF > /usr/local/etc/poudriere.d/list
sysutils/beadm
sysutils/lsblk
devel/m4
EOF

Accepting all possible licenses is also a good idea.

# echo DISABLE_LICENSES=yes >> /usr/local/etc/poudriere.d/make.conf

We will also specify which options should (and should not) be included in our built packages.

# cat << EOF > /usr/local/etc/poudriere.d/13-0-R-amd64-make.conf
ALLOW_UNSUPPORTED_SYSTEM=yes
DISABLE_LICENSES=yes
EOF

# cat << EOF > /usr/local/etc/poudriere.d/13-1-R-amd64-make.conf
ALLOW_UNSUPPORTED_SYSTEM=yes
DISABLE_LICENSES=yes
EOF

# cat << EOF > /usr/local/etc/poudriere.d/13-2-R-amd64-make.conf
ALLOW_UNSUPPORTED_SYSTEM=yes
DISABLE_LICENSES=yes
EOF

Poudriere Options

You may choose the Poudriere packages options the same interactive way you do when you use the FreeBSD Ports tree.

To do that – here are the needed spells.

# poudriere options -c -j 13-0-R-amd64 -f /usr/local/etc/poudriere.d/list
# poudriere options -c -j 13-1-R-amd64 -f /usr/local/etc/poudriere.d/list
# poudriere options -c -j 13-2-R-amd64 -f /usr/local/etc/poudriere.d/list

Nginx

To make most of the Poudriere you will also need some web server. I have chosen Nginx for that task as its currently ‘the’ standard for the Internet.

Its setup is not complicated – just repeat steps below and you are done.

# service nginx enable

# sed -i '' -E 's|text/plain[\t\ ]*txt|text/plain txt log|g' /usr/local/etc/nginx/mime.types

# cat << EOF > /usr/local/etc/nginx/nginx.conf
events {
  worker_connections 1024;
}

http {
  include      mime.types;
  default_type application/octet-stream;

  server {
    listen 80 default;
    server_name ${IP};
    root /usr/local/share/poudriere/html;

    location /data {
      alias /usr/local/poudriere/data/logs/bulk;
      autoindex on;
    }

    location /packages {
      root /usr/local/poudriere/data;
      autoindex on;
    }
  }
}
EOF

# service nginx restart

The /usr/local/etc/nginx/mime.types part will allow you to display the *.log files in the browser instead of ‘forcing’ the browser to pointlessly download them.

Our web server seems to work properly.

# sockstat -l4
USER     COMMAND    PID   FD PROTO  LOCAL ADDRESS         FOREIGN ADDRESS
www      nginx      95263 7  tcp4   *:80                  *:*
root     nginx      95262 7  tcp4   *:80                  *:*
root     sshd       706   5  tcp4   *:22                  *:*

Memcached

As we will be using devel/ccache-memcached package to speed up builds – we would also need memcached to be running.

We already have needed configuration in /etc/rc.conf file so we only need to start it.

# grep memcached /etc/rc.conf
  memcached_enable="YES"
  memcached_flags="-l localhost -m 8192"

# service memcached restart

# sockstat -l4
USER     COMMAND    PID   FD PROTO  LOCAL ADDRESS         FOREIGN ADDRESS
nobody   memcached  37844 13 tcp4   127.0.0.1:11211       *:*
www      nginx      69727 7  tcp4   *:80                  *:*
root     nginx      69726 7  tcp4   *:80                  *:*
root     sshd       706   5  tcp4   *:22                  *:*

Ccache

We will now configure ccache(1) service.

Like success have many father the same ccache(1) have many configs – to be sure – we will propagate all of them.

We will use /var/ccache dir for the ccache(1) cache dir = but feel free to put it somewhere else or even with a dedicated ZFS dataset.

# mkdir -p /var/ccache

# cat << EOF > /usr/local/etc/ccache.conf
max_size = 0
cache_dir = /var/ccache
base_dir = /var/ccache
memcached_conf = --SERVER=localhost:11211
memcached_only = true
EOF

# cat << EOF > /root/.ccache/ccache.conf
max_size = 0
cache_dir = /var/ccache
base_dir = /var/ccache
memcached_conf = --SERVER=localhost:11211
memcached_only = true
EOF

# cat << EOF > /var/ccache/ccache.conf
max_size = 0
cache_dir = /var/ccache
base_dir = /var/ccache
memcached_conf = --SERVER=localhost:11211
memcached_only = true
EOF

The ccache(1) stats output after several builds below.

# ccache -s
cache directory                     /var/ccache
primary config                      /var/ccache/ccache.conf
secondary config      (readonly)    /usr/local/etc/ccache.conf
stats updated                       Fri Apr 28 04:10:17 2023
cache hit (direct)                  4510
cache hit (preprocessed)             713
cache miss                          2481
cache hit rate                     67.80 %
called for link                     5616
called for preprocessing            1476
multiple source files                 18
compile failed                      1143
preprocessor error                   351
bad compiler arguments                72
unsupported source language            9
autoconf compile/link               3147
no input file                        441
cleanups performed                     0
files in cache                      6303
cache size                          26.6 MB

Poudriere Packages Build Process

Now as you have everything configured and ready – you may build your custom packages.

These next commands will build repositories with your configured packages.

# poudriere bulk -j 13-0-R-amd64 -f /usr/local/etc/poudriere.d/list
# poudriere bulk -j 13-1-R-amd64 -f /usr/local/etc/poudriere.d/list
# poudriere bulk -j 13-2-R-amd64 -f /usr/local/etc/poudriere.d/list

The Poudriere console output is pretty colorful and nice – here is how it looks.

poudriere-build

Lets check how it look on the browser side.

poudriere-www-01

Lets ‘click’ the 13-2-R-amd64-default name for some details.

poudriere-www-02

It shows that 14 packages has been built in the process and all of them succeed.

Lets now click the date_time build name.

poudriere-www-03

You will now see the details about that build run – with logs and time needed for each package build.

You can ‘click’ on the package name to get the build log details.

poudriere-www-04

Here is how our three repositories look after the build process.

# ls -l /usr/local/poudriere/data/packages
total 26K
drwxr-xr-x 4 root wheel 14 2023-04-28 04:10 13-0-R-amd64-default/
drwxr-xr-x 4 root wheel 14 2023-04-28 04:06 13-1-R-amd64-default/
drwxr-xr-x 4 root wheel 14 2023-04-28 04:07 13-2-R-amd64-default/

# tree /usr/local/poudriere/data/packages
/usr/local/poudriere/data/packages
β”œβ”€β”€ 13-0-R-amd64-default
β”‚Β Β  β”œβ”€β”€ All -> .latest/All
β”‚Β Β  β”œβ”€β”€ Latest -> .latest/Latest
β”‚Β Β  β”œβ”€β”€ meta.conf -> .latest/meta.conf
β”‚Β Β  β”œβ”€β”€ meta.pkg -> .latest/meta.pkg
β”‚Β Β  β”œβ”€β”€ meta.txz -> .latest/meta.txz
β”‚Β Β  β”œβ”€β”€ packagesite.pkg -> .latest/packagesite.pkg
β”‚Β Β  └── packagesite.txz -> .latest/packagesite.txz
β”œβ”€β”€ 13-1-R-amd64-default
β”‚Β Β  β”œβ”€β”€ All -> .latest/All
β”‚Β Β  β”œβ”€β”€ Latest -> .latest/Latest
β”‚Β Β  β”œβ”€β”€ meta.conf -> .latest/meta.conf
β”‚Β Β  β”œβ”€β”€ meta.pkg -> .latest/meta.pkg
β”‚Β Β  β”œβ”€β”€ meta.txz -> .latest/meta.txz
β”‚Β Β  β”œβ”€β”€ packagesite.pkg -> .latest/packagesite.pkg
β”‚Β Β  └── packagesite.txz -> .latest/packagesite.txz
└── 13-2-R-amd64-default
    β”œβ”€β”€ All -> .latest/All
    β”œβ”€β”€ Latest -> .latest/Latest
    β”œβ”€β”€ meta.conf -> .latest/meta.conf
    β”œβ”€β”€ meta.pkg -> .latest/meta.pkg
    β”œβ”€β”€ meta.txz -> .latest/meta.txz
    β”œβ”€β”€ packagesite.pkg -> .latest/packagesite.pkg
    └── packagesite.txz -> .latest/packagesite.txz

10 directories, 15 files

Our Repository Client Setup

Now we need to configure our FreeBSD clients to start using our Poudriere created repositories.

Here is what we need to do on such client.

# mkdir -p /usr/local/etc/pkg/repos

# cat << EOF > /usr/local/etc/pkg/repos/13-2-R-amd64.conf
13-2-R-amd64: {
    url: "http:/10.0.10.123/packages/13-2-R-amd64-default/",
    mirror_type: "http",
    signature_type: "pubkey",
    pubkey: "/usr/local/etc/ssl/certs/poudriere.cert",
    enabled: yes,
    priority: 100
}
EOF

# pkg update -f
Updating FreeBSD repository catalogue...
Fetching meta.conf: 100%    163 B   0.2kB/s    00:01
Fetching packagesite.pkg: 100%    7 MiB 626.5kB/s    00:11
Processing entries: 100%
FreeBSD repository update completed. 32980 packages processed.
Updating 13-2-R-amd64-HEAD repository catalogue...
Fetching meta.conf: 100%    163 B   0.2kB/s    00:01
Fetching packagesite.pkg: 100%    6 KiB   5.7kB/s    00:01
Processing entries: 100%
13-2-R-amd64-HEAD repository update completed. 14 packages processed.
All repositories are up to date.

We now have our first FreeBSD client system configured against our Poudriere created repository.

Lets install/update the m4 package for a test.

# pkg install m4
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
Updating 13-2-R-amd64-HEAD repository catalogue...
13-2-R-amd64-HEAD repository is up to date.
All repositories are up to date.
The following 2 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        m4: 1.4.19,1 [13-2-R-amd64-HEAD]

Installed packages to be REINSTALLED:
        pkg-1.19.1_1 [13-2-R-amd64-HEAD] (options changed)

Number of packages to be installed: 1
Number of packages to be reinstalled: 1

The process will require 2 MiB more space.
9 MiB to be downloaded.

Proceed with this action? [y/N]: y
[1/2] Fetching pkg-1.19.1_1.pkg: 100%    8 MiB   8.7MB/s    00:01
[2/2] Fetching m4-1.4.19,1.pkg: 100%  214 KiB 218.7kB/s    00:01
Checking integrity... done (0 conflicting)
[1/2] Reinstalling pkg-1.19.1_1...
[1/2] Extracting pkg-1.19.1_1: 100%
[2/2] Installing m4-1.4.19,1...
[2/2] Extracting m4-1.4.19,1: 100%

Now some FreeBSD client notes … if you are a Linux fan you probably know that – for example on Red Hat Linux (and its clones) – its relatively easy to just list the configured repositories with yum repolist command.

# yum repolist
repo id         repo name
appstream       CentOS Linux 8 - AppStream
baseos          CentOS Linux 8 - BaseOS
epel            Extra Packages for Enterprise Linux 8 - x86_64
epel-modular    Extra Packages for Enterprise Linux Modular 8 - x86_64
extras          CentOS Linux 8 - Extras

… unfortunately there is not 1:1 equivalent on FreeBSD side for pkg(8) repositories.

The closest one that is available out of the box are:

# pkg -vv | grep -A 999 '^Repositories:'
Repositories:
  FreeBSD: {
    url             : "pkg+http://pkg.FreeBSD.org/FreeBSD:13:amd64/latest",
    enabled         : yes,
    priority        : 0,
    mirror_type     : "SRV",
    signature_type  : "FINGERPRINTS",
    fingerprints    : "/usr/share/keys/pkg"
  }
  13-2-R-amd64: {
    url             : "http://10.0.10.123/packages/13-2-R-amd64-default/",
    enabled         : yes,
    priority        : 100,
    mirror_type     : "HTTP",
    signature_type  : "PUBKEY",
    pubkey          : "/usr/local/etc/ssl/certs/poudriere.cert"
  }

# grep -h '^[^#]' /etc/pkg/* /usr/local/etc/pkg/repos/*
FreeBSD: {
  url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest",
  mirror_type: "srv",
  signature_type: "fingerprints",
  fingerprints: "/usr/share/keys/pkg",
  enabled: yes
}
13-2-R-amd64: {
    url: "http://10.0.10.123/packages/13-2-R-amd64-default/",
    mirror_type: "http",
    signature_type: "pubkey",
    pubkey: "/usr/local/etc/ssl/certs/poudriere.cert",
    enabled: yes,
    priority: 100
}

Not very pretty.

After asking at GitHub for potential solution or pkg(8)man page overlook I was informed that there is no such option … so I came with my own POSIX /bin/sh shell scripts/functions for the rescue πŸ™‚

For example pkg-repo-var-en.sh that will list all pkg(8) repositories with their enabled/disabled status.

# ./pkg-repo-var-en.sh
REPO          ENABLED  PRIO  URL
FreeBSD       yes      0     pkg+http://pkg.FreeBSD.org/${ABI}/latest
13-2-R-amd64  yes      100   http://10.0.10.123/packages/13-2-R-amd64

# cat pkg-repo-var-en.sh
#! /bin/sh

( # HEADER
  echo -e "\nREPO ENABLED PRIO URL"
  for REPO in /etc/pkg/* /usr/local/etc/pkg/repos/*
  do
    REPOCUR=$( grep '^[^#]' "${REPO}" )

    # REPO
    echo "${REPOCUR}" | awk -F ':' '/\{[\ \t]*$/ {printf(" %s ",$1)}'

    # ENABLED
    echo "${REPOCUR}" | awk '/enabled:/ {printf(" %s ",$NF)}' | tr -cd '[a-zA-Z ]'

    # PRIO
    if echo "${REPOCUR}" | grep -q priority
    then
      echo "${REPOCUR}" | awk '/priority:/ {printf(" %s ",$NF)}' | tr -cd '[0-9 ]'
    else
      echo -n " 0 "
    fi

    # URL
    echo "${REPOCUR}" | grep '^[^#]' | awk -F'"' '/url:/ {print $2}' | tr -d ','

  done 2> /dev/null
) | column -t 2> /dev/null

Next Builds

So … you have successfully build your custom repository once … these are the steps to create new up-to-date package every next time.

// UPDATE JAILS
# poudriere jail -u -j 13-0-R-amd64
# poudriere jail -u -j 13-1-R-amd64
# poudriere jail -u -j 13-2-R-amd64

// UPDATE PORTS
# poudriere ports -u

// BUILD REPOSITORIES
# poudriere bulk -j 13-0-R-amd64 -f /usr/local/etc/poudriere.d/list
# poudriere bulk -j 13-1-R-amd64 -f /usr/local/etc/poudriere.d/list
# poudriere bulk -j 13-2-R-amd64 -f /usr/local/etc/poudriere.d/list

For example – if there are not new packages/changes – this is how the Poudriere output would look like.

poudriere-build-not-needed

Summary

Not sure what should I add here more … I definitely need to compare Poudriere against ports-mgmt/synth alternative one day … but it is not this day – as Aragorn once said πŸ™‚

Pick your packages to customize and have fun.

Take care.

UPDATE 1 – Local pkg(8) Repository from Poudriere Build

After the packages are built with Poudriere harvester there are several ways to distribute these packages to ‘target’ servers.

On of the simplest ways of using/installing these packages is to create local ‘dir/file’ repository.

This is how the directories with packages look like after the desired package set is built with Poudriere.

# tree -L 2 /usr/local/poudriere/data/packages
/usr/local/poudriere/data/packages
β”œβ”€β”€ 14-2-R-amd64-default
β”‚Β Β  β”œβ”€β”€ All -> .latest/All
β”‚Β Β  β”œβ”€β”€ data.pkg -> .latest/data.pkg
β”‚Β Β  β”œβ”€β”€ data.tzst -> .latest/data.tzst
β”‚Β Β  β”œβ”€β”€ Latest -> .latest/Latest
β”‚Β Β  β”œβ”€β”€ logs -> .latest/logs
β”‚Β Β  β”œβ”€β”€ meta -> .latest/meta
β”‚Β Β  β”œβ”€β”€ meta.conf -> .latest/meta.conf
β”‚Β Β  β”œβ”€β”€ packagesite.pkg -> .latest/packagesite.pkg
β”‚Β Β  └── packagesite.tzst -> .latest/packagesite.tzst
β”œβ”€β”€ 14-2-R-amd64-idm
β”‚Β Β  β”œβ”€β”€ All -> .latest/All
β”‚Β Β  β”œβ”€β”€ data.pkg -> .latest/data.pkg
β”‚Β Β  β”œβ”€β”€ data.txz -> .latest/data.txz
β”‚Β Β  β”œβ”€β”€ Latest -> .latest/Latest
β”‚Β Β  β”œβ”€β”€ logs -> .latest/logs
β”‚Β Β  β”œβ”€β”€ meta -> .latest/meta
β”‚Β Β  β”œβ”€β”€ meta.conf -> .latest/meta.conf
β”‚Β Β  β”œβ”€β”€ packagesite.pkg -> .latest/packagesite.pkg
β”‚Β Β  └── packagesite.txz -> .latest/packagesite.txz
β”œβ”€β”€ 14-2-R-amd64-samba
β”‚Β Β  β”œβ”€β”€ All -> .latest/All
β”‚Β Β  β”œβ”€β”€ data.pkg -> .latest/data.pkg
β”‚Β Β  β”œβ”€β”€ data.txz -> .latest/data.txz
β”‚Β Β  β”œβ”€β”€ Latest -> .latest/Latest
β”‚Β Β  β”œβ”€β”€ logs -> .latest/logs
β”‚Β Β  β”œβ”€β”€ meta -> .latest/meta
β”‚Β Β  β”œβ”€β”€ meta.conf -> .latest/meta.conf
β”‚Β Β  β”œβ”€β”€ packagesite.pkg -> .latest/packagesite.pkg
β”‚Β Β  └── packagesite.txz -> .latest/packagesite.txz
└── ansible.PKG.tar
 
13 directories, 19 files

We will now create a local repository under /root/ansible/14-2-R-amd64-default dir for the 14-2-R-amd64-default package set.

# mkdir -p /root/ansible

# cp -ap /usr/local/poudriere/data/packages/14-2-R-amd64-default /root/ansible

# ls /root/ansible
14-2-R-amd64-default
 
# mkdir -p /usr/local/etc/pkg/repos
 
# echo "FreeBSD: { enabled: no }" > /usr/local/etc/pkg/repos/FreeBSD.conf
 
# cat << EOF > /usr/local/etc/pkg/repos/ansible.conf
local: {
  url: "file:///root/ansible/14-2-R-amd64-default",
  enabled: yes
}
EOF
 
# pkg repos
ansible: {
  url             : "file:///root/ansible/14-2-R-amd64-default",
  enabled         : yes,
  priority        : 0
}

Now we can check if pkg(8) sees packages in the new local repository.

# pkg stats
Local package database:
        Installed packages: 1
        Disk space occupied: 47 MiB
  
Remote package database(s):
        Number of repositories: 1
        Packages available: 264
        Unique packages: 264
        Total size of packages: 982 MiB

If needed you can list all available packages with this command.

# pkg search -g '*'

You can now install any needed package(s) on that system with pkg(8) command as usual.

# pkg install ansible vim zsh

Hope that helps.

EOF