By PistonmasterUpdated 7 min read

Testing Minecraft Proxy Networks - BungeeCord and Velocity Guide

How to test and configure Minecraft proxy networks, validate forwarding modes, and troubleshoot connection issues

minecraftbungeecordvelocityproxynetworkingserver-network

Testing Minecraft Proxy Networks

A proxy sits between players and your backend servers, routing connections so people can hop between lobbies, survival worlds, and minigames without disconnecting. This guide covers how to set up, secure, and test proxy networks using Velocity and BungeeCord.

Why Run a Proxy?

Without a proxy, each server is its own island -- players disconnect, swap IPs, and reconnect. A proxy gives them a single address and handles the routing. You also get centralized player management and backend IPs that stay hidden from the public internet.

A minimal network is one proxy, one lobby, and one or more game servers. The proxy itself is lightweight (512MB--1GB of RAM) since it's only routing packets.

Choosing a Proxy

Velocity is the only correct choice for new networks. It's built by the PaperMC team, uses HMAC-signed forwarding by default (not the "trust the IP" model BungeeCord relies on), and it's noticeably faster under load. The plugin ecosystem is smaller than BungeeCord's, but every major plugin already supports it.

If you're starting fresh, there's no reason to pick anything else.

BungeeCord is legacy software. It still works, and it has the biggest plugin ecosystem, but its forwarding model (ip_forward) is insecure by design -- it trusts connections based on the proxy's IP address, which means anyone who reaches a backend directly can forge any player identity. You can bolt on BungeeGuard to patch this, but you're still working around a fundamentally broken trust model.

Waterfall (PaperMC's BungeeCord fork) exists, but PaperMC is basically done with it. It's in maintenance mode and still uses the same insecure forwarding.

Only use BungeeCord if you're locked into plugins that genuinely have no Velocity equivalent -- and even then, consider whether it's worth the security tradeoff.

Setting Up Velocity

Download the latest build from the PaperMC downloads page, then run it once to generate config files:

Terminal
java -Xms512M -Xmx512M -jar velocity.jar

Proxy Configuration

The main config is velocity.toml:

velocity.toml
bind = "0.0.0.0:25577"
motd = "&bMy Minecraft Network"
show-max-players = 500
player-info-forwarding-mode = "modern"

[servers]
lobby = "127.0.0.1:25565"
survival = "127.0.0.1:25566"

try = ["lobby"]

[forced-hosts]
"survival.example.com" = ["survival"]

Velocity also generates a forwarding.secret file with a random token. This shared secret is how the proxy proves to backends that a player is who they claim to be.

Forwarding Secret

The forwarding secret is the single most important credential in your network. If it leaks, an attacker can connect directly to a backend and impersonate any player by forging identity data. Generate a strong random value, keep it out of version control, and make sure it matches exactly between Velocity and every backend.

Backend Server Configuration

Every backend server behind Velocity needs three changes:

server.properties -- disable online-mode so the proxy handles authentication, and bind to localhost so players can't bypass the proxy:

server.properties
online-mode=false
server-ip=127.0.0.1
server-port=25565

spigot.yml -- make sure BungeeCord mode is off (Velocity uses its own forwarding):

spigot.yml
settings:
  bungeecord: false

config/paper-global.yml -- enable Velocity forwarding and paste the same secret from the proxy's forwarding.secret file:

paper-global.yml
proxies:
  velocity:
    enabled: true
    online-mode: true
    secret: "paste-your-forwarding-secret-here"

Start the backends first, then the proxy. Connect to localhost:25577 and run /glist on the proxy console to confirm your bots or client show up on the right backend.

BungeeCord Setup

If you're stuck with BungeeCord, the setup is simpler but fundamentally less secure:

config.yml
listeners:
  - host: 0.0.0.0:25577
    max_players: 500
    force_default_server: true

ip_forward: true

servers:
  lobby:
    address: localhost:25565
    restricted: false
  survival:
    address: localhost:25566
    restricted: false

priorities:
  - lobby

On backends, set online-mode=false in server.properties and bungeecord: true in spigot.yml. Since BungeeCord's legacy forwarding blindly trusts any connection from the proxy IP, you should also install BungeeGuard to add token-based authentication on top. It's a band-aid, but it's better than nothing.

Player Info Forwarding

Forwarding is how the proxy tells backend servers who a player actually is -- their username, UUID, and skin data. This is where most people break their setup.

Velocity Modern Forwarding signs player data with an HMAC using the shared secret. The backend checks the signature before accepting the connection. Without the secret, nobody can fake a player identity. This is the only forwarding mode you should be using on a new network.

Legacy Forwarding (BungeeCord and Velocity's legacy mode) sends player data as plain text in the handshake. The backend trusts it because the connection came from the proxy's IP. Think about what that means: if an attacker reaches a backend directly -- through a misconfigured firewall, a leaked IP, anything -- they can log in as any player, including admins. You can mitigate this with firewalls and BungeeGuard, but you're layering defenses on top of a protocol that was never secure in the first place. Modern forwarding just solves the problem.

Confirming Forwarding Works

After setup, check these three things:

  1. Players get correct UUIDs. Connect through the proxy and check your UUID on the backend (a plugin like Essentials shows it with /whois). It should match your Mojang/Microsoft UUID, not an offline-mode hash.

  2. Skins load correctly. If forwarding is broken, skins won't transfer to backends. In our testing, this is usually the first visible symptom of a misconfigured secret.

  3. Direct backend connections are rejected. Try connecting a client straight to localhost:25565 (bypassing the proxy). With modern forwarding enabled, the backend should refuse the connection. If you can join with any username, your forwarding is broken and your network is wide open.

Testing the Network

Functional Tests

Start with basic connectivity. Connect through the proxy, confirm you land in the lobby, then /server survival and make sure you switch cleanly. Try /server nonexistent and confirm you get an error without being kicked. Stop a backend while bots are connected and check that they either fall back to another server (if configured in the try list) or get kicked with a clear message.

Load Testing with Bots

Manual testing doesn't cover concurrent load. You need bots to find out whether your proxy holds up when 50 players switch servers at the same time, connect in a burst, or stay online for hours.

SoulFire works well for this. Point it at your proxy address, set a join delay of 1--2 seconds between bots, and start with 10--20 connections. Use the Chat Logger plugin to watch server messages and Auto Reconnect to test connection stability over time.

What to test at scale:

  • Connection bursts. Connect 50 bots within 10 seconds. All should reach the lobby without errors.
  • Simultaneous switching. With 50 bots in the lobby, have them all run /server survival at once. Monitor proxy and backend logs for errors. Check TPS on both servers during the migration.
  • Long-duration stability. Leave 20 bots connected for several hours, periodically switching servers. Watch for memory leaks in the proxy, timeout disconnects, or gradual TPS degradation.
  • Backend failure recovery. Kill a backend server while bots are on it. Confirm fallback behavior matches your config.

What to monitor:

Terminal
# Player distribution across servers (on proxy console)
/glist

# Proxy errors in real time
tail -f velocity-proxy/logs/latest.log | grep -i error

# Backend TPS (on each backend, requires Spark)
/spark tps

In our testing, a properly configured Velocity proxy handles 100+ connections per second, switches servers in under 500ms, and stays under 1GB of RAM. BungeeCord can't match those numbers -- we consistently saw higher latency and memory usage under the same conditions. If you see connection timeouts during bursts, increase read-timeout in the [advanced] section of velocity.toml. If switching is slow, check that backend spawn chunks are pregenerated and not causing lag on player join.

Troubleshooting

"Can't connect to downstream server" -- The proxy can reach the backend but something fails during the handshake. Check that the backend is running, the port matches velocity.toml, online-mode=false is set, and the forwarding secret matches. Test raw connectivity with telnet 127.0.0.1 25565 from the proxy machine.

Wrong UUIDs or missing skins -- Forwarding is misconfigured. Confirm that velocity.toml uses player-info-forwarding-mode = "modern", paper-global.yml has velocity.enabled: true with the correct secret, and spigot.yml has bungeecord: false. Restart everything after changes -- config reloads don't always pick up forwarding changes cleanly.

Players can join backends directly -- Your backends are exposed to the internet. Bind them to 127.0.0.1 in server.properties, or firewall the backend ports:

Terminal
# Allow only proxy IP, drop everything else
sudo iptables -A INPUT -p tcp --dport 25565 -s PROXY_IP -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 25565 -j DROP

Random disconnects -- Usually network instability or aggressive timeouts. Increase read-timeout to 60000 in velocity.toml's [advanced] section. If the problem persists, check for packet loss on the network path between proxy and backends.

Slow server switching -- Almost always caused by backends generating terrain when players arrive. Pregenerate the spawn area with Chunky. If backends are on different physical machines, network latency between them adds to switch time too. In our testing, keeping backends on the same machine or local network cuts switch times roughly in half compared to cross-datacenter setups.


Misconfigured forwarding isn't just a bug -- it's a security hole. Use Velocity, use modern forwarding, lock down your backends, and load test with bots before you open to players. The setup takes maybe an hour. Fixing a compromised network after the fact takes a lot longer.