How to keep configuration files under version control with Etckeeper

On Linux-based operating system the /etc directory is used to hold global configuration files for applications and services. A good set of configurations is really important for a good working system, so being able to keep track of changes and quickly revert them, in case something go wrong, is crucial. Etckeeper helps us achieve this goal keeping configuration files under version control.

In this tutorial we see how to keep configuration files in the /etc directory under version control using Etckeeper and git.

In this tutorial you will learn:

  • How to install Etckeeper in some of the most used Linux distributions
  • How to configure Etckeeper
  • How to initialize a git repository in /etc with Etckeeper
  • How to use Etckeeper to create commits
  • How to use Etckeeper to run git commands
  • How to enable or disable scheduled commits
  • How to destroy a repository
How to keep configuration files under version control with Etckeeper
How to keep configuration files under version control with Etckeeper
Software requirements and conventions used
Category Requirements, Conventions or Software Version Used
System Distribution independent
Software etckeeper, git
Other Administrative privileges to install software
Conventions # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command $ – requires given linux-commands to be executed as a regular non-privileged user

Installation

The first thing we need to do is to install Etckeeper and one of the version control tools supported by it. Etckeeper supports a variety of version control systems, but for the sake of this tutorial we will use git, which is the default, anyway. Below you can find the commands needed to install Etckeeper and git in some of the most used Linux distributions:

Distribution Installation command
Fedora
 $ sudo dnf install etckeeper git
Debian-based distributions
 $ sudo apt-get update && sudo apt-get install etckeeper git
Archlinux
 $ sudo pacman -Sy etckeeper git

Configuring Etckeeper

Before starting to work with Etckeeper, we need to configure it by editing the /etc/etckeeper/etckeeper.conf configuration file. Your favorite Linux distribution probably already managed to set the appropriate values in the file, but let’s take a quick look at it (I am currently using Fedora; if you use another distribution, default values and details may be different from what showed below).

Configuring the Version Control System

In the first section of the configuration file we get to choose what version control system Etckeeper should use. Here, as you can see, the default is git. To use another one we can simply comment the default and remove the comment from the appropriate choice:

# The VCS to use.
#VCS="hg"
VCS="git"
#VCS="bzr"
#VCS="darcs"



We can specify additional options to be used when commits are created with the VCS of our choice, via the respective variables:

# Options passed to git commit when run by etckeeper.
GIT_COMMIT_OPTIONS=""

# Options passed to hg commit when run by etckeeper.
HG_COMMIT_OPTIONS=""

# Options passed to bzr commit when run by etckeeper.
BZR_COMMIT_OPTIONS=""

# Options passed to darcs record when run by etckeeper.
DARCS_COMMIT_OPTIONS="-a"

Finally, we can configure one or more optional “remotes” to which changes should be pushed to via the PUSH_REMOTE variable:

# To push each commit to a remote, put the name of the remote here.
# (eg, "origin" for git). Space-separated lists of multiple remotes
# also work (eg, "origin gitlab github" for git).
PUSH_REMOTE=""

Setting the low and high level package managers

Linux distributions usually use low and high level package managers: the former are commonly used to perform the actual installation of packages, the latter, rely on the functionalities of the former, and manage higher level features, such as dependencies resolution. In the Etckeeper configuration file we need  to specify the low and high level packages managers in use. Etckeeper needs to know those information because it automatically commits changes to the repository when a package is installed or upgraded, and configuration files are modified or created as a consequence. Again, the correct values are probably already set by your distribution of choice, but here are the values you want to use on the distributions we mentioned before:

Distribution Low level package manager High level package manager
Fedora rpm dnf
Debian-based distributions dpkg apt
Archlinux pacman pacman

Here is how values are set in Fedora:

# The high-level package manager that's being used.
# (apt, pacman, pacman-g2, yum, dnf, zypper, apk etc)
HIGHLEVEL_PACKAGE_MANAGER=dnf

# The low-level package manager that's being used.
# (dpkg, rpm, pacman, pacmatic, pacman-g2, apk etc)
LOWLEVEL_PACKAGE_MANAGER=rpm

Initializing the repository

Once we are done configuring Etckeeper we can initialize the repository in the /etc directory. We do it by running the following command:

$ sudo etckeeper init

In this case we are using git as a version control system, therefore the command will cause an hidden .git directory to be created under /etc. As usual, in case we want to exclude files from being tracked and committed, we can do it by specifying them inside the .gitignore file, which should be automatically created. In this case the file contains some pre-loaded entries managed by etckeeper:

# begin section managed by etckeeper (do not edit this section by hand)

# new and old versions of conffiles, stored by apt/rpm
*.rpmnew
*.rpmorig
*.rpmsave

# old versions of files
*.old

# mount(8) records system state here, no need to store these
blkid.tab
blkid.tab.old

# some other files in /etc that typically do not need to be tracked
nologin
ld.so.cache
prelink.cache
mtab
mtab.fuselock
.pwd.lock
*.LOCK
network/run
adjtime
udev/hwdb.bin
lvm/cache
lvm/archive
X11/xdm/authdir/authfiles/*
ntp.conf.dhcp
.initctl
webmin/fsdump/*.status
webmin/webmin/oscache
apparmor.d/cache/*
service/*/supervise/*
service/*/log/supervise/*
sv/*/supervise/*
sv/*/log/supervise/*
*.elc
*.pyc
*.pyo
init.d/.depend.*
openvpn/openvpn-status.log
cups/subscriptions.conf
cups/subscriptions.conf.O
fake-hwclock.data
check_mk/logwatch.state

# editor temp files
*~
.*.sw?
.sw?
\#*\#
DEADJOE

# end section managed by etckeeper

As specified  in the file, entries managed by etckeeper should not be modified manually (they are usually updated when upgrading etckeeper version, via the dedicated update-ignore command). We can, however,  add our custom ones outside the related section.

Running vcs commands and creating commits

Each VCS has its own commands. Etckeeper works as a sort of wrapper around them via the vcs subcommand. Suppose, for example, we want to check the files which are staged in our repository. Since we are working with git, we normally would run the git status command. Here, instead, we use:

$ etckeeper vcs status



To create a commit manually, we can use this strategy, or, more conveniently, we can use the etckeeper dedicated sub-command: commit, and pass the commit message as argument. Here is how we perform our first commit:

$ sudo etckeeper commit "first commit"

Now, let’s try to perform some changes inside the /etc directory. Say, for example we want to change the number of seconds the GRUB bootloader waits for the user input before booting the default entry. As we know, we can do it by changing the value of the GRUB_TIMEOUT variable inside the /etc/default/grub file. The default value is 5. Here we set it to 10:

GRUB_TIMEOUT=5

To make the change effective we should invoke the appropriate command to regenerate the Grub configuration, but this is not relevant to our example. To commit the change, we would run:

$ sudo etckeeper commit "Changed grub timeout value"

Now, to list our commits, we would run:

$ sudo etckeeper vcs log

The command returns a list of the commits we made, most recent first:

commit ad3b3f52bd0d7de538f0cae44a6b467b78b6d632 (HEAD -> master)
Author: egdoc <egdoc@users.noreply.github.com>
Date: Thu Oct 27 11:51:50 2022 +0200

Changed grub timeout value

commit bd1169e784acb39f177673364bfe2ce0036d8c4f
Author: egdoc <egdoc@users.noreply.github.com>
Date: Thu Oct 27 11:39:08 2022 +0200

first commit

Since we are using git, to take a look at the differences occurred between the two commits, we can use the diff command, and provide the commits id as arguments:

$ sudo etckeeper vcs diff ad3b3f bd1169

In this case, as expected, the command returns the following result:

diff --git a/default/grub b/default/grub
index 5c695ec..d37c897 100644
--- a/default/grub
+++ b/default/grub
@@ -1,4 +1,4 @@
-GRUB_TIMEOUT=10
+GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true

By the way, you can take a look at our tutorial about comparing files with diff, if you are not familiar with the output of this tool.

Etckeeper is also able to track changes in the metadata of files and to handle empty directories. Those functionalities cannot be achieved directly via the versioning systems, cause they aren’t build with this goal in mind. Etckeeper saves the relevant information using pre-commit hooks and stores them in the /etc/.etckeeper file.

Reverting to a previous commit

One of the advantages of keeping configuration files under control, is the ability to quickly revert to a previous and know-to-work status, should something go wrong or just as a matter of preference. In this case, to revert the change we made, and use the default GRUB_TIMEOUT value, we would run:

$ sudo etckeeper vcs checkout bd1169

Where bd1169 are the first six characters of the commit id. After we perform a checkout, or other operations as a rebase, we need to run etckeeper init again, to make sure the correct permissions are restored.

Scheduled commits

Etckeeper comes with a cron job and a systemd timer which can be used to automatically create commits once per day. The cron job is active by default, and is implemented in the /etc/cron.daily/etckeeper file:

#!/usr/bin/sh
set -e
if [ -e /etc/etckeeper/daily ] && [ -e /etc/etckeeper/etckeeper.conf ]; then
	. /etc/etckeeper/etckeeper.conf
	if [ "$AVOID_DAILY_AUTOCOMMITS" != "1" ]; then
		/etc/etckeeper/daily
	fi
fi



As you can see from the content of the file, the actual action is perfomed if the “AVOID_DAILY_AUTOCOMMITS” variable is not set to 1, therefore if we want to disable the cronjob, all we have to do is to remove the comment from the appropriate line in the /etc/etckeeper/etckeeper.conf file, and set the desired value. The systemd.timer unit, instead, is disabled by default, and can be enabled by using the following command:

$ sudo systemctl enable etckeeper.timer

The timer is associated with the etckeeper.service unit (/usr/lib/systemd/system/etckeeper.service), which executes the same file used for the daily cronjob we saw above. By the way, take a look at our tutorial on systemd timers, if you want to know how they work in detail.

De-initing a repository

If for some reason we decide that we don’t want to use Etckeeper anymore (perhaps we want to start anew), and we want to remove the repository created in the /etc/ directory, we can use the following command:

$ sudo etckeeper deinit 

When the “deinit” subcommand is invoked, we are prompted to confirm the action, which will remove the files relative to the repository and the metadata tracked by etckeeper:

** Warning: This will DESTROY all recorded history for /etc,
** including the git repository.

Are you sure you want to do this? [yN]

If we want to avoid the interactive prompt, we can just add the -f option to the command.

Conclusions

In this tutorial we learned how to install and use the Etckeeper tool on some of the most used Linux distributions. Etckeeper relies on the supported Version Control Systems to turn the /etc directory into a repository, in order to keep track of the changes which occur to files and directories contained in it, making us able to easily revert to specific commits should something behave unexpectedly. If you wish to know more about Etckeeper, please take a look at the manual, or the online documentation.



Comments and Discussions
Linux Forum