← All posts

Securing a Linux Server with Fail2Ban and a Custom SSH Port

Originally published on Server Mastery - original post, 2023-08-27. Republished here with light edits.

Let me explain this the way I would to someone who has never touched a server before.

Every computer that is reachable from the internet has "doors" - technical name: ports. One specific door, numbered 22, is the one used for SSH, which is simply the remote control for your server. It is how you (or anyone) types commands into a server from far away, like a screen-sharing session but text-only.

Here is the problem: everyone knows door 22 is the SSH door. So all day, every day, automated programs called bots go around the entire internet, knocking on door 22 of every single server they can find, trying common usernames and passwords over and over. This is called a brute-force attack - not a targeted hacker, just a robot playing the odds on millions of servers at once. I have never put a server online that did not get these knocks within hours.

Two simple things fix almost all of this:

  • Move the door. Change SSH from port 22 to some other number. The lazy, automated bots only check port 22 - they will not even find your door.
  • Hire a bouncer. Install a program called Fail2Ban that watches who is knocking. If someone gets the password wrong a few times in a row, Fail2Ban locks them out for a while, automatically.

Neither trick alone is "real" security - a determined attacker can still find the new port, and a bouncer cannot stop someone who already has the right key. But together, they remove essentially all of the automated noise, which is 99% of what actually hits a typical server.

What you need

I originally tested this on Debian 10 and CentOS 7. The exact commands below still work the same way on any current Debian, Ubuntu, or RHEL-based system (Rocky Linux, AlmaLinux, etc.) - only the very first command (how you install software) changes between the two.

Step 1: Update the system first

Before changing anything security-related, make sure the server's software is current - this closes any known holes that already have a fix available.

# Debian / Ubuntu
apt-get update && apt-get upgrade && apt-get dist-upgrade

# CentOS / RHEL / Rocky / Alma
yum update

Step 2: Move SSH to a different door number

Open the SSH settings file - this is the file that controls how the remote-control door behaves:

nano /etc/ssh/sshd_config

Look for a line that says #Port 22 (the # means it is currently "commented out", i.e. ignored). Change it to a real, active line with a different number:

#Port 22
Port 21348

You can pick any free number above 1024 - 21348 is just an example. Whatever you choose, write it down somewhere safe. From now on, every time you connect you will need to mention this number, for example: ssh -p 21348 yourusername@yourserver. If you forget the number, you will not be able to get back in through SSH.

Step 3: Install Fail2Ban, the automatic bouncer

apt-get install fail2ban

Step 4: Copy the settings file (do not edit the original)

Fail2Ban comes with a default settings file called jail.conf. Updates to Fail2Ban can silently overwrite that file later, wiping out anything you changed in it. So the standard practice is: never edit jail.conf directly - instead make a copy named jail.local, and edit that copy.

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Step 5: Tell the bouncer what to watch and how strict to be

nano /etc/fail2ban/jail.local

Find (or add) these lines. bantime is how long someone gets locked out, and maxretry is how many wrong attempts they get before that happens:

bantime = 60m
maxretry = 3

[sshd]
enabled = true
mode = aggressive
port = 21348
logpath = %(sshd_log)s
backend = %(sshd_backend)s

[dropbear]
enabled = true
port = 21348
logpath = %(dropbear_log)s
backend = %(dropbear_backend)s

Important: the port number in this file has to be the exact same number you set in Step 2. If they do not match, Fail2Ban keeps watching the old, empty door and never actually protects your real one.

Step 6: Save, and restart both programs so the changes take effect

In the nano text editor, save with Ctrl+X, then press Y, then Enter. Then restart both services:

systemctl restart sshd
systemctl restart fail2ban

Do not close your current connection yet. Open a second, separate connection window and test that you can still log in using the new port number. If something is wrong with the settings and you get locked out, your first window - still connected on the old session - is what lets you go back in and fix the mistake. If you close it before testing, and something is broken, you may need help from your hosting provider to get back in.

Two more things worth doing while you are in there

Changing the door and hiring a bouncer stops the automated noise, but a careful setup goes one step further:

  • Turn off password logins entirely, once you have a key set up. A "key" is a more secure way to prove who you are than a password - it cannot be guessed by a bot no matter how many attempts it makes. Once your key works, set PasswordAuthentication no in the same sshd_config file. After this, no password - guessed or not - can get anyone in through SSH at all.
  • Add a firewall (a program like ufw on Debian/Ubuntu, or firewalld on CentOS/RHEL) so that only the doors you actually use - your new SSH port, and whatever your website or app needs - are reachable from the internet at all. Everything else stays closed by default.

That is the whole setup. It takes about ten minutes and removes the vast majority of automated attack attempts a server will ever see. Happy to talk through your specific setup - see the contact section on the homepage.

← All posts