DGuard

Setting up Velocity: a network with a lobby

We build a network from a Velocity proxy, a lobby and a survival server: velocity.toml, secure player info forwarding, Paper configs on the backends and the firewall — without it, anyone can join under someone else's name.

The DGuard team8 min read

In short: Velocity accepts players on port 25565 and routes them to the servers listed under `[servers]` in `velocity.toml`. The game servers switch to offline mode and get player data from the proxy through modern forwarding, using the secret in forwarding.secret. The last step is mandatory: firewall the servers so the only way in is through the proxy.

Still choosing a proxy? Read Velocity vs BungeeCord first. This guide is the hands-on setup.

The network layout

Take a typical network on one machine. Velocity listens on port 25565 — the only address players use. The lobby runs on 127.0.0.1:30066, survival on 127.0.0.1:30067. Both are Paper or Leaf; keeping them on the same Minecraft version is simplest. If a server lives on another machine, its address in the config is external and a firewall becomes non-negotiable.

Installing Velocity

  1. 1

    Install Java

    Current Velocity requires Java 25 or newer. Your Paper servers have their own requirements: Paper 1.21 runs on Java 21.

  2. 2

    Download Velocity

    Grab the latest stable build from papermc.io/downloads/velocity and put the jar in a folder of its own.

  3. 3

    Start it once

    On first start Velocity creates velocity.toml and a forwarding.secret file with a random string. Stop the proxy by typing end in the console.

start.sh from the Velocity docs (Linux and macOS)
#!/bin/sh
java -Xms1G -Xmx1G -XX:+UseG1GC -XX:G1HeapRegionSize=4M -XX:+UnlockExperimentalVMOptions -XX:+ParallelRefProcEnabled -XX:+AlwaysPreTouch -XX:MaxInlineLevel=15 -jar velocity*.jar

Configuring velocity.toml

velocity.toml — the lines that matter
bind = "0.0.0.0:25565"
online-mode = true
player-info-forwarding-mode = "modern"
forwarding-secret-file = "forwarding.secret"

[servers]
lobby = "127.0.0.1:30066"
survival = "127.0.0.1:30067"

try = [
    "lobby"
]

[forced-hosts]
# remove the examples or add your own domains
  • bind — the address and port the proxy accepts players on. By default, every address on the machine, port 25565.
  • online-mode = true — the proxy authenticates player accounts. Leave it on: in offline mode Velocity itself logs that it's a security risk.
  • player-info-forwarding-mode = "modern" — secure forwarding of name, UUID, IP and skin to the servers. The default is "NONE", in which case every player appears to come from the proxy with an offline-mode UUID.
  • [servers] — server names and addresses. The name on the left is what players type in /server.
  • try — where to send a player on login and when they're kicked from a server. Put the lobby first.
  • [forced-hosts] — maps domains to servers, e.g. survival.example.com straight to survival. The examples in the default config point to lobby, factions and minigames: if those aren't in [servers], Velocity won't start.

Configuring the Paper servers

Every server behind the proxy is configured the same way. Below is the lobby; survival differs only in its port.

  1. 1

    server.properties

    online-mode=false — the proxy has already authenticated the player. The port is the one in velocity.toml: server-port=30066. If the proxy and servers share a machine, add server-ip=127.0.0.1 so the server only accepts local connections. Everything else: server.properties explained.

  2. 2

    spigot.yml

    settings.bungeecord: false — BungeeCord-style forwarding isn't used with modern forwarding, and the Velocity docs ask you to turn it off.

  3. 3

    config/paper-global.yml

    Under proxies.velocity: enabled: true, online-mode: true (matching velocity.toml), and secret set to the string from forwarding.secret.

  4. 4

    Restart and check

    Restart the server, join through the proxy address and make sure you have your own skin and the correct UUID.

config/paper-global.yml on every server in the network
proxies:
  velocity:
    enabled: true
    online-mode: true
    secret: "the-string-from-forwarding.secret"

The firewall: the step that matters most

Your servers now run in offline mode. The Velocity docs are blunt: if a server can be reached around the proxy, anyone can join as any player. Modern forwarding makes spoofing harder, but the same docs say it is not a replacement for a firewall. The options the Velocity docs describe:

  • Bind to localhost. Proxy and servers on one machine — server-ip=127.0.0.1 in every server's server.properties. Easiest, but useless once servers live on different machines or on shared hosting.
  • An OS firewall — iptables or nftables on Linux, Windows Firewall: the server ports accept connections only from the proxy's IP. Velocity strongly recommends this.
  • An encrypted tunnel between machines — WireGuard, OpenVPN and the like. Solid, but complex to set up.
  • An IP whitelist plugin — the last line of defence when nothing else is possible, e.g. on shared hosting.

Check from the outside: from another machine, a connection to the server's address on port 30066 or 30067 must fail. The only port open to players is the proxy's. Protecting the proxy itself from bots and DDoS is covered in Bots and DDoS.

Moving between servers and built-in commands

/server is built into Velocity and available to everyone by default (permission velocity.command.server): on its own it shows the current server and the others; with a name it sends you there. Other built-in commands: /glist — players across the network (nobody has the permission by default), /send — move a player or everyone to another server, /velocity reload — re-read velocity.toml.

A lobby usually gets a server-selector plugin: a menu or NPCs that send players to a game mode. Many of them use the BungeeCord plugin messaging channel, which Velocity supports via bungee-plugin-message-channel in [advanced]. Proxy permissions come from a Velocity permissions plugin such as LuckPerms; across a network, every copy connects to the same database — MySQL, MariaDB, PostgreSQL or MongoDB.

DGuard on every server in the network

A proxy relays packets but can't see the world, so the anticheat goes on the game servers. With DGuard it looks like this:

  1. 1

    Add each server in the panel

    The lobby and survival are separate servers in the DGuard panel, each with its own dg_… key. The key is shown once — save it.

  2. 2

    Install PacketEvents and DGuard on each server

    Each game server's plugins/ gets the latest PacketEvents release and DGuard.jar. DGuard doesn't go on the proxy.

  3. 3

    Paste the key and restart

    Put the key into plugins/DGuard/config.yml → license.key, then restart. /dguard license shows the license state.

A server running DGuard needs outbound HTTPS to the DGuard site for the license, updates and the cloud check of aim and TriggerBot rules. The firewall above blocks incoming connections to the servers — leave outgoing ones open. Decide on the lobby too: if it has a PvP zone or parkour, cheaters with Fly and KillAura will show up there as well.

One more network concern: vanilla bans are stored per server, in each server's banned-players.json, so a player banned on survival can still join another mode. To make a ban apply network-wide, use a punishment plugin with a shared database across all servers, or a ban plugin on the proxy.

Common mistakes

  • "Server '…' for forced host '…' does not exist" — [forced-hosts] still has examples pointing to servers that aren't in [servers]. Remove them or fix the names.
  • "Fallback server … is not registered in your configuration" — try lists a server that isn't in [servers].
  • Players without skins and with the wrong UUIDs — forwarding is off: you need player-info-forwarding-mode = "modern" in velocity.toml and proxies.velocity.enabled: true on the server.
  • The server rejects players after setup — the secret in paper-global.yml doesn't match forwarding.secret, or proxies.velocity.online-mode doesn't match the proxy's online-mode.
  • ViaVersion on both the proxy and the servers — ViaVersion's docs ask for one place only: either the proxy or the servers behind it. They also warn that on the proxy an anticheat may perform worse, because the translation happens on a different level. Keep ViaVersion on the game servers, next to the anticheat — see ViaVersion.

FAQ

Do backend servers behind Velocity need online-mode=false?

Yes, every server behind the proxy has online-mode=false in server.properties, because Velocity authenticates players. velocity.toml keeps online-mode = true, and the servers must be firewalled.

Where do I get the secret for paper-global.yml?

Velocity creates forwarding.secret with a random string on first start. Put that string into proxies.velocity.secret in every server's config/paper-global.yml.

Why do players have no skins on my Velocity network?

Forwarding is most likely off: velocity.toml needs player-info-forwarding-mode = "modern", and the server needs proxies.velocity.enabled: true with the same secret.

How do players switch servers on a Velocity network?

With /server <name> — it's built into Velocity and available to everyone by default. Without a name it shows where you are and which servers exist.

Where does the anticheat go on a Velocity network?

On every game server: the proxy can't see movement or combat. DGuard goes on each server with its own key and the latest PacketEvents release alongside.

Sources

All sections

Run the best anticheat for modern Minecraft

DGuard catches all 47 kinds of cheats in our comparison — the closest rival, Intave, has 27. Full protection on every plan, free up to 30 players online.