How I manage my dotfiles across hundreds of machines
Tags: development
Published: 2019-05-07 12:05:50

---
title: How I manage my dotfiles across hundreds of machines
published: true
tags: development
canonical_url: https://www.fullstacksensei.com/blog/dotfiles/
---

Almost all of the command line tools I use on my Mac workstation, on my development server in the cloud, and on my company’s Linux server infrastructure store their configuration in so-called “dotfiles” — files (or even whole directories) in my user home directory that are hidden from plain sight by prefixing their name with a period, for example `.vimrc`. (Like this example, actually quite a few of these files do end in `rc`. That’s why they’re sometimes also called “rc files”.)

On dev.to, Jonathan Carter asked [“How do you manage and synchronize your dotfiles across multiple machines?”](https://dev.to/lostintangent/how-do-you-manage-and-synchronize-your-dotfiles-across-multiple-machines-2n24) Since “multiple” in my case means “more than 500 servers” (we operate a [managed high-performance hosting platform for Drupal and WordPress](https://www.freistilbox.com/)), I thought I’d answer his question in a short blog post.

## dotfile management

Most of the dotfiles I use come from our shared [team dotfiles repository](https://github.com/freistil/dotfiles). Having a big overlap in configuration settings between our SRE allows us to easily share _and take over_ a terminal session via [tmate](https://tmate.io/) without having to struggle with individual `tmux` or `vim` keybindings. Doing pair work in a terminal session has the huge advantage that it takes up much less bandwidth than screensharing via [Zoom](https://www.zoom.us) or [Slack](https://www.slack.com).

Some tools still allow a certain degree of individuality. For example, the shell prompt details can vary without causing confusion. You can also have your own magic shell and git aliases. That’s why I layer my [personal dotfiles repository](https://github.com/geewiz/dotfiles) on top of the team one.

Another complication is that the BSD subsystem on the Mac sometimes behaves a bit differently from Linux. That’s why, for a few configuration files, I’m maintaining alternative versions. They’re stored in subfolders starting with `tag-`. The dotfile deployment then installs the right version depending on the host OS.

## dotfile deployment

So how do you maintain a set of dotfiles in your home directory on hundreds of machines if they come from two overlapping, even conflicting, git repositories? The trick is to clone both repositories and then symlink the configuration files to where they are expected by their application. The key to keeping this process simple and error-free is [rcm](https://github.com/thoughtbot/rcm). It can handle multiple dotfile directories, each with its own precendence. You can also provide it with tag names telling it from where to source certain dotfiles.

I install rcm manually when I set up a new development machine (which only happens once or twice a year). On our servers, it gets installed automatically via our configuration management software Chef.

Here’s the script that I use to deploy my dotfiles:

```
#!/bin/bash

if ! which rcup >/dev/null; then
  echo "Fatal: rcm is not installed on this machine."
  exit 1
fi

os_type=$(uname -s)

# Remove oh-my-zsh
rm -rf ~/.oh-my-zsh

if [[-d ~/.dotfiles]]; then
  cd ~/.dotfiles
  git pull
else
  git clone https://github.com/geewiz/dotfiles.git ~/.dotfiles
fi

if [[-d ~/.freistil-dotfiles]]; then
  cd ~/.freistil-dotfiles
  git pull
else
  git clone https://github.com/freistil/dotfiles.git ~/.freistil-dotfiles
fi

rcup -f -t $os_type -d ~/.dotfiles -d ~/.freistil-dotfiles

```

As you can see, it clones the dotfiles repositories (after a bit of cleanup) and finally calls `rcup` using an OS-specific tag (“linux” or “darwin”). Thanks to a a [`post-up` hook](https://github.com/freistil/dotfiles/blob/master/hooks/post-up), it even launches `vim` to update its plugins from Github.

You can find the current incarnation of the deployment script in my personal repository as [`bin/dotfiles`](https://github.com/geewiz/dotfiles/blob/master/bin/dotfiles). Since its directory gets symlinked as `~/.bin` and added to my shell search path, I can execute the `dotfiles` command at any time to update my local configuration.

As for the initial deployment on a new machine, I simply curlbash the script:

```
curl -L https://raw.githubusercontent.com/geewiz/dotfiles/master/bin/dotfiles | bash

```

That’s how I manage and deploy my dotfiles to have a consistent setup across all my work machines and our hosting infrastructure.

If you’d like to watch me put these nifty dotfiles to good use, join me on Twitch for my next [live coding session](https://fullstacksensei.com/livestream/)!