Skip to content

Paper

Example software configuration for Paper

yaml
# Paper software configuration

software:

  # Unique identifier for the software
  id: 'paper'

  # Human readable name for the software
  name: 'Paper'

  # Images that can be used for this software
  images:
    "java_25": "ghcr.io/protoxon/images:java_25"
    "java_21": "ghcr.io/protoxon/images:java_21"
    "java_17": "ghcr.io/protoxon/images:java_17"
    "java_16": "ghcr.io/protoxon/images:java_16"
    "java_11": "ghcr.io/protoxon/images:java_11"
    "java_8": "ghcr.io/protoxon/images:java_8"

  # Version to image mappings
  mappings:
    - java_8:  "<=1.16.5"
    - java_16: ">=1.17 <=1.17.1"
    - java_17: ">=1.18 <=1.20.4"
    - java_21: ">=1.20.5 <=1.21.11"
    - java_25: ">=1.21.12"
    - default: java_21

  # The command to start the server
  invocation: "java -Xms128M -XX:MaxRAMPercentage=95.0 -Dterminal.jline=false -Dterminal.ansi=true -XX:+PerfDisableSharedMem -XX:+ParallelRefProcEnabled -jar server.jar"  # Start command for the server
  
  # The command sent to stop the server gracefully
  stop-command: "stop"

  # The console output indicating the server is fully online
  online-signal: ")! For help, type"

  # Installs the server and warms it up
  install-script:
    entrypoint: bash
    script: "#!/bin/bash\n# Paper Installation Script\nPROJECT=paper\n\n# Set defaults if not provided\n: \"${SERVER_JARFILE:=server.jar}\"\n\nif [ -n \"${DL_PATH}\" ]; then\n    echo -e \"Using supplied download url: ${DL_PATH}\"\n    DOWNLOAD_URL=`eval echo $(echo ${DL_PATH} | sed -e 's/{{/${/g' -e 's/}}/}/g')`\nelse\n    VER_EXISTS=`curl -s https://api.papermc.io/v2/projects/${PROJECT} | jq -r --arg VERSION $VERSION '.versions[] | contains($VERSION)' | grep -m1 true`\n    LATEST_VERSION=`curl -s https://api.papermc.io/v2/projects/${PROJECT} | jq -r '.versions' | jq -r '.[-1]'`\n\n    if [ \"${VER_EXISTS}\" == \"true\" ]; then\n        echo -e \"Version is valid. Using version ${VERSION}\"\n    else\n        echo -e \"Specified version not found. Defaulting to the latest ${PROJECT} version\"\n        VERSION=${LATEST_VERSION}\n    fi\n\n    BUILD_EXISTS=`curl -s https://api.papermc.io/v2/projects/${PROJECT}/versions/${VERSION} | jq -r --arg BUILD ${BUILD_NUMBER} '.builds[] | tostring | contains($BUILD)' | grep -m1 true`\n    LATEST_BUILD=`curl -s https://api.papermc.io/v2/projects/${PROJECT}/versions/${VERSION} | jq -r '.builds' | jq -r '.[-1]'`\n\n    if [ \"${BUILD_EXISTS}\" == \"true\" ]; then\n        echo -e \"Build is valid for version ${VERSION}. Using build ${BUILD_NUMBER}\"\n    else\n        echo -e \"Using the latest ${PROJECT} build for version ${VERSION}\"\n        BUILD_NUMBER=${LATEST_BUILD}\n    fi\n\n    JAR_NAME=${PROJECT}-${VERSION}-${BUILD_NUMBER}.jar\n    echo \"Version being downloaded\"\n    echo -e \"MC Version: ${VERSION}\"\n    echo -e \"Build: ${BUILD_NUMBER}\"\n    echo -e \"JAR Name of Build: ${JAR_NAME}\"\n    DOWNLOAD_URL=https://api.papermc.io/v2/projects/${PROJECT}/versions/${VERSION}/builds/${BUILD_NUMBER}/downloads/${JAR_NAME}\nfi\n\ncd /home/container\n\necho -e \"Running curl -o ${SERVER_JARFILE} ${DOWNLOAD_URL}\"\nif [ -f ${SERVER_JARFILE} ]; then\n    mv ${SERVER_JARFILE} ${SERVER_JARFILE}.old\nfi\n\ncurl -f -o ${SERVER_JARFILE} ${DOWNLOAD_URL}\nif [ $? -ne 0 ]; then\n    echo \"ERROR: Failed to download server jar. Aborting.\"\n    exit 1\nfi\n\nif [ ! -f ${SERVER_JARFILE} ]; then\n    echo \"ERROR: Server jar not found after download. Aborting.\"\n    exit 1\nfi\n\n# Wite the default server properties file\ncat > server.properties <<EOF\nserver-port=25565\nserver-ip=\nmax-players=50\nmotd=SLS\nallow-nether=false\nonline-mode=false\nenable-command-block=true\nspawn-protection=0\nview-distance=12\nEOF\n\n# Wite the default bukkit config file\ncat > bukkit.yml <<EOF\nsettings:\n  allow-end: false\nEOF\n\n# Wite the default spigot config file\ncat > spigot.yml <<EOF\nsettings:\n  bungeecord: true\nEOF\n\nprintf \"\\033[1m\\033[33mcontainer@sls~ \\033[0mjava -version\\n\"\njava -version\n\necho \"eula=true\" > eula.txt\n\nFIFO=\"server.pipe\"\nmkfifo $FIFO\n\necho \"Starting server for warmup...\"\njava -Xms128M -XX:MaxRAMPercentage=80.0 -Dterminal.jline=false -Dterminal.ansi=true \\\n    -jar ${SERVER_JARFILE} < $FIFO > server-output.log 2>&1 &\nSERVER_PID=$!\n\n# Check server actually started\nsleep 2\nif ! kill -0 $SERVER_PID 2>/dev/null; then\n    echo \"ERROR: Server process failed to start. Aborting.\"\n    cat server-output.log\n    exit 1\nfi\n\n# Keep write end of pipe open so server doesn't block on stdin\nexec 3>$FIFO\n\nSTART_TIME=$(date +%s)\nTIMEOUT=600\nSUCCESS=false\n\necho \"Waiting for server to reach 'Preparing level'...\"\n\ntail -F server-output.log 2>/dev/null | while read -r line; do\n    echo \"[SERVER] $line\"\ndone &\nTAIL_PID=$!\n\nwhile true; do\n    if [ -f server-output.log ] && grep -q \"Preparing level\" server-output.log; then\n        echo \"Server reached 'Preparing level'. Killing process...\"\n        kill -9 $SERVER_PID 2>/dev/null || true\n        SUCCESS=true\n        break\n    fi\n\n    # Check if server died unexpectedly\n    if ! kill -0 $SERVER_PID 2>/dev/null; then\n        echo \"ERROR: Server process died unexpectedly. Aborting.\"\n        cat server-output.log\n        exit 1\n    fi\n\n    NOW=$(date +%s)\n    ELAPSED=$((NOW - START_TIME))\n    if [ \"$ELAPSED\" -ge \"$TIMEOUT\" ]; then\n        echo \"ERROR: Timeout reached waiting for server. Aborting.\"\n        kill -9 $SERVER_PID 2>/dev/null\n        cat server-output.log\n        exit 1\n    fi\n\n    sleep 2\ndone\n\n# Wait for process to exit after kill\nwait $SERVER_PID 2>/dev/null || true\n\n# Cleanup\nexec 3>&-\nkill $TAIL_PID 2>/dev/null || true\nrm -f $FIFO\nrm -f server-output.log\n\n# Clean up server-generated files not needed in the image\nrm -rf world world_nether world_the_end logs\n\nif [ \"$SUCCESS\" = true ]; then\n    echo \"Warmup complete.\"\n    exit 0\nelse\n    echo \"ERROR: Warmup did not complete successfully.\"\n    exit 1\nfi"
    skip_scripts: false

  # Default limits  
  limits:
    memory_limit: 4096
    swap: 0
    io_weight: 500
    cpu_limit: 0
    disk_space: 8192
    threads: ""
    oom_disabled: true

  # Config patch to set the server ip and port  
  configs:
    server.properties:
      parser: properties
      find:
        server-ip: "0.0.0.0"
        server-port: "{{server.build.default.port}}"
        query.port: "{{server.build.default.port}}"