FreeBSD Port Build with a Non-Default LDAP Option
A small company runs a FreeBSD 14.1 application server that hosts an internal Python service. The service must be built with a non-default port option that enables a proprietary LDAP plugin, and the binary package from the official repository is compiled without it. The server has 40 GB free on /usr and 8 GB RAM; building in a jail is possible but there is no separate build host. The team wants repeatable installs and a documented way to rebuild after base-system updates. They also want to avoid pulling in a second Python major version because another application depends on Python 3.11. The ports tree is already checked out under /usr/ports. A junior admin suggests simply running pkg install and copying the missing plugin file into place. The senior admin rejects that plan because it would be overwritten on upgrade and is hard to audit.
1. Choose between binary packages and ports for this service, and give the concrete build and install sequence. Include how to capture the chosen option so the build is repeatable.
Read the worked answer
The binary package is unsuitable because it lacks the required LDAP option, and copying a plugin by hand breaks package ownership and will not survive upgrades. Use the ports system on this server, or poudriere if the service will be deployed to several machines.
For a single server:
- Go to the port directory:
cd /usr/ports/<category>/<port>. - Run
make config-recursiveand enable the LDAP option. Answer options for dependencies as well. - Install with
make install clean. - Capture the generated options file under
/var/db/ports/<category>_<port>/optionsin version control, or maintain the same selections in a poudriere make.conf. Do not rely on memory. - Verify the running binary has the feature, for example by checking the application's startup banner or running its feature test, rather than assuming the build succeeded.
For repeatability across servers, poudriere is the better judgment call: it builds packages in clean jails from a defined ports tree and options set, then the servers install normal packages. On one server, direct ports is acceptable but the options file and ports revision must be recorded.
2. The port's dependency graph now tries to install Python 3.12, but another application on the same server requires Python 3.11. What should you do, and what should you avoid?
Read the worked answer
First confirm the dependency chain with pkg info -d <port> and by reading the port Makefile. If the Python default is changing, set the default in /etc/make.conf before rebuilding:
DEFAULT_VERSIONS+=python=3.11 python3=3.11
Then remove stale work directories and rebuild the port and any ports that were linked against a different Python version. Use pkg info -d to find reverse dependencies and rebuild those that need the shared library.
Do not symlink python3 to python3.11 or force-install the Python 3.12 package alongside it. That creates an inconsistent package database and can break the other application at runtime. Also do not copy the plugin into the package-managed tree. If the port genuinely requires Python 3.12, the correct decision is to isolate the two applications, for example in separate jails, rather than forcing incompatible runtimes onto one host.
3. How would you verify the installation and plan later upgrades without losing the custom option?
Read the worked answer
Verification should cover the package database, the feature itself, and the base system. Use pkg check -Ba to find missing libraries, pkg audit -F to check known vulnerabilities, and a functional test that exercises the LDAP plugin. pkg info -D <port> shows package messages and can reveal build-time notes, but the authoritative option record is the saved options file or poudriere configuration.
For upgrades, read /usr/ports/UPDATING before rebuilding, update the ports tree, and rebuild the port with the same options. Base-system updates are separate: use freebsd-update fetch and freebsd-update install, then reboot if the kernel or userland requires it. After either update, rerun the functional test. If poudriere is used, rebuild the package there and install it with pkg upgrade; that keeps the custom option reproducible and avoids compiling on the production server.