Home / Alt manpages / deb-conffiles(5)

  • deb-conffiles(5)
  • File format
  • linux

Manage Debian conffiles Without Upgrade Surprises

List a file in DEBIAN/conffiles that is not actually in the package, and dpkg will quietly ignore the whole declaration rather than warn you. This guide builds a package whose control archive contains a valid DEBIAN/conffiles file, checks the result, and covers when the remove-on-upgrade flag is the right call. Allow about fifteen minutes if you already have a package skeleton. The examples use dpkg 1.22.6 and dpkg-dev 1.22.6 on this machine.

This is a packaging exercise, not a way to edit /etc on an installed system. Build in a temporary directory or package workspace. None of the commands below need sudo; save elevated privileges for a later, deliberate installation step.

1. Check the installed packaging tools

Confirm the version and the command you will use to inspect the archive:

$ dpkg-query -W -f='${Package} ${Version}\n' dpkg-dev dpkg
dpkg 1.22.6ubuntu6.6
dpkg-dev 1.22.6ubuntu6.6
$ command -v dpkg-deb
/usr/bin/dpkg-deb

The installed manual describes DEBIAN/conffiles as a list stored in the package's control archive. It gets read while creating and processing a package; it is not a file that lives under the package's ordinary data directory.

2. Create the package layout

Start with a minimal package tree. Replace /tmp/example-conffile with a private workspace if you plan on keeping the source:

$ mkdir -p /tmp/example-conffile/pkg/DEBIAN
$ mkdir -p /tmp/example-conffile/pkg/etc/example

The control file needs the normal package metadata. Keep this one deliberately small:

$ editor /tmp/example-conffile/pkg/DEBIAN/control
Package: example-conffile
Version: 1.0
Architecture: all
Maintainer: Example <[email protected]>
Description: example package with a configuration file

Create the configuration file at the same absolute path you are about to declare. This is the trap from the opening line: a normal, unflagged conffile has to exist in the binary package, or dpkg silently ignores the declaration instead of erroring out:

$ editor /tmp/example-conffile/pkg/etc/example/app.conf
mode=standard

3. Write one absolute path per line

Put the declaration in pkg/DEBIAN/conffiles. Paths must be absolute. Each line can carry an optional leading flag separated from the path by whitespace; do not use shell quoting or a package-relative path here:

$ editor /tmp/example-conffile/pkg/DEBIAN/conffiles
/etc/example/app.conf

Trailing whitespace gets trimmed, but an empty line or a line of only whitespace is not accepted. Keep the file boring: one declaration per line, no comments unless your packaging tooling explicitly supports them. A comment is not documented conffiles syntax, whatever your editor's highlighting suggests.

Checkpoint

Inspect the file before building:

$ sed -n 'l' /tmp/example-conffile/pkg/DEBIAN/conffiles
/etc/example/app.conf$

The trailing $ shown by sed is its own line marker, not part of the file.

4. Build and inspect the archive

Build the package as an ordinary user:

$ dpkg-deb --build /tmp/example-conffile/pkg /tmp/example-conffile/example-conffile.deb
dpkg-deb: building package 'example-conffile' in '/tmp/example-conffile/example-conffile.deb'.

Inspect the control metadata without installing anything:

$ dpkg-deb --info /tmp/example-conffile/example-conffile.deb
 new Debian package, version 2.0.
 size ... bytes: control archive=... bytes.
      22 bytes,     1 lines      conffiles
 Package: example-conffile
 Version: 1.0
 Architecture: all
 ...

Sizes and displayed metadata vary. The checkpoint that matters is the conffiles entry along with the package name and version. Read the stored file directly if you need to check the exact bytes:

$ dpkg-deb --ctrl-tarfile /tmp/example-conffile/example-conffile.deb \
    | tar -xOf - ./conffiles
/etc/example/app.conf

Also confirm the data archive actually ships the declared file:

$ dpkg-deb --contents /tmp/example-conffile/example-conffile.deb
drwxr-xr-x ... ./etc/
drwxr-xr-x ... ./etc/example/
-rw-r--r-- ... ./etc/example/app.conf

5. Mark a retired conffile for removal

Use the only flag the installed manual documents for a file that should go on the next upgrade:

remove-on-upgrade /etc/example/old-app.conf

That entry behaves differently from an ordinary conffile: the old file must be absent from the new binary package. Do not leave a placeholder at pkg/etc/example/old-app.conf, since dpkg and dpkg-deb reject a package that both marks a path for removal and ships it anyway.

Destructive action

This flag deletes a file from every system that installs the upgrade. Before publishing it, confirm the path is genuinely obsolete and note down where any replacement configuration now lives. Do not use it just to force a user's edited config back to a vendor default. Build the package, then check both the control entry and the data listing again:

$ dpkg-deb --info /tmp/example-conffile/example-conffile.deb | sed -n '/conffiles/,+2p'
      ... bytes,     1 lines      conffiles
$ dpkg-deb --contents /tmp/example-conffile/example-conffile.deb \
    | grep -F '/etc/example/old-app.conf'
$ printf 'grep status: %s\n' "$?"
grep status: 1

A status of 1 from that final grep means the retired path was not shipped. It does not install the package, and it does not prove an upgrade will go smoothly: test the package on a disposable system before it reaches production.

Common traps

  • A relative path such as etc/example/app.conf is invalid. Use /etc/example/app.conf.
  • An ordinary declaration with no matching data file may be silently ignored by dpkg. Check both control metadata and archive contents.
  • An empty or whitespace-only line is not accepted. Remove blank declarations instead of trusting the trim.
  • The flag is not a general deletion mechanism. The only documented one is remove-on-upgrade, and it fires on the next upgrade only.
  • Do not install a package just to inspect it. dpkg-deb --info, --contents and --ctrl-tarfile are read-only archive checks.

If you built a test package under /tmp, remove that workspace once you have saved anything you need. If you never installed the package, there is no package-state change to undo. If you did install it separately, follow your normal package rollback plan: deleting the build directory will not uninstall it for you.

Done means

  • DEBIAN/conffiles contains valid absolute paths, one per line.
  • Every ordinary declaration matches a file that is actually in the binary package.
  • Any remove-on-upgrade path is absent from the binary package and reviewed as a deliberate removal.
  • dpkg-deb --info, --contents and the control-archive check show the package you intended.
  • The package has been tested before any elevated installation or production upgrade.