Every Minecraft player has dreamed of running their own server at least once.
This article distills the lessons I learned while setting up a small, friend‑only technical-survival server. It’s aimed at hobbyists who want to play with three to five friends, and it doesn’t touch professional networking or DevOps.
Hardware
First, a disclaimer: I’m an Apple devotee, so my hardware advice is inevitably biased.
If you’re shopping for a dedicated machine, I heartily recommend the entry‑level M‑series Mac mini. I run three lightweight sub‑servers on the 8 GB model; it works, but 16 GB feels comfortable.
I think the Mac mini has four key advantages:
Whisper‑quiet operation and ultra‑low power draw—perfect for something that lives on your desk.
Even the first‑gen M1’s single‑core performance can power a mid‑sized technical server (Minecraft is heavily single‑threaded).
Anything faster is louder; anything quieter is slower.
macOS is actually easier to manage than Windows for server tasks.
But there are downsides, too:
Apple’s notoriously pricey RAM.
macOS hasn’t seen as much headless‑server testing. Mine’s stable, but if you prefer Linux you can install Fedora Asahi Remix (untested by me).
Some users report ARM compatibility issues with heavy modpacks or potential P-E core scheduling quirks (I haven’t encountered them; shaders are client‑side anyway).
My environment
Physical machine: Mac mini (M1, 8G RAM)
Operating system: macOS 15 Sequoia
Terminal: Mac terminal + Zsh
installed game version: 1.21.4
Although this article is all about building with macOS, the same operations can be performed on windows and linux. At the same time, a tutorial can never cover all the possible problems that may arise during the process of setting up a server, it is highly recommended to use this tutorial along with the help of llm (ChatGPT, Gemini, grok etc.), which are able to deal with all kinds of problems that are difficult to find precedents for on the web. The links in this tutorial are in a mix of Chinese and English, so if you have trouble reading them, please use the built-in translation function of your browser.
Fabric
What Is Fabric?
Fabric is a lightweight mod loader that lets us run server‑side mods such as the Carpet suite or masa’s utilities—essentials for technical play.
Install Java
Minecraft Java Edition obviously needs Java, and since 1.20.5 the minimum version is 21. On macOS I install the JDK via Homebrew because it’s just two terminal commands.
When the install completes, run java -version. Seeing openjdk version "21.x.x" (or higher) means success. If you don’t, add Java to your PATH with the snippet below.
Run java -version again and you should now see the version string.
Set Up the Fabric Server
Download Fabric from here—this guide uses fabric-server-mc.1.21.4-loader.0.16.14-launcher.1.0.3.jar as an example—and execute the .jar inside your chosen server folder:
The launcher will fetch the server jar and libraries, then throw an error like this:
1
[main/WARN]: Failed to load eula.txt
2
[main/INFO]: You need to agree to the EULA in order to run the server. Go to eula.txt for more info.
That’s expected. Your folder should now contain these files:
1
./
2
├── libraries/
3
├── logs/
4
├── versions/
5
├── mods/
6
├── eula.txt
7
└── server.properties
Drop your server‑side mods into mods/ (at minimum install Fabric API) and change false to true in eula.txt to accept the EULA.
Run the jar again. When [Server thread/INFO]: Done! appears, the server is ready. For networking help see the networking section; the Extras section shows my own config for reference.
Velocity
What Is Velocity?
Technical servers often run multiple backends—Survival, Mirror, Creative—and let players switch with /server. Velocity is the proxy that makes this possible.
Velocity is a proxy for a Minecraft network. It contains no server logic; it simply routes incoming clients to the correct backend according to your rules.
Think of the network as a hotel and Velocity as the concierge desk. Guests check in, get directions to their rooms, and can move to another room by returning to the desk. The desk isn’t a room itself, but it knows which ones exist and who’s allowed in.
Bringing the analogy back to Minecraft, we can draw two conclusions:
Velocity is not a game server; it only handles client ↔ server connections.
Velocity is the sole entry point, so every backend must be registered there. Players never see individual addresses.
First we download the FabricProxy-Lite Mod and put it in the mods folder. At this point we run the server once to generate the configuration file. After shutting down the server, create a velocity folder inside the server folder, download the latest version of velocity.jar and put it in. Now run in the terminal:
Terminal window
cdvelocity
java-jarvelocity-3.4.0-SNAPSHOT-469.jar
to start Velocity. When [INFO]: Done! appears, the proxy has booted and created velocity.toml. For a Survival–Mirror–Creative setup, edit these fields:
1
bind = "0.0.0.0:25577"
2
online-mode = true
3
player-info-forwarding-mode = "modern"
4
5
[servers]
6
main = "127.0.0.1:25565"
7
mirror = "127.0.0.1:25566"
8
creative = "127.0.0.1:25567"
9
10
try = [
11
"main",
12
"mirror"
13
]
After saving the changes we go back to the previous folder, the server folder. The config folder was automatically created here the first time velocity was run, and inside there is a configuration file FabricProxy-Lite.toml. At this point we open this configuration file and find the entry secret = “”. At this point we go back to the velocity folder where we can find forwarding.secret and open it up to see a string of keys. Fill this key into secret = “your-secret-key” and save the changes.
Running the Network
The cluster service requires multiple server instances, at this point we can use the current server folder as the main server and make two copies of it as the mirror and creative servers respectively. In these two servers, we change the server-port in server.properties to 25566 and 25567 respectively, and at this point, we pass java -jar fabric-server-mc.1.21.4-loader.0.16.14-launcher.1.0.3.jar in each of the three server folders to start the servers, and the cluster service is up and running. Now we can switch between subservices in-game with the /server <name> command.
MCDR
What is MCDR?
Vanilla servers can’t run plugins, and Paper/Spigot alter core mechanics. Minecraft Daemon Reforged (MCDR) lets us run plugins without touching the vanilla server core.
MCDR 2.14 requires Python 3.8+. On macOS you can install it quickly with Homebrew:
Terminal window
brewinstallpython
python3--version
You should see Python 3.x.x (≥ 3.8) when you run python3 --version.
Install MCDR
MCDR’s docs are excellent; this section paraphrases them.
On macOS the docs recommend an isolated install because:
If you’re using Windows, the command above should work fine, and MCDR will be installed to the global environment - you may ignore this section
For Linux and Mac OS, it’s not recommended to install MCDR system-wide (with root), because it can cause conflicts with other Python packages and affect system dependencies
System-wide installation also makes version management difficult and requires administrator privileges, increasing security risks
System-wide installation may even result in an externally-managed-environment error. See PEP 668 for the detailed specification
It’s safer to keep the installation isolated. As workarounds, there’re multiple options for you. In conclusion:
Method
Pros
Cons
pip
Native, always available
Not isolated, may affect global packages with root privileges
pipx
Simplest
3rd party, different command set
venv
Native support
Requires manual environment activation
docker
Reliable across environments
More dependencies and disk space, convoluted learning path
system package
-
Same as pip, not recommended
I chose pipx, which you can also install via Homebrew:
Terminal window
brewinstallpipx
pipxensurepath
Then install MCDR itself:
Terminal window
pipxinstallmcdreforged
Launching
If you’ve set up Velocity, you now have multiple server instances. Start MCDR inside each one; your folder should look like this:
1
./
2
├── config/
3
├── libraries/
4
├── logs/
5
├── mods/
6
├── velocity/
7
├── versions/
8
├── world/
9
├── banned-ips.json
10
├── banned-players.json
11
├── eula.txt
12
├── fabric-server-mc-launcher.jar
13
├── ops.json
14
├── server.properties
15
├── usercache.json
16
└── whitelist.json
I suggest creating a sibling directory outside the server folder and initializing MCDR there:
Terminal window
cdmy_mcdr_server
mcdreforgedinit
MCDR creates the default structure:
1
my_mcdr_server/
2
├─ config/
3
├─ logs/
4
│ └─ MCDR.log
5
├─ plugins/
6
├─ server/
7
├─ config.yml
8
└─ permission.yml
Copy all files from your original server into the new server sub‑folder so it looks like:
1
my_mcdr_server/
2
├─ config/
3
├─ logs/
4
│ └─ MCDR.log
5
├─ plugins/
6
├─ server/
7
++ │ ├─ ...
8
++ │ ├─ minecraft_server.jar
9
++ │ └─ server.properties
10
├─ config.yml
11
└─ permission.yml
Tailor the configs to your needs—see the config guide. At minimum, change:
For permission.yml (plugin permissions; gameplay permissions remain in ./server/ops.json):
1
default_level: user
2
owner:
3
- your-MC-account-name
MCDR is now installed. Stop the server, cd into each MCDR folder, and run mcdreforged to launch. In‑game and console now accept the !!MCDR command.
Congrats—your technical Minecraft server is live! Enjoy your handiwork, and read on for port‑forwarding and other advanced tweaks.
Networking
Skip this section if you already have a static public IP.
Most home ISPs provide dynamic or private addresses unless you pay for a static IP. Such addresses can’t host a public server directly. If you’re unsure whether yours is static, try this (credit: GPT‑4o):
Power‑cycle your router or modem and wait a few minutes.
Check the public IP again.
Interpretation:
If the IP changed → you have a dynamic IP.
If the IP stayed the same → you may have a static IP (verify with ISP).
Some dynamic IP leases are long and look static.
Log into your router’s admin panel.
Most routers default to dynamic IP. To confirm:
Visit 192.168.1.1 or 192.168.0.1.
Navigate to Network or WAN settings.
Check the connection type:
DHCP, Dynamic IP, or PPPoE → dynamic.
Static IP → static public address.
Call your ISP (most reliable).
Ask support, “Do I have a static public IP?”
Many ISPs sell static IPs if you need one.
NAT Traversal / Reverse Proxy
I’m no networking guru; for definitions see these intros: Cloudflare or the Wikipedia article on NAT traversal. Reverse proxying lets you expose a local server to the internet without a static IP.
- Easy to use - WireGuard‑based, very secure - Peer‑to‑peer access inside a private network
- Unstable inside mainland China - Funnel is still in preview / not on all platforms
I use frp. Here’s a quick setup (see the official docs for details):
⚠️ Legal note: I host all services outside mainland China. I don’t know your local laws—this is purely technical info. Proceed at your own risk.
First, rent a VPS. Check real‑user reviews on subreddits like r/VPS or r/homelab. A minimal plan (1 vCPU, 1 GB RAM) is plenty, but you must get an IPv4.
SSH into the VPS: ssh root@your-vps-ip-address.
Download frp (pick the build that matches your OS/arch):
Edit frps.toml with nano. If Velocity listens on 25577, the VPS config should be:
1
[common]
2
bind_port = 7000
3
token = "your-secret-token"
4
5
[minecraft]
6
type = tcp
7
local_port = 25577
8
remote_port = 25565
Save with Ctrl+X, Y, Enter.
Repeat on your home machine for frpc.toml:
1
[common]
2
server_addr = your-vps-ip-address
3
server_port = 7000
4
token = "your-secret-token"
5
6
[minecraft]
7
type = tcp
8
local_ip = 127.0.0.1
9
local_port = 25577
10
remote_port = 25565
Make sure the token matches in both files. Start the services with nohup ./frps -c ./frps.toml > frps.log 2>&1 & on the VPS and nohup ./frpc -c ./frpc.toml > frps.log 2>&1 & locally.
Your server is now reachable via your-vps-ip-address:25565.
Advanced
Security
Public Minecraft servers are prime targets for griefers—r/admincraft is full of horror stories. Always lock things down, or randoms will nuke your world. Trust me, it happened to my previous server.
Vanilla includes a whitelist. Set white-list=true in server.properties and add UUIDs to whitelist.json. Look up UUIDs at mcuuid.net. Format:
1
[
2
{
3
"uuid": "player-1-uuid",
4
"name": "player-1-name"
5
},
6
{
7
"uuid": "player-2-uuid",
8
"name": "player-2-name"
9
},
10
]
The whitelist is per backend; configure each one and restart so only listed accounts can join.
Also make yourself an op. The console has full power, but ops let you run admin commands in‑game. Add yourself to ops.json like:
1
[
2
{
3
"uuid": "op-uuid",
4
"name": "op-name",
5
"level": 4,
6
"bypassesPlayerLimit": false
7
}
8
]
For stronger protection, use fail2ban to block brute‑force logins.
Custom Domain
A domain isn’t mandatory for a friends‑only server, but it’s convenient. Buy a domain and make sure you can edit DNS.
Create an A record pointing to your server’s IP:
Type
Name
Value
A
mc
Your-ip-addr
You can now join via mc.yourdomain.com.
Velocity also lets you map sub‑domains to individual backends—configure them in velocity.toml:
1
[forced-hosts]
2
"main.yourdomain.com" = [
3
"main"
4
]
5
"mirror.yourdomain.com" = [
6
"mirror"
7
]
8
"creative.yourdomain.com" = [
9
"creative"
10
]
Extras
Mods
Below is the list of mods installed on my server (version 1.21.4). It’s a fairly standard tech‑survival setup—feel free to use it as a reference.