A community CS2 or TF2 server gets a "the server's down" complaint roughly every 90 seconds during peak hours, and the first thing to check is almost never SSH or the logs. It's a single A2S_INFO packet — 25 bytes out, ~120 bytes back — that tells you in under a second whether the server is up, healthy, on the wrong map, or quietly rate-limiting your queries.
What A2S_INFO actually returns ¶
Send FF FF FF FF 54 53 6F 75 72 63 65 20 45 6E 67 69 6E 65 20 51 75 65 72 79 00 (UDP) to the game port. Since the 2020 challenge handshake update, the first response is usually FF FF FF FF 41 + a 4-byte challenge — repeat the request with the challenge bytes appended and you get the real reply. Inside that reply:
- Server name + map name (lets you confirm which server you're hitting if there are multiple instances on the same host)
- App ID (730 for CS2, 440 for TF2, 4000 for Garry's Mod, 252490 for Rust)
- Players online + max + bot count
- VAC enabled flag
- Game version
That's five distinct facts in one round-trip. Most heavier checks (rcon, log tail, console connect) take 30+ seconds and tell you fewer of them. Start with A2S.
Five things a missing or wrong A2S response is telling you ¶
1. Total timeout — UDP can't reach the box
Most often a firewall change, less often a real outage. If your web control panel for the host is up and the dedicated server's TCP rcon port responds, but UDP A2S times out, you're looking at a network-layer block specific to the game port. Hetzner's default firewall, Vultr post-attack mitigation, and OVH's Game-DDoS profile all do this.
Confirmation: nc -uv <host> 27015 from a known-good client. If nc reports "Connection refused" or hangs without a banner, UDP is filtered upstream of your dedicated server's listener.
2. Challenge response only — never the full reply
You get the 0x41 challenge byte back, send the follow-up with the challenge appended, and… nothing. This is almost always SourceTV in a degraded state — it shares the A2S query handler, and a stalled SourceTV thread can block the second-stage response while still returning the initial challenge.
Fast diagnosis: tv_status in srcds console. If it reports a high latency or a hung viewer, tv_stop + tv_relay 0 usually frees it. The full A2S response should return within seconds.
3. Wrong app ID
The reply parses, but the App ID field doesn't match what you're running. This means either (a) you're hitting an old stale srcds instance that didn't get killed during your last restart, or (b) someone else's CS:GO leftover is squatting on the port your CS2 server tried to bind. Both are common after a forgotten screen session.
ss -lup | grep 27015 to see the actual listening process. If the PID isn't your current srcds, kill it and restart cleanly.
4. Player count obviously wrong (e.g. shows 0 when 24 are connected)
Source-engine servers running plugins that hook the player-count handler (some MetaMod / SourceMod hide-player addons, some redirect plugins) can blank A2S without affecting the actual player list. Compare A2S's number to status in console. If they disagree by more than the bot count, a plugin is intercepting; check your addons/sourcemod/plugins dir for anything ending in fakeclients, showdowncount, or privacy.
5. Intermittent timeouts — A2S works most queries, fails some
UDP rate-limit. By default srcds caps A2S queries at roughly 30 per minute per source IP. Past that it silently drops; the dropper looks identical to a packet loss event from outside. Most common after a "server status checker" wakes up in someone's CI and starts hammering you.
Two fixes:
sv_max_queries_sec— bump the per-IP rate limit (default 3, raise to 30+ for community servers that get a lot of monitoring).net_chan_limit_msec— adjusts the global query budget. Useful if you're getting hit from multiple monitoring services simultaneously.
Don't disable rate limiting outright. A2S amplification attacks are a real thing — a 25-byte query can elicit a ~1.5 KB response, which is the kind of multiplier DDoS amplifiers love. Cap, don't remove.
Decision flow ¶
| What you observed | Where to look next |
|---|---|
| Total UDP timeout | Host firewall, then upstream provider's DDoS profile |
| Challenge byte returned, no full reply | SourceTV — tv_status in srcds console |
| Reply received, wrong App ID | ss -lup for stray srcds processes |
| Reply received, player count looks wrong | SourceMod plugins folder, then plugin manager logs |
| Reply works most of the time, sometimes drops | sv_max_queries_sec |
| Everything looks fine but players still complain | Network path from their region; A2S is intra-network healthy |
The point of starting with A2S ¶
The five fingerprints above each have a different next step, and most of them avoid any need to SSH into the box. A bad SourceTV state, a stale srcds, a lost UDP packet — none of these need you to dig through 200 MB of log files. They need you to read one packet's worth of bytes.
That's why every Source-server admin tool worth running starts with A2S: it's cheap, fast, no auth, and gives you a rich enough signal to triage. Heavier checks (rcon, log tail, top) only come after the A2S response has told you which area to look in.
FAQ ¶
What's the easiest way to fire an A2S_INFO from the command line?
Either steamcmd with +app_info_print <appid> for offline metadata, or a one-liner with nc -u for the live query: printf '\xff\xff\xff\xffTSource Engine Query\x00' | nc -uw1 host port. For repeated diagnostics use a real client like the python-a2s library or our own /source/<host:port> page, which handles the challenge handshake automatically.
Does this apply to Rust and Ark?
Yes. Rust uses the same Source query protocol on its game port (28015 by default), and Ark uses 27015. The fingerprints above all transfer; only the exact CVAR names differ between the engines.
What about CS:GO Workshop maps changing the App ID?
App ID stays 730 for CS:GO and CS2 regardless of which workshop map is loaded. The map name in A2S changes, the App ID doesn't. If you see a different App ID on a "CS2 server" you're either hitting a stray srcds from a different game or someone reskinned their server's reply (it's possible but rare and requires a custom plugin).