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

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.