Fabric Minecraft Server in a Proxmox LXC Container: Mods + JVM Tuning

Run a Fabric 1.20.1 Minecraft server in an unprivileged Proxmox LXC container with performance mods (Lithium, Starlight, Carpet), JVM garbage collection tuning, and systemd service management.

Running a Minecraft server in an LXC container is tidier than a bare VM: near-native performance, isolated from the rest of the cluster, snapshotable, and easy to migrate. This guide covers Fabric 1.20.1 with the performance mod stack that makes a single-node CPU cluster playable for small groups.


Performance target

On a Ryzen 5 2400G with 4 GB RAM allocated to the container and 3 GB to the JVM, expect:

Metric Idle 4 players 8 players
TPS 20.0 19.8 18.5–20.0
MSPT 4–6ms 8–14ms 14–22ms
RAM used 800 MB 1.4 GB 2.1 GB
CPU % 5–8% 20–35% 45–65%

The mods below get you from stock’s 12–18 MSPT at 4 players down to 8–14ms.


Mod stack

Mod What it fixes
Fabric API Required loader for all Fabric mods
Lithium Server-side optimizations: physics, collision, chunk loading
Starlight Complete rewrite of the lighting engine (~30% faster chunk load)
Carpet Admin utilities: tick control, spawn tracking, /log profiling
Carpet-Extra Additional Carpet features: block update optimizations
Note

Skip Sodium/Iris/Indium — those are client-side rendering mods. Server performance mods are Lithium and Starlight. Clients can use any mods they want regardless of what’s on the server.


Task 1: Create the container

1Create CT 104 on pvelab035 min
Field Value
VMID 104
Hostname minecraft
OS Ubuntu 24.04 LXC (unprivileged)
Host pvelab03
IP 10.25.144.76 (or your choice)
Cores 4
RAM 4096 MB
Disk 20 GB
Tip

4 GB RAM is fine for up to 10 players. For larger servers or many loaded chunks, increase to 8 GB and set JVM to -Xmx6G.


Task 2: Install Java and create the server

1Install Java 213 min

Minecraft 1.20.1 requires Java 17+. Java 21 performs better with virtual threads and the Shenandoah GC:

Inside CT 104

apt-get update && apt-get install -y curl wget jq
apt-get install -y openjdk-21-jre-headless
java -version
# → openjdk version "21.0.x" ...
2Create the minecraft user and directories2 min
Inside CT 104

useradd -m -s /bin/bash minecraft
mkdir -p /srv/minecraft/{server,mods,backups}
chown -R minecraft:minecraft /srv/minecraft
3Download Fabric installer and bootstrap the server5 min
Inside CT 104 — as root, then switch to minecraft user

cd /srv/minecraft/server
wget -q "https://meta.fabricmc.net/v2/versions/installer" -O - | \
jq -r '.[0].url' | xargs wget -q -O fabric-installer.jar

# Bootstrap the server jar (Fabric loader 0.16.0, Minecraft 1.20.1)
su - minecraft -c "java -jar /srv/minecraft/server/fabric-installer.jar server \
-mcversion 1.20.1 \
-loader 0.16.0 \
-downloadMinecraft \
-dir /srv/minecraft/server"
4Accept the EULA1 min
Inside CT 104

echo "eula=true" > /srv/minecraft/server/eula.txt
chown minecraft:minecraft /srv/minecraft/server/eula.txt

Task 3: Install performance mods

1Download Lithium and Starlight3 min

Download the 1.20.1-compatible versions from Modrinth:

Inside CT 104

MODS_DIR="/srv/minecraft/server/mods"

# Lithium — check Modrinth for current 1.20.1 build
wget -q "https://cdn.modrinth.com/data/gvQqBUqZ/versions/FT.../lithium-fabric-mc1.20.1-0.11.2.jar" \
-O "$MODS_DIR/lithium.jar"

# Starlight — Fabric 1.20.1
wget -q "https://cdn.modrinth.com/data/H8CaAYZC/versions/.../starlight-1.1.2+fabric.dce1c55.jar" \
-O "$MODS_DIR/starlight.jar"

# Carpet
wget -q "https://github.com/gnembon/fabric-carpet/releases/download/1.4.112/fabric-carpet-1.20.1-1.4.112+v230628.jar" \
-O "$MODS_DIR/carpet.jar"

chown minecraft:minecraft "$MODS_DIR"/*.jar
Always verify mod versions against your MC + loader version

Mod downloads change URLs as new versions release. Before running: check the Modrinth project page for each mod, filter by Minecraft 1.20.1 + Fabric, and grab the direct download URL from the latest compatible release.


Task 4: Tune the JVM and create the systemd service

1Create start.sh with optimized JVM flags5 min

The flags below use Shenandoah (low-pause GC), pin threads to avoid cross-NUMA latency, and pre-touch memory:

Create /srv/minecraft/server/start.sh

cat > /srv/minecraft/server/start.sh {'<<'} 'EOF'
#!/bin/bash
cd /srv/minecraft/server
exec java \
-Xms2G -Xmx3G \
-XX:+UseShenandoahGC \
-XX:ShenandoahGCHeuristics=adaptive \
-XX:+DisableExplicitGC \
-XX:+AlwaysPreTouch \
-XX:+UseNUMA \
-XX:+PerfDisableSharedMem \
-Dfml.ignorePatchDiscrepancies=true \
-jar fabric-server-launch.jar --nogui
EOF
chmod +x /srv/minecraft/server/start.sh
chown minecraft:minecraft /srv/minecraft/server/start.sh
2Create the systemd service3 min
Create /etc/systemd/system/minecraft.service

cat > /etc/systemd/system/minecraft.service {'<<'} 'EOF'
[Unit]
Description=Minecraft Fabric Server 1.20.1
After=network.target

[Service]
User=minecraft
WorkingDirectory=/srv/minecraft/server
ExecStart=/srv/minecraft/server/start.sh
ExecStop=/bin/kill -s SIGTERM $MAINPID
Restart=on-failure
RestartSec=10
StandardInput=null

[Install]
WantedBy=multi-user.target
EOF

systemctl enable --now minecraft
3Verify the server starts and verify TPS5 min
Watch the server log

journalctl -u minecraft -f
# Wait for: [Server thread/INFO]: Done (15.234s)! For help, type "help"

Once live, connect with Minecraft client to 10.25.144.76:25565. In-game, verify TPS with Carpet:

In-game console (Carpet mod required)

/carpet setDefault commandLog true
/log tps
# → TPS: 20.0, MSPT: 6.24

Task 5: Automatic backups

1Create a backup script5 min
Create /srv/minecraft/backups/backup.sh

cat > /srv/minecraft/backups/backup.sh {'<<'} 'EOF'
#!/bin/bash
BACKUP_DIR="/srv/minecraft/backups"
WORLD_DIR="/srv/minecraft/server/world"
DATE=$(date +%Y%m%d_%H%M)
TAR="/srv/minecraft/backups/world_$(date +%Y%m%d_%H%M).tar.gz"

# Tell players about the backup
# (works if minecraft-send-command tool is installed, skip otherwise)

tar -czf "$TAR" -C /srv/minecraft/server world
echo "Backup: $TAR ($(du -sh $TAR | cut -f1))"

# Keep last 7 daily backups
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +7 -delete
EOF
chmod +x /srv/minecraft/backups/backup.sh

Add to root crontab:

Schedule daily 3AM backup

echo "0 3 * * * /srv/minecraft/backups/backup.sh >> /var/log/minecraft-backup.log 2>&1" | crontab -

Proxmox snapshot for pre-update safety

Before any Minecraft or mod update:

Proxmox host — snapshot CT 104 before updates

pct snapshot 104 pre-update-$(date +%Y%m%d) \
--description "Before Minecraft/mod update"

# To roll back if the update breaks things:
pct rollback 104 pre-update-20260705

The snapshot includes the entire container filesystem — world data, mods, configs. Rollback takes under 30 seconds.


Server management reference

Common management commands from pvelab03 host

# View live log
journalctl -u minecraft -f

# Restart (saves world first via SIGTERM → ExecStop)
pct exec 104 -- systemctl restart minecraft

# Check memory usage
pct exec 104 -- ps aux | grep java

# Emergency stop (only if systemctl fails)
pct exec 104 -- kill -9 $(pgrep -f fabric-server)

# View backup list
pct exec 104 -- ls -lh /srv/minecraft/backups/

The complete Proxmox cluster setup supporting this server — including Tailscale for remote access and Grafana alerts for monitoring the container’s RAM and CPU — is covered in the other posts in this series.