Linux – manage unix user settings across multiple machines

configurationlinuxnot-root-user

I have many different linux machines with similar "profiles". I want to keep my settings in sync. e.g vimrc, zshrc,. I have the problem that they are various distributions of Linux with various setups and software versions, e.g, some of them with a windowing system, some not, Some have Zsh, some don't, some have varying versions of it. I realize I could dropbox, or github, etc, my settings. But as the environment has become more complex this has become more difficult (I already Github). I also find it challenging to keep each machine in sync. These are mostly client machines, with different internet connections (and different networks, e.g some home some office, so "push" to machine won't work for keeping in sync. I don't expect that a solution would automatically detect my code, e.g. zshrc is incompatible with an old version, but it'd be nice to hint things as such so they aren't synced, perhaps a template.

Are there any existing solutions that could help me solve this problem?

Best Answer

I can tell you what I do. This may or may not be the best option for you, depending on what programs you have configuration files for, how much variation there is between machines, and how much effort you prefer to put in writing portable configuration files versus duplicating maintenance between per-version or per-site files.

All my configuration files are under version control. I use CVS, which is perfectly sufficient for the task, but if you're starting now (as opposed to back when Linus didn't believe in version control), you may use another version control system. Version control is always good, regardless of whether you have multiple checkouts. To synchronize a modification between sites, I commit and update.

I strive to write portable files. For example, my .zshrc is supposed to be compatible with all versions since 2.5 (however this is a bit of a stretch: I haven't tested it recently, and the last time I loaded it on a machine with zsh 2.5, it was really slow). This means I have a lot of things like if type someprogram >/dev/null 2>/dev/null and case $ZSH_VERSION (when I can't avoid it). The same goes for other programs whose configuration file is an interpreted language (bash, Emacs, Vim, Fvwm, Sawfish, …). I didn't want to maintain separate versions of these files, so every version-dependent definition is under a conditional statement. If you want to keep the hassle down (at the expense of supporting fewer combinations), you can do something like

case $ZSH_VERSION in
  [5-9]*|4.[2-9].*) . ~/.zshrc-42;;
  4.[01].*) . ~/.zshrc-40;;
  3.1.[6789]) . ~/.zshrc-31;;
  *) . ~/.zshrc-2;;
esac

But there are other system dependencies (e.g. the version of ls so you know whether to alias it to gnuls --color -b or ls --color -b or colorls -G or ls -Fb or …). Splitting everything into separate files gets tiresome pretty quickly.

I keep a per-site directory with per-site settings, which are loaded by the main file. For example, my .zshrc contains the lines

if [ -r ~/Here/lib/shell/local.zshrc ]; then
  . ~/Here/lib/shell/local.zshrc
fi

Here is a symbolic link to a directory containing site-specific configuration files. It doesn't exist on sites that I haven't customized. The local .zshrc typically contains aliases, directory aliases and the like. Most sites have a local .profile that define a few environment variables. All site-specific configurations are under the same version control system (checking them all out is just a few kB more).

A few files are automatically generated by a makefile. For example, I have a script to generate ~/.ssh/config from a common list of hosts (aliases and options for machines reachable from anywhere) plus a site-specific list of hosts (for machines reachable only within a network).

Related Question