The full file

This is what gets written the first time the plugin runs.

plugins/GeoRestrict/config.yml
# Schema version. Bumped by us when the file layout changes.
configVersion: 4

# ---- Lookup gateway ----
gatewayUrl: "https://geoprotect.demonzdevelopment-e64.workers.dev/"
gatewayToken: ""
directFallbackEnabled: false
blockOnLookupFailure: true
lookupThreads: 4
maxCacheEntries: 100000

# ---- 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."

# ---- Cache & network ----
cacheTtlDays: 30
updateCheck: true
connectionTimeoutMs: 3000

# ---- 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

KeyTypeDefaultNotes
configVersionint4Schema version. Bumped when file layout changes. Don't edit.
gatewayUrlURLpublic WorkerWhere lookups go. Auto-prefixed with https:// if you forget.
gatewayTokenstring""Bearer token for the Worker. Required when the Worker has tokens configured.
directFallbackEnabledboolfalseHit an upstream provider directly if the Worker is down. Privacy: the IP leaves your server without the gateway's token.
blockOnLookupFailurebooltrueWhen every lookup path fails, block. Recommended. Flip to false if you prefer fail-open.
lookupThreadsint 1–324Background threads for HTTP calls and webhook delivery.
maxCacheEntriesint100000Hard cap. Oldest entries are evicted past this. 0 = no cap.
countryModeenumBLOCKLISTALLOWLIST / BLOCKLIST / DISABLED.
countrieslistCN, RU, KP, IRISO-3166 alpha-2. Case is normalized.
asnModeenumDISABLEDALLOWLIST / BLOCKLIST / DISABLED. Auto-disables if asns is empty.
asnslist[]AS numbers, e.g. AS16276. With or without prefix is fine.
vpnCheckEnabledbooltrueEnable ISP keyword + boolean flag checks.
vpnKeywordslist~80 stringsMatched case-insensitive against the ISP/AS name. Be careful — overly broad terms cause false positives on legit ISPs.
kickMessageCountrystringShown to players blocked by country.
kickMessageAsnstringShown to players blocked by ASN.
kickMessageVpnstringShown to players blocked by VPN/hosting detection.
kickMessageLookupFailurestringShown when blockOnLookupFailure: true and lookup failed.
cacheTtlDaysint 1–36530How long a cached lookup is trusted.
updateCheckbooltrueHits Modrinth every 6h, logs when a new version is out.
connectionTimeoutMsint3000HTTP timeout for both the Worker and direct fallback.
discord.webhookURL""Empty = no notifications. Use a private webhook URL.
discord.maskIpbooltrueShow 1.2.x.x instead of the full IPv4.
discord.logAllowedboolfalseWebhook on every allow. This can be high-volume on an active server.
discord.logDeniedbooltrueWebhook on every deny.
discord.titlestringEmbed title.
discord.colorAllowedint65280Decimal RGB. Green by default.
discord.colorDeniedint16711680Decimal RGB. Red by default.
discord.fieldslist7 defaultEmbed fields. Placeholders: %player%, %status%, %ip%, %country%, %asn%, %isp%, %reason%.

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.

Back up your config before upgrading. Auto-migration is one-way. If you've heavily customized vpnKeywords or Discord field names, double-check after the first restart.