How to Run a Minecraft Server: Multiple Approaches
Table of contents
Background
In An intro to Minecraft mods, I outline my reasons for choosing the Fabric framework over Forge. Continuing with that same reasoning, this post will be outlining multiple approaches for running a Minecraft server using Fabric (although at a high level, the concepts should still apply to Forge).
You may want to do some research beforehand to determine which mods you want to run on your server, since Fabric mods will only run on a Fabric server, and Forge mods will only run on a Forge server.
If you're not sure what a Minecraft server is, you can simply think of it as a place to house Minecraft mods. To get a better idea of how a server fits into modding in general, read the Fabric Server section of the aforementioned post.
Overview
You might be wondering where the "multiple approaches" bit comes in, since we are only focusing on Fabric. We'll be covering the following ways to host a Fabric server:
local machine
Windows
Linux/MacOS
VPS
Regardless of where the server is hosted, it can be invoked (or "spun up") in multiple ways:
raw commands in a shell
running a script file
running the server in a Docker container
Choosing a server location
In the Development Environment section of the first post, we covered the fact that your development environment matters, in terms of which computer you use. Conversely, the computer you choose to use as your server doesn't matter at all -- so long as it has the proper version of Java and enough RAM to run Minecraft.
Separate machine vs local machine
Speaking of RAM, that is one reason you might choose to run your server on a separate computer; the default amount of RAM allocated to the Minecraft server is 2GB, which your computer may not have to spare.
Even if RAM isn't an issue for you, you may still want a separate machine for other reasons -- a big one being availability; if you want your server to be accessible round-the-clock, you likely want a separate machine. Otherwise, your server goes down if your computer shuts off or loses network connectivity.
On the other hand, if your server needs are more casual and constant availability isn't a concern, then running the server locally (from your main machine) might be enough for you.
A new computer isn't necessary
You also might be thinking, "I can't afford to buy another computer to run a server on". If that's the case, you could explore these options:
using an old computer
buying a Raspberry Pi (can be found for less than $100)
using a Virtual Private Server (monthly cost depending on usage and server specs)
Docker
Docker might be a good option if you want to be able to reuse the same server configuration on multiple devices, or if you don't want to alter an existing Java configuration. Here are a few things to note about running a server in a Docker container:
it will still consume RAM on whatever computer is running the container
no Java configuration is required
- Java is automatically installed in the container
Docker containers don't "care" where they are run from
you can bundle the container's configuration into a file on your local machine
that same file can be used to run an identical container on a separate machine (regardless of that machine's OS)
Docker can run from
your local machine
another physical machine
an old laptop
a Raspberry Pi
a Virtual Private Server
...or any other hardware that supports Docker.
Here's an example of when you might want to use Docker:
You are testing out a Minecraft server configuration with multiple mods, and multiple custom game settings. You're testing this configuration out on your laptop, but you want to be able to recreate the configuration on another machine without having to install each mod and enable each custom game setting all over again.
This is a great reason to use Docker. At a high level, the configuration would look something like this:
find and download a Docker image that is preconfigured for running a Minecraft server
- think of the image as the blueprint for the container
use the image to run a container
the image's blueprint is used to construct and "run" the container
think of a container as a self-contained environment for which to run software
load the mods you want to test into the container via a volume
a volume is a way to link file storage between the host machine and the container
- the host machine is the computer that Docker is installed on
the volume is where the
/mods
folder will live
once you've decided on the game settings and mods you want to use, put instructions on how the container should be run in a
docker-compose.yml
fileDocker Compose files describe the specifics of how the server container be run, such as
the version of Minecraft to use
which user(s) to grant operator permissions
game settings (max players, spawn point, mobs, etc.)
We'll illustrate these concepts with examples later in the Running a Server with Docker section.
Running a Server
Java Prerequisite
If you plan on running a server on a machine other than your own, make sure to install Java on that machine, following the instructions provided by Fabric.
If you're using Docker, make sure the image you're using has the correct version of Java. The image likely has a way to specify a Java version with a tag for the image.
If you're using Linux for your server, the instructions Fabric provides for setting up Java are fairly basic. For more detailed instructions, see Installing Java on Ubuntu.
Loading a mod onto the server
For mods to work on the server, we need to make sure that our Minecraft client has those same mods. More specifically, that means:
you have an installation of the Fabric launcher (client) whose version matches the Minecraft version of your server
- this is the launcher you select when you open the Minecraft application on your computer
the
/mods
folder for your Fabric launcher installation contains:the
.jar
file for the proper version of the Fabric APIa
.jar
file for each mod
the
/mods
folder for your Fabric server must contain the same.jar
files as the/mods
folder in the Fabric launcher
In other words, the /mods
folder within your Fabric launcher client should have the same contents as the /mods
folder on your Fabric server. If you want to read more about the reasoning, check out the Fabric docs on this topic.
once the
/mods
folders match on the client and server, launch the serveronce the server is running, grant
op
(operator) permissions to necessary player(s)connect to the server using the Connecting to your server instructions below
verify that you can use the mod
Approach-specific instructions are detailed below.
Running a Server on Linux/MacOS
This is perhaps the most accessible option since it can be run from:
a machine running Linux
Raspberry Pi
VPS
a machine running MacOS
Here we'll follow instructions from the Fabric wiki, and walk through them as we go.
If you've been following along, you should already have Java installed. The next step is to go to the server download page and download the relevant version:
# make a directory for the server
mkdir fabric-server
cd fabric-server
# download the file to our fabric-server directory
curl -OJ https://meta.fabricmc.net/v2/versions/loader/1.19.4/0.14.19/0.11.2/server/jar
# confirm the download worked
ls
# output
fabric-server-mc.1.19.4-loader.0.14.19-launcher.0.11.2.jar
Now that we have the server's .jar
file downloaded, we can use the command supplied on the download page to launch the server using that .jar
file:
# launch the server, allocating 2GB RAM
java -Xmx2G -jar fabric-server-mc.1.19.4-loader.0.14.19-launcher.0.11.2.jar nogui
We get an error, which is expected because we need to accept the EULA:
[21:10:21] [main/ERROR]: Failed to load properties from file: server.properties
[21:10:21] [main/WARN]: Failed to load eula.txt
[21:10:21] [main/INFO]: You need to agree to the EULA in order to run the server. Go to eula.txt for more info.
If we inspect the contents of our server folder, we can see that files and directories have been generated as a result of attempting running the server. Among these is the file eula.txt
:
# in fabric-server directory
ls -la # press enter
# output
drwxr-xr-x 4 idev idev 4096 Jun 12 21:10 .fabric
-rw-r--r-- 1 idev idev 158 Jun 12 21:10 eula.txt
-rw-r--r-- 1 idev idev 155095 Jun 12 21:09 fabric-server-mc.1.19.4-loader.0.14.19-launcher.0.11.2.jar
drwxr-xr-x 8 idev idev 4096 Jun 12 21:10 libraries
drwxr-xr-x 2 idev idev 4096 Jun 12 21:10 logs
drwxr-xr-x 2 idev idev 4096 Jun 12 21:10 mods
-rw-r--r-- 1 idev idev 1272 Jun 12 21:10 server.properties
drwxr-xr-x 3 idev idev 4096 Jun 12 21:10 versions
Now we can open that file with our preferred text editor and change false
to true
:
vim eula.txt
# inside eula.txt
eula=true
# save and exit eula.txt
Now that we've agreed to the EULA, we can re-run the command to launch the server:
# launch the server, allocating 2GB RAM
java -Xmx2G -jar fabric-server-mc.1.19.4-loader.0.14.19-launcher.0.11.2.jar nogui
The server starts up this time with no errors:
[21:15:16] [Worker-Main-2/INFO]: Preparing spawn area: 91%
[21:15:16] [Worker-Main-2/INFO]: Preparing spawn area: 94%
[21:15:17] [Worker-Main-5/INFO]: Preparing spawn area: 97%
[21:15:17] [Server thread/INFO]: Time elapsed: 28858 ms
[21:15:17] [Server thread/INFO]: Done (35.063s)! For help, type "help"
Now that the server is running, we can click into the terminal and type op your_player_name
[14:24:08] [Server thread/INFO]: Time elapsed: 8357 ms
[14:24:08] [Server thread/INFO]: Done (10.491s)! For help, type "help"
op awesomeminecraftplayer42023
[14:25:01] [Server thread/INFO]: Made maddoxchunk a server operator
Running a Server on Windows
The Fabric instructions do a pretty good job of walking through this one, but we'll go through the steps here anyway (starting with STEP 3: Install Fabric in the Server Folder):
go here and click the 'download for Windows' button
run the file
select the 'Server' tab
select the version and install the location
the Minecraft version should match the Minecraft version of the mod(s) you want to use
note that this file location has nothing to do with your installation of Minecraft
press 'Install'
click 'Download server jar'
click 'Generate'
open the folder location where you saved the server to
run the
start.bat
fileyou'll get an error about the EULA
close the terminal
open
eula.txt
in the server folder that has thestart.bat
filechange
false
totrue
ineula.txt
save and exit the file
run
start.bat
againclick into the terminal with the server running and type
op your_player_name
to grant operator permissions
Running a Server with Docker
I won't go over installing Docker, since their official docs should be enough to get you there.
It's worth mentioning that once you have Docker installed, the steps below will work the same (more or less), regardless of your operating system.
Run a Vanilla Minecraft server in a container
Once you've got Docker installed, it's time to download and run a Minecraft server image.
start by going to the documentation for the Docker image we're using
run the listed command
docker run -d -it -p 25565:25565 -e EULA=TRUE itzg/minecraft-server
this runs the container in the background so that our terminal is free to run other commands
confirm the container is running with
docker ps
copy the
CONTAINER ID
from thedocker ps
commandrun
docker stop <CONTAINER ID>
to stop the containerrun
docker ps
again to confirm the container is not running
Run a Fabric Minecraft server in a container
The docker
command above allowed us to run a "vanilla" Minecraft server. However, we are interested in running a Fabric server, so we consult the Types and platforms documentation.
From here we can select 'Fabric' from the menu on the left. We can see a command that instructs us on how to run a Fabric server by using the -e TYPE=FABRIC
flag. However, there is something else that's different about this command: it's mounting a volume with -v /path/on/host:/data
. Before we run this command, we need to set up that directory on our host machine (the one running Docker).
Mounting a data directory
If we head to the Data directory documentation, we get some instructions on how to do this.
Let's try running a container with an attached data volume, using the supplied command from the Fabric section of the image docs:
mkdir mc-data
docker run -d -v ./mc-data:/data \
-e TYPE=FABRIC \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
Okay, so we've started a container and mounted the volume, but how do we use it?
It's a bit difficult to picture right now, since we're running the container as a background process with the -d
flag. Let's try running it again without that flag and see what happens:
# first, remove/stop the container
docker rm mc
# run the same command without the -d flag
docker run -v ./mc-data:/data \
-e TYPE=FABRIC \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
# output
[init] Running as uid=1000 gid=1000 with /data as 'drwxrwxr-x 2 1000 1000 4096 Jun 15 11:12 /data'
... # (more output)
[init] ERROR: version lookup failed:
This isn't an error with the volume. We would get the same error if we ran the command without the -v flag
. The only reason we didn't see the error before is that we ran the process in the background, so the output wasn't visible.
This error is because we need to specify a Fabric/Minecraft version for the container to run.
Let's try it again, this time using the appropriate flags to specify the version:
docker rm mc
docker run -v ./mc-data:/data \
-e TYPE=FABRIC \
-e VERSION=1.19.4 \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
We still get an error, but this time it's different:
[init] ERROR failed to install Fabric launcher from 1.19.4, LATEST, LATEST
This is yet another misleading error message. In my case, it was happening due to an issue with WSL2. The issue is resolved by deleting the ~/.docker/config.json
file.
If you encountered the error above, go ahead and delete the config.json
file, then run the commands again to make sure it works:
docker rm mc
docker run -v ./mc-data:/data \
-e TYPE=FABRIC \
-e VERSION=1.19.4 \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
Now that we know we can get the server running, it's time to add our mod.
Loading mods onto the server
Looking again at the Data directory documentation, we can see that the /mods
folder lives inside the /data
directory, which we have created as mc-data
on our host machine.
Speaking of the data directory, if we inspect the contents of mc-data
, we can see that the folder is no longer empty since we have successfully run the server:
# stop the server if it's still running using CTRL + C
ls mc-data
#output
banned-ips.json fabric-server-mc.1.19.4-loader.0.14.21-launcher.0.11.2.jar ops.json whitelist.json
banned-players.json libraries server.properties world
crash-reports logs usercache.json
eula.txt mods versions
Recall from Loading a mod onto the server that the /mods
folder on our server should match the /mods
folder in our Fabric launcher installation. As such, we copy the contents of that folder to our data directory for the container
# copy the contents of the Fabric
# launcher's /mods folder into the mc-data/mods folder
cp -a /path/to/fabric/launcher/mods .mc-data/mods
Now we are ready to run our server again:
docker rm mc
docker run -v ./mc-data:/data \
-e TYPE=FABRIC \
-e VERSION=1.19.4 \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
Go ahead and connect to your server using the instructions below.
The game loads up when we connect, but we have a problem -- we aren't able to run commands. Normally, we could just go to our terminal and op
our player, but things work a bit differently with Docker. Since we are running the server in a container, we don't have direct access to the terminal like we do when we run the server directly in the operating system.
So how do we issue commands to our Docker container? Enter RCON
.
RCON
RCON
is short for Remote Control, and allows Minecraft commands to be issued remotely.
Okay, but... how do we use it?
Thankfully, the Docker image we're using includes rcon-cli
. Let's see it in action:
# stop the container (if running)
docker stop mc
# start the container again
docker start mc
Before we can run rcon-cli
, we need to wait for server to completely load, since RCON
does not become enabled until that point. When you see the following message in the terminal, you're ready to use rcon-cli
:
[03:28:23] [Server thread/INFO]: Done (8.096s)! For help, type "help"
[03:28:23] [Server thread/INFO]: Starting remote control listener
[03:28:23] [Server thread/INFO]: Thread RCON Listener started
[03:28:23] [Server thread/INFO]: RCON running on 0.0.0.0:25575
Once the RCON
service has started, we can open a new terminal window and use rcon-cli
:
# replace your_player_name with the actual name of your player
docker exec mc rcon-cli op your_player_name
# output
Made your_player_name a server operator
Now that you are an operator, you can use commands in Minecraft. Go ahead and use the appropriate command(s) to test out your mod (if applicable).
Docker Compose
When I originally explained the use cases for Docker, a big selling point was the portability, and the ability to reuse configurations. So far, we haven't seen how Docker can achieve that. We ran a bunch of commands, and even hit some errors in the process.
How can a workflow like that be reusable?
The answer is that it can't, and that's where Docker Compose comes into play.
Now that we have a working configuration, we can package that configuration into a docker-compose.yml
file so that we don't have to remember the commands. Instead, we can just point Docker to the docker-compose.yml
file.
Let's go through the instructions:
first install Docker Compose by following the instructions here.
make a new directory and change into it
mkdir mc-compose cd mc-compose
create a
docker-compose.yml
file and put the following in it
note that the file below is slightly different from the file linked in the documentation (we added the
VERSION
andTYPE
environment variables)also note that indentation matters in a
.yml
file
version: "3.8" services: mc: image: itzg/minecraft-server tty: true stdin_open: true ports: - "25565:25565" environment: EULA: "TRUE" VERSION: "1.19.4" TYPE: "FABRIC" volumes: # attach the relative directory 'data' to the container's /data path - ./data:/data
Using an .env
file
To make things even more reusable, we can use an .env
file located in the same folder as our docker-compose.yml
file.
vim .env
# .env
VERSION=1.19.4
SERVER_TYPE=FABRIC
DATA_DIR=./mc-data
Now we can update our docker-compose.yml
:
# docker-compose.yml
version: "3.8"
services:
mc:
image: itzg/minecraft-server
container_name: mc
tty: true
stdin_open: true
ports:
- "25565:25565"
environment:
EULA: "TRUE"
VERSION: "${VERSION}"
TYPE: "${SERVER_TYPE}"
volumes:
# attach the relative directory 'data' to the container's /data path
- "${DATA_DIR}:/data"
Run the server with docker compose up
to make sure the new config works.
Automating RCON
Remember how we had to wait for the server to spin up before we could use rcon-cli
? That was kind of annoying. It would be nice if there were a way to automate this.
Thankfully, someone made a pull request, and some new commands were added to the image. These commands allow rcon-cli
to run automatically, either when the server starts, or when the game client connects to the server.
We'll keep things simple and just automate the provisioning of operator permissions. In the docker-compose.yml
file below, you'll notice a new RCON_CMDS_STARTUP
property under environment
:
# docker-compose.yml
version: "3.8"
services:
mc:
image: itzg/minecraft-server
container_name: mc
tty: true
stdin_open: true
ports:
- "25565:25565"
environment:
EULA: "TRUE"
VERSION: "${VERSION}"
TYPE: "${SERVER_TYPE}"
RCON_CMDS_STARTUP: |-
/op your_username_goes_here
volumes:
# attach the relative directory 'data' to the container's /data path
- "${DATA_DIR}:/data"
Go ahead and run the container with docker compose up
. If you get an error like Additional property RCON_CMDS_STARTUP is not allowed
, the issue is likely that something isn't indented properly. Go back into the file and make sure the new command is indented one level in from environment
.
But remember, we want this docker-compose.yml
file to be as reusable as possible. Once it's complete, any changes that we need to make to the configuration should be done via the .env
file. Let's put our player name into the .env
file:
vim .env
# .env
VERSION=1.19.4
SERVER_TYPE=FABRIC
DATA_DIR=/mnt/c/Users/iDev/fabric-1.19.4-client/
OP_PLAYER=your_username_goes_here
Now we can adjust our docker-compose.yml
file accordingly:
# docker-compose.yml
version: "3.8"
services:
mc:
image: itzg/minecraft-server
container_name: mc
tty: true
stdin_open: true
ports:
- "25565:25565"
environment:
EULA: "TRUE"
VERSION: "${VERSION}"
TYPE: "${SERVER_TYPE}"
RCON_CMDS_STARTUP: |-
/op ${OP_PLAYER} # note that there are no quotes in this command
volumes:
# attach the relative directory 'data' to the container's /data path
- "${DATA_DIR}:/data"
Note that the syntax is slightly different for this command, compared to the others. There are no quotes around the command. Using quotes will cause an error.
It's also possible to specify more than one player, but the error handling still needs to be worked out. This means that if you make a typo in one player's name, or one of the players doesn't exist, the entire command will fail.
If you're interested in experimenting with this, the syntax for specifying multiple players is as follows:
# .env
# OP_PLAYERS=player1:player2:player3 # this will fail; no valid players
OP_PLAYERS=your_user_name_goes_here:player2 # this will fail; at least one invalid player
Reusing a Docker config
So far, we've seen how using Docker Compose can save us from having to type long complicated commands. We can take it a step further and place our docker-compose.yml
file on another machine so that it can run the same container with the same configuration.
First things first, we'll copy the file from our local machine over to a Virtual Private Server that has Docker installed. Also note that a user named mc-admin
has already been created on the VPS:
# in mc-compose folder on local machine
# make sure to add the '/' at the end of vps-mc!
rsync -a ./docker-compose.yml digitalocean.minecraft:/home/mc-admin/vps-mc/
If you're unfamiliar with rsync
, here is what the command above does:
takes the
docker-compose.yml
file in our current directory on the local machineuses SSH behind the scenes to log into the VPS (
digitalocean.minecraft
)an SSH config file obscures the username and IP of the Digital Ocean VPS we're logging into
to execute without a SSH config file:
- replace
digitalocean.minecraft
withuser@ip.address.of.vps
- replace
creates a directory
vps-mc/
on the VPS, under the existingmc-admin
user's/home
directorythis is why the
/
is important at the end of the commandwithout the
/
,vps-mc
will be created as a file instead of a folder
places the
docker-compose.yml
file in the/home/mc-admin/vps-mc
directory of the VPS
Since I've previously configured ssh
, I don't need to supply a username and password when I run the command above.
If you haven't configured ssh
, it would look more like this:
# we need to specify username@server
rsync -a ./docker-compose.yml mc-admin@docker.vps.ip:/home/mc-admin/vps-mc/
If you want to learn how to simply your ssh
flow like I have, make sure to check out my Managing SSH Keys post.
Before we run the server, we need to transfer over a few more files and folders:
rsync ./.env digitalocean.minecraft:/home/mc-admin/vps-mc/
rsync -a --mkpath ./mc-data/mods/ digitalocean.minecraft:/home/mc-admin/vps-mc/mc-data/mods/
Now we're ready to run the server on the VPS:
ssh digitalocean.minecraft
# now in vps
cd vps-mc
docker compose up
# output
permission denied while trying to connect to the Docker daemon socket at
unix:///var/run/docker.sock:
Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json?all=1&filters=%7B%22label%22%3A%7B%22com.docker.compose.config-hash%22%3Atrue%2C%22com.docker.compose.project%3Dpi-mc%22%3Atrue%7D%7D":
dial unix /var/run/docker.sock: connect: permission denied
Okay, so we got a permissions error. No biggie, this is a pretty common thing to run into with Docker. I had already configured it on my local machine, but we need to set it up on the VPS.
Enabling rootless Docker
Yes, prefixing Docker Compose command with sudo
would fix our issue, but running Docker as root goes against best practices, so we're going to do it the proper way:
You can follow along with this step by viewing the Docker documentation.
first we'll start by updating our package manager
sudo apt-get update && sudo apt-get upgrade
next we'll install the package that Docker tells us we need
sudo apt-get install uidmap
follow the instructions under Distribution-specific hint
sudo apt-get install -y dbus-user-session
the package is already installed, so no need to log out/back in
follow the instructions under the Install section
dockerd-rootless-setuptool.sh install
receive
command not found
errorcontinue following instructions:
sudo apt-get install -y docker-ce-rootless-extras
received another error:
Unable to locate package docker-ce-rootless-extras
switch to the Without Packages tab and run
curl -fsSL https://get.docker.com/rootless | sh
The installation was successful, but we have some output to read through:
# output from the install script
[INFO] Installed docker.service successfully.
[INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service`
[INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger sharif`
[INFO] Creating CLI context "rootless"
Successfully created context "rootless"
[INFO] Using CLI context "rootless"
Current context is now "rootless"
[INFO] Make sure the following environment variable(s) are set (or add them to ~/.bashrc):
export PATH=/usr/bin:$PATH
[INFO] Some applications may require the following environment variable too:
export DOCKER_HOST=unix:///run/user/1000/docker.sock
Going through the sections of output one by one:
since I want Docker to run when the system starts, I run the provided command
sudo loginctl enable-linger sharif
I need to set both the
PATH
andDOCKER_HOST
environment variablesI'm using
zsh
and notbash
, so environment variables are set differentlyI refer to a previous blog post of mine to set the environment variables at the profile level
Now we should be able to run docker compose up
from our vps-mc
directory again without getting a permissions error.
Connecting to your server
On our computer with Minecraft installed, we can open our Minecraft Launcher, and confirm that we can connect to the server.
select the Fabric Launcher installation
- make sure the version of Minecraft for the launcher aligns with the version of Minecraft for your server
when the game loads, select 'Multiplayer'
accept the warning about third-party online play
select 'Direct Connection'
depending on how you set up your server, you'll need to enter the hostname accordingly
local server:
localhost:25565
VPS:
<IP of your server>:25565
click 'Join Server'
Resources
Subscribe to my newsletter
Read articles from Sharif Elkassed directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by