1. Change your sshd
listening port
As simple as it sounds, changing your port from the default 22
to a custom value (e.g. 2200
) on a public IP could reduce the number of port scans from thousands a day to a few dozen. For a tutorial see here.
That being said, while this does reduce the annoyance of being port-scanned, it DOES NOT provide real security. "Security by obscurity" is a myth and nothing more.
2. Use public key login and disable password login
Bots might guess a password right, but they're never going to guess a private key right. As long as you use modern algorithms and don't leak your key accidentally. For a tutorial see here.
Note that this does mean you will no longer be able to login from any random machine, unless you carry the key with you (which you need to secure via some other way).
3. Use fail2ban
If they fail 5 times, ban them from trying again for a day or something. That'll show them. Very effective against brute force attempts. For a tutorial see here.
The downside is that you might lock yourself out if you've got wobbly fingers one day (drunk or something, I don't know).
4. Pre-ban a list of IPs known for abusive use
Sources like AbuseIPDB maintain big lists of known malicious IPs accessible via API. You will need an API key to use it, but you can register a free account easily enough. Pull the list and use something like iptables
to ban those known IPs in bulk. Set up a cron job to automate it periodically for best effect. Here's a very simple script I wrote (and am personally using) to do just that. Feel free to use it as reference, but DON'T USE IT IN PRODUCTION.
In my personal experience, this method is equally effective (if not more so) as method #3.
Personally, I use all 4 methods listed above, and my VPS might get one or two malicious login attempts in my security log at most, in a bad month. Here's the interception history of iptables
via method #4:
$ abip-hist
Chain abip-ban (1 references)
pkts bytes target prot opt in out source destination
362 14480 DROP all -- * * 45.143.200.6 0.0.0.0/0
307 12280 DROP all -- * * 185.156.73.104 0.0.0.0/0
288 12672 DROP all -- * * 212.133.164.75 0.0.0.0/0
277 19911 DROP all -- * * 146.88.240.4 0.0.0.0/0
250 11000 DROP all -- * * 212.133.164.14 0.0.0.0/0
230 9200 DROP all -- * * 45.146.164.213 0.0.0.0/0
215 8600 DROP all -- * * 185.156.73.67 0.0.0.0/0
214 8560 DROP all -- * * 5.188.206.18 0.0.0.0/0
202 8080 DROP all -- * * 193.27.228.63 0.0.0.0/0
201 8040 DROP all -- * * 193.27.228.64 0.0.0.0/0
199 7960 DROP all -- * * 193.27.228.59 0.0.0.0/0
197 7880 DROP all -- * * 193.27.228.65 0.0.0.0/0
197 7880 DROP all -- * * 193.27.228.61 0.0.0.0/0
196 7840 DROP all -- * * 45.135.232.119 0.0.0.0/0
196 7840 DROP all -- * * 193.27.228.60 0.0.0.0/0
196 7840 DROP all -- * * 193.27.228.58 0.0.0.0/0
189 7560 DROP all -- * * 45.146.165.149 0.0.0.0/0
184 7360 DROP all -- * * 45.155.205.247 0.0.0.0/0
184 7360 DROP all -- * * 195.54.160.228 0.0.0.0/0
182 7280 DROP all -- * * 45.143.203.12 0.0.0.0/0
181 7240 DROP all -- * * 45.141.84.57 0.0.0.0/0
180 7200 DROP all -- * * 45.135.232.85 0.0.0.0/0
176 7040 DROP all -- * * 45.146.165.148 0.0.0.0/0
...
this goes on for 1700 lines...
$ uptime
06:36:49 up 16 days, 15:24