Regular Expression matching in ssh config
I have a bunch of servers with the names srv1.domain.com, srv2.domain.com, ..., srv50.domain.com
I want to be able to connect to these servers by ssh srv1
I don't want to put 50 configuration entries to my .ssh/config such as
HOST srv1
HOSTNAME srv1.domain.com
USER amac
IdentityFile /home/amac/.ssh/id_rsa
What I like is a regular expression matching, which would allow me to write something like
HOSTNAME (srv[0-9]*).domain.com
HOST \1
USER amac
IdentityFile /home/amac/.ssh/id_rsa
Is this possible? Maybe by creating a bash alias which would convert all instances of "srv(.*)" to srv\1.domain.com, where \1 corresponds to the substring in the paranthesis matched by the regular expression?
Thanks.
Solution 1:
This sounds like a problem best solved by DNS. Add this to your
/etc/resolv.conf
:search domain.com
If a DNS lookup contains no dots1 or returns an NXDOMAIN >response then another DNS lookup will be made with that search value >appended.
Examples:
If you do
ssh srv1
, the DNS lookup will be made forsrv1.domain.com
.If you do
ssh srv1.dc1
, the DNS lookup will be forsrv1.dc1
which will return NXDOMAIN. The automatic followup DNS lookup will be forsrv1.dc1.domain.com
.You can add multiple search domains to that line separated by whitespace and they will be tried in the order listed until one of them returns an A record2.
1.) This value is configurable and refers to the number of dots the short name must have fewer than. The default value is 1 and it should be set higher than 1 for sites where the hosts are of the form
srv1.dc1.domain.com
. This avoids the useless request to the root servers for thedc1
top level domain.2.) Or an AAAA record.
Updated answer 25th Nov 2020:
Although the outdated answer above is still a fully valid one, nowadays, I would rather suggest using the ssh_config
built-in mechanism CanonicalDomains
That would mean, instead of changing /etc/resolv.conf
or DNS records, you can simply add the following lines to the top of your ssh_config
file:
CanonicalizeHostname yes
CanonicalDomains domain.com
Please refer to the official ssh_config documentation for details around these configuration statements.
Solution 2:
This should do the trick on OpenSSH 5.5 and greater.
Host *.*
Hostname %h
Host *
Hostname %h.domain.com
IdentityFile /path/to/keyfile.pem
The first rule matches any normal domain names and just passes the domain name through. The second rule handles single word hosts and appends domain.com to the end.
One side effect of this is that even for ssh calls to anotherdomain.com, ssh will try to use the IdentityFile for domain.com. I don't think that matters however.
Solution 3:
You can use ProxyCommand
to use regex
on the host name specified on the command line.
Host srv*.domain.com
User amac
ProxyCommand nc $(sed -e "s/.domain.com//" <<< "%h") %p
IdentityFile /home/amac/.ssh/id_rsa
Now ssh srv23.domain.com
would connect to srv23
.
Note, you don't need to specify HostName
.
Solution 4:
openssh supports patterns (see http://linux.die.net/man/5/ssh_config), but not references to matches (AFAIK).
You can specify wildcards pretty much as you had it in the question:
Host srv*.domain.com
User amac
IdentityFile /home/amac/.ssh/id_rsa
If you don't want to have to specify the full hostname, you can either do the dns trick mentioned before (and change the Host line to srv*) or create a shell function as follows:
ss() {
if [ -z "$1" ]; then
echo "specify a server #, eg ss 10"
else
echo "ssh'ing to srv$1.domain.com"
ssh srv$1.domain.com
fi
}
and use it like:
ss 10
Easier than changing dns and doesn't cause problems when you want to hit srv01.someotherdomain.com.
Solution 5:
I had a problem that when specifying
Host srv*
Hostname %h.domain.com
I could no longer connect using full host names:
$ ssh srv677.domain.com
ssh: Could not resolve hostname srv677.domain.com.domain.com: Name or service not known
Note that doubling domain.com.
To be able to connect via both short and full forms of host names, I did the following trick:
Host srv* !srv*.domain.com
Hostname %h.domain.com
User amac
IdentityFile /home/amac/.ssh/id_rsa
Host srv*.domain.com
User amac
IdentityFile /home/amac/.ssh/id_rsa
Or even better solution (inspired by this answer https://superuser.com/a/469470):
Host *.domain.com srv* vrs*
User amac
IdentityFile /home/amac/.ssh/id_rsa
Host !*.domain.com srv* vrs*
Hostname %h.domain.com
It is better because it does not require copying all options twice.