Dotfile Management with Yadm

6 minute read

Intro

One of the major benefits of Unix-like desktop systems is the ability to configure and fine-tune your desktop environment. The majority of these files are dotfiles, because traditionally they either reside in a folder that starts with a dot, e.g .ssh, or the file itself .zshrc. Obviously, this isn’t always the case, what’s important is that these are files and directories that contain configuration variables, functions, and settings.

Some of the dotfiles on my system include:

  • .zshrc
  • .ssh/ directory is encrypted, more on that later
  • .aws/
  • .gitconfig
  • .spacemacs
  • .aliases

This is considered a small list, but it handles the core of my desktop environment’s configuration. What becomes a hassle is when you run multiple desktops and include laptops in your arsenal.

  1. Does anyone really want to manage separate dotfiles for each desktop environment when most, if not all of the files are exactly the same?
  2. What if we need to revert previous changes?

The answer to these questions is why we’re here.

Enter yadm

Yadm (Yet Another Dotfiles Manager), solves the problems that we mentioned above. It’s a wrapper for Git, includes encryption support, and it’s extremely portable and lightweight since it’s just a Bash script. Git revision control allows you to create a centralized repository for you to push and pull configuration files where you get all the benefits of a typical git repository.

Installing Yadm

Installing Yadm is easy, most Linux distributions have yadm in their official repositories. There is also a homebrew package for OS X. At the time of this writing Fedora 35 is the latest stable release but does not have yadm in its official repo, however you can grab the latest Fedora Rawhide RPM package from OpenSuse Build System.

Check the full installation list here.

Getting Started

Outside of installing yadm and git on your local systems, you will probably want to set up your own private Git server. You could obviously use a private git repo from GitHub, Bitbucket, GitLab, or any one of the other Git services instead of managing your own server. If you elect not to manage sensitive configuration files, you could also just use a public Git repo.

I wouldn’t recommend using any Git service to store your configuration files. In my opinion, when dealing with a set of files that at one point in the future may contain sensitive files or credentials you won’t want to risk pushing them to a public Git repository. In my opinion, when taking control and adding more privacy to your digital life you should try to avoid services, and instead choose to store your dotfiles on your own private remote server. Luckily, there really isn’t much to install or manage to host your Yadm repo.

Setup Git Bare Repo

There really is no server to install, you simply install Git (if not installed already) and initialize your repo. Git isn’t a daemon so once you have the CLI tool installed, you either execute it on the server where it manages the git repo directories or run the CLI on your local computer to manage the Git working directories.

On your remote node that will act as the centralized host you want to add a dedicated Git user.

adduser git -m

You want to make sure this user has a home directory, as this will be where the Git repositories reside. You can store the repositories in any directory, but since this user will already own the home directory, we won’t need to set any permissions.

Next, you switch to the newly created git user, and initialize the bare repo in your home directory.

[git@mygithost ~]$ git init --bare dotfiles.git

You should see a directory named dotfiles.git. Conventionally, repositories initialized with the –bare flag ends in .git.

Why Bare Repo?

So why do we create a “bare” repo instead of a regular repo? If you’re familiar with using a Git service like GitHub you can create a Git repo through github.com before or after you git init your local project so you can push it to the remote git repo.

When you run git init, it creates a WORKING directory. It’s intended to be used as a directory where your file changes will take place. So this makes sense to run on your local dev machine. However, for the remote server that exists to store your repo and no person or service will be making changes to the files there is no need to take up file-space storing a working directory.

Setup connection

You’d want to use ssh keys to log in to the remote git server as the git user. The way to do this varies depending on the VPS or cloud service provider you use. Some general-purpose guides:

The goal is to be able to git remote add origin mygithost:dotfiles.git and push/pull without being bothered with passwords. Again, you have multiple options, one such is to use ssh_config

Host mygithost 
	HostName 2.34.33.4 
	User admin 
	Port 22 
	IdentityFile ~/.ssh/mygitkey.pem
  

Setup Yadm

As mentioned Yadm is largely a wrapper for Git. So most of the commands are the same, just prepended with yadm. So to initialize the working directory of yadm, you would execute:

[localuser@dev-computer ~]$ yadm init

Notice that we want to initialize our home directory because this is the root of all our config files. After that, you add the files and directories you want to version control.

For example:

yadm add .spacemacs
yadm add .aws
yadm add myReadMe.org # I like to keep a file of config specific notes

After you’ve added the files you want to manage, you commit and push similarly to using pure Git.

yadm commit -m "added files"
yadm push -u origin master

Encrypted Files

Some configuration files are sensitive, they either contain credentials or are themselves private keys. Yadm is nice enough to offer a simple way to manage encrypted files without much manual work. You simply need to have either OpenSSL or GPG installed, and edit the yadm text file located in your local .config/ directory.

Edit a file at $HOME/.config/yadm/encrypt (create if it doesn’t exist) to include the files and/or directories you want to encrypt. My file consists of:

.ssh/*
.aws/credentials

I have every file inside my .ssh/ directory encrypted, and the one .aws/credentials file with sensitive credentials added. After the file is saved you tell Yadm you files to encrypt, then you add the file you just created along with the generated encrypted archive to versioning.

yadm encrypt
<ENTER PASSWORD>
yadm add .config/yadm/encrypt
yadm add .local/share/yadm/archive

Now we can commit and push this to our remote repo. And on another system that we want to sync our config files with you run yadm pull & yadm decrypt.

Wrapping Up

We now have a system that accomplishes our two main goals. Our important configuration files now have versioning, and we only need to maintain a central repository of configuration files. We only need to maintain one set of configuration files, but what if we have different systems? Say my desktop runs Linux, but I have a MacBook running OS X which requires slight configuration differences. One way is to make use of Alternate Files - yadm. This way we can specify different files depending on specific conditions.

Yadm also supports bootstrapping, the ability to create and run scripts to do any extra configuring in addition to the files you’re syncing. As an ideal use case for my setup you can imagine the extra libraries and software I have installed to work with Spacemacs. Such as the yaml-language-server which I installed using NPM, and certain Python libraries like flycheck. All of which I would rather not have to install manually on each new system. You can create an executable script that gets ran when you execute yadm bootstrap to install and configure any extra software.