Every server is re-checked every four hours and scored on how reliably it answers. Filter it below, download it, or fetch it from your own code — free, no key.
| group | host | port | af | region | latency | status | uptime 7d |
|---|---|---|---|---|---|---|---|
| fetching the server list… | |||||||
The list this page draws is public JSON. No key, no sign-up, and CORS is open, so it can be fetched from a browser as easily as from a server.
https://www.warpgate.io/servers.json
Use this one. It is plain HTTPS on the standard port, so it gets through networks that block everything but 80 and 443.
https://warpgate.io:8001/servers
http://ovh1.p2pd.net:8000/servers
The same file, served from the monitor's own ports, for software that already uses them. The plain HTTP one will not load from an HTTPS page. All three send gzip to clients that ask for it.
The list is rebuilt every minute, but each server is only re-checked every four hours, so fetching more often than every few minutes gets you nothing new.
Both endpoints send an ETag. Send it back as If-None-Match and an unchanged
list costs a few hundred bytes instead of the whole thing.
curl -s -o servers.json --etag-save etag.txt --etag-compare etag.txt \
-w '%{http_code}\n' https://www.warpgate.io/servers.json
import json, urllib.request
servers = json.load(urllib.request.urlopen("https://www.warpgate.io/servers.json"))
# best-scoring public STUN servers over IPv4/UDP
for group in servers["STUN(see_ip)"]["IPv4"]["UDP"][:5]:
s = group[0]
print(s["ip"], s["port"], round(s["score"], 3))
const servers = await (await fetch("https://www.warpgate.io/servers.json")).json();
const ntp = servers.NTP.IPv4.UDP.map(group => group[0]);
Servers are nested by kind, address family and transport:
{
"STUN(see_ip)": { "IPv4": { "UDP": [ [server], ... ], "TCP": [...] }, "IPv6": {...} },
"STUN(test_nat)": { ... },
"MQTT": { ... }, "TURN": { ... }, "NTP": { ... },
"timestamp": 1789262981
}
Each list is sorted best score first. Every entry in it is itself a small list of servers that belong
together — nearly always one. For STUN(test_nat) it is four: the two addresses and two ports
of one RFC 3489 server, which only works as a set. STUN(see_ip) servers tell a client its
public address; STUN(test_nat) servers can also tell it what kind of NAT it is behind.
| field | meaning |
|---|---|
ip, port | where to reach it |
fqns | host names that resolved to this address |
score | 0 to 1. Rewards passing checks and unbroken uptime, and only climbs as history builds up, so a newly added server starts low |
test_no, failed_tests | checks run, and how many of them failed |
uptime, max_uptime | seconds of the current, and the longest, unbroken run of passing checks |
last_success | Unix time it last answered. A server silent for 14 days stops being checked, so this is the field that says a listing has gone stale |
af | 2 is IPv4, 10 is IPv6 |
proto | 2 is UDP, 1 is TCP |
type | 3 STUN address lookup, 4 STUN NAT test, 5 MQTT, 6 TURN, 7 NTP |
user, password | credentials for TURN servers that need them |
id, status_id, group_id, alias_id, table_type | the monitor's own bookkeeping — don't rely on these |
The list comes from dogdorm, an open-source monitor that actively probes each server: STUN binding and change requests, TURN allocation, MQTT connections and NTP queries. It exists to keep warpgate's NAT traversal working on public infrastructure, and is published because a list that is actually checked is useful to anyone building peer-to-peer software.
Run your own dogdorm and this page will draw it too: use change at the top, or add
?src= to the address.