MuteBefehl Wiki

Shield

Protects the proxy from Minecraft-specific attacks such as connection, ping and login floods, built into the cloud.

An open Minecraft port is an easy target. Bot waves, ping floods and malformed packets can bring a Velocity proxy to its knees long before the game servers behind it even notice, and every player on the network is kicked with it. Most networks answer this with an external protection service or a hand-built HAProxy setup in front of the proxy, with its own configuration, its own dashboard and one more thing that can break.

MuteCloud ships that protection built in. The shield sits in front of every proxy on its node, takes the connections, checks them in seven layers and hands only clean ones on to Velocity. Server list requests are answered from its own cache, so a ping flood never reaches the proxy at all.

INTERNETYOUR NODEBEHIND THE SHIELDPlayersreal logins, any versionAttacksBot wavesPing floodsLogin floodsMalformed packetsSlow connectionsKnown bad addressesMuteCloud Shieldpublic port, built into the node1 Connection limits2 First packet timeout3 Handshake check4 Server list from cache5 Login limits6 Behaviour score7 Block listVelocitylocal only, not reachablesees every real player IPGame serversLobbyBedWarsand every other groupPROXY v2××××××

One switch. shield on, then restart the proxy with groups <Proxy> rollout. MuteCloud moves Velocity to an internal port, switches it to the PROXY protocol and takes over the public one.

Real player IPs. Velocity and every plugin behind it keep seeing the real address of each player, so IP bans, alt checks and statistics keep working. This is where many self-built setups fail.

Part of the cloud, not bolted on. Rejections, blocks and attacks show up in shield, in the dashboard, as metrics and as alerts through your webhook. Limits can be changed while it runs.

Honest about its limits. The shield stops the attacks that are aimed at Minecraft itself, which is what small and medium networks mostly face. A pure bandwidth flood that fills the line to your machine never reaches it; against that only filtering at your provider helps.

How it works

The shield is built into MuteCloud and sits in front of every proxy on its own node. It accepts the players' connections, checks them and hands only clean ones on to Velocity. It answers server list requests itself, so a ping flood never reaches the proxy in the first place.

shield
shield on
shield off
shield block 203.0.113.7 60
shield block 198.51.100.0/24
shield unblock 198.51.100.0/24
shield list

addon enable shield and addon disable shield do the same as shield on and shield off; addon lists it as a built-in addon next to the others.

What it protects against

The shield works in layers, from the raw connection up to the player name.

LayerWhat is checked
Connectionat most per_ip_connections open connections per address, new ones only at per_ip_rate per second with a burst of per_ip_burst, at most global_connections in total
First packetif it does not arrive within first_packet_ms, the connection is closed, which keeps half-open connections short
Handshakelength fields, packet id, address length and next state must be valid, otherwise the connection is closed immediately
Server listat most status_per_second pings per address, the answer comes from the cache
Loginat most logins_per_minute per address, the name must match username_pattern
Scoreevery violation costs points, from score_threshold on the address is blocked for block_minutes minutes
Block listsingle addresses and ranges, with or without expiry, survives restarts

The score drops by score_decay every minute. A successful login subtracts 20, so regular players do not slide into a block. Malformed packets cost 30, a first packet that arrives too late 15, every exceeded limit 10, a ping over the limit 1, and an attempt despite a block 50. Opening a connection and closing it again without sending a single byte, such as a reachability check, costs nothing.

After the login the shield passes the bytes through unchanged. Encryption between player and Velocity is not affected; the shield only sees the handshake and the name.

What it does not protect against

The shield runs on the same machine as the proxy. A flood that simply fills the line, that is volumetric attacks with UDP, SYN or reflection in the gigabit range, never even reaches the shield. Only filtering in front of the machine helps against that, at the server's hosting provider or with a service that protects Minecraft traffic. The shield complements such a setup, it does not replace it.

Nor does it detect bots that log in like real players, with a valid name and within the allowed rate. For that there are plugins on the proxy that check in game.

Switching it on

shield on

This writes enabled = true under [shield] in network.toml and places a marker mutecloud-shield.toml in the template of every proxy group. That changes the template, and the proxy picks up the shield on its next start. By default proxies wait for approval, exactly as with any other change to their template:

groups Proxy rollout

Until then the running proxies keep accepting players directly as before, and shield shows "on, waiting for the proxies to restart". Switching it off takes the same way back.

When a proxy with the marker starts, the following happens:

  1. The shield binds the public address, by default the proxy's port on all addresses.
  2. Velocity gets a free port between 40000 and 40999 on 127.0.0.1 and is no longer reachable from outside.
  3. With proxy_protocol = true the cloud sets haproxy-protocol = true under [advanced] in the proxy's velocity.toml. The shield sends a PROXY protocol version 2 header ahead of every connection, so Velocity and every plugin see the player's real address.

If the public address is already taken, the proxy starts without the shield as before, and the log says why. Without the marker, velocity.toml stays as the template defines it.

Settings

The limits apply immediately, without a restart. Only enabled, listen and proxy_protocol need one, because they change what Velocity listens on.

network.toml
[shield]
enabled = false
listen = ""
proxy_protocol = true
per_ip_connections = 4
per_ip_rate = 2
per_ip_burst = 8
global_connections = 2000
first_packet_ms = 2000
status_per_second = 1
logins_per_minute = 4
username_pattern = "^[a-zA-Z0-9_]{3,16}$"
score_threshold = 100
score_decay = 5
block_minutes = 30
status_cache_seconds = 5
alert_rejects_per_minute = 500
allow = []
KeyMeaning
listenempty means 0.0.0.0 on the proxy's port, a bare IP keeps the port, IP:port sets both
proxy_protocolpass real player addresses on to Velocity, should stay on
global_connectionscounts all open connections, including players already playing, raise it for large networks
status_cache_secondshow often the shield fetches the server list from the proxy
alert_rejects_per_minutefrom this many rejections in one minute shield-attack is sent, 0 turns it off
allowaddresses and ranges that are never blocked and never limited

allow is empty by default. If many players share one address, for example at a LAN event, that address belongs here, otherwise the per-address limits apply. The same goes for your own services that log in or ping often.

The shield fetches the server list from the proxy separately for every game version that is currently asking, for at most sixteen versions at once. Until a new version has been fetched for the first time, the client gets the generic answer with its own protocol version, just as Velocity would do. If the proxy is not reachable, the cache stays empty and the request goes through.

Blocks

shield block 203.0.113.7 60 Spam
shield block 198.51.100.0/24
shield unblock 203.0.113.7
shield list

Without minutes a block is permanent. shield list shows every block with remaining time and origin; automatic blocks appear there as automatisch with their score. Existing connections keep running after a block, only new ones are rejected. The list is stored in shield/blocklist.json in the cloud's directory and saved every minute and on shutdown.

Watching it

shield shows which proxies the shield is in front of, how many connections are open, what was rejected and why, and the most conspicuous addresses with their score. The dashboard shows the same in the Network section, where addresses can also be blocked directly.

Two events are sent through the alerts, each at most once within quiet minutes:

EventWhen
shield-attackmore rejections in one minute than alert_rejects_per_minute
shield-blockthe shield has blocked addresses automatically, with count and last address

/metrics exposes mutecloud_shield_connections_accepted_total, mutecloud_shield_connections_rejected_total with the reason as reason, mutecloud_shield_connections_active, mutecloud_shield_front_connections per proxy, mutecloud_shield_blocked, mutecloud_shield_auto_blocks_total, mutecloud_shield_status_total with from set to cache or proxy, mutecloud_shield_logins_total and mutecloud_shield_bytes_total.

In a cluster

Every node protects only the proxies running on it and keeps its own block list. The marker in the template comes from the leader along with the templates, so shield on and shield off switch the whole cluster. Each node reads the limits from its own network.toml, and shield shows the state of the node it runs on.

Outlook

Dedicated edge nodes are planned: a node on another machine that runs no servers, only the shield. It accepts the players and passes them over the private network to the least loaded healthy proxy in the cluster. That keeps the address of the game machine hidden, and its proxies only accept connections from the edge nodes.

On this page