440,000+ attempts to hack my VPS

A dive into 440K+ SSH attacks on 8 VPS providers. Despite hosting nothing of note, I have been targeted and have been surprised by the data I found.

Published on 2025-07-23 | 9m 26s

One day, I logged into my Hetzner server and was greeted by this message at the top:

There were 4025 failed login attempts since the last successful login.

This server hosts nothing public. It is where I do most of my experimentation on in regards to self hosting. It's also where I run tasks like running a long running code if I need to. Basically, no one except me and Hetzner should even be interested in it.

That's the day I learned a fundamental truth about the internet: the moment you connect a server online, you become a target. It doesn't matter if your server hosts nothing but a "Hello World" page - attackers will find it and probe it relentlessly.

While I wasn't worried as I use an SSH key to log in, this discovery sparked my curiosity. I then created a script to upload the failed logins for analysis. In just three months, I got over 440,000 failed login attempts over my 8 VPS providers.

I mean, some of them were definitely from me mistyping my username or whatnot but I definitely did not do the bulk of those failed logins.

By the way, don't ask why I have 8 VPS providers. I also don't know the answer.

The Security Fundamentals (Skip if You Know This)

Before diving into the data, let me quickly cover the basic security measures I implement on every new VPS:

What I DO:

  1. Disable password authentication and enable public key authentication only. Generate an SSH key and log in only using that key. That alone is usually enough to stop all attacks. It's also more convenient as there's no typing involved so that's also a plus for you.

  2. Close unnecessary ports using the firewall. Keep only 22/SSH, 80/HTTP, and 443/HTTPS. If I need a port, I will temporarily enable it. However, under most circumstances there's no reason to keep more than these three open. Sometimes, I even close HTTP and HTTPS ports if I just need it to run a script.

    Note that closing a port will only close inbound connections and not necessarily outbound ones. So if you're worried that your server will become useless, it won't. If an app communicated with an HTTPS API, it will still be able to do so.

    Also, you might not know this but if you're using Docker, it bypasses your firewall. I legitimately did not know this until around 1 month after using it. Thankfully, no attacks has occured, but this really made me furious on Docker's behavior.

  3. Set PermitRootLogin no. Use sudo to do your root activities. There's no good reason to allow root access in SSH. Even if you somehow need root, you can log in as a sudo user and then do sudo su -.

  4. Install Tailscale. Most of the services I host on my VPS are not meant for other people. So by installing Tailscale, I can make sure that these services bind only to the local port (127.0.0.1 or fe80::1) yet still be accessible everywhere.

    Note that these are things I do. I find Tailscale to be really easy to setup but it really is just Wireguard under the hood. Thus, if you don't need Tailscale's other features or are distrustful of them, you can just use Wireguard. It will do the same thing.

  5. For publicly accessible websites, proxy through Cloudflare. I use Cloudflare, but you can use any other CDN or DDOS protection service. Doing a proxy hides your IP address so if someone wanted to DDOS you, they will have to go through Cloudflare first - which is extremely good at doing this. If I have a public site, any nslookup usually results in CloudFlare IPs. The exceptions are private IP addresses. Like, good luck attacking 100.64.0.0/10 as that's a CGNAT address.

These five steps alone eliminate 99% of successful attacks. But even if you do the first three steps, you can prevent most attacks. I do suggest you invest in DDOS protection if you're hosting anything public as you cannot underestimate how bad it can get.

What I DON'T Do (And Why):

  1. Change SSH port: While changing from port 22 to something like 2200 reduces attack volume, it's security through obscurity. The inconvenience of remembering custom ports outweighs the minimal security benefit for me.

  2. Install fail2ban: Since I've disabled password authentication, even if attackers somehow guessed my password correctly, they still couldn't log in without my private key.

    It's true that fail2ban can also work for other services but given that I only access most things I host through a VPN, it's more likely that I will lock myself out for 10 minutes (or whatever I set) than locking out an attacker. For my threat model, it wasn't worth it.

  3. Whitelist IP addresses: I don't have a static IP, so I'd likely lock myself out when my ISP rotates addresses. The operational risk isn't worth it. I do have a VPN in Tailscale but I enable SSH access for the cases where Tailscale isn't working or isn't available (for example, I might want to use another VPN). I also don't want to accidentally lock myself out the moment I travel to another place.

Building the Monitoring System

Linux always logs every authentication attempt by default - whether successful or failed. The system I used was somewhat simple:

  1. Log Collection Script: A bash script that uploads auth logs to an R2 database. I have thought of doing an sftp to a home server but R2 is very reliable so I decided it wasn't worth the hassle.
  2. Data Processing: The logs are parsed and stored in PostgreSQL. Initially, I used SQLite but I started needing features like IP address lookups that were incredibly slow on SQLite (it crashed my PC many times).
  3. IP Enrichment: Each IP is enhanced with geolocation and ASN data for analysis.

Here's the core upload script:

#!/bin/bash
DEVICE="device_name"
UPLOAD_URL="https://endpoint"
TEMP_FILE="${LOG_FILE}.upload"

# OS Detection & Log Path Setup
if [ -f /etc/redhat-release ]; then
    LOG_FILE="/var/log/secure"          # RHEL/CentOS
elif [ -f /etc/debian_version ]; then
    LOG_FILE="/var/log/auth.log"        # Debian/Ubuntu
else
    echo "Unsupported OS. Exiting."
    exit 1
fi

# Copy, upload, and truncate on success
cp --preserve "$LOG_FILE" "$TEMP_FILE"

response=$(curl -s -o /dev/null -w "%{http_code}" \
    -F "file=@$TEMP_FILE" \
    -H "device:$DEVICE" \
    -H "type:ssh" \
    "$UPLOAD_URL")

if [ "$response" -eq 200 ]; then
    echo "Upload succeeded. Truncating original log."
    sudo truncate -s 0 "$LOG_FILE"
    rm -f "$TEMP_FILE"
else
    echo "Upload failed (HTTP $response). Log preserved."
    rm -f "$TEMP_FILE"
    exit 1
fi

The Data: 440,000+ Attacks Across 8 Providers

This turned out to be a bit more interesting than I expected. That said, I'm a nerd and I don't think a random person would find this interesting at all. Or maybe they would. Who knows?

Attack Volume by Provider

Most of my providers are from Europe and the US. The Asian landscape is pretty barren when it comes to affordable VPS. Compared between the two, European VPS providers are much more attacked:

Provider Attack Count
Servitro 135942
Hetzner 78982
Layer 7 73918
Servarica 59808
Contabo 54191
GCloud (TWN) 28383
Racknerd 11701
In general, per day the most hit is Servitro. I don't know why this VPS provider gets so much hate but it's not something they can do much about. And graphing it out, it looks like you can generally expect ~1000 attacks per day on each VPS you place in the internet.
A graph of the daily attacks in my VPS
A graph of the daily attacks in my VPS. Median is 8203 attacks per day

Geographic Distribution of Attacks

That being said, I was also incredibly curious about where attackers come from. Now, take this data with a grain of salt - there are many caveats here. First, I don't know if these are from the attackers computers or something they infected. I also don't know if the data I got my IP from is accurate at locating the data. This is really more of a "huh - that's interesting" kind of data than something to act on.

A graph of the originating country IPs
A graph of the originating country IPs. Values are shown below on the table
Country Count
RUS 🇷🇺 134621
CHN 🇨🇳 53476
USA 🇺🇸 30614
VNM 🇻🇳 21975
GBR 🇬🇧 19092
HUN 🇭🇺 16325
SGP 🇸🇬 16129
NLD 🇳🇱 15067
IND 🇮🇳 12423
KOR 🇰🇷 11071
Other Countries 112122

No surprises here - Russia, China, and the US dominate the attack landscape, accounting for nearly half of all attempts (~49.4%). Then again, we don't know how many of these are "legitimate IPs being used to attack". Some of these could be a random IoT camera infected with malware or a VPS from a provider in this country. It is pretty interesting to see the trends play out though.

Most Problematic ASNs (Internet Service Providers)

ASN or Autonomous System Number is kind of how you can determine who owns which IP addresses. That's how sites like "What's my IP" generally figure out what your internet provider is. I was pretty interested in which providers were bad.

A graph of the most problematic ASNs
A graph of the most problematic ASNs. Values are shown below on the table
ASN Provider Attacks
Proton66 OOO 128658
DigitalOcean, LLC 37295
SS-Net 16291
UNMANAGED LTD 14836
cheapy.host LLC 13281
Viettel Corporation 10532
Zhengzhou Fastidc Technology Co.,Ltd. 9818
Limited Network LTD 8524
Korea Telecom 8120
CHINANET-BACKBONE 7003
Other 188505

Proton66 stands out dramatically. I didn't hear of the provider before so I searched and just recently they have been said to be harboring cybercriminals. Makes sense why they have almost 3.5x the attacks as the next.

DigitalOcean's presence in the top 5 is concerning but not entirely surprising - as one of the largest cloud providers, it's bound to have some abusive users. However, the volume suggests they may need better abuse detection systems.

Seriously, I expected them to appear somewhere on the list but Top 2? Digital Ocean, you may need to vet your customers better.

The Most Targeted Usernames

Perhaps what surprised me the most is actually the data on the most targeted usernames:

Username Count
admin 97263
user 84295
root 34588
ubuntu 15096
invalid 14104
debian 10462
test 5804
oracle 3949
jackson 3469
ftpuser 2972
Other 170923
admin and user beats root as the most targeted username. Honestly, it weirds me out that this is the case since I expected root to be the clear winner. I'm not going to say to stop using these as if you enable SSH authentication, it shouldn't be too much of a worry. However, how did this beat root?

Random names like jackson appear frequently (possibly from leaked databases). Is Jackson a common IT nickname? I'm calling every incompetent IT person Jackson now.

Conclusion

I recently got an IPv6 address (yay!) so this data actually prepared me. NAT doesn't exist anymore so the firewall is actually mine to manage now. I'll probably post one soon when I can.

That being said, I actually scoured my data for IPv6 attacks. There are no attacks. Not almost none - none at all. All attacks come from IPv4 which I guess should mean upgrading to IPv6 can give some security benefit. That being said, this is short-lived as most of the valuable targets are still on IPv4 infrastructure like corporations.

Again - IPv6 is NOT a security feature. It's just that if you are dealing with someone who is convinced that NAT somehow protects them, I guess this can be a counterargument (though a bad one to be sure).

While seeing 440K+ failed login attempts might seem alarming, it's actually reassuring evidence that proper security measures work. Not a single attack succeeded across any of my servers. And I don't think they will anytime soon.

Want to implement similar monitoring? The complete code and setup instructions are available in my GitHub repository.