Felipe Martín

Using ssh_config Match to connect to a host using multiple IP or Hostnames

My main computer is a MacBook Pro from 2017, but I have some servers laying around and one other laptop connected at home with ArchLinux installed that I use mainly for development. I connect to it remotely either directly using a SSH/Mosh + Tmux + Emacs/Vim combination, or using the pretty convenient VSCode Remote Extensions when I’m not feeling much of a hacker.

Thing is, I may access this computer either from my home network directly if I’m at home or via a SDN if I am not (at the office, coffeeshop, visiting family, etc).

My approach was to setup the hosts directly on my ~/.ssh/ssh_config as you would with different machines:

1
2
3
4
5
6
# .ssh/config
Host laptop.lan
    HostName 192.168.1.2 # Internal network IP

Host laptop.sdn
    Hostname 10.0.0.2 # SDN IP

That way, I would connect to each one of them depending on the situation. Using tmux and ssh is not that much of a problem since I could just detach from home, go away, then connect via SDN an everything would be there (though I had to remember which alias to use instead of just ssh laptop). For VSCode is not that convenient since I would need to close the connection, made a new one to the new host and so on. Surely we could made this simpler, right?

In my home network, my main router is also my DNS server (with Ad Blocking, rules and all kind of fancy things), and that server resolves my local domain (*.lan) to LAN IP Addresses, so I can start with a simple config as I had previously:

1
2
3
# .ssh/config
Host laptop
    HostName laptop.lan

Now, what happens if I’m not at home? I could solve this in several ways:

  • I could ping my router, but that could collide with other networks out there.
  • I could check if my Wifi BSSID is one of the APs at home, but I could also connect via Ethernet.
  • I could check if I can resolve the laptop.lan address, though this requires network access, but in the end is the one I ended up using.
1
2
3
4
5
$ dig +short laptop.lan
192.168.1.2 # At home

$ dig +short laptop.lan
# Empty result when away from home

Now, here comes the Match magic:

1
2
3
4
5
6
# .ssh/config
Host laptop
    HostName laptop.lan

Match originalhost laptop exec "[[ $(/usr/bin/dig +short laptop.lan) == '' ]]"
    HostName laptop.sdn

Using Match we can replace properties for a defined host using matches. In this ad-hoc example what I did is:

  • Match originalhost laptop: The connection host need to match laptop
  • exec "[[ $(/usr/bin/dig +short laptop.lan) == '' ]]": Execute dig and try to resolve my LAN’s laptop domain name. This needs to be a successful command for it to match, in this case we compare digs output to an empty string to evaluate if we can resolve the laptop.lan domain name (check the [[ ]]).
  • HostName laptop.sdn If both rules match, replace the HostName property with the laptop’s SDN domain name.

This is a pretty easy way to just ssh laptop wherever I am. I didn’t knew about this particular keyword until today, and it’s pretty powerful!

Documentation: ssh_config(5) manpage