
How to Create SSH Keys with OpenSSH on macOS or Linux
SSH keys are the gold standard for secure server authentication, replacing vulnerable password-based login systems with cryptographic key pairs that make brute force attacks practically impossible. While many developers stick to basic password authentication or rely on hosting providers to handle security, understanding how to generate and manage SSH keys properly gives you complete control over your server access and significantly hardens your infrastructure. This guide walks through creating SSH keys using OpenSSH on macOS and Linux systems, covering everything from basic key generation to advanced configuration options, troubleshooting common issues, and implementing security best practices that’ll keep your servers locked down tight.
How SSH Key Authentication Works
SSH key authentication relies on public-key cryptography, where you generate a mathematically related pair of keys: a private key that stays on your local machine and a public key that gets copied to remote servers. When you attempt to connect, the SSH client uses your private key to create a digital signature that the server validates against your stored public key, proving your identity without transmitting any sensitive data over the network.
The process happens in milliseconds but involves sophisticated cryptographic operations. Your SSH client generates a random challenge, signs it with your private key, and sends both the challenge and signature to the server. The server then uses your public key to verify the signature matches the challenge, confirming you possess the corresponding private key without ever seeing it.
Modern SSH implementations support several key algorithms, each with different security and performance characteristics:
Algorithm | Key Size | Security Level | Performance | Compatibility |
---|---|---|---|---|
RSA | 2048-4096 bits | High (3072+ bits) | Moderate | Universal |
Ed25519 | 256 bits | Excellent | Fast | Modern systems |
ECDSA | 256-521 bits | High | Fast | Good |
DSA | 1024 bits | Deprecated | Fast | Legacy only |
Step-by-Step SSH Key Generation
OpenSSH comes pre-installed on macOS and virtually every Linux distribution, so you can start generating keys immediately. The ssh-keygen command handles all key generation tasks with various options for customization.
Basic Key Generation
For most use cases, Ed25519 keys provide the best combination of security and performance:
ssh-keygen -t ed25519 -C "your-email@domain.com"
This command creates a new Ed25519 key pair with your email as a comment for identification. You’ll see output like:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/username/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/username/.ssh/id_ed25519
Your public key has been saved in /home/username/.ssh/id_ed25519.pub
For environments requiring RSA compatibility, generate a 3072 or 4096-bit RSA key:
ssh-keygen -t rsa -b 4096 -C "your-email@domain.com"
Advanced Key Generation Options
You can customize key generation with additional parameters for specific requirements:
# Generate key with custom filename
ssh-keygen -t ed25519 -f ~/.ssh/production_server_key -C "production-access"
# Generate key with specific number of KDF rounds (higher = more secure but slower)
ssh-keygen -t ed25519 -a 100 -C "high-security-key"
# Generate key for specific hostname
ssh-keygen -t ed25519 -f ~/.ssh/myserver_key -C "access-to-myserver.com"
The -a option sets the number of KDF (Key Derivation Function) rounds used when saving the private key. Higher values make brute force attacks against stolen key files more difficult but increase the time needed to load the key.
Understanding Key File Structure
SSH key generation creates two files in your ~/.ssh directory:
- Private key (id_ed25519): Never share this file. It proves your identity and should have 600 permissions
- Public key (id_ed25519.pub): Safe to share. Gets copied to servers you want to access
You can examine your public key content with:
cat ~/.ssh/id_ed25519.pub
The output shows the key type, the actual key data (base64 encoded), and your comment:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG4rT3vTt99Ox5kndS4HmgTrKBT8SKzhK4rhGkEVGlCI your-email@domain.com
Copying Keys to Remote Servers
Once you’ve generated SSH keys, you need to copy the public key to servers where you want passwordless access. The ssh-copy-id command automates this process:
# Copy default key to server
ssh-copy-id username@server.com
# Copy specific key to server
ssh-copy-id -i ~/.ssh/custom_key.pub username@server.com
# Copy key to server running on custom port
ssh-copy-id -p 2222 username@server.com
If ssh-copy-id isn’t available, you can manually copy the key:
# Manual key copying method
cat ~/.ssh/id_ed25519.pub | ssh username@server.com "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
This command creates the necessary directories, sets proper permissions, and appends your public key to the authorized_keys file on the remote server.
SSH Configuration and Key Management
Managing multiple SSH keys becomes complex quickly. The SSH config file (~/.ssh/config) simplifies connection management and key assignment:
# ~/.ssh/config example
Host production
HostName prod.mycompany.com
User deploy
IdentityFile ~/.ssh/production_key
Port 2222
Host staging
HostName staging.mycompany.com
User admin
IdentityFile ~/.ssh/staging_key
Host github.com
User git
IdentityFile ~/.ssh/github_key
Host *
AddKeysToAgent yes
UseKeychain yes # macOS only
IdentitiesOnly yes
With this configuration, you can connect using simple aliases:
ssh production
ssh staging
git clone git@github.com:username/repo.git
The global settings (* host) enable useful features:
- AddKeysToAgent: Automatically adds keys to ssh-agent when used
- UseKeychain: On macOS, stores passphrases in Keychain
- IdentitiesOnly: Only use explicitly configured keys, preventing key guessing
SSH Agent for Key Management
SSH agent runs in the background, holding decrypted private keys in memory so you don’t need to enter passphrases repeatedly. Most Linux desktop environments and macOS start ssh-agent automatically, but you can manage it manually:
# Start ssh-agent (if not running)
eval $(ssh-agent)
# Add key to agent
ssh-add ~/.ssh/id_ed25519
# Add key with custom lifetime (1 hour)
ssh-add -t 3600 ~/.ssh/production_key
# List loaded keys
ssh-add -l
# Remove all keys from agent
ssh-add -D
On macOS, you can store passphrases permanently in Keychain:
# Add key to agent and Keychain on macOS
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Real-World Use Cases and Examples
SSH keys enable numerous automation and security scenarios beyond basic server access.
Git Repository Access
Using SSH keys for Git operations eliminates the need to enter credentials repeatedly and supports token-based authentication systems:
# Generate dedicated key for GitHub
ssh-keygen -t ed25519 -f ~/.ssh/github_key -C "github-access"
# Add to SSH config
echo "Host github.com
User git
IdentityFile ~/.ssh/github_key" >> ~/.ssh/config
# Test connection
ssh -T git@github.com
Automated Deployment Scripts
Deployment automation requires passwordless access to production servers. Create dedicated deployment keys with restricted permissions:
# Generate deployment-specific key
ssh-keygen -t ed25519 -f ~/.ssh/deploy_key -N "" -C "automated-deployment"
# Copy to deployment servers
for server in web1.prod.com web2.prod.com; do
ssh-copy-id -i ~/.ssh/deploy_key.pub deploy@$server
done
In your deployment scripts:
#!/bin/bash
# deployment.sh
export SSH_KEY=~/.ssh/deploy_key
# Deploy to multiple servers
for server in web1.prod.com web2.prod.com; do
ssh -i $SSH_KEY deploy@$server "cd /var/www && git pull origin main && sudo systemctl restart nginx"
done
Database Server Access
Database servers often require secure tunneling through bastion hosts. SSH keys simplify this multi-hop access:
# ~/.ssh/config for database access
Host bastion
HostName bastion.company.com
User admin
IdentityFile ~/.ssh/bastion_key
Host database
HostName db.internal.company.com
User dbadmin
IdentityFile ~/.ssh/database_key
ProxyJump bastion
Connect directly to the database server through the bastion:
ssh database
# or create a tunnel for database tools
ssh -L 5432:localhost:5432 database
Security Best Practices
SSH key security goes beyond just generating strong keys. Implementing comprehensive security practices protects against various attack vectors.
Key Protection
Always protect private keys with strong passphrases and proper file permissions:
# Set restrictive permissions on SSH directory
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_*
chmod 644 ~/.ssh/*.pub
chmod 600 ~/.ssh/config
Use strong, unique passphrases for each private key. Consider using a password manager to generate and store these securely.
Key Rotation Strategy
Implement regular key rotation, especially for high-privilege access:
# Generate new key with date suffix
ssh-keygen -t ed25519 -f ~/.ssh/production_$(date +%Y%m%d) -C "production-access-$(date +%Y-%m-%d)"
# Copy new key to servers
ssh-copy-id -i ~/.ssh/production_$(date +%Y%m%d).pub admin@production.com
# Update SSH config to use new key
# Remove old key from servers after confirming new key works
Server-Side Hardening
Configure SSH servers to maximize security when using key authentication:
# /etc/ssh/sshd_config security settings
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PermitRootLogin no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
These settings disable password authentication, limit login attempts, and automatically disconnect idle sessions.
Troubleshooting Common Issues
SSH key authentication can fail for various reasons. Here are the most common issues and their solutions:
Permission Problems
Incorrect file permissions cause most SSH key failures:
# Fix common permission issues
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_*
chmod 644 ~/.ssh/*.pub
chmod 600 ~/.ssh/authorized_keys # on server
On the server side, ensure the authorized_keys file has correct permissions and ownership:
# On remote server
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown $USER:$USER ~/.ssh ~/.ssh/authorized_keys
SSH Agent Issues
When keys don’t load automatically, check ssh-agent status:
# Check if ssh-agent is running
echo $SSH_AUTH_SOCK
# If not set, start ssh-agent
eval $(ssh-agent)
# Verify keys are loaded
ssh-add -l
# Add keys if missing
ssh-add ~/.ssh/id_ed25519
Connection Debugging
Use verbose SSH output to diagnose connection problems:
# Enable verbose output
ssh -v username@server.com
# Even more verbose
ssh -vvv username@server.com
Look for messages about key loading, authentication attempts, and server responses. Common error patterns include:
- “Permission denied (publickey)”: Key not recognized or server misconfigured
- “Too many authentication failures”: SSH agent offering too many keys
- “Connection refused”: SSH service not running or firewall blocking
Key Format Compatibility
Some older systems don’t support newer key formats. Convert keys if needed:
# Convert modern private key format to older format
ssh-keygen -p -m PEM -f ~/.ssh/id_rsa
# Generate key in specific format
ssh-keygen -t rsa -b 4096 -m PEM -f ~/.ssh/legacy_key
Alternative Key Types and When to Use Them
While Ed25519 provides the best general-purpose security, specific scenarios might require different key types:
Scenario | Recommended Key Type | Reason |
---|---|---|
Modern infrastructure | Ed25519 | Best security/performance balance |
Legacy system compatibility | RSA 3072/4096 | Universal support |
Government/compliance | ECDSA P-384 | FIPS 140-2 approved |
High-performance applications | Ed25519 | Fastest signature verification |
IoT/embedded devices | ECDSA P-256 | Lower memory requirements |
For compliance-heavy environments, check with your security team about approved algorithms and key sizes before generating keys.
Advanced Configuration Options
SSH supports numerous advanced features that enhance security and functionality in complex environments.
Certificate-Based Authentication
SSH certificates provide centralized key management for large organizations:
# Generate certificate authority key
ssh-keygen -t ed25519 -f ssh_ca_key -C "SSH Certificate Authority"
# Create user certificate
ssh-keygen -s ssh_ca_key -I user@company.com -n user1,user2 -V +52w ~/.ssh/id_ed25519.pub
Hardware Security Keys
Modern SSH supports FIDO2/WebAuthn hardware keys for enhanced security:
# Generate key stored on hardware token
ssh-keygen -t ed25519-sk -O resident -C "hardware-key-$(date +%Y%m%d)"
# Generate key requiring touch verification
ssh-keygen -t ecdsa-sk -O verify-required -C "touch-required-key"
Hardware keys provide excellent security since the private key never leaves the physical device, making remote attacks nearly impossible.
Restricted Key Usage
Limit what specific keys can do using authorized_keys options:
# ~/.ssh/authorized_keys with restrictions
command="rsync --server --daemon ." ssh-ed25519 AAAAC3N... backup-key
from="192.168.1.0/24" ssh-ed25519 AAAAC3N... office-access-key
no-port-forwarding,no-X11-forwarding ssh-ed25519 AAAAC3N... restricted-key
These restrictions enforce specific commands, limit source IPs, or disable dangerous features like port forwarding.
Performance Considerations
SSH key performance varies significantly between algorithms, especially in high-throughput scenarios:
Algorithm | Key Generation | Signature Speed | Verification Speed | Key Size |
---|---|---|---|---|
Ed25519 | Fast | Very Fast | Very Fast | 68 bytes |
RSA 3072 | Slow | Slow | Fast | 384 bytes |
ECDSA P-256 | Fast | Fast | Moderate | 104 bytes |
For automated systems making thousands of SSH connections, Ed25519’s performance advantage becomes significant. The smaller key sizes also reduce network overhead and storage requirements.
Integration with Cloud and Container Platforms
Modern deployment environments require SSH key integration with cloud services and container orchestration platforms.
Cloud Instance Access
Most cloud providers support SSH key injection during instance creation:
# AWS CLI example
aws ec2 import-key-pair --key-name production-key --public-key-material fileb://~/.ssh/id_ed25519.pub
# Launch instance with key
aws ec2 run-instances --image-id ami-12345678 --key-name production-key --instance-type t3.micro
Container Development
Development containers often need SSH key access for Git operations:
# Dockerfile for development container
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y openssh-client git
COPY --from=host ~/.ssh/id_ed25519 /root/.ssh/id_ed25519
RUN chmod 600 /root/.ssh/id_ed25519
For production containers, use build-time secrets or init containers to avoid embedding keys in images.
SSH keys represent a fundamental security improvement over password authentication, but their effectiveness depends entirely on proper implementation and management. The techniques covered here—from basic key generation to advanced security configurations—provide the foundation for building robust, secure infrastructure access systems. Whether you’re managing a single VPS or orchestrating access to hundreds of servers, mastering SSH key authentication is essential for modern system administration and development workflows.
For developers and organizations looking to implement these practices on reliable infrastructure, consider exploring MangoHost VPS services for development and testing environments, or dedicated servers for production workloads that demand maximum security and performance. Both platforms support advanced SSH configurations and provide the stable foundation needed for implementing comprehensive key management strategies.
Remember that SSH security is an ongoing process, not a one-time setup. Regular key rotation, monitoring access logs, and staying updated with the latest OpenSSH releases ensure your authentication systems remain secure against evolving threats. The investment in proper SSH key management pays dividends in both security and operational efficiency throughout your infrastructure’s lifecycle.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.