Advanced SSH Key Management on a VPS: Multiple Keys, Agents, Jump Hosts, and Hardening

Advanced SSH Key Management on a VPS: Multiple Keys, Agents, Jump Hosts, and Hardening

SSH keys are the foundation of secure VPS access — but most administrators only scratch the surface of what key-based authentication can do. Managing multiple keys for different users and purposes, forwarding agent credentials through jump hosts, restricting keys to specific commands, and auditing who accessed the server and when are all standard practice in well-secured infrastructure. This guide covers the full SSH key management workflow.

Generating Strong SSH Keys

# Ed25519: best option — small keys, fast, secure (use this)
ssh-keygen -t ed25519 -C "deploy@myproject" -f ~/.ssh/myproject_ed25519

# RSA 4096: compatible with older systems that don't support Ed25519
ssh-keygen -t rsa -b 4096 -C "deploy@myproject" -f ~/.ssh/myproject_rsa

# Always set a passphrase — protects the private key if the file is stolen
# The passphrase is handled by ssh-agent so you only type it once per session

# View public key (this is what you copy to servers)
cat ~/.ssh/myproject_ed25519.pub

Deploying Keys to a VPS

# Method 1: ssh-copy-id (simplest)
ssh-copy-id -i ~/.ssh/myproject_ed25519.pub deploy@YOUR_VPS_IP

# Method 2: Manual (when ssh-copy-id isn't available)
cat ~/.ssh/myproject_ed25519.pub | ssh deploy@YOUR_VPS_IP \
  "mkdir -p ~/.ssh && chmod 700 ~/.ssh && \
   cat >> ~/.ssh/authorized_keys && \
   chmod 600 ~/.ssh/authorized_keys"

# Method 3: Copy file directly
scp ~/.ssh/myproject_ed25519.pub deploy@YOUR_VPS_IP:/tmp/
ssh deploy@YOUR_VPS_IP "cat /tmp/myproject_ed25519.pub >> ~/.ssh/authorized_keys && rm /tmp/myproject_ed25519.pub"

Managing Multiple Keys with ~/.ssh/config

The SSH config file lets you define aliases, key assignments, and connection options per host — so you never need to remember which key goes with which server:

nano ~/.ssh/config
# Production web server
Host prod-web
    HostName 203.0.113.10
    User deploy
    IdentityFile ~/.ssh/prod_ed25519
    Port 22

# Production database server (only via jump host)
Host prod-db
    HostName 10.0.0.5
    User postgres
    IdentityFile ~/.ssh/prod_ed25519
    ProxyJump prod-bastion

# Bastion / jump host
Host prod-bastion
    HostName 203.0.113.1
    User bastion
    IdentityFile ~/.ssh/bastion_ed25519
    Port 2222

# Development server
Host dev
    HostName dev.yourdomain.com
    User ubuntu
    IdentityFile ~/.ssh/dev_ed25519

# GitHub (separate key per service is good practice)
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/github_ed25519

# Global defaults
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    AddKeysToAgent yes
    IdentitiesOnly yes   # Only use explicitly configured keys

Now connect using aliases:

ssh prod-web          # Uses correct key automatically
ssh prod-db           # Tunnels through bastion transparently
git push origin main  # Uses GitHub key

SSH Agent: Enter Passphrase Once Per Session

# Start ssh-agent (usually auto-started by your OS/desktop)
eval "$(ssh-agent -s)"

# Add keys to agent (prompts for passphrase once)
ssh-add ~/.ssh/prod_ed25519
ssh-add ~/.ssh/dev_ed25519

# List loaded keys
ssh-add -l

# After adding, SSH connections use the agent — no passphrase needed
ssh prod-web

Agent Forwarding for Jump Hosts

Agent forwarding lets you use your local SSH keys from a remote server (e.g., to pull from GitHub while SSH’d into a VPS) — without copying private keys to the server:

# Enable agent forwarding in ~/.ssh/config for specific hosts only:
Host prod-bastion
    ForwardAgent yes   # Only enable for trusted hosts you fully control

# Or use -A flag for one-off connections:
ssh -A deploy@bastion.yourdomain.com

# From bastion, SSH to internal servers using your local key:
ssh postgres@10.0.0.5    # Your local key forwarded through bastion

Security note: Only forward the agent to hosts you fully trust and control. A compromised server with agent forwarding can use your forwarded keys to access other servers.

Restricting Keys on authorized_keys

The authorized_keys file supports per-key restrictions — limit what each key can do:

nano ~/.ssh/authorized_keys
# Restrict key to a single command (useful for backup scripts, monitoring)
command="/usr/local/bin/backup.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA... backup@monitoring

# Restrict to specific IP address
from="203.0.113.0/24",no-port-forwarding ssh-ed25519 AAAA... office@work

# Allow port forwarding but restrict to one command
command="rsync --server -avz . /backup/",no-pty ssh-ed25519 AAAA... rsync-backup

# Full access key (no restrictions — for human admin use)
ssh-ed25519 AAAA... admin@laptop

Hardening sshd_config

sudo nano /etc/ssh/sshd_config
# Disable password authentication entirely
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no

# Disable root login
PermitRootLogin no

# Limit SSH to specific users
AllowUsers deploy alice bob

# Change default port (obscures from automated scanners)
Port 2222

# Disable unused features
X11Forwarding no
AllowAgentForwarding no   # Only enable if you need it
AllowTcpForwarding no

# Use only modern algorithms
KexAlgorithms curve25519-sha256,diffie-hellman-group16-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

# Log verbosely for audit trail
LogLevel VERBOSE

# Disconnect idle sessions
ClientAliveInterval 300
ClientAliveCountMax 2
MaxStartups 3:50:10
sudo sshd -t   # Test config before applying
sudo systemctl reload ssh

Auditing SSH Access

# View all successful SSH logins
sudo grep "Accepted publickey" /var/log/auth.log | tail -30

# View failed attempts (brute force monitoring)
sudo grep "Failed password\|Failed publickey" /var/log/auth.log | \
  awk '{print $11}' | sort | uniq -c | sort -rn | head -20

# Who is currently logged in
who
w

# Recent login history
last | head -30

# Login history for specific user
last deploy | head -20

Rotate Keys Safely

# Step 1: Generate new key pair
ssh-keygen -t ed25519 -C "deploy-new-$(date +%Y%m)" -f ~/.ssh/deploy_new

# Step 2: Add new public key to server (while old key still works)
ssh-copy-id -i ~/.ssh/deploy_new.pub deploy@YOUR_VPS_IP

# Step 3: Test new key works
ssh -i ~/.ssh/deploy_new deploy@YOUR_VPS_IP "echo 'new key works'"

# Step 4: Remove old key from authorized_keys
ssh deploy@YOUR_VPS_IP "sed -i '/old_key_comment/d' ~/.ssh/authorized_keys"

# Step 5: Update ~/.ssh/config to use new key
# Step 6: Securely delete old private key
shred -vzu ~/.ssh/old_key

Getting Started

SSH key management is the security foundation for every Ubuntu VPS at VPS.DO. The key steps are: generate Ed25519 keys with passphrases, use ~/.ssh/config for multi-server management, disable password authentication in sshd_config, and restrict individual keys in authorized_keys to the minimum necessary permissions. VPS.DO’s emergency KVM console provides recovery access if you accidentally lock yourself out during hardening.

Conclusion

Advanced SSH key management — per-service keys, config file aliases, agent forwarding through jump hosts, and per-key command restrictions — transforms SSH from a basic login mechanism into a fine-grained access control system. Combined with sshd hardening and audit logging, key-based SSH provides both convenience (no password typing with agent) and security (no passwords to brute-force, per-key restrictions, complete audit trail).

Fast • Reliable • Affordable VPS - DO It Now!

Get top VPS hosting with VPS.DO’s fast, low-cost plans. Try risk-free with our 7-day no-questions-asked refund and start today!