RE:NODE

How to set up BungeeCord: jar, config.yml and backends

By RE:NODE Team
14 min read


Setting up BungeeCord takes four steps: download BungeeCord.jar from md_5's build server, start it once so it writes config.yml, point that file at your backend servers, and change three settings on each backend so it accepts players through the proxy and nobody else. The first three take ten minutes. The fourth is where networks get broken into, because a BungeeCord backend trusts whatever identity a connection claims, so it has to be unreachable from the internet or protected by BungeeGuard.

Before you start, one honest note. For a brand new network, Velocity is the better proxy: it is faster, PaperMC maintains it, and its modern forwarding protects backends without a firewall. BungeeCord vs Velocity explains the difference, and the Velocity network guide is the setup if you go that way. BungeeCord is still maintained, still widely run, and the right choice when a plugin you depend on only exists for it. If that is you, this is the setup, done properly.

What BungeeCord does, and what it does not#

BungeeCord is a proxy that speaks the Minecraft protocol. Players connect to it, it authenticates them with Mojang once, then opens its own connection to a backend server and relays packets both ways. Typing /server survival makes the proxy drop the lobby connection and open one to survival while the player's own connection stays up. That is the whole trick: several separate Minecraft servers, one address, no disconnect between them.

It holds no world, ticks no entities and runs no Bukkit plugins. That has three consequences people discover the hard way:

  • Plugins do not cross over. Paper and Spigot plugins go on the backends. Only BungeeCord plugins - built against the BungeeCord API - go in the proxy's plugins folder.
  • Player data is per backend. Inventories, homes, balances and ops.json live on each backend separately. The proxy shares none of it.
  • It does not translate versions. The client and the backend it lands on must speak the same protocol. BungeeCord accepts a wide range of client versions at its own door, but a 1.21 client still cannot play on a 1.20 backend unless ViaVersion sits somewhere in the chain.

It also does not make a laggy world faster. If one survival world is struggling, a proxy adds a hop and changes nothing else. A proxy is for several distinct servers under one name.

TCP 25565ip_forwardPlayersJava editionBungeeCordpublic :25565Lobby127.0.0.1:25566Survival127.0.0.1:25567Creative127.0.0.1:25568
One public port, backends reachable only by the proxy

Requirements and sizing#

The proxy is light. It spends CPU on compression and encryption and very little memory on anything else.

Network sizeProxy heapProxy CPU
Up to 50 players256-512 MBUnder one core
50-300 players512 MB - 1 GBOne core
300+ players1-2 GBOne to two cores

Run it on a current Java. The jar has historically been undemanding, but recent builds track modern Java, and since your Paper backends need Java 21 for current Minecraft versions anyway, use Java 21 for the proxy too and keep one runtime to think about. Minecraft JVM flags and Java versions covers which Java goes with which game version.

The money goes on the backends. A network of a proxy, a lobby and two gamemodes is four processes, each with its own memory limit, and the lobby should be the smallest of the backends because it simulates almost nothing.

Downloading the official BungeeCord.jar#

BungeeCord has one official source: md_5's Jenkins build server at ci.md-5.net, linked from the SpigotMC site. The file is called BungeeCord.jar and the latest successful build is always at a stable path:

bash
$ mkdir -p ~/network/proxy && cd ~/network/proxy$ wget -O BungeeCord.jar \    https://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/artifact/bootstrap/target/BungeeCord.jar

There is no installer and no BuildTools step - unlike Spigot itself, the proxy jar is distributed ready to run. Avoid "BungeeCord download" mirrors on random hosting sites. Some are simply stale; some have shipped modified jars. If a page offers you a BungeeCord jar with a version number in the file name, it did not come from md_5.

Waterfall, the fork you will still see recommended in older tutorials, is no longer developed. Do not start a new network on it.

First start and the files it creates#

Start the proxy once with a small heap:

bash
$ java -Xms512M -Xmx512M -jar BungeeCord.jar

It generates its files, binds to its default port and waits. Type end in the console to stop it cleanly. You now have:

File or folderWhat it is
config.ymlThe whole proxy configuration
modules/Built-in command modules (cmd_server, cmd_list, cmd_send and so on)
modules.ymlWhere the modules are fetched from
plugins/BungeeCord plugins, empty at first
proxy.log.0The current log, rotated to .1, .2

Two defaults in the generated file catch nearly everyone. The listener binds to port 25577, not 25565, and the example server entry points at localhost:25565. That arrangement assumes you will move your existing Minecraft server off 25565 and put the proxy in front of it on a different port - most people want the opposite, so change both. The default max_players on the listener is 1, which only affects the number shown in the server list, but it makes a working network look broken.

config.yml, key by key#

This is a complete, working configuration for a proxy with three backends on the same machine. Comments mark the keys you must change.

config.yml
online_mode: trueip_forward: truenetwork_compression_threshold: 256connection_throttle: 4000connection_throttle_limit: 3player_limit: -1timeout: 30000log_commands: falselog_pings: falseprevent_proxy_connections: falselisteners:- host: 0.0.0.0:25565  motd: '&bThe Longhouse Network'  max_players: 200  tab_list: GLOBAL_PING  tab_size: 60  force_default_server: true  priorities:  - lobby  forced_hosts:    survival.example.com: survival  ping_passthrough: false  query_enabled: false  query_port: 25565  proxy_protocol: false  bind_local_address: trueservers:  lobby:    address: 127.0.0.1:25566    motd: 'Lobby'    restricted: false  survival:    address: 127.0.0.1:25567    motd: 'Survival'    restricted: false  creative:    address: 127.0.0.1:25568    motd: 'Creative'    restricted: false

The listener block

listeners is a list, and almost every network has exactly one entry.

  • host is the address and port the proxy binds. 0.0.0.0:25565 means every interface on the standard port. On a panel host it must match the allocation you were given.
  • motd and max_players are what the server list shows. Colour codes use &.
  • priorities is the ordered list of servers a player is tried against on login. The first that accepts them wins. Every name here must exist under servers, spelled identically, or players get the fallback error in the troubleshooting section.
  • force_default_server: true sends every player to the first priority server on every login. With false, BungeeCord's reconnect module sends them back to the last server they were on, which is what you want for a survival-first network and not for a lobby-first one.
  • forced_hosts maps the hostname a player typed to a server, so survival.example.com skips the lobby. Each hostname needs DNS pointing at the proxy.
  • ping_passthrough: true shows a backend's MOTD and player count in the list instead of the proxy's own. Leave it false unless you have a reason.
  • tab_list is GLOBAL_PING, GLOBAL or SERVER. SERVER lets each backend control its own tab list, which is what tab plugins on the backends expect.
  • proxy_protocol: true is only for when something like HAProxy or a TCP load balancer sits in front of BungeeCord and sends PROXY protocol headers. Turn it on without that and every connection fails.

Global keys

  • online_mode: true - the proxy authenticates players with Mojang. Leave this on. Turning it off creates a cracked network where anyone can log in as anyone.
  • ip_forward: true - passes each player's real IP, UUID and skin to the backends. Off by default, and with it off every player arrives on the backends with the proxy's address and an offline-mode UUID. Turn it on; it pairs with the backend setting in the next section.
  • network_compression_threshold: 256 - packets above this many bytes are compressed. The default is right for traffic to players.
  • connection_throttle and connection_throttle_limit - how many logins one IP may make inside the window, in milliseconds. Raise the limit if many players share one address, such as a school or a LAN party.
  • player_limit: -1 - a hard cap across the whole proxy, -1 for none. Different from max_players, which is only the displayed number.
  • timeout: 30000 - milliseconds before an unresponsive connection is dropped.

The servers block

Each entry is a name, an address and a restricted flag. The name is what /server <name> and priorities use, and what plugins on the backends use when they send players around, so pick short, lowercase names and never rename them casually. restricted: true means a player needs the bungeecord.server.<name> permission to connect - useful for a staff-only build server.

Query and the built-in permissions

query_enabled turns on the GameSpy4 query protocol that some server-list sites and status bots use, on UDP query_port. Most networks leave it off. If you enable it, the port is UDP, and on a host with fixed allocations it has to be one you actually have - game server ports explained covers why query ports exist.

The generated file also contains a groups block with md_5 as an example admin, and a permissions block that gives the default group /server and /glist. This tiny built-in system works, but it knows nothing about ranks. Remove the md_5 entry, add your own username to admin if you want, and plan to replace it with LuckPerms on the proxy - the LuckPerms guide shows how to scope proxy permissions with a server context.

What to change on every backend#

Each backend is an ordinary Spigot or Paper server. Three files change.

server.properties (backend)
server-ip=127.0.0.1server-port=25566online-mode=false
spigot.yml (backend)
settings:  bungeecord: true
bukkit.yml (backend)
settings:  connection-throttle: -1

Why each one:

  • online-mode=false is required. The proxy already authenticated the player; a backend in online mode would try to do it again, and the proxy refuses with Server is online mode!.
  • bungeecord: true in spigot.yml makes the backend read the forwarded IP and UUID that ip_forward sends. Without it, players get offline-mode UUIDs and lose their data the moment you fix it later.
  • connection-throttle: -1 in bukkit.yml stops the backend rate-limiting logins. Every login comes from the proxy's address, so the backend's own throttle would otherwise kick legitimate players during busy moments with "Connection throttled".

On Paper, also check config/paper-global.yml (or paper.yml before 1.19): proxies.bungee-cord.online-mode should be true, telling Paper the identities arriving through the proxy were verified. Plugins that care about premium accounts read it.

Each backend needs its own port, and every backend must run the same Minecraft version as the clients that reach it, or carry ViaVersion. Restart the backends after these changes; spigot.yml is not reloaded live. server.properties explained covers the other settings worth trimming on a lobby, such as view-distance and spawn-protection.

Firewalling the backends#

Here is why this matters. A backend with online-mode=false and bungeecord: true believes any handshake that claims to carry forwarded data. Anyone who can reach its port can connect with a crafted handshake saying they are your operator, and the backend lets them in with that player's UUID, permissions and inventory. Public tools do exactly this, and scanners find open backends quickly.

There are three ways to close the hole, in order of strength.

  1. Bind to localhost. When the proxy and the backends share a machine, server-ip=127.0.0.1 on each backend makes them unreachable from outside. This is the simplest and best option, and it is what the example config above uses.
  2. Firewall the ports. When backends are on other machines, allow their ports only from the proxy's address, and deny everyone else. The ufw example below does this.
  3. BungeeGuard. When you cannot firewall - on most shared panel hosts each server is a separate container with its own public port - install BungeeGuard on the proxy and on every backend. The proxy plugin generates a secret token and adds it to forwarded data; the backend plugin holds that token in its allowed-tokens list and rejects connections without it. It is the same idea as Velocity's modern forwarding, bolted on.

For option 2, on a backend whose proxy lives at 203.0.113.10, the rule order matters - ufw applies the first match, so the allow goes in before the deny:

bash
$ sudo ufw allow from 203.0.113.10 to any port 25566 proto tcp$ sudo ufw deny 25566/tcp

On RE:NODE every server, proxy or backend, is its own container with its own public allocation, so option 1 and option 2 are not available to you between servers. BungeeGuard on the proxy and every backend is the setup to use there, and the direct-join test above is how you confirm it works. The broader list of things to lock down is in the Minecraft server security checklist.

Running it, plugins and commands#

Start the backends first, then the proxy. Order is not strictly required, but a proxy that starts with no backend up will kick the first players with the fallback error.

bash
$ java -Xms512M -Xmx512M -XX:+UseG1GC -jar BungeeCord.jar

Proxy plugins go in plugins/ as jars, and the proxy has to be restarted to load them. BungeeCord has a /greload command, but it does not reload plugins and has never been reliable for much beyond the server list - most admins restart the proxy instead, which disconnects everyone, so batch changes and restart at a quiet hour. Typical proxy plugins are LuckPerms (BungeeCord build), BungeeGuard, ViaVersion if you want it on the proxy, Geyser and Floodgate for Bedrock players (Geyser and Bedrock crossplay), and a network chat or ban plugin. Check each download page says BungeeCord, not Spigot - a Bukkit plugin in the proxy's folder fails to load with an error at startup.

CommandPermissionEffect
/server <name>bungeecord.command.serverMove yourself
/glistbungeecord.command.listPlayers on each server
/send <player> <server>bungeecord.command.sendMove someone else
/find <player>bungeecord.command.findWhich server they are on
/alert <message>bungeecord.command.alertBroadcast to the network
/ip <player>bungeecord.command.ipShow a player's address
/greloadbungeecord.command.reloadRe-read config.yml
endbungeecord.command.endStop the proxy (console)

Backend plugins that send players between servers - selector menus, lobby signs, minigame return-to-lobby - talk to the proxy over the BungeeCord plugin messaging channel. They need nothing installed on the proxy, but they do need the server names in config.yml to match what you configured in them.

Once the proxy works, put a hostname on it with an A record and an SRV record so players type mc.example.com with no port - SRV records for Minecraft has the exact record.

Troubleshooting the first-time errors#

"If you wish to use IP forwarding, please enable it in your BungeeCord config as well!" The backend has bungeecord: true in spigot.yml, but the proxy is not forwarding. Set ip_forward: true in the proxy's config.yml and restart the proxy. You also see this when someone connects to the backend directly, bypassing the proxy - which, if it works at all, tells you the backend is reachable from outside.

"Could not connect to a default or fallback server, please try again later", usually followed by Connection refused. The proxy tried every server in priorities and none answered. Check in order: is the backend actually running; does the address in servers match the backend's server-ip and server-port; is the name in priorities spelled exactly like the key under servers; and, if the backend is on another machine, does your firewall let the proxy through. A backend bound to 127.0.0.1 is unreachable from a proxy on a different machine.

`Server is online mode!` The backend still has online-mode=true. Set it to false and restart.

Everyone logs in as a fresh player with no inventory. UUIDs are arriving in offline form, so ip_forward is off on the proxy or bungeecord is off on the backend. Stop and fix it before more people play; each login creates player data you will have to clean up.

`Connection throttled! Please wait before reconnecting.` from a backend during busy periods. The backend's connection-throttle in bukkit.yml is still on; set it to -1.

`Address already in use` on startup. Something else holds the listener port, often a backend still on 25565 after you moved the proxy there. Move the backend or change host.

`Outdated server!` or `Outdated client!` The client and the backend versions differ. Keep every backend on the client's version or add ViaVersion. Minecraft version upgrades covers the order to update a network in.

Players can join but the server list shows 1 slot. That is the default max_players: 1 on the listener. It is cosmetic; change it to the number you want shown.

FAQ#

Where do I download BungeeCord.jar safely?

From md_5's Jenkins at ci.md-5.net, the lastSuccessfulBuild artifact of the BungeeCord job, which the SpigotMC site links to. It is distributed as a ready jar with no BuildTools step. Mirrors on other sites are unnecessary and sometimes stale or modified.

Should I use BungeeCord or Velocity for a new network?

Velocity, unless a plugin you need only exists for BungeeCord. Velocity's modern forwarding is signed, so backends reject direct connections without a firewall or BungeeGuard, and it handles more players per core. BungeeCord works, but needs that extra protection to be safe.

Do backends need the same plugins as the proxy?

No, they are separate worlds. Bukkit, Spigot and Paper plugins go on backends; BungeeCord plugins go on the proxy. A few, such as LuckPerms, Floodgate and BungeeGuard, publish both builds and run in both places, each with the build made for it.

Why does BungeeCord default to port 25577?

Because it assumes you already have a Minecraft server on 25565 and are putting the proxy beside it. Most networks swap them: the proxy takes 25565 so players need no port, and the backends move to other ports.

Can backends run different Minecraft versions?

Only if every client can still talk to the backend it lands on. The proxy does not translate versions. Either keep all backends on one version or install ViaVersion, on the proxy or on each backend but not both.

Is offline mode on the backends dangerous?

On its own, very. It is safe only when the backends cannot be reached except through the proxy: bound to 127.0.0.1, firewalled to the proxy's address, or protected by BungeeGuard. Test by joining a backend directly; it must refuse you.