SecurityDecember 2, 20257 min read

How to Sync SSH Keys Across Machines Without Compromising Security

SSH keys are the backbone of secure development workflows. Here's how to sync them across machines without ever exposing your private keys.

The Problem: One Machine Has Your Keys, the Others Don't

You generate an SSH key pair on your primary laptop. You add the public key to GitHub, your staging server, and a handful of cloud instances. Everything works. Then you sit down at your work desktop — or a new MacBook — and you are locked out of everything.

The common workarounds are all bad. Copying keys via USB drive means an unencrypted private key sitting on a physical device you could lose. Emailing them to yourself puts your private key in plaintext on Google's servers, your company's email archive, and every device where that email syncs. Pasting them into Slack is even worse — those messages are searchable, retained, and accessible to every workspace admin.

You could generate a new key pair on each machine and add every public key to every server. That works until you have three laptops, a desktop, and a cloud dev box. Now you are managing fifteen authorized_keys entries across five servers, and revoking access for a single machine means tracking down which key belongs to which device.

Why SSH Keys Should Never Live in a Git Repo

Some developers put their entire ~/.ssh directory in a dotfiles repo. This is a serious security mistake, even in a private repository. Git stores every version of every file forever. If your private key is committed even once, it exists in the repository history permanently. Running git rm only removes it from the working tree — the blob remains in the object store.

Private repositories are not as private as they seem. Anyone with read access — current teammates, CI systems, future employees — can clone the repo and extract every SSH key you have ever committed. A single compromised account with repo access exposes every key in history.

Rule of thumb: if a file grants access to systems, it does not belong in version control. Not in plaintext, not even in a private repo.

The ConfigSync Approach: Encrypted SSH Module

ConfigSync treats SSH keys as a first-class module. When you add the SSH module, it auto-detects your key pairs, config file, and known_hosts. Private keys are encrypted with AES-256-GCM before they leave your machine. Public keys are synced unencrypted since they are designed to be shared.

Add the SSH module
# Auto-detect and track all SSH assets $ configsync add module ssh Detected SSH assets: ~/.ssh/id_ed25519 (private key, will be encrypted) ~/.ssh/id_ed25519.pub (public key, unencrypted) ~/.ssh/id_rsa (private key, will be encrypted) ~/.ssh/id_rsa.pub (public key, unencrypted) ~/.ssh/config (will be encrypted) ~/.ssh/known_hosts (unencrypted) Added ssh module with 6 files.

The module intelligently classifies each file. Private keys and your SSH config (which may contain hostnames, usernames, and proxy commands) are encrypted. Public keys and known_hosts are synced in plaintext because they contain no secrets.

The Workflow: Push, Pull, Done

Once the module is added, syncing SSH keys follows the same push/pull workflow as everything else in ConfigSync:

Push from your primary machine
$ configsync push --filter ssh Encrypting private keys... ✓ ~/.ssh/id_ed25519 (AES-256-GCM, encrypted) ✓ ~/.ssh/id_rsa (AES-256-GCM, encrypted) ✓ ~/.ssh/config (AES-256-GCM, encrypted) ✓ ~/.ssh/id_ed25519.pub (unencrypted) ✓ ~/.ssh/id_rsa.pub (unencrypted) ✓ ~/.ssh/known_hosts (unencrypted) Pushed ssh module (6 files).
Pull on your new machine
$ configsync pull --filter ssh Restoring SSH assets... ✓ ~/.ssh/id_ed25519 (decrypted, permissions: 0600) ✓ ~/.ssh/id_rsa (decrypted, permissions: 0600) ✓ ~/.ssh/config (decrypted, permissions: 0600) ✓ ~/.ssh/id_ed25519.pub (permissions: 0644) ✓ ~/.ssh/id_rsa.pub (permissions: 0644) ✓ ~/.ssh/known_hosts (permissions: 0644) Restored 6 SSH files with correct permissions.

File permissions are critical for SSH. OpenSSH refuses to use a private key with permissions more permissive than 0600. ConfigSync restores private keys to 0600 and public keys to 0644 automatically, so your keys work immediately after pulling.

Key Rotation Made Simple

When you rotate SSH keys — whether on a schedule or because a key was compromised — the workflow is straightforward. Generate your new keys, then push. ConfigSync's snapshot history retains previous versions, so you can roll back if needed.

Rotate and push
# Generate a new key $ ssh-keygen -t ed25519 -C "sean@newkey" # Push the updated module $ configsync push --filter ssh ✓ Snapshot saved (previous version retained in history) ✓ 6 files pushed. # On other machines, pull the new keys $ configsync pull --filter ssh ✓ Updated ~/.ssh/id_ed25519 (new key detected)

Old key versions remain in your encrypted snapshot history. If you need to access a server that still has the old public key authorized, you can restore a previous snapshot while you update the server-side authorized_keys.

Bonus: SSH Config Templates with Variables

Different machines often need slightly different SSH configurations. Your work laptop routes through a corporate proxy, your home machine connects directly, and your cloud dev box uses different identity files. ConfigSync supports template variables in SSH config:

SSH config with template variables
# ~/.ssh/config (with ConfigSync template vars) Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519 Host staging HostName {{STAGING_HOST}} User {{DEPLOY_USER}} ProxyJump {{PROXY_HOST}} IdentityFile ~/.ssh/id_ed25519 Host production HostName {{PROD_HOST}} User {{DEPLOY_USER}} IdentityFile ~/.ssh/id_ed25519
Set machine-specific variables
# On your work laptop $ configsync config set vars.PROXY_HOST proxy.corp.example.com $ configsync config set vars.STAGING_HOST 10.0.1.50 # On your home machine $ configsync config set vars.PROXY_HOST "" $ configsync config set vars.STAGING_HOST staging.example.com

Template variables are resolved at pull time, so a single SSH config file adapts to each machine's network environment. The template itself is encrypted and synced; the variable values are stored locally on each machine.

Stop Copying Keys Through Insecure Channels

SSH keys grant access to your servers, your repositories, and your infrastructure. They deserve better than being pasted into chat messages or copied onto USB drives. ConfigSync gives you a secure, repeatable workflow: encrypt locally, sync through the cloud, decrypt on authorized machines, and restore with correct permissions every time.

Get started in 30 seconds
$ npm install -g configsync $ configsync login $ configsync add module ssh $ configsync push

Ready to try ConfigSync?

Sync your entire dev environment across machines in minutes. Free forever for up to 3 devices.