
August 17, 2026
10 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
If you manage Linux servers for web applications, leaving default SSH settings exposed is the fastest route to compromise. Bots scan public IPs relentlessly, and password-based authentication remains the primary attack vector for brute-force campaigns. To properly Harden SSH: Key Auth, Fail2ban, and Port Hardening are the three non-negotiable controls that stop automated attacks before they consume your server’s resources or breach your application data.
sshd_config, enforce Ed25519 keys only, configure Fail2ban to ban IPs after 3 failed attempts, and move SSH to a non-standard port to reduce log noise from opportunistic scanners.On production Laravel and WordPress systems I maintain across Nepal and internationally, this baseline configuration has prevented countless intrusion attempts. It is not theoretical security; it is operational hygiene. For teams managing multiple client sites, combining these controls with automated deployment workflows—like those discussed in my guide on CI/CD pipeline setup in Nepal—ensures security is baked into infrastructure provisioning rather than bolted on later.
How Do You Configure OpenSSH to Harden SSH: Key Auth, Fail2ban, and Port Hardening?
The foundation of server access security lies in the /etc/ssh/sshd_config file. Default Ubuntu 24.04 configurations prioritize convenience over security, often allowing password authentication and root login. In practice, I treat SSH configuration as code: version-controlled, reviewed, and deployed consistently via tools like Deployer or Ansible.
Disabling Password Authentication Safely
Before touching any configuration, generate and deploy an SSH key pair. Locking yourself out of a production server because you disabled passwords without a working key is a rite of passage nobody wants. On your local machine, generate an Ed25519 key (the current standard for performance and security):
ssh-keygen -t ed25519 -C "kokil@production-deploy" -f ~/.ssh/id_ed25519_prod
ssh-copy-id -i ~/.ssh/id_ed25519_prod.pub user@your-server-ip Verify key-based login works in a new terminal session before proceeding. Then edit the SSH daemon configuration:
sudo nano /etc/ssh/sshd_config
# Apply these directives:
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
PubkeyAuthentication yes
AuthenticationMethods publickey
PermitRootLogin no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2 The AuthenticationMethods publickey directive is critical. Without it, some PAM configurations may still fall back to password prompts even when PasswordAuthentication no is set. Validate syntax before restarting:
sudo sshd -t
sudo systemctl restart ssh Selecting Modern Cryptographic Algorithms
Ubuntu 24.04 ships OpenSSH 9.x, which supports modern algorithms by default. However, explicit configuration prevents downgrade attacks and ensures compliance. Add these lines to sshd_config:
HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com
PubkeyAcceptedAlgorithms ssh-ed25519,sk-ssh-ed25519@openssh.com
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com This configuration rejects RSA keys entirely. If legacy systems require RSA, add rsa-sha2-512 to PubkeyAcceptedAlgorithms but plan migration. On legal-tech portals handling sensitive client documents, I enforce Ed25519 exclusively—there is no legitimate reason to accept weaker cryptography in 2026.
How Does Fail2ban Protect SSH When You Harden SSH: Key Auth, Fail2ban, and Port Hardening?
Even with key-only authentication, SSH logs fill with connection attempts from misconfigured clients, former employees, and bots probing for weaknesses. Fail2ban monitors these logs and dynamically updates firewall rules to block offending IPs. This reduces log noise, conserves server resources, and provides visibility into attack patterns.
Installing and Configuring Fail2ban on Ubuntu 24.04
Install Fail2ban and create a local override file (never edit jail.conf directly):
sudo apt update && sudo apt install fail2ban -y
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local Edit /etc/fail2ban/jail.local with production-appropriate values:
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 3
backend = systemd
banaction = nftables-multiport
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = %(sshd_log)s
maxretry = 3
bantime = 24h
findtime = 5m Note the port = 2222 value. This must match your custom SSH port exactly. Fail2ban uses nftables on Ubuntu 24.04 by default; if you still use UFW with iptables backend, change banaction to ufw. Enable and start the service:
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd Tuning Fail2ban for Production Reality
Default Fail2ban settings are too aggressive for shared hosting environments where multiple developers connect from the same NAT gateway. On client projects with distributed teams, I adjust thresholds:
- Development/staging servers:
maxretry = 5,bantime = 30m— allows for typos and key rotation mistakes - Production application servers:
maxretry = 3,bantime = 24h— strict enforcement - Bastion/jump hosts:
maxretry = 2,bantime = 72h— highest security tier
Create ignore rules for trusted IP ranges (office networks, CI/CD runners, monitoring systems):
[sshd]
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 192.168.0.0/16 203.0.113.50/32 Never add broad CIDR blocks unless you control the entire range. A common mistake is ignoring cloud provider metadata IPs or CDN ranges that attackers can abuse.
Why Change the Default Port When You Harden SSH: Key Auth, Fail2ban, and Port Hardening?
Moving SSH from port 22 does not stop determined attackers. Nmap scans all ports. However, it dramatically reduces log volume from automated botnets that only target port 22. On a typical production server, changing the port reduces SSH-related log entries by 90–95%. This makes genuine security events visible and reduces storage costs for log aggregation services.
Changing the SSH Port Without Locking Yourself Out
This operation requires careful sequencing. On one occasion, I changed the port on a client’s WooCommerce server without updating UFW first, causing a 45-minute outage while waiting for console access. Follow this exact order:
- Add the new port to UFW before changing sshd_config:
sudo ufw allow 2222/tcp comment 'SSH alternate port' sudo ufw reload - Edit sshd_config to listen on both ports temporarily:
Port 22 Port 2222 - Restart SSH and verify connectivity on the new port:
sudo systemctl restart ssh ssh -p 2222 user@your-server-ip - Only after confirmed access, remove port 22:
# Edit sshd_config: remove "Port 22", keep only "Port 2222" sudo sshd -t && sudo systemctl restart ssh sudo ufw delete allow 22/tcp
Update Fail2ban’s port directive to match. Update deployment scripts, CI/CD pipelines, and documentation. On projects using Deployer 7, this means updating the deploy.php host configuration:
host('production')
->setHostname('your-server-ip')
->setPort(2222)
->setRemoteUser('deploy');
Firewall Hardening Beyond Port Changes
Port hardening alone is insufficient. Implement rate limiting at the firewall level as an additional layer:
sudo ufw limit 2222/tcp comment 'SSH rate limit'
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw enable The limit rule allows connections but blocks IPs making more than 6 attempts in 30 seconds. This complements Fail2ban by catching volumetric attacks before they reach the SSH daemon. For servers behind Cloudflare or similar proxies, consider restricting SSH access to proxy IP ranges only, though this complicates direct emergency access.
What Are Common Mistakes When Teams Harden SSH: Key Auth, Fail2ban, and Port Hardening?
In 15 years of managing production infrastructure, I’ve seen hardened configurations fail due to operational oversights rather than technical flaws. Understanding these pitfalls prevents costly outages and false confidence.
| Mistake | Consequence | Prevention |
|---|---|---|
| Disabling passwords before testing keys | Complete lockout requiring console recovery | Always test key auth in separate session first |
| Editing jail.conf instead of jail.local | Config overwritten on package upgrade | Use .local overrides exclusively |
| Changing port without updating firewall | SSH unreachable until physical/console access | Add new port to UFW before modifying sshd_config |
| Ignoring trusted IPs in Fail2ban | CI/CD pipelines or team members banned | Maintain explicit ignoreip list for automation |
| Using RSA keys with weak padding | Vulnerable to signature forgery attacks | Migrate to Ed25519; reject RSA in sshd_config |
| Not validating sshd_config syntax | Daemon fails to restart, no remote access | Always run sshd -t before systemctl restart |
Another frequent issue is failing to update backup and monitoring systems. If your backup solution connects via SSH, it will break when you disable password auth or change ports. Audit all automated systems that touch the server: rsync jobs, monitoring agents, deployment tools, and third-party integrations. On eCommerce platforms with payment webhook receivers or inventory sync services, this step is critical. For teams evaluating whether their current setup meets modern standards, reviewing server security best practices in Nepal provides additional context specific to regional infrastructure constraints.
Key Management Hygiene
Hardening SSH is not a one-time task. Key management requires ongoing discipline:
- Rotate keys annually or immediately upon personnel changes
- Use unique keys per environment — never share production keys with staging
- Store private keys encrypted with strong passphrases; use ssh-agent for convenience
- Audit authorized_keys regularly — remove stale entries from departed team members
- Consider certificate-based auth for large teams using HashiCorp Vault or Teleport
For solo developers or small agencies managing dozens of client sites, SSH certificates add complexity that may not justify the overhead. In those cases, disciplined key management with per-client keys stored in a password manager provides adequate security. The goal is sustainable security, not perfect security that gets abandoned under operational pressure.
Final Steps to Maintain Your Harden SSH: Key Auth, Fail2ban, and Port Hardening Setup
Implementing these controls takes approximately 30 minutes per server. The real work is maintaining them through upgrades, team changes, and incident response. Schedule quarterly reviews of SSH configurations, Fail2ban ban statistics, and key inventories. Document your hardening process so new team members inherit secure defaults rather than reinventing them.
Monitor Fail2ban effectiveness with weekly log reviews. If ban rates drop to near-zero, verify that bots haven’t shifted to other attack vectors (HTTP brute force, API abuse). Security is iterative. The configuration described here reflects current best practices for Ubuntu 24.04 and OpenSSH 9.x in 2026; revisit it when major versions change.
For teams managing multiple production servers across Nepal or globally, consistent hardening is only possible with infrastructure-as-code. Manual configuration drifts. Whether you use Ansible, Terraform, or simple shell scripts versioned in Git, automate these settings from day one. If you need assistance auditing existing servers or implementing hardened SSH across your fleet, reach out to discuss your infrastructure security needs.

