> ## Content Index
> Fetch the complete content index at: https://blog.sudowl.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Migrating from BungeeCord/Waterfall to Velocity — A Practical Walkthrough
- URL: https://blog.sudowl.com/migrate-bungeecord-waterfall-to-velocity/
- Published: 2026-05-02T10:00:00.000Z
- Updated: 2026-10-11T10:16:27.000Z
- Description: How to migrate a Minecraft proxy network from BungeeCord or Waterfall to Velocity — config translation, plugin replacements, modern IP forwarding, and the gotchas.
- Author: Lukas
- Tags: Minecraft, Gameserver, Linux

If you read [Waterfall vs BungeeCord](/waterfall-vs-bungeecord-minecraft-proxy/) and decided you actually want Velocity, this is the migration. Did this for a 4-backend network last year — about three hours of work, mostly translating plugin configs.

**TL;DR:**

```bash
sudo systemctl stop bungeecord
mkdir /opt/velocity && cd /opt/velocity
VER=4.2.0   # current stable: https://papermc.io/downloads/velocity
URL=$(curl -s -A "your-name/1.0 (you@example.com)" \
  "https://fill.papermc.io/v3/projects/velocity/versions/$VER/builds/latest" \
  | jq -r '.downloads."server:default".url')
wget -O velocity.jar "$URL"   # needs jq
java -jar velocity.jar  # generates velocity.toml, then Ctrl-C

```

Then translate `config.yml` → `velocity.toml`, swap every Bungee plugin for its Velocity counterpart, set every backend's `server.properties` to use `modern` IP forwarding instead of BungeeCord-style. Details below.

## Why migrate at all

Three reasons: lower latency under load, active development (PaperMC declared Waterfall end-of-life in March 2024; builds since then are sporadic), and the plugin ecosystem has caught up — every plugin I needed has a Velocity build by 2026.

If your network is fine and you're not hitting walls, don't migrate. The juice isn't worth the squeeze for a 20-player friends server. For anything bigger, or anything you expect to keep running 3+ years, do it.

## Pre-flight

Before touching anything:

```bash
sudo systemctl stop bungeecord
cp -r /opt/bungeecord /opt/bungeecord.bak.$(date +%F)

```

Full directory copy. If the migration goes sideways, `mv` brings the old proxy back in 30 seconds. Pattern from [rsync backups on Linux](/rsync-backup-linux/).

Make a list of every plugin in `/opt/bungeecord/plugins/` and its config. You'll re-create each one.

```bash
ls /opt/bungeecord/plugins/ > /tmp/plugin-list.txt

```

## Install Velocity

Velocity wants Java 17+. Check:

```bash
java -version

```

If it's older, install Temurin 21 — Velocity runs better on it:

```bash
sudo apt install temurin-21-jdk

```

Get the JAR:

```bash
sudo adduser --system --group --home /opt/velocity velocity
cd /opt/velocity
VER=4.2.0   # current stable: https://papermc.io/downloads/velocity
URL=$(curl -s -A "your-name/1.0 (you@example.com)" \
  "https://fill.papermc.io/v3/projects/velocity/versions/$VER/builds/latest" \
  | jq -r '.downloads."server:default".url')
sudo -u velocity wget -O velocity.jar "$URL"
sudo -u velocity java -jar velocity.jar

```

First run generates `velocity.toml`, `forwarding.secret`, and the `plugins/` folder, then asks you to set up. Ctrl-C — we're going to write the config from scratch.

## velocity.toml — translation from config.yml

Velocity uses TOML, not YAML. The mental mapping:

```toml
config-version = "2.7"

bind = "0.0.0.0:25565"
motd = "&6&lThe Network &7- &fpick a world"
show-max-players = 100
online-mode = true
prevent-client-proxy-connections = false

player-info-forwarding-mode = "modern"
forwarding-secret-file = "forwarding.secret"

announce-forge = false
announce-proxy-commands = true
log-command-executions = false
log-player-connections = true

[servers]
lobby = "127.0.0.1:25566"
survival = "127.0.0.1:25567"
creative = "127.0.0.1:25568"
try = ["lobby"]

[forced-hosts]
"survival.example.com" = ["survival"]
"creative.example.com" = ["creative"]

[advanced]
compression-threshold = 256
compression-level = -1
login-ratelimit = 3000
connection-timeout = 5000
read-timeout = 30000
haproxy-protocol = false
tcp-fast-open = false
bungee-plugin-message-channel = true
show-ping-requests = false
failover-on-unexpected-server-disconnect = true
announce-forge = false
kick-existing-players = false
ping-passthrough = "DISABLED"
sample-players-in-ping = false

[query]
enabled = false
port = 25565
map = "Velocity"
show-plugins = false

```

Field-by-field map from BungeeCord's `config.yml` (see my [BungeeCord config.yml deep-dive](/bungeecord-config-yml-explained/) for the source side):

| BungeeCord                      | Velocity                                 |
| ------------------------------- | ---------------------------------------- |
| listeners\[0\].host             | bind                                     |
| listeners\[0\].motd             | motd                                     |
| listeners\[0\].max\_players     | show-max-players                         |
| listeners\[0\].forced\_hosts    | \[forced-hosts\]                         |
| listeners\[0\].priorities       | \[servers\].try                          |
| listeners\[0\].tab\_list        | (gone — Velocity handles tab via plugin) |
| servers                         | \[servers\] (flat key=value)             |
| ip\_forward: true               | player-info-forwarding-mode = "modern"   |
| online\_mode                    | online-mode                              |
| connection\_throttle            | advanced.login-ratelimit                 |
| network\_compression\_threshold | advanced.compression-threshold           |

## The IP forwarding switch

This is the only step that requires touching every backend.

BungeeCord-style forwarding works by trusting whatever the proxy puts in the handshake. Modern (Velocity) forwarding signs the player data with a shared secret — backends verify the signature, so a malicious connection that bypassed the proxy fails.

Velocity generated `/opt/velocity/forwarding.secret` on first run. Copy its contents — that's the shared secret.

On every backend (Paper 1.13+ required for modern forwarding), edit `config/paper-global.yml`:

```yaml
proxies:
  velocity:
    enabled: true
    online-mode: true
    secret: "<contents-of-forwarding.secret>"

```

And `server.properties`:

```ini
online-mode=false

```

Yes, still `false` — same contract as BungeeCord. The proxy authenticates, the backend trusts. The difference is the trust is now cryptographically verified.

Restart each backend. If a backend is on Spigot or older Paper, it can't do modern forwarding — either upgrade to current Paper or fall back to `player-info-forwarding-mode = "legacy"` in Velocity (BungeeCord-compatible, less secure).

## Plugin replacements

Every BungeeCord plugin needs a Velocity equivalent. The common ones:

| BungeeCord               | Velocity                              |
| ------------------------ | ------------------------------------- |
| LuckPerms-Bungee         | LuckPerms-Velocity                    |
| BungeeTabListPlus        | TAB (works on Velocity)               |
| RedisBungee              | RedisBungee-Velocity (community fork) |
| BungeeCord-Authenticator | nLogin / AuthMeVelocity               |
| ServerListMOTD           | MotdManager                           |

Move configs over carefully — most plugins keep similar config structures between platforms, but YAML key names sometimes differ. Read the plugin's Velocity README before assuming the old config drops in.

Drop new JARs into `/opt/velocity/plugins/`, restart Velocity, watch the log:

```bash
sudo -u velocity tail -f /opt/velocity/logs/latest.log

```

## Systemd unit

`/etc/systemd/system/velocity.service`:

```ini
[Unit]
Description=Velocity Minecraft proxy
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=velocity
Group=velocity
WorkingDirectory=/opt/velocity
ExecStart=/usr/bin/java -Xms512M -Xmx1G -XX:+UseG1GC \
  -XX:G1HeapRegionSize=4M -XX:+UnlockExperimentalVMOptions \
  -XX:+ParallelRefProcEnabled -XX:+AlwaysPreTouch \
  -jar velocity.jar
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

```

1 GB heap is plenty for a 100-player network. More on systemd units in [systemd service unit files](/systemd-service-unit-file/).

```bash
sudo systemctl daemon-reload
sudo systemctl enable --now velocity

```

## DNS / firewall — nothing changes

Velocity binds to the same port (25565). DNS records, [UFW rules](/ufw-firewall-rules-ubuntu/), `forced_hosts` domains — all unchanged. You're swapping the engine, not the address.

## Verifying

From a client, connect. Tab list, server-switch (`/server lobby`), permissions — all should work like before. Check that the backends see real player UUIDs:

```bash
grep -E "^\[..:..:..\] .* logged in" /opt/paper/lobby/logs/latest.log | tail

```

UUIDs should be Mojang UUIDs, not offline-mode generated ones. If they're offline UUIDs, modern forwarding isn't actually active — re-check the secret on both sides.

## Rolling back

Worst case:

```bash
sudo systemctl stop velocity
sudo systemctl start bungeecord  # if you kept the unit

```

And revert each backend's `config/paper-global.yml` to disable modern forwarding. Five minutes if you took the pre-flight backups.

## Gotchas

- **Forwarding secret must match exactly.** Trailing newlines, accidental spaces — the JVM is unforgiving. Copy via `cat /opt/velocity/forwarding.secret` and paste literally.
- **Spigot can't do modern forwarding.** Migrate backends to Paper first if any are on Spigot.
- **Velocity does not auto-overwrite `velocity.toml` on shutdown.** This is the opposite of BungeeCord, which is good — your config is yours.
- **Player permissions don't transfer.** LuckPerms data carries over (it's per-user, not per-platform), but if you used BungeeCord's built-in permissions, you have to re-add them to LuckPerms. Build the LuckPerms config first, test on staging, then migrate prod.
- **Some 1.8 / 1.12 clients can't connect via modern forwarding.** Velocity supports them, but you need `player-info-forwarding-mode = "bungeeguard"` (BungeeGuard plugin on backends) instead of `modern`. Fine for legacy compatibility, slightly less clean.

If you're running a fresh new network, this is one of the first decisions. If you're migrating, do it on a Sunday morning and keep the BungeeCord directory around for two weeks before deleting it.

---

### Related posts

- [Hosting a Forge / NeoForge Modpack Server on Linux — The Pragmatic Guide](https://blog.diengdoh.com/forge-neoforge-modpack-server-linux/?ref=blog.sudowl.com)
- [LuckPerms on BungeeCord and Velocity — Permissions That Actually Scale](https://blog.diengdoh.com/luckperms-bungeecord-velocity-setup/?ref=blog.sudowl.com)
- [Waterfall vs BungeeCord — Which Minecraft Proxy Should You Run?](https://blog.diengdoh.com/waterfall-vs-bungeecord-minecraft-proxy/?ref=blog.sudowl.com)