Skip to main content

OpenSSH Hardening

·865 words·5 mins
Essential Posts hardening ssh ubuntu
Table of Contents
SSH - This article is part of a series.
Part 4: This Article
The default settings of SSH prioritize accessibility, not security.

Starting with OpenSSH 8.2, SSH supports directory-based configuration. This means OpenSSH reads the Include /etc/ssh/sshd_config.d/*.conf line in the main /etc/ssh/sshd_config file first.

Cloud providers (like AWS, Azure or DigitalOcean) use cloud-init to securely inject initial SSH keys.

For example, in Ubuntu, etc/ssh/sshd_config.d/50-cloud-init.conf is an auto-generated file created by cloud-init during the initial setup of cloud instance. It dictates specific SSH behavior.

If we make edits to /etc/ssh/sshd_config (such as trying to disable PasswordAuthentication). But it doesn’t seem to take effect. It is likely being overridden by conflicting settings in /etc/ssh/sshd_config.d/50-cloud-init.conf

This guide will walk through step-by-step SSH hardening on Ubuntu VPS.

In this post, we are using ubuntu as username.

Let’s move on to Ubuntu server hardening.

SSH Daemon (sshd)
#

Here, we don’t backup SSHD configuration. Because we won’t make any change and simply override the default configuration.

Instead, we can make safe edits to SSH config by defining our own hardening file/rules: /etc/ssh/sshd_config.d/99-hardening-settings.conf

% sudo cat > /etc/ssh/sshd_config.d/99-hardening-settings.conf <<EOF
# Disable OS Banner (before login)
DebianBanner no

# Add an additional port
#Port 22
Port 22022

# Disable root login entirely
PermitRootLogin no

# Disable password authentication 
PasswordAuthentication no

# Disable empty passwords
PermitEmptyPasswords no

# Disable keyboard-interactive and challenge-response auth (s/key or PAM-based prompts)
ChallengeResponseAuthentication no

# Disable Pluggable Authentication Module (PAM)
#UsePAM no
## UsePAM can ensure locked account cannot login

# Use key-based authentication
PubkeyAuthentication yes

# Use only SSH protocol 2
Protocol 2

# Limit authentication attempts per connection
MaxAuthTries 3

# Set connection timeout 
ClientAliveInterval 600
ClientAliveCountMax 2

# Disable X11 forwarding (not needed)
X11Forwarding no

# Disable TCP forwarding unless you specifically need it
AllowTcpForwarding no

# Only allow specific users to connect via SSH
AllowUsers ubuntu opc

# Use strong key exchange algorithms, ciphers, and MACs
KexAlgorithms sshd_config curve25519-sha256,curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

# Max login time (in seconds) after connecting - prevent rbute-force or DoS
LoginGraceTime 20

# Limit the open multiplexed shell login sessions per network (default 10)
MaxSessions 3

# To print the Message of the Dar upon successful login
PrintMotd yes

# Disable custom environment variables from client
PermitUserEnvironment no

EOF

Basically, the hardening settings include:

  • Disable the OS banner
  • Change the default SSH port
  • Disable password authentication method
  • Disable direct root-login
  • Disable empty password
  • Enforce public key authentication method
  • Enforce strong key exchange algorithm
  • Prevent brute-force or DoS attacks

Do not close the existing SSH session. Test the new configuration with another new terminal instead.

Then, follow by testing and restart the OpenSSH Server.

% sudo sshd -t 
% sudo systemctl restart ssh

Remember: Before disabling root, ensure your non-root user (ubuntu) is in the sudo group.

Check with groups ubuntu or add with sudo usermod -aG sudo ubuntu.

And (optional) try validate it by copying public key from local machine to Ubuntu server at TCP port 22022.

% ssh-copy-id -i ~/.ssh/ided25519.pub -p 22022 username@ubuntu_server_ip

Firewall Lockdown
#

Update firewall rules.

% sudo ufw allow 22022/tcp
% sudo ufw limit 22022/tcp
% sudo ufw logging medium
% sudo ufw status numbered

And ensure all the rules are correct! Or delete any unnecessary rules with:

% sudo ufw delete RULE_NUMBER

Install Fail2Ban
#

Fail2Ban monitors log files for repeated authentication failures. It automatically bans offending IP addresses by adding firewall rules.

Tip: It’s essential for any internet-facing server.

Start by install and setup a local fail2ban.

% sudo apt install fail2ban
% sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Add the following configuration to /etc/fail2ban/jail.local:

[DEFAULT]
# Ban duration: 1 hour for first offense
bantime = 3600

# Time window for counting failures
findtime = 600

# Number of failures before ban
maxretry = 5

# Use UFW as the ban action
banaction = ufw

[sshd]
enabled = true
port = 22022
filter = sshd
logpath = /var/log/auth.log
maxretry = 4
bantime = 7200
findtime = 300

This configuration:

  • Bans IPs for 1 hour by default (2 hours for SSH specifically)
  • Looks at a 5-minute window for SSH (10 minutes default)
  • Triggers after 4 failed SSH attempts (5 for other services)
  • Uses UFW to implement the bans (ufw status)

Then enable and start Fail2Ban:

% sudo systemctl enable fail2ban
% sudo systemctl start fail2ban
%
% sudo systemctl restart fail2ban

Check the overall status and SSHD jail:

% sudo fail2ban-client status
% sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 3
   |- Total banned:     3
   `- Banned IP list:   186.13.24.118 64.89.161.56 71.173.193.16

To manually unban an IP:

% sudo fail2ban-client set sshd unbanip 127.0.0.2

Troubleshooting
#

Test the configuration file for any syntax errors:

% sudo sshd -t
Tip! Must be sudo sshd -t to avoid annoying error like sshd: no hostkeys available -- exiting..

If no errors are reported, restart the SSH service:

% sudo systemctl restart ssh

Another way to debug the validity of the configuration file.

This is to output the effective configuration to stdout.

% sudo sshd -T

Links#

SSH - This article is part of a series.
Part 4: This Article

Related

Enable Auto Updates
·94 words·1 min
Essential Posts 101 hardening ubuntu
Consider enabling auto security updates.
SSH Key Generation
·244 words·2 mins
Posts auth cli ssh ubuntu
Securing OpenSSH with key-based authentication.
SSH Passphrase Management
·302 words·2 mins
Posts passphrase ssh
Add a passphrase to an existing SSH key pair.