Declare Debian package configuration files without upgrade surprises
You will build a Debian package whose control archive contains a valid DEBIAN/conffiles file, inspect the result, and decide when the remove-on-upgrade flag is appropriate. 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.
The route
Jump straight to the step you need, or tick off Done means at the end.
This is a packaging operation, not a command for editing /etc on an installed system. Build in a temporary directory or package workspace. The commands below do not need sudo; use elevated privileges only 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 control archive. It is read while creating and processing a package; it is not a file that belongs 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 are keeping the package source:
$ mkdir -p /tmp/example-conffile/pkg/DEBIAN
$ mkdir -p /tmp/example-conffile/pkg/etc/example
The control file needs normal package metadata. This example keeps it 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 that you will declare. A normal, unflagged conffile must exist in the binary package, or dpkg will ignore the declaration:
$ 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 may have an optional leading flag separated from the path by whitespace; do not use shell quoting or a package-relative path:
$ editor /tmp/example-conffile/pkg/DEBIAN/conffiles
/etc/example/app.conf
Trailing whitespace is trimmed, but an empty line or a line containing only whitespace is not accepted. Keep the file boring: one declaration per line, with no comments unless your package tooling explicitly supports them. A comment is not documented conffiles syntax.
Checkpoint
Inspect the file before building:
$ sed -n 'l' /tmp/example-conffile/pkg/DEBIAN/conffiles
/etc/example/app.conf$
The final $ shown by sed is its 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
...
The sizes and the displayed metadata vary. The useful checkpoint is the conffiles entry and the package name and version. Read the stored file itself if you need to verify the exact bytes:
$ dpkg-deb --ctrl-tarfile /tmp/example-conffile/example-conffile.deb \
| tar -xOf - ./conffiles
/etc/example/app.conf
Also check that the data archive contains 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 documented by the installed manual when a file should be removed on the next upgrade:
remove-on-upgrade /etc/example/old-app.conf
That entry is different from an ordinary conffile. The old file must not be present in the new binary package. Do not leave a placeholder at pkg/etc/example/old-app.conf; dpkg and dpkg-deb reject a package that both marks the path for removal and ships it.
This is a destructive package behaviour. Before publishing such an upgrade, check that the path is genuinely obsolete and record where any replacement configuration lives. Do not use this flag merely to force a user's edited configuration back to a vendor default. Build the package, then inspect 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 or prove that an upgrade will be safe; test the package in a disposable system before a production rollout.
6. Avoid the common failure modes
- A relative path such as
etc/example/app.confis invalid. Use/etc/example/app.conf. - An ordinary declaration without a matching data file may be ignored by dpkg. Check both control metadata and archive contents.
- An empty or whitespace-only line is not accepted. Remove blank declarations rather than relying on trimming.
- Do not assume the flag is a general-purpose deletion mechanism. The documented flag is specifically
remove-on-upgrade, and it applies on the next upgrade. - Do not install a package just to inspect it.
dpkg-deb --info,--contentsand--ctrl-tarfileare read-only archive checks.
If you created a test package under /tmp, remove that workspace only after saving anything you need. If you have not installed the package, there is no package-state change to undo. If you did install it separately, use your normal package rollback plan; deleting the build directory does not uninstall it.
Done means
DEBIAN/conffilescontains valid absolute paths, one per line.- Every ordinary declaration matches a file in the binary package.
- A
remove-on-upgradepath is absent from the binary package and has been reviewed as a deliberate removal. dpkg-deb --info,--contentsand the control-archive check show the intended package.- The package has been tested before any elevated installation or production upgrade.