Linux Administration·8 min read·

SSH Config Host Aliases, IdentitiesOnly, Jumps

Stop repeating long ssh flags. Build a ~/.ssh/config with Host aliases, IdentitiesOnly, and jump hosts so private VPS nodes stay one command away.

NB

Netbay Engineering

Netbay Engineering

On this page

The SSH command line grows a tail of flags the moment you have more than one box. You type ssh -i ~/.ssh/id_ed25519_prod -p 22 -J bastion deploy@10.0.0.4, then you type it again from a second terminal and miss a flag. OpenSSH already ships a client configuration file that turns that mess into ssh prod. It is the client-side map: Host aliases, IdentitiesOnly so the agent does not spray every key at a MaxAuthTries-limited daemon, and a jump host that stays public while the rest of the fleet stays private.

From ssh flags to a named Host alias LAPTOP ssh prod ~/.ssh/config alias + key pin JUMP HOST public Lucknow VPS APP NODE private RFC1918 IdentitiesOnly yes | ProxyJump bastion | HostName stays in config One short name. One key. One hop. No flags to remember on a bad day. sshd on the app node never sees the public internet; only the jump host does.

Why a config file beats a shell alias

A shell alias hides flags, but it does not compose. scp, sftp, rsync -e ssh, git, and ansible all speak the OpenSSH client, and they all read ~/.ssh/config. They do not read your .bashrc. Put HostName, User, Port, IdentityFile, and ProxyJump in the config and every tool that shells out to ssh inherits the same map. That is the whole point of doing this work once.

The file is line-oriented. A Host line starts a stanza. Keywords under it apply until the next Host or Match. First match wins for each keyword, which is why you put specific aliases above wildcards. A trailing Host * stanza is the right place for shared defaults such as HashKnownHosts, ServerAliveInterval, and IdentitiesOnly. Do not put a specific IdentityFile on Host * unless you enjoy debugging which key just got offered.

Permissions matter as much as syntax. The directory ~/.ssh must be 700 and the config file 600, owned by you. OpenSSH will ignore a group-writable config. That is not a suggestion; it is how the client refuses to trust a file someone else could have edited.

Host aliases and pattern matching

Give every machine a short name you can type in the dark. The alias is the Host value. The real address is HostName, which can be a public IP, a private RFC1918 address, or a DNS name. User and Port belong in the stanza so you never pass them on the command line again.

bash
Host bastion
  HostName 203.0.113.10
  User deploy
  IdentityFile ~/.ssh/id_ed25519_bastion
  IdentitiesOnly yes

Host prod
  HostName 10.0.0.4
  User deploy
  IdentityFile ~/.ssh/id_ed25519_prod
  IdentitiesOnly yes
  ProxyJump bastion

Host *
  IdentitiesOnly yes
  ServerAliveInterval 30
  ServerAliveCountMax 3
  HashKnownHosts yes

Patterns are useful when a fleet shares a suffix. Host db-*.internal matches db-1.internal. Host !bastion * applies a default to everything except the jump box. Keep the pattern language boring. Clever negative matches that nobody else can read will lock a colleague out at 2 a.m. Document the alias list next to your inventory, or generate the config from that inventory so the two cannot drift.

IdentitiesOnly stops the agent from burning tries

This is the setting people skip, then blame MaxAuthTries. ssh-agent holds every key you have loaded: laptop, personal Git host, old project, the break-glass key you added last quarter. By default the client offers them in order until the server accepts one or hangs up. A hardened sshd with MaxAuthTries 3 will disconnect after three publickey failures. Your correct key never gets a turn.

IdentitiesOnly yes tells the client to offer only the IdentityFile listed in the matching stanza, plus any -i flags you passed. Combined with a per-host IdentityFile, the agent still decrypts the key (so you keep a passphrase), but it no longer sprays the rest of the keyring at the daemon. That is the difference between a working login and Too many authentication failures.

Confirm what the client will actually do before you depend on it. ssh -G prints the expanded configuration after alias and pattern matching. Pipe it through grep and you will see hostname, user, identityfile, proxyjump, and identitiesonly without opening a network connection.

bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/config
ssh -G prod | grep -Ei "hostname|user|port|identityfile|proxyjump|identitiesonly"
ssh -v prod true

The verbose trace shows each key offered. If you still see files you did not list, a wildcard stanza or an extra IdentityFile is winning. Put the specific Host prod block above Host *. Extra IdentityFile lines in the same stanza add keys to the offer list.

Jump hosts as first-class Host entries

A jump host, or bastion, is the only machine with a public address. Application nodes listen on a private network. The client reaches them with ProxyJump, which is the modern replacement for a hand-rolled ProxyCommand. Name the bastion as its own Host alias, then point application aliases at it. Nested hops work: ProxyJump bastion,mid is two hops, evaluated left to right.

Keep the bastion thin. It exists to accept your key, forward a tunnel, and not run application code. Give it a dedicated IdentityFile so a compromise of an application key does not equal a compromise of the front door. Put AllowUsers on the bastion sshd so random local accounts cannot authenticate. The application nodes can then restrict source addresses to the bastion private IP, which you will wire in a later sshd Match block.

Do not copy private keys onto the jump host. ProxyJump opens a second SSH connection from your laptop through the already-authenticated hop. The private key never leaves the client. That is a different, safer model than agent forwarding, which we will refuse to treat as the default later in this series.

If a hop fails, ssh -J bastion prod is the one-off equivalent of the config. Use it to test, then put the same values back in the file. Ubuntu 24.04 on a Lucknow VPS needs no extra TCP forwarding limits on a jump box that only you use.

Include files and a config you can review

Once the file passes a page, split it. Include ~/.ssh/config.d/* keeps work.conf, lab.conf, and personal.conf apart. The main file holds Host * defaults. Directory order is lexical, so name files 10-work.conf if you care which alias wins. Never commit private keys. HostName values and usernames are inventory: useful, slightly sensitive, not a public gist.

A short takeaway: aliases give you names, IdentitiesOnly gives you a single key per name, and ProxyJump gives you a private fleet behind one public box. That is the whole client map. You can spin up an Ubuntu 24.04 jump host on Netbay in under 60 seconds and follow along — netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance