> ## Content Index
> Fetch the complete content index at: https://blog.sudowl.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Hosting a Forge / NeoForge Modpack Server on Linux — The Pragmatic Guide
- URL: https://blog.sudowl.com/forge-neoforge-modpack-server-linux/
- Published: 2026-05-01T14:00:00.000Z
- Updated: 2026-10-11T10:16:27.000Z
- Description: Run a CurseForge or Modrinth modpack server (Forge / NeoForge) on Ubuntu. Server-pack download, JVM tuning for modded RAM appetite, systemd unit, update workflow.
- Author: Lukas
- Tags: Minecraft, Gameserver, Linux

Vanilla Minecraft is one app ID and a JAR. A modpack server is a whole stack — modloader, 200+ mod JARs, config files for each, a JVM tuned for the RAM bloat. Most "modpack hosting" tutorials skip the parts that actually break.

This is what I run for a small group on a 200-mod NeoForge pack. Same pattern applies to Forge.

**TL;DR:**

```bash
mkdir /opt/modpack && cd /opt/modpack
wget <server-pack-zip-url-from-curseforge-or-modrinth>
unzip server-pack.zip
chmod +x run.sh   # ships with most modern packs
./run.sh

```

If the pack ships a `run.sh` (most modern ones do), it handles modloader install. If not, install Forge/NeoForge yourself first.

## Get the right files

CurseForge and Modrinth distinguish between **client packs** (what your players install) and **server packs** (what you install). Always grab the server pack. The client pack contains the visual / audio mods you don't need (and which crash a headless server).

On CurseForge: pack page → Files → look for "Server Pack" download button. Modrinth: pack → Versions → download the `.mrpack` and use [Packwiz](https://packwiz.infra.link/?ref=blog.sudowl.com) to bootstrap, OR look for the project's pre-built server zip.

Some packs don't ship server packs at all — they expect you to use [ATLauncher](https://atlauncher.com/?ref=blog.sudowl.com) or BCC-style auto-bootstrap. In that case, download the modlist manually and copy mods marked "server-side" to your install. Slow but works.

## Install — the modern path (run.sh)

NeoForge and recent Forge ship the modpack with an `install.sh` or `run.sh` that handles modloader install:

```bash
sudo adduser --system --group --home /opt/modpack modpack
cd /opt/modpack
sudo -u modpack unzip server-pack.zip -d .
sudo -u modpack chmod +x run.sh

# First run — bootstraps the modloader, accepts EULA, then exits or runs
sudo -u modpack ./run.sh

```

First boot downloads the actual modloader libraries (Forge / NeoForge / Mojang server JAR), accepts the EULA prompt (`echo "eula=true" > eula.txt` if it asks), then either starts the server or exits.

If it exits cleanly, you're set up but haven't started yet — the systemd unit below boots properly.

## Install — the manual path (legacy Forge)

If the pack doesn't ship `run.sh`:

1. Download the Forge installer for the pack's MC version + Forge version. Pack manifest tells you both.
2. Run installer:  
```bash  
java -jar forge-1.20.1-47.4.0-installer.jar --installServer  
```
3. Drop pack mods into `mods/`. Drop config files into `config/`.
4. Start with the generated `run.sh` or build one:  
```bash  
#!/bin/bash  
cd "$(dirname "$0")"  
exec java @user_jvm_args.txt @libraries/net/minecraftforge/forge/<version>/unix_args.txt $@  
```

The `@argfile` syntax is Forge's way of separating user args from massive class-path args. Don't try to inline.

## RAM — the part nobody warns you about

Vanilla Minecraft server is happy with 2 GB. A 200-mod pack needs **8 GB minimum**, comfortable at 12-16 GB. Mods don't only add features — they add startup-time class loading, eager world generators, ticking entities, and dimensional cache.

The classic mistake is `-Xmx4G` because the box is 8 GB. After 30 minutes of play with 4 players, the JVM is GC-thrashing, TPS drops to 5, players blame "lag". Give it 12 GB:

```bash
java -Xms6G -Xmx12G [...]

```

Ratio matters: `Xms` near `Xmx` (within 2x) avoids heap-resize stalls. JVMs grow heap reluctantly under modded load.

## JVM flags — Aikar's are still the move

Standard tuned flags for Minecraft (originally Aikar's, evolved by various contributors):

```
-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200
-XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC
-XX:+AlwaysPreTouch -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40
-XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5
-XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15
-XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5
-XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1
-Dusing.aikars.flags=https://mcflags.emc.gs -Daikars.new.flags=true

```

Drop them into `user_jvm_args.txt` next to `run.sh`, or paste into the systemd ExecStart. They tune G1GC for "low pause, high throughput" — exactly the workload modded MC is.

## Systemd unit

`/etc/systemd/system/modpack.service`:

```ini
[Unit]
Description=NeoForge Modpack Server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=modpack
Group=modpack
WorkingDirectory=/opt/modpack
ExecStart=/opt/modpack/run.sh nogui
Restart=on-failure
RestartSec=15
RuntimeMaxSec=86400
MemoryMax=14G

[Install]
WantedBy=multi-user.target

```

`RuntimeMaxSec=86400` — daily restart. Modded JVMs accumulate metaspace pressure that GC doesn't reclaim. After \~30 hours, world generation lags noticeably. Daily restart prevents.

`MemoryMax=14G` (slightly above your `-Xmx`) — hard cap. JVMs occasionally exceed heap due to off-heap allocations; this stops the kernel OOM-killer from picking the wrong process. [systemd unit reference](/systemd-service-unit-file/).

Enable and watch:

```bash
sudo systemctl daemon-reload
sudo systemctl enable --now modpack
sudo journalctl -u modpack -f

```

First boot of a 200-mod pack takes **5-15 minutes**. Don't panic. Look for `Done (XXXs)! For help, type "help"` — that's actually-ready.

## Ports

```bash
sudo ufw allow 25565/tcp

```

Minecraft Java is TCP only. [UFW rules](/ufw-firewall-rules-ubuntu/).

If you're running multiple modpack servers behind a [Velocity proxy](/velocity-minecraft-proxy-setup-from-scratch/), bind each backend to `127.0.0.1` and let the proxy be the only public-facing port.

## Backups — bigger than you think

Modded saves are huge. World folders for a 200-mod pack hit 5-10 GB after a month. The files that matter:

- `world/` — the entire directory
- `config/` — pack config (don't lose tweaks)
- `defaultconfigs/` — pack-distributed defaults

Nightly:

```bash
systemctl stop modpack
rsync -a --delete /opt/modpack/world/ /backup/modpack/world/$(date +%F)/
rsync -a --delete /opt/modpack/config/ /backup/modpack/config/$(date +%F)/
systemctl start modpack

```

Stop-rsync-start is mandatory for modded saves. A live rsync of a 5 GB modded world catches mid-write chunk files about 1 in 20 attempts. The 60-second downtime beats restoring a corrupt backup. [rsync rotation pattern](/rsync-backup-linux/).

Keep 14 days. Modded worlds are precious — players invested 100+ hours in those bases.

## Updates

Modpack updates are not Minecraft patches. They're the modpack author bumping mod versions, sometimes the modloader version. The procedure:

```bash
sudo systemctl stop modpack
cd /opt/modpack
# Backup current state
sudo -u modpack tar czf ../modpack-pre-update-$(date +%F).tar.gz mods/ config/

# Replace mods/ and config/ with the new server pack contents
# (each pack ships an update procedure — read it before)

sudo systemctl start modpack

```

After updating, watch the log carefully — mod incompatibilities fail at JVM init, not at runtime. If anything's wrong, the server doesn't start. Roll back from the tarball, you're back in 30 seconds.

## The two failure modes you'll hit

**"Server crashed on startup with mixin errors."** Mod conflict — a dependency mod is missing or wrong version. Look at the latest crash log under `crash-reports/`. Mixin failures are loud and tell you which mod crashed which.

**"TPS drops to 5 after 20 minutes."** Mod doing dumb tick work — heavy entity (mob farms, chunkloaders), inefficient block tick, world generator looping. `mods` console command on most modloaders shows tick time per mod. Find the offender, ban or replace.

For comparison with vanilla and a per-modloader breakdown, see [Minecraft server software comparison](/minecraft-server-software-comparison/) — that post covers when Forge / NeoForge / Fabric / Paper each make sense.

## When to host this yourself vs pay for hosting

A 12 GB modpack server on Hetzner CPX31 runs €15/month — same machine as my [ARK](/ark-survival-ascended-dedicated-server-linux/) and [Enshrouded](/enshrouded-dedicated-server-linux/) game-server pricing. Managed modpack hosting is €10-15/month for a single 8-12 GB instance, with patch latency and limited mod control.

If you want to run *your* mod tweaks (curated mods, custom recipes via KubeJS, etc.), self-host. If you just want vanilla-plus pack hosted, paid hosting saves you the systemd unit. For homelab + friends, self-host wins on price and flexibility.

---

### Related posts

- [LuckPerms on BungeeCord and Velocity — Permissions That Actually Scale](https://blog.diengdoh.com/luckperms-bungeecord-velocity-setup/?ref=blog.sudowl.com)
- [Waterfall vs BungeeCord — Which Minecraft Proxy Should You Run?](https://blog.diengdoh.com/waterfall-vs-bungeecord-minecraft-proxy/?ref=blog.sudowl.com)
- [BungeeCord config.yml — Every Option Explained](https://blog.diengdoh.com/bungeecord-config-yml-explained/?ref=blog.sudowl.com)