Mastering Secure SSH Access to Your Ubuntu Server in Minutes
Routine cloud operations hinge on reliable, secured remote access. SSH is the entry point—treat it as such. Misconfigured, SSH is a liability; properly hardened, it forms the backbone of your infrastructure’s management layer.
The Attack Surface
OpenSSH, the standard for Ubuntu server remote management, defaults to password authentication on port 22. Check any security scan: internet-exposed systems routinely see brute-force attempts. The question isn’t if, but how often.
SSH Hardening: Implementation Guide
Assume Ubuntu 22.04 LTS or similar. Adjust accordingly for older distros.
1. Verify OpenSSH Installation and Daemon Status
sudo apt-get update
sudo apt-get install -y openssh-server
sudo systemctl status ssh
A running service outputs active (running)
. If you see inactive (dead)
, start the daemon:
sudo systemctl enable --now ssh
Gotcha
Firewalls (UFW, iptables, cloud security groups) block port 22 by default in many hosting environments.
sudo ufw allow 22/tcp comment 'OpenSSH for admin access'
sudo ufw enable
ufw status
2. Key-Based Authentication
Generate Local SSH Key Pair
ed25519 is preferred for performance and security. On macOS/Linux:
ssh-keygen -t ed25519 -a 10 -C "admin@host"
-a 10
: Increases key derivation rounds (slows brute force).- Defaults to
~/.ssh/id_ed25519
.
Deploy Public Key to Server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server_ip
If ssh-copy-id
isn’t available:
cat ~/.ssh/id_ed25519.pub | ssh user@server_ip "umask 077; mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
Non-obvious: On some hardened images, /home/user/.ssh
may be locked down (700) and fail writes. Adjust file permissions accordingly.
Test Key Authentication
ssh -i ~/.ssh/id_ed25519 user@server_ip
Prompted for the passphrase, not the account password. If the server still asks for an account password, inspect /etc/ssh/sshd_config
and ~/.ssh/authorized_keys
permissions (600
for authorized_keys, 700
for .ssh).
3. SSH Daemon Configuration
Edit the config:
sudo nano /etc/ssh/sshd_config
Minimum changes for solid hardening:
# Never allow root logins directly
PermitRootLogin no
# Only public key auth
PasswordAuthentication no
ChallengeResponseAuthentication no
# Optionally, move off the default port. Not real security, but reduces scanning noise.
Port 2222
# Protocol 2 only (should be default since Ubuntu 16.04, but check)
Protocol 2
# Timeouts (discover idle connections, potentially hang prevention)
ClientAliveInterval 300
ClientAliveCountMax 1
# Restrict access narrowly
AllowUsers sysadmin deployer
Restart the service (and do not log out of your current SSH session when testing):
sudo systemctl restart ssh
Practical tip: If OpenSSH misconfigures, the daemon may fail with little explanation. Always execute from a persistent root console or via tmux
/screen
, and keep an unfixed session open.
Common Configuration Pitfalls
Symptom | Diagnosis |
---|---|
Can't connect after changing port | Upstream firewall not adjusted |
Still prompts for password despite keys | Permissions wrong on ~/.ssh or keys missing |
Daemon fails to start; log shows "bad configuration" | Syntax error in sshd_config |
Too many authentication failures | SSH agent loaded with too many identities |
Check logs:
sudo tail -f /var/log/auth.log
4. Extra Layer: Fail2ban and 2FA
Brute force will never cease. fail2ban
can fill the gap.
sudo apt-get install -y fail2ban
sudo systemctl enable --now fail2ban
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
Look for [sshd]
, adjust maxretry
and bantime
as needed.
Two-Factor Authentication: For high-value targets,
sudo apt-get install libpam-google-authenticator
google-authenticator
sudo nano /etc/pam.d/sshd # Add "auth required pam_google_authenticator.so"
Trade-off: Automations and orchestrators will break unless supporting OATH/TOTP.
5. Troubleshooting Example
Lockout scenario—common after configuration changes:
- Connect via cloud provider web console (Google/AWS/Azure serial console, etc.)
- Revert recent
/etc/ssh/sshd_config
edits.
Example error in /var/log/auth.log
:
sshd[2397]: Authentication refused: bad ownership or modes for directory /home/user/.ssh
Ownership must be user:user, mode 700 for .ssh
, 600 for authorized_keys
.
Conclusion
SSH entry points demand systematic hardening. Key-based access, strict daemon configuration, and layered defenses (like fail2ban or network-level whitelists) form the baseline for any serious production workload. Don’t assume cloud images are secure by default—verify, test, and re-test your configuration.
Non-obvious tip: Some cloud images auto-inject public keys via cloud-init; local changes may be overridden on system rebuild or scale-out. Review cloud provider docs.
Summary Table: SSH Hardening Steps
Step | Command/Config Example | Purpose |
---|---|---|
Install server | sudo apt-get install openssh-server | Enable SSH daemon |
Generate key pair | ssh-keygen -t ed25519 -a 10 ... | Local secure authentication |
Copy public key | ssh-copy-id user@host | Register login identity |
Disable passwords | PasswordAuthentication no | Prevent brute-force |
Change port | Port 2222 | Reduce scan exposure |
Deploy fail2ban | sudo apt-get install fail2ban | Block repeated attackers |
SSH is never “set and forget.” Scheduled audits—both config and auth logs—are recommended.