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.comandgithub-workboth point at the realgithub.com— they just present different keys. IdentitiesOnly yestells SSH to offer only the key named inIdentityFile, 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:
- Git reads the project’s remote URL (
git@github-work:...). - Git hands the connection to your system’s SSH client, which searches
~/.ssh/configfor a matchingHost github-workblock. - SSH transparently connects to the real
github.comwhile signing the authentication challenge with the key from that block’sIdentityFile.
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:
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/configcombining all your hosts - An
ssh -Tconnection 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/confighost aliases to map each key to each service; it’s the layer that works for every editor and terminal. - Always add
IdentitiesOnly yeswhen juggling multiple accounts on the same host. - Pair the alias with
git config --localso both the authentication and the author identity match the account. - Use the SSH Config Generator to build all of it without memorizing the syntax.