Bots found my home server in minutes, but 3 settings shut them out

Bots found my home server in minutes, but 3 settings shut them out


I needed a cleaner way to SSH into homelab servers without exposing any internal services. A small Linux SSH jump server was the answer. It could just sit on the edge of the network and give me one controlled entry point with everything else tucked away behind a network firewall.

The only problem is I hate deploying public-facing servers with vulnerable ports because it’s like painting a big target sign on my home IP address.

Within half an hour of putting the server online, the logs were already full of login attempts from random IP addresses. Not one or two curious knocks, either. Hundreds of attempts had hit a server that didn’t even exist an hour ago.

So, I made three fairly simple changes that significantly stopped the noise and turned a password-friendly SSH target into something more secure.

The bots found my jump box before I finished building it

Port 22 had made my server an irresistible target for bots

This new server only had one job. It just needed to act as a controlled SSH entry point into my home-ops setup, not become another public-facing attack vector for bots. There weren’t any dashboards, web servers, or file shares waiting behind a login screen. It was just a boring old SSH box on my edge network.

Before locking it down, I wanted to check what was actually listening. This command showed me the most recent SSH noise:

sudo ss -tulpn

That showed what I expected. That SSH was listening on port 22, and that’s it. At this point, the server had only been up for about one hour, so I wanted to see any recent failed attempts at port scanning and SSH authentication:

sudo journalctl -u ssh --since "1 hour ago" | grep -Ei "failed|invalid|disconnect|authentication"

There were already hundreds, and the usernames attempted were the same lazy guesses like root and admin. But there were some interesting attempts with usernames like vagrant, ansible, minecraft, and jenkins. I used this command to summarize the top ones:

sudo journalctl -u ssh --since "1 hour ago" | grep -Eio "invalid user [^ ]+" | sort | uniq -c | sort -nr | head

The source IPs were also quite varied, rather than belonging to a single address:

sudo journalctl -u ssh --since "1 hour ago" | grep -Eio "from ([0-9]{1,3}\.){3}[0-9]{1,3}" | awk '{print $2}' | sort | uniq -c | sort -nr | head

The output showed that it wasn’t a targeted attack. It was just the usual bot traffic that starts almost immediately after putting a Linux SSH box on the public-facing internet.

Moving SSH off port 22 made the server feel less exposed

It did not make SSH secure, but it stopped most of the drive-by noise

Linux Ubuntu SSH server with SSH port moved to a higher service port

Changing the SSH port is typically the first Linux hardening step I take with every public-facing Linux server I deploy. I don’t pretend that shifting port off of 22 means I can suddenly declare the server hardened. In fact, it won’t do a single thing if someone is determined to find an open SSH port.

It does, however, significantly reduce the log noise from automated bot scanning because it stops my server from looking like a honeypot. Most of the junk scans hitting my server didn’t have much smarts behind them. It was just automated traffic looking for the default SSH port and trying the same old username guesses over and over.

Rather than editing the main config directly, I added my own SSH config file:

sudo nano /etc/ssh/sshd_config.d/99-homeops-hardening.conf 

The first and most important setting was simple:

Port 52522

Before reloading SSH, I opened the new port in Ubuntu’s UFW (Uncomplicated Firewall). The point of this was to stop me accidentally locking myself out of SSH once the new config kicked in on reload.

Then I tested the new login from another terminal:

ssh -p 52522 home-ops-relay@ggcontentlabs.com 

Only after that was the old SSH firewall rule for port 22 finally removed:

sudo ufw delete allow OpenSSH 

Changing the port can kind of be thought of as moving the doorbell way away from the street rather than magically making SSH invisible. It doesn’t offer protection against brute force attacks (that comes later), but it stops the bot traffic dead in its tracks.

With Ubuntu specifically, if you’re changing the SSH port from an existing SSH session, you’ll need to disable the ssh.socket listener AFTER you’ve confirmed the new port works.

Key-only login made password guessing irrelevant

The bots could still knock, but I stopped offering the lock they were picking

Powershell SSH attempt to authenticate with Linux server with and without private key

Moving SSH away from the port instantly made the logs quieter, but this change makes it much safer. Most of the automated bot scanning tried to use usernames and passwords over and over again, hoping I was silly enough to use a common dictionary word for my root password.

Making a complex password with a passphrase tool for root is just good security practice, but the real fix to password guessing is switching my own login over to SSH keys instead. Instead of proving who I am with a password, my laptop uses a private key that matches the public key stored on the server.

Once I confirmed the key-based SSH was working, I added these settings to my SSH hardening file from the previous step:

sudo nano /etc/ssh/sshd_config.d/99-homeops-hardening.conf 

PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no

Then I tested the SSH config before reloading it:

sudo sshd -t
sudo systemctl reload ssh

This now meant that the bots could password-guess all day long but never gain access. I also disabled direct root login, but only after creating a new user account and giving it sudo access:

sudo adduser home-ops-relay-admin 
sudo usermod -aG sudo home-ops-relay-admin 

Then move the SSH key over for that account:

sudo mkdir -p /home/home-ops-relay-admin/.ssh sudo cp ~/.ssh/authorized_keys /home/home-ops-relay-admin/.ssh/authorized_keys sudo chown -R home-ops-relay-admin:home-ops-relay-admin /home/home-ops-relay-admin/.ssh sudo chmod 700 /home/home-ops-relay-admin/.ssh sudo chmod 600 /home/home-ops-relay-admin/.ssh/authorized_keys 

Finally, I tested the configuration by forcing a password-only SSH attempt against the new port:

ssh -o PreferredAuthentications= -o PubkeyAuthentication=no -p 52522 home-ops-relay@ggcontentlabs.com 

The test failed, which is exactly what I needed to see. Logs would still show the connection attempts, but the attempts no longer really mattered.

Fail2ban stopped repeat offenders from getting unlimited chances

The jump box finally started telling noisy strangers to go away

Fail2ban local jail custom configuration and logged jailed IP addresses from incorrect authentication attempts

Moving the SSH port away from 22 and switching to key-only login, the server was already less inviting and far less noisy. But I still needed one last layer to block any bots that kept on poking.

Fail2ban is my go-to Linux tool for doing just that. When the same IP address fails too many times within a set window, Fail2ban will temporarily block it at the firewall level. On my jumpbox that’s sitting on the public internet, it’s one of the best safety nets I can install to give me peace of mind.

Fail2ban is easy to set up and configure, even when I changed the SSH port:

sudo apt update 
sudo apt install fail2ban 

Then I created a local jail config for SSH:

sudo nano /etc/fail2ban/jail.d/sshd.local 


[sshd] enabled = true 
port = 52522 
maxretry = 3 
findtime = 10m 
bantime = 1h 

Then I just enabled Fail2ban, generated some interesting failed attempts from my mobile connection to test, and checked the SSH jail:

sudo systemctl enable --now fail2ban 
sudo fail2ban-client status sshd 

Fail2ban is the last of the three steps to stop the bots dead. It’s like my personal server bouncer, standing behind the existing hardening and blocking any persistent bots that just wouldn’t accept failure.

fail2ban-1-to-1

Price model

Open-Source

Operating System

Linux, FreeBSD, Homebrew, Docker

Fail2ban is a lightweight intrusion-prevention tool that watches service logs for repeated failed login attempts and temporarily bans offending IP addresses using firewall rules.


My SSH jumpbox is now ready to exist (relatively) bot-free

The bot noise level had dropped from a constant roar to a few whispers

Custome bash script output of final logs, fail2ban jails, and ports involved in the 3-step hardening process for Linux

I just needed a simple job box, not a whole new security project. But unfortunately, as soon as a new server touches the public internet, even if that’s just an SSH port, it becomes one. My new server, overwhelmed by bot traffic within minutes of booting up, proved that.

Moving SSH off port 22 dramatically reduced the number of hits my server took from automated scanning bots. Switching to key-only login for SSH removed the threat and annoyance of password guessing as an attack. Finally, Fail2ban gave any lingering repeat offenders a nice little timeout when they kept hammering away at my server.

Of course, none of this makes SSH invincible. Still, I perform these three basic hardening steps for every single Linux server I deploy to the public-facing internet, and I recommend anyone doing the same to do this too.

I cannot stop the internet from being a hostile place for homelab servers. Bots will still scan, bad usernames will still appear occasionally in the logs, and public servers will always demand caution. But with these hardening steps, I turn all my noisy targets into something less appealing to bots.



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *