Guidefor server owners3 min read
Setting up a Velocity proxy network
A proxy moves players between servers without disconnecting them. The setup, the one security setting everyone gets wrong, and when you should not use one at all.
What a proxy is for
A proxy sits between players and your servers. Players connect to the proxy, and it forwards them to whichever backend server they should be on, and can move them to another one without disconnecting them.
That last part is the whole point. A lobby, a survival world and a minigame server behind one proxy feel like one server with instant travel between areas.
If you have one server, you do not need this. A proxy in front of a single backend adds a hop, a second process to run, and a second thing to go wrong, in exchange for nothing.
The shape of it
players
|
Velocity proxy :25565 (the only port open to the internet)
/ | \
lobby survival minigames (bound to 127.0.0.1, unreachable from outside)
:30001 :30002 :30003
Two rules produce that diagram, and both matter:
- Only the proxy is reachable from the internet.
- Backends listen on localhost, or on a private network the internet cannot route to.
Configure the backends first
Every backend server needs, in server.properties:
online-mode=false
server-port=30001
server-ip=127.0.0.1
online-mode=false looks alarming and is correct here. The proxy verifies each player
against Mojang's session servers, then tells the backend who they are. If the backends also
tried to verify, every player would fail, because a player only authenticates once.
This is exactly why the backends must be unreachable. A backend in offline mode accepts
whatever username it is handed. If someone can reach port 30001 directly, they can join as
anybody, including your administrators. server-ip=127.0.0.1 is what stops that, and a
firewall rule is what stops it properly.
Then, in Paper's config/paper-global.yml:
proxies:
velocity:
enabled: true
online-mode: true
secret: "<the same secret as the proxy>"
Configure the proxy
In velocity.toml:
bind = "0.0.0.0:25565"
motd = "<your network>"
# modern is the correct choice. Do not use legacy unless a backend
# genuinely cannot support it.
player-info-forwarding-mode = "modern"
forwarding-secret-file = "forwarding.secret"
[servers]
lobby = "127.0.0.1:30001"
survival = "127.0.0.1:30002"
minigames = "127.0.0.1:30003"
try = ["lobby"]
[forced-hosts]
"survival.example.com" = ["survival"]
forwarding.secret is a shared secret the proxy signs player data with, so a backend can
prove the connection came from your proxy. Generate a long random one, keep it out of version
control, and paste the same value into each backend's config.
Modern forwarding is the setting people get wrong. Legacy forwarding, inherited from BungeeCord, sends player identity with no signature at all, so anything that can reach a backend can claim to be the proxy. Modern forwarding signs it. Use modern unless something in your stack truly cannot, and if that is the case, treat the network isolation as the only thing protecting you.
Which plugins go where
They are different plugins and they are not interchangeable. A Velocity plugin uses Velocity's API and will not load on Paper; a Paper plugin will not load on Velocity.
On the proxy: anything about moving between servers or spanning the network. Network chat, cross-server messaging, queues, the server selector, network-wide bans.
On the backends: anything touching blocks, worlds, inventories or gameplay. World protection, economy, homes, claims.
The plugin catalogue filters by Velocity specifically, so you can see what actually targets the proxy.
Common problems
Everyone appears as the same player, or usernames are wrong. Forwarding is misconfigured. The secret must be byte-identical on the proxy and every backend, and the mode must match on both sides.
"Unable to connect to lobby". The backend is not running, is on a different port, or is
bound to an address the proxy cannot reach. Check server-ip and server-port against the
proxy's [servers] entry.
Players can join backends directly. Your firewall is not doing its job. server-ip alone
is not enough on a machine with several network interfaces.
Different Minecraft versions between proxy and backend. Velocity supports a range of client versions, but a backend must still speak a protocol the client does. The connection checker resolves this in one lookup.
Resources
Velocity is light. It holds no world and simulates nothing, so 512 MB to 1 GB of heap is plenty even for a large network. Spending eight gigabytes on it is a common and completely wasted expense. See how much RAM a server needs.
Build history and checksums for Velocity are on its own page, straight from PaperMC's API.