From status pings to internet-wide radar
A short history of Minecraft server scanners — from hand-typed IPs and the 0xFE ping, through protocol rewrites and internet-wide scans, to what discovery looks like today. With code from every era.
Every Minecraft server scanner is an answer to the same question a kid asked in 2010, typing an IP address into a forum post: is this server up?
The tools that answer that question have been rewritten three times, driven by protocol changes, an arms race of player-count vanity, and eventually the same internet-wide radar that indexes the rest of the web. This is the history — with the actual code from each era.
Era one: the ping and the forum post (2010–2013)
Early multiplayer Minecraft had no server discovery. You found servers through word of mouth and forum threads, and “scanning” was a friend saying “yeah it’s up, I just played.”
Then came the status ping — the original 0xFE packet. Send a single byte
to port 25565, get back a binary blob: MOTD, player count, max players.
That was the entire product, and it was enough to build the first
generation of tools: desktop checkers, forum widgets, and the first server
lists with live player counts. The whole scanner fit in a screenful:
import socket
s = socket.create_connection(("play.example.com", 25565), timeout=5)
s.sendall(b"\xfe") # the entire request
data = s.recv(512)
# response: 0xFF length, 0xA7 magic, then UTF-16 fields
fields = data[3:].decode("utf-16-be").split("\x00")
motd, online, maximum = fields[-3], fields[-2], fields[-1]
print(f"{motd} — {online}/{maximum} players")
The economics were simple. Server owners needed the front page of a server list, because that was the only discovery surface that existed. Player counts became the currency of the entire ecosystem — which is why the first scanner-adjacent industry was, honestly, fake player counting.
Era two: the protocol rewrite (2013–2016)
1.7 threw the old ping away. The modern handshake arrived: connect, send a handshake packet with “status” as the intent, receive a JSON blob — MOTD, favicon, version, players, and crucially protocol version numbers.
This was the moment scanners became real software. The JSON was structured enough to diff, graph, and archive. The handshake got a varint-framed binary layout, but the community wrapped it in a library almost immediately, and scanning collapsed to three lines:
from mcstatus import JavaServer
server = JavaServer.lookup("play.example.com") # resolves SRV records
status = server.status()
print(status.motd) # parsed chat components
print(status.players.online) # int
print(status.version.protocol) # the real fingerprint
Server lists grew live graphs. Continuous trackers started polling thousands of servers on a schedule — the first time you could watch an entire network breathe, or watch a big server die in real time.
It was also the era of the vanity arms race: player counts were ranking currency, so servers lied about them, so scanners got paranoid. The first cheating was idle bots padding the count; server lists added activity checks; the bots wandered around. The second generation was subtler — servers reporting thirty players while four were online, straight from the status response. That forced a split that still exists: trust the response, or verify it by connecting a real client session and counting joins. Trust-based scanners stayed fast and cheap; verification-based scanners became heavy, stateful, and accurate. Countermeasures got creative on both sides — servers fingerprinted scanners by handshake timing and served them lies, scanner operators rotated IPs and randomized intervals, and server owners embedded invisible formatting codes in MOTDs to corrupt naive parsers. It’s the exact web-scraping arms race, in miniature, fought by teenagers over leaderboard positions.
Era three: the internet notices (2016–2021)
Meanwhile, the people who scan everything noticed 25565.
Masscan and ZMap made internet-wide scanning cheap — minutes to sweep the full IPv4 space — and Minecraft’s handshake is short enough to use as a banner-grab target:
# find every Minecraft server on the planet
masscan -p25565 0.0.0.0/0 --rate 100000 -oG scan.txt
# then shake hands with each survivor to get the real status
Suddenly Censys and Shodan had Minecraft servers indexed alongside routers
and cameras. The Shodan query language made the census searchable:
product:"Minecraft Server" port:25565, filter by version, by country, by whether the MOTD suggests cracked authentication. Operators discovered
their own hidden backends — the ones behind proxies, never linked anywhere
— indexed next to printers and webcams.
The griefing community understood the implications before the defenders did. For raid-focused groups, a scanner became target acquisition: enumerate, filter for small and unguarded, check the version against a list of known exploits. A fresh vulnerability in a popular server jar meant an instant, sortable list of every server in the world still running it. The player-sample field — intended for vanity widgets — leaked staff alt accounts during the big anarchy-server incursions, because a status ping hands a sample of who’s online to anyone who asks.
Some of this is documented in unusual detail, because one incident forced the whole ecosystem to pay attention.
Log4Shell: the week everyone learned what a scanner was for
When Log4Shell landed in December 2021, Minecraft was the most exposed consumer software ecosystem on the internet: hundreds of thousands of Java servers, most running some version of Log4j, most publicly reachable on a well-known port.
The scanners arrived within hours — probing shaped specifically for Minecraft, pushing payloads through chat, MOTDs, and handshake fields, because those strings get logged and logged strings were the injection point. Server lists became target lists. For about a week, “is this server patched?” was answerable from a scanning dashboard before it was answerable by the server’s own admins.
The community response was improvised and strange: server software shipped
filters banning the ${ character sequence from chat entirely — censorship
as a firewall rule. The quieter aftermath mattered more: DDoS-for-hire
operations mined the same indexes for targets, and “we found you with a
scanner” became a standard opening line in a raid.
Today: dense, cached, and uncomfortable
Which brings us to now. The modern scanner pulls a lot from one handshake: SRV resolution, MOTD parsing (legacy and component JSON), favicon, player counts and samples, mod indicators (Forge/Fabric handshake data), geo-IP, and version intelligence. Almost nobody hand-scans anymore — the fresh census lives in a few big indexes and status APIs, and everyone else reads from them.
The modern scan is also no longer one packet. It’s a small state machine:
import asyncio
from mcstatus import JavaServer
async def probe(addr: str) -> dict:
server = JavaServer.lookup(addr) # SRV resolution
status = await server.async_status() # Java handshake
return {
"addr": addr,
"proto": status.version.protocol, # true protocol version
"software": status.software or "?", # brand, when the server admits it
"players": status.players.online,
"sample": [p.name for p in (status.players.sample or [])],
}
async def sweep(addrs: list[str]):
return await asyncio.gather(*(probe(a) for a in addrs))
…and that’s only the Java half. Bedrock is a separate protocol on a separate port — an unauthenticated raknet ping — so any scanner worth the name runs two engines. The handshake negotiation leaks the mod platform (Forge and Fabric respond differently), and the status response leaks everything else. A modern scanner walks away from one exchange knowing the address infrastructure, true protocol version, software, mod platform, player count, a sample of who’s online, and — in the favicon, often literally — the operator’s Discord invite. That’s not a ping anymore. That’s a census form the server fills out for you.
What the census taught us
A decade of scanning produced a longitudinal census nobody set out to build, and a few findings generalize.
The version long tail is eternal. The most popular protocol version on the internet is always several years out of date — whole communities standardize on an old version for performance or PvP mechanics and stay for a decade. The median Minecraft server is a museum.
Hosting is concentrated. The “thousands of independent owners” map is mostly a map of five or six datacenter networks, which is why one provider outage takes out a visible slice of the ecosystem at once.
The ecosystem breathes. December swells the numbers, school weeks deflate them, and every update produces a spike-and-decay curve you can set your watch by.
Most servers are empty. A few thousand servers hold nearly all the players; the tail is millions of boxes running for a friend group of three. The scanner world’s dirty secret is that most of its traffic is spent re-checking empty machines.
The defenders’ handbook
Being scannable is a choice you didn’t know you were making, and operators developed a playbook for un-making it.
The first move: make the status response boring — hide the player sample, blank the MOTD. The server does nothing dishonest; it just declines to fill out the census form. Every scanner author has had to decide whether an empty response is a dead server or a shy one.
The second is structural: behind a proxy network, backends live on internal addresses that never resolve publicly. SRV records were an operator convenience that doubled as the first access-control layer. The census mostly indexes misconfigurations.
The third is hostile: fingerprint the polling pattern, serve the scanner a fake count. It’s exactly as reliable as fingerprinting ever is — it burns legitimate tools and occasionally fools the dishonest ones.
The fourth is the interesting one: consent. Crawler web got robots.txt, an honor-system protocol that mostly works. Minecraft scanning never got its robots.txt — the technology to scan is trivial, the technology to refuse is nearly nonexistent, and the gap between those two is where everyone’s arguments live.
Where it goes
The trajectory points the same direction as the rest of infrastructure: continuous, passive, and inferred. Player counts are already graphed continuously; the next step is inference from that telemetry — detecting dying networks, botted counts (the counterfeit war never ended, it moved into statistics), and outage patterns across the long tail.
One quiet thing holds it all together: the handshake kept the old ping working through the rewrite, kept version negotiation open-ended, and kept the status response self-describing — so a scanner from 2013 still gets answers from most of the internet. Minecraft server scanning is one of the only corners of the internet where a thirteen-year-old tool still works in production, and that’s not an accident. It’s the rarest kind of engineering discipline: leaving the door open behind you.
The kid’s question from 2010 got answered. The interesting questions now are all variations of what else can one handshake tell you? — and, if you’re the one being scanned, whether you ever agreed to answer it.