Home›Java›Mods›ProxyShield VPN & Proxy Blocker
ProxyShield VPN & Proxy Blocker
ModsJava

ProxyShield VPN & Proxy Blocker

Java mod listed for Minecraft 1.21. Downloads from the MC Java Mods app on Android.

⬇ Download on Spigot


[​IMG] [​IMG] [​IMG] [​IMG] [​IMG]

[​IMG] [​IMG] [​IMG] [​IMG] [​IMG] [​IMG] [​IMG] [​IMG] [​IMG] [​IMG]

[​IMG] [​IMG]

​

[​IMG]

ProxyShield


Blocks VPNs, proxies, Tor exits and datacenter ranges at login - by asking several services at once
and adding up what they say, instead of trusting one of them.

That difference is the whole plugin. Every anti-VPN queries an API and kicks on proxy: true. The
problem is what happens when that one service has never heard of the VPN in front of it: it answers
"clean", nothing else is asked, and the connection goes through. The list of VPNs any single free
dataset misses is long, and it is exactly the list of VPNs people actually pay for.

ProxyShield asks all of them, weighs the answers, and refuses the connection once enough of them
agree. One blind provider can no longer wave a VPN through, and one noisy provider can no longer
kick your players on its own.

Build - Runs on

Install one jar, on the machine that accepts the connection. On a network that is the proxy -
a Paper build behind BungeeCord only ever sees the proxy's own address. The Paper and Folia jars are
built from the same sources and are interchangeable; both exist so people find a jar named after
their platform.

Drop it in, restart, done. Seven providers are enabled out of the box and none of them needs an API
key.

Showcase



How a verdict is reached

Every enabled provider is queried at the same time. Each one carries a weight, the answers are
added up, and the connection is refused once the total reaches required-score. At the default of
1.5, one strong provider is enough on its own, or any two weaker ones, or one weak provider plus a
reverse-DNS hit.

Code (Text):

api:
  mode: consensus          # or failover
  required-score: 1.5
  providers:
    ip-api:     { enabled: true, weight: 1.0 }
    blackbox:   { enabled: true, weight: 1.0 }
    ipapi-is:   { enabled: true, weight: 1.5 }
    proxycheck: { enabled: false, weight: 2.0, key: "" }
 
Raise the score to 2.5 if you would rather miss a VPN than kick a real player. Lower it to 1.0
to block on any single hit, which is what most other anti-VPN plugins do by default.

mode: failover keeps the old behaviour - ask in order, first answer wins. It costs fewer requests
and detects less.

This does not multiply your quota the way it sounds. Answers are cached, simultaneous logins
from one address share a single lookup, the fan-out stops the moment the score is reached, the cache
survives restarts and reloads, and a provider that starts failing is dropped from the rotation until
it recovers. In practice a busy server spends fewer requests than v2.1 did, not more.

26 services, 15 of them free

Enabling one is a single line. Each entry knows its own response layout, so nothing is guessed at.

No key needed: ip-api, blackbox, iprisk, ipquery, ipapi-is, iplocate, freeipapi,
funkemunky, negativity, fastasfuck, zombiebot, rayzs, marvinmc, ip-check, zowi

Key based: proxycheck, ipqualityscore, vpnapi, iphub, iphunter, ip2location,
vpnblocker, getipintel, antivpn-io, 2ip, abuseipdb

A service that needs a key stays inert until you add one, and says so once at start-up rather than
failing on every login. Anything not in the list can be described directly in config.yml with a
URL and dotted field paths - no code, no waiting for an update.

/proxyshield providers shows every enabled service with its weight, health and latency.
/proxyshield check <ip> shows what each one said about a specific address, which is what you want
open in front of you when somebody reports a false positive.

The signals that cost nothing

APIs are lists of addresses somebody already reported. An attack from a range rented this morning is
invisible to all of them - but not to the server being attacked.

Network (ASN) rules. Address feeds always lag: a VPN rents a new range and the public lists catch
up days later. The network number behind it does not change nearly as often, so blocking the ASN
stops every address inside it at once. /proxyshield lookup <ip> prints the number to put in the
list.

Reverse DNS. Hosting and VPN operators name their machines after themselves, so a PTR record like
mad-01.torguard.io gives it away for free, with no quota and no rate limit. It adds weight rather
than blocking outright, because plenty of ordinary ISPs put words like host in their customer
names. Runs under a hard timeout so a slow resolver cannot stall a login.

Behaviour. Thirty accounts appearing out of one /24 inside a minute is a shape a normal player
base does not produce. So is one address cycling through a dozen names, or an account whose country
changes between two logins ten minutes apart. These add weight too, so a school or a Discord
community joining together is not a mass kick.

Tor exit list. The most reliable feed there is - those addresses are published by the network
itself.

Not kicking real players

The cost of an anti-VPN is not the VPN it misses. It is the regular who gets thrown out on a Friday
evening and does not come back.

Trust. An account that has connected cleanly often enough, over long enough, stops being
re-judged on every login. Mobile players behind carrier-grade NAT are the ones a hosting block hits
hardest - their address can sit in a flagged range one evening and not the next - and this is what
keeps them online. It never overrides your manual blacklist, and it is reset the moment an account
is caught behind a proxy.

Connection type. Where a provider reports that an address is residential or mobile, the hosting
block does not apply to it. Carriers land in datacenter ranges more often than you would think.

Dry-run. detection.dry-run: true reports everything and disconnects nobody. Run it for a day,
read blocks.log, then switch enforcement on knowing what it would have done.

Silent mode. No staff broadcast and no console line, while the log file and the Discord webhook
keep recording. Watch the filter without announcing every detection to everyone online.

On a network

One server needs no setup - verdicts and player history live in two files next to the config.

A network of several proxies should share them, so each address is paid for once for the whole
network instead of once per proxy, and every front end agrees about it:

Code (Text):

storage:
  type: redis            # or mysql, mariadb, postgresql, sqlite, h2, file, memory
  redis:
    host: "127.0.0.1"
    port: 6379
    password: ""
 
Redis also pushes: whitelisting an address or running /proxyshield clearcache on one proxy takes
effect on the others immediately, rather than whenever the entry happens to expire.

No database driver and no Redis library is bundled, so nothing is relocated into a server that did
not ask for it. Most Bukkit servers already have a MySQL and a SQLite driver; if yours does not, drop
the driver jar into the ProxyShield folder and name it under storage.sql.driver-path.

If the store cannot be reached, the plugin says so once and falls back to file storage. A database
outage never becomes a login outage.

Order of decision

Strictly top to bottom, first match wins. Everything that can allow a player is evaluated before
anything that can block one, so you can always whitelist your way out of a false positive.

# - Check - Result - Cost

Steps 1 to 8 never touch the network.

Bedrock players are exempt by default. Wherever Geyser runs anywhere other than the player's own
machine, the address seen here is Geyser's - and a Geyser instance on rented hardware sits in exactly
the datacenter ranges the feeds list, so without that exemption a server would drop every Bedrock
player the moment hosting detection was switched on.

Performance

Measured with the default feeds, 62,555 entries compiled into 35,161 merged ranges:


The provider round is the only part with real latency. It runs off the main thread on every
platform, so it delays that one player's login and never the server tick, and it has a hard ceiling
( api.total-timeout-seconds) - whatever answered by then decides. Set use-api: false for a
feed-only setup with no network traffic per login at all.

Commands

All need proxyshield.admin. Aliases: /ps, /antivpn.

Command - Does

Permissions

Node - Default - Grants

On Paper, BungeeCord and Sponge no permission data exists yet during the login handshake, so
proxyshield.bypass only resolves for operators there. For reliable exemptions on those platforms
use the name or IP whitelist. On Velocity the permission works normally.

PlaceholderAPI

Available on the Bukkit builds when PlaceholderAPI is installed. Every placeholder reads the cache,
so none of them can stall the main thread.

Placeholder - Shows

For other plugins

Code (Text):

if (ProxyShieldApi.isAvailable() && ProxyShieldApi.isProxy(address)) {
    // cache only, safe on the main thread
}

LookupResult result = ProxyShieldApi.lookup(address);   // blocking, async only
boolean regular = ProxyShieldApi.isTrusted(uuid);
 
Read-only: it answers questions, it never changes a verdict or disconnects anybody.

Configuration

Everything behaves identically on all five platforms and lives in one config.yml. Player facing
text is separate, in messages_en.yml / messages_de.yml, so you can translate or reword anything
without touching the jar.

Spoiler: The settings people change first
Code (Text):

detection:
  dry-run: false               # detect and report, never kick
  block-proxy: true
  block-hosting: true
  block-tor: true
  allow-residential-hosting: true   # do not kick mobile carriers

  asn:
    enabled: true
    blocked: []                # e.g. "AS9009" - M247, used by many commercial VPNs
    allowed: []                # your own hosting, a school, a carrier

  rdns:
    enabled: true
    weight: 1.0

api:
  mode: consensus
  required-score: 1.5          # 1.0 blocks on any single hit, 2.5 is cautious
  total-timeout-seconds: 6     # ceiling for the whole lookup stage of one login

trust:
  enabled: true
  min-logins: 5
  min-days: 3

heuristics:
  enabled: true
  max-joins-per-subnet-per-minute: 12
  max-accounts-per-ip: 4
  geo-jump-minutes: 10

country:
  enabled: true
  mode: whitelist              # only these countries may connect
  codes: ["DE", "AT", "CH"]

notifications:
  silent: false                # true = log and webhook only, no live alerts
 

Spoiler: Describing a service the plugin does not know
Code (Text):

api:
  providers:
    my-provider:
      enabled: true
      url: "https://example.com/api/{ip}?key={key}"
      key: ""
      weight: 1.0
      format: json             # json or plain
      proxy-fields: ["security.vpn", "security.proxy"]
      hosting-fields: ["is_datacenter"]
      country-fields: ["location.country_code"]
      asn-fields: ["asn.asn"]
      score-field: "risk_score"
      score-threshold: 70
      key-header: ""           # set if the key goes in a header, e.g. X-Key
      nested-by-ip: false      # true if the answer is keyed by the address
 
Dotted paths work, so security.vpn reads {"security":{"vpn":true}}. For a service that answers
with a bare word:

Code (Text):

    my-simple-provider:
      enabled: true
      url: "https://example.com/check?ip={ip}"
      format: plain
      true-values: ["true", "y", "1"]
 

Metrics

Anonymous statistics through bStats: server count, platform, Java version and which ProxyShield
settings are in use. No addresses and no player data.
Public at bstats.org, and switched off with
metrics.enabled: false.

Support

Questions and bug reports: dc.gg/paperstream
Source and issues: codeberg.org/LucasTHCR/ProxyShield

Plugin details

Read from the plugin's own plugin.yml.

Quick facts

Install steps are the general flow for this file type — How to install Minecraft Java mods & modpacks walks through it step by step.

ProxyShield VPN & Proxy Blocker is a free Minecraft Java mod. Compatible with Minecraft 1.21. Downloaded 58 times (via Spigot). Download it and open it directly in the game.

Explore more