SSH (Secure Shell) is secure by design, but relying on its default settings is not enough.

In my guide on preparing Ubuntu servers for first use, we touched on a few essential SSH tweaks to enhance security. However, there are additional steps you can take to further secure your server.

In this detailed exploration of the sshd_config file, we’ll dive deep into everything you need to know about securing SSH.

I'll also share tips from my own experience to help you go beyond the basics and fully enhance your SSH security.

Preparation

To make the most of this guide, ensure you have a properly set up Ubuntu server.

👉
Check out my guide on preparing Ubuntu servers to ensure your server is properly set up.

If you don’t have one, consider getting a free VPS server to follow along.

Basics

SSH is split into two key parts: the server part, known as sshd, which runs on the server you want to access, and the client part, ssh, used to connect to that server.

Typically, you'd use an SSH client from your laptop to manage the server.

For Windows users, a common choice is Putty, while Mac users can simply use the built-in terminal.

In terms of security, the server side of SSH is what matters most. It's the server that decides on critical security aspects, like whether to allow password authentication or not.

The server's decisions override any preferences set by the client.

The server's SSH settings are found inside the /etc/ssh/sshd_config file.

On the client side, you'll find configuration settings in the /etc/ssh/ssh_config file for system-wide settings, or in the ~/.ssh/config file for individual user settings.

These settings can also be adjusted when making a connection using command-line options.

🙆‍♂️
This guide will primarily focus on the server side of SSH.

Key Considerations

Before we dive into the tips for securing SSH, it's important to remember that not every tip will suit everyone.

Think carefully about which tweaks fit your server's needs. Make sure to really understand each tip and decide if it's right for your setup.

For instance, while disabling password authentication is a common security practice, it might reduce the necessity for tools like Fail2ban.

Remember, we're dealing with settings in the /etc/ssh/sshd_config file.

Before making any changes, it's wise to backup this original file to avoid any unintended disruptions.

💡
Most variables in this file are commented out by default. Remember to uncomment them when changing any value.

Additionally, some server providers might include custom configurations in the /etc/ssh/sshd_config.d/ directory.

I recommend reviewing these files carefully to ensure compatibility with any adjustments you plan to make.

Lastly, it's important to reload the SSH service instead of restarting it. Reloading reduces the risk of losing your connection and being unable to reconnect.

Also, always use the sudo sshd -t command after each adjustment and before reloading SSH. This helps ensure the syntax and options are correct.

The SSH Port

SSH usually runs on port 22, which is well-known to hackers and can lead to brute-force attacks.

To reduce these attacks, it's a good idea to change the default port to a less common one.

Look for the Port variable inside the /etc/ssh/sshd_config file, which by default is commented out and set to 22.

Uncomment it and change the value to a different number, like this:

Port 592

It's important to remember that after changing the default SSH port and reloading SSH, you should use the -p option followed by the new port number when sshing into the server again.

Access Control

Scroll down a bit, and you'll find these three variables, which are commented out:

#LoginGraceTime 2m
#MaxAuthTries 6
#MaxSessions 10

The LoginGraceTime variable specifies how long a user has to finish the authentication process. While the default value is set to 2 minutes, you might want to reduce this to a shorter duration, such as 20 seconds.

The MaxAuthTries variable specifies the maximum number of login attempts a user is allowed to make. The default value permits up to 6 tries. This means a user can attempt to access the server up to 6 times.

After failing all attempts, they are blocked from accessing the server. You might consider lowering this limit to, for example, 3 tries.

The MaxSessions variables controls the maximum number of concurrent sessions allowed per user connection. The default value typically allows 10 sessions. This means a user can have up to 10 active SSH sessions at the same time.

If your server doesn't need to support many simultaneous sessions, you could consider reducing this number. For instance, setting it to 5 could be more appropriate.

LoginGraceTime 20
MaxAuthTries 3
MaxSessions 5

These are my recommended values for these three variables.

Prevent Empty Passwords

On a Linux server, it's possible to create users with empty passwords, which is not recommended because they can access the server without any authentication.

By default, SSH prevents users with empty passwords from accessing the server, but it's always good to double-check.

Look for the PermitEmptyPasswords variable and make sure it's set to no like this:

#PermitEmptyPasswords no

It's commented out by default. If it's already set to no, you can leave it as is.

Idle Timeout Interval

The idle timeout interval defines how long an SSH connection remains active when there's no user activity.

For instance, if you ssh into the server and leave the terminal open without any interaction, this creates an idle session, which can pose a security risk.

Therefore, it's wise to set a timeout interval that automatically closes the SSH connection if the session becomes idle.

This can be configured with the ClientAliveInterval and ClientAliveCountMax variables.

The ClientAliveInterval variable determines the time in seconds the server waits before sending a check-up message to the client to keep the SSH connection alive.

For example, setting it to 60 seconds means the server checks every 60 seconds if the client is still connected.

The ClientAliveCountMax variable sets the maximum number of check-up messages the server can send without receiving a response before terminating the connection.

For example, if it's set to 3 and the client doesn't respond to three messages, the server will end the session.

ClientAliveInterval 60
ClientAliveCountMax 3

These are my recommended values for these two variables.

So, if a client is inactive for 180 seconds (3 checks, 60 seconds each), the server will end the SSH session.

Rhosts

Rhosts, though now uncommon, was once a weaker method for authentication, relying on trusting clients based on their IP address alone.

By default, Rhosts is typically disabled. However, as I often emphasize, it's wise to double-check.

Look for the IgnoreRhosts variable and ensure it is set to yes like this:

#IgnoreRhosts yes

It's commented out by default. If it's already set to yes, you can leave it as is.

X11 Forwarding

By default, SSH can forward X11 sessions, which can be useful for certain graphical applications.

Unless necessary, disable X11 forwarding in SSH, as the X11 protocol isn't security-oriented.

Find the  X11Forwarding variable and set it to no like this:

X11Forwarding no

Disabling non-essential features like X11 forwarding in SSH can greatly strengthen your server's security.

Agent and TCP Forwarding

SSH agent forwarding lets you use your SSH keys to move from one server to another without keeping keys on the first server.

It makes connecting through multiple servers easier but can be risky for security.

SSH TCP forwarding, also known as port forwarding, lets you redirect data between your local and remote machine.

Disable these two features if you don't need them to minimize the attack surface.

Find the  AllowAgentForwarding and AllowTcpForwarding variables and set them to no like this:

AllowAgentForwarding no
AllowTcpForwarding no

I suggest turning them off since they are usually enabled by default, unless it's absolutely necessary for your specific needs.

Root Access

When you first access your server, you might use the root user, but this isn't advisable.

The root user has full control over the server, and it's easy to accidentally cause damage when executing commands as root.

Using a non-root user is safer, as it requires the sudo prefix for administrative tasks and prompts for a password. Additionally, opting for a non-root user enhances security against brute force attacks.

Since the root user is the default on all Linux servers, it's often targeted by attackers trying to guess your password. Using a non-root user can help mitigate this risk.

Therefore, it's always better to use a non-root user and restrict root user access to the server entirely.

🙆‍♂️
If you’ve completed my guide on preparing Ubuntu servers, you should have created a non-root user with root privileges. If not, be sure to check it out.

Locate the PermitRootLogin variable, which is usually commented out by default, and change its value to no like this:

PermitRootLogin no

By doing this, you can access the server only with your non-root user, whose username is not publicly known.

Password Authentication

Accessing your server usually involves using a password with SSH. But a more secure method is SSH key authentication.

This uses two keys: a public key on your server and a private key you keep. You get access when the server verifies you have the private key.

This method is safer than just using a password, as it ensures only someone with the private key can enter the server.

🙆‍♂️
If you’ve completed my guide on preparing Ubuntu servers, you should have created a key pair. If not, be sure to check it out.

Find the PasswordAuthentication variable and set its value to no like this:

PasswordAuthentication no

By doing this, you ensure that the server can only be accessed using SSH keys.

Always remember to keep your private key secure.

Restrict SSH Access

When not every user needs access to the server, it's a good practice to limit SSH access to a select few.

One method is by creating a group, adding necessary users to it, and then utilizing the AllowGroups option to permit only those in the group to ssh into the server.

However, my preferred method is using the AllowUsers option. This allows me to specify exactly which users can SSH into the server.

With AllowUsers, you're effectively granting access to certain users while simultaneously denying it to all others.

If you wish to limit access to selected users only, scroll to the end of the file and add the AllowUsers option followed by the usernames. 

AllowUsers <user1> <user2> <user3>

This ensures that only the specified users can access the server via SSH.

You could also restrict SSH traffic to a single and trusted IP address. This means only that specific IP can connect to your server using SSH.

If you have a fixed, unchanging IP address, I highly recommend doing this. However, it may not be advisable if your Internet Service Provider assigns a dynamic IP that changes periodically.

To set this up, it's quite similar to what I explained earlier about restricting access for specific users. Just use the AllowUsers option like this:

AllowUsers <user>@<ip_address>

This ensures only the specified user from that specific IP can connect via SSH.

AllowUsers *@<ip_address>

This restricts access to the specified IP for all users on the server.

These simple changes add an extra layer of security by allowing SSH access only to approved users from specific IP addresses.

Reloading SSH

After you've made your changes, be sure to reload the SSH service to apply them.

Before that, you should verify the configuration for errors. You can do this using the following command:

sudo sshd -t

Use this command to reload SSH:

sudo systemctl reload ssh

Once the service is reloaded, your changes will be in effect.

You can also use the sudo sshd -T command to list all variables with their values, allowing you to check whether the changes have taken effect or not.

Conclusion and Final Thoughts

I hope this guide has been helpful in enhancing your understanding of securing SSH beyond the basics.

By applying these tips, you can significantly strengthen your server's security.

🙆‍♂️
There's more to securing Linux servers. I’ve created a comprehensive guide on server security and hardening, where I share the exact security measures I implement on my own servers.

If you found value in this guide or have any questions or feedback, please don't hesitate to share your thoughts in the discussion section.

Your input is greatly appreciated, and you can also contact me directly if you prefer.