102

We have a bastion server that we use to connect to multiple hosts, and our .ssh/config has grown to over a thousand lines (we have hundreds of hosts that we connect to). This is beginning to get a little unwieldy and I'd like to know if there is a way to break the .ssh/config file up into multiple files. Ideally, we'd specify somewhere that other files would be treated as an .ssh/config file, possibly like:

~/.ssh/config
  ~/.ssh/config_1
  ~/.ssh/config_2
  ~/.ssh/config_3
  ...

I have read the documentation on ssh/config, and I don't see that this is possible. But maybe someone else has had a similar issue and has found a solution.

3

8 Answers 8

76

The ~/.ssh/config file don't have a directive for including other files, possibly related to SSH's check for file permissions.

Suggestions around this can include a script to cat several changes together either on the system or via checkin hooks on a repository. One might also look into tools such as Puppet or Augeas.

However you approach it, though, you'll have to concatenate individual files to be a single file from outside of the file.

$ cat ~/.ssh/config_* >> ~/.ssh/config

note: overwrite: > v.s. append: >>

Update December 2017:

From 7.3p1 and up, there is the Include option. Which allows you to include configuration files.

Include
    Include the specified configuration file(s).  Mul‐
    tiple pathnames may be specified and each pathname
    may contain glob(3) wildcards and, for user config‐
    urations, shell-like “~” references to user home
    directories.  Files without absolute paths are
    assumed to be in ~/.ssh if included in a user con‐
    figuration file or /etc/ssh if included from the
    system configuration file.  Include directive may
    appear inside a Match or Host block to perform con‐
    ditional inclusion.
1
  • 1
    Thanks Jeff, this is a good idea. I don't know too much about Puppet or Augeas, so for the sake of keeping things as simple as possible, your solution seems best. I could break up the config into multiple configs, and create a simple script to recreate the .ssh/config file whenever one of the files is modified. I don't know how clean of a solution this is, but it does seem to do the trick and works for my purposes.
    – wrangler
    Mar 31, 2012 at 18:19
69

You can specify current config file to use in ssh option like this:

ssh -F /path/to/configfile

Seems it's the only way.

Also there is noway to include one config into another.

1
  • A nice to have option when using Perl's Net::OpenSSH Module (e.g. for multiple private key files.), where the module doesn't give all possibilities. Oct 1, 2016 at 15:48
42

Starting with ssh 7.3 (released on August 1st, 2016), an Include directive is available.

Include: Include the specified configuration file(s). Multiple path names may be specified and each pathname may contain glob wildcards and shell-like "~" references to user home directories. Files without absolute paths are assumed to be in ~/.ssh. An Include directive may appear inside a Match or Host block to perform conditional inclusion.

(Here is the link to the resolved bug report, that also includes the patch: https://bugzilla.mindrot.org/show_bug.cgi?id=1585#c24)

2
  • 2
    That's too cool. Look forward to this. It should finally solve this problem the right way :)
    – wrangler
    Jul 12, 2016 at 16:40
  • 2
    Just add the Include directive at the top of the config file. I cannot figure out why it's not working at the bottom.
    – pylover
    Sep 28, 2018 at 7:00
17

I personally use those commands to compile the ssh config:

alias compile-ssh-config='echo -n > ~/.ssh/config && cat ~/.ssh/*.config > ~/.ssh/config'
alias ssh='compile-ssh-config && ssh'
# (This will get used by other programs depending on the ~/.ssh/config)
# (If you need you can run the compile-ssh-config command via cron etc.)

or:

alias compile-ssh-config='echo -n > ~/.ssh/config-compilation && cat ~/.ssh/*.config > ~/.ssh/config-compilation'
alias ssh='compile-ssh-config && ssh -F ~/.ssh/config-compilation'
# (This is saver and won't over write an existing ~/.ssh/config file)

because:

alias ssh='ssh -F <(cat .ssh/*.config)'

does not work for me, returning:

ssh: Can't open user config file /dev/fd/63: Bad file descriptor

Hope this will be of any help.

2
  • ssh -F <(cat .ssh/*.config) would be ideal. I came up with this too, but I'm getting the same error. Anyone know what's the problem here?
    – ku1ik
    Apr 7, 2016 at 13:41
  • 2
    ssh checks file permissions, I think this kind of redirect doesn't support that check. Sep 25, 2016 at 16:42
2

I also would use cat config_* > config to generate the whole config. But I wouldn't use puppet/cfengine etc for this, if they aren't in place yet (BTW: why not use a config management system???).

I would generate a package (deb, rpm) and put it in a local repository. And in the postinst script the cat generates your config. Perhaps you also include a local folder... The advantage is, that ssh/config updates activates on a daily base while cron-apt &Co run.

2

you should using Include option above all the Host tag in ~/.ssh/config file. else ssh won't resovle the your Includes.

Include ~/.ssh/config-*

Host tunnel HostName database.example.com ....

0

You could use a Makefile in ~/.ssh:

    config: config.in config.app.in
        > $@
        (for f in $+; do cat $$f; echo; done) | sed '$$ d' >> $@

    config.app.in:
        (echo "# Generated with foobar.sh."; \
            foobar.sh) > $@
    .PHONY: config.app.in

Then move your existing config to config.in and run make to generate config.

0

I've been playing with the concept of a config.d directory for my config organizing. So to add to the above pile of options, here's what's been working for me.

The directory structure is something like

~/.ssh/config.d
├── system_1
├── system_2
├── system_3
├── personal_boxen
├── git_things
├── random
└── rubbish

The function that builds the ~/.ssh/config and lives in my shell's run-config is as follows

sshMakeConfig() {
    echo '# AUTOGENERATED by sshMakeConfig()' > ~/.ssh/config
    for i in ~/.ssh/config.d/*
        do echo "#${i}" | tee -a ~/.ssh/config
        cat ${i} >> ~/.ssh/config
    done
}

Optionally add sshMakeConfig to the bottom of your run-config if you want to ensure a fresh config on each shell session

Any time I need to recompile my ~/.ssh/config, I do so by running sshMakeConfig in some form (directly, sourcing my run-config, or starting a new shell)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .