How to perform hostname canonicalization

Perform hostname canonicalization to simplify your configuration and ease work with multiple servers.

Basic configuration

Basic SSH client configuration is very straightforward.

CanonicalizeHostname yes                                                                                                                 
CanonicalDomains example.org example.com                                                                              
CanonicalizeMaxDots 1                                                                                                                    
CanonicalizeFallbackLocal yes
CanonicalizePermittedCNAMEs *.redis.example.org:redis.example.com

Particular options

CanonicalizeHostname and CanonicalDomains

CanonicalizeHostname allows to perform hostname canonicalization, it is disabled by default.

CanonicalizeHostname no

Hostname canonicalization will be not performed by default.

$ ssh -v server : 
OpenSSH_8.1p1 Ubuntu-5, OpenSSL 1.1.1d  10 Sep 2019
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
ssh: Could not resolve hostname server: Name or service not known

Enable CanonicalizeHostname and provide list of domain suffixes using CanonicalDomains to perform hostname canonicalization. This is the minimal required configuration.

CanonicalizeHostname yes
CanonicalDomains example.org example.com
$ ssh -v server
OpenSSH_8.1p1 Ubuntu-5, OpenSSL 1.1.1d  10 Sep 2019
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: ssh: Could not resolve hostname server.example.org.: No address associated with hostname
debug1: Canonicalized hostname "server" => "server.example.com"
debug1: hostname canonicalisation enabled, will re-parse configuration
debug1: re-parsing configuration
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: Connecting to server [192.0.2.21] port 22.
debug1: Connection established.
[...]
Authenticated to server.example.com ([192.0.2.21]:22).
[...]

Notice, client configuration will be parsed again after the hostname canonicalisation is performed.

CanonicalizeMaxDots

CanonicalizeMaxDots specifies the maximum number of dot characters in a canocalized hostname. By default it will accept 1 dot at most.

CanonicalizeHostname yes
CanonicalDomains example.org example.com
CanonicalizeMaxDots 1

This configuration will ensure that you can connect to server and server.internal.

$ ssh -v server
OpenSSH_8.1p1 Ubuntu-5, OpenSSL 1.1.1d  10 Sep 2019
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: ssh: Could not resolve hostname server.example.org.: No address associated with hostname
debug1: Canonicalized hostname "server" => "server.example.com"
debug1: hostname canonicalisation enabled, will re-parse configuration
debug1: re-parsing configuration
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
[...]
$ ssh -v server.internal
OpenSSH_8.1p1 Ubuntu-5, OpenSSL 1.1.1d  10 Sep 2019
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: ssh: Could not resolve hostname server.internal.example.org.: No address associated with hostname
debug1: Canonicalized hostname "server.internal" => "server.internal.example.com"
debug1: hostname canonicalisation enabled, will re-parse configuration
debug1: re-parsing configuration
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config

This configuration will not perform hostname canonicalization for server.lxd.internal as it would require CanonicalizeMaxDots set to 2 at least.

$ ssh -v server.lxd.internal
OpenSSH_8.1p1 Ubuntu-5, OpenSSL 1.1.1d  10 Sep 2019
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: hostname canonicalisation enabled, will re-parse configuration
debug1: re-parsing configuration
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
ssh: Could not resolve hostname server.lxd.internal: Name or service not known

CanonicalizeFallbackLocal

CanonicalizeFallbackLocal is enabled by default and controls whether ssh client will use system resolver to look up the unqualified hostname when the target hostname cannot be found.

CanonicalizeHostname yes
CanonicalDomains example.org example.com
CanonicalizeMaxDots 1
CanonicalizeFallbackLocal yes

It ensures that you can use system resolver which can be handy at times.

$ cat /etc/nsswitch.conf
# /etc/nsswitch.conf
#
# Example configuration of GNU Name Service Switch functionality.
# If you have the `glibc-doc-reference' and `info' packages installed, try:
# `info libc "Name Service Switch"' for information about this file.

passwd:         files systemd
group:          files systemd
shadow:         files
gshadow:        files

hosts:          files mdns4_minimal [NOTFOUND=return] dns
networks:       files

protocols:      db files
services:       db files
ethers:         db files
rpc:            db files

netgroup:       nis
$ cat /etc/hosts
127.0.0.1       localhost
127.0.1.1       desktop

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

192.0.2.21 local.server
$ ssh -v local.server
OpenSSH_8.1p1 Ubuntu-5, OpenSSL 1.1.1d  10 Sep 2019
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: ssh: Could not resolve hostname local.server.example.org.: No address associated with hostname
debug1: ssh: Could not resolve hostname local.server.example.com.: No address associated with hostname
debug1: hostname canonicalisation enabled, will re-parse configuration
debug1: re-parsing configuration
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: Connecting to local.server [192.0.2.21] port 22.
debug1: Connection established.
[...]

Turning off CanonicalizeFallbackLocal will disable this behaviour.

CanonicalizeHostname yes
CanonicalDomains example.org example.com
CanonicalizeMaxDots 1
CanonicalizeFallbackLocal no
$ ssh -v local.server
OpenSSH_8.1p1 Ubuntu-5, OpenSSL 1.1.1d  10 Sep 2019
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: ssh: Could not resolve hostname local.server.example.org.: No address associated with hostname
debug1: ssh: Could not resolve hostname local.server.example.com.: No address associated with hostname
ssh: Could not resolve host "local.server"

CanonicalizePermittedCNAMEs

CanonicalizePermittedCNAMEs allows to specify rules to determine which CNAMEs should be followed. To be exact, this option allows to use the target of the CNAME record in defined cases which is really cool.

CanonicalizeHostname yes
CanonicalDomains example.org example.com
CanonicalizeMaxDots 1
CanonicalizeFallbackLocal yes

By default CNAME record will be not followed.

$ ssh -vvv personal.server 
OpenSSH_8.1p1 Ubuntu-5, OpenSSL 1.1.1d  10 Sep 2019
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug2: resolve_addr: could not resolve name personal.server as address: Name or service not known
debug3: resolve_canonicalize: attempting "personal.server" => "personal.server.example.org."
debug1: Canonicalized hostname "personal.server" => "personal.server.example.org"
debug1: hostname canonicalisation enabled, will re-parse configuration
debug1: re-parsing configuration
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug2: ssh_connect_direct
debug1: Connecting to personal.server [192.0.2.21] port 22.
debug1: Connection established.
[...]
debug1: Authenticating to personal.server.example.org:22 as 'milosz'
[...]
debug1: Host 'personal.server.example.org' is known and matches the ECDSA host key.
[...]
Authenticated to personal.server.example.org ([192.0.2.21]:22).
[...]

Specifing simple rules will allow to follow specific CNAME records.

CanonicalizeHostname yes
CanonicalDomains example.org example.com
CanonicalizeMaxDots 1
CanonicalizeFallbackLocal yes
CanonicalizePermittedCNAMEs *.server.example.org:server.internal.example.com 
$ ssh -vvv personal.server 
OpenSSH_8.1p1 Ubuntu-5, OpenSSL 1.1.1d  10 Sep 2019
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug2: resolve_addr: could not resolve name personal.server as address: Name or service not known
debug3: resolve_canonicalize: attempting "personal.server" => "personal.server.example.org."
debug3: check_follow_cname: check "personal.server.example.org" CNAME "server.internal.example.com"
Canonicalized DNS aliased hostname "personal.server.example.org" => "server.internal.example.com"
debug1: hostname canonicalisation enabled, will re-parse configuration
debug1: re-parsing configuration
debug1: Reading configuration data /home/milosz/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug2: ssh_connect_direct
debug1: Connecting to personal.server [192.0.2.21] port 22.
debug1: Connection established.
[...]
debug1: Authenticating to server.internal.example.com:22 as 'milosz'
[...]
debug1: Host 'server.internal.example.com' is known and matches the ECDSA host key.
[...]
Authenticated to server.internal.example.com ([192.0.2.21]:22).
[...]

Additional notes

Hostname canonicalisation in OpenSSH

Some notes on OpenSSH's optional hostname canonicalization