Mastering Secure Access: Engineering SSH Installation and Hardening on Ubuntu
Uptime matters. When a critical server goes dark, SSH is your lifeline. But default configurations? Frequently exploited. Here’s a focused guide for secure, efficient SSH setup on Ubuntu 22.04 LTS.
Why Bother with SSH Hardening?
SSH—specifically OpenSSH—is the industry baseline for encrypted terminal access. Yet on a fresh Ubuntu server, default settings expose more risk than most teams realize: root login is often enabled, password authentication on, and the service is wide open on port 22. These are low-hanging fruit for automated attack scripts.
1. Install OpenSSH Server
Prerequisites:
- Ubuntu 22.04 LTS (or similar; commands are unchanged since 20.04)
- User in the
sudo
group
Install via apt:
sudo apt update
sudo apt install openssh-server
Test that installation succeeded:
sudo systemctl status ssh
Look for Active: active (running)
in the output.
If not running, activate:
sudo systemctl start ssh
Note: FirewallD or UFW may block the default port. If not connecting, check sudo ufw status
.`
2. Local SSH Validation
Don’t assume it works—verify:
ssh $(whoami)@localhost
First connection establishes the ~/.ssh/known_hosts
fingerprint. On success, shell access confirms both server-side and local client functionality.
Common error:
ssh: connect to host localhost port 22: Connection refused
- Likely cause: SSH service not running, port blocked, or configuration error.
3. Essential SSHD Hardening
Open SSH daemon config:
sudo nano /etc/ssh/sshd_config
Key parameters (explain why while editing):
PermitRootLogin no
Prevents brute-force password attempts directly to root—forces use of privilege escalation post-login.PasswordAuthentication no
(after key setup)
Only enable after SSH keys are working—forbid password login to stop dictionary attacks.Port 21922
Changing from 22 blocks most basic scan scripts, but won’t fool targeted attackers. Choose a random high port (1024–65535).AllowUsers alice opsbackup
Restricts remote login to specified local users (usernames, not groups).
Save, then:
sudo systemctl restart ssh
Gotcha: Syntax errors in sshd_config
will prevent SSH from starting. Validate changes via:
sudo sshd -t
before restarting the service. Logs appear in /var/log/auth.log
.
4. SSH Key Authentication
On your workstation (preferably a Linux or macOS device), generate an Ed25519 key:
ssh-keygen -t ed25519 -C "ops-admin@yourdomain.com"
Directory:
- Private key:
~/.ssh/id_ed25519
- Public key:
~/.ssh/id_ed25519.pub
Copy the public key over:
ssh-copy-id -i ~/.ssh/id_ed25519.pub alice@server_ip
Alternatively (when ssh-copy-id
isn’t available):
cat ~/.ssh/id_ed25519.pub | ssh alice@server_ip 'umask 077; mkdir -p ~/.ssh; cat >> ~/.ssh/authorized_keys'
Test with:
ssh alice@server_ip -p 21922
On success, disable password authentication as above.
5. Additional Hardening for Production
- Fail2Ban:
Blocks repeated failed auth attempts.
sudo apt install fail2ban
sudo systemctl enable --now fail2ban
Default rules jail SSH. For tweaks, edit /etc/fail2ban/jail.local
.
- UFW (Uncomplicated Firewall):
Permit only your custom SSH port.
sudo ufw allow 21922/tcp
sudo ufw enable
View current rules:
sudo ufw status numbered
- Banner Notifications:
Logins should be traceable.
sudo sh -c 'echo "Authorized access only. Sessions logged." > /etc/issue.net'
Add/Edit in sshd_config
:
Banner /etc/issue.net
A subtle but useful legal warning, plus evidence of intent.
- Disable SSHv1, Restrict Ciphers (rare edge case):
By default in recent Ubuntu, protocol version 2 only is enabled. For extreme compliance (PCI, NIST), review allowed ciphers:
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
But beware, overly restrictive cipher lists can block old clients.
Non-obvious Tips
- Watch the logs.
Monitor/var/log/auth.log
for repeated connections. - SSHD sockets:
Tryss -tlnp | grep sshd
to verify listening on just the desired IPs and port. - Rolling restarts:
Never lock yourself out. Add a new key, open a new session, validate, only then disable password authentication.
SSH Security Workflow: Summary Table
Task | Command/Setting | Notes |
---|---|---|
Install OpenSSH | sudo apt install openssh-server | Ubuntu 20.04+/22.04 |
Check running state | sudo systemctl status ssh | |
Validate config | sudo sshd -t | Checks for errors |
Disable root SSH login | PermitRootLogin no | /etc/ssh/sshd_config |
Change port | Port 21922 | Pick high, nonstandard |
Restrict allowed users | AllowUsers alice bob | List separated by spaces |
Generate SSH key | ssh-keygen -t ed25519 -C "email" | |
Deploy public key | ssh-copy-id ... or cat ... | |
Disable password login | PasswordAuthentication no | Only after keys confirmed |
Enable Fail2Ban | sudo apt install fail2ban && sudo systemctl enable --now fail2ban | Blocks brute force |
Configure firewall | sudo ufw allow 21922/tcp AND sudo ufw enable | Also check cloud firewalls |
Known Issues
- Some cloud providers inject their own keys at provisioning—review
~/.ssh/authorized_keys
for unexpected entries. - Changing the SSH port may break monitoring or auto-configuration tools relying on port 22. Update dependent configs/scripts accordingly.
Practical Example: Minimal Bastion Host
For a jump-box in a production DMZ:
- Only
ssh
user allowed. - Port
30022
. - Keys only, strictly no password login.
- Fail2Ban + UFW enabled, cloud firewall restricted.
Result: Attack surface is minimized, automated scans are dropped, and auditability is retained.
SSH isn’t magic; it’s a tool—make it robust, understand its defaults, question its behavior. And if you’re unsure, audit before deploying to production.
For further automation, see Ansible modules (community.general.openssh_keypair
), or consider enforcing 2FA via libpam-google-authenticator
.