Configuration
YAML, one file. Edit and run /georestrict reload — no restart needed.
gatewayUrl and gatewayToken exactly as generated. A copied endpoint or mismatched token can block every uncached join. Provider selection belongs in the Worker and is not configured in the plugin. Read the lookup flow first, or ask in the Demonz Development Discord before changing that section.
The full file
This is what the upcoming v2.1.0 patch writes on first run (schema v6).
# Full help: https://georestrict-docs.pages.dev/configuration
# Support: https://discord.com/invite/GYsTt96ypf
# Do not change Worker-related settings unless you operate the Worker
# and understand the lookup path. A wrong value can block joins.
# Schema version. Bumped by us when the file layout changes.
configVersion: 6
# ---- Lookup gateway (most servers should leave this unchanged) ----
gatewayUrl: "https://geoprotect.demonzdevelopment-e64.workers.dev/"
gatewayToken: ""
blockOnLookupFailure: true
lookupThreads: 4
maxCacheEntries: 100000
# ---- Local player connections (opt-in) ----
blockLocalConnections: false
# ---- Country ----
countryMode: BLOCKLIST # ALLOWLIST | BLOCKLIST | DISABLED
countries:
- CN
- RU
- KP
- IR
# ---- ASN ----
asnMode: DISABLED # ALLOWLIST | BLOCKLIST | DISABLED
asns: []
# ---- VPN detection ----
vpnCheckEnabled: true
vpnKeywords:
- "vpn"
- "nordvpn"
- "expressvpn"
- "protonvpn"
- "mullvad"
- "shadowsocks"
- "wireguard"
- "digitalocean"
- "ovh sas"
- "hetzner"
- "amazon aws"
- "google cloud"
- "tor exit"
- "exit node"
# ---- Kick messages ----
kickMessageCountry: "Your country is not allowed on this server."
kickMessageAsn: "Your ISP/ASN is not allowed on this server."
kickMessageVpn: "VPN or proxy connections are not allowed."
kickMessageLookupFailure: "Geo verification is temporarily unavailable. Please try again later."
kickMessageLocalConnection: "Local network connections are not allowed on this server."
# ---- Cache & network ----
cacheTtlDays: 30
updateCheck: true
connectionTimeoutMs: 3000
# ---- Floodgate / Geyser (Bedrock) ----
floodgate:
enabled: true # Auto-detect Bedrock players via Floodgate
bypassGeorestrict: false # Bypass all country/ASN/VPN rules for Bedrock
bypassVpnCheck: false # Bypass VPN/hosting keyword check for Bedrock only
# ---- Discord ----
discord:
webhook: ""
maskIp: true
logAllowed: false
logDenied: true
title: "GeoRestrict"
colorAllowed: 65280
colorDenied: 16711680
fields:
- { name: "Player", value: "%player%", inline: true }
- { name: "Status", value: "%status%", inline: true }
- { name: "IP", value: "%ip%", inline: true }
- { name: "Country", value: "%country%", inline: true }
- { name: "ASN", value: "%asn%", inline: true }
- { name: "ISP", value: "%isp%", inline: false }
- { name: "Reason", value: "%reason%", inline: false }
Every key, one by one
| Key | Type | Default | Notes |
|---|---|---|---|
configVersion | int | 6 | Schema version. Bumped when file layout changes. Don't edit. |
gatewayUrl | URL | public Worker | Where lookups go. Leave this unchanged unless you operate another compatible Worker. |
gatewayToken | string | "" | Bearer token for a private Worker. Keep it empty for the public Worker and never publish a real token. |
blockOnLookupFailure | bool | true | When every lookup path fails, block. Recommended. Flip to false if you prefer fail-open. |
blockLocalConnections | bool | false | Reject loopback/LAN player IPs before geolocation. Enable at the public-facing proxy or on a backend receiving real forwarded player IPs. |
lookupThreads | int 1–32 | 4 | Background lookup threads. Changing this setting requires a restart. |
maxCacheEntries | int | 100000 | Hard cap. Oldest entries are evicted past this. 0 = no cap. |
countryMode | enum | BLOCKLIST | ALLOWLIST / BLOCKLIST / DISABLED. |
countries | list | CN, RU, KP, IR | ISO-3166 alpha-2. Case is normalized. In BLOCKLIST mode, LOCAL also rejects loopback/LAN players in v2.1.0. |
asnMode | enum | DISABLED | ALLOWLIST / BLOCKLIST / DISABLED. Auto-disables if asns is empty. |
asns | list | [] | AS numbers, e.g. AS16276. With or without prefix is fine. |
vpnCheckEnabled | bool | true | Enable ISP keyword + boolean flag checks. |
vpnKeywords | list | ~80 strings | Matched case-insensitive against the ISP/AS name. Be careful — overly broad terms cause false positives on legit ISPs. |
kickMessageCountry | string | — | Shown to players blocked by country. |
kickMessageAsn | string | — | Shown to players blocked by ASN. |
kickMessageVpn | string | — | Shown to players blocked by VPN/hosting detection. |
kickMessageLookupFailure | string | — | Shown when blockOnLookupFailure: true and lookup failed. |
kickMessageLocalConnection | string | — | Shown when the explicit local-blocking flag rejects a player. A LOCAL country block uses kickMessageCountry. |
cacheTtlDays | int 1–365 | 30 | How long a cached lookup is trusted. |
updateCheck | bool | true | Hits Modrinth every 6h, logs when a new version is out. |
connectionTimeoutMs | int | 3000 | HTTP timeout for the plugin's Worker request. |
floodgate.enabled | bool | true | Auto-detect Floodgate Bedrock players if Floodgate is installed. |
floodgate.bypassGeorestrict | bool | false | Bypass country, ASN, VPN and local-connection rules for Floodgate Bedrock players. |
floodgate.bypassVpnCheck | bool | false | Bypass only VPN/hosting keyword checks for Floodgate Bedrock players. |
discord.webhook | URL | "" | Empty = no notifications. Use a private webhook URL. |
discord.maskIp | bool | true | Show 1.2.x.x instead of the full IPv4. |
discord.logAllowed | bool | false | Webhook on every allow. This can be high-volume on an active server. |
discord.logDenied | bool | true | Webhook on every deny. |
discord.title | string | — | Embed title. |
discord.colorAllowed | int | 65280 | Decimal RGB. Green by default. |
discord.colorDenied | int | 16711680 | Decimal RGB. Red by default. |
discord.fields | list | 7 default | Embed fields. Placeholders: %player%, %status%, %ip%, %country%, %asn%, %isp%, %xuid%, %device_os%, %reason%. |
Developer API & Geo-Routing
GeoRestrict exposes a clean Developer API (GeoRestrictAPI) for third-party plugins across Paper/Spigot, BungeeCord, and Velocity. Use it for restriction enforcement or for raw geolocation routing without kicking players:
// Check if GeoRestrict API is ready
if (GeoRestrictAPI.isAvailable()) {
// 1. Restriction check (returns allow/deny & kick reason)
GeoRestrictAPI.checkIp("1.1.1.1", "PlayerName").thenAccept(result -> {
if (!result.allowed) {
System.out.println("Blocked: " + result.reason);
}
});
// 2. Geo-Routing: Get ISO Country Code without blocking
GeoRestrictAPI.getCountryCode("1.1.1.1").thenAccept(country -> {
System.out.println("Player Country: " + country); // e.g. "US", "DE", "JP"
});
// 3. Raw Geo Data: Get full GeoResponse (country, ASN, ISP, VPN flags)
GeoRestrictAPI.lookup("1.1.1.1").thenAccept(geo -> {
if (geo != null) {
System.out.println("ISP: " + geo.asName + ", VPN: " + geo.isVpn);
}
});
// 4. More getters: country name, AS org name and provider signal flags
GeoRestrictAPI.getCountryName("1.1.1.1").thenAccept(name ->
System.out.println("Country: " + name)); // e.g. "United States"
GeoRestrictAPI.isHosting("8.8.8.8").thenAccept(hosting ->
System.out.println("Hosting: " + hosting));
// 5. Batch lookups in parallel (order preserved; failed IPs resolve to null)
GeoRestrictAPI.lookupAll(java.util.List.of("1.1.1.1", "8.8.8.8")).thenAccept(map -> {
map.forEach((ip, geo) -> System.out.println(ip + " -> " + geo.countryCode));
});
// 6. Offline cache helpers (never touch the network)
String cached = GeoRestrictAPI.getCachedCountryCode("1.1.1.1");
GeoRestrictAPI.purgeCache();
}
Blocking local players
In v2.1.0, set blockLocalConnections: true, or add LOCAL to a country BLOCKLIST. Reload, then run /georestrict check 127.0.0.1: it should report Allowed: No and Country: LOCAL. Addresses are detected automatically; no fixed player IP list is required.
The rule covers loopback, LAN, link-local, IPv6 unique-local and unspecified addresses, including mapped IPv4 and scoped IPv6. Other reserved ranges retain their previous behavior. Local rejection uses no geolocation request or geo-cache entry; public players keep their normal rules. Bukkit operators, permission bypasses and Floodgate full bypasses still apply to joins.
On a proxy network, enable blocking on the public-facing BungeeCord/Velocity instance, or configure trusted player IP forwarding before enabling it on the backend. Keep both local-denial options off on a backend that only sees a local proxy/Geyser IP, since it cannot distinguish remote players from local ones. Existing LOCAL blocklist entries start taking effect after upgrading.
Migrating old configs
If your configVersion is older than the bundled one, the plugin merges the bundled defaults into your file on next load. Your values win. New keys are added in-place rather than appended at the bottom of the file. The result is re-written and configVersion is bumped. A log line tells you it happened.
vpnKeywords or Discord field names, double-check after the first restart.