← Notes & write-ups

What a third of a million failed logins taught me about my server

20 June 2026· 3 min read

This site runs on a small, internet-facing Linux server. A few weeks after it went live, I opened the authentication logs out of curiosity and was not ready for the scale.

Filtering for failed SSH logins, the username "root" alone had been tried 291,215 times. Counting the rest pushes the total past 400,000 failed attempts. They were not evenly spread. A handful of hosts dominated: 62,798 tries from one IP, 62,231 from another, then a long tail each in the tens of thousands.

The usernames they guessed read like a cheat-sheet of automated playbooks: root, ubuntu, admin, user, test, oracle, postgres, git, mysql, debian. None of it is targeted at me. It is internet-wide background noise: botnets sweeping every reachable address, spraying default usernames at the SSH port. Almost none of those accounts even exist on the box.

I also looked up where the busiest sources came from, and the answer was telling. The two heaviest attackers, about 62,000 attempts each, were both cloud VMs inside AS63949, which is Akamai Connected Cloud, the network that used to be called Linode. I had them written down as two separate operators until I looked the ASN up. The rest traced to Microsoft Azure, Hetzner, and ISPs across Myanmar, Slovenia, Bangladesh, Vietnam, Ireland and Finland. That is the modern shape of brute-force: cheap rented or compromised cloud machines doing the work. My first draft of this post said that blocking one IP barely moves the needle, and my own table says otherwise. The two busiest hosts account for 125,029 attempts between them, close to a third of everything I logged, and blocking them would have been worth doing. What blocking does not buy is a lower arrival rate for long, because the next rented VM costs the operator a few cents and the address was never the asset.

Seeing it laid out was clarifying: every internet-facing host lives inside this constant hum of opportunistic attacks. The question is not whether you are probed. It is whether the easy attacks have been made pointless. So I looked at my own part of the setup through that lens:
• The database and app never touch the public internet. They are bound to localhost behind a reverse proxy; only the static site and a locked-down API are exposed.
• The web layer sends proper security headers, and the admin surface is gated.

And the clearest hardening lessons the data argues for:
• Key-only SSH. With no password to guess the attempts keep arriving and stop being able to land, which turns the whole category from risk into wasted traffic.
• Rate-limiting and lockout, so no single host can hammer the server thousands of times an hour.
• Turning logs into signal, so an alert fires when the pattern changes, because a new attacker doing something unusual matters far more than a bot trying "root" for the 291,216th time.

This is a first pass on a small server, not a SOC. But it taught me the most useful thing about defense so far: most of it is not clever, it is structural: reduce what is reachable, remove the weak door, then actually watch. That’s the part of blue-team work I want to get good at.

Methodology & sources / Phương pháp & Nguồn:
- The numbers in this post come straight from my own server's authentication logs (auth.log / journalctl, filtered for failed SSH logins); the busiest source IPs were attributed with public WHOIS/RDAP. This is primary data and you can check it. The parser and the two Sigma rules are at github.com/daihongphucecq/soc-ssh-analysis; the script runs against any auth.log and prints the same tables.
- Technique classification, MITRE ATT&CK: Brute Force T1110 — with the observed behaviour matching Password Guessing T1110.001 and Password Spraying T1110.003.
- Companion post on this site: "AutoJack and the wall that was never there."