Velocity is a proxy that lets players connect to one address and then move between servers with the /server command – for example from the lobby to survival or to minigames. We'll show how to install and configure Velocity, connect it to your servers with secure modern forwarding, and lock down the servers behind the proxy so nobody can reach them directly.
What you'll need
- At least two Minecraft servers: Paper or Purpur (version 1.13 or newer), or Fabric, Forge or NeoForge with a forwarding mod
- Somewhere to run the proxy: a VPS with Ubuntu 24.04 or Debian 13 (connecting over SSH); we're preparing a separate Minecraft Proxy product
- Access to the Files and Server properties tabs for each server
- About 40 minutes
When you need a proxy#
| You want | Do you need a proxy? |
|---|---|
| One server for friends or a community | No |
| A lobby + one or more game servers on one address | Yes |
| Different game modes (survival, creative, minigames) with switching without disconnecting | Yes |
| Shared chat, permissions or bans across servers | Yes (with plugins on the proxy) |
| Bedrock players across the whole network | Yes, Geyser then runs only on the proxy |
The proxy doesn't run the game itself, it only forwards connections. It's light on resources: 1–2 GB of memory is enough for dozens of players.
How the network works#
Player ──► mc.example.cz:25565 (Velocity, authenticates the player)
│
├──► lobby (Paper, online-mode=false, accepts only the proxy)
├──► survival (Paper, online-mode=false, accepts only the proxy)
└──► minihry (Paper, online-mode=false, accepts only the proxy)- The player connects to the proxy's address. The proxy checks with Microsoft that they have a genuine account (
online-mode = true). - The proxy sends them to the first server in the
trylist (the lobby). - Along with the connection, the proxy passes the server the player's name, UUID, skin and real IP address (player info forwarding). It signs the data with a secret key that only the proxy and your servers know.
- The servers behind the proxy (backends) don't authenticate anything themselves (
online-mode=false) and only trust a proxy with a valid key. Anyone who connects directly gets the messageThis server requires you to connect with Velocity.
Proxy, servers and domain#
- Proxy: Velocity 4.x requires Java 25. Run it on a VPS (VPS Performance, VPS Budget). Only Velocity plugins belong on the proxy – Paper plugins don't work on it.
- Backends: regular Minecraft servers. They can run at StormHost as separate services (each with its own address and port), or on the same VPS as the proxy.
- Domain (optional): players type
mc.example.czinstead of an IP (Server address and domain).
The Minecraft Proxy product
We're preparing a standalone proxy as a service. It will have a Proxy flag preset for Velocity in the Startup tab. Until then, use a VPS – the steps are below.
Installing Velocity on a VPS#
This works on both Ubuntu 24.04 and Debian 13. Run the commands as root.
Install Java 25 and
curl:bash apt update apt install openjdk-25-jre-headless curlapt update– downloads the current package list.apt install openjdk-25-jre-headless– installs the Java 25 runtime without graphics libraries (a server doesn't need them).curl– a program for downloading files from the internet (if you already have it, nothing happens).
Check the version:
bash java -versionThe first line of the output must contain
25.Create a user and a folder for the proxy:
bash useradd --system --create-home --home-dir /opt/velocity --shell /usr/sbin/nologin velocityuseradd --system– creates a system user without a password (the proxy won't run as root).--create-home --home-dir /opt/velocity– creates the/opt/velocityfolder where the proxy will live.--shell /usr/sbin/nologin– nobody can log in as this user.velocity– the user name.
On papermc.io/downloads/velocity (opens in a new window), copy the link to the latest stable version and download it:
bash cd /opt/velocity curl -o velocity.jar "<DOWNLOAD_URL>" chown velocity:velocity velocity.jarcd /opt/velocity– goes to the proxy folder.curl -o velocity.jar– downloads the file and saves it asvelocity.jar.<DOWNLOAD_URL>– the link you copied from the page. Replace the whole thing including the angle brackets, keep the quotes.chown velocity:velocity– makes thevelocityuser the file's owner.
Start the proxy for the first time so it creates its configuration:
bash runuser -u velocity -- env MALLOC_ARENA_MAX=2 java -Xms1G -Xmx1G -XX:MaxDirectMemorySize=512M -XX:+UseG1GC -XX:G1HeapRegionSize=4M -XX:+UnlockExperimentalVMOptions -XX:+ParallelRefProcEnabled -XX:+AlwaysPreTouch -jar velocity.jarrunuser -u velocity --– runs the command after--as thevelocityuser.env MALLOC_ARENA_MAX=2– limits the allocator's memory arenas so the proxy doesn't use extra memory for nothing.-Xms1G -Xmx1G– gives the proxy 1 GB of heap (all at once, so it doesn't need to grow it while running). For a bigger network, raise it to2G. The proxy needs plenty of memory outside the heap for networking too, so don't give it more than half the memory you have for it.-XX:– a cap for network buffers. Without it, they can grow up to the size of the heap.MaxDirectMemorySize= 512M -XX:+UseG1GC … -XX:+AlwaysPreTouch– flags recommended by the Velocity documentation (the G1 garbage collector tuned for a proxy).-jar velocity.jar– starts the proxy.
The Startup script generator builds the command for a different memory size.
After startup you'll see a
Done (…)!line. Typeendand press Enter, and the proxy shuts down. The folder now containsvelocity.tomlandforwarding.secret.To keep the proxy running permanently and have it start on its own after a VPS reboot, create a systemd service for it following Run an app 24/7 on a VPS. In the unit file, set
User=velocity,WorkingDirectory=,/opt/ velocity Environment=, and inMALLOC_ ARENA_ MAX=2 ExecStartput the command from step 5 withoutrunuser -u velocity -- env MALLOC_ARENA_MAX=2and with the full path to Java, so it starts with/usr/bin/java -Xms1G ….Allow the proxy port in the VPS firewall: TCP
25565(and Geyser's UDP port if you'll use it). See Firewall in the customer area and UFW.
velocity.toml#
Open /opt/ (for example nano /opt/). Here's an example with settings for a network of three servers (leave the rest of the file as is):
bind = "0.0.0.0:25565"
motd = "<gold><bold>StormCraft</bold></gold> <gray>| lobby, survival, minihry"
show-max-players = 100
online-mode = true
force-key-authentication = true
player-info-forwarding-mode = "modern"
forwarding-secret-file = "forwarding.secret"
[servers]
lobby = "203.0.113.10:30066"
survival = "203.0.113.11:30067"
minihry = "203.0.113.12:30068"
try = [
"lobby"
]
[forced-hosts]
"survival.example.cz" = [
"survival"
]| Setting | What it does | Recommended value | When to change |
|---|---|---|---|
config-version | The file format version. | Don't change | Never – Velocity manages it itself. |
bind | The IP address and port the proxy listens on. | "0.0.0.0:25565" | A different port if you don't want to or can't use 25565. |
motd | The description in the server list. MiniMessage format (<gold>, <bold>, <#09add3>), not § codes. | Your description | Any time. |
show-max-players | How many slots the server list shows. Velocity doesn't limit the player count; it's only a display value. | E.g. 100 | Depending on the size of the network. |
online-mode | The proxy authenticates player accounts with Microsoft. | true | Never on a public server. |
force-key-authentication | Requires players to have a chat signing key. | true | false when Geyser runs on the proxy (Bedrock players can't chat otherwise). |
prevent-client-proxy-connections | Kicks a player whose internet provider doesn't match what the authentication server sees. Weak protection against VPNs. | false | Leave it. |
player-info-forwarding-mode | How the proxy passes player data: none (nothing, players get offline UUIDs), legacy (BungeeCord format, insecure), bungeeguard (legacy with a key), modern (signed Velocity format, version 1.13+). | "modern" | legacy/bungeeguard only for servers on 1.12 and older. |
forwarding-secret-file | The file with the secret forwarding key. | "forwarding.secret" | Don't change it. |
announce-forge | The proxy announces itself as a Forge server in the server list. | false | true for a network of modded servers. |
kick-existing-players | When the same account logs in a second time, the first session is kicked (Vanilla behavior). | false | true if your players expect it. |
[servers] | The list of backends as name = "IP:port". Players see the name in /server. | Your servers' addresses | When you add or move a server. |
try | The order of servers the proxy tries to send players to after they join or get kicked from a server. | ["lobby"] | Add a fallback server for players to land on when the lobby isn't running. |
[forced-hosts] | Sends players straight to a specific server based on the address they typed (anyone who types survival.example.cz ends up directly on the survival server). | As needed | When you want a separate subdomain for each server. The domain must point to the proxy. |
Three items in the [advanced] and [query] sections are worth a look:
| Section and setting | What it does | Recommended value | When to change |
|---|---|---|---|
[advanced] › login-ratelimit | The minimum gap (ms) between connections from one IP. | 3000 | Don't change it; it protects against flooding. |
[advanced] › failover-on-unexpected-server-disconnect | When a backend crashes, sends players to another server instead of disconnecting them. | true | Leave it. |
[query] › enabled | Answers Query (GameSpy4) requests. | false | When a statistics website needs it. |
Velocity 3 and 4
In version 4, instead of the ping-passthrough = "DISABLED" line there's a separate [ping-passthrough] section with the version, players, description, favicon and modinfo switches. They decide what the proxy takes over from the backend in the server list. By default everything is off and the motd from velocity.toml applies.
The forwarding secret#
On its first start, Velocity creates a forwarding.secret file with a random 12-character key. We recommend replacing it with a longer one:
- Generate a random password of 32 or more characters (letters and digits) in the password generator.
- Put it as the only line in
/opt/(for example withvelocity/ forwarding. secret nano). - You'll then enter the same key on all backends.
The key is like an admin password
Anyone who knows forwarding.secret and a backend's address can connect to it as any player, including you. Don't send it to anyone, don't put it in public repositories, and if you suspect a leak, replace it on the proxy and on all backends.
Backend setup (Paper and Purpur)#
For every server behind the proxy:
In the Server properties tab, in the Players group, turn off Account authentication (
online-mode=false) and click Save.The customer area shows a warning that anyone can join. Behind a proxy with modern forwarding that's correct – the proxy does the authentication and the server only accepts players with a valid key.
In the Files tab, open
spigot.ymland check thatsettings.bungeecordisfalse:spigot.ymlYAML settings: bungeecord: falsebungeecord– turns on forwarding in BungeeCord (legacy) format. It must be off for modern forwarding.
Open
config/paper-global.ymland set the following in theproxiessection:config/ paper-global.yml YAMLproxies: velocity: enabled: true online-mode: true secret: "<SECRET>"Replace
<SECRET>with the contents of theforwarding.secretfile from the proxy. Replace the whole thing including the angle brackets, keep the quotes.Restart the server.
What the settings in paper-global.yml mean:
| Setting | What it does | Recommended value | When to change |
|---|---|---|---|
proxies.velocity.enabled | The server accepts modern forwarding from Velocity and rejects direct connections. | true | Only when removing the proxy. |
proxies. | Must match online-mode in velocity.toml. Decides which UUIDs players get. | true | Never, if the proxy authenticates players. |
proxies.velocity.secret | The same key as in forwarding.secret on the proxy. | Contents of forwarding.secret | When you replace the key. |
On Paper 1.18.2 and older, these settings are in paper.yml under the names settings., settings. and settings..
Fabric, Forge and NeoForge#
| Loader | What to install | Where to enter the key |
|---|---|---|
| Fabric | The FabricProxy-Lite mod (from Modrinth, requires Fabric API) | config/, the secret = "<SECRET>" entry |
| Forge, NeoForge | The ProxyCompatibleForge mod | The mod's configuration file in the config folder (as described on the mod's Modrinth page) |
FabricProxy-Lite settings:
| Setting | What it does | Recommended value | When to change |
|---|---|---|---|
secret | The key from forwarding.secret. | Contents of forwarding.secret | When you replace the key. |
hackOnlineMode | Allows connections through the proxy even with online-mode on on the backend. | true (default) | Leave it. |
hackEarlySend | Sends player data earlier. LuckPerms requires it, as do some other mods. | true if you use LuckPerms | Otherwise the default false. |
hackMessageChain | Fixes players getting kicked with an invalid chat signature message after switching servers. | false | true when players get kicked over the chat signature after /server. |
Securing the backends#
A backend with online-mode=false and no working forwarding would let anyone in under any name. Depending on where your servers run:
- Backends at StormHost (separate services): we set the address and port automatically (
server-ipcan't be changed), so the servers are reachable from the internet. Modern forwarding is what protects them: withproxies., the server rejects anyone who doesn't come through the proxy with a valid key. So never usevelocity. enabled: true legacyornone. - Backends on the same VPS as the proxy: in each backend's
server.properties, setserver-ip=127.0.0.1, and invelocity.tomluse the addresses127.0.0.1:<PORT>. The servers are then not reachable from outside at all. In the VPS firewall, allow only the proxy port. - Backends on another VPS: in the backend's firewall, allow the server port only from the proxy's IP address (Firewall in the customer area).
Switching servers and plugins on the proxy#
| Command | What it does | Permission |
|---|---|---|
/server | Shows which server you're on and offers the others. | velocity.command.server (everyone has it by default) |
/server survival | Switches to the survival server. | The same |
/glist | The player count on the proxy; with all, a breakdown by server. | velocity.command.glist (nobody by default) |
/send <NICK> <SERVER> | Moves a player to another server. | velocity.command.send |
velocity reload | Reloads velocity.toml (in the proxy console). | velocity.command.reload |
shutdown | Shuts down the proxy (console only). | – |
Plugins on the proxy (in the /opt/velocity/plugins folder, Velocity versions):
- LuckPerms – permissions for proxy commands. For permissions on the servers, LuckPerms must also be on every backend and all instances must use the same MySQL/MariaDB database (MySQL for plugins). On each backend, set a different
serverin the LuckPerms configuration (for examplelobby,survival) so you can grant permissions per server, and setmessaging-service: sqlso changes take effect on all servers right away. Details are in the LuckPerms guide. - Geyser and Floodgate – Bedrock players; install them only on the proxy (guide).
- spark – proxy profiling, the
sparkvcommand.
Verify it works#
- Start the proxy and the backends. The proxy console shows
Listening on …:25565andDone (…)!. - Connect to the proxy address in the game. You'll land on the
lobbyserver. - Type
/server survival– it switches you without disconnecting. - In the backend console, check the line with your connection: it must contain your real IP address, not the proxy's. Then forwarding works. In the default Streamer mode, the customer area console hides IP addresses – for this check, click Show details at the top.
- Try connecting directly to the backend's address. You must get
This server requires you to connect with Velocity.
Troubleshooting#
Your server did not send a forwarding request to the proxy. Make sure the server is configured for Velocity forwarding.#
The backend doesn't have modern forwarding turned on. Check proxies. in config/paper-global.yml (FabricProxy-Lite on Fabric) and that you restarted the server after the change.
Unable to verify player details#
The key on the backend doesn't match forwarding.secret on the proxy. Copy it again (without extra spaces or blank lines) and restart the backend.
This server requires you to connect with Velocity.#
You're connecting directly to the backend – that's correct, the server is protected. If you see this message even when connecting through the proxy, the proxy's player-info-forwarding-mode is set to something other than modern.
Unable to connect you to lobby. Please try again later.#
The proxy couldn't reach the backend: the server isn't running, the address or port in [servers] doesn't match the address in that server's Network tab, or a firewall is blocking the connection.
There are no available servers to connect you to. Try again later or contact an admin.#
None of the servers in the try list are available. Start the lobby or add a fallback server to try.
Players have an empty inventory and different permissions after moving to the proxy#
The players got different UUIDs. The cause is player-info-forwarding-mode = "none" (offline UUIDs) or a mismatch between online-mode on the proxy and proxies. on the backend. Set modern forwarding and both values to true. Data under the old UUIDs stays in the world and plugin files; make a backup before moving a large network to a proxy.
The proxy won't let Bedrock players in, or they can't chat#
See Crossplay with Bedrock: Geyser must be on the proxy and force-key-authentication must be off in velocity.toml.
Summary
- Players connect only to the proxy; the proxy authenticates accounts (
online-mode = true) and the backends haveonline-mode=false. - Always use
player-info-forwarding-mode = "modern", and on the backendsproxies.with the same key fromvelocity. enabled: true forwarding.secret. forwarding.secretis secret; replace it with a long random key.- Velocity 4 requires Java 25, and plugins on the proxy must be made for Velocity.
- Check that a direct connection to a backend ends with
This server requires you to connect with Velocity.
Further reading#
- Velocity: getting started (opens in a new window)
- Velocity: player information forwarding (opens in a new window)
- Velocity: configuration (opens in a new window)
- Velocity: securing your servers (opens in a new window)
- Paper: global configuration (opens in a new window)
- LuckPerms: network installation (opens in a new window)