SSH keys are one of the most common ways to authenticate securely to Linux servers, Git hosts, and automation systems. Compared to passwords, they are more resistant to guessing attacks and much easier to automate safely.
For DevOps work, SSH keys are everywhere: server access, Git operations, CI deployments, bastion hosts, and remote automation.
SSH key authentication is based on a public/private key pair.
When you connect, the server checks whether your public key is trusted and then proves that your client holds the matching private key.
The private key should never be copied casually between machines or committed to source control.
ssh-keygenThe recommended modern key type for most users is ed25519.
ssh-keygen -t ed25519 -C "devops@example.com"You will normally be asked:
A passphrase protects the private key at rest. If someone copies your key file, the passphrase adds an extra barrier.
Example custom filename:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_work -C "work key"Tip: Use separate keys for different environments when you need better isolation, such as work, personal, and production access.
The server stores trusted public keys in:
~/.ssh/authorized_keysA convenient way to copy your key is:
ssh-copy-id devops@server.example.comThat appends your public key to the remote authorized_keys file.
You can also do it manually by copying the contents of your .pub file.
cat ~/.ssh/id_ed25519.pubThen paste that public key into ~/.ssh/authorized_keys on the server.
SSH is strict about permissions because weak permissions can expose keys.
Typical secure settings are:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pubIf permissions are too open, SSH may refuse to use the files.
Note: Permission problems are a very common reason key authentication fails even when the key content itself is correct.
~/.ssh/configThe SSH client config file lets you define shortcuts and per-host settings.
Example:
Host prod-web
HostName server.example.com
User devops
Port 2222
IdentityFile ~/.ssh/id_ed25519_workAfter this, you can connect with:
ssh prod-webUseful options in ~/.ssh/config include:
Host for the aliasHostName for the real server name or IPUser for the login accountPort for non-default SSH portsIdentityFile for selecting a specific keyThis keeps complex SSH commands out of your memory and scripts.
ssh-agent and ssh-addIf your private key has a passphrase, entering it every time can be inconvenient. ssh-agent stores unlocked keys in memory for the session.
Start or use the agent, then add a key:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -lNow SSH can use the unlocked key without prompting for the passphrase on every connection.
Agent forwarding lets a remote host use your local SSH agent to authenticate to another host without copying your private key to the first server.
Example:
ssh -A bastion.example.comThis is useful in jump-host workflows, but it should be enabled carefully. If the intermediate host is compromised, agent forwarding can increase risk.
Only use it where you trust the systems involved.
A typical first-time setup looks like this:
ssh-keygen -t ed25519 -C "devops@example.com"
ssh-copy-id devops@server.example.com
ssh devops@server.example.comIf the login fails, check:
authorized_keys~/.ssh and key files have safe permissionsFor noisy debugging, SSH can show details:
ssh -v devops@server.example.comSSH keys work by matching a local private key with a trusted public key on the server. Generate modern keys with ssh-keygen, protect them with a passphrase, use authorized_keys correctly, and simplify repeated connections with ~/.ssh/config and ssh-agent.
Once this workflow feels natural, remote Linux access becomes faster and more secure.
<MCQExercise
exercise={{
id: "linux-ssh-keys-q1",
title: "Exercise 1: Public versus private key",
description: "Which file should stay secret on your local machine?",
options: [
{ id: "a", text: "The public key file such as id_ed25519.pub" },
{ id: "b", text: "The private key file such as id_ed25519" },
{ id: "c", text: "The remote authorized_keys file contents after login" },
{ id: "d", text: "The /etc/hosts file" },
],
correctId: "b",
explanation: "The private key proves your identity and must remain protected on the client side. The public key is the shareable half that can be placed on servers.",
wrongExplanations: {
a: "The public key is designed to be shared with servers and services.",
c: "authorized_keys stores public keys, not the private secret used for authentication.",
d: "/etc/hosts is unrelated to SSH key secrecy.",
},
}}
/>
<MCQExercise
exercise={{
id: "linux-ssh-keys-q2",
title: "Exercise 2: Copying a key to a server",
description: "Which command conveniently installs your public key into a remote user's authorized_keys file?",
options: [
{ id: "a", text: "ssh-copy-id devops@server.example.com" },
{ id: "b", text: "scp ~/.ssh/id_ed25519 devops@server.example.com" },
{ id: "c", text: "chmod 777 ~/.ssh" },
{ id: "d", text: "journalctl -u sshd" },
],
correctId: "a",
explanation: "ssh-copy-id sends your public key to the remote server and appends it to the correct authorized_keys file. It is safer and easier than copying a private key or editing blindly.",
wrongExplanations: {
b: "Copying the private key to a server is unsafe and is not how normal SSH key setup should work.",
c: "Loose permissions would create security problems and can even break SSH authentication.",
d: "journalctl reads logs and does not install keys.",
},
}}
/>
<MCQExercise
exercise={{
id: "linux-ssh-keys-q3",
title: "Exercise 3: SSH client shortcuts",
description: "What is the main benefit of entries in ~/.ssh/config?",
options: [
{ id: "a", text: "They replace the SSH server with a firewall" },
{ id: "b", text: "They define host aliases and per-host settings such as user, port, and key file" },
{ id: "c", text: "They rotate server logs automatically" },
{ id: "d", text: "They store Linux kernel modules" },
],
correctId: "b",
explanation: "~/.ssh/config lets you create short host aliases and remember settings like User, Port, and IdentityFile. That makes repeated SSH access much more convenient and less error-prone.",
wrongExplanations: {
a: "SSH client configuration does not replace the server or a firewall.",
c: "Log rotation is unrelated to SSH client config entries.",
d: "Kernel modules are managed elsewhere and have nothing to do with SSH aliases.",
},
}}
/>
SSH refuses to use a private key that other accounts on the machine can read, and simply stops rather than risking it. chmod 600 ~/.ssh/id_ed25519 fixes the key, chmod 700 ~/.ssh the directory, and chmod 644 is correct for the .pub file, which is public by design. On the server side, ~/.ssh/authorized_keys must be 600 and the user's home directory must not be group-writable, that last one is the cause of most "key is correct but login still fails" cases.
The private key stays on your machine and proves who you are; the public key is copied to every server you want to reach and can be shared freely. Authentication works by the server sending a challenge that only the matching private key can answer, so the private key never crosses the network, which is why it is safer than a password. ssh-copy-id user@host installs the public key into the server's authorized_keys. If you are ever asked to send a key, it is the .pub one.
Yes. Without one, anyone who obtains the file has your access to every server that trusts it, including from a stolen laptop or a backup. A passphrase encrypts the key at rest, and ssh-agent means you type it once per session rather than per connection: ssh-add ~/.ssh/id_ed25519, or on macOS ssh-add --apple-use-keychain to persist across reboots. Keys used by automation are the exception, and those should be separate, narrowly scoped keys rather than your personal one.
It stores per-host settings so you stop retyping them. A block such as Host prod with HostName 10.0.4.12, User deploy, Port 2222 and IdentityFile ~/.ssh/prod_ed25519 turns a long command into ssh prod, and scp, rsync and Git all honour it. It is also where you configure jump hosts with ProxyJump bastion, which is far cleaner than chaining SSH commands, and ServerAliveInterval 60 to stop idle sessions dropping.
Not entirely, and it is worth knowing why. ssh -A lets processes on the remote host use your agent to authenticate onward, which means root on that host, or anyone who compromises it, can use your key while you are connected. They cannot steal the key itself, but they can act as you for the duration. Prefer ProxyJump (ssh -J bastion target), which tunnels the connection without exposing the agent. If you must forward, do it per-host in ~/.ssh/config, never globally.
Set up a Linux firewall without locking yourself out: compare ufw, firewalld and iptables, allow SSH first, default deny, zones and persistent rules.
Find what went wrong in Linux logs: /var/log versus the systemd journal, tail -F over -f, grep filtering, logrotate, journald size caps and error triage.
Triage Linux performance in order: CPU, memory and I/O. Learn what load average counts, why free memory looks low and how to read iowait with vmstat.