trevorblackman.dev

Blog

Organizing SSH Keys and Taming Multiple Git Accounts

July 7, 2026

How organizing SSH keys into per-service folders led me to SSH config host aliases, and a new tool that generates the config and per-project git commands for you.

I recently started organizing my SSH keys into named folders, one per service, and I wish I had thought of this years ago. Instead of a ~/.ssh directory full of cryptically named id_rsa_2, id_ed25519_new, and key-final-really files, everything now lives in a folder that tells me exactly what it’s for:

~/.ssh/github/keys
~/.ssh/aws/keys
~/.ssh/other-github-account/keys

One glance and I know which key belongs to which service. No more guessing, no more ssh-keygen -lf archaeology to figure out what a key unlocks.

The new problem the folders created

The folder structure solved storage, but it immediately surfaced the next problem: how do I tell each project which key to use?

If you have one GitHub account, SSH quietly uses your default key and everything just works. The moment you add a second GitHub account (work vs. personal), or an AWS CodeCommit repo, the default behavior falls apart. GitHub identifies you by the key you present — so if SSH offers the wrong key first, you’re suddenly pushing as the wrong account, or getting Permission denied (publickey) on a repo you absolutely have access to.

My first instinct was to look for a setting in VS Code to pin a key per project. That’s a dead end: you cannot configure SSH key locations natively within individual VS Code settings. The standard — and, it turns out, most robust — solution lives one layer down, in your system’s SSH client: the ~/.ssh/config file.

Step 1: Map keys to host aliases in ~/.ssh/config

Open (or create) ~/.ssh/config and add a Host block for each account or use case, mapping a unique alias to its private key:

# Main/Personal GitHub Account
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/github/keys/id_ed25519
    IdentitiesOnly yes

# AWS CodeCommit (or AWS server)
Host aws-backbone
    HostName git-codecommit.us-east-1.amazonaws.com
    User Your-AWS-SSH-Key-ID
    IdentityFile ~/.ssh/aws/keys/id_rsa
    IdentitiesOnly yes

# Second GitHub Account (e.g., Work or Personal Alt)
Host github-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/other-github-account/keys/id_ed25519
    IdentitiesOnly yes

Two things worth calling out:

  • The Host line is an alias you invent; the HostName line is the real server SSH connects to. Notice that github.com and github-work both point at the real github.com — they just present different keys.
  • IdentitiesOnly yes tells SSH to offer only the key named in IdentityFile, even if your ssh-agent is holding others. Without it, the agent may present your personal key before your work key, and GitHub will happily log you in as the wrong account. This one line prevents an entire category of confusing auth failures.

Using the real domain as the alias (like the first block) makes that key the default for every github.com URL — perfect for your primary account. Custom aliases like github-work are opt-in per repository.

Step 2: Point each project at the right alias

For any repository that should use a non-default key, update its remote URL to use the alias instead of the real domain:

# 1. Verify your current remote URL
git remote -v

# 2. Update the remote URL to use the specific host alias
git remote set-url origin git@github-work:username/repo-name.git

Note how github.com is replaced by github-work in the SSH URL. That’s the entire trick — the alias in the URL is what routes the connection through the right Host block, and therefore the right key.

You can verify the whole chain works with:

ssh -T git@github-work

Step 3: Pin the commit identity per project

Choosing the right key solves authentication, but commits carry their own author info. To avoid committing to a work repo with your personal email (or vice-versa), set the identity locally in each repository:

git config --local user.name "Your Name"
git config --local user.email "work-email@company.com"

The --local flag scopes this strictly to the current repository, overriding your global defaults. Between the host alias and the local identity, a work repo is now fully isolated from your personal setup.

How it works under the hood

Once everything is wired up, every git command — whether from the terminal or VS Code’s source control UI — resolves the same way:

  1. Git reads the project’s remote URL (git@github-work:...).
  2. Git hands the connection to your system’s SSH client, which searches ~/.ssh/config for a matching Host github-work block.
  3. SSH transparently connects to the real github.com while signing the authentication challenge with the key from that block’s IdentityFile.

No per-editor settings, no environment variables, no wrapper scripts. The SSH client does the routing, so it works identically everywhere.

I built a tool for this

Writing these blocks by hand is fine once, but I kept wanting to add hosts, double-check flag placement, and regenerate the per-project commands. So I built a small browser tool:

SSH Config Generator →

You describe each host once — the alias, the real hostname, the user, the path to the key, and the commit identity you want on every repo there — and it generates:

  • A complete, ready-to-paste ~/.ssh/config combining all your hosts
  • An ssh -T connection test for each alias

Each host also has a throwaway Projects area. Whenever you spin up a new repo under that account, you just paste its browser URL — a GitHub link, a GitLab link, or an Azure DevOps /_git/ link — and it hands back a single copy/paste-and-run block that repoints the project’s origin at the right alias and pins the local commit identity in one shot:

git remote set-url origin git@github-work:username/repo-name.git
git config --local user.name "Your Name"
git config --local user.email "work-email@company.com"

Your hosts and keys are saved in the browser so they’re there next time; the project URLs are deliberately not saved, because they change every time you sit down to wire up a new repo. It also warns you about duplicate aliases (SSH only ever matches the first one), and nothing is sent anywhere.

Takeaways

  • Organize keys into per-service folders like ~/.ssh/github/keys — future you will thank present you.
  • Use ~/.ssh/config host aliases to map each key to each service; it’s the layer that works for every editor and terminal.
  • Always add IdentitiesOnly yes when juggling multiple accounts on the same host.
  • Pair the alias with git config --local so both the authentication and the author identity match the account.
  • Use the SSH Config Generator to build all of it without memorizing the syntax.