← All articles
GAMING Advanced Game Server Hosting: Mods, Performance Tuni... 2026-02-09 · 8 min read · gaming · game-server · minecraft

Advanced Game Server Hosting: Mods, Performance Tuning, and Multi-Game Management

Gaming 2026-02-09 · 8 min read gaming game-server minecraft valheim terraria palworld mods performance docker

You've got a basic game server running. Friends can connect, the world generates, and everything seems fine. Then someone adds a few mods, the player count grows, the server starts lagging during peak hours, and you realize that running a game server well is different from just running one.

This guide covers the next level: mod management, performance tuning, automated maintenance, multi-game setups, and the operational practices that separate a server people tolerate from one people love playing on.

Docker logo

Mod Management

Mods are where game servers get interesting — and where they get complicated. A modded Minecraft server with 200+ mods is a different beast from vanilla. Managing mods across updates, compatibility issues, and player expectations requires a system.

Minecraft: Mod Loaders and Management

The itzg/minecraft-server Docker image supports all major mod loaders:

services:
  minecraft-modded:
    image: itzg/minecraft-server
    container_name: minecraft-modded
    restart: unless-stopped
    ports:
      - "25565:25565"
    volumes:
      - ./minecraft-data:/data
    environment:
      EULA: "TRUE"
      MEMORY: "8G"
      TYPE: "FABRIC"                    # or FORGE, NEOFORGE, QUILT
      VERSION: "1.21.4"
      MODRINTH_PROJECTS: |
        sodium
        lithium
        fabric-api
        starlight
        iris
      MODRINTH_ALLOWED_VERSION_TYPE: "release"

The MODRINTH_PROJECTS environment variable automatically downloads and updates mods from Modrinth. For CurseForge mods, use CF_API_KEY and CURSEFORGE_FILES.

Modpack Deployment

For curated modpacks, pin the exact version to prevent unexpected updates:

    environment:
      TYPE: "AUTO_CURSEFORGE"
      CF_API_KEY: "${CF_API_KEY}"
      CF_PAGE_URL: "https://www.curseforge.com/minecraft/modpacks/all-the-mods-10"
      CF_FILE_ID: "5432100"             # Pin to specific file version

Valheim: BepInEx and Mods

Valheim mods use the BepInEx framework. The lloesche/valheim-server image supports it natively:

services:
  valheim:
    image: lloesche/valheim-server
    container_name: valheim
    restart: unless-stopped
    ports:
      - "2456-2457:2456-2457/udp"
    volumes:
      - ./valheim-config:/config
      - ./valheim-data:/opt/valheim
    environment:
      SERVER_NAME: "My Valheim Server"
      WORLD_NAME: "MyWorld"
      SERVER_PASS: "secretpassword"
      VALHEIM_PLUS: "true"              # Install Valheim Plus mod
      # Or for BepInEx mods:
      BEPINEX: "true"
    cap_add:
      - sys_nice

Place BepInEx plugins in ./valheim-config/bepinex/plugins/.

Terraria: tModLoader

For modded Terraria, use tModLoader:

services:
  terraria-modded:
    image: jacobsmile/tmodloader1.4:latest
    container_name: terraria-modded
    restart: unless-stopped
    ports:
      - "7777:7777"
    volumes:
      - ./terraria-data:/root/.local/share/Terraria
    environment:
      WORLD_NAME: "ModdedWorld"
      DIFFICULTY: "2"
      MAX_PLAYERS: "16"
      # Mods are managed through the tModLoader mod browser
      # or placed in the Mods directory

Palworld: Server Configuration

Palworld's dedicated server has extensive configuration:

services:
  palworld:
    image: thijsvanloef/palworld-server-docker:latest
    container_name: palworld
    restart: unless-stopped
    ports:
      - "8211:8211/udp"
      - "27015:27015/udp"
    volumes:
      - ./palworld-data:/palworld
    environment:
      PUID: 1000
      PGID: 1000
      COMMUNITY_SERVER: "true"
      SERVER_NAME: "My Palworld Server"
      SERVER_PASSWORD: "secretpassword"
      ADMIN_PASSWORD: "adminpassword"
      MAX_PLAYERS: 16
      # Performance tuning
      PAL_EGG_DEFAULT_HATCHING_TIME: "1.000000"
      DEATH_PENALTY: "None"
      ENABLE_PLAYER_TO_PLAYER_DAMAGE: "false"

Performance Tuning

JVM Tuning for Minecraft

Minecraft's biggest performance bottleneck is the Java Virtual Machine. The default JVM flags are conservative. These Aikar flags are the community standard for optimized Minecraft servers:

    environment:
      JVM_XX_OPTS: >-
        -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

Memory allocation guidelines:

Players Vanilla Light Mods (20-50) Heavy Mods (100+)
1-5 2-3GB 4-5GB 6-8GB
5-10 3-4GB 5-6GB 8-10GB
10-20 4-6GB 6-8GB 10-12GB
20+ 6-8GB 8-12GB 12-16GB

Don't over-allocate memory. Giving Minecraft 16GB when it only needs 8GB causes longer garbage collection pauses.

Performance Mods for Minecraft

Server-side performance mods make a dramatic difference:

Mod Loader Effect
Lithium Fabric Optimizes game physics, AI, block ticking
Starlight Fabric/Forge Rewrites the lighting engine (massive improvement)
FerriteCore Fabric/Forge Reduces memory usage
Chunky Fabric/Forge Pre-generates chunks (eliminates lag from exploration)
Krypton Fabric Optimizes networking code
C2ME Fabric Parallelizes chunk generation

A Fabric server with Lithium + Starlight + FerriteCore performs dramatically better than vanilla, especially with 10+ players.

Pre-generating the World

Chunk generation is the biggest source of lag spikes. Pre-generate your world before players connect:

# In-game command (with Chunky mod)
/chunky radius 5000
/chunky start

# This generates all chunks within 5000 blocks of spawn
# Takes 30-60 minutes depending on hardware
# After completion, exploration within this area causes zero generation lag

CPU and I/O Optimization

Game servers benefit from specific host optimizations:

# Set CPU governor to performance (prevents frequency scaling lag spikes)
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

# Or make it persistent
sudo apt install cpufrequtils
echo 'GOVERNOR="performance"' | sudo tee /etc/default/cpufrequtils

# For Docker: pin game server containers to specific CPU cores
docker update --cpuset-cpus="0-3" minecraft

Store game server data on SSDs. World data involves many small random reads and writes — exactly the workload where SSDs shine and HDDs struggle. A Minecraft server on an NVMe drive loads chunks noticeably faster than one on a hard drive.

Network Optimization

# Increase network buffer sizes (helps with many simultaneous players)
sudo sysctl -w net.core.rmem_max=16777216
sudo sysctl -w net.core.wmem_max=16777216

# Make persistent in /etc/sysctl.d/99-gameserver.conf
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 5000

Automated Backups

Game world data is irreplaceable. Automated backups are non-negotiable.

Minecraft Backup Script

#!/bin/bash
# minecraft-backup.sh — Backup Minecraft world with server notification

CONTAINER="minecraft"
BACKUP_DIR="/mnt/backup/minecraft"
MAX_BACKUPS=14
DATE=$(date +%Y-%m-%d_%H-%M)

mkdir -p "$BACKUP_DIR"

# Notify players
docker exec "$CONTAINER" rcon-cli "say Server backup starting in 10 seconds..."
sleep 10

# Disable auto-save and force save
docker exec "$CONTAINER" rcon-cli "save-off"
docker exec "$CONTAINER" rcon-cli "save-all"
sleep 5

# Create backup
tar -czf "$BACKUP_DIR/world-$DATE.tar.gz" -C /path/to/minecraft-data world world_nether world_the_end

# Re-enable auto-save
docker exec "$CONTAINER" rcon-cli "save-on"
docker exec "$CONTAINER" rcon-cli "say Backup complete!"

# Rotate old backups
ls -t "$BACKUP_DIR"/world-*.tar.gz | tail -n +"$((MAX_BACKUPS + 1))" | xargs -r rm

echo "Backup complete: world-$DATE.tar.gz ($(du -sh "$BACKUP_DIR/world-$DATE.tar.gz" | cut -f1))"

Systemd Timer for Automated Backups

# /etc/systemd/system/minecraft-backup.timer
[Unit]
Description=Minecraft World Backup

[Timer]
OnCalendar=*-*-* 04:00:00
OnCalendar=*-*-* 16:00:00
Persistent=true

[Install]
WantedBy=timers.target
# /etc/systemd/system/minecraft-backup.service
[Unit]
Description=Minecraft World Backup
After=docker.service

[Service]
Type=oneshot
ExecStart=/opt/scripts/minecraft-backup.sh
User=root
sudo systemctl enable --now minecraft-backup.timer

Valheim Automatic Backups

The lloesche/valheim-server image has built-in backup support:

    environment:
      BACKUPS: "true"
      BACKUPS_CRON: "0 */6 * * *"      # Every 6 hours
      BACKUPS_DIRECTORY: "/config/backups"
      BACKUPS_MAX_AGE: 7                # Keep 7 days
      BACKUPS_MAX_COUNT: 28             # Keep max 28 backups
      BACKUPS_IF_IDLE: "false"          # Don't backup if no players are on

Multi-Game Server Management

Running multiple game servers efficiently requires planning around resource contention.

Resource Allocation Strategy

# docker-compose.yml — Multi-game setup with resource limits
services:
  minecraft:
    image: itzg/minecraft-server
    container_name: minecraft
    restart: unless-stopped
    ports:
      - "25565:25565"
    volumes:
      - ./minecraft:/data
    environment:
      EULA: "TRUE"
      MEMORY: "6G"
    deploy:
      resources:
        limits:
          cpus: "4.0"
          memory: 8G
        reservations:
          cpus: "2.0"
          memory: 6G

  valheim:
    image: lloesche/valheim-server
    container_name: valheim
    restart: unless-stopped
    ports:
      - "2456-2457:2456-2457/udp"
    volumes:
      - ./valheim-config:/config
      - ./valheim-data:/opt/valheim
    environment:
      SERVER_NAME: "My Valheim Server"
      WORLD_NAME: "MyWorld"
      SERVER_PASS: "secretpassword"
    deploy:
      resources:
        limits:
          cpus: "2.0"
          memory: 4G
        reservations:
          cpus: "1.0"
          memory: 2G

  terraria:
    image: ryshe/terraria:latest
    container_name: terraria
    restart: unless-stopped
    ports:
      - "7777:7777"
    volumes:
      - ./terraria:/root/.local/share/Terraria
    stdin_open: true
    tty: true
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 1G
        reservations:
          cpus: "0.5"
          memory: 512M

  palworld:
    image: thijsvanloef/palworld-server-docker:latest
    container_name: palworld
    restart: unless-stopped
    ports:
      - "8211:8211/udp"
      - "27015:27015/udp"
    volumes:
      - ./palworld:/palworld
    environment:
      SERVER_NAME: "My Palworld Server"
      SERVER_PASSWORD: "secretpassword"
      ADMIN_PASSWORD: "adminpassword"
      MAX_PLAYERS: 16
    deploy:
      resources:
        limits:
          cpus: "4.0"
          memory: 16G
        reservations:
          cpus: "2.0"
          memory: 8G

Server Status Dashboard

Use Crafty Controller or AMP (Application Management Panel) for a unified web interface to manage multiple game servers:

  crafty:
    image: registry.gitlab.com/crafty-controller/crafty-4:latest
    container_name: crafty
    restart: unless-stopped
    ports:
      - "8443:8443"     # Web UI
      - "25565:25565"   # Minecraft
      - "19132:19132/udp" # Bedrock
    volumes:
      - ./crafty/backups:/crafty/backups
      - ./crafty/logs:/crafty/logs
      - ./crafty/servers:/crafty/servers
      - ./crafty/config:/crafty/app/config
      - ./crafty/import:/crafty/import

Crafty provides:

Scheduled Restarts

Game servers accumulate memory leaks and performance degradation over time. Scheduled restarts keep things fresh.

Minecraft Restart with Warning

#!/bin/bash
# minecraft-restart.sh — Graceful restart with player warnings

CONTAINER="minecraft"

# Warn players
docker exec "$CONTAINER" rcon-cli "say Server restarting in 5 minutes for maintenance"
sleep 240  # 4 minutes
docker exec "$CONTAINER" rcon-cli "say Server restarting in 1 minute!"
sleep 50
docker exec "$CONTAINER" rcon-cli "say Server restarting in 10 seconds!"
sleep 10

# Save and stop
docker exec "$CONTAINER" rcon-cli "save-all"
sleep 5
docker restart "$CONTAINER"

Schedule it for low-activity hours:

# /etc/systemd/system/minecraft-restart.timer
[Timer]
OnCalendar=*-*-* 06:00:00
Persistent=true

Monitoring and Alerting

Server Status Checks

A simple health check script:

#!/bin/bash
# check-game-servers.sh

check_port() {
    local name="$1" host="$2" port="$3" proto="${4:-tcp}"
    if [ "$proto" = "udp" ]; then
        nc -zu "$host" "$port" -w 3 2>/dev/null
    else
        nc -z "$host" "$port" -w 3 2>/dev/null
    fi
    if [ $? -eq 0 ]; then
        echo "OK: $name ($host:$port/$proto)"
    else
        echo "FAIL: $name ($host:$port/$proto)"
        # Send notification (webhook, email, etc.)
    fi
}

check_port "Minecraft" localhost 25565
check_port "Valheim" localhost 2456 udp
check_port "Terraria" localhost 7777
check_port "Palworld" localhost 8211 udp

Minecraft-Specific Monitoring

The itzg/minecraft-server image includes a health check. Monitor it with Docker's built-in health check:

    healthcheck:
      test: mc-health
      start_period: 1m
      interval: 5s
      retries: 20

For TPS (ticks per second) monitoring — the key Minecraft performance metric:

# Check TPS via RCON
docker exec minecraft rcon-cli "tps"
# Expected output: TPS from last 1m, 5m, 15m: 20.0, 20.0, 20.0
# Below 18 TPS = noticeable lag. Below 15 TPS = unplayable.

Networking and Remote Access

Port Forwarding

Each game needs specific ports forwarded on your router:

Game Port(s) Protocol
Minecraft Java 25565 TCP
Minecraft Bedrock 19132 UDP
Valheim 2456-2457 UDP
Terraria 7777 TCP
Palworld 8211 UDP

VPN Alternative

Instead of port forwarding (which exposes your home IP), use a VPN:

# Playit.gg setup (no Docker needed on the host)
curl -SsL https://playit.gg/downloads/playit-linux_64-signed | bash
# Follow the interactive setup to create tunnels for your game ports

Hardware Recommendations

Budget Game Server (1-2 games, 5-10 players)

Mid-Range Game Server (3-4 games, 10-20 players)

Heavy Game Server (5+ games, 20+ players, heavy mods)

Important: Game servers (especially Minecraft) benefit more from high single-thread CPU performance than from many cores. An Intel i5-13600K outperforms a dual-Xeon server for Minecraft because most game server logic is single-threaded.

Final Thoughts

The difference between a game server that's "fine" and one that's genuinely good comes down to operational care: automated backups, scheduled restarts, performance monitoring, and proactive mod management. None of it is hard, but it does require setting up the automation and then leaving it alone to do its job.

Start with one game, get it running well with backups and scheduled restarts, then expand. Your friends won't care about your fancy container orchestration setup — they'll care that the server is fast, stable, and their builds are safe. Focus on those outcomes and the rest is just implementation details.