FreeBSD etcupdate Operations: Merge System Configuration Across Upgrades
Use etcupdate's reference trees, three-way merges, conflict status, and rollback to reconcile FreeBSD system files without overwriting local policy.
Updating the FreeBSD base system changes more than binaries. Files such as those under /etc can gain new defaults, obsolete settings, or changed syntax while a host carries local edits. etcupdate(8) manages this boundary by keeping reference trees and attempting three-way merges between the previous base configuration, the new base configuration, and the machine’s local files. It is a reconciliation tool, not an automatic approval system: a conflict still requires an administrator to decide which behavior is correct.
The key is to establish a trustworthy baseline before the update cycle begins. If the reference tree does not correspond to the currently installed world, a future merge can misclassify vendor changes. Keep the base-system update method and the configuration merge procedure coordinated, and do not apply a new merge while an earlier conflict set is unresolved.
Inventory state before the upgrade
Check whether etcupdate has reference data and whether an earlier merge has unresolved conflicts:
etcupdate status
etcupdate diff
ls -ld /var/db/etcupdate /var/db/etcupdate/current /var/db/etcupdate/previous
The default work directory is /var/db/etcupdate, but the installed manual and any local flags determine the actual path. Treat status and diff as read-only review steps. Save output with the source revision, installed world version, host identifier, and change record. Do not include secret-bearing files verbatim in a general ticket.
If the reference tree has not been initialized, bootstrap it from source that matches the currently installed world. The simplest documented sequence is:
etcupdate extract
etcupdate diff
extract creates the reference from the source tree; it is not an instruction to point at arbitrary newer source. If /usr/src has already advanced, obtain or check out a source tree matching the running world before bootstrapping. The manual describes using -s to select a source tree and -B where appropriate; verify the exact options and workflow in the target release’s manual before adapting a command.
Review the initial diff as a baseline. Existing local modifications that are intentional should be recorded and retained. If a difference is obsolete or accidental, resolve it deliberately before the update rather than asking a later merge to infer policy from an unknown history.
Run one merge after the base update stage
Follow the release-specific update procedure for the host’s installation model. etcupdate manages configuration files not updated as part of make installworld; it does not replace fetching or installing the base system, package updates, boot-environment creation, or boot loader maintenance. A packaged-base installation can have a different overall update sequence, so follow that release’s current Handbook and do not assume that source-based installworld steps apply.
For a source-based update cycle, a typical order is to establish a matching prior reference, update source and base binaries using the documented procedure, then run etcupdate against the new source tree:
# Run from the intended FreeBSD source tree, after reviewing its revision.
etcupdate
etcupdate status
etcupdate diff
This is an outline, not a substitute for the complete source upgrade procedure. Preserve the source revision and build configuration used for the new world. If the merge reports conflicts, do not rerun it as a way to erase or “refresh” the conflict markers. The manual states that unresolved conflicts block a new merge; identify and resolve the current set first.
Use a maintenance window for hosts where an incorrect resolver, SSH, firewall, or service configuration could cut off access. Keep a console or alternate administrative path available, and save a complete external backup of critical local configuration before changing the reference or destination files.
Resolve conflicts as policy decisions
When a conflict is present, inspect three versions: the prior base file, the new base file, and the local destination. Determine whether a change is upstream behavior, local policy, or an accidental edit. A conflict marker is not safe to leave in a shell-sourced configuration file, and choosing “ours” or “theirs” globally can silently remove important settings.
Use the supported status and resolution workflows, then inspect the result with a diff:
etcupdate status
etcupdate resolve
etcupdate diff
The default resolver is interactive. Resolve each affected path with the actual service owner or configuration-management owner. Validate syntax with the file’s native checker when available, and compare the merged file against the host’s intended policy. Files with locally customized certificates, resolver configuration, authentication modules, or firewall rules require special care and may need a separate native update process.
If the merge incorporated an incorrect file, etcupdate revert can restore a selected file to the appropriate reference version. Confirm the exact semantics in the installed manual before invoking it; a revert is a state change, not a generic undo of all local edits. Preserve a copy and review the resulting diff before accepting it.
Do not hand-edit the internal reference trees under /var/db/etcupdate to silence a conflict. Those trees are the tool’s merge state. Correct the destination file through the documented resolution path, repair the source selection if the baseline is wrong, and keep an auditable record of the decision.
Validate the merged system, not only the diff
A clean merge can still produce a configuration that is syntactically valid but operationally wrong. After resolving files, validate each subsystem:
etcupdate status
etcupdate diff
service -e
sysrc sshd_enable hostname
The last two commands are examples of separate checks. Substitute the specific services and variables managed by the changed files. service -e reports enabled rc scripts; it does not check application health. Use service-specific config validation, review logs, inspect listening sockets, and perform client-side checks from the right network segment.
If /etc contains configuration managed by Ansible, Salt, Puppet, or another source-of-truth system, coordinate ownership before accepting an etcupdate change. A vendor default merge and a configuration-management rollout can overwrite each other. Record which system is authoritative for each file and encode intended local policy in that system after resolving the upgrade conflict.
Configuration merging does not update every file on the host. The tool’s stated scope is files not updated by installworld but maintained in the source tree; the manual specifically gives /etc/fstab and /etc/rc.conf as files it does not manage. Other update mechanisms may own files elsewhere. It also does not prove that a changed file will be read by a running daemon. Restart or reload only the affected service when the service documentation requires it, and verify the new process or behavior.
Rollback and repeatability
Before each merge, retain an external copy of files whose loss would cause an outage, along with etcupdate status and the source revision. The utility stores prior and current reference trees, but those are not a substitute for a host backup. If the merge is wrong, restore the specific destination files from the reviewed copy or use the documented per-file revert command, then validate the service state.
Do not delete /var/db/etcupdate to “reset” the tool during an upgrade. Removing reference state destroys the history needed for the next three-way comparison and can make the next run behave like an unreviewed bootstrap. Rebuild or bootstrap state only when the installed world’s matching source has been established and the manual’s recovery workflow is followed.
For a fleet, roll out to a canary first. Compare conflict counts and filenames between hosts; identical package sets can still have different local changes. Automate inventory and alerts, but require human review for configuration conflicts that can alter access, name service, storage mounts, or security policy. Keep the exact command, work directory, source tree, results, file approvals, service checks, and rollback evidence in the change record.
Acceptance means the reference trees match the intended base transition, etcupdate status shows no unresolved conflicts, etcupdate diff contains only reviewed policy changes, every affected file passes its native validation, and the actual services respond correctly after the required reload or reboot. That is stronger evidence than a successful merge command.
Related:
- How to Safely Upgrade FreeBSD Between Major Versions
- FreeBSD pkgbase: Managing the Operating System as Signed Packages
Sources: