etckeeper

Related articles
Git
Cron
Etckeeper
is a collection of tools to keep track of
/etc/
in a repository (
Git
,
Mercurial
,
Bazaar
or
Darcs
are supported). A
pacman hook
auto-commits changes before a system-upgrade and file permissions are tracked, which version control does not normally support, but is important for files like
/etc/shadow
.
Installation
Install
the
etckeeper
package.
Configuration
The preferred version control system (default is
git
) and other options are to be configured in
/etc/etckeeper/etckeeper.conf
.
Etckeeper supports using
pacman
as a
LOWLEVEL_PACKAGE_MANAGER
and
HIGHLEVEL_PACKAGE_MANAGER
in
etckeeper.conf
.
Usage
After configuration the repository for the
/etc
path has to be initialized:
# etckeeper init
And perform a first commit to keep track of the changes, this is a necessary step for etckeeper to be able to work automatically:
# etckeeper commit "first commit"
Note
In
/etc/passwd
the root user must have its comment field (5th field) filled with
root
so that the commit doesn't fail
As of
etckeeper
version 1.18.3-1, pre-install and post-install
pacman hooks
are executed automatically on package installation, update and removal. A manual
#Wrapper script
is not required anymore.
To track other changes to the
/etc
path, you need to either commit changes manually (see the
etckeeper(8)
man page for commands) or use one of the stopgap solutions below.
Warning
git checkout/rebase/merge/cherry-pick/... can cause file permissions broken which then lead to e.g. SSH/sudo login denied.
git
can not store file permissions directly so it is handled by
etckeeper
and you need to run the
etckeeper init
again to restore them after a checkout.
Alternatively, you can use
Systemd#systemd-tmpfiles - temporary files
to preserve the permissions.
systemd
Service and timer units are included in the package. Simply
enable
etckeeper.timer
.
See
Systemd/Timers
for more information and
Systemd#Editing provided units
if you wish to edit the provided units.
Cron
There is a
cron script
in the source distribution.
You can use this script to automatically commit changes on a schedule.
For example, to make it run daily:
Have
cron
installed and enabled.
Put script as
/etc/cron.daily/
script_name
.
Make it
executable
for
root
.
See
cron
for more information.
Incron
Note
This section applies only to incron version 5.10.
To automatically create commits on
every
file modification inside
/etc/
, use
incron
. It utilizes native filesystem signalling through
inotify(7)
.
After installing incron and initializing etckeeper, add root to the users allowed to run incron scripts:
# echo root >> /etc/incron.allow
Then edit the incrontab with:
# incrontab -e
Add in the text:
# /etc IN_MODIFY /bin/etckeeper commit "[message]"
Where
[message]
could be something like
"modified $#"
where $# is a special incrontab wildcard expanded to the name of the file modified.
Do note that Incron is not capable of watching subdirectories. Only files within the path will be monitored. If you need subdirectories monitored, you must give them their own entry. However, commits when top-level files are modified will still commit all changes.
See:
[1]
,
incrond(8)
Automatic push to remote repo
Warning
Pushing your etckeeper repository to a publicly accessible remote repository can expose sensitive data such as password hashes or private keys. Proceed with caution.
Whilst having a local backup in
/etc/.git
is a good first step, etckeeper can automatically push your changes on each commit to a remote repository such as Github.
First, add your remote Github repository:
# etckeeper vcs remote add backup
https://github.com/user/repo.git
Next, one of two hooks must be used or configured to push:
Using etckeeper provided hook
Edit the
PUSH_REMOTE
option in
/etc/etckeeper/etckeeper.conf
, with the name of
the remote repository you want etckeeper to push to. For example:
PUSH_REMOTE="
backup
"
Multiple remote repositories can be added separated with spaces.
Through a custom hook
Create an executable file
/etc/etckeeper/commit.d/40github-push
:
#!/bin/sh
set -e

if [ "$VCS" = git ] && [ -d .git ]; then
  cd /etc/
  git push backup master
fi
Wrapper script
If you want to track changes of a frequently executed command (e.g.
command
), a simple wrapper script can help to automate it. For example, create:
/usr/local/bin/checketc.sh
#!/bin/bash

etckeeper pre-install
command
etckeeper post-install
and make it executable. Alternatively, you may call the Etckeeper commands via a bash alias or function, see
Bash#Aliases
for more information.
Note
Before Etckeeper version 1.18.3-1 such manual wrapper script was required for Pacman integration. Now the Pacman hooks perform the commands automatically.
Reflector
To automatically commit the change after each
Reflector
invocation, make the
reflector.service
depend on a systemd service.
/usr/libexec/etckeeper/reflector
#!/bin/sh
set -e
if ! etckeeper vcs diff --quiet pacman.d/mirrorlist; then
  # cons:
  # - assumes git
  # - doesn't benefit from etckeeper's user.name/user.email logic
  export GIT_AUTHOR_NAME="$USER"
  export GIT_AUTHOR_EMAIL="$USER@$HOSTNAME"
  export GIT_COMMITTER_EMAIL="$USER@$HOSTNAME"
  etckeeper vcs commit -m "reflector" -- pacman.d/mirrorlist >/dev/null

  # cons: might commit too much
  # etckeeper commit "reflector" >/dev/null
fi
/etc/systemd/system/etckeeper-reflector.service
[Unit]
Description=Autocommit /etc/pacman.d/mirrorlist
Documentation=
https://wiki.archlinux.org/title/Etckeeper#Reflector
DefaultDependencies=no
Conflicts=shutdown.target

[Service]
Type=oneshot
ExecStart=/usr/libexec/etckeeper/reflector
IOSchedulingClass=idle
and this
drop-in file
:
/etc/systemd/system/reflector.service.d/etckeeper.conf
[Unit]
Before=etckeeper-reflector.service
Wants=etckeeper-reflector.service
Make
/usr/libexec/etckeeper/reflector
executable
and do a
daemon-reload
.
Now, whenever
reflector.timer
triggers the changes will immediately be saved, without interfering with unrelated configuration changes.
Testing
Restart
reflector.service
, then examine:
# etckeeper vcs diff
# etckeeper vcs show HEAD
etckeeper
should show you that
reflector
has updated your mirrorlist -- it will have at least bumped the timestamp.