<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Etckeeper on Matty Spangler</title>
    <link>https://mattyspangler.codeberg.page/tags/etckeeper/</link>
    <description>Recent content in Etckeeper on Matty Spangler</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 08 Mar 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://mattyspangler.codeberg.page/tags/etckeeper/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Etckeeper on Kicksecure</title>
      <link>https://mattyspangler.codeberg.page/posts/kicksecure-etckeeper/</link>
      <pubDate>Sun, 08 Mar 2026 00:00:00 +0000</pubDate>
      
      <guid>https://mattyspangler.codeberg.page/posts/kicksecure-etckeeper/</guid>
      <description>&lt;p&gt;This article is part of my &lt;a href=&#34;../kicksecure-self-hosting/&#34;&gt;Self-Hosting with Kicksecure&lt;/a&gt; series.&lt;/p&gt;
&lt;h2 id=&#34;1-introduction&#34;&gt;1. Introduction&lt;/h2&gt;
&lt;p&gt;Before making any system changes, I want to decide on a way to record every change I make so that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I can easily reproduce my work if I ever have to reinstall or migrate to another machine&lt;/li&gt;
&lt;li&gt;I can easily identify problematic configs and revert them&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t forget the reasoning behind a particular security decision or config change in 6 months&lt;/li&gt;
&lt;li&gt;I can identify what changes I made as opposed to changes made by software or other people&lt;/li&gt;
&lt;li&gt;I can compare the current state of my configs against a &amp;lsquo;known-good&amp;rsquo; config&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;/etc&lt;/code&gt; directory will contain most of my configs. Outside of /etc I will need to pay attention to my dotfiles which I like to manage with GNU Stow.&lt;/p&gt;</description>
      <content>&lt;p&gt;This article is part of my &lt;a href=&#34;../kicksecure-self-hosting/&#34;&gt;Self-Hosting with Kicksecure&lt;/a&gt; series.&lt;/p&gt;
&lt;h2 id=&#34;1-introduction&#34;&gt;1. Introduction&lt;/h2&gt;
&lt;p&gt;Before making any system changes, I want to decide on a way to record every change I make so that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I can easily reproduce my work if I ever have to reinstall or migrate to another machine&lt;/li&gt;
&lt;li&gt;I can easily identify problematic configs and revert them&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t forget the reasoning behind a particular security decision or config change in 6 months&lt;/li&gt;
&lt;li&gt;I can identify what changes I made as opposed to changes made by software or other people&lt;/li&gt;
&lt;li&gt;I can compare the current state of my configs against a &amp;lsquo;known-good&amp;rsquo; config&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;/etc&lt;/code&gt; directory will contain most of my configs. Outside of /etc I will need to pay attention to my dotfiles which I like to manage with GNU Stow.&lt;/p&gt;
&lt;p&gt;Etckeeper is a neat piece of software that turns &lt;code&gt;/etc&lt;/code&gt; into a git repository. It automatically commits changes before and after package installations, and I can manually commit my own changes too.&lt;/p&gt;
&lt;h2 id=&#34;2-installation&#34;&gt;2. Installation&lt;/h2&gt;
&lt;p&gt;Kicksecure protects itself by isolating system maintainence tasks from daily activity. This means administrative tasks like installing new software cannot be performed from the standard user account, even with sudo. You have to reboot and select an option to boot into a session with the sysmaint account, make your changes, and then reboot back into the standard user session to continue with daily usage.&lt;/p&gt;
&lt;p&gt;Having booted with sysmaint, I install Etckeeper from the Debian repositories:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install etckeeper
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;3-etckeeper-basics&#34;&gt;3. Etckeeper Basics&lt;/h2&gt;
&lt;p&gt;Do the standard git stuff:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git config --global user.email &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;person@email.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git config --global user.name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;I&amp;#39;m a person with a name!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;I start by initializing the repository:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;```&lt;/span&gt;bash
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /etc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;etckeeper init
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And making my initial commit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;etckeeper commit &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Initial configuration snapshot&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Etckeeper hooks into apt. When I install or remove packages, it automatically commits them to the git repo. So I don&amp;rsquo;t need to worry about doing a commit myself! I only need to commit after I make manual changes in /etc.&lt;/p&gt;
&lt;p&gt;For configuration changes I make outside of apt:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# within /etc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git add .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;etckeeper commit &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Descriptive message about what changed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;4-viewing-history&#34;&gt;4. Viewing History&lt;/h2&gt;
&lt;p&gt;Standard git commands work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /etc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git log --oneline
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;View a specific change:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git show COMMIT_HASH
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compare two states:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git diff COMMIT_HASH1 COMMIT_HASH2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;5-the-gitignore-file&#34;&gt;5. The .gitignore File&lt;/h2&gt;
&lt;p&gt;Some files in &lt;code&gt;/etc&lt;/code&gt; shouldn&amp;rsquo;t be tracked: temporary files, secrets, or auto-generated content.&lt;/p&gt;
&lt;p&gt;On my server I ended up configuring a ZFS RAID. Here&amp;rsquo;s an example of excluding tracking of my ZFS cache with a few other things in &lt;code&gt;/etc/.gitignore&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# Ignore auto-generated ZFS cache
/zfs/zfs-list.cache/

# Example: ignore temporary files
*.tmp
*.swp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After editing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git add .gitignore
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;etckeeper commit &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Updated gitignore to exclude my auto-generated ZFS cache&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;6-backups&#34;&gt;6. Backups&lt;/h2&gt;
&lt;p&gt;Always back up your changes so you have access to these records if your system breaks! In my case, I back up to a local &amp;lsquo;bare repository&amp;rsquo; on my BTRFS backup drive. I explain how I set up this drive on Kicksecure in a &lt;a href=&#34;../kicksecure-btrfs-storage/&#34;&gt;later post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, because I&amp;rsquo;d like to be able to identify known-good states of my configs even if an attacker compromises my server or network, I sanatize + compress + back up my data (or just the hashes for big files) to an air-gapped system regularly using something similar to a &lt;a href=&#34;https://en.wikipedia.org/wiki/Unidirectional_network&#34;&gt;data diode&lt;/a&gt;. The air gap setup is beyond the scope of this post, but I thought the suggestion might interest readers!&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how I back up my /etc repo:&lt;/p&gt;
&lt;h3 id=&#34;61-create-a-bare-repository&#34;&gt;6.1. Create a Bare Repository&lt;/h3&gt;
&lt;p&gt;On my already mounted BTRFS storage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /mnt/storage_name/host_vault/kicksecure-etckeeper.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git init --bare /mnt/storage_name/host_vault/kicksecure-etckeeper.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;62-add-as-remote&#34;&gt;6.2. Add as Remote&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /etc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git remote add localvault /mnt/storage_name/host_vault/kicksecure-etckeeper.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;63-push-changes&#34;&gt;6.3. Push Changes&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git push -u localvault main
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Future pushes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git push localvault
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;64-push-after-every-commit&#34;&gt;6.4. Push After Every Commit&lt;/h3&gt;
&lt;p&gt;This became a habit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;etckeeper commit &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Made a change&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git push localvault
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;7-what-to-track&#34;&gt;7. What to Track&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what I have tracked so far in &lt;code&gt;/etc&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/etc/fstab&lt;/code&gt; - Mount point config&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/crypttab&lt;/code&gt; - Encrypted drive config&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/ufw/&lt;/code&gt; - Firewall rules&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/ssh/&lt;/code&gt; - SSH configuration&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/permission-hardener.d/&lt;/code&gt; - Kicksecure permission whitelists&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/systemd/system/&lt;/code&gt; - Custom systemd units&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/modprobe.d/&lt;/code&gt; - Kernel module configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;8-whats-next&#34;&gt;8. What&amp;rsquo;s Next&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;../kicksecure-btrfs-storage/&#34;&gt;Encrypted BTRFS Storage on Kicksecure&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
  </channel>
</rss>
