- Velocity needs Java 25, listens on 25565 by default, and writes
velocity.tomlon first start. - Set
player-info-forwarding-mode = "modern", copy theforwarding.secretinto every backend'spaper-global.yml, and setonline-mode=falsein each backend'sserver.properties. - Firewall the backends so only the proxy can reach them. The Velocity docs are blunt: modern forwarding is not a firewall.
- On our list, 983 online servers report Velocity in their version string against 77 for BungeeCord.
A Minecraft Velocity proxy setup has four parts: install the proxy, tell it where your backend servers are, make the proxy and the backends agree on how player identity is forwarded, and block every path to a backend that does not go through the proxy. Most broken networks got the first two right and skipped the last two, which is why players show up with wrong skins or, worse, anyone can log in as anyone by connecting straight to a backend.
Velocity is the proxy the Paper team builds and recommends, and it has won the argument on our list: 983 online servers report Velocity in their version string, 147 report the Velocity-CTD fork, and only 77 report BungeeCord (23 for Waterfall). If you are choosing between them, read BungeeCord vs Velocity first. This guide assumes you have picked Velocity and have at least one Paper backend.
What a proxy changes
Without a proxy, a player connects to your server, Mojang authenticates them, and that server owns the session. With Velocity in front, the player connects to the proxy, the proxy authenticates them, then opens a second connection to a backend on the player's behalf. That means:
- Backends run in offline mode. They cannot authenticate a connection that arrives from the proxy, so
online-mode=falseis required on each one. This is the step that makes the firewall mandatory. - The proxy forwards who the player is. Skin, UUID and IP address travel from proxy to backend in the handshake. If forwarding is off, every player has a Steve skin, an offline UUID, and the proxy's IP.
- The proxy owns the MOTD and the player count. What server lists and the multiplayer screen see comes from
velocity.toml, not from any backend. Our pinger reads the proxy, so that is where your MOTD and icon now live. - Some plugins move to the proxy. Permissions, vote receiving, version compatibility and Bedrock support all have a proxy-side install. Gameplay plugins stay on the backends.
Install Velocity
- Install Java 25 or newer. The Velocity getting-started page states "Velocity requires at least Java 25." Check with
java -versionon the machine that will run the proxy. - Download the jar from papermc.io and put it in its own folder, not inside a backend's folder.
- Start it once. The docs' recommended flags are
java -Xms1G -Xmx1G -XX:+UseG1GC -XX:G1HeapRegionSize=4M -XX:+UnlockExperimentalVMOptions -XX:+ParallelRefProcEnabled -XX:+AlwaysPreTouch -XX:MaxInlineLevel=15 -jar velocity.jar. A proxy does not need much memory; 1 GB carries a lot of players because it holds no world data. - Stop it once the console prints that it is listening. It has generated
velocity.tomland aforwarding.secretfile next to the jar. - Note the port. Velocity binds
0.0.0.0:25565by default, which is the normal Minecraft port. If a backend is on the same machine and already uses 25565, move the backend, not the proxy, so players can connect without typing a port.
velocity.toml, the keys that matter
The generated file has comments for every key. These are the ones you will actually touch:
| Key | Default | What to do |
|---|---|---|
bind | "0.0.0.0:25565" | The address and port players connect to. Leave 25565 unless something else needs it. |
motd | A MiniMessage string | Your public MOTD. MiniMessage format, so gradients and hex colors work without a plugin. |
show-max-players | 500 | The max shown in the server list. Keep it honest: a "3 / 500" listing looks dead, and inflated maxes are one of the things our count flags catch. |
online-mode | true | Leave true. The proxy is now the only thing that authenticates players. |
force-key-authentication | true | Enforces chat signing keys. Leave it unless a plugin tells you otherwise. |
player-info-forwarding-mode | "NONE" | Set to "modern" for Paper 1.13+ backends. See the next section. |
forwarding-secret-file | "forwarding.secret" | The file holding the shared secret. Do not paste the secret into velocity.toml itself. |
[servers] | lobby, factions, minigames examples | One line per backend: name = "ip:port". Names are what /server uses. |
try | ["lobby"] | The order Velocity tries at login, and the fallback list when a backend kicks a player. |
[forced-hosts] | Examples | Send survival.example.com straight to a named backend. Needs DNS for each hostname. |
[advanced] compression-threshold | 256 | Packet size before compression. Leave it. |
[advanced] login-ratelimit | 3000 | Milliseconds between logins from one IP. A cheap brake on join floods. |
A minimal working file for a hub plus one survival server on the same machine looks like this:
bind = "0.0.0.0:25565"
motd = "<gradient:#5e4fa2:#f79459>My Network</gradient> | Season 3 just started"
show-max-players = 100
online-mode = true
player-info-forwarding-mode = "modern"
forwarding-secret-file = "forwarding.secret"
[servers]
hub = "127.0.0.1:25566"
survival = "127.0.0.1:25567"
try = ["hub", "survival"]
[forced-hosts]
"survival.example.com" = ["survival"]
The full key reference is on the configuration page. After any change, /velocity reload re-reads the file without a restart.
Modern forwarding: the proxy and every backend must agree
Velocity's forwarding page lists four modes. legacy is the BungeeCord method and is described there as "fundamentally insecure"; bungeeguard is legacy plus a token; modern is the one to use with Paper 1.13 or newer. Do this on the proxy and then on each backend:
- Proxy: set
player-info-forwarding-mode = "modern"invelocity.toml. Openforwarding.secretand copy the string inside. It is your shared password. - Each backend, server.properties: set
online-mode=false. If the backend is on the same machine as the proxy, also setserver-ip=127.0.0.1so it only listens locally. - Each backend, spigot.yml: make sure
settings.bungeecordisfalse. Modern forwarding and BungeeCord forwarding cannot both be on. - Each backend, config/paper-global.yml: fill in the
proxies.velocityblock below.online-modehere must match the proxy'sonline-mode, so it staystrue. - Restart the backends, then the proxy. Join through the proxy and check your skin and your UUID in the backend console. Both should be your real ones.
# config/paper-global.yml on every backend
proxies:
bungee-cord:
online-mode: true
proxy-protocol: false
velocity:
enabled: true
online-mode: true
secret: "paste-the-contents-of-forwarding.secret-here"
Paper 1.18.2 and older keep these settings in paper.yml under settings.velocity-support. Fabric backends need the FabricProxy-Lite mod for forwarding; Forge backends need ProxyCompatibleForge. Spigot without Paper cannot do modern forwarding at all and has to fall back to legacy plus BungeeGuard.
Firewall the backends
The Velocity security page "strongly recommends the use of a firewall" and says modern forwarding "is not a replacement for a firewall." A backend in offline mode that is reachable from the internet lets anyone log in as any username, including yours. Pick the option that matches your setup:
Bind each backend to server-ip=127.0.0.1. Nothing outside the machine can reach it, and the proxy connects locally.
Ask the host how to restrict a backend's port to the proxy's IP. Many panels have an allowlist per port; if yours does not, use BungeeGuard mode so a token is required even if the port is open.
Use the OS firewall (ufw, iptables, Windows Firewall) to allow the backend port only from the proxy's address, or put the machines on a WireGuard network and bind backends to the tunnel IP.
Test it from a home connection: add a backend's public IP and port to your server list. If it pings, the firewall is not done.
Hub, try order and forced hosts
The try list is the order Velocity attempts when a player logs in. It also serves as the fallback: when a backend closes a player's connection (a restart, a kick, a crash), the proxy tries the next server in the list that it has not tried yet before disconnecting them. Two consequences:
- Put a lightweight hub first. A hub that holds a few chunks and a compass menu starts in seconds and never lags, so the first thing a new player sees is fast. On our list, servers tagged network number 207, and nearly all of them land players on a hub.
- Put your main mode second. If the hub is down for a restart, players still get in. If you only list the hub, a hub restart disconnects everyone.
- Give players
/server. Velocity's built-in/server <name>is granted to everyone by default throughvelocity.command.server;/glistand/sendare not, so give staffvelocity.command.glistandvelocity.command.sendthrough LuckPerms on the proxy. - Use forced hosts for direct addresses. With
"survival.example.com" = ["survival"]and a DNS record for that name, players who type it skip the hub. The Velocity FAQ notes this only works when the client sends the hostname, so set it up with a real DNS record, not an IP.
Plugins that live on the proxy
Velocity does not load BungeeCord plugins; the FAQ answers that question with a flat "No." Look for a Velocity build on Hangar or Modrinth before you assume a plugin will not work. What goes where:
| Plugin | Where it runs | Notes |
|---|---|---|
| LuckPerms | Proxy and every backend | All instances share one MySQL, MariaDB or PostgreSQL database; set messaging-service to pluginmsg for a single proxy. Our LuckPerms guide covers the per-server contexts. |
| NuVotifier | Proxy receives, backends reward | Proxy on port 8192 with forwarding.method set to pluginMessaging; backends with port -1. Step by step in the NuVotifier guide. |
| Geyser and Floodgate | Proxy | Geyser's docs say to install it only on the proxy. Put Floodgate on the backends as well if an anti-cheat needs to exempt Bedrock players. Once it works, our Bedrock probe lists you on crossplay automatically. |
| ViaVersion | Proxy | Install on the proxy or the backends, not both. Lets newer clients join older backends. |
| TAB | Proxy (recommended by its wiki) | Needs VelocityScoreboardAPI on the proxy and TAB-Bridge on backends for PlaceholderAPI values. |
| EssentialsX, GriefPrevention, anti-cheat, shops | Backends only | Anything that touches blocks, inventories or movement has no business on the proxy. |
Test before you announce
- Join through the proxy and confirm your skin loads and the backend console shows your real UUID and IP, not the proxy's.
- Try each backend directly from outside. Every one should time out or refuse.
- Restart a backend while standing on it. You should land on the next
tryentry, not on the multiplayer screen. - Ping the proxy from a server list. The MOTD, icon and count should be the proxy's. Our is it down checker shows exactly what our pinger sees, including the version string.
- Run
/velocity dumpif something is off; it produces an anonymized report you can paste in the PaperMC Discord.
Once the proxy is the only door in, list the proxy's address (never a backend's) on your listing, set the game modes each backend offers, and claim the listing from its server page so the description and the 7-day chart are yours to manage. If the network launches on a date, a coming-soon listing collects "Notify me" sign-ups until then.
Quick questions
Do I need Velocity if I only run one server?
No. A single Paper server does not need a proxy, and adding one only adds a hop. Velocity earns its place when you have two or more backends, or when you want the proxy's login rate limit and MOTD in front of a single server that restarts often.
Why does Velocity use port 25565 and BungeeCord 25577?
They simply chose different defaults. Velocity binds 0.0.0.0:25565 out of the box so players can connect without a port; BungeeCord's default listener is 0.0.0.0:25577. You can set either to anything.
What is Velocity-CTD?
A community fork of Velocity that adds commands like /transfer and /velocity uptime plus some performance options. 147 servers on our list report it. It follows Velocity's configuration, so everything in this guide applies, but its plugins and support come from the fork's GitHub, not PaperMC.
Can Velocity run BungeeCord plugins?
Not natively. Snap is an experimental third-party adapter that loads BungeeCord plugins on Velocity, but its own README says not to run it in production without extensive testing, and some events do not work. Look for a native Velocity build first.
Players get "Unable to connect to server" on join. What now?
The Velocity FAQ's checklist: confirm every backend is started and responding to console input, confirm the proxy is started, and confirm each is bound to the port and IP you put in [servers]. Nine times out of ten it is a wrong port in that section or a backend that is still starting.
