| |

LFCS 113 ๐Ÿง SSH Keys โ€” Generating and Deploying

โฑ๏ธ Estimated read: 10 min | |

The previous chapters configured the SSH server to accept key-based authentication and reject passwords. This chapter covers the client side: generating a key pair, deploying the public key to the server’s authorized_keys file, and fixing the permission errors that cause key authentication to fail silently. The LFCS exam tests the workflow and the specific permission requirements. The most common failure is not a wrong keyโ€”it is a wrong permission on the .ssh directory or the authorized_keys file. OpenSSH refuses to use a key if the permissions are too permissive, and the error message (Permission denied (publickey)) does not indicate that the cause is a permission issue.

Key point: The private key stays on the client, with permissions 600. The public key goes to the server’s ~/.ssh/authorized_keys, which must also be 600. The .ssh directory on both sides must be 700. A home directory that is group-writable will also cause key authentication to fail.


Why key deployment requires precise permissions

The silent failure problem. OpenSSH checks the permissions of the .ssh directory, the private key, and the authorized_keys file before attempting authentication. If any of these are accessible to group or other users, the key is ignored. The server does not report “your authorized_keys is too permissive.” It reports “Permission denied (publickey),” which sends the administrator looking for a key mismatch that does not exist .

The private key protection problem. The private key is the credential. If it is readable by another user on the client machine, that user can authenticate as the key’s owner. The 600 permission on the private key ensures that only the owner can read it. The public key (644) is safe to share because it cannot be used to derive the private key .

The deployment problem. The public key must be appended to the server’s ~/.ssh/authorized_keys. The file can contain multiple keys, one per line. If the file does not exist, it must be created with the correct permissions before the key is added. If the file exists but has the wrong permissions, the key is ignored even if it is present .

The algorithm problem. The default key algorithm in modern OpenSSH is ed25519. It is faster and more secure than RSA at equivalent key sizes. RSA is still supported for compatibility with older systems, but the key size should be at least 4096 bits. The exam may ask for the command to generate an ed25519 key or an RSA key .

The trade-off. Keys without a passphrase are convenientโ€”they authenticate without any prompt. Keys with a passphrase are more secureโ€”a stolen private key is useless without the passphrase. The ssh-agent caches the passphrase for a session, so the user types it once and the agent handles the rest. The exam tests the generation and deployment, not the agent configuration, but the passphrase is the security layer that makes the private key worth protecting.


a. Generating the key pair

The ssh-keygen command generates the key pair. The -t flag specifies the algorithm. The -b flag specifies the bit size for RSA. The -C flag adds a comment (typically the email address) for identification.

# Generate an ED25519 key (preferred)
ssh-keygen -t ed25519 -C "user@example.com"

# Generate an RSA key (for compatibility)
ssh-keygen -t rsa -b 4096 -C "user@example.com"

The command prompts for three things: the file path (default ~/.ssh/id_ed25519 or ~/.ssh/id_rsa), the passphrase (empty for no passphrase), and the confirmation of the passphrase. The private key is written to the specified path. The public key is written to the same path with a .pub extension .

# Default output paths for ED25519
~/.ssh/id_ed25519       # Private key
~/.ssh/id_ed25519.pub   # Public key

The private key must not be shared. The public key is the file that will be deployed to the server.


b. Deploying the public key with ssh-copy-id

The ssh-copy-id command automates the deployment. It logs into the remote server (using password authentication, which must still be enabled), creates the ~/.ssh directory if it does not exist, and appends the public key to ~/.ssh/authorized_keys .

# Deploy the default key
ssh-copy-id user@server

# Deploy a specific key
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server

The -i flag specifies the public key file. If omitted, ssh-copy-id uses the default identity file or the keys loaded in the agent. The command prompts for the remote user’s password, then installs the key .

After deployment, the authorized_keys file on the server contains the public key. The file permissions are set by ssh-copy-id, but they should be verified.

# Verify the key is present
ssh user@server "cat ~/.ssh/authorized_keys"

# Verify permissions
ssh user@server "ls -la ~/.ssh/authorized_keys"
# Expected: -rw------- (600)

c. Manual deployment and permission correction

If ssh-copy-id is unavailable, the public key can be appended manually. The cat command reads the local public key, pipes it over SSH, and appends it to the remote authorized_keys.

# Manual deployment
cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

This works, but it does not set the permissions. The .ssh directory and the authorized_keys file must be corrected manually.

# Fix permissions on the server
ssh user@server "chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"

The correct permissions are mandatory. The .ssh directory must be 700 (read, write, execute for the owner only). The authorized_keys file must be 600 (read and write for the owner only). The private key on the client must be 600. The public key can be 644 .

The home directory permissions are also checked. If the home directory is group-writable (e.g., 775), OpenSSH refuses key authentication. The home directory should be 700 or 750 .


Complete Example Session

# ============================================
# PART 1: GENERATE THE KEY PAIR
# ============================================

ssh-keygen -t ed25519 -C "admin@example.com"
# Enter file in which to save the key: (Enter)
# Enter passphrase: (Enter for no passphrase)
# Enter same passphrase again: (Enter)
# Your identification has been saved in ~/.ssh/id_ed25519
# Your public key has been saved in ~/.ssh/id_ed25519.pub
# ============================================
# PART 2: VERIFY THE KEY FILES
# ============================================

ls -la ~/.ssh/id_ed25519*
# -rw-------  id_ed25519
# -rw-r--r--  id_ed25519.pub
# ============================================
# PART 3: DEPLOY THE PUBLIC KEY
# ============================================

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
# Password prompt: enter the remote user's password
# Number of key(s) added: 1
# ============================================
# PART 4: TEST KEY AUTHENTICATION
# ============================================

ssh user@server
# Login succeeds without a password prompt.
# ============================================
# PART 5: VERIFY SERVER-SIDE PERMISSIONS
# ============================================

ssh user@server "ls -la ~/.ssh/"
# drwx------  .ssh
# -rw-------  authorized_keys
# ============================================
# PART 6: FIX PERMISSIONS IF NEEDED
# ============================================

ssh user@server "chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"
# ============================================
# PART 7: MANUAL DEPLOYMENT (ALTERNATIVE)
# ============================================

cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
ssh user@server "chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"
# ============================================
# PART 8: VERIFY THE PUBLIC KEY ON SERVER
# ============================================

ssh user@server "cat ~/.ssh/authorized_keys"
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... admin@example.com
# ============================================
# PART 9: TROUBLESHOOT FAILURE
# ============================================

ssh -v user@server
# Look for "Offering public key: ~/.ssh/id_ed25519"
# If the server rejects it, check permissions on both sides.

The nine parts trace the key lifecycle: generation, file verification, deployment with ssh-copy-id, authentication test, server-side permission check, permission correction, manual deployment, key verification, and verbose troubleshooting.


Quick Reference

Key Generation

CommandAlgorithmDefault Path
ssh-keygen -t ed25519ED25519~/.ssh/id_ed25519
ssh-keygen -t rsa -b 4096RSA 4096~/.ssh/id_rsa

Deployment Commands

CommandPurpose
ssh-copy-id user@serverDeploy default key
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@serverDeploy specific key
cat ~/.ssh/id_ed25519.pub | ssh user@server "cat >> ~/.ssh/authorized_keys"Manual deployment

Permission Requirements

PathPermissionPurpose
~/.ssh700Directory, both sides
~/.ssh/id_ed25519600Private key, client only
~/.ssh/id_ed25519.pub644Public key, both sides
~/.ssh/authorized_keys600Server only
Home directory700 or 750Both sides, not group-writable

Best Practices

โœ… Do This:

ssh-keygen -t ed25519 -C "user@example.com"
<!-- Use ED25519 for new keys -->                     # โœ…
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
<!-- Deploy the public key -->                        # โœ…
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
<!-- Fix permissions on the server -->                # โœ…

โŒ Don’t Do This:

# Share or copy the private key
<!-- Private key stays on the client -->              # โŒ
# Leave authorized_keys at 644 or 664
<!-- OpenSSH ignores the key -->                      # โŒ
# Use RSA 2048 for new keys
<!-- Use ED25519 or RSA 4096 -->                      # โŒ

Common Pitfalls

PitfallWhy It HappensFix
Permission denied (publickey)Wrong permissions on .ssh or authorized_keyschmod 700 ~/.ssh, chmod 600 ~/.ssh/authorized_keys
Key ignoredHome directory group-writablechmod 700 ~ or chmod 750 ~
ssh-copy-id failsPassword auth disabled on serverTemporarily enable password auth
Key not foundWrong path or filenameUse -i with the correct path
Multiple keys conflictOld key in authorized_keysRemove the old key

Real-World Examples

1. Generate ED25519 Key

ssh-keygen -t ed25519 -C "user@example.com"

2. Generate RSA Key

ssh-keygen -t rsa -b 4096 -C "user@example.com"

3. Deploy with ssh-copy-id

ssh-copy-id user@server

4. Manual Deploy

cat ~/.ssh/id_ed25519.pub | ssh user@server "cat >> ~/.ssh/authorized_keys"

5. Fix Server Permissions

ssh user@server "chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"

6. Verify Key on Server

ssh user@server "cat ~/.ssh/authorized_keys"

7. Test Authentication

ssh user@server

8. Verbose Troubleshooting

ssh -v user@server

9. Check Private Key Permission

chmod 600 ~/.ssh/id_ed25519

10. Check Home Directory Permission

chmod 750 ~

Visual

Key Deployment Flow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  CLIENT                                      โ”‚
โ”‚  ~/.ssh/id_ed25519 (private, 600)            โ”‚
โ”‚  ~/.ssh/id_ed25519.pub (public, 644)         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ”‚ ssh-copy-id
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  SERVER                                      โ”‚
โ”‚  ~/.ssh/ (700)                               โ”‚
โ”‚  ~/.ssh/authorized_keys (600)                โ”‚
โ”‚  Contains the public key                     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ”‚ ssh user@server
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Server verifies signature with public key   โ”‚
โ”‚  Client proves possession of private key     โ”‚
โ”‚  Access granted, no password                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Permission Failure Path

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  authorized_keys is 644 (readable by others) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  OpenSSH refuses to use the key              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Server returns: Permission denied (publickey)โ”‚
โ”‚  The key is present but ignored.             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ”‚ chmod 600
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Key is accepted.                            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Key generationssh-keygen -t ed25519
RSA alternativessh-keygen -t rsa -b 4096
Deploymentssh-copy-id user@server
Manual deploymentcat key.pub | ssh user@server "cat >> ~/.ssh/authorized_keys"
Private key permission600
Public key permission644
.ssh directory700
authorized_keys600
Home directory700 or 750

Key takeaways:

  • The private key never leaves the client. The public key is deployed to the server’s authorized_keys. The private key is the credential and must be protected with 600 permissions .
  • ssh-copy-id automates deployment. It creates the .ssh directory and authorized_keys if needed, and appends the public key. Manual deployment requires setting the permissions afterward .
  • Permissions are mandatory. The .ssh directory must be 700, the authorized_keys file must be 600, and the home directory must not be group-writable. OpenSSH refuses to use keys with permissive permissions, and the error message does not indicate the cause .
  • ssh -v is the diagnostic tool. The verbose output shows which keys are offered and whether the server accepts them. If the key is offered but rejected, the problem is permissions or a key mismatch .
  • ED25519 is the preferred algorithm. It is faster and more secure than RSA at equivalent key sizes. RSA is supported for compatibility but should be at least 4096 bits .

Remember: The key deployment is a two-sided operation. The client generates the pair. The server stores the public key. The permissions on both sides determine whether the key is used. The private key is 600. The public key is 644. The .ssh directory is 700. The authorized_keys file is 600. If any of these is wrong, the key is ignored and the error message is the same as a wrong key.

Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!