Przejdź do głównej zawartości

Steam Query Protocol (A2S)

If you've ever wondered how Steam knows your game server exists, how the server browser populates, or why your server sometimes doesn't show up — the answer is the Steam Server Query Protocol, commonly called A2S.

This guide explains what A2S is, how it works, which games use it, and how to troubleshoot common issues.

What is the Steam Query Protocol?

The Steam Query Protocol is a UDP-based protocol that allows clients (like the Steam server browser, or tools like python-a2s) to request information from a game server. Valve originally designed it for Source Engine games (Counter-Strike, Team Fortress 2, Half-Life), but it's now used by most games with Steam multiplayer.

When you open the Steam server browser and see a list of servers with player counts, map names, and ping times — that data comes from A2S queries.

The Three Main Query Types

QueryRequestResponsePurpose
A2S_INFO\xFF\xFF\xFF\xFF\x54Server name, map, players, max players, game, OSBasic server information
A2S_PLAYER\xFF\xFF\xFF\xFF\x55Player names, scores, play timeWho's currently playing
A2S_RULES\xFF\xFF\xFF\xFF\x56Server configuration key-value pairsServer settings (cvars)

All three use UDP and follow a challenge-response pattern to prevent spoofing.

How A2S Works

┌──────────┐                    ┌──────────────┐
│ Client │ │ Game Server │
│ (Steam) │ │ (Query Port) │
└─────┬─────┘ └──────┬───────┘
│ │
│ A2S_INFO request (UDP) │
│────────────────────────────────>│
│ │
│ Challenge response │
│<────────────────────────────────│
│ │
│ A2S_INFO + challenge token │
│────────────────────────────────>│
│ │
│ Server info response │
│<────────────────────────────────│
│ │
  1. Client sends a query to the server's query port (usually the game port or game port + 1)
  2. Server responds with a challenge — a random 4-byte token
  3. Client re-sends the query with the challenge token included
  4. Server responds with the actual data

The challenge step was added by Valve to prevent reflection/amplification DDoS attacks, where attackers would spoof the source IP to flood a victim with server responses.

Query Port vs Game Port

This is one of the most common sources of confusion. Most games use two different ports:

PortProtocolPurpose
Game PortUDP (usually)Actual game traffic — player connections, world state
Query PortUDPSteam browser queries, monitoring tools, A2S

The query port is typically:

  • Game port + 1 (Source Engine convention: game on 27015, query on 27016)
  • A fixed offset (ARK uses game port 7777, query port 27015)
  • The same port (some games handle both on one port)
GameDefault Game PortQuery PortProtocol
Rust2801528016UDP
ARK: Survival Evolved777727015UDP
ARK: Survival Ascended777727015UDP
Valheim24562457UDP
DayZ230227016UDP
7 Days to Die2690026900UDP (same port)
Enshrouded1563615637UDP
Palworld821127015UDP
SCUM704227015UDP
V Rising98769877UDP
Unturned2701527016UDP
Project Zomboid1626116261UDP (same port)
Satisfactory777715777UDP
Factorio34197N/ANo A2S — uses own protocol
Minecraft2556525565TCP (own protocol, not A2S)
Minecraft and Factorio Don't Use A2S

Minecraft uses its own Server List Ping protocol over TCP. Factorio uses a custom matchmaking protocol. These games bypass Steam's query system entirely.

Querying a Server with Python

You can query any A2S-compatible server using the python-a2s library:

pip install python-a2s
import a2s

# Query server info
address = ("your-server-ip", 27015) # Use the QUERY port, not game port
info = a2s.info(address, timeout=3.0)

print(f"Server: {info.server_name}")
print(f"Map: {info.map_name}")
print(f"Players: {info.player_count}/{info.max_players}")
print(f"Game: {info.game}")
print(f"Platform: {info.platform}")
print(f"VAC: {info.vac_enabled}")

# Query players
players = a2s.players(address)
for player in players:
print(f" {player.name}: {player.score} points, {player.duration:.0f}s")

# Query server rules/cvars
rules = a2s.rules(address)
for key, value in rules.items():
print(f" {key} = {value}")

From Inside a Kubernetes Cluster

If your server runs inside K8s (like Reactor's infrastructure), you can query from within the cluster using the pod's internal IP:

kubectl exec <pod-name> -c game-server -- \
python3 -c "import a2s; print(a2s.info(('127.0.0.1', 27015)).server_name)"

Why Your Server Isn't Showing Up

If your game server is running but doesn't appear in the Steam server browser, check these common causes:

1. Query Port Not Open

The query port must be reachable from the internet over UDP. Many hosting providers and firewalls block UDP by default.

Fix: Ensure your firewall allows inbound UDP on the query port. On Reactor, all required ports are automatically opened via NodePort services.

2. Wrong Query Port Configuration

Some games default to a query port that differs from what Steam expects.

Fix: Check the game's configuration file for a QueryPort or QUERY_PORT setting. Make sure it matches what's actually exposed.

3. Server Not Registered with Steam Master Server

Most games automatically register with the Steam master server on startup. If this fails (due to network issues or misconfiguration), the server won't appear in the browser.

Fix: Check the game server logs for messages like "Master server connection" or "Steam authentication". A GSLT (Game Server Login Token) is required for some games.

4. NAT / Port Forwarding Issues

If the game server binds to an internal IP but the external IP differs, Steam queries may fail because the server reports the wrong IP.

Fix: Set MULTIHOME=0.0.0.0 or the correct external IP in your server configuration.

5. Rate Limiting

Steam limits how many queries a single IP can make. If you're running monitoring tools that query too frequently, the server may stop responding.

Fix: Reduce query frequency to once every 5-10 seconds per server.

GSLT — Game Server Login Tokens

Some games (Rust, CS2, Garry's Mod) require a Game Server Login Token (GSLT) to appear in the Steam server browser. Without a GSLT, the server runs but is invisible to Steam matchmaking.

How to Get a GSLT

  1. Go to Steam Game Server Account Management
  2. Enter the game's App ID (e.g., 252490 for Rust)
  3. Add a memo (e.g., "My Rust Server")
  4. Copy the generated token
  5. Set it in your server config (+sv_setsteamaccount <token> for Source games)
Reactor handles GSLT automatically

When you provision a game server on Reactor that requires a GSLT, we automatically generate and configure it for you using the Steam Web API. No manual setup needed.

Monitoring & Uptime Checking

You can use A2S queries to build monitoring systems that check if your game server is healthy:

import a2s
import time

def check_server(host, port, timeout=5):
try:
info = a2s.info((host, port), timeout=timeout)
return {
"online": True,
"players": info.player_count,
"max_players": info.max_players,
"map": info.map_name,
"latency_ms": round(info.ping * 1000),
}
except Exception:
return {"online": False}

# Poll every 30 seconds
while True:
status = check_server("your-server-ip", 27015)
if not status["online"]:
print("⚠️ Server is DOWN!")
# Send alert via Discord webhook, email, etc.
else:
print(f"✅ {status['players']}/{status['max_players']} players on {status['map']}")
time.sleep(30)

Games That Use A2S on Reactor

The following games hosted on Reactor use the Steam Query Protocol for server browser visibility:

Further Reading


Need help with your game server? Contact us or check our game-specific guides.