Minecraft

From Sea of Fate
Jump to navigationJump to search

Introduction

We are to have some Minecraft servers on the Home Lab'. The general setup will be to have a Velocity server in front several Minecraft host Virtual Machines. Velocity works in a similar way to a Nginx reverse proxy whereby Pfsense forwards all Minecraft traffic to the Velocity server including the SNI and Velocity redirects traffic to the required hostname based on the DNS name. Cloudflare does not reverse proxy Minecraft traffic on the free tier and as we do not want to have to deal with random bots from the east so we will not leave the port open on the edge or Pfsense to random bots with port scanners. So we will use grey cloud at Cloudflare but DNS will point to a service like TCPShield and our firewalls only accept Minecraft traffic from their IP addresses and Velocity will only accept named servers and drop any unknown DNS names.

Installation

The installation will be in some distinct stages to enable each step to be proved to be working before proceeding to the next stage. First we setup a simple vanilla Minecraft server and set the firewall to port forward to it directly. Once that is proven to be working we will setup a Velocity server that will receive all 25565 traffic and forward it to the working Minecraft host. The next phase after the first host is getting traffic forwarded is to setup a second host and make sure velocity can forward to each, included in this step will be hardening the Velocity server with whatever security measures that it has available. When we are sure that Velocity is working properly we can work on the remote access stage, where we use TCPShield to proxy the service and have Cloudflare DNS only names setup with cherry.seaoffate.net and apple.seaoffate.net etc. From this point forward any new Minecraft servers will simply follow the same setup procedure.

The First Minecraft Host Configuration

The first Minecraft host needs to have enough resources to run the JVM and the server but as it just a vanilla server the specification does not need to be excessive. The table shows the highlights.

Item Value Notes
CPU 2
RAM 4GB
Swap 16gb Additional disk allocated from Lexar SSD
Storage 96GB Initially set at 32gb
Base OS Debian 13.3 Server version
Hostname Cherry
IP Address 192.168.100.30

Hardware Configuration

The Cherry host was created as a clone of the Debian template and then the basic specifications were improved so we will need to configure these extra items in the OS. First we need to identify the harddrive to use as the swap file

lsblk

The result is likely to show that the disk is likely to be /dev/sdb so we can set the swap space and enable it with

sudo mkswap /dev/sdb
sudo swapon /dev/sdb

To make the swap file persistent we edit the fstab

sudo nano /etc/fstab

Add the line:

/dev/sdb none swap sw 0 0

and remove or comment out the line that refers to

/dev/sda3

Before the storage sda main partition can be expanded to the full 96GB we have to remove the swap that is in the way so disable the existing swap with

sudo swapoff /dev/sda3

Open the disk utility to modify sda

sudo fdisk /dev/sda

Delete the swap partition with the option d, then type 3 to delete partition 3, then w to save and exit. The next thing to do is expand the Primary Root Partition so open fdisk again:

sudo fdisk /dev/sda

Delete the root partition:

  • Type d (Delete)
  • Type 2 (this only deletes the table entry, not the data).
  • Type n (Create a new partition)
  • Type p (Primary Partition)
  • Type 2 (For Partition number 2)
  • Type enter (Use default values for start sector)
  • Type enter (Use default values for end sectors to fill the 96GB)
  • CRITICAL: When asked if you want to remove the signature, type N.
  • Type w (Save and exit)

To finalize Storage reboot to refresh the kernel partition table:

sudo systemctl reboot

When the VM reboots expand the filesystem into the new space:

sudo resize2fs /dev/sda2

We can verify the new swap and new sda size with

df -h

Now that the hardware is setup and configured we can proceed to the software installation

Software Installation

The software installation consists of updates, install the JVM and then install the Minecraft server. So to start as we do on most hosts with updates

sudo apt update
sudo apt upgrade

Install Necessary Utilities:

sudo apt install htop screen wget curl -y

Install Java 25:

sudo apt install openjdk-25-jre-headless -y

Verify Java Installation (Ensure it reports OpenJDK 25)

java -version 

Now we install the Minecraft server

Create the Server Directory:

mkdir ~/minecraft_server && cd ~/minecraft_server

Download the Server Software:

wget -O server.jar [1](https://piston-data.mojang.com/v1/objects/97ccd4c0ed3f81bbb7bfacddd1090b0c56f9bc51/server.jar)

Assuming the file downloaded we need an initial run to generate the file:

java -Xms1G -Xmx1G -jar server.jar nogui

When the file is first created it will not run until we Accept the EULA with the command:

sed -i 's/eula=false/eula=true/' eula.txt

We can create the Start Script:

nano start.sh

Paste in the following #!/bin/bash while true do echo "--- Starting Minecraft Server ---" java -Xms3G -Xmx3G \ --enable-native-access=ALL-UNNAMED \ -XX:+UseG1GC \ -XX:MaxGCPauseMillis=200 \ -XX:+UnlockExperimentalVMOptions \ -XX:+DisableExplicitGC \ -XX:+AlwaysPreTouch \ -jar server.jar nogui echo "--- Server stopped. Restarting in 5 seconds (Ctrl+C to cancel) ---" sleep 5 done Set the script to execute with

chmod +x start.sh

We can start the server with

./start.sh

Note we can type the command stop in the terminal and the server will save the world and stop it for 5 seconds during the 5 seconds, if we type ctrl+c it will end the script or if we just leave it the server will restart.

Enable External Access

We will need to access the server from outside world so we should forward the Minecraft port 25565 to the IP address of cherry. To make the port forward rules in Pfsense easier to understand we add an alias for cherry's IP address and a port alias for 25565. We add a port forward rule to Pfsense that says source IP 192.168.0.0/16 and any port, destination this firewall (self) Destination port Minecraft_standard, redirect IP_cherry port Minecraft_standard.

Testing

With this configuration loading a Minecraft client and setting the destination server to the WAN port IP address it will connect to the cherry host.

As part of the wider LAN setup we added a Adguard LXC to manage DNS. Part of the Adguard configuration was made to avoid the hairpin network access so a DNS redirect was made to forward *.seaoffate.net to Pfsense WAN and as the default domain name was set to seaoffate.net. So now when we have a destination of cherry Adguard will translate the hostname to cherry.seaoffate.net and redirect it to Pfsense, Pfsense will then forward to the relevant server. If that does not work as expected the next test would be to set the destination to cherry.seaoffate.net which should be redirected by Adguard.

Velocity Installation

The Velocity server VM does not need to be especially high because all it needs to do is accept connections and forward them on to the relevant host and any associated functions like handle logon, bans and etc. Unlike the cherry host that we just setup the base specification from the Debian template needs to be cut down a bit and does not need a extra swap file or anything special.

Item Value Notes
CPU 1
RAM 1GB
Storage 32GB
Base OS Debian 13.3 Server version
Hostname Vangueria
IP Address 192.168.100.29

Software Installation

As there is no additions to the VM's specification there is no hardware to configure so we can get straight to the software installation. So the well known update/upgrade and the packages can be installed with

sudo apt update && sudo apt upgrade -y
sudo apt install -y openjdk-25-jre-headless htop screen wget jq curl

Once the dependencies are installed, we create a dedicated application directory and use an automated script to identify the most recent build of Velocity 3.4.0. This ensures we are not relying on hardcoded links that may expire.

mkdir ~/velocity && cd ~/velocity
export PROJECT="velocity"
export VERSION="3.4.0-SNAPSHOT"
export LATEST_BUILD=$(curl -s https://api.papermc.io/v2/projects/${PROJECT}/versions/${VERSION} | jq '.builds[-1]')
wget -O ~/velocity/velocity.jar "https://api.papermc.io/v2/projects/${PROJECT}/versions/${VERSION}/builds/${LATEST_BUILD}/downloads/${PROJECT}-${VERSION}-${LATEST_BUILD}.jar"

The initial boot of Velocity is performed to generate the necessary configuration files. We launch it with a 512MB heap size and then shut it down gracefully using the end command once the prompt appears.

java -Xms512M -Xmx512M -jar velocity.jar

Proxy Configuration and Routing

The primary configuration for the proxy is handled within the velocity.toml file. This file dictates how the proxy listens for incoming traffic and how it maps domain names to internal IP addresses. We edit this file to ensure the proxy is listening on all interfaces and that it is using the modern forwarding protocol.

nano ~/velocity/velocity.toml

Modify these specific lines:

  • Bind Address: bind = "0.0.0.0:25565" (Allows it to hear traffic from pfSense).
  • Forwarding Mode: player-info-forwarding-mode = "modern" (This is the most secure protocol for 2026).
  • ping-passthrough should be set to ALL. This is to ensure the server list on the Minecraft client correctly displays the status and version of the backend servers
  • Server List: Scroll down to the [servers] section:
[servers]
 cherry = "192.168.100.30:25565"
 apple = "192.168.100.35:25565"

 [servers]
 try = [
    "cherry"
 ]
  • Forced Hosts: This tells the proxy which server to pick based on the URL the player typed:
[forced-hosts]
 "cherry.seaoffate.net" = ["cherry"]
 "apple.seaoffate.net" = ["apple"]

Save and close the file. next we need a start.sh file for Velocity

nano ~/velocity/start.sh

copy the following into the file #!/bin/bash while true do echo "--- Starting Vangueria Proxy ---" java -Xms512M -Xmx512M \ -XX:+UseG1GC \ -XX:MaxGCPauseMillis=200 \ -XX:+UnlockExperimentalVMOptions \ -XX:+DisableExplicitGC \ -XX:+AlwaysPreTouch \ -jar velocity.jar echo "--- Proxy stopped. Restarting in 5s ---" sleep 5 done To make the script executable

chmod +x ~/velocity/start.sh

At this point the since Vangueria is now set to Modern Forwarding, Cherry will reject all connections until it has the forwarding.secret. the secret can be obtained with the command

cat ~/velocity/forwarding.secret

Copy the code to a safe location because we will need it to setup cherry (and apple). then we should be able to finally start the proxy with the start.sh

./start.sh

Now we move to cherry to setup it's ability to receive connections from Vangueria.

Configuring Cherry To Accept Proxied Connections

To complete the integration between the proxy and the backend, Cherry must be transitioned from a standalone Vanilla server to a "Proxy-Aware" host. Because Vanilla Minecraft does not natively support Velocity’s Modern Forwarding (the security handshake), we use the Fabric Loader as a lightweight wrapper. This allows us to install a bridge mod that validates the secret key without changing the gameplay experience.The transition of Cherry involves three main phases: installing the Fabric environment, adding the bridge mods, and configuring the security handshake to match Vangueria.

First, we must stop the existing server and install the Fabric transition layer. This replaces the standard Mojang launcher with a version capable of loading the security bridge. We need to download the Fabric Installer and then Install Fabric for the 1.21.1 environment.

cd ~/minecraft_server
wget https://maven.fabricmc.net/net/fabricmc/fabric-installer/1.0.1/fabric-installer-1.0.1.jar
java -jar fabric-installer-1.0.1.jar server -mcversion 1.21.1 -downloadMinecraft

Once complete, the installer will have created a new file named fabric-server-launch.jar. This is now the primary entry point for the server.

To install the Security Bridge we require two specific components in the mods folder: the Fabric API (the library that allows mods to interact with the game engine) and FabricProxy-Lite (the specific mod that handles the Velocity secret key). It is vital to use version-matched JARs for 1.21.1 to ensure stability.

mkdir -p ~/minecraft_server/mods
wget -O ~/minecraft_server/mods/FabricProxy-Lite.jar https://github.com/OKTW-Network/FabricProxy-Lite/releases/download/v2.10.1/FabricProxy-Lite-2.10.1.jar
wget -O ~/minecraft_server/mods/fabric-api.jar https://github.com/FabricMC/fabric-api/releases/download/0.116.11%2B1.21.1/fabric-api-0.116.11+1.21.1.jar

To configure the handshake after placing the mods, we must run the server once to generate the configuration structure, then shut it down to inject the secret. Update start.sh to point to fabric-server-launch.jar instead of server.jar

sed -i 's/server.jar/fabric-server-launch.jar/' start.sh

Initial run to generate config (Type 'stop' once the 'Done' message appears)

./start.sh

Now, we create the configuration file and link it to Vangueria. This is where we ensure the backend only trusts traffic coming from our proxy.

mkdir -p ~/minecraft_server/config
nano ~/minecraft_server/config/FabricProxy-Lite.toml

Paste the following configuration into the file, ensuring the secret matches the one obtained from Vangueria:

enabled = true
hackOnlineMode = true
secret = "PASTE_YOUR_VANGUERIA_SECRET_HERE"

The final step is to adjust the server.properties file. Because Vangueria handles the official Mojang authentication at the "front door," the backend server must be set to offline mode to allow the proxy to pass the authenticated user data through.

sed -i 's/online-mode=true/online-mode=false/' server.properties

With the configuration complete, the server should be launched inside a named screen session to ensure it remains active.

screen -S minecraft ./start.sh

We should now change the Pfsense port forward rule to forward traffic to the 192.168.100.29 (IP address of Vangueria) and then connecting a client from a laptop outside of Pfsense and using the address cherry.seaoffate.net, we can try using the IP address of the Pfsense WAN port but it may not work (if the default server is set to cherry it may connect)

Additional Options

There are a few additional considerations that will make the servers run more reliably. The first is thing that needs to be done is to run the server in a screen so that there does not need to be a SSH session to be running. The following will start a screen called minecraft and will execute the start.sh command.

screen -S minecraft ./start

To exit the minecraft screen and return to the main SSH type ctrl + a and then d, the minecraft screen can be reloaded with the command

screen -r minecraft

The next thing that we will need to do is to have the minecraft server start whenever the host reboots. So we need to add a cron tab to the start.sh

crontab -e

Select nano if asked then add the line

@reboot screen -dmS minecraft /home/nigel/minecraft_server/start.sh

The next thing is not a minecraft helper exactly but it will be useful as a reminder in the future. When a user logs on to the host the message of the day will be displayed to add simple notes to the message we can simply edit the motd with the command

sudo nano /etc/motd

Adding a second Minecraft server Apple

Now that we have the basic setup with potential for multiple hosts we will need to create at least one more so that we can prove the proxy works as intended. The next server will be a different version with some mods. As soon as we start adding mods to a Minecraft world they will use more resources so we will need the next host to be a bit better specified.

Item Value Notes
CPU 5
RAM 12GB
Swap 16gb Additional disk allocated from Lexar SSD
Storage 150GB Initially set at 32gb
Base OS Debian 13.3 Server version
Hostname Apple
IP Address 192.168.100.35

Hardware Configuration

As we did with the cherry host earlier we need to configure the hardware changes that have been made on the basic specification like adding the Lexar HD as the swap file. We must stop using the swap partition on the primary drive so we can move it out of the way. Turn off all swap.

sudo swapoff -a

Since your swap partition (sda3) is at the end of the disk, it acts as a "blocker." We need to delete it and the root partition, then recreate the root partition to fill the entire space.

sudo fdisk /dev/sda
  • Type p to print the table (confirming sda2 is root and sda3 is swap).
  • Type d then 3 to delete the swap partition.
  • Type d then 2 to delete the root partition (Don't worry, the data stays in the blocks).
  • Step B: Recreate and Expand
  • Type n for a new partition.
  • Type p for Primary. Note if disk is using a GPT (GUID Partition Table) there will be no P option, primary partitions only exist in the old MBR style of disks
  • Type 2 for Partition number 2.
  • Press Enter for the default Start Sector (it must match the old start sector of sda2).
  • Press Enter for the default End Sector (this will now jump to the end of the 150GB disk).
  • CRITICAL: When it asks "Do you want to remove the signature?", type N.
  • Type w to write changes and exit.

Now, reboot to make sure the kernel is looking at the new 150GB table entry.

sudo systemctl reboot

Once you log back in, expand the actual data "container" (the ext4 filesystem) to fill that new partition:

sudo resize2fs /dev/sda2

Now that the main drive is expanded, let's get that high-speed swap set up on your 16GB secondary disk.

sudo mkswap /dev/sdb
sudo swapon /dev/sdb

We need to update /etc/fstab so your VM knows where to find its memory "safety net" on every boot.

sudo nano /etc/fstab

Look for the line that mentions the old swap (it likely mentions sda3 or a long UUID string). Delete that line or put a # at the start of it. Add this new line at the bottom:

/dev/sdb none swap sw 0 0

Save and exit. Then to confirm the changes have been made use the following commands to show the new sda2 disk size and the swap disk

df -h
free -h

Software installation

Since Apple is a fresh VM, we need to ensure the underlying Debian OS is fully patched and has the necessary build tools and repositories before we drop a massive modpack into it. Modern modpacks like FTB University rely heavily on Java 21 or Java 25, so we will set that foundation now. First, we refresh the local package index and upgrade any existing system components. Update package lists and upgrade system and install essential utilities for file management and monitoring

sudo apt update && sudo apt upgrade -y
sudo apt install -y htop screen wget curl jq unzip zip

Install Java 25 and verify the version to ensure it's active

sudo apt install -y openjdk-25-jre-headless
java -version

with the JRE installed we can now pull the explicit API endpoint for the FTB University installer. We will use the -JLO flags with curl. This tells it to follow redirections, process headers properly, and save the binary with its true system filename so the metadata doesn't drop.

mkdir ~/ftb_university
cd ~/ftb_university
curl -JLO "https://api.feed-the-beast.com/v1/modpacks/public/modpack/108/latest/server/linux"

When the file finirm ~/ftb_university/serverinstall_108_*shes downloading, it will have a specific auto-generated string name based on the pack ID. Let's make it executable and kick off the automated build process

chmod +x serverinstall_108_*
./serverinstall_108_* --auto

Assuming the automated build script successfully assembled the library trees, we can clear the raw installation binaries to save block space.

 rm ~/ftb_university/serverinstall_108_*

We need to generate the basic runtime parameters so the engine treats your backend initialization correctly. We need accept the core EULA agreement before the server can start and Disable Mojang online lookup to yield authentication control to Vangueria.

echo "eula=true" > ~/ftb_university/eula.txt
printf "online-mode=false\nmotd=FTB University Home\nallow-flight=true\nmax-tick-time=180000" > ~/ftb_university/server.properties

We will launch the first server loop. Forge will map out the dimensions and establish the baseline mod settings.

./run.sh

Since this is a clean workspace, the installer script will start downloading the specific runtime libraries. Watch the console scroll past the mod registry logs. Let the text settle completely until it opens up the standard interactive game prompt (>). Once you see that prompt, type stop and hit Enter to close down the thread cleanly. This will finalize our asset paths so we can secure the proxy sync.