BungeeCord is a proxy that sits in front of multiple Minecraft servers and lets players switch between them without disconnecting. One IP, multiple servers — lobby, survival, minigames, whatever.
This guide uses Waterfall, which is Paper's maintained BungeeCord fork. BungeeCord still works but Waterfall gets more fixes and is what most people run now.
When you actually need this
A proxy network makes sense when you have multiple separate game modes that need to feel like one server. If you just want one survival server, don't bother — it adds complexity and an extra process for no gain.
Architecture
Players connect to:
Waterfall proxy (:25565, public)
├── lobby (Paper, :25566, internal only)
├── survival (Paper, :25567, internal only)
└── minigames (Paper, :25568, internal only)
The backends are never exposed to the internet. Only the proxy port is public. This is important.
Set up the backend servers first
Each backend is a normal Paper server. Set them up following the Paper setup guide. Then make two changes on each backend:
1. server.properties — set a unique port and disable online-mode:
server-port=25566
online-mode=false
online-mode=false is required because authentication happens at the proxy. The backend can't do it again. This means your firewall rules matter — if a backend is reachable from the internet with online-mode off, anyone can connect without a valid account.
2. spigot.yml — enable BungeeCord IP forwarding:
settings:
bungeecord: true
This passes the real player IP and UUID through the proxy. Without it, all players appear to come from 127.0.0.1 and UUID-based permissions break.
Restart each backend after these changes.
Install Waterfall
sudo useradd -r -m -d /opt/waterfall -s /bin/bash waterfall
sudo mkdir -p /opt/waterfall
# Download from papermc.io/downloads/waterfall
sudo curl -o /opt/waterfall/waterfall.jar "https://api.papermc.io/v2/projects/waterfall/versions/1.21/builds/BUILD/downloads/waterfall-1.21-BUILD.jar"
sudo chown -R waterfall:waterfall /opt/waterfall
First run to generate config:
sudo -u waterfall java -jar /opt/waterfall/waterfall.jar
Stop it with Ctrl+C after it finishes starting.
config.yml
The main config lives at /opt/waterfall/config.yml. The important parts:
player_limit: -1
ip_forward: true
listeners:
- query_port: 25577
motd: '&bMy Network'
tab_list: GLOBAL_PING
query_enabled: false
proxy_protocol: false
forced_hosts: {}
ping_passthrough: false
priorities:
- lobby
bind_local_address: true
host: 0.0.0.0:25565
max_players: 200
tab_size: 60
force_default_server: false
servers:
lobby:
motd: '&bLobby'
address: 127.0.0.1:25566
restricted: false
survival:
motd: '&2Survival'
address: 127.0.0.1:25567
restricted: false
groups: {}
permissions:
default:
- bungeecord.command.server
- bungeecord.command.list
admin:
- bungeecord.command.alert
- bungeecord.command.end
- bungeecord.command.ip
- bungeecord.command.reload
Key settings:
ip_forward: true— must matchbungeecord: truein spigot.yml on backendspriorities— first server in the list is where new players landhost: 0.0.0.0:25565— the public-facing port- Backend addresses use
127.0.0.1— they're local only
systemd service for Waterfall
[Unit]
Description=Waterfall Minecraft Proxy
After=network.target
[Service]
Type=simple
User=waterfall
WorkingDirectory=/opt/waterfall
ExecStart=/usr/bin/java -Xms256M -Xmx512M -jar /opt/waterfall/waterfall.jar
Restart=on-failure
RestartSec=10s
StartLimitBurst=3
StartLimitIntervalSec=60s
[Install]
WantedBy=multi-user.target
Waterfall doesn't need much memory — 256-512MB is plenty. The backends need the RAM.
sudo systemctl daemon-reload
sudo systemctl enable waterfall
sudo systemctl start waterfall
sudo journalctl -u waterfall -f
Firewall — this part matters
Only the proxy port should be public. Backend ports must be blocked from the internet:
# Allow proxy port
sudo ufw allow 25565/tcp comment "Minecraft proxy"
# Block backend ports from external access
# (if backends are on the same host, they're already on loopback — fine)
# If backends are on separate hosts, use private network IPs and block public access:
sudo ufw deny 25566/tcp
sudo ufw deny 25567/tcp
sudo ufw deny 25568/tcp
If backends are on separate machines, put them on a private network and bind server-ip= in server.properties to the private interface only, not 0.0.0.0.
Test the connection
sudo journalctl -u waterfall -f
Connect with a Minecraft client to your server IP. You should land on the lobby. Use /server survival to switch servers (if the default permissions are set). Players with op can always use /server.
Common issues
"Your account is not premium" — backend has online-mode=true, should be false.
All players show as the same IP in backend logs — bungeecord: true not set in spigot.yml, or ip_forward: false in Waterfall config.
Can't connect to backend directly but proxy works — correct, that's expected. Backends don't need to be reachable directly.
Proxy connects but immediately drops — check that the backend is actually running and listening on the configured port: ss -tlnp | grep 25566
Plugins
Waterfall has its own plugin folder (/opt/waterfall/plugins/) for proxy-level plugins. These run on the proxy, not on the backends. Common ones: LuckPerms (network-wide permissions), ChatBridge (cross-server chat). Most game plugins still go on the individual backend servers.