This is a containerized version of my Paper Minecraft Java server. The image works great on all Docker platforms including Raspberry Pi!
There is also a version that has Geyser + Floodgate installed which will let Minecraft Bedrock players connect to your Java server!
The official GitHub repository is located here.
The official Docker Hub repository is located here.
The Minecraft Bedrock version of the container is located here. This is for the Java version.
It’s now possible to convert your worlds between Bedrock and Java versions. Check out my guide on Chunker here for more information.
Features
- Sets up fully operational Minecraft server in less than a couple of minutes
- Runs the highly efficient “Paper” Minecraft server
- Plugin support for Paper / Spigot / Bukkit
- Uses named Docker volume for safe and easy to access storage of server data files (which enables more advanced Docker features such as automatic volume backups)
- Installs and configures OpenJDK 18
- Automatic backups to minecraft/backups when server restarts
- Full logging available in minecraft/logs folder
- Updates automatically to the latest version when server is started
- Runs on all Docker platforms including Raspberry Pi
Usage
First you must create a named Docker volume. This can be done with:
docker volume create yourvolumename
Now you may launch the server and open the ports necessary with one of the following Docker launch commands.
With default port:
docker run -it -v yourvolumename:/minecraft -p 25565:25565 --restart unless-stopped 05jchambers/legendary-java-minecraft-paper:latest
With custom port:
docker run -it -v yourvolumename:/minecraft -p 12345:12345 -e Port=12345 --restart unless-stopped 05jchambers/legendary-java-minecraft-paper:latest
With a custom Minecraft version (add -e Version=1.X.X, must be present on Paper’s API servers to work):
docker run -it -v yourvolumename:/minecraft -p 25565:25565 -e Version=1.17.1 --restart unless-stopped 05jchambers/legendary-java-minecraft-paper:latest
With a maximum memory limit in megabytes (optional, prevents crashes on platforms with limited memory, -e MaxMemory=2048):
docker run -it -v yourvolumename:/minecraft -p 25565:25565 -e MaxMemory=2048 --restart unless-stopped 05jchambers/legendary-java-minecraft-paper:latest
Using a different timezone:
docker run -it -v yourvolumename:/minecraft -p 25565:25565 -e TZ="America/Denver" --restart unless-stopped 05jchambers/legendary-java-minecraft-paper:latest
Skipping backups on a certain folder:
docker run -it -v yourvolumename:/minecraft -p 25565:25565 -e NoBackup="plugins" --restart unless-stopped 05jchambers/legendary-java-minecraft-paper:latest
Skipping permissions check:
docker run -it -v yourvolumename:/minecraft -p 25565:25565 -e NoPermCheck="Y" --restart unless-stopped 05jchambers/legendary-java-minecraft-paper:latest
Configuration / Accessing Server Files
The server data is stored where Docker stores your volumes. This is typically a folder on the host OS that is shared and mounted with the container. I’ll give the usual locations here but if you’re having trouble just do some Googling for your exact platform and you should find where Docker is storing the volume files.
You can find your exact path by typing:
docker volume inspect yourvolumename
This will give you the fully qualified path to your volume like this:
{ "CreatedAt": "2022-05-09T21:08:34-06:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/yourvolumename/_data", "Name": "yourvolumename", "Options": {}, "Scope": "local" }
On Linux it’s typically available at:
/var/lib/docker/volumes/yourvolumename/_data
On Windows it’s at
C:\ProgramData\DockerDesktop
but may be located at something more like
\wsl$\docker-desktop-data\version-pack-data\community\docker\volumes\
if you are using WSL (Windows Subsystem for Linux).
On Mac it’s typically
~/Library/Containers/com.docker.docker/Data/vms/0/ If you are using Docker Desktop on Mac then you need to access the Docker VM with the following command first:
screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
You can then normally access the Docker volumes using the path you found in the first step with docker volume inspect
Most people will want to edit server.properties. You can make the changes to the file and then restart the container to make them effective.
Backups are stored in the “backups” folder
Log files with timestamps are stored in the “logs” folder.
Plugin Support for Paper / Spigot / Bukkit
This is a “Paper” Minecraft server which has plugin compatibility with Paper / Spigot / Bukkit.
Installation is simple. There is a “plugins” folder on your Docker named volume.
Navigate to your server files on your host operating system (see accessing server files section if you don’t know where this is) and you will see the “plugins” folder.
You just need to drop the extracted version of the plugin (a .jar file) into this folder and restart the container. That’s it!
Some plugins have dependencies so make sure you read the installation guide first for the plugin you are looking at.
A popular place to get plugins is: dev.bukkit.org
Troubleshooting Note – Oracle Virtual Machines
A very common problem people have with the Oracle Virtual Machine tutorials out there that typically show you how to use a free VM is that the VM is much more difficult to configure than just about any other product / offering out there.
It is because there are several steps you need to take to open the ports on the Oracle VM. You need to both:
- Set the ingress ports (TCP/UDP) in the Virtual Cloud Network (VCN) security list
- *and* set the ingress ports in a Network Security Group assigned to your instance
Both of these settings are typically required before you will be able to connect to your VM instance. This is purely configuration related and has nothing to do with the script or the Minecraft server itself.
I do not recommend this platform due to the configuration difficulty but the people who have gone through the pain of configuring an Oracle VM have had good experiences with it after that point. Just keep in mind it’s going to be a rough ride through the configuration for most people.
Troubleshooting Note – Hyper-V
There is a weird bug in Hyper-V that breaks UDP connections on the Minecraft server. The easy workaround for this is that you have to use a Generation 1 VM with the Legacy LAN network driver.
There is a second fix that was shared by bpsimons here. For that fix you need to install ethtool first with sudo apt install ethtool. Next in your /etc/network/interfaces file add “offload-tx off” to the bottom as the issue appears to be with TX offloading.
Here’s an example:
# The primary network interface auto eth0 iface eth0 inet static address 192.168.1.5 netmask 255.255.255.0 network 192.168.1.0 broadcast 192.168.1.255 gateway 192.168.1.1 offload-tx off
This can also be done non-persistently with the following ethtool command:
ethtool -K eth0 tx off
Additional Support
The comments section right here is the best place for support. The second best place is the GitHub issues section.
I will add additional documentation based on what problems people are running into / questions people are asking because right now I’m not really sure what those will be yet. Definitely let me know if you need any of these things!
Thanks for all your work and your long thorough explanations that you do.
I’m going to start a new world for our Minecraft server and put it in docker as you explained. The question I have is this – On my old server I would run an incremental backup of the world folder every hour or so in case some friends light our house on fire or something like that. In my testing the docker volumes folder (linux /var/lib/docker/volumes/…) is only able to be opened by root. Is there any way I can set up my server so those can be read by a normal user? I’ve tried changing the folder permissions and even doing a chown to change the ownership but it seems to revert back to root at some point. Do you have any suggestions?
Thanks so much.
Hey David,
Welcome! So I think this should be possible (although be careful with backups when the server is running as things can get weird). I don’t think you will be able to use Docker volumes for this though. Most likely you’ll need to use a shared OS mount.
The way you’d do this is instead of using a Docker volume during startup you would use a shared folder basically. Instead of using -v minecraft:/minecraft you would use something like -v /your/folder:/minecraft.
I’d definitely be careful doing live backups on the Minecraft server though via files. The script/containers do this when the container restarts since the server isn’t running yet basically. The reasons are pretty complex but involve not everything is written to disk immediately and some of it lives in memory. If the server is closed all of this is wrote to disk and the files are closed. The server basically has ownership of the files when it’s running and will write the block changes when it feels like it basically.
A safer way to do this might be via plugins. I know there are backup plugins. The reason I think this may be a safer approach is that the plugins are running inside of the Minecraft server so they’re accessing all of that data as the Minecraft sees it (which may not all be written/reflected in the file system while it’s running).
In other words like a lot of other applications the Minecraft server “locks” the files and doesn’t expect other things to be editing them. It doesn’t always sync it’s changes right away which can make backups while running via filesystem corrupt a lot of the time. There’s another backup plugin available here as well. There’s a lot of choices and ones you can look through.
I think the bind mount will let you do what you’re trying to do though. Just make sure to try testing some of those backups and make sure they’re actually restoring correctly. I think a plugin solution would be nice though. Some of these you just type a command like /ebackup start. These backups should be safe even when running.
You may still run into permissions issues while the server is running. Another suggestion I would have to work around this (which would theoretically work with the Docker volume as well) is to add your backup command/account to the (passwordless) sudoers list (but only for your backup command). If you use sudo before you backup these files it should still work. It’s always going to be owned by root though when it’s running and I’d imagine that will be true for the shared OS mount as well.
My standalone version of the script actually adds sudoers entries for special commands like this:
Update_Sudoers() {
if [ -d /etc/sudoers.d ]; then
sudoline="$UserName ALL=(ALL) NOPASSWD: /bin/bash $DirName/minecraftbe/$ServerName/fixpermissions.sh -a, /bin/systemctl start $ServerName, /bin/bash $DirName/minecraftbe/$ServerName/start.sh"
if [ -e /etc/sudoers.d/minecraftbe ]; then
AddLine=$(sudo grep -qxF "$sudoline" /etc/sudoers.d/minecraftbe || echo "$sudoline" | sudo tee -a /etc/sudoers.d/minecraftbe)
else
AddLine=$(echo "$sudoline" | sudo tee /etc/sudoers.d/minecraftbe)
fi
else
echo "/etc/sudoers.d was not found on your system. Please add this line to sudoers using sudo visudo: $sudoline"
fi
}
The most important line is this though:
sudoline="$UserName ALL=(ALL) NOPASSWD: /bin/bash $DirName/minecraftbe/$ServerName/fixpermissions.sh -a, /bin/systemctl start $ServerName, /bin/bash $DirName/minecraftbe/$ServerName/start.sh"
This line adds parameter-specific sudo permissions to allow the command to run as root (but only entered exactly as we put it in the file). You can see here what the permissions are. It only has permissions to start the server with systemctl, run the fix permissions script as sudo and run start.sh as sudo. All other sudo command attempts would be denied (or they’d be prompted for a password). This would be the secure way to get around this. If you made your own secure sudoers list entry such as:
mybackupaccount ALL=(ALL) NOPASSWD: /usr/bin/cp /backupdir /destdir
Adding a line like this to your sudoers file would allow the backup account to *only* run sudo cp /backupdir /destdir for example (without having to enter a password meaning you can use it in scripts). If you tried to use any other command with sudo it would be denied. If you tried to use sudo cp and copy to a different directory it would also be denied. Only typing the command exactly as it shows in the sudoers file would be allowed to be ran as root without having to enter a password (since we whitelisted only that specific command).
Hopefully that helps and makes sense / gives you some options here!
When starting the server for the first time, using docker-compose, how do I tell Minecraft to create a superflat map?
Hey Doug,
Great question. The best way to do this is to actually start the container for the first time and then stop it immediately. Next go to your server data folder (typically /var/lib/docker/yourvolumename/_data).
Now if you edit the server.properties file look for the:
level-type=default
Change this to
level-type=flat
Now remove your “world” folder with:
sudo rm -rf world
Now if you start the server again it will generate a flat type world. If you are meaning flatter than this then superflat often means server side plugins (which you could install those as well). I’d start with flat though first and see if that gets you close to where you want it to be!
Thanks so much for this! I’ve used your previous Raspberry Pi version and am migrating over to the Docker version now. Have Docker up and running on my Raspberry Pi and was able to test that it is working with a simple ‘hello-world’ container.
Created the volume as you instructed and tested with just the basic default port command. It seemed like it completed all the pulls, but wasn’t able to finish. This was the output:
latest: Pulling from 05jchambers/legendary-java-minecraft-paper
ceab7032a497: Pull complete
754d4bf25883: Pull complete
a20ecc4dce1a: Pull complete
2d9f2c5a8117: Pull complete
3701130af22e: Pull complete
46e29ec769d1: Pull complete
c78a83a27926: Pull complete
09bbe066d6ff: Pull complete
Digest: sha256:4d735e5c2ffdf871e6da23fc276e24766797f5a80ce1ede75ea6288c90cc9aae
Status: Downloaded newer image for 05jchambers/legendary-java-minecraft-paper:latest
Paper Minecraft Java Server Docker script by James A. Chambers
Latest version always at https://github.com/TheRemote/Legendary-Java-Minecraft-Paper
Don't forget to set up port forwarding on your router! The default port is 25565
Port used: 25565
Taking ownership of all server files/folders in /minecraft...
Complete
No daily restart scheduled
Updating to most recent paperclip version ...
Unable to connect to update website (internet connection may be down). Skipping update ...
Starting Minecraft server...
Error: Unable to access jarfile /minecraft/paperclip.jar
I can confirm that the server can access the internet and other containers are able to pull and work. Any ideas?
Hey Josh,
Welcome! So most commonly this has been due to running an older version of Raspberry Pi OS (usually Debian Buster). In that version the DNS in Docker isn’t working. Basically the error is saying that it can’t connect to the internet.
The easiest way to fix it is to do a clean install of Raspberry Pi OS Bullseye. This is available using the Raspberry Pi Imager tool or on their site as the latest image. This should take care of it for you.
Hopefully that helps!
Thanks, James. Followed your advice. Completely wiped the SD card and started fresh with the latest version of Bullseye. I did choose the 64bit Lite version, I hope that’s okay. Updated and upgraded to make sure everything was up to date. Configured Memory Split to 16, but aside from hostname and SSH, left most of the system untouched. Installed docker and ran the ‘docker run hello-world’ command to make sure it was working correctly. (I did add the ‘pi’ user to the docker group so I wouldn’t have to always run docker commands with sudo.)
This time when I ran the docker command, I got a different set of errors:
System has not been booted with systemd as init system (PID 1). Can’t operate.
Failed to connect to bus: Host is down
Scheduling daily restart:
Updating to most recent paperclip version …
/scripts/start.sh: line 148: {“error”:”Version not found.”} + 0: syntax error: operand expected (error token is “{“error”:”Version not found.”} + 0″)
Starting Minecraft server…
Error: Unable to access jarfile /minecraft/paperclip.jar
Was about to dig into the systemd issue, but thought I would check with you first and see if you had see this before.
Thanks again for all the help!
Hey Josh,
Go ahead and add:
-e Version=1.19.2
to your startup line. Version 1.19.3 isn’t out yet which is why it’s giving and error saying version not found. That’s true. There’s no Paper version 1.19.3 yet so it’s failing to download it.
We’re still waiting for them to release this but it shouldn’t be much longer. For now if you manually specify the version as 1.19.2 this will get around this error until 1.19.3 is released for Paper.
That should get it going here!
Ah! I feel foolish! All set now, it’s working and I was able to connect with the Minecraft client.
I ran it without the -d flag, so had to quit out of the Minecraft instance after starting it. I tried running the command with the -d flag, but it gave me an error that the port was already allocated and when I tried to connect the server was running again. I’m not used to not having to fiddle with things! I’m new to docker so I need to read up on it and get used to how it works.
I found your old notes explaining why with your old scripts you recommended running it on 32bit Raspberry Pi OS, is that still your recommendation? I have a Raspberry Pi 4 Model B with 4GB of RAM, which seems to run the 64bit version well. But I’m wondering if it’ll have the same negative impact on running the Minecraft server.
Anyway, thanks again for all the help on this!
Hey Josh,
I would recommend the 64 bit version on modern Pis (especially above about 2GB). The 32 bit version has severe limitations on memory usage. My old notes probably would have been for when we had devices with 512MB – 1GB of RAM (at a maximum). 32-bit will not be able to utilize all your memory for the server and is capped for sure so I’d stick with 64 bit.
I’m glad you got everything else going. Your setup sounds great to me and I’d leave it as 64-bit. Enjoy and take care!
Awesome! You’ve been such a great help. Just sent a donation through CashApp.
Last question (I think!). In the previous version, since you were using ‘screen’ to launch Minecraft, it was easy to connect to the console (‘screen -r minecraft’) and then run commands on the server (like making a user operator, for example). I can’t figure out how to do something similar with the new docker set up. Can you point me in the right direction?
Hey Josh,
Great question and thanks so much for sending me a tip! So believe it or not it works almost exactly the same as the screen -r syntax.
The way you do it with Docker is do:
docker container ls -a
docker container attach yourcontainerid
You can detach again just like with screen by pressing Ctrl+A followed by Ctrl+D. Basically attaching and detaching is exactly the same as screen and works the same way. It’s just docker attach instead of screen -r.
Hopefully that helps!
Again, feel silly I didn’t figure that out! Getting the container id seems so obvious now! One thing I noticed. Ctrl+A followed by Ctrl+D didn’t detach, but looking around a bit, it seems that Ctrl+P followed by Ctrl+Q does it. Tested and that seemed to work for me.
A conceptual question. As I’m researching and learning about docker more, it seems like the ‘run’ command is the equivalent of ‘create’ and ‘start’ for a container. So once the container is created, is there a way to change the environment variables that were passed to it? Say I wanted to change the backup time or adjust MaxMemory. (Also, are there more environment variables than the ones specified above?)
I read a bit about the ‘commit’ command, but have to admit that I wasn’t quite sure how that worked.
The other idea I had is that I could stop the running container and remove it. (Thinking to remove at this stage so there aren’t errors when trying to bind the new container to the same port.) The data should still be preserved in the volume, right? Then I could create a new container using the same ‘run’ command, but this time with different environment variables. Since it’s still pointing to the same volume for the data, the properties and state of the world should be preserved, right? Is my logic sound here? Or is there a better way to do it?
Hey Josh,
Don’t feel silly at all, I’m always happy to answer stuff like that because now that you’ve learned it you can see that it seems so intuitive you forget that unless you know the “trick” people have no way of knowing that! It honestly helps me know what I need to improve on the documentation as well (and there are some improvements that need to be made for sure). I’d almost like to write a completely basic “Getting Started” guide that would actually overlap for all of the containers. It would explain all of these little details like that and I think this is something I’d like to publish by the end of the year or not too long after that.
The question about using the run command and the environment variables is another great question. The best way to change these is to actually stop the container. The container’s examples use the Restart=unless-stopped and basically the easiest way to think of it is that until it’s stopped it will “remember” the environment variables it started with. Once you stop it manually with docker stop if you start it again the environment variables will change to those and those will be the ones it remembers (even if you restart the computer). Basically manually stopping it and starting it with different flags is the proper way to change these (so that it will remember them and the changes will “stick”).
Now for your question about stopping the container and removing it. Yes, you can absolutely do this. You are correct that it will not impact your Docker volume. You have to use totally different commands to delete the Docker volume (definitely don’t do that, that’s in the docker volume set of commands instead of docker container) and it will remain safe on disk.
I frequently do this and delete the old versions of the containers off my disk and Docker cache. I can sometimes generate a dozen different instances developing a single update for example. They actually build up over time and become cluttered and a problem. Feel free to clean out the container instances themselves like you’re suggesting (docker container rm xxxxxx). This is totally safe.
In fact this might even be a easier/safer way to change the flags. If you just delete the old instance that is absolutely one way to make sure those flags are toast without any question. It will not impact the data at all when you start or pull a new instance and in fact it will run as if nothing even happened (but with the new flags you give it). Hopefully that clarifies!
Excellent! Thanks so much. Double for pushing me to finally explore docker. I haven’t been avoiding it per se, but never really had a good reason to give it a shot until now!
Hey Josh,
No problem at all! I actually resisted it for years and had the standalone version of these scripts (still exist). I really try to steer people toward Docker now but that is a complete 180 from where I used to be with it.
I always thought it sounded like an additional layer of unnecessary complexity and buzzword technology that I simply did not need. It was only until I finally tried porting the containers that I ran them using the Docker volume (with the benefits of being able to just delete it like we talked about) and have everyone running it always have the same up to date OpenJDK version that I realized I should have done it so much sooner.
I realized Docker completely solved all of the nightmares that plagued me for years (and still do) on the standalone versions and are a constant problem such as apt repositories not having the latest OpenJDK, differences in libraries between distros and lots of many other difficult problems to deal with universally with a single script like that.
The other thing that opened my eyes to why Docker was absolutely worth it was the giant Minecraft Java hacks that happened with log4j. That attack could have worked against someone running the standalone version of the scripts (although I never received a report of it happening to anyone running my scripts specifically).
It would do nothing against the Docker container. This is because Docker is running it’s own fake operating system (Ubuntu 22.10 right now) just for the container that only exists in RAM/memory. That is where the hacker would be inside if they ran the log4j exploit against your Docker containerized server.
They’d be inside the same “fake” containerized OS that the server is (which is where Java is also running, inside the container isolated from the rest of your system). They can’t access your real machine’s files as they are walled off from that. All of the changes they make to the fake OS in RAM are lost the second the container is restarted as it is just a copy of Ubuntu loaded at startup from a default image and doesn’t actually save any files that aren’t stored in the Docker volume.
This is what gives Docker so much extra security over running standalone. The security is within the containerization model itself basically and it’s quite powerful against threats both known and ones yet to even be discovered for this reason. It has nothing to do with any specific exploit. It protects you by simply isolating the things you are running from your real system (and each other). That way even if they do get hacked (for whatever reason) the hacker is just stuck in some fake containerized virtual OS that will discard anything they do the second it’s restarted.
Definitely let me know if you have any more questions come up, take care!
Yes, I remember wrestling with the Java version issues with the previous scripts. (You did an excellent job of making it as easy as possible for us users, though!)
For me it was having an aversion to virtual machines going back to work I did with Java in the early days and it was such a resource hog. The tax on resources put me off using anything that is a layer of abstraction between the process and the hardware, especially when resources are scarce. And I know docker isn’t quite the same thing, but the similarity made me skeptical, even as others were praising it. Which is dumb because I’ve used other virtual machines for others servers in the meantime and even run some servers in a RAM disk, so I can’t really explain why it took me so long to come around!
And all the security advantages and deployability across different distros and OSes is great. I didn’t even think about the log4j thing! Anyway, I’m on board now. Thanks again!
After changing the paper global & world defaults here:
/var/lib/docker/volumes/mcvol/_data/config
and relaunching with:
sudo docker run -it -v mcvol:/minecraft -p 25565:25565 -p 19132:19132/udp -p 19132:19132 05jchambers/legendary-minecraft-geyser-floodgate:latest
They reset to defaults on restart. Where do I need to be changing the configs to prevent them from being overwritten?
Hey Rob,
Welcome! That is a bit strange. That should not be happening due to this code:
# Copy config files if this is a brand new server
if [ ! -e "/minecraft/bukkit.yml" ]; then
cp /scripts/bukkit.yml /minecraft/bukkit.yml
fi
if [ ! -e "/minecraft/paper.yml" ]; then
cp /scripts/paper.yml /minecraft/paper.yml
fi
if [ ! -e "/minecraft/spigot.yml" ]; then
cp /scripts/spigot.yml /minecraft/spigot.yml
fi
if [ ! -e "/minecraft/server.properties" ]; then
cp /scripts/server.properties /minecraft/server.properties
fi
if [ ! -e "/minecraft/plugins/Geyser-Spigot/config.yml" ]; then
cp /scripts/config.yml /minecraft/plugins/Geyser-Spigot/config.yml
fi
Basically these only get copied if they don’t already exist. Are you seeing anything in your console when you start the server related to your config? The only reason I could think this may be happening is if you have an invalid configuration. If you’re trying to put an invalid option in there it would reset the config.
Can you check and see if you’re getting any output such as “config reset”?
Just a couple true/false options nothing invalid. No errors, or config resets in the console when it starts up. I was specifically changing Collisions, and Xray:
Under Global:
collisions:
enable-player-collisions: false
Under world:
anticheat:
anti-xray:
enabled: true
engine-mode: 2
I did notice your script paths referenced /minecraft/XConfigFiles
Where I am changing these options under ‘/var/lib/docker/volumes/mcvol/_data/config’ for the given docker volume you create.
The only minecraft folder I see, is in a random /proc/nnnn/minecraft folder presumably generated when the docker image launches. Interestingly if you change the configs over there it automagically changes them in the /var/lib…./_data/config.
either way they reset to defaults on restart, in my own ignorance I’m probably doing it wrong ( likely ) 🙂
This runs on a PC, under a DietPi(for x86) build I was testing. So there isn’t anything additional running, or wacky configs. Pretty basic.
I stop the server, ssh over to the var/lib/ folders change the two config files, and relaunch with the aforementioned sudo docker run -it -v mcvol:/minecraft ~~etc~~
That’s it.
Thanks for the response – appreciated .
Hey Rob,
The files are mounted at /minecraft basically if that makes sense. That is the mountpoint (and actually corresponds to /var/lib/docker/volumes/yourvolume/_data). You wouldn’t want to actually make the folder “minecraft” in there for example even though in the script that appears to be how it is working. That “minecraft” folder is actually your /var/lib/docker/volumes/yourvolume/_data folder. Think of it like a symbolic link/symlink to that folder on the filesystem that really just points to a different place.
Maybe we are overthinking this. Is the server running when you are making these changes? If so I would try editing the container files when the server is not running and then starting the container afterward. The /var/lib/docker/volumes/yourvolume/_data is the only actual real folder that exists. Everything else is an illusion and part of the image / only exists in memory. You will definitely want to make your changes to /var/lib/docker/volumes/yourvolume/_data with the container closed and then start and let’s see if that eliminates this behavior potentially here.
If this turns out to be the issue then I think what you are finding is the “fake” OS copy that is in memory (and the copies of the files that exist in there). This is how Docker works basically. It loads a base image of Ubuntu but it only exists in memory. It’s an illusion and all of the changes made will be lost the moment the container reboots.
That’s why none of your changes are persisting when you are editing the in-memory copies. This is part of why Docker is so secure. If someone hacked you through your Minecraft server they would be inside that same fake OS and nothing they changed/did would persist after restarting the container. It’s really, really hard for attackers to even understand what is happening (especially remotely) unless you understand containerization as well as Docker itself really well. I’m impressed you found these in the /proc filesystem as that’s quite cool/interesting. You can see why/how it’s all working here from your experience and that the changes are just lost each restart.
Can you try editing when the container is closed and then starting the container and see if this impacts the behavior? The file you would edit with it closed would theoretically be /var/lib/docker/volumes/yourvolume/_data/server.properties if you were editing server.properties. It would not surprise me if your changes are getting overwritten by the actively running copies potentially or it might be a safeguard to prevent external sources from modifying the files while the container is running that is resetting or ignoring your changes (meaning they are “locked” essentially by Docker security).
If not I would also recommend starting a new server with yourvolume2 or something like that and looking at the structure of the folders that it creates from scratch. There is no such real “minecraft” folder as it appears for sure. The “scripts” folder also only exists in memory because those are hardcoded into the image. It’s actually impossible to modify the /script copies as those are part of the image (other than the in-memory copies like you have been) but you should be able to modify the config files. Make sure that nothing has got switched around in the mean time and creating a new server will give you a reference to “fix” your old folders / config file locations to be where it expects them if that makes sense.
I’d imagine that if you use the in-game commands/plugins to set some of these settings you’ll find they stick. If that’s the case it would be another confirmation that the Docker in-memory copies are being protected (or aren’t where we think) when the container is running.
Think of it like file locking as an example. When the Docker container is running it “locks” those files and doesn’t expect (and won’t respect) changes made while that is the case (as it has been doing all of it’s /proc sorcery and everything it does under the hood to make it all work, who knows how many copies of it are floating around in memory). When the Docker container is closed this is released again (and the finalized version of the Docker volume gets written back to disk) and then we can actually modify the volume’s folder directly and it will respect the changes when the container is running again.
There are likely Docker settings and platform-specific situations that impact this as well potentially but it sounds to me like that’s what is happening. For example there are different ways of approaching storing data for containers like this such as “bind mounts” that actually do let you share files live with the host OS or even network/cloud storage. This type of volume though is not one of those and is one that is considered managed by Docker and I think that is why you are running into trouble here.
Let’s see if those get us any closer here!
Hi James,
Hope you’re well!
I decided to get my feet wet into Docker as you’ve come up with yet another fantastic way to spin up a Minecraft server. I have everything working – but the GeyserMC Bedrock plugin for Spigot. I had no issues exposing the port suggested on wiki.geysermc.org on the original Minecraft server script for Linux, but for the life of me I cannot get the port exposed through Docker even after many deep dives through their Wiki’s. Adding -p :/udp to your Docker run command doesn’t seem to work, even though it should… and the port is open on my TP-LINK router.
The issue isn’t urgent but any ideas would be much appreciated!
Cheers, Yui
Hey Yui,
This can definitely be a tricky configuration! I think you’re really close here most likely. The problem may actually be online-mode. I didn’t see any mention of Floodgate here but basically Floodgate makes it work with “online mode” servers that use Xbox Live authentication (this is the default).
Do you have online-mode set to true in your server.properties? You may be able to set it to false but then people won’t be able to use Xbox Live authentication (not a big deal for PC but definitely a bigger problem for console and other platforms). This may or may not be an issue for you.
How sure are you that the port is actually closed? Did you scan it with an external port checker tool or nmap? The reason I ask is that it sounds like you did everything right for the Docker configuration. You’d basically do it exactly the way I do it in the examples (I would forward both TCP and UDP to be safe). Remember that Java uses primarily TCP networking while Bedrock is almost exclusively UDP. This may be important if you haven’t configured your ports for both TCP and UDP for sure (including the “Java” ports).
Can you see if an external port checker tool like portchecker.co picks up the port as open? Let’s see what you find!
Hi James,
Thanks for your suggestion of forwarding both TCP and UDP ports. I think I was just compeltely went over my head and I blamed it on networking jank, lol. Geyser + Floodgate seems to be working perfectly now.
Strangely enough, even when I have a client connected through a console or PC Bedrock, the port still doesn’t show as open on sites like portchecker.co . Maybe this has to do with the way docker exposes to the host and not to the internet?
Anyways, thanks for the prompt help – you really are amazing! Take care 🙂
Cheers, Yui
Hey Yui,
No problem at all, I’m always impressed at how so many of you navigate these waters that haven’t necessarily ever even seen or worked with the Minecraft server at all before (or certainly not with these parts of it)! Most of my solutions I suggest are based on my interactions with others setting up similar things as well!
The portchecker.co issue is definitely interesting. I’m actually not 100% sure about this one but it could absolutely be related to Docker. Is this manifesting itself as when players look at the server on their client’s server list it doesn’t show any players online but then they can connect anyways and play? If it’s symptoms similar to that then it usually is involving the “ping” port I mentioned before which is typically TCP (and the only thing that is TCP in Bedrock just about). Some of this weirdness could be involving these protocol differences between the two versions. If so there is probably some kind of Geyser option that may influence this behavior.
Are people actually connecting over the internet or is it all LAN? If they aren’t connecting over the internet then it shouldn’t matter. If they are connecting over the internet and that is working then I’m guessing it’s because Bedrock is UDP and portchecker.co is probably only testing TCP (I don’t see an option on portchecker.co to change it to UDP so I doubt they support this). I’d think this would show as open theoretically but if you’re definitely observing it’s not and it’s still working then my guess is the explanation as to why involves UDP somehow or internals about how Geyser/Floodgate actually work (or potentially Docker influenced as well).
I should probably make one of these containers. I had to pay a $60 membership fee for the Docker Hub site and I have 3 more free slots for projects on my account before I have to upgrade it to a bigger one. Packaging this would probably really help a lot of people out and seems like a worthy use of one of those project/container slots. I also don’t think there’s anything else like it out there (or if there is it probably sucks).
I probably have a lot more competition for the regular container itself (this one) but people seem to not like the competing containers to this one very much either for various reasons as people had been asking me for YEARS to create this and port my standalone projects to Docker containers and I’m so glad that I finally listened as they’ve turned out really well.
I’m very glad you got it working, thanks for the great feedback and kind words, take care and enjoy!
This is exactly what I’ve been looking for! But there seams to be a problem, the docker container closes after a few seconds of running. Are you able to help? I am running it on an Unraid server that was recently set up. I am very happy to answer questions about my setup. It creates the following files in the volume before closing: bukkit.yml eula.txt paper.yml paperclip.jar server.properties spigot.yml
Hey Drew,
Can you share your output and see if there are any log files created in the “logs” folder? Those look like what normally get copied here from the defaults but I’m not seeing any of the server files like bedrock_server.
Some output should let us know a little bit more about what is going on!
No logs were created. I used {docker inspect } to look for the exit code, which turned out to be 1.
Ah, found the problem, it appears that I can’t set a ram limit grater than 4GB (4,096MB). I was attempting 16GB (16384MB). It’s not much of a worry as I have 64GB of ram. Though it would be nice to have the ability to do larger capacities.
Hey Drew,
That’s an interesting limitation! Your OS is 64 bit right? I’d imagine it is as the per-process limits for Linux processes are something more like 3GB if I am remembering correctly.
This may have to do with Docker settings as well. Thanks for posting what it was, that is not what was I was expecting! I will keep an eye on this and do some experimenting as this may be a Docker setting or something impacting this. Thanks for reporting it!
Happy to help any way possible, thanks for being so responsive. One last thing of note, I keep getting this error every minute in logs
:[io.netty.channel.epoll.EpollEventLoop] Unexpected exception in the selector loop.[0m
.channel.unix.Errors$NativeIoException: epoll_wait(..) failed: Function not implemented
Hey Drew,
Oh wow, that is a really interesting one! It looks like a Netty error and not one that I’ve seen before.
There is an option in server.properties called native_transport. I think it is true by default. Can you try setting it to false? If it’s set to false try setting it to true.
This basically toggles whether it uses your native Linux sockets or not. Something is strange about yours. Which architecture are your Unraid servers? I doubt it’s x86_64 or aarch64/arm but if it is then I’d be curious exactly which version of Linux is installed on there.
Very interesting findings, I look forward to seeing what you find!
Well that worked wonders. The error is gone and I was able to connect for the first time! My server is running two Xeon(R) CPU E5-2690 0 @ 2.90GHz and eight HPE 8GB DDR3 1600 MHz ECC RAM; On a HPE ProLiant DL380p Gen8 Server.
What is different is my command for making the server:
/usr/local/emhttp/plugins/dynamix.docker.manager/scripts/docker create --name='vasher_con_legendary' --net='bridge' --privileged=true -e TZ="America/Los_Angeles" -e HOST_OS="Unraid" -p '25565:25565/tcp' -p '25565:25565/udp' -p '25575:25575/tcp' -p '25575:25575/udp' -v '/mnt/user/Services/minecraftserver/vasher_con_legendary/':'/minecraft':'rw' '05jchambers/legendary-java-minecraft-paper'
Hey Drew,
Wow, that was a lucky guess for the record books that it was that one specific setting! My reasoning was that since these are all using the Docker base image they all have the exact same dependencies so that didn’t make any sense. It could have been Docker configuration related but I had a hunch that this may be some kind of Netty sockets/networking platform related issue.
They actually have this specific setting for occasions like this as it is known that the “native” networking can create problems on some platforms. On other platforms the non-native “Netty” networking can actually create problems. That’s why I said to toggle it from whatever it was to the other one as it’s more about switching it to the opposite mode of what it’s using when you get an issue like this as in some cases it just makes it “go away”.
It’s not extremely common but the server world is exactly where I would expect to see it on more exotic/fancy setups/architectures. I was going to say that this could be permissions related but it looks like you are launching the container with the –privileged flag which I would think would take care of any socket related permissions. The error did say not implemented though so it’s possible that Netty is just missing something for that networking stack whether it’s related to the architecture or the OS.
If it’s working well with the flag toggled I probably would leave it unless it’s causing some other kind of problem. There’s nothing wrong with using either networking stack and some work better than others on certain platforms.
Thanks for providing such detailed information!
Thank you very much for the help! You have a good day.
No problem at all, take care and enjoy!
Unraid is Slackware-based Linux distribution.
Dumb question, but with the Docker container, how and where can one specify the MaxMemory environment variable?
EDIT: Actually, to answer my own question: docker run -e MaxMemory=
Hey Will,
That is not a dumb question at all. You are actually the first person that I have confirmed actually having used this flag/parameter!
It should come in pretty handy on low memory devices. The way it is coded now it does have a lower limit (the -Xms parameter) of something like 300-400 MB which could theoretically be squeezed down to the absolute minimum but it’s going to be tough with less than that. The reality of Java Minecraft is there’s a certain amount of overhead/bulk from the Java Virtual Machine and the way the game is designed/programmed so I would call this a reasonable floor (around 400 MB or so acknowledging there’s a little bit of breathing room down to the mid 300 range).
Still, especially with multiple instances this lets you budget your memory much more appropriately (or even just to keep it from overwhelming the entire machine’s memory usage). Definitely feel free to stop by if anything else comes up. The container is pretty much brand new and I’m happy to answer any questions about it as we are basically writing the documentation for this with our conversations (some of which I’ll formalize right into the docs depending on what people ask / have trouble with).
Take care!
Thanks for the reply, and great job on the Docker work. Super easy to use. I was only asking as I am running both your Bedrock and Java images and I want to limit (even on a 8GiB RaspberryPi 4) the Java instance. Java being Java!
Hey Will,
That is totally understandable. I do the same thing for sure!