- Go 99.1%
- Shell 0.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Use a 20-second health-check interval and a 3-second UDP deadline while retaining the three-failure offline threshold. Update fallback values, tests, and both README language sections. |
||
| cmd/masterserver | ||
| internal | ||
| .gitignore | ||
| build.sh | ||
| go.mod | ||
| LICENSE | ||
| README.md | ||
AUC Masterserver
AUC Masterserver is the lightweight HTTP service behind the All Under Control server browser. Game servers send heartbeats, clients request the public server list, and background workers check SQP reachability over UDP.
Diese README enthält die englische und deutsche Dokumentation.
English
Endpoints
POST /heartbeatregisters or refreshes a game server.GET /listreturns all currently registered servers and their SQP status.GET /healthreturns uptime, registry and whitelist information.
The service stores live data in memory. A server expires after the configured time without a heartbeat.
Heartbeat
The heartbeat body is JSON matching the GameServer model. The server derives IP, ID, LastSeen and IsOfficial; values submitted for those fields are not trusted.
Important limits:
- Maximum request body: 16 KiB.
PortandSQPPort:1through65535; an omittedSQPPortdefaults to7980.- Maximum registered servers: 10,000 globally and 64 per public IP.
- Application rate limit: 5 heartbeats per second per IP with a burst of 20.
- Text, player counts and nesting depth are bounded and validated.
- Unknown JSON fields and multiple JSON objects are rejected. The legacy
Hostfield is accepted but ignored because the address is derived by the masterserver.
Successful response:
{"status":"success"}
Server description BB-Code
Descriptions may use the BB-Code understood by the game client:
[LR]and[LF][COLOR=#RRGGBB]...[/COLOR][B]...[/B][S]...[/S][CENTER]...[/CENTER][LIST][*]First item[*]Second item[/LIST]
Tags must be properly nested. Raw TextMeshPro tags such as <color=...> and literal control characters are rejected. Use [LR] or [LF] for line breaks. Other metadata fields do not support rich-text markup.
Client IP and nginx
The default listen address is loopback-only:
[SERVER]
port=127.0.0.1:5001
serverTimeoutSeconds=60
whitelistReloadMinutes=5
allowPrivateIPs=false
heartbeatRatePerSecond=5
heartbeatBurst=20
sqpCheckIntervalSeconds=20
sqpTimeoutMilliseconds=3000
sqpFailureThreshold=3
httpReadHeaderTimeoutSeconds=5
httpReadTimeoutSeconds=10
httpWriteTimeoutSeconds=15
httpIdleTimeoutSeconds=60
The heartbeat rate uses a token bucket per public IP. nginx has an independent rate limit; when changing these values, its limit_req_zone rate and burst should be kept in sync or configured slightly more permissively.
Legacy values port=5001 and port=:5001 are also converted to 127.0.0.1:5001. A non-loopback address must be configured explicitly.
X-Real-IP is trusted only when the direct HTTP peer is a loopback address. This matches a local nginx reverse proxy and prevents clients reaching the Go service directly from spoofing their IP. nginx must overwrite, rather than forward, any client-provided header:
# http context
limit_req_zone $binary_remote_addr zone=auc_heartbeat:10m rate=5r/s;
server {
listen 443 ssl;
location = /heartbeat {
client_max_body_size 16k;
limit_req zone=auc_heartbeat burst=20 nodelay;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:5001;
}
location = /list {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:5001;
}
location = /health {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:5001;
}
}
Keep TCP port 5001 blocked from external networks. If nginx runs in a container or on another host, loopback trust does not apply; the proxy/network design must then be adapted explicitly.
With allowPrivateIPs=false, private, loopback, link-local, multicast, documentation, CGNAT and other special-purpose addresses are rejected.
Official-server whitelist
Official servers are identified by API keys in whitelist.json next to the binary:
[
"official-server-key-1",
"official-server-key-2"
]
The file is created and enforced with owner-only permissions (0600) on platforms supporting POSIX permission bits. Keys are removed before data enters the in-memory registry or /list response. Use HTTPS between game servers and nginx.
SQP checks
The checker sends UDP ping and expects pong.
- Default port:
7980 - Per-check deadline:
sqpTimeoutMilliseconds(default: 3 seconds) - Periodic interval:
sqpCheckIntervalSeconds(default: 20 seconds) - Offline threshold:
sqpFailureThresholdconsecutive failures (default: 3) - Worker count: 16
- Queue capacity: 1,024 checks
Checks are deduplicated per server and use a bounded worker pool. A heartbeat starts an immediate check only for a new server or a changed SQP port. A previously online server remains online during isolated UDP packet loss and changes to offline only after the configured number of consecutive failures. SQP state is deleted when its server expires.
Build and test
Go 1.26.5 or newer is required.
go test -race ./...
go vet ./...
./build.sh
build.sh creates Linux, Windows and macOS binaries below dist/.
Deutsch
Endpunkte
POST /heartbeatregistriert oder aktualisiert einen Gameserver.GET /listliefert alle aktuell registrierten Server und ihren SQP-Status.GET /healthliefert Betriebszeit sowie Informationen über Registry und Whitelist.
Der Dienst hält die aktiven Daten im Arbeitsspeicher. Ein Server wird entfernt, wenn innerhalb des konfigurierten Zeitraums kein Heartbeat eingeht.
Heartbeat
Der Heartbeat enthält JSON entsprechend dem GameServer-Modell. IP, ID, LastSeen und IsOfficial werden vom Masterserver bestimmt; dafür übermittelte Werte werden nicht vertraut.
Wichtige Grenzen:
- Maximale Request-Größe: 16 KiB.
PortundSQPPort:1bis65535; ohneSQPPortwird7980verwendet.- Maximal 10.000 registrierte Server insgesamt und 64 je öffentlicher IP-Adresse.
- Anwendungsseitig 5 Heartbeats pro Sekunde und IP-Adresse, kurzzeitig bis zu 20.
- Texte, Spielerzahlen und Verschachtelungstiefe werden begrenzt und validiert.
- Unbekannte JSON-Felder und mehrere JSON-Objekte werden abgelehnt. Das alte Feld
Hostwird aus Kompatibilitätsgründen akzeptiert, aber ignoriert, weil der Masterserver die Adresse selbst bestimmt.
Erfolgreiche Antwort:
{"status":"success"}
BB-Code für die Serverbeschreibung
Die Beschreibung unterstützt den vom Spiel ausgewerteten BB-Code:
[LR]und[LF][COLOR=#RRGGBB]...[/COLOR][B]...[/B][S]...[/S][CENTER]...[/CENTER][LIST][*]Erster Eintrag[*]Zweiter Eintrag[/LIST]
Tags müssen korrekt verschachtelt sein. Direkte TextMeshPro-Tags wie <color=...> und echte Steuerzeichen werden abgelehnt. Für Zeilenumbrüche sind [LR] oder [LF] zu verwenden. Andere Metadatenfelder unterstützen keine Rich-Text-Formatierung.
Client-IP und nginx
Standardmäßig lauscht der Dienst ausschließlich auf Loopback:
[SERVER]
port=127.0.0.1:5001
serverTimeoutSeconds=60
whitelistReloadMinutes=5
allowPrivateIPs=false
heartbeatRatePerSecond=5
heartbeatBurst=20
sqpCheckIntervalSeconds=20
sqpTimeoutMilliseconds=3000
sqpFailureThreshold=3
httpReadHeaderTimeoutSeconds=5
httpReadTimeoutSeconds=10
httpWriteTimeoutSeconds=15
httpIdleTimeoutSeconds=60
Das Heartbeat-Limit arbeitet als Token-Bucket je öffentlicher IP-Adresse. nginx besitzt ein unabhängiges Rate-Limit. Werden die Werte geändert, müssen limit_req_zone und burst in nginx entsprechend synchronisiert oder dort etwas großzügiger gewählt werden.
Alte Werte wie port=5001 und port=:5001 werden ebenfalls in 127.0.0.1:5001 umgewandelt. Eine andere Bind-Adresse muss ausdrücklich angegeben werden.
X-Real-IP wird ausschließlich akzeptiert, wenn die direkte HTTP-Verbindung von einer Loopback-Adresse kommt. Das entspricht einem lokalen nginx-Reverse-Proxy und verhindert, dass direkte Clients ihre Adresse fälschen. nginx muss einen eingehenden Header überschreiben:
proxy_set_header X-Real-IP $remote_addr;
Der interne TCP-Port 5001 muss zusätzlich durch die Firewall vor externen Verbindungen geschützt werden. Läuft nginx in einem Container oder auf einem anderen Host, muss das Proxy-Vertrauensmodell ausdrücklich dafür angepasst werden.
Mit allowPrivateIPs=false werden private, lokale, Link-local-, Multicast-, Dokumentations-, CGNAT- und weitere Spezialadressen abgelehnt.
Official-Server-Whitelist
Official-Server werden über API-Keys in der Datei whitelist.json neben der Binary erkannt. Auf Systemen mit POSIX-Dateirechten wird die Datei mit 0600 erstellt und beim Laden entsprechend abgesichert. API-Keys werden vor dem Speichern aus den Serverdaten entfernt und niemals über /list ausgegeben. Zwischen Gameservern und nginx sollte ausschließlich HTTPS verwendet werden.
SQP-Prüfungen
Der Checker sendet ein UDP-ping und erwartet pong.
- Standardport:
7980 - Zeitlimit pro Prüfung:
sqpTimeoutMilliseconds(Standard: 3 Sekunden) - Periodisches Intervall:
sqpCheckIntervalSeconds(Standard: 20 Sekunden) - Offline-Schwelle:
sqpFailureThresholdaufeinanderfolgende Fehler (Standard: 3) - 16 parallele Worker
- Warteschlange für 1.024 Prüfungen
Prüfungen werden je Server zusammengefasst und über einen begrenzten Worker-Pool ausgeführt. Ein Heartbeat startet nur für einen neuen Server oder einen geänderten SQP-Port eine sofortige Prüfung. Ein zuvor erreichbarer Server bleibt bei einzelnen verlorenen UDP-Paketen online und wird erst nach der konfigurierten Anzahl aufeinanderfolgender Fehler als offline markiert. Beim Ablauf eines Servers wird auch dessen SQP-Status entfernt.
Bauen und testen
Benötigt wird Go 1.26.5 oder neuer.
go test -race ./...
go vet ./...
./build.sh
Das Build-Skript erzeugt Linux-, Windows- und macOS-Binaries unter dist/.