How to configure SSH public key authentication

Public key authentication allows you to connect to an SSH server without using a password, utilizing a pair of cryptographic keys. This method is more secure than traditional passwords and facilitates task automation.

How It Works

The system uses a key pair:

  • Private key: Stored on your local computer. Should never be shared.
  • Public key: Copied to the server. Can be freely shared.

When you connect, the server verifies that you possess the private key corresponding to the registered public key.

Prerequisites

  • SSH access to the server with username and password (for initial setup)
  • SSH client installed on your local computer

Quick Method

From Linux / macOS

Run the following command, replacing the values according to your configuration:

REMOTE_USER="user"
REMOTE_HOST="server.example.com"
REMOTE_PORT="22"

# Generate the key (if it doesn't exist) and copy it to the server
if [ ! -f ~/.ssh/id_ed25519 ]; then
    ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
fi
ssh-copy-id -p $REMOTE_PORT $REMOTE_USER@$REMOTE_HOST

For systems that don't support Ed25519, use RSA:

REMOTE_USER="user"
REMOTE_HOST="server.example.com"
REMOTE_PORT="22"

if [ ! -f ~/.ssh/id_rsa ]; then
    ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa
fi
ssh-copy-id -p $REMOTE_PORT $REMOTE_USER@$REMOTE_HOST

From Windows (PowerShell)

Run the following command, replacing the values according to your configuration:

$REMOTE_USER = "user"
$REMOTE_HOST = "server.example.com"
$REMOTE_PORT = "22"

# Generate the key if it doesn't exist
if (!(Test-Path "$env:USERPROFILE\.ssh\id_ed25519")) {
    ssh-keygen -t ed25519 -N '""' -f "$env:USERPROFILE\.ssh\id_ed25519"
}

# Copy the public key to the server
Get-Content "$env:USERPROFILE\.ssh\id_ed25519.pub" | ssh -p $REMOTE_PORT "$REMOTE_USER@$REMOTE_HOST" "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

For systems that don't support Ed25519, use RSA:

$REMOTE_USER = "user"
$REMOTE_HOST = "server.example.com"
$REMOTE_PORT = "22"

if (!(Test-Path "$env:USERPROFILE\.ssh\id_rsa")) {
    ssh-keygen -t rsa -b 4096 -N '""' -f "$env:USERPROFILE\.ssh\id_rsa"
}

Get-Content "$env:USERPROFILE\.ssh\id_rsa.pub" | ssh -p $REMOTE_PORT "$REMOTE_USER@$REMOTE_HOST" "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Once executed, verify the connection:

ssh -p $REMOTE_PORT "$REMOTE_USER@$REMOTE_HOST"

Manual Step-by-Step Method

If you prefer to perform the process manually or the quick method doesn't work, follow these steps.

Step 1: Generate the Key Pair

Linux / macOS

ssh-keygen -t ed25519 -C "your-email@example.com"

Windows (PowerShell)

ssh-keygen -t ed25519 -C "your-email@example.com"

The command will ask for:

  1. File location: Press Enter to accept the default location.
  2. Passphrase: Enter a password to protect the private key (recommended) or press Enter to leave it empty.

Windows (PuTTYgen)

If you use PuTTY instead of OpenSSH:

  1. Open PuTTYgen.
  2. Select EdDSA (or RSA 4096 bits).
  3. Click Generate and move the mouse to generate randomness.
  4. Optionally, enter a passphrase.
  5. Save the private key with Save private key (.ppk file).
  6. Copy the text from the "Public key for pasting into OpenSSH authorized_keys file" field.

Step 2: Copy the Public Key to the Server

Option A: Using ssh-copy-id (Linux/macOS)

ssh-copy-id -p 22 user@server.example.com

Option B: Manual

  1. Display your public key:
cat ~/.ssh/id_ed25519.pub
  1. Connect to the server:
ssh user@server.example.com
  1. Create the directory and file if they don't exist, and add the key:
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "your-complete-public-key" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Step 3: Verify the Connection

Disconnect and reconnect:

ssh user@server.example.com

If everything is correct, you'll access without entering the server password.

Disable Password Authentication (optional)

Once you've verified that key authentication works, you can disable password access for greater security.

Warning: Make sure key authentication works before disabling passwords, or you could lock yourself out of the server.

  1. Edit the SSH configuration file:
sudo nano /etc/ssh/sshd_config
  1. Find and modify the following line:
PasswordAuthentication no
  1. Save the file and restart the SSH service:
# Ubuntu/Debian
sudo systemctl restart ssh

# AlmaLinux/CentOS/RHEL
sudo systemctl restart sshd

Troubleshooting

Permission denied (publickey)

  • Verify permissions on the server:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
  • Confirm that the public key is correctly copied in authorized_keys.
  • Verify that you're using the correct private key.

Connection Still Asks for Password

  • Verify that PubkeyAuthentication yes is in /etc/ssh/sshd_config (enabled by default on most servers).
  • Check the server logs:
sudo tail -f /var/log/auth.log        # Ubuntu/Debian
sudo tail -f /var/log/secure          # AlmaLinux/CentOS
  • Make sure the authorized_keys file doesn't have broken lines (each key must be on a single line).

Key Not Found

  • Verify that the key exists:
ls -la ~/.ssh/
  • If using a custom location, specify it when connecting:
ssh -i /path/to/your/key user@server.example.com

Security Best Practices

  1. Use a passphrase: Protect your private key with a strong password.
  2. Don't share the private key: Each user should have their own key pair.
  3. Use Ed25519: It's more secure and efficient than RSA.
  4. Disable root SSH access: Configure PermitRootLogin no in sshd_config.
  5. Regularly review authorized_keys: Remove keys from users who no longer need access.
  6. Backup your keys: Keep a secure copy of your private key.

References