Run the BungeeCord Minecraft proxy as a reproducible, multi-architecture Docker image, built with Nix.
flake.nix produces one image per BungeeCord Jenkins build number with
dockerTools.streamLayeredImage. The BungeeCord jar is a hash-pinned fetch from the SpigotMC
Jenkins (versions.json), the runtime JDK is chosen per build (jdk-boundaries.json), and the
proxy runs behind mc-server-init as PID 1 (PTY
console, named-pipe command injection, and a graceful end on SIGTERM). Images are built for
linux/amd64 and linux/arm64 and published as a single multi-arch manifest, signed with cosign,
with an SBOM and SLSA provenance.
Published on Docker Hub:
| Tag | Meaning |
|---|---|
latest |
The newest stable build (also tagged with its build number) |
<build> |
A specific Jenkins build number, e.g. 2080, 1119 |
<mc> |
The Minecraft version that build targets, e.g. 26.1, 1.7.10 |
Every Minecraft version BungeeCord has supported is published — the last build before support
moved to the next version — each tagged with both its Minecraft version and its build number
(1.21 and 2053 point at the same image). latest follows the newest. Modern BungeeCord is
multi-protocol, so e.g. the 1.16 image also accepts 1.8–1.16 clients; pick the tag for the
newest version you need.
| Minecraft | Build | Runtime JDK |
|---|---|---|
26.1 (= latest) |
2080 |
21 |
1.21 |
2053 |
17 |
1.20 |
1848 |
17 |
1.19 |
1708 |
11 |
1.18 |
1636 |
11 |
1.17 |
1609 |
11 |
1.16 |
1575 |
8 |
1.15 |
1500 |
8 |
1.14 |
1425 |
8 |
1.13 |
1402 |
8 |
1.12 |
1329 |
8 |
1.11 |
1232 |
8 |
1.10 |
1199 |
8 |
1.9 |
1157 |
8 |
1.7.10 |
1119 |
8 |
1.6.2 |
666 |
8 |
1.5.2 |
548 |
8 |
1.5.0 |
386 |
8 |
1.4.7 |
251 |
8 |
Each image runs on the JDK it was compiled with — the Java that was current when that build was
made (its manifest Build-Jdk), floored to JDK 8 (nixpkgs has no JRE 7). Verified Build-Jdk
transitions: Java 8→11 at build 1604, 11→17 at 1724, 17→21 at 2063. All assignments
verified by booting. jdk-boundaries.json records the minimum and desired JRE per range; the version
list is discovered from each jar's manifest and kept current by bump-latest.yml.
Two runtime constraints found while testing (the contemporary-JDK choice steers clear of both):
- JDK 17 is required from build 2054 (Minecraft 26.1): its
Bootstraprefuses to start on anything older — that's theminjump to 17 injdk-boundaries.json. - Builds 948–1604 (Minecraft 1.8–1.16) embed a
SecurityManager, which JDK 24 removed, so those builds cannot run on JRE 24+ (they run fine on their contemporary 8/11).
No dedicated
1.8tag: build 1119 is both the last 1.7.10-protocol build and the last1.8project build, so it's published as1.7.10; any1.9+ image proxies 1.8 clients too. And build701(1.6.4) is not published — its bootstrap hard-requires Java 7 (java.version.startsWith("1.7")), and no Java 7 runtime is available via nixpkgs (nor reliably on arm64).
docker run --rm -d \
-p 25565:25565 \
-v "$(pwd)/bungeecord:/srv/bungeecord" \
--name bungeecord \
d3strukt0r/bungeecord-p 25565:25565— the proxy listens on 25565 (the conventional Minecraft port). The image defaults BungeeCord's listener to 25565; override it with e.g.-e BUNGEE__LISTENERS__0__HOST=0.0.0.0:25577.-v …:/srv/bungeecord— persistconfig.yml,modules/,plugins/, and logs. The container runs as a non-root user (uid 65532); make sure the host directory is writable by it.- Pick a tag (
d3strukt0r/bungeecord:1119) to pin a specific build.
docker exec bungeecord console "<command>"console injects a line into the running proxy's stdin via a named pipe (no RCON). You can also
attach interactively with docker attach bungeecord.
docker stop bungeecordmc-server-init turns SIGTERM/SIGINT into BungeeCord's graceful end command, then SIGKILLs
only if it doesn't shut down in time.
See compose.yml for a proxy + backend-server example.
All variables also support Docker Secrets: append _FILE (e.g. MEMORY_FILE) and point it at a
file such as /run/secrets/<name>.
| Variable | Default | Description |
|---|---|---|
MEMORY |
(unset) | Heap size; sets both -Xms and -Xmx. K/M/G suffix. Unset = the JVM's own (container-aware) default heap sizing. |
INIT_MEMORY |
${MEMORY} |
Initial heap (-Xms) override. |
MAX_MEMORY |
${MEMORY} |
Max heap (-Xmx) override. |
JVM_FLAGS_PRESET |
none |
GC/tuning flag set: none or velocity (PaperMC proxy flags). |
JVM_OPTS |
Extra raw JVM arguments. |
To pass arguments to BungeeCord itself, just append them to the container command — if the first
one starts with - they're forwarded straight to the proxy, e.g.
docker run … d3strukt0r/bungeecord --noconsole. (A non-option command such as bash instead runs
as an override: docker run -it … d3strukt0r/bungeecord bash.)
Any BUNGEE__… variable is written into config.yml. __ separates path segments, an all-digits
segment is a list index, and values are YAML-typed:
-e BUNGEE__ONLINE_MODE=false # online_mode: false
-e BUNGEE__PLAYER_LIMIT=100 # player_limit: 100
-e BUNGEE__IP_FORWARD=true # ip_forward: true
-e BUNGEE__LISTENERS__0__MOTD=Hi # listeners[0].motd: "Hi"Quote a value that must stay a string but looks numeric. For list-heavy sections (listeners,
servers) it is usually simpler to mount your own config.yml into /srv/bungeecord.
BungeeCord generates config.yml in the /srv/bungeecord volume on first start. The sample below
shows the defaults (the image only changes the listener host to 0.0.0.0:25565); these are the
keys you can override with BUNGEE__… env vars.
Example config.yml
connection_throttle_limit: 3
online_mode: true
log_commands: false
network_compression_threshold: 256
listeners:
- query_port: 25577
motd: '&1Another Bungee server'
tab_list: SERVER
query_enabled: false
proxy_protocol: false
forced_hosts:
pvp.md-5.net: pvp
ping_passthrough: false
priorities:
- lobby
bind_local_address: true
host: 0.0.0.0:25565
max_players: 500
tab_size: 60
force_default_server: false
connection_throttle: 4000
log_pings: true
ip_forward: true
prevent_proxy_connections: false
forge_support: false
stats: 287a5297-3c79-...
inject_commands: true
disabled_commands:
- disabledcommandhere
groups:
D3strukt0r:
- admin
- moderator
timeout: 30000
permissions:
default:
- bungeecord.command.server
- bungeecord.command.list
moderator:
- bungeecord.command.find
- bungeecord.command.send
- bungeecord.command.ip
- bungeecord.command.alert
admin:
- bungeecord.command.end
- bungeecord.command.reload
servers:
lobby:
motd: '&1Just another BungeeCord - Forced Host'
address: localhost:25566
restricted: false
player_limit: -1/srv/bungeecord— server working directory (config, modules, plugins, logs).25565/tcp— proxy listener.
- Nix — reproducible, multi-arch image builds
- BungeeCord — the proxy software
- mc-server-init — PID-1 console/signal handling
- GitHub Actions — CI/CD
Please read CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.
There is no project-specific versioning.
- Manuele - D3strukt0r
See also the full list of contributors who participated in this project.
We're currently looking for contributions for the following:
- Bug fixes
- Translations
- etc...
For more information, please refer to our CONTRIBUTING.md guide.
This project is licensed under the MIT License - see the LICENSE.txt file for details.
- Geoff Bourne with itzg/docker-bungeecord
- James Rehfeld with rehf27/docker-bungeecord
- Leopere with Leopere/docker-bungeecord
- Hat tip to anyone whose code was used
- Inspiration
- etc