Setting Up a Velocity Proxy: The 2026 Guide
Step-by-step guide to running a Velocity proxy in front of your Minecraft network - install, secure the backend, configure forwarding, and avoid the common pitfalls that break player login.
Fabricio Souza
Founder, GeneX Plugins · 7+ years building Minecraft plugins
If you're running more than one Minecraft server and want players to hop between them with a /server command - lobby, survival, minigames, creative - you need a proxy. In 2026, Velocity is the right default. BungeeCord still works but is in maintenance-only mode; Waterfall (the Paper fork of BungeeCord) was deprecated in 2023.
This guide walks through a clean Velocity setup that doesn't break Geyser (Bedrock support), gets your IP forwarding right, and isn't a security disaster. Read the whole thing before you start - the order matters.
What Velocity actually is (and isn't)
Velocity is a Minecraft proxy. It accepts incoming player connections on port 25565, then forwards them to backend servers running on internal ports (25566, 25567, ...). The proxy handles authentication, plugin messaging, and /server commands. The backend servers don't know about each other - they just trust whatever the proxy tells them.
Velocity is NOT a server. You can't put players "on" the Velocity proxy - they're always on a backend. The proxy is just routing.
Architecture in 30 seconds
public internet
│
│ port 25565
▼
┌──────────┐
│ Velocity │ proxy
└────┬─────┘
┌───────────┼───────────┐
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Lobby │ │Survival│ │Creative│ backends (Paper)
│ :25566 │ │ :25567 │ │ :25568 │
└────────┘ └────────┘ └────────┘
- Public sees only port 25565
- Backends bind only on
127.0.0.1(not the public IP) - they're internal-only - Velocity uses a shared secret (Modern Forwarding) to tell backends who's connecting
Pre-flight checklist
Before you touch anything, confirm:
- Your backend servers all run Paper 1.20.5+ (older Spigot works but you lose Modern Forwarding, which is the secure mode)
- Java 21+ installed on the machine that'll run Velocity (Velocity 3.3+ requires it)
- You can configure firewall rules - backends MUST be unreachable from the public internet directly
- You have a domain name pointing to the proxy IP (optional but improves UX)
Skipping any of these makes the rest harder. Especially the firewall part - misconfigured backend exposure is the #1 cause of "people bypass my proxy and join my survival server directly with no rank."
Step 1: Install Velocity
Download from papermc.io/downloads/velocity. One JAR file. Drop it in a fresh directory (NOT inside any Minecraft server directory).
Start once to generate config:
java -Xms512M -Xmx1G -XX:+UseG1GC -jar velocity-*.jarVelocity uses way less RAM than a backend server - 1GB is plenty for hundreds of concurrent players. It'll start, generate velocity.toml and forwarding.secret, then stop with a "configure me" message.
Stop the server and edit velocity.toml.
Step 2: Configure forwarding
In velocity.toml, the critical block is:
player-info-forwarding-mode = "modern"
forwarding-secret-file = "forwarding.secret"Modern forwarding is the secure mode for Paper 1.20.5+ backends. It uses a shared secret so backends only trust connections from your specific Velocity instance. Don't use "legacy" or "bungeeguard" unless you have a specific backwards-compat reason.
The forwarding.secret file already exists - Velocity created it on first run. Open it, copy the contents, and paste into each backend's config/paper-global.yml:
proxies:
velocity:
enabled: true
online-mode: true
secret: paste-the-secret-hereSet online-mode: false in each backend's server.properties (Velocity does the Mojang auth check, backends trust the proxy). Backend bind-address should be 127.0.0.1 so they're not reachable from the internet.
Step 3: Define your backends in velocity.toml
[servers]
lobby = "127.0.0.1:25566"
survival = "127.0.0.1:25567"
creative = "127.0.0.1:25568"
try = [
"lobby"
]try is the connection order - Velocity tries to put new players on lobby first; if it's full or down, falls back to the next. For a single-lobby setup, one entry is fine.
If you want servers grouped (e.g. multiple minigame instances), use forced-hosts:
[forced-hosts]
"pvp.example.com" = ["pvp1", "pvp2"]Players connecting via pvp.example.com get routed to pvp1 first, pvp2 if full.
Step 4: Bind, port, and limits
bind = "0.0.0.0:25565"
motd = "&aMy Network\n&7Survival · Creative · PvP"
show-max-players = 500
online-mode = true
prevent-client-proxy-connections = false
ping-passthrough = "disabled"
[advanced]
compression-threshold = 256
compression-level = -1
login-ratelimit = 3000
connection-timeout = 5000
read-timeout = 30000A few notes:
online-mode = true: requires Mojang auth. Always. If you set to false you're running an offline-mode network and any username can connect as anyone.prevent-client-proxy-connections: blocks players using Proxy/Wisp clients to route their connection through other proxies. Leave at the default unless you have a specific reason.login-ratelimit: minimum ms between login attempts from the same IP. 3000ms blocks login spammers.compression-threshold: 256 is a good balance. Lower = more CPU, less bandwidth; higher = the opposite.
Step 5: Firewall
This is where most setups go wrong. The goal:
- Public CAN reach Velocity on port 25565
- Public CANNOT reach any backend port (25566+)
If you're on a single VPS with ufw:
sudo ufw allow 25565/tcp comment 'Velocity proxy public'
sudo ufw deny 25566:25600/tcp comment 'Backends - proxy only'
sudo ufw enableIf your backends are on separate machines (recommended at scale), the firewall lives on each backend's host and should only allow inbound from the Velocity host's IP.
To verify: try to connect to your backend port directly from another machine on the internet. It should time out. If it doesn't, your firewall isn't working - fix that before going live.
Step 6: Geyser / Bedrock support
Geyser-Spigot does NOT go on backends. Geyser-Velocity goes on the proxy.
Drop Geyser-Velocity.jar and floodgate-velocity.jar into Velocity's plugins/ directory. Geyser's default port is 19132/UDP - allow that through firewall too if you want Bedrock players.
On each backend, install floodgate-paper.jar so backends recognize Floodgate-prefixed UUIDs (Bedrock players get a . in their name by default - this is normal, configurable in floodgate config).
Step 7: Plugins on the proxy vs backends
Quick reference of where each plugin type lives:
| Plugin category | Where it goes |
|---|---|
| Permissions (LuckPerms) | Both - proxy for proxy commands, backend for game commands. They sync via SQL or messaging service. |
| Anti-cheat (Vulcan, Negativity) | Backends only - proxy can't see entity state |
| Economy (most) | Backends - or proxy + backend with a shared SQL database |
| Chat formatting | Either - proxy is better if chat should be cross-server visible |
| Geyser-Velocity, Floodgate-Velocity | Proxy |
| ViaVersion | Backends (for version compat with old clients) |
/server, /find, /glist | Proxy - built into Velocity or via plugins like LuckPerms-Velocity |
A common mistake: installing a Paper-only plugin on Velocity. It won't load - Velocity has a separate plugin API. Plugins for Velocity have separate downloads with -velocity in the name.
Step 8: Run it as a service
Don't just java -jar velocity.jar in a screen session. Use systemd so it restarts on crash:
# /etc/systemd/system/velocity.service
[Unit]
Description=Velocity Minecraft Proxy
After=network.target
[Service]
Type=simple
User=minecraft
WorkingDirectory=/opt/velocity
ExecStart=/usr/bin/java -Xms512M -Xmx1G -XX:+UseG1GC -XX:+ParallelRefProcEnabled -jar velocity.jar
Restart=on-failure
RestartSec=10s
[Install]
WantedBy=multi-user.targetThen sudo systemctl enable --now velocity. Logs go to journalctl -u velocity -f. Same approach works for backends.
Common failure modes
| Symptom | Cause | Fix |
|---|---|---|
| "You are not whitelisted" on backend | paper-global.yml proxy config not enabled | Set proxies.velocity.enabled: true, restart |
| Player connects but appears as a random offline UUID | Forwarding mode mismatch (Velocity says modern, backend expects legacy) | Set player-info-forwarding-mode = "modern" on Velocity AND proxies.velocity.enabled on backends |
| Players can join the backend directly bypassing proxy | Firewall not blocking backend port | Block backend ports at the firewall |
| Bedrock players show as Steve skin | Floodgate not installed on backend | Install floodgate-paper.jar on every backend |
| TPS lag on a specific backend but not others | That backend specifically has the issue - proxy isn't the cause | Run spark on the affected backend |
Should you use Velocity if you don't have multiple servers yet?
Probably not. Velocity adds operational complexity that only pays off when you have backends to route between. If you're running one survival server with no plans to add more, plain Paper is simpler.
If you're thinking "I might want a creative world later" - add Velocity then, not now. Migrating a single-server network to a Velocity setup later is straightforward (~2 hour job). Maintaining an over-engineered Velocity setup for a single backend is months of unnecessary friction.
Custom proxy plugins
Most networks reach a point where they need custom proxy-side logic: cross-server messaging, network-wide rank sync, custom queue systems for full servers, anti-VPN integration that runs proxy-side. These are not categories where free plugins shine - they're highly opinionated and tend to be slightly off for each network's actual needs.
If you've hit that point, we build custom proxy plugins targeting Velocity 3.3+ with the same delivery guarantees as our backend plugin work. The wiring is different but the deliverable shape is the same.
TL;DR setup order
- Install Java 21+ on the proxy host
- Download Velocity, run once, stop
- Edit
velocity.toml: modern forwarding, list your backends, set the MOTD - Copy
forwarding.secretcontents into each backend'spaper-global.yml - Set backends to
online-mode=falseandbind-address=127.0.0.1 - Firewall: allow 25565 inbound, deny everything else
- Install Geyser-Velocity + Floodgate (on both proxy and backends) if you want Bedrock
- systemd service for the proxy
- Test: connect with Java client, verify
/server <name>works, try to bypass the proxy from another machine and confirm timeout - Go live
Stuck on a specific step? Drop into our Discord - proxy setup questions come up weekly and we've seen most permutations of broken.
Last updated . Spotted a mistake? Let us know.