ssh -i ~/.ssh/id_ed25519 user@host connects using a specific private key, and it is the answer to the question everyone asks. It is also the answer you should stop using within a week. Typing -i on every connection means memorising which key goes with which host, and getting it wrong repeatedly. ~/.ssh/config maps hosts to keys once, and then ssh myserver just works. Learn the flag, then immediately graduate past it.
Table of contents
- The flag, and the permission error you will hit
- Stop typing -i: use ~/.ssh/config
- Getting the public key onto the server
- When the key is refused and you cannot see why
- Use an agent, and stop retyping the passphrase
- How this fits the rest of the stack
- FAQ
The flag, and the permission error you will hit
ssh -i ~/.ssh/id_ed25519 [email protected]
-i (identity file) points at the private key - the one without the .pub extension. The public half lives on the server in ~/.ssh/authorized_keys; the private half never leaves your machine.
And here is the error you will hit within about thirty seconds:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for 'id_ed25519' are too open.
This private key will be ignored.
SSH refuses to use a private key that other users on the machine can read. It is not being fussy - a world-readable private key is a key you should assume is compromised.
chmod 600 ~/.ssh/id_ed25519
chmod 700 ~/.ssh
This is the single most common SSH key failure, and it comes up constantly after copying a key from another machine, unzipping one from a cloud provider, or moving one across a filesystem that does not preserve permissions - which is why keys copied through Windows or a USB stick nearly always need this.
Stop typing -i: use ~/.ssh/config
The flag does not scale. Three servers with three different keys, and you are now maintaining a mental map and getting it wrong.
Create ~/.ssh/config:
Host prod
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/prod_ed25519
IdentitiesOnly yes
Host staging
HostName 203.0.113.20
User deploy
IdentityFile ~/.ssh/staging_ed25519
IdentitiesOnly yes
Port 2222
Host github.com
IdentityFile ~/.ssh/github_ed25519
IdentitiesOnly yes
Now:
ssh prod
That is the whole thing. Right key, right user, right port, right host.
IdentitiesOnly yes is not optional and it is the setting almost everyone omits. Without it, SSH offers every key it knows about - every key in ~/.ssh, plus everything loaded into your agent - before trying the one you specified. Servers commonly cap authentication attempts at six, so if you have seven keys, you can be rejected with Too many authentication failures while holding a perfectly valid key it never got around to offering. IdentitiesOnly yes tells SSH to offer only the key named in this block.
And scp, rsync, and git all read this file too. Configure it once, and everything that speaks SSH inherits it.
Getting the public key onto the server
The private key is useless until the server trusts its public half.
The easy way:
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]
Note the .pub. This is the one place you use the public key, and copying the private key to a server is a mistake that ends careers.
ssh-copy-id appends it to ~/.ssh/authorized_keys on the server and fixes the permissions there. It needs an existing way in - a password, or another working key.
By hand, if ssh-copy-id is not available:
cat ~/.ssh/id_ed25519.pub | ssh deploy@host \
"mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
The permissions in that command are the point. On the server, ~/.ssh must be 700 and authorized_keys must be 600, and the home directory itself must not be group-writable. sshd checks all of this and silently refuses the key if any of it is wrong - logging the reason only on the server side, where you cannot see it, which is why this failure is so opaque from the client.
When the key is refused and you cannot see why
Public key authentication fails and the client tells you nothing useful. Turn on verbosity:
ssh -vvv -i ~/.ssh/id_ed25519 deploy@host
The lines that matter:
debug1: Offering public key: /home/me/.ssh/id_ed25519 ED25519 SHA256:abc...
debug1: Authentications that can continue: publickey,password
debug1: Trying private key: /home/me/.ssh/id_rsa
If you see your key offered and the server still moves on, the key is not in authorized_keys on the server, or the permissions on the server side are wrong.
If your key is never offered, the client is not using it - wrong path, or SSH exhausted its attempts on other keys first (which IdentitiesOnly yes fixes).
The checklist, in order:
- Client-side key file is
600, and~/.sshis700. - Server-side
~/.sshis700,authorized_keysis600, and the home directory is not group-writable. - The public key in
authorized_keysis on one line, complete, and not mangled by a copy-paste that inserted line breaks. - The username is right - keys are per-user, and
authorized_keysfordeploydoes nothing forubuntu. sshd_confighasPubkeyAuthentication yes.
If you have server access, sudo journalctl -u ssh -n 50 after a failed attempt tells you exactly what sshd objected to. That log is where the real answer lives, and the client is deliberately vague to avoid leaking information to attackers.
Use an agent, and stop retyping the passphrase
A private key should have a passphrase - it is the only thing protecting you if the file is ever stolen. But typing it on every connection is miserable, and misery leads people to create keys with no passphrase at all.
The agent solves this. Unlock the key once per session:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
On macOS, persist it into the keychain so it survives a reboot:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Worth knowing what you have traded: the agent will now sign anything, for any process running as your user, with no prompt. That is convenient, and it is also a real attack surface - a malicious dependency does not need to steal your key file, it just asks the agent nicely. If the key can reach production, that is a good reason to look at a hardware key or a vault-backed agent that requires confirmation for each use.
And one habit worth keeping: ssh -A (agent forwarding) exposes your agent to the remote host, where root can use it to authenticate as you. Do not forward your agent to machines you do not fully control. Use ProxyJump instead - it is what you actually wanted, and it does not hand your keys to a box you are just passing through.
How this fits the rest of the stack
Whatever you decide here, the cost of the decision only shows up as a bill. The RunxBuild hosting calculator is the right place to model that before committing: the compute, the database, the storage, the bandwidth, the worker - each one is a separate line item, and the real cost of a platform is the sum, not the headline number. The RunxBuild dashboard is where the team sees the actual usage once it is running.
Useful related references:
- SSH Permission Denied: The Six Things to Check First
- SSH Specify Key: IdentityFile, -i, and the Right Defaults
- Windows Make SSH Key: PowerShell, CMD, and the Right Defaults
- Services on RunxBuild
FAQ
How do I SSH using a private key?
ssh -i /path/to/private_key user@host, pointing at the private key (no .pub extension). Better: put the key in ~/.ssh/config against the host with IdentityFile, so you can just run ssh myserver and everything - including scp, rsync and git - picks it up automatically.
Why does SSH say my private key permissions are too open?
SSH refuses to use a private key that other users can read, because a world-readable key should be treated as compromised. Run chmod 600 on the key and chmod 700 on ~/.ssh. This is the most common failure after copying a key from another machine or a filesystem that does not preserve permissions.
What does IdentitiesOnly yes do?
It tells SSH to offer only the key named in that config block, instead of every key it knows about. Without it, SSH may burn through the server’s authentication attempt limit (usually six) offering other keys and get rejected with Too many authentication failures while holding a perfectly valid key.
Why is my SSH key rejected even though it is in authorized_keys?
Usually permissions on the server side - ~/.ssh must be 700, authorized_keys must be 600, and the home directory must not be group-writable. sshd silently refuses the key otherwise. Run ssh -vvv to see whether the key is even being offered, and check the server’s journalctl for the real reason.
Is ssh -A agent forwarding safe?
Not to machines you do not fully control. Forwarding exposes your agent to the remote host, where root can use it to authenticate as you anywhere your keys work. Use ProxyJump instead when you are just passing through a bastion - it achieves the same thing without handing over your keys.