Site-wide Configuration Management for Debian GNU/Linux
- Readying the APT Repo server
- Key Generation
- Nginx Configuration
- Add to Repository
- Installation on Client Machines
I may be a FreeBSD fangirl, but my company is a Debian GNU/Linux shop. This tutorial looks at how I create site configurations with config-package-dev, package them, and make them available on the network.
- Exists within APT, so no tools are required on a target machine besides those shipped with the operating system.
- Configuration packages make it easy to distribute a configuration across a site.
- Separation of machine and configuration. Configurations can be installed over a machine of any state, and the machine returns to its previous state upon uninstallation thanks to dpkg-divert.
- Simple codename separation for maintaining compatible but discrete packages across releases, also enabling seamless release upgrades that would otherwise fail due to incompatible configuration, e.g. apache2 during the upgrade from Debian 5 to 6.
- Free (monetarily)
- Free (philosophically)
- Config-package-dev can build configuration packages that transform the in-place configuration files, leaving the configuration package agnostic to config file changes from upstream.
Readying the APT Repo server
Create a local user
repo who will run reprepro and under whose home directory we will host the repository, then create the directory skeleton for the repository itself.
APT repositories can be signed with a GnuPG private key. To generate one, install
gnupg along with the
Start rngd, seeding it with
/dev/urandom. Without rngd, GnuPG may take a very very long time to gather enough entropy for safe key generation, as I experienced on a VMware ESXi virtual machine.
To create the key, run
gpg --gen-key as
repo and follow the prompts. Be sure to place a passphrase on your new key when prompted, or anybody who gets ahold of the private key can sign with it.
Take a peek at
gpg --list-secret-keys and make sure your key matches expectation.
Lastly, export the public component of the key to the document root of the repository so clients can access it.
Reprepro’s configuration lives within the root of the repository, under the HTTP document root. In this setup, it’s
This file defines the distributions for which we host repositories. It may contain multiple distribution definition blocks, separated from each other by one blank line. Each codename release of Debian (Lenny, Squeeze, Wheezy, et cetera) is a separate distribution in this context.
This working example is a repository hosting the
extra components for Debian 6.0 “Squeeze” on the i386 and amd64 architectures and signed by a GnuPG key with id
013CFE9D, as seen in the previous section.
This file defines configuration for reprepro itself. Most of these are personal preference. They correspond to command line arguments to reprepro.
Define a new virtual host to expose our repository on the network, making sure to deny access to the configuration and database subdirectories. I host with SSL, listening on port 80 only to issue redirects to the SSL host on port 443.
Enable it by symlinking your virtual host configuration file under
sites-enabled, and reload nginx.
Packaging is a complex topic, and newcomers would do well to read the Introduction to Debian Packaging.
You should have the package you’re configuring installed on your repository build machine, or file diversion might fail during package construction.
Install a few necessary build dependencies.
Example Package: Configuration Transformation
This is a working example of a configuration transformation package that, when installed, will disable root logins in OpenSSH, force SSH 2 protocol, disable host-based authentication, and disallow empty passwords.
Create the directory structure for the package.
control file names, declares dependencies for, and includes a description for our package.
rules is a Makefile where we configure config-package-dev for this package, telling it what on-filesystem files we wish to transform.
transform_sshd_config.dashie is named for the file it’s transforming,
/etc/ssh/sshd_config.dashie, diverted to
/etc/ssh/sshd_config by our package. My transform files are usually written in perl, but that’s not a requirement.
postinst is a shell script called with the argument
configure after package installation. In this example, it restarts the OpenSSH server to pick up its new configuration.
changelog keeps a history of the package. It can be edited by hand or updated by a tool such as
compat is a very simple file, containing only the number of the debhelper version needed by your package. This package, for example, declares a need for debhelper (>= 6.0.0), the version shipped with Debian Lenny.
copyright file is simply the license you prefer for the package.
Example Package: Configuration Replacement
This is a working example of a configuration replacement package that, when installed, will install a systemwide
zshrc, a custom ZSH prompt, and a blank
.zshrc in the skeleton home directory. The blank
.zshrc prevents ZSH from prompting users for first-run configuration, instead preferring our system-wide config.
Specify a dependency on ZSH in
control, so the systemwide
zshrc will exist for us to replace.
<name-of-package>.install is a list of source and destination for files you want
dh_install to install. This simple one-line example says every file in and under the packages’
files directory should be installed to the root of the filesystem.
In this packages
rules, list the files the package will replace. In this case, the package installs
/etc/zsh/zshrc.dashie and diverts it to
This package has a
files directory containing the installed files in their proper tree. The simple
dh_install file above will copy this entire directory tree over the root of the filesystem.
The other required files,
license, are no different from the previous example.
debuild -us -uc in the package’s top-level directory. The
-uc arguments tell
dpkg-buildpackage not to cryptographically sign the source or the
.changes file, just the package. If all goes well, you’ll find a
If the build is unsuccessful, example the verbose output for the cause.
Updating Existing Packages
When making changes to a package you’ve already built and distributed, comment your change with
-i to increment the package version number, then
debuild as usual.
dch will automatically try to guess your name and email address, but you can specify them with the
DEBEMAIL environment variables.
Add to Repository
Use reprepro to add the newly-built
.deb to the repository. Specify the package’s component (
main for packaged software,
extra for configuration packages) and the codename distribution to target.
When prompted, enter your GnuPG key’s passphrase.
gpg-agent can help mitigate annoying successive password prompts.
Installation on Client Machines
With all that mess taken care of, configuring a client machine is as easy as adding your new repository to the APT sources list.
Enabling HTTPS transport for apt.
Adding the repo’s public key to the APT keyring.
Your packages should now be available for installation through APT.
Set a few environment variables in the new user’s
.profile, depending on your shell of choice.
DEBFULLNAME will automatically apply to
dch changelogs generated as this user. Aliasing reprepro to reprepro with a basedir argument lets us easily run the command from any directory.
You can permanently specify
debuild arguments in your user’s
.devscripts to save including them manually every time.
Keychain is a handy piece of software to keep gpg-agent alive. Install it with
apt-get install keychain and add an entry with your key ID to your