Skip to main content

Managing SSH Connections with ~/.ssh/config

··5 mins·
Makoto Morinaga
Author
Makoto Morinaga
A personal notebook for tech notes, coding, and system experiments.
Table of Contents

Using ~/.ssh/config simplifies SSH connections, eliminating the need to remember and type lengthy commands for each server. By configuring host aliases, specifying usernames, defining ports, and managing SSH keys, access to multiple servers becomes more convenient and efficient.

Creating the Config File
#

If SSH key authentication is already set up, the ~/.ssh directory should exist. Otherwise, create it as follows.

Verify if the ~/.ssh directory exists
#

Terminal
ls -la

If ~/.ssh does not exist, create it and set the appropriate permissions:

Terminal
mkdir ~/.ssh
chmod 700 ~/.ssh

Create the ~/.ssh/config file
#

Terminal
touch ~/.ssh/config

Editing ~/.ssh/config
#

Next, add server connection details to ~/.ssh/config. A typical configuration looks like this:

~/.ssh/config
# Server A
Host serverA
    HostName example.com
    Port 22
    User makoto
    IdentityFile ~/.ssh/serverA.key

# Server B
Host serverB
    HostName 192.168.1.10
    Port 50134
    User makoto
    IdentityFile ~/.ssh/serverB.key

# Server C
Host serverC
    HostName test-server.com
    Port 48912
    User makoto

Understanding Key Parameters
#

Parameter Description
Host Alias for the server (used in SSH commands)
HostName Server domain name or IP address
Port SSH port (default: 22)
User SSH login username
IdentityFile Path to the private key (for key authentication)

Additional parameters can be configured as needed, but these are the most essential ones.

Connecting to Servers
#

Once the ~/.ssh/config file is set up, connecting to a server is as simple as using the alias defined in the Host field.

To connect to Server A:

Terminal
ssh serverA

To connect to Server B:

Terminal
ssh serverB

To connect to Server C:

Terminal
ssh serverC

Additional Useful SSH Config Parameters
#

Beyond the basics, several advanced options further improve usability and security.

Forwarding GPG Agent via RemoteForward
#

RemoteForward forwards a local Unix socket to the remote host, enabling remote operations such as git commit -S without copying private keys.

Important
#

  • For Unix-domain socket forwarding with RemoteForward, the first path is on the remote host and the second path is on the local machine.
  • For RemoteForward, stale socket cleanup on the remote side requires StreamLocalBindUnlink yes in the remote server’s sshd_config
  • Socket paths differ between Linux and macOS

Socket paths
#

Typical socket paths:

Environment Socket example
Linux (systemd) /run/user/<UID>/gnupg/S.gpg-agent
macOS (GPGTools / brew) /Users/<username>/.gnupg/S.gpg-agent

Check your socket path:

Terminal
ls -l /run/user/$(id -u)/gnupg/ 2>/dev/null
ls -l ~/.gnupg/ 2>/dev/null

Example: macOS → Linux remote
#

~/.ssh/config
Host remote-with-gpg
    HostName dev.example.com
    User makoto
    RemoteForward /run/user/1000/gnupg/S.gpg-agent /Users/makoto/.gnupg/S.gpg-agent

Server-side configuration note
#

If the remote socket path already exists, configure StreamLocalBindUnlink yes on the remote server side. This lets sshd remove the existing socket before binding, avoiding:

shell
bind: Address already in use
channel_setup_fwd_listener: cannot listen to path ...

This setup allows signing or SSH authentication remotely while keeping private keys local.

StreamLocalBindUnlink applies on the side that creates, or binds, the Unix-domain socket. For LocalForward, the socket is created by the local SSH client, so the option is configured in the client-side ~/.ssh/config. For RemoteForward, the socket is created by the remote sshd, so stale socket cleanup on the remote side requires the option to be configured in /etc/ssh/sshd_config.

/etc/ssh/sshd_config
# /etc/ssh/sshd_config
StreamLocalBindUnlink yes

After updating the server configuration, reload or restart the SSH daemon:

Terminal
sudo systemctl restart sshd
# or depending on the distribution
sudo systemctl restart ssh

In short, for RemoteForward, setting StreamLocalBindUnlink yes in the client-side ~/.ssh/config does not clean up the remote socket. The option must be enabled on the remote server side.

Selecting Only the Intended Key with IdentitiesOnly
#

When multiple keys are loaded, SSH may attempt them all, leading to authentication failures. IdentitiesOnly yes forces SSH to use only the key specified for that host.

~/.ssh/config
Host serverA
    HostName example.com
    User makoto
    IdentityFile ~/.ssh/serverA.key
    IdentitiesOnly yes

This option is recommended when multiple SSH or GPG keys are in use.

Connecting Through a Jump Host with ProxyJump
#

ProxyJump allows connecting to a target server through an intermediate host (bastion), without chaining commands manually.

~/.ssh/config
Host bastion
    HostName bastion.example.com
    User makoto

Host internal-server
    HostName 10.0.0.50
    User makoto
    ProxyJump bastion

After setting this up:

Terminal
ssh internal-server

SSH automatically routes through the bastion server.

Tunneling Local Ports with LocalForward
#

LocalForward creates an encrypted tunnel from a local port to a remote service. This is useful for securely accessing internal services such as databases or dashboards.

~/.ssh/config
Host db-server
    HostName internal-db.example.com
    User makoto
    LocalForward 15432 127.0.0.1:5432

After connecting:

Terminal
ssh db-server
psql -h localhost -p 15432

Typical use cases include:

  • accessing internal PostgreSQL / MySQL
  • accessing private development services locally
  • viewing dashboards without exposing them publicly

Sharing Common Settings with Host *
#

To avoid repeating configuration values across multiple hosts, you can define shared defaults using Host *. Settings under this section apply to all hosts unless overridden later.

~/.ssh/config
# Shared defaults
Host *
    IdentitiesOnly yes
    ServerAliveInterval 30
    AddKeysToAgent yes

Note on configuration order
#

SSH evaluates patterns in the order they appear in the file. Because Host * matches every host, placing it too early can unintentionally override settings that were meant to apply only to specific hosts.

Here’s an example of a recommended structure:

~/.ssh/config
# Specific hosts first

Host bastion
User makoto
IdentityFile ~/.ssh/bastion.key

# Shared defaults afterwards

Host *
IdentitiesOnly yes
ServerAliveInterval 30

Note on pattern matching
#

Host patterns use shell-style wildcards, meaning they match partial names as well, not just exact matches. This makes selective grouping possible, for example:

~/.ssh/config
# Matches any name ending in "-test"
Host *-test
User tester
IdentityFile ~/.ssh/test.key

# Matches hosts starting with "db"
Host db*
LocalForward 15432 127.0.0.1:5432

# Matches everything
Host *
IdentitiesOnly yes

Pattern matching is powerful, but be aware of how it interacts with ordering. For example, the pattern *-test matches hosts such as qa-test, prod-test, and test-test.

Likewise, a definition like Host server should generally appear before Host * so that host-specific settings are matched first.

Understanding both glob-style pattern matching and order-based precedence is essential when managing many hosts. Getting this right allows you to avoid duplication, apply consistent defaults, and selectively override only where necessary.

Summary of Advanced Parameters
#

Parameter Purpose
RemoteForward Forward local agent/socket to remote host
StreamLocalBindUnlink Remove stale Unix-domain socket before binding; configure it on the side that binds the socket
IdentitiesOnly Use only the specified key
ProxyJump Connect via a bastion/jump host
LocalForward Access remote services through local ports
Host * Define shared defaults; order and patterns matter

Related