Is there a way for one SSH config file to include another one?

137

36

In case it matters:

  • OS: Ubuntu 10.04
  • SSH: OpenSSH_5.3p1 Debian-3ubuntu5

I'd like one SSH config file to include another one. The use case would be to define whatever I want in my default .ssh/config file and then pre-pend a couple of extra things in a separate file (e.g. ~/.ssh/foo.config). I want the second file to incorporate the first one, though, so I don't have to duplicate everything in the first one. Is that doable? Thanks!

Joe Casadonte

Posted 2011-02-18T17:45:01.283

Reputation: 3 945

2

Same question on serverfault: http://serverfault.com/questions/375525/can-you-have-more-than-one-ssh-config-file

– guettli – 2014-10-29T17:56:48.623

Answers

154

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

Include

    Include the specified configuration file(s).  Multiple pathnames may be specified and each pathname may contain glob(3) wildcards and, for user configurations, shell-like “~” references to user home directories.  Files without absolute paths are assumed to be in ~/.ssh if included in a user configuration file or /etc/ssh if included from the system configuration file.  Include directive may appear inside a Match or Host block to perform conditional inclusion.
Source: ssh_config(5).

For example you could have in ~/.ssh/config:

Include config.d/home

Host github.com
    HostName github.com
    User git

and in ~/.ssh/config.d/home:

Host laptop
    HostName laptop.lan

From the comments, use the below to include all files in the config.d directory:

Include config.d/* 

Osaka

Posted 2011-02-18T17:45:01.283

Reputation: 1 656

13check version with $ ssh -V – Pieter – 2016-11-13T01:25:08.043

8Use Include config.d/* to include all entries in config.d. – Simon Woodside – 2016-11-17T05:41:36.067

22Ftr: this has to go in the top of the file and cannot just be appended to the list of Host entries. – dtk – 2017-02-21T16:47:57.863

2

tried on Ubuntu 16.04. Though, it works, but the autocomplete is broken which makes it less useful. If you want to upgrade ssh on ubuntu, check this link https://gist.github.com/stefansundin/0fd6e9de172041817d0b8a75f1ede677

– cwhsu – 2018-01-06T10:12:02.643

@dtk thanks for that. That's what was stumping me – Adam Keenan – 2019-07-24T23:34:04.550

1@dtk another workaround is to put the Include inside a Host * entry and avoid reordering the config – dfogni – 2020-01-21T10:11:22.060

28

No, to my knowledge this is not possible.

Here are the links to corresponding open feature requests / bug tickets:

https://bugzilla.mindrot.org/show_bug.cgi?id=1585

https://bugs.launchpad.net/ubuntu/+source/openssh/+bug/739495

rems

Posted 2011-02-18T17:45:01.283

Reputation: 1 850

2

Also this bug on Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=631189

– Lluís – 2014-07-03T11:50:17.833

8OMG. It is hapening. From 2016-04-15 13:01:08 EST: Slightly modified patch applied, this will be in openssh-7.3 – oschrenk – 2016-06-18T00:15:38.600

This answer was correct at the time, but is outdated now. – Mark Stosberg – 2018-12-06T21:40:37.507

25

If you want to start a ssh client, you could do this in bash:

#files are .ssh/config and ~/.ssh/foo.config
alias ssh='ssh -F <(cat .ssh/config ~/.ssh/foo.config)'

then you use ssh normally and it will have both files read in that order.

For the server daemon sshd you could do the same, just use -f instead of -F and write this down where you start the daemon directly. you don't need an alias.

A second possibility according to the man page is to put the system wide configuration in /etc/ssh/ssh_config and the user one in ~/.ssh/config.

Update Apparently there is some problem with some bash versions and how the devices are created. (see http://bugs.alpinelinux.org/issues/1465)

This is a workaround (though in my opinion ugly):

mkfifo /tmp/ssh_fifo
cat ~/.ssh/config ~/.ssh/foo.config >/tmp/ssh_fifo & 
ssh -F /tmp/ssh_fifo myserver
rm /tmp/ssh_fifo

so if you want, you may create a function out of it (or a script):

ssh() {
    tmp_fifo=$(mktemp -u --suffix=_ssh_fifo)
    mkfifo "$tmp_fifo" 
    cat ~/.ssh/config ~/.ssh/foo.config >"$tmp_fifo" 2>/dev/null & 
    /usr/bin/ssh -F "$tmp_fifo" "$@"
    rm "$tmp_fifo"
}

estani

Posted 2011-02-18T17:45:01.283

Reputation: 546

1Sadly this doesn't work on OSX's ssh: Can't open user config file /dev/fd/63: Bad file descriptor – Ash Berlin-Taylor – 2012-08-23T13:10:56.423

It does not work for me also on (Ubuntu 11.10) Linux giving the same error as @AshBerlin posted above. – Szymon Jeż – 2012-11-27T15:13:02.543

@AshBerlin you may try it too, this should work also for OSX, until the bug gets fixed – estani – 2012-11-27T19:32:33.277

Given ssh checks three places, 1. command line, 2. ~/.ssh/config, 3. /etc/ssh/ssh_config, you shouldn't need to pass ~/.ssh/config on the command line as well. Just alias ssh='ssh -F ~/.ssh/foo.config' and ~/.ssh/config should get picked up after that. As long as you don't mind foo.config being loaded first that should be cleaner than the above workaround. – jim – 2013-02-05T03:27:47.017

1@jim no it doesn't work like that. The first one found is used. Have you tried it? from the man page "-F configfile: Specifies an alternative per-user configuration file. If a configuration file is given on the command line, the system-wide configuration file (/etc/ssh/ssh_config) will be ignored." – estani – 2013-02-06T10:52:53.130

Oh. That's disappointing. I was going off the man page for ssh_config: `ssh(1) obtains configuration data from the following sources in the following order:

1.   command-line options
2.   user's configuration file (~/.ssh/config)
3.   system-wide configuration file (/etc/ssh/ssh_config)`
 – jim  – 2013-02-08T00:50:22.563

@jim Indeed... I read that man page again and the first line after that reads: "For each parameter, the first obtained value will be used." Exactly the opposite as what I've seen... have you tried it? It looks as if that was changed with some version and the ssh_config wasn't updated (or the help was written before the code :-) – estani – 2013-02-08T09:25:14.067

@estani: no, I haven't tried it. So you're probably right. – jim – 2013-02-09T20:24:52.057

17

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 tha patch: https://bugzilla.mindrot.org/show_bug.cgi?id=1585#c24)

Christian Hudon

Posted 2011-02-18T17:45:01.283

Reputation: 273

14

Similarly to the other 'ugly' here's mine one-liner:

alias ssh="cat ~/.ssh/config.d/* > ~/.ssh/config; ssh"

Aleksandr Makov

Posted 2011-02-18T17:45:01.283

Reputation: 263

Note that sftp command will not trigger config recalculation. – VasyaNovikov – 2015-03-13T22:44:20.040

2(I still like the answer because it uses "config.d/" and is very simple.) – VasyaNovikov – 2015-03-13T22:49:20.947

2simple, elegant, yet hacky – code_monk – 2016-05-29T14:31:15.920

beware: will overwrite any existing ~/.ssh/config file – mhansen – 2020-02-23T06:47:40.397

6

Well, I kinda cheat to do this. In my bash .profile-ish files I have a block that replaces various pieces of my home directory on login, so I just generate a new one each time. Example:

rm ~/.ssh/config
cat ~/conf/myservers.sshconfig >> ~/.ssh/config

[ -f ~/conf/workservers.sshconfig ] && cat ~/conf/workservers.sshconfig >> ~/.ssh/config
(or something like this:)
for i in `ls ~/conf/sshconfigs` ; do
    cat $i >> ~/.ssh/config
done

chmod 600 ~/.ssh/config

This also lets me do things like add config blocks to the ssh config file only if i'm on host A or B, but not on my home systems.

Now I know, someone will gripe that if you log in a lot this could cause excessive slowdown, but in practice I've never actually noticed it. And I'm sure you could put this in a script and fire it via cron too.

Dave

Posted 2011-02-18T17:45:01.283

Reputation: 61

3

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.

Szymon Jeż

Posted 2011-02-18T17:45:01.283

Reputation: 131

You could go a step further and combine this with fswatch, for automated compilation on file change – cavalcade – 2015-02-28T06:34:32.013

3

Another, FUSE-based solution (not tested myself):

https://github.com/markhellewell/sshconfigfs

"Rather than having to continue managing one big file, [...] instead build a config "file" dynamically from many smaller logical chunks."

I've also found an article doing this via FIFOs: http://www.linuxsysadmintutorials.com/multiple-ssh-client-configuration-files/

amontero

Posted 2011-02-18T17:45:01.283

Reputation: 31

1I find the comment content to be descriptive enough - it says "FUSE" (Perhaps expanding the acronym would be better); The link is just to an implementation. – aviv – 2013-06-23T20:20:25.067

1Wasn't aware of short answers problem, answer expanded. Looks like I will have to check back the site for my answers from time to time, in absence of email notifications :) Learnt to use favs, by now. Thanks for the comments. – amontero – 2013-07-07T14:17:02.020

2

None of these alias solutions work for git or other programs other than ssh.

I've slapped together a quick-and-dirty, but you might want to improve on it.

Add this to your ~/.bashrc

mkdir -p ~/.ssh/config.d/
[ -e ~/.ssh/config ] && mv ~/.ssh/config ~/.ssh/config.bak.$(date -Ins)
cat ~/.ssh/config.d/* > ~/.ssh/config

Each time you start a session, it'll merge together all the files in ~/.ssh/config.d. (line 3)

The downside with this version is that if you change ~/.ssh/config next session you open your changes would be lost, so to prevent that I move the existing file to a .bak file. (line 2) The problem there is you're gonna have a whole lot of .bak files after a while.

Dean Rather

Posted 2011-02-18T17:45:01.283

Reputation: 2 499

Excellent with adding some is_anything_changed condition – vp_arth – 2015-07-04T04:57:10.277

1

You can easily upgrade SSH version on Ubuntu to v7.3 (tested on Ubuntu Xenial 16.04) by installing packages from Yakkety:

echo "deb http://archive.ubuntu.com/ubuntu yakkety main" > /etc/apt/sources.list.d/yakkety.list
apt-get update
apt-get install -y ssh
rm /etc/apt/sources.list.d/yakkety.list
apt-get update

Check SSH version

ssh -V
OpenSSH_7.3p1 Ubuntu-1, OpenSSL 1.0.2g 1 Mar 2016

Configure SSH to use includes from ~/.ssh/config.d directory

mkdir ~/.ssh/config.d
sed -i '1iInclude config.d/*' ~/.ssh/config

panticz.de

Posted 2011-02-18T17:45:01.283

Reputation: 231

0

My dumb answer :

  • Tried to install OpenSSH > 7.3 on Xenial (16.04)
  • Didn't like the mess it made

So I settled for this :

  • Keep your separate OpenSSH config files in ~/.ssh/config.d/
  • When you change one, do cat ~/.ssh/config.d/* > ~/.ssh/config
  • On the glorious day you upgrade to a distro version that has OpenSSH 7.3p1 or newer, you can instead create a file that contains

Include config.d/*

Adrian

Posted 2011-02-18T17:45:01.283

Reputation: 156

0

I cannot upgrade SSH on my machine neither.

I used GNU make to generate the ssh config file only when needed:

# Concatenates all the .config files.
aInput  = *.config
aOutput = ~/.ssh/config

aCurrentMakefile = $(lastword $(MAKEFILE_LIST))

$(aOutput): $(shell ls $(aInput)) $(aCurrentMakefile)
    @echo "Generating $(aOutput)"
    @echo "# File generated by $(aCurrentMakefile) on $(shell date +'%F %T.%6N')" > $(aOutput)
    @cat $(aInput) >> $(aOutput)

Then ssh is aliased to

alias ssh='make -s -f ~/Tools/config.d/makefile -C ~/Tools/config.d && ssh'

It works like a charm.

ggmath

Posted 2011-02-18T17:45:01.283

Reputation: 1