Kevin Coughlin. Blog

Network-Aware Minecraft Server on macOS

I wanted my Minecraft server to automatically start when I connect to my home WiFi, gracefully shut down when I leave, and perform daily maintenance restarts like production game servers. Here's how I set it up on macOS.

The Problem

Running a Minecraft server 24/7 on a laptop isn't practical. I wanted it to:

The Solution

A shell script (mc-server-manager) with LaunchAgents for network monitoring and scheduled restarts.

WiFi Detection Gotcha

The commonly recommended approach:

networksetup -getairportnetwork en0

Returns "not associated" on 6GHz WiFi networks, even when connected. This is a known bug on newer macOS versions with WiFi 6E.

The fix is to use system_profiler instead:

system_profiler SPAirPortDataType | \
    awk '/Current Network Information:/{getline; gsub(/^[[:space:]]+|:$/,""); print; exit}'

This correctly returns the SSID regardless of which band you're connected to.

Configuration

All settings live in ~/.config/mc-server/config:

# Network
TARGET_SSID="HomeWiFi"

# Server
SERVER_DIR="$HOME/Development/minecraft/minecraft-server/server"
SESSION_NAME="minecraft-server"

# JVM Memory
MIN_RAM="4G"
MAX_RAM="4G"

# Scheduled restart (24h format, local time)
RESTART_ENABLED="true"
RESTART_HOUR="00"
RESTART_MINUTE="00"
RESTART_TIMEZONE="America/Los_Angeles"

# Warning intervals before restart (seconds)
RESTART_WARNINGS="300 60 30 10 5"

JVM Optimization

The script uses modern Aikar's flags optimized for Paper 1.20+ on Java 21:

build_jvm_flags() {
    local flags=(
        "-Xms${MIN_RAM}" "-Xmx${MAX_RAM}"

        # G1GC optimized for Minecraft's allocation patterns
        "-XX:+UseG1GC"
        "-XX:+ParallelRefProcEnabled"
        "-XX:MaxGCPauseMillis=200"
        "-XX:+UnlockExperimentalVMOptions"
        "-XX:+DisableExplicitGC"
        "-XX:+AlwaysPreTouch"

        # G1GC region sizing
        "-XX:G1NewSizePercent=30"
        "-XX:G1MaxNewSizePercent=40"
        "-XX:G1HeapRegionSize=8M"
        "-XX:G1ReservePercent=20"
        "-XX:G1HeapWastePercent=5"
        "-XX:G1MixedGCCountTarget=4"

        # G1GC tuning
        "-XX:InitiatingHeapOccupancyPercent=15"
        "-XX:G1MixedGCLiveThresholdPercent=90"
        "-XX:G1RSetUpdatingPauseTimePercent=5"
        "-XX:SurvivorRatio=32"
        "-XX:MaxTenuringThreshold=1"
        "-XX:+PerfDisableSharedMem"

        # Debug helpers (no perf impact)
        "-XX:+HeapDumpOnOutOfMemoryError"
        "-XX:HeapDumpPath=$DATA_DIR/heapdump.hprof"
    )
    echo "${flags[*]}"
}

Key points:

Scheduled Restarts

Like production game servers, the script supports scheduled restarts with player warnings:

restart_server() {
    local reason="${1:-Scheduled maintenance}"

    # Warnings at 5m, 1m, 30s, 10s, 5s
    for secs in 300 60 30 10 5; do
        server_say "[RESTART] Server restarting in $(format_duration $secs) - $reason"
        sleep_until_next_warning
    done

    server_cmd "save-all"
    server_say "[RESTART] Restarting NOW!"
    server_cmd "stop"

    # Wait for graceful shutdown, then cleanup and restart
    cleanup_server
    start_server
}

The cleanup_server function handles maintenance:

LaunchAgents

Two LaunchAgents handle automation:

Network Monitor

com.user.minecraft-server-network - Triggers on WiFi changes:

<key>WatchPaths</key>
<array>
    <string>/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist</string>
    <string>/Library/Preferences/SystemConfiguration/NetworkInterfaces.plist</string>
</array>
<key>StartInterval</key>
<integer>60</integer>

Scheduled Restart

com.user.minecraft-server-restart - Daily at midnight:

<key>StartCalendarInterval</key>
<dict>
    <key>Hour</key>
    <integer>0</integer>
    <key>Minute</key>
    <integer>0</integer>
</dict>

Usage

mc-server-manager status    # Show server state, network, config
mc-server-manager start     # Start server
mc-server-manager stop      # Graceful stop with save
mc-server-manager restart   # Full restart with 5m/1m/30s/10s/5s warnings
mc-server-manager quick     # Quick restart (10s warning)
mc-server-manager attach    # Attach to console (Ctrl+B,D to detach)
mc-server-manager config    # Print current config
mc-server-manager cleanup   # Run maintenance manually
mc-server-manager logs      # Tail manager log

Example output from status:

=== Minecraft Server ===
Server running: yes
Network: HomeWiFi (target: HomeWiFi)
Session: minecraft-server
Attach: tmux attach -t minecraft-server

=== Scheduled Restart ===
Enabled: true
Time: 00:00 (America/Los_Angeles)
Warnings: 300 60 30 10 5

=== Config ===
File: ~/.config/mc-server/config
JVM: 4G - 4G

Why tmux over screen?

macOS ships with screen 4.00.03 from 2006. It lacks features like -Logfile and has quirks with detached sessions. tmux is actively maintained, has better scripting support, and integrates well with the rest of my workflow.

Files

FilePurpose
~/.local/bin/mc-server-managerManagement script (v1.1.0)
~/.config/mc-server/configConfiguration
~/Library/LaunchAgents/com.user.minecraft-server-network.plistNetwork monitor
~/Library/LaunchAgents/com.user.minecraft-server-restart.plistScheduled restart
~/.local/share/minecraft-server/manager.logManager logs
~/.local/share/minecraft-server/heapdump.hprofOOM heap dump (if triggered)

Setup

# Load the agents
launchctl load ~/Library/LaunchAgents/com.user.minecraft-server-network.plist
launchctl load ~/Library/LaunchAgents/com.user.minecraft-server-restart.plist

# Generate a config file
mc-server-manager config > ~/.config/mc-server/config

# Edit to taste
vim ~/.config/mc-server/config

Now the server manages itself: starts on home WiFi, stops when leaving, restarts nightly with cleanup, and warns players before any restart.